1.LDA基本简介
LDA(Latent Dirichlet Allocation)是一种文档主题生成模型,也称为一个三层贝叶斯概率模型,包含词、主题和文档三层结构。
2.热点区域分析
2.1热点函数功能分析
/* 1.digamma */
double digamma(double x)
{
double p;
x=x+6;
p=1/(x*x);
p=(((0.004166666666667*p-0.003968253986254)*p+
0.008333333333333)*p-0.083333333333333)*p;
p=p+log(x)-0.5/x-1/(x-1)-1/(x-2)-1/(x-3)-1/(x-4)-1/(x-5)-1/(x-6);
return p;
}
功能分析:
此函数对输入x进行了算术运算得到输出p。
此函数无for循环,但执行比例较高,说明调用次数较高,被调用所在的for循环加速价值高。
/* 2.lda_inference */
double lda_inference(document* doc, lda_model* model, double* var_gamma, double** phi)
{
double converged = 1;
double phisum = 0, likelihood = 0;
double likelihood_old = 0, oldphi[model->num_topics];
int k, n, var_iter;
double digamma_gam[model->num_topics];
// compute posterior dirichlet
for (k = 0; k < model->num_topics; k++)
{
var_gamma[k] = model->alpha + (doc->total/((double) model->num_topics));
digamma_gam[k] = digamma(var_gamma[k]);
for (n = 0; n < doc->length; n++)
phi[n][k] = 1.0/model->num_topics;
}
var_iter = 0;
while ((converged > VAR_CONVERGED) &&
((var_iter < VAR_MAX_ITER) || (VAR_MAX_ITER == -1)))
{
var_iter++;
for (n = 0; n < doc->length; n++)
{
phisum = 0;
for (k = 0; k < model->num_topics; k++)
{
oldphi[k] = phi[n][k];
phi[n][k] =
digamma_gam[k] + model->log_prob_w[k][doc->words[n]];
if (k > 0)
phisum = log_sum(phisum, phi[n][k]);
else
phisum = phi[n][k]; // note, phi is in log space
}
for (k = 0; k < model->num_topics; k++)
{
phi[n][k] = exp(phi[n][k] - phisum);
var_gamma[k] =
var_gamma[k] + doc->counts[n]*(phi[n][k] - oldphi[k]);
// !!! a lot of extra digamma's here because of how we're computing it
// !!! but its more automatically updated too.
digamma_gam[k] = digamma(var_gamma[k]);
}
}
likelihood = compute_likelihood(doc, model, phi, var_gamma);
assert(!isnan(likelihood));
converged = (likelihood_old - likelihood) / likelihood_old;
likelihood_old = likelihood;
// printf("[LDA INF] %8.5f %1.3e\n", likelihood, converged);
}
return(likelihood);
}
功能分析:
此函数两个循环for-for,while-for-for;循环中调用了函数digamma和compute_likelihood。
第一个循环对输入数据进行算术运算产生了三个数组。
第二个循环消费三个数组并调用digamma函数,得到输出数据digamma_gam[]。此循环为最耗时循环。
/* 3.compute likelihood */
double
compute_likelihood(document* doc, lda_model* model, double** phi, double* var_gamma)
{
double likelihood = 0, digsum = 0, var_gamma_sum = 0, dig[model->num_topics];}}
int k, n;
for (k = 0; k < model->num_topics; k++)
{
dig[k] = digamma(var_gamma[k]);
var_gamma_sum += var_gamma[k];
}
digsum = digamma(var_gamma_sum);
likelihood =
lgamma(model->alpha * model -> num_topics)
- model -> num_topics * lgamma(model->alpha)
- (lgamma(var_gamma_sum));
for (k = 0; k < model->num_topics; k++)
{
likelihood +=
(model->alpha - 1)*(dig[k] - digsum) + lgamma(var_gamma[k])
- (var_gamma[k] - 1)*(dig[k] - digsum);
for (n = 0; n < doc->length; n++)
{
if (phi[n][k] > 0)
{
likelihood += doc->counts[n]*
(phi[n][k]*((dig[k] - digsum) - log(phi[n][k])
+ model->log_prob_w[k][doc->words[n]]));
}
}
}
return(likelihood);
}
功能分析:
此函数包含两个循环:for,for-for;循环中调用了digamma函数
第一个循环调用了digamma产生两个数据:一个标量,一个向量
第二个循环消费了第一循环的生产数据,循环不断进行树状计算得到输出数据likelihood。此循环为最耗时循环。
2.2热点区域调用关系分析
(1)热点函数调用
点:(self,total)
函数除去子函数的自身执行时间百分比,函数本身加上调用热点子函数总和百分比
边:(子函数执行比例,调用次数)
(2)lda-inference函数热点区域调用与数据流图(省略了部分非耗时循环的数据流图)
热点区域剖视借助了VTune工具,图中标红的循环为耗时最高循环
(3)compute_likelihood函数热点区域调用与数据流图(省略了部分非耗时循环的数据流图