码迷,mamicode.com
首页 > 其他好文 > 详细

【LDA】用MPI优化GibbsLDA++-0.2

时间:2015-06-21 18:33:37      阅读:237      评论:0      收藏:0      [点我收藏+]

标签:

MPI 是“Message Passing Interface”的缩写,通常用来做单机多线程的并发编程。


1. GibbsLDA++中训练框架大致如下:

循环:训练过程迭代N次
{
     循环:遍历每一个训练样本(指doc)
     {
           循环:遍历训练样本中的每一个word
           {
                  循环:gibbs采样过程,遍历每一个topic
                  {
                         会更新:
                         doc-topic矩阵、
                         word-topic矩阵、
                         doc-topic的边缘分布向量、
                         word-topic的边缘分布向量
                         当前word在topic上的分布向量
                  }
           }
     }
}

LDA的训练过程主要通过gibbs采样过程来完成。在内存中会存储:(1)所有训练样本;(2)doc-topic矩阵、word-topic矩阵、几个topic相关的分布向量等。整个训练过程由上面嵌套的四重循环组成。当训词典不大且练样本集合不大的时候,gibbs采样是一个cpu消耗集中的项目,而不是内存占用的项目。也就是说cpu是整个训练的瓶颈。


2. 尝试用openmp来实现训练过程的单机并行化

主要是利用openmp利用单机cpu上的多个核心,将循环依照核心的数目来进行划分,例如:将一重循环划分为较小的两重循环,分别放在cpu的两个核心上进行运算,再将得到的结果进行合并。这样使用需要有个要求:数据独立性。即划分为两个循环之后,这两个循环内部不会对同一个变量或者内存区域进行修改,如果有的话,就会产生“竞争”关系,就会因为写内存的时机不同、程序运行出不同的结果。

2.1 在最内层循环用openmp

主要是计算“当前word在topic上的分布向量”的时候,遍历topic,这时候word在topic上的分布向量可以依据topic的不同拆分成不同的区域,相互并不干扰。代码如下:

#pragma omp parallel for num_threads(2)
    for (int k = 0; k < K; k++) 
	{
		p[k] = (nw[w][k] + beta) / (nwsum[k] + Vbeta) *
		    (nd[m][k] + alpha) / (ndsum[m] + Kalpha);
    }

上面代码用“#pragma omp parallel for num_threads(2)”指定该循环在两个核心上运算。

用GibbsLDA++自带的训练样本为例,实验结果如下:

没用MPI的,gibbs采样时间消耗:62.657s

用MPI的,gibbs采样时间消耗:94.626s

用MPI的,效率反而更低了!

现在能想到的原因,大概是针对K(topic个数)的循环太小了(实验中K的取值是100),且处于最内层循环,被调用的次数最多。这会引起大量的、拆分K循环给2个cpu的操作,这些操作也有性能损耗,且损耗大于了拆分后独立运行的收益,造成性能下降。

2.2 在第二层循环(遍历训练样本)中用openmp

第二层循环是遍历训练样本,在这一层循环用openmp实际上是对训练样本进行划分,并分别训练。代码如下:

#pragma omp parallel for num_threads(2)
		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;
			}
		}

这样修改,gibbs采样的运行时间就降低很多了,结果如下:

没用MPI的,gibbs采样时间消耗:62.657s

用MPI的,gibbs采样时间消耗:40.068s

降低了1/3的训练时间。

不过这样做会有数据依赖的问题:将第二层循环切分为两个并行的循环的话,这两个并行的小循环,最内层循环都会对word做gibbs采样,即都会读取和更新doc-topic和word-topic矩阵、以及那些边缘分布。从这个角度讲,算法运行出来的结果应该是不正确的结果。不过,换另外的角度想:

(1)对数据进行并行化,也就是将doc集合进行划分,那么doc-topic矩阵和doc边缘分布相对也划分成多份,互不干扰。不过word-topic矩阵以及当前word在每个topic上的分布的向量,会有相互之间的干扰。

(2)word-topic矩阵的内容,每个word不同,更新的区域不同,当并行循环计算的word不同的时候,也不会受到影响;当并行循环计算的word相同的时候,刚好需要累加计算结果,也OK

(3)word在每个topic上的分布的向量,这个结果会收到影响。例如:如果将训练数据划分为两份,这两份中分别找到两个word(通常是不同的),用来更新上面的向量,而这个向量的写操作如果不受保护的话,会写“混”了。不过,如果全局都是这种写混的状态的话....结果也说不准

(4)Gibbs采样是概率算法,已经验证过,即便是参数相同,每次运行的结果也不同。


完。


转载请注明出处:http://blog.csdn.net/xceman1997/article/details/46582637

【LDA】用MPI优化GibbsLDA++-0.2

标签:

原文地址:http://blog.csdn.net/xceman1997/article/details/46582637

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!