Topic Model 的复杂度计算(时间和空间)
来源:互联网 发布:在淘宝点击卖家没反应 编辑:程序博客网 时间:2024/06/05 08:53
算法复杂度包含两个方面,时间复杂度和空间复杂度,也就是常称的计算复杂度和内存空间占用两方面。下面先说主题模型的计算复杂度,再说内存占用。
时间复杂度
本来这个问题挺简单的,但是有搞统计的同学不知道CS里面的复杂度是怎么计算,就写到这里吧。本文比较三个topic model时间复杂度的计算方法,分别是LDA,Biterm,和hdLDA。
时间复杂度的计算很好掌握,就是把算法中的最基本操作作为单元操作,设定其时间复杂度为O(1)。最简单的可以是赋值、加减乘除等操作;复杂的也可以将之前文章中讲到的一次Gibbs sampling抽样(一个变量t+1时刻的值,由其它变量t时刻的值抽得),作为一个单元操作。最后看该操作总共执行了多少次,若执行了M次,则算法的时间复杂度就是O(M)。
在Topic Model中,单元操作可看作是一次Gibbs抽样(其实可以更细粒度到加减乘除运算,但是本次所对比的LDA和Biterm模型的单次抽样复杂度相同,所以不需要比较更细粒度的运算)。那么计算时间复杂度就是计算该抽样所执行的次数。所以接下来就是看一下套在单元计算外面的计算步骤。
int last_iter = liter;for (liter = last_iter + 1; liter <= niters + last_iter; liter++) { printf("Iteration %d ...\n", liter); for (int m = 0; m < M; m++) { for (int n = 0; n < ptrndata->docs[m]->length; n++) { int topic = sampling(m, n); z[m][n] = topic; } }}
由上面代码可以看出,最外层是一个迭代次数
int model::sampling(int m, int n) { // remove z_i from the count variables int topic = z[m][n]; int w = ptrndata->docs[m]->words[n]; nw[w][topic] -= 1; nd[m][topic] -= 1; nwsum[topic] -= 1; ndsum[m] -= 1; double Vbeta = V * beta; double Kalpha = K * alpha; // do multinomial sampling via cumulative method for (int k = 0; k < K; k++) { p[k] = (nw[w][k] + beta) / (nwsum[k] + Vbeta) * (nd[m][k] + alpha) / (ndsum[m] + Kalpha); } // cumulate multinomial parameters for (int k = 1; k < K; k++) { p[k] += p[k - 1]; } double u = ((double)random() / RAND_MAX) * p[K - 1]; for (topic = 0; topic < K; topic++) { if (p[topic] > u) { break; } } nw[w][topic] += 1; nd[m][topic] += 1; nwsum[topic] += 1; ndsum[m] += 1; return topic;}
可以看到核心计算过程也就是在为p[k]赋值的过程,而k一共有K个。所以最终的复杂度也就是:
那么计算Biterm topic model也就很简单了。由于该模型的主题分布不在文档上,而是在biterm上,而biterm的个数为
对于hdLDA模型来说,其抽样步骤比较繁琐。具体代码为:
printf("Sampling %d iterations!\n", niters);int last_iter = liter;for (liter = last_iter + 1; liter <= niters + last_iter; liter++) { for (int m = 0; m < M; m++) { for (int n = 0; n < ptrndata->contents[m]->length; n++) { int topic = sampling_step_one(m, n); z[m][n] = topic; } } for (int m = 0; m < M; m++) { for (int c = 0; c < ptrndata->comments[m]->C; c++) { xdc[m][c] = sampling_step_two_x(m, c); ydc[m][c] = sampling_step_two_y(m, c); } } for (int m = 0; m < M; m++) { for (int c = 0; c < ptrndata->comments[m]->C; c++) { sampling_step_three(m, c); } }}
可以看到每一个sampling step在外层都共享了
ptrndata->contents[m]->length
这与LDA代码部分相似。
而sampling_step_two()和sampling_step_three()则各自循环下面次数,也就是每篇正文的跟帖条数:
ptrndata->comments[m]->C
由于不是每篇正文的跟帖数目都是相同的,因此这里也取平均值,记作
接下来再看看每一个抽样步骤中的时间复杂度。sampling_step_one()的代码是这样的:
int model::sampling_step_one(int m, int n) { int topic = z[m][n]; int w = ptrndata->contents[m]->words[n]; ndk[m][topic] -= 1; nkv[topic][w] -= 1; ndksum[m] -= 1; nkvsum[topic] -= 1; for (int k = 0; k < K; k++) { p[k] = exp(log(ndk[m][k] + gdk[m][k] + alpha) - log((ndksum[m] + gdksum[m] + Kalpha)) + log((nkv[k][w] + gkv[k][w] + betaFM[k][w])) - log((nkvsum[k] + gkvsum[k] + VbetaF[k]))); } // cumulate multinomial parameters for (int k = 1; k < K; k++) { p[k] += p[k - 1]; } // scaled sample because of unnormalized p[] double u = ((double)rand() / RAND_MAX) * p[K - 1]; for (topic = 0; topic < K; topic++) { if (p[topic] >= u) { break; } } if (topic == K){ topic = K - 1; } ndk[m][topic] += 1; nkv[topic][w] += 1; ndksum[m] += 1; nkvsum[topic] += 1; return topic;}
可以看到其中核心计算步骤迭代了K次,与LDA和Biterm相同。因此对于sampling_step_one()步来说,其具有复杂度
对于sampling_step_two_x()和sampling_step_two_y()来说,其代码非常相似,节省篇幅起见,下面只给出step_two_x()的代码:
int model::sampling_step_two_x(int m, int c){ int topic = 0; for (int i = 0; i < ptrndata->comments[m]->commlines[c]->length; i++) { if(I[m][c][i]) { topic = xdc[m][c]; gdk[m][topic] -= 1; gdksum[m] -= 1; gkv[topic][ptrndata->comments[m]->commlines[c]->words[i]] -= 1; gkvsum[topic] -= 1; } } for (int k = 0; k < K; k++) { p[k] = log(1.0); double left = log(ndk[m][k] + gdk[m][k] + alpha) - log(ndksum[m] + gdksum[m] + Kalpha); for (int i = 0; i < ptrndata->comments[m]->commlines[c]->length; i++) { if (I[m][c][i]){ int w = ptrndata->comments[m]->commlines[c]->words[i]; p[k] += (log(nkv[k][w] + gkv[k][w] + betaFM[k][w]) - log(nkvsum[k] + gkvsum[k] + VbetaF[k])); } } p[k] += left; p[k] = exp(p[k]); } // cumulate multinomial parameters for (int k = 1; k < K; k++) { p[k] += p[k - 1]; } double u = ((double)rand() / RAND_MAX) * p[K - 1]; for (topic = 0; topic < K; topic++) { if (p[topic] >= u) { break; } } if (topic == K){ topic = K - 1; } for (int i = 0; i < ptrndata->comments[m]->commlines[c]->length; i++) { if(I[m][c][i]) { gkv[topic][ptrndata->comments[m]->commlines[c]->words[i]] += 1; gkvsum[topic] += 1; gdk[m][topic] += 1; gdksum[m] += 1; } } return topic;}
可以看出这一步中,计算时间复杂度为
而sampling_step_three()的复杂度为
空间复杂度
空间复杂度就是程序在计算时,需要放在内存中用于存储中间结果的矩阵、向量等数据类型所占的空间。一般省略掉无关重要的变量,如标记变量等。而只关注与算法核心相关的内存空间占用(好像更贴近伪代码)。
在LDA中,算法需要维护三个矩阵:
Biterm因为没有了文档的概念,没有了矩阵
hdLDA所需要的不重要变量特别多,但是如果不计入核心算法的话,有
发现好简单啊。
- Topic Model 的复杂度计算(时间和空间)
- 时间复杂度和空间复杂度的计算
- 计算算法的时间和空间复杂度
- 计算算法的时间和空间复杂度
- 计算算法的时间和空间复杂度
- 【C/C++】空间复杂度和时间复杂度的计算
- 如何计算一个算法的时间复杂度和空间复杂度
- 计算算法的时间复杂度和空间复杂度
- 关于时间复杂度和空间复杂度的计算
- 计算时间和空间复杂度
- 计算时间和空间复杂度
- 计算时间和空间复杂度
- 计算时间复杂度和空间复杂度
- 关于计算时间复杂度和空间复杂度
- 关于计算时间复杂度和空间复杂度
- 【推荐】-时间复杂度和空间复杂度计算
- 0-时间复杂度&空间复杂度的计算
- 常用排序算法的时间和空间复杂度及算法时间复杂度的简单计算
- 快速幂 hdu5690 All X
- 关于Unity游戏的序列化
- Hortworks Hadoop 2.4.2安装、配置
- Unity实现json格式的序列化并发布
- 分布式文件系统简介
- Topic Model 的复杂度计算(时间和空间)
- 在NLP上,CNN、RNN(认为LSTM等变体也是RNN)、最简单全连结MLP,三者相比,各有何优劣?
- Hibernate_并发(悲观锁&乐观锁)_Demo
- Geekband012第十二周笔记分享
- 机器学习-RBF高斯核函数处理
- IntelliJ IDEA WEB项目的部署配置
- 关于SDWebImage的使用和相关面试题
- IDEA 常见问题
- Spring概括总结