参考资料
http://52opencourse.com/111/%E6%96%AF%E5%9D%A6%E7%A6%8F%E5%A4%A7%E5%AD%A6%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86%E7%AC%AC%E5%9B%9B%E8%AF%BE-%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%EF%BC%88language-modeling%EF%BC%89
吴军,《数学之美》第3章:统计语言模型
http://www.speech.sri.com/projects/srilm/
Stanley F. Chen and Joshua Goodman. An empirical study of smoothing techniques for language modeling. Computer Speech and Language, 13:359-394, October 1999.
http://www.speech.sri.com/projects/srilm/manpages/ngram-discount.7.html
目标
熟悉语言模型相关的知识、训练流程
能够完成和语言模型相关的工作。
前置问题
什么是语言模型,语言模型可以用来做什么
语言模型刻画词序列概率大小。任何需要词汇序列概率大小的地方都可以用到语言模型,比如:
机器翻译:P(high winds tonite) > P(large winds tonite)
拼写纠错:P(about fifteen minutes from) > P(about fifteen minuets from)
语音识别:P(I saw a van) >> P(eyes awe of an)
音字转换:P(你现在干什么|nixianzaiganshenme) > P(你西安在干什么|nixianzaiganshenme)
自动文摘、问答系统、中文分词... ...
语言模型如何训练和评估
训练就是数数加平滑,评估主要用ppl和实际应用中的指标,如WER。主要工具是srilm中的ngram-count和ngram
语言模型如何用于语音识别
声学模型出来是一系列词汇序列。语言模型就是对这些词汇序列再加上语言模型得分,选出最合理的一句话。实际kaldi中:
- arpa语言模型利用arpa2fst转换成G.fst,
- 然后与L_disambig.fst(词典转换得到)、ilabels_${N}_${P}(三音素上下文)、Ha.fst 构图得到HCLG.fst。
- 解码过程中,来了一帧语音计算各个pdf-id(有限的,HCLG网格图能够到达的)概率,然后根据HCLG.fst,得到下一帧pdf-id集合。也就是说HCLG.fst起到了一个网格限制的作用,限制了从一个pdf-id只能到有限的pdf-id。
什么是语言模型,语言模型可以用来做什么
语言模型刻画词序列概率大小,假如一个词序列用S表示,那么如何确定该词序列概率呢,用链式法则:
//链式法则
//只看前两个,也就是3gram
取其中任意一个为例:
也就是说,要想得到一个ngram条件概率,只需要统计count数目,然后相除就可以了。
问题:这种极大似然统计,会导致训练集中没有出现的ngram概率为0。实际中,很多测试集中ngram在训练集中都没有出现过。
解决办法:数据平滑。看见事件概率分一部分出来,给将来的未看见的事件。
设计到两个问题:
- 一个是如何"切蛋糕",哪些ngram概率需要减少,具体减少多少?
-
一个是"分配切出来的蛋糕",这些概率分配给哪些没出现的ngram,分配多少?
常用的数据平滑策略是Good-Turing discount + Katz backoff
Good-Turing discount
各种discount方法公式计算见:
Ngram discount计算
语言模型如何训练和评估
srilm中训练lm的工具是ngram-count,评估lm的工具是ngram,常用命令包括训练、ppl计算、插值、裁剪,分别为:
- ngram-count -order 3 -vocab momo.dic -text train.txt -lm lm.3gram
- ngram -lm lm.3gram -order 3 -ppl test.txt -debug 2 >ppl.txt
- ngram -order 3 -lm lm.3gram.base -mix-lm lm.3gram -lambda 0.7 -write-lm lm.mix7v3.150M
- ngram-prune -order 3 -lm lm.mix7v3.150M -write-lm lm.mix7v3.70M -size 7e+07 (仿照ngram prune实现的工具,size参数后面是最终语言模型ngram数目)
除此之外,常用的语言模型开源工具还有kenLM,kaldi中也有训练lm的工具。
评估主要有两个指标:
-
困惑度(PerPLexity,PPL)
实际计算中通常得到的是值,转换后如下
: 句子中词的个数。ppl计算中包括</s>,ppl1中计算不包括</s>,所有N要少1,ppl1比ppl要大不少 - 实际应用中的指标,如语言模型用于语音识别,就可以用语音识别中词错误率来评估(Word Error Rate,WER)
错误词类型包括替换错误Sub,删除错误Del,插入错误Ins。由于插入错误的存在,WER有可能大于100%。除了WER,还有句子错误率SER。
FAQ
srilm工具中如何编写自己的程序?
- 进入lm/src 目录,cp ngram-count.cc ngram-count-example.cc, 修改 ngram-count-example.cc;
- 修改Makefile文件,REAL_PROGRAM_NAMES 部分增加ngram-count-example
- 返回srilm目录,make 得到srilm/lm/bin/i686-m64/count-example 可执行程序。
实际make过程包括:
-
g++ -march=athlon64 -m64 -Wall -Wno-unused-variable -Wno-uninitialized -DINSTANTIATE_TEMPLATES -fopenmp -I. -I../../include -c -g -O0 -o ../obj/i686-m64/LM.o LM.cc
-
ar ruv ../obj/i686-m64/liboolm.a ../obj/i686-m64/matherr.o ../obj/i686-m64/Prob.o ../obj/i686-m64/Counts.o ../obj/i686-m64/XCount.o ../obj/i686-m64/Vocab.o ../obj/i686-m64/VocabMap.o ../obj/i686-m64/VocabMultiMap.o ../obj/i686-m64/VocabDistance.o ../obj/i686-m64/SubVocab.o ../obj/i686-m64/MultiwordVocab.o ../obj/i686-m64/TextStats.o ../obj/i686-m64/LM.o ../obj/i686-m64/LMClient.o ../obj/i686-m64/LMStats.o ../obj/i686-m64/RefList.o ../obj/i686-m64/Bleu.o ../obj/i686-m64/NBest.o ../obj/i686-m64/NBestSet.o ../obj/i686-m64/NgramLM.o ../obj/i686-m64/NgramStatsInt.o ../obj/i686-m64/NgramStatsShort.o ../obj/i686-m64/NgramStatsLong.o ../obj/i686-m64/NgramStatsLongLong.o ../obj/i686-m64/NgramStatsFloat.o ../obj/i686-m64/NgramStatsDouble.o ../obj/i686-m64/NgramStatsXCount.o ../obj/i686-m64/NgramProbArrayTrie.o ../obj/i686-m64/NgramCountLM.o ../obj/i686-m64/MSWebNgramLM.o ../obj/i686-m64/Discount.o ../obj/i686-m64/ClassNgram.o ../obj/i686-m64/SimpleClassNgram.o ../obj/i686-m64/DFNgram.o ../obj/i686-m64/SkipNgram.o ../obj/i686-m64/HiddenNgram.o ../obj/i686-m64/HiddenSNgram.o ../obj/i686-m64/VarNgram.o ../obj/i686-m64/DecipherNgram.o ../obj/i686-m64/TaggedVocab.o ../obj/i686-m64/TaggedNgram.o ../obj/i686-m64/TaggedNgramStats.o ../obj/i686-m64/StopNgram.o ../obj/i686-m64/StopNgramStats.o ../obj/i686-m64/MultiwordLM.o ../obj/i686-m64/NonzeroLM.o ../obj/i686-m64/BayesMix.o ../obj/i686-m64/LoglinearMix.o ../obj/i686-m64/AdaptiveMix.o ../obj/i686-m64/AdaptiveMarginals.o ../obj/i686-m64/CacheLM.o ../obj/i686-m64/DynamicLM.o ../obj/i686-m64/HMMofNgrams.o ../obj/i686-m64/WordAlign.o ../obj/i686-m64/WordLattice.o ../obj/i686-m64/WordMesh.o ../obj/i686-m64/simpleTrigram.o ../obj/i686-m64/LMThreads.o ../obj/i686-m64/MEModel.o ../obj/i686-m64/hmaxent.o ../obj/i686-m64/NgramStats.o ../obj/i686-m64/Trellis.o 2>&1 | c++filt
-
g++ -march=athlon64 -m64 -Wall -Wno-unused-variable -Wno-uninitialized -DINSTANTIATE_TEMPLATES -fopenmp -I. -I../../include -c -g -O0 -o ../obj/i686-m64/ngram-count-example.o ngram-count-example.cc
-
g++ -march=athlon64 -m64 -Wall -Wno-unused-variable -Wno-uninitialized -DINSTANTIATE_TEMPLATES -fopenmp -I. -I../../include -u matherr -L../../lib/i686-m64 - g -O0 -o ../bin/i686-m64/ngram-count-example ../obj/i686-m64/ngram-count-example.o ../obj/i686-m64/liboolm.a ../../lib/i686-m64/libflm.a ../../lib/i686-m64/libdstruct.a ../../lib/i686-m64/libmisc.a ../../lib/i686-m64/libz.a -lm -lpthread 2>&1 | c++filt
简单来说就是:
重新编译LM.o;
重新生成liboolm.a静态库;
编译生成ngram-count-example.o;
链接生成ngram-count-example
训练语料很大时如何训练语言模型
语料分片统计ngram-count,然后混合训练语言模型
直接用并行方式训练。自己写一个MapReduce hadoop程序;
网友评论