在主题模型的构建中,如果训练集较小,效果通常不会太理想(对监督学习),但是大数据量语料分析,常规方式性能堪忧,微软开源的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秒左右可出结果