短文本的LDA模型实现及应用(二)

在主题模型的构建中,如果训练集较小,效果通常不会太理想(对监督学习),但是大数据量语料分析,常规方式性能堪忧,微软开源的LightLDA在性能上有了很大的提升。详见

http://www.flickering.cn/uncategorized/2016/05/peacock%E9%87%87%E6%A0%B7%E7%AE%97%E6%B3%95%E6%80%A7%E8%83%BD%E6%AF%94%E8%BE%83/

对比sparkLDA和JGibbsLDA,前者不支持Gibbs采样,还是用的EM和差分推理。后者是一个需要用命令行运行的工程,应该可以整合到spark,但是基于对lightLDA高性能口碑的好奇和兴趣,以及假如要使用lda模型,大型语料上的运行性能还是很重要的。

一、升级gcc版本

centos7的gcc满足4.8.5的版本要求,但是centos6需要升级。

#1.gcc版本检查 需要先确认
yum install gcc gcc-c++
 gcc --version 4.4.7 #gcc的版本要求是gcc-4.8.5:

#2.gcc编译安装
wget https://ftp.gnu.org/gnu/gcc/gcc-4.8.5/gcc-4.8.5.tar.gz
#编译安装 GCC 需要依赖 mpc,mpfr,gmp包。好在 GCC 源码里自带脚本可以轻松下载依赖包
tar czxf gcc-4.8.5.tar.gz
 cd gcc-4.8.5
 ./contrib/download_prerequisites
 mkdir gcc-build-4.8.5
 cd gcc-build-4.8.5
../configure --prefix=/usr --enable-checking=release --enable-languages=c,c++ --disable-multilib
make –j4 && make install

参数说明:
<1>--prefix 为了避免安装后系统里出现多个版本的 GCC,这里直接将编译安装的目录指定为 /usr,如果不指定–prefix,则会默认安装到 /usr/local 下
<2>--enable-languages        //指定 gcc 能编译哪些语言的文件,每种语言用逗号分隔, 例如 c,c++,java
<3>--disable-multilib    //默认gcc 能在32位系统上将代码编译成64位程序,或者在64位系统上编译成32位程序,

完成后, 默认会替换为正确的4.8.5的,及其特殊情况下会冲突

#gcc 冲突解决
 which gcc  #如果显示的是/usr/bin/gcc
 mv /usr/bin/gcc /usr/bin/gcc4.4.7
 ln -s /usr/local/bin/gcc(新gcc) /usr/bin/gcc

# g++冲突解决
 mv /usr/bin/g++ /usr/bin/g++4.4.7
 ln -s /usr/local/bin/g++(新) /usr/bin/g++

# cc 冲突解决
 mv /usr/bin/cc /usr/bin/cc4.4.7
 ln -s /usr/local/bin/cc(新) /usr/bin/cc

#c++冲突解决
 mv /usr/bin/c++ /usr/bin/c++4.4.7
 ln -s /usr/local/bin/c++(新) /usr/bin/c++

二。git安装

yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel
 yum install gcc perl-ExtUtils-MakeMaker
 yum remove git
 cd /usr/local/src
 wget https://www.kernel.org/pub/software/scm/git/git-2.0.5.tar.gz --no-check-certificate
 tar xzf git-2.0.5.tar.gz
 cd git-2.0.5
 make prefix=/usr/local/git all
 make prefix=/usr/local/git install
 echo "export PATH=$PATH:/usr/local/git/bin" >> /etc/bashrc
 source /etc/bashrc
 git --version

三、LightLDA源码安装

cd /usr/local/src
 git clone https://github.com/Microsoft/lightlda #如果报ssl error可能是ssl版本低,升级yum update nss
 cd lightlda

安装
默认安装sh ./build.sh会报错,里面的一些地址已经更换,按照以下的顺序安装:

1.下载DMTK,微软开源的机器学习工具包,lightLDA是基于DMTK的

yum install libopenmpi-dev openmpi-bin build-essential cmake git
 git clone -b multiverso-initial https://github.com/Microsoft/multiverso.git
 cd multiverso

2.安装第三方组件:
cd third_party
默认运行sh ./install.sh会失败的
  2.1 安装 zeromq
    注意一点:需要将zeromq的lib路径加入到/etc/ld.so.conf 后再编译,否则在后面运行的时候报错:

bin/lightlda: error while loading shared libraries: libzmq.so.5: cannot open shared object file: No such file or directory

