报告 spark LDA 模型的对数似然/困惑(本地模型与分布式模型不同?)

mou*_*hio 2 scala lda apache-spark

给定一个训练语料库docsWithFeatures,我在 Spark(通过 Scala API)中训练了一个 LDA 模型,如下所示:

import org.apache.spark.mllib.clustering.{LDA, DistributedLDAModel, LocalLDAModel}
val n_topics = 10;
val lda = new LDA().setK(n_topics).setMaxIterations(20)
val ldaModel = lda.run(docsWithFeatures)

val distLDAModel = ldaModel.asInstanceOf[DistributedLDAModel]
Run Code Online (Sandbox Code Playgroud)

现在我想报告模型的对数似然和困惑度。

我可以像这样得到对数似然:

scala> distLDAModel.logLikelihood
res11: Double = -2600097.2875547716
Run Code Online (Sandbox Code Playgroud)

但这就是事情变得奇怪的地方。我也想要困惑,它只为本地模型实现,所以我运行:

val localModel  = distLDAModel.toLocal
Run Code Online (Sandbox Code Playgroud)

这让我得到这样的(日志)困惑:

scala> localModel.logPerplexity(docsWithFeatures)
res14: Double = 0.36729132682898674
Run Code Online (Sandbox Code Playgroud)

但是局部模型也支持对数似然计算,我是这样运行的:

scala> localModel.logLikelihood(docsWithFeatures)
res15: Double = -3672913.268234148
Run Code Online (Sandbox Code Playgroud)

那么这里发生了什么?两个对数似然值不应该相同吗?分布式模型的文档说

“logLikelihood:给定推断主题和文档主题分布的训练语料库的对数似然”

而对于本地模型,它说:

“logLikelihood(documents):根据推断的主题计算提供的文档的下限。”

我想这些是不同的,但我不清楚如何或为什么。我应该使用哪一种?也就是说,给定训练文档,哪一个是模型的“真实”似然?

总结一下,两个主要问题:

1 - 两个对数似然值如何以及为什么不同,我应该使用哪个?

2 - 在报告困惑时,我认为我应该使用 的指数是否正确logPerplexity result?(但为什么模型会给出日志困惑而不是简单的困惑?我错过了什么吗?)

Jas*_*man 5

1) 这两个对数似然值不同,因为它们正在计算两个不同模型的对数似然。DistributedLDAModel正在有效地计算对数似然的模型,其中主题的参数和每个文档的混合权重是常数(正如我在另一篇文章中提到的,DistributedLDAModel本质上是正则化的 PLSI,尽管您还需要使用它logPrior来解释正则化),而LocalLDAModel认为每个文档的主题参数和混合权重是随机变量。所以在这种情况下LocalLDAModel您必须整合(边缘化)主题参数和文档混合权重以计算对数似然(这就是使变分近似/下界变得必要的原因,尽管即使没有近似,对数似然也不是相同,因为模型不同。)

至于你应该使用哪个,我的建议(不知道你最终想要做什么)是使用你最初训练的类(即DistributedLDAModel.)附带的对数似然方法。作为旁注,主要(仅?)我可以看到将 aDistributedLDAModel转换为LocalLDAModelvia 的原因toLocal是为了能够计算新的(未训练的)文档集的主题混合权重(有关更多信息,请参阅我在此线程上的帖子:Spark MLlib LDA,如何推断新的未见文档的主题分布?),该操作在DistributedLDAModel.

2) log-perplexity 只是负对数似然除以语料库中的标记数。如果您除以 log-perplexity,math.log(2.0)则结果值也可以解释为在给定模型的情况下对您的语料库(作为词袋)进行编码所需的每个令牌的近似位数。