使用 JGibbLDA 进行 LDA 模型训练及主题分布预测

时间:2022-06-07
本文章向大家介绍使用 JGibbLDA 进行 LDA 模型训练及主题分布预测,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

最近新闻个性化推荐项目中用到 LDA 来确定各个新闻的主题分布,我优先使用了 Spark Mllib LDA,发现并不理想,主要表现在极吃内存且计算慢,所以打算暂时放弃之。优先使用 Spark LDA 的主要原因是希望和能和 Spark Streaming 结合在一起进行实时预测。所以在考察新方案时优先考虑 Java 实现的 LDA 开源版本,之后发现了 JGibbLDA,下面从使用角度进行简单介绍

JGibbLDA 是一个由 Java 语言实现的 LDA 库,使用吉布斯采样进行参数估计和推断

在命令行中训练 JGibbLDA 模型

本节,将介绍如何使用该工具。假设当前工作目录是在 JGibbLDA 根目录并且我们使用的是 linux,命令行如下:

java [-mx512M] -cp bin:lib/args4j-2.0.6.jar jgibblda.LDA -est [-alpha <double>] [-beta <double>] [-ntopics <int>] [-niters <int>] [-savestep <int>] [-twords <int>] –dir <string> -dfile <string>

各参数含义:

  • -est:从头开始推断 LDA 模型
  • -alpha <double>:alpha 的值,LDA 的超参数。默认值为 50/K(K 是 topics 个数)
  • -beta <double>:beta 的值,同样是 LDA 的超参数。默认值为 0.1
  • -ntopics <int>:topics 个数。默认值为100,需要根据输入数据集来定
  • -niters <int>:吉布斯采样迭代次数。默认值为 2000
  • -savestep <int>:LDA 模型在哪一步(以吉布斯采样迭代为单位)保存到磁盘。默认值为200
  • -twords <int>:每个 topic 最匹配的词个数。默认值为0。如果将该值设为大于0,比如 20,JGibbLDA 将在每次将模型保存到磁盘的时候都会打印出每个 topic 最匹配的 20 个词
  • -dir <string>:训练数据文件所在目录
  • -dfile <string>:训练数据文件名

数据格式

训练数据和待预测数据具有相同的格式,如下:

[M]
[document1]
[document2]
...
[documentM]

第一行 [M] 是指总文档数,在此之后的每一行都是一个文档。[documenti] 是数据集第 i 个文档且由 Ni 个词组成:

[documenti] = [word-i1] [word-i2] ... [wordi-Ni]

所有的 [Word-ij](i=1..M, j=1..Ni) 都是词并由空格隔开(这里不要求每行的词个数一致,根据对应文档的正式情况填写即可)

注意:这里的每行的词都应该是提取出来的(比如利用分词库提取)

输出

使用 JGibbLDA 进行吉布斯采样 LDA 推荐会输出以下五个文件:

  • <model_name>.others
  • <model_name>.phi
  • <model_name>.theta
  • <model_name>.tassign
  • <model_name>.twords

其中:

  • <model_name>:LDA 模型的名字,对应于模型被保存在硬盘上的时间步骤。举例来说,在吉布斯采样第 400 次迭代的时候保存到磁盘的模型的名字为 model-00400,第 1200 次采样的名字为 model-01200,最后一次迭代对应的模型名字为 model-final
  • <model_name>.others:该文件训练 LDA 模型的各个参数,比如:
alpha=?
beta=?
ntopics=? # i.e., number of topics
ndocs=? # i.e., number of documents
nwords=? # i.e., the vocabulary size
liter=? # i.e., the Gibbs sampling iteration at which the model was saved
  • <model_name>.phi:该文件包含 “词-主题” 分布,每行是一个 topic,每列是词汇表中的一个词
  • <model_name>.theta:该文件包含 “主题-文档” 分布,每行是一个文档,每列是一个主题
  • <model_name>.tassign:该文件包含训练数据中的词对应的主题,每行代表一个文档,由一组 <word-ij>:<word-ij的 topic> 组成
  • <model_file>.twords:包含每个 topic 最匹配的词,词个数在命令行参数中指定

JGibbLDA 还保存一个叫做 wordmap.txt,该文件保存了词及其对应的 id(整形)

案例

举例,我们希望以 models/casestudy/newdocs.dat 为训练数据推断出一个 LDA 模型,然后用该模型推断存储在 models/casestudy/newdocs.dat 中的文档的主题分布

设置主题数为100,alpha = 0.5 且 beta = 0.1,迭代 1000 次,每迭代 100 次保存一次模型至磁盘,每次保存模型时打印出与各个 topic 最相关的 20 个词。假设我们现在处于 JGibbLDA 的根目录,那么我们将执行以下命令:

java -mx512M -cp bin:lib/args4j-2.0.6.jar jgibblda.LDA -est -alpha 0.5 -beta 0.1 -ntopics 100 -niters 1000 -savestep 100 -twords 20 -dfile models/casestudy/newdocs.dat

训练完之后,在目录 models/casestudy,我们可以看到上文中描述的 5 个输出文件


现在,我们需要在上一步 1000 次迭代之后再执行 800 次迭代,并设置每 100 次迭代保存一次模型,每次保存模型时打印出各个 topic 最相关的 30 个词,那么我们将执行下面的命令行:

java -mx512M -cp bin:lib/args4j-2.0.6.jar -estc -dir models/casestudy/ -model model-01000 -niters 800 -savestep 100 -twords 30

接下来,我们需要使用上一步训练出的模型对 newdocs.dat(该文件存储在模型相同目录) 中的文档进行主题分布预测,我们可以使用这样的命令:

java -mx512M -cp bin:lib/args4j-2.0.6.jar -inf -dir models/casestudy/ -model model-01800 -niters 30 -twords 20 -dfile newdocs.dat

编码预测文档主题分布

初始化推断器

为了在一个未知的数据集上推断出一个 LDA 主题模型,我们首先需要一个推断器。由于加载一个模型的耗时较长,我们通常初始化一个推断器并在多次推断中使用。首先,我们需要创建一个 LDACmdOption 实例,并类似下面这样进行初始化:

LDACmdOption ldaOption = new LDACmdOption(); 
ldaOption.inf = true; 
ldaOption.dir = "C:\LDAModelDir"; 
ldaOption.modelName = "newdocs"; 
ldaOption.niters = 100;

其中,LDACmdOptiondir 成员是包含模型(比如:通过命令行训练而来)的目录;成员 modelName 是模型名;niters 表示在第几次迭代保存的模型。接下来,我们使用 ldaOption 来初始化推断器:

Inferencer inferencer = new Inferencer(); 
inferencer.init(option);

预测未知数据

  • 预测文件中的数据
ldaOption.dfile = "input-lda-data.txt"; 
Model newModel = inferencer.inference();

其中,dfile 对应的文件格式与训练数据一致

  • 预测一个字符串数组
String [] test = {"politics bill clinton", "law court", "football match"};
Model newModel = inferencer.inference(test);