vi /etc/ld.so.conf
#加入 /usr/local/src/lightlda/multiverso/third_party/lib ldconfig
# 注意这个时候会报错ldconfig: /usr/lib64/libstdc++.so.6.0.19-gdb.py 不是 ELF 文件 - 它起始的魔数错误
 mv /usr/lib64/libstdc++.so.6.0.19-gdb.py /usr/lib64/bak_libstdc++.so.6.0.19-gdb.py #后重新执行ldconfig

wget https://archive.org/download/zeromq_4.1.3/zeromq-4.1.3.tar.gz
#如果失败,自行下载到本地上传到third_party
 tar -zxf zeromq-4.1.3.tar.gz cd zeromq-4.1.3
 ./configure --prefix=/usr/local/src/lightlda/multiverso/third_party --without-libsodium
 make -j4
 make install -j4
 cd ..
 rm -rf zeromq-4.1.3

2.2 Get the C++ Wrapper zmq.hpp

wget https://github.com/zeromq/cppzmq/blob/master/zmq.hpp
# 不能直接wget会乱码,下载整个cppzmq的项目,解压出来zmp.hpp后单独上传
 mv zmq.hpp /usr/local/src/lightlda/multiverso/third_party/include/

2.3 Get MPICH2

wget http://www.mpich.org/static/downloads/3.0.4/mpich-3.0.4.tar.gz
# wget或者单独下载后上传
 tar -zxf mpich-3.0.4.tar.gz cd mpich-3.0.4
 ./configure --prefix=/usr/local/src/lightlda/multiverso/third_party --disable-fc --disable-f77
 make -j4
 make install -j4
 cd ..
 rm -rf mpich-3.0.4/
 rm -rf *.tar.gz

至此,已经完成第三方组件的编译安装

3.编译安装zmtk和lightlda

  3.1 编译安装DMTK

cd ../
make -j4 all

3.2 编译安装lightLDA

cd ..
 make -j4

至此,在lightLDA的bin目录下已经有lightlda和其他工具了

四、说明

Smultiverso(DMTK):是一个标准c++lib库,是一个基于框架的参数服务器,用来在多台机器上训练大数据的机器学习模型,提供了友好的api接口,使用者不必考虑分布式模型存储和操作,内部线程和内部进程间的交互,多线程的管理,只需要专注于机器学习的逻辑:数据,模型和训练。

Libzmq:zeroMq轻量级的消息内核继承了标准的socket接口,具有定制化消息中间件产品的特点,zeroMQ socke提供了异步消息队列,多消息模式,消息过滤的抽象,无缝对接多种传输协议。

mpich-3.0.4:是一个高性能便携式Message Passing Interface标准的实现,将线程的管理和交互分离。

五、实例文档的安装使用

1.下载示例文档

wget https://archive.ics.uci.edu/ml/machine-learning-databases/bag-of-words/docword.nytimes.txt.gz
wget https://archive.ics.uci.edu/ml/machine-learning-databases/bag-of-words/vocab.nytimes.txt

2.安装使用
  (1)解压后的txt文件是UCI格式的文件,格式如下(其中前三行统计数据可以没有)

文档数
单词数
NNZ
docID wordID count
docID wordID count

  (2)需要使用example中的text2libsvm将UCI格式转化为libsvm,默认脚本是python2的,在python3下如要修改如下:

print使用print()替代
#if not word_dict.has_key(word_id):用if word_id not in word_dict:替代

  (3)用bin/dump_binary将libsvm转化为二进制的lightLDA格式数据

  (4)示例的doc文件是6000W的数据,可以用head -n 100000 docword.nytimes.txt > docword.nytimes_new.txt 提取10w数据测试

  (5)完整的执行过程如下:

cd /usr/local/src/lightlda/
 mkdir mytest cd mytest
 cp ../example/text2libscm.py ./
 vi text2libscm.py  #修正代码
 mkdir output

#输出output的libsvm和字典文件
python ./text2libsvm.py ./docword.nytimes.txt ./vocab.nytimes.txt output/nytimes.libsvm output/nytimes.word_id.dict

#输出block文件和vocab
../bin/dump_binary output/nytimes.libsvm output/nytimes.word_id.dict output 0

#运行lightLDA
 ../bin/lightlda -num_vocabs 18000 -num_topics 10 -num_iterations 100 -alpha 2 -beta 0.1 -mh_steps 2 -num_local_workers 1 -num_blocks 1 -max_num_document 500 -input_dir output -data_capacity 2

3.lightlda参数说明:

-num_vocabs 数据集中包含的单词数目,是词汇表中的词的数目,可以比实际值偏大
 -num_topics 要训练的主题数目,经验值是sqrt(#docs)/3,可以用HDP或交叉验证确定
 -num_iterations 迭代次数,越多越好
 -alpha 对称Dirichlet分布的参数alpha,经验值设置为 50/#topics -beta 对称Dirichlet分布的参数beta, 经验值设置为0.1
 -max_num_document 训练的文档数目
 -input_dir 训练数据所在目录,目录下需有转化为lightlda自定义的输入格式文件
 -data_capacity 至少要最大的block文件的size,block文件是由dump_binary生成的。
 -model/alias/delta capacity 可以指定任意值,一般model/alias大小是同义数量级,delta相对会小很多。

4. 输出结果
   结果数据直接在mytest目录:一共4个文件

doc_topic.0 #doc_topic.blockID 这个blockID下的doc_topic分布,格式: 文档id 主题id:次数 server_0_table_0.model #word_topic分布,格式:词id 主题id:次数
server_0_table_1.model #只有一行,所有主题的出现次数统计, 主题id:次数
 LightLDA.40000.log #日志文件


六、分布式运行过程
lightlda的真正能力在于分布式的执行,可以在多台机器上同步线性扩展,以下例子在2台阿里云8GBECS上测试

1.以50W数据测试 (以下内容在server1上运行)

cd mytest
head -n 500000 docword.nytimes_ori.txt > docword.nytimes.txt  #截取50W测试数据
#转换成libsvm格式
 python ./text2libsvm.py ./docword.nytimes.txt ./vocab.nytimes.txt output/nytimes.libsvm output/nytimes.word_id.dict

2.数据预处理,将libsvm切分为几部分,使用phraug
(1)分割为2份数据  #在mytest目录下

git clone https://github.com/zygmuntz/phraug.git

#因为脚本是python2的,将chunk.py修改为版本3的

修改print
os[n].write( line)修改为os[n].write( line.encode('utf-8') )

        #因为测试环境2台机器,将数据分割为2份:

cd output/
 python ../phraug/chunk.py ./nytimes.libsvm 2 #结果生成nytimes_0.libsvm 和nytimes_1.libsvm

(2)转换格式为2进制的lightLDA格式

cd ../ ../bin/dump_binary output/nytimes_0.libsvm output/nytimes.word_id.dict output 0
 ../bin/dump_binary output/nytimes_1.libsvm output/nytimes.word_id.dict output 1
#在output下生成如下的文件
 block.0 clock.1
 vocab.0 vocab.1
 vocab.0.txt vocab.1.txt
 nytimes_0.libsvm nytimes_1.libsvm

(3)将1的文件放置到server2的指定目录下,同时修改为0
(4)在server2重命名1的文件: 注意:每个文件夹下是5个文件
(5)配置两台机器的无密码访问

cd ~/.ssh #看看里面有没有id_rsa,如果没有需要生成秘钥
 ssh-keygen -t rsa ssh-copy-id root@远端IP #两台机器分别执行
 ssh-copy-id root@自己IP #否则报错Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password)

(6)在其中一台机器上执行

/usr/local/src/lightlda/mytest #创建机器列表文件machinelist
 vi machinelist
 47.95.237.1
 60.205.1.2

#将mpi的路径加入到系统环境中
vi /etc/profile PATH=$PATH:$HOME/bin:/usr/local/src/lightlda/multiverso/third_party/bin
 export LD_LIBRARY_PATH=/usr/local/src/lightlda/multiverso/third_party/lib

 source /etc/profile

#分布式执行:注意开启动态端口的防火墙
 /etc/hosts的主机名和ip一定对应

(7)执行

cd /usr/local/src/lightlda/mytest
 mpiexec -machinefile ./machinelist ../bin/lightlda -num_vocabs 18000 -num_topics 10 -num_iterations 100 -alpha 2 -beta 0.1 -mh_steps 2 -num_local_workers 1 -num_blocks 1 -max_num_document 500 -input_dir output -data_capacity 2

(8)问题:
*** Error in `../bin/lightlda': munmap_chunk(): invalid pointer: 0x0000000008b778f0 ***

测试50W数据在8G的ecs上报错,30w测试通过,多轮测试发现是内存限制(50W单机也无法运行),注意不同的数据集调整-num_vocabs等参数

(9)补充
偶然发现,lightLDA的python实现

https://github.com/nzw0301/lightLDA


六、其他

  实际测试,单台8GB机器最多运行数据30W左右,50W就报内存错误,看来对内存的依赖较大
  lightlda对多文档的主题模型分析非常有效,性能也非常好,2台机器70W左右再10秒左右可出结果

你可能感兴趣的:(短文本的LDA模型实现及应用(二))