Skip to content

Commit be4ad5f

Browse files
authored
Merge pull request #60 from zhaopu7/develop
add neural language model.
2 parents b1e2b23 + 78b8055 commit be4ad5f

File tree

17 files changed

+959
-1
lines changed

17 files changed

+959
-1
lines changed

language_model/README.md

Lines changed: 204 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,204 @@
1-
TBD
1+
# 语言模型
2+
3+
## 简介
4+
语言模型即 Language Model,简称LM,它是一个概率分布模型,简单来说,就是用来计算一个句子的概率的模型。利用它可以确定哪个词序列的可能性更大,或者给定若干个词,可以预测下一个最可能出现的词语。它是自然语言处理领域的一个重要的基础模型。
5+
6+
## 应用场景
7+
**语言模型被应用在很多领域**,如:
8+
9+
* **自动写作**:语言模型可以根据上文生成下一个词,递归下去可以生成整个句子、段落、篇章。
10+
* **QA**:语言模型可以根据Question生成Answer。
11+
* **机器翻译**:当前主流的机器翻译模型大多基于Encoder-Decoder模式,其中Decoder就是一个语言模型,用来生成目标语言。
12+
* **拼写检查**:语言模型可以计算出词语序列的概率,一般在拼写错误处序列的概率会骤减,可以用来识别拼写错误并提供改正候选集。
13+
* **词性标注、句法分析、语音识别......**
14+
15+
## 关于本例
16+
Language Model 常见的实现方式有 N-Gram、RNN、seq2seq。本例中实现了基于N-Gram、RNN的语言模型。**本例的文件结构如下**`images` 文件夹与使用无关可不关心):
17+
18+
19+
```text
20+
.
21+
├── data # toy、demo数据,用户可据此格式化自己的数据
22+
│ ├── chinese.test.txt # test用的数据demo
23+
| ├── chinese.train.txt # train用的数据demo
24+
│ └── input.txt # infer用的输入数据demo
25+
├── config.py # 配置文件,包括data、train、infer相关配置
26+
├── infer.py # 预测任务脚本,即生成文本
27+
├── network_conf.py # 本例中涉及的各种网络结构均定义在此文件中,希望进一步修改模型结构,请修改此文件
28+
├── reader.py # 读取数据接口
29+
├── README.md # 文档
30+
├── train.py # 训练任务脚本
31+
└── utils.py # 定义通用的函数,例如:构建字典、加载字典等
32+
```
33+
34+
**注:一般情况下基于N-Gram的语言模型不如基于RNN的语言模型效果好,所以实际使用时建议使用基于RNN的语言模型,本例中也将着重介绍基于RNN的模型,简略介绍基于N-Gram的模型。**
35+
36+
## RNN 语言模型
37+
### 简介
38+
39+
RNN是一个序列模型,基本思路是:在时刻t,将前一时刻t-1的隐藏层输出和t时刻的词向量一起输入到隐藏层从而得到时刻t的特征表示,然后用这个特征表示得到t时刻的预测输出,如此在时间维上递归下去,如下图所示:
40+
41+
<p align=center><img src='images/rnn_str.png' width='500px'/></p>
42+
43+
可以看出RNN善于使用上文信息、历史知识,具有“记忆”功能。理论上RNN能实现“长依赖”(即利用很久之前的知识),但在实际应用中发现效果并不理想,于是出现了很多RNN的变种,如常用的LSTM和GRU,它们对传统RNN的cell进行了改进,弥补了RNN的不足,下图是LSTM的示意图:
44+
45+
<p align=center><img src='images/lstm.png' width='500px'/></p>
46+
47+
本例中即使用了LSTM、GRU。
48+
49+
### 模型实现
50+
51+
本例中RNN语言模型的实现简介如下:
52+
53+
* **定义模型参数**`config.py`中的`Config_rnn`****中定义了模型的参数变量。
54+
* **定义模型结构**`network_conf.py`中的`rnn_lm`**函数**中定义了模型的**结构**,如下:
55+
* 输入层:将输入的词(或字)序列映射成向量,即embedding。
56+
* 中间层:根据配置实现RNN层,将上一步得到的embedding向量序列作为输入。
57+
* 输出层:使用softmax归一化计算单词的概率,将output结果返回
58+
* loss:定义模型的cost为多类交叉熵损失函数。
59+
* **训练模型**`train.py`中的`main`方法实现了模型的训练,实现流程如下:
60+
* 准备输入数据:建立并保存词典、构建train和test数据的reader。
61+
* 初始化模型:包括模型的结构、参数。
62+
* 构建训练器:demo中使用的是Adam优化算法。
63+
* 定义回调函数:构建`event_handler`来跟踪训练过程中loss的变化,并在每轮时结束保存模型的参数。
64+
* 训练:使用trainer训练模型。
65+
66+
* **生成文本**`infer.py`中的`main`方法实现了文本的生成,实现流程如下:
67+
* 根据配置选择生成方法:RNN模型 or N-Gram模型。
68+
* 加载train好的模型和词典文件。
69+
* 读取`input_file`文件(每行为一个sentence的前缀),用启发式图搜索算法`beam_search`根据各sentence的前缀生成文本。
70+
* 将生成的文本及其前缀保存到文件`output_file`
71+
72+
73+
## N-Gram 语言模型
74+
75+
### 简介
76+
N-Gram模型也称为N-1阶马尔科夫模型,它有一个有限历史假设:当前词的出现概率仅仅与前面N-1个词相关。一般采用最大似然估计(Maximum Likelihood Estimation,MLE)的方法对模型的参数进行估计。当N取1、2、3时,N-Gram模型分别称为unigram、bigram和trigram语言模型。一般情况下,N越大、训练语料的规模越大,参数估计的结果越可靠,但由于模型较简单、表达能力不强以及数据稀疏等问题。一般情况下用N-Gram实现的语言模型不如RNN、seq2seq效果好。
77+
78+
### 模型实现
79+
80+
本例中N-Gram语言模型的实现简介如下:
81+
82+
* **定义模型参数**`config.py`中的`Config_ngram`****中定义了模型的参数变量。
83+
* **定义模型结构**`network_conf.py`中的`ngram_lm`**函数**中定义了模型的**结构**,如下:
84+
* 输入层:本例中N取5,将前四个词分别做embedding,然后连接起来作为输入。
85+
* 中间层:根据配置实现DNN层,将上一步得到的embedding向量序列作为输入。
86+
* 输出层:使用softmax归一化计算单词的概率,将output结果返回
87+
* loss:定义模型的cost为多类交叉熵损失函数。
88+
* **训练模型**`train.py`中的`main`方法实现了模型的训练,实现流程与上文中RNN语言模型基本一致。
89+
* **生成文本**`infer.py`中的`main`方法实现了文本的生成,实现流程与上文中RNN语言模型基本一致,区别在于构建input时本例会取每个前缀的最后4(N-1)个词作为输入。
90+
91+
## 使用说明
92+
93+
运行本例的方法如下:
94+
95+
* 1,运行`python train.py`命令,开始train模型(默认使用RNN),待训练结束。
96+
* 2,运行`python infer.py`命令做prediction。(输入的文本默认为`data/input.txt`,生成的文本默认保存到`data/output.txt`中。)
97+
98+
99+
**如果用户需要使用自己的语料、定制模型,需要修改的地方主要是`语料``config.py`中的配置,需要注意的细节和适配工作详情如下:**
100+
101+
102+
### 语料适配
103+
104+
* 清洗语料:去除原文中空格、tab、乱码,按需去除数字、标点符号、特殊符号等。
105+
* 编码格式:utf-8,本例中已经对中文做了适配。
106+
* 内容格式:每个句子占一行;每行中的各词之间使用一个空格符分开。
107+
* 按需要配置`config.py`中对于data的配置:
108+
109+
```python
110+
# -- config : data --
111+
112+
train_file = 'data/chinese.train.txt'
113+
test_file = 'data/chinese.test.txt'
114+
vocab_file = 'data/vocab_cn.txt' # the file to save vocab
115+
116+
build_vocab_method = 'fixed_size' # 'frequency' or 'fixed_size'
117+
vocab_max_size = 3000 # when build_vocab_method = 'fixed_size'
118+
unk_threshold = 1 # # when build_vocab_method = 'frequency'
119+
120+
min_sentence_length = 3
121+
max_sentence_length = 60
122+
```
123+
124+
其中,`build_vocab_method `指定了构建词典的方法:**1,按词频**,即将出现次数小于`unk_threshold `的词视为`<UNK>`**2,按词典长度**`vocab_max_size`定义了词典的最大长度,如果语料中出现的不同词的个数大于这个值,则根据各词的词频倒序排,取`top(vocab_max_size)`个词纳入词典。
125+
126+
其中`min_sentence_length``max_sentence_length `分别指定了句子的最小和最大长度,小于最小长度的和大于最大长度的句子将被过滤掉、不参与训练。
127+
128+
*注:需要注意的是词典越大生成的内容越丰富但训练耗时越久,一般中文分词之后,语料中不同的词能有几万乃至几十万,如果vocab\_max\_size取值过小则导致\<UNK\>占比过高,如果vocab\_max\_size取值较大则严重影响训练速度(对精度也有影响),所以也有“按字”训练模型的方式,即:把每个汉字当做一个词,常用汉字也就几千个,使得字典的大小不会太大、不会丢失太多信息,但汉语中同一个字在不同词中语义相差很大,有时导致模型效果不理想。建议用户多试试、根据实际情况选择是“按词训练”还是“按字训练”。*
129+
130+
### 模型适配、训练
131+
132+
* 按需调整`config.py`中对于模型的配置,详解如下:
133+
134+
```python
135+
# -- config : train --
136+
137+
use_which_model = 'rnn' # must be: 'rnn' or 'ngram'
138+
use_gpu = False # whether to use gpu
139+
trainer_count = 1 # number of trainer
140+
141+
142+
class Config_rnn(object):
143+
"""
144+
config for RNN language model
145+
"""
146+
rnn_type = 'gru' # or 'lstm'
147+
emb_dim = 200
148+
hidden_size = 200
149+
num_layer = 2
150+
num_passs = 2
151+
batch_size = 32
152+
model_file_name_prefix = 'lm_' + rnn_type + '_params_pass_'
153+
154+
155+
class Config_ngram(object):
156+
"""
157+
config for N-Gram language model
158+
"""
159+
emb_dim = 200
160+
hidden_size = 200
161+
num_layer = 2
162+
N = 5
163+
num_passs = 2
164+
batch_size = 32
165+
model_file_name_prefix = 'lm_ngram_pass_'
166+
```
167+
168+
其中,`use_which_model`指定了要train的模型,如果使用RNN语言模型则设置为'rnn',如果使用N-Gram语言模型则设置为'ngram'`use_gpu`指定了train的时候是否使用gpu;`trainer_count`指定了并行度、用几个trainer去train模型;`rnn_type` 用于配置rnn cell类型,可以取‘lstm’或‘gru’;`hidden_size`配置unit个数;`num_layer`配置RNN的层数;`num_passs`配置训练的轮数;`emb_dim`配置embedding的dimension;`batch_size `配置了train model时每个batch的大小;`model_file_name_prefix `配置了要保存的模型的名字前缀。
169+
170+
* 运行`python train.py`命令训练模型,模型将被保存到当前目录。
171+
172+
### 按需生成文本
173+
174+
* 按需调整`config.py`中对于infer的配置,详解如下:
175+
176+
```python
177+
# -- config : infer --
178+
179+
input_file = 'data/input.txt' # input file contains sentence prefix each line
180+
output_file = 'data/output.txt' # the file to save results
181+
num_words = 10 # the max number of words need to generate
182+
beam_size = 5 # beam_width, the number of the prediction sentence for each prefix
183+
```
184+
185+
其中,`input_file`中保存的是带生成的文本前缀,utf-8编码,每个前缀占一行,形如:
186+
187+
```text
188+
189+
我 是
190+
```
191+
用户将需要生成的文本前缀按此格式存入文件即可;
192+
`num_words`指定了要生成多少个单词(实际生成过程中遇到结束符会停止生成,所以实际生成的词个数可能会比此值小);`beam_size`指定了beam search方法的width,即每个前缀生成多少个候选词序列;`output_file`指定了生成结果的存放位置。
193+
194+
* 运行`python infer.py`命令生成文本,生成的结果格式如下:
195+
196+
```text
197+
198+
<EOS> 0.107702672482
199+
我 爱 。我 中国 中国 <EOS> 0.000177299271939
200+
我 爱 中国 。我 是 中国 <EOS> 4.51695544709e-05
201+
我 爱 中国 中国 <EOS> 0.000910127729821
202+
我 爱 中国 。我 是 <EOS> 0.00015957862922
203+
```
204+
其中,‘我’是前缀,其下方的五个句子时补全的结果,每个句子末尾的浮点数表示此句子的生成概率。

language_model/config.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# coding=utf-8
2+
3+
# -- config : data --
4+
5+
train_file = 'data/chinese.train.txt'
6+
test_file = 'data/chinese.test.txt'
7+
vocab_file = 'data/vocab_cn.txt' # the file to save vocab
8+
9+
build_vocab_method = 'fixed_size' # 'frequency' or 'fixed_size'
10+
vocab_max_size = 3000 # when build_vocab_method = 'fixed_size'
11+
unk_threshold = 1 # # when build_vocab_method = 'frequency'
12+
13+
min_sentence_length = 3
14+
max_sentence_length = 60
15+
16+
# -- config : train --
17+
18+
use_which_model = 'ngram' # must be: 'rnn' or 'ngram'
19+
use_gpu = False # whether to use gpu
20+
trainer_count = 1 # number of trainer
21+
22+
23+
class Config_rnn(object):
24+
"""
25+
config for RNN language model
26+
"""
27+
rnn_type = 'gru' # or 'lstm'
28+
emb_dim = 200
29+
hidden_size = 200
30+
num_layer = 2
31+
num_passs = 2
32+
batch_size = 32
33+
model_file_name_prefix = 'lm_' + rnn_type + '_params_pass_'
34+
35+
36+
class Config_ngram(object):
37+
"""
38+
config for N-Gram language model
39+
"""
40+
emb_dim = 200
41+
hidden_size = 200
42+
num_layer = 2
43+
N = 5
44+
num_passs = 2
45+
batch_size = 32
46+
model_file_name_prefix = 'lm_ngram_pass_'
47+
48+
49+
# -- config : infer --
50+
51+
input_file = 'data/input.txt' # input file contains sentence prefix each line
52+
output_file = 'data/output.txt' # the file to save results
53+
num_words = 10 # the max number of words need to generate
54+
beam_size = 5 # beam_width, the number of the prediction sentence for each prefix
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
我 是 中国 人 。
2+
我 爱 中国 。我 是 中国 人 。
3+
我 爱 中国 。我 是 中国 人 。
4+
我 爱 中国 。我 是 中国 人 。
5+
我 爱 中国 。我 是 中国 人 。
6+
我 爱 中国 。我 是 中国 人 。
7+
我 爱 中国 。我 是 中国 人 。
8+
我 爱 中国 。我 是 中国 人 。
9+
我 爱 中国 。我 是 中国 人 。
10+
我 爱 中国 。我 是 中国 人 。
11+
我 爱 中国 。我 是 中国 人 。
12+
我 爱 中国 。我 是 中国 人 。
13+
我 爱 中国 。我 是 中国 人 。
14+
我 爱 中国 。我 是 中国 人 。
15+
我 爱 中国 。我 是 中国 人 。
16+
我 爱 中国 。我 是 中国 人 。
17+
我 爱 中国 。我 是 中国 人 。
18+
我 爱 中国 。我 是 中国 人 。
19+
我 爱 中国 。我 是 中国 人 。
20+
我 爱 中国 。我 是 中国 人 。
21+
我 爱 中国 。我 是 中国 人 。
22+
我 爱 中国 。我 是 中国 人 。
23+
我 爱 中国 。我 是 中国 人 。
24+
我 爱 中国 。我 是 中国 人 。
25+
我 爱 中国 。我 是 中国 人 。
26+
我 爱 中国 。我 是 中国 人 。
27+
我 爱 中国 。我 是 中国 人 。
28+
我 爱 中国 。我 是 中国 人 。
29+
我 爱 中国 。我 是 中国 人 。
30+
我 爱 中国 。我 是 中国 人 。
31+
我 爱 中国 。我 是 中国 人 。
32+
我 爱 中国 。我 是 中国 人 。
33+
我 爱 中国 。我 是 中国 人 。
34+
我 爱 中国 。我 是 中国 人 。
35+
我 爱 中国 。我 是 中国 人 。
36+
我 爱 中国 。我 是 中国 人 。
37+
我 爱 中国 。我 是 中国 人 。
38+
我 爱 中国 。我 是 中国 人 。
39+
我 爱 中国 。
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
我 是 中国 人 。
2+
我 爱 中国 。我 是 中国 人 。
3+
我 爱 中国 。我 是 中国 人 。
4+
我 爱 中国 。我 是 中国 人 。
5+
我 爱 中国 。我 是 中国 人 。
6+
我 爱 中国 。我 是 中国 人 。
7+
我 爱 中国 。我 是 中国 人 。
8+
我 爱 中国 。我 是 中国 人 。
9+
我 爱 中国 。我 是 中国 人 。
10+
我 爱 中国 。我 是 中国 人 。
11+
我 爱 中国 。我 是 中国 人 。
12+
我 爱 中国 。我 是 中国 人 。
13+
我 爱 中国 。我 是 中国 人 。
14+
我 爱 中国 。我 是 中国 人 。
15+
我 爱 中国 。我 是 中国 人 。
16+
我 爱 中国 。我 是 中国 人 。
17+
我 爱 中国 。我 是 中国 人 。
18+
我 爱 中国 。我 是 中国 人 。
19+
我 爱 中国 。我 是 中国 人 。
20+
我 爱 中国 。我 是 中国 人 。
21+
我 爱 中国 。我 是 中国 人 。
22+
我 爱 中国 。我 是 中国 人 。
23+
我 爱 中国 。我 是 中国 人 。
24+
我 爱 中国 。我 是 中国 人 。
25+
我 爱 中国 。我 是 中国 人 。
26+
我 爱 中国 。我 是 中国 人 。
27+
我 爱 中国 。我 是 中国 人 。
28+
我 爱 中国 。我 是 中国 人 。
29+
我 爱 中国 。我 是 中国 人 。
30+
我 爱 中国 。我 是 中国 人 。
31+
我 爱 中国 。我 是 中国 人 。
32+
我 爱 中国 。我 是 中国 人 。
33+
我 爱 中国 。我 是 中国 人 。
34+
我 爱 中国 。我 是 中国 人 。
35+
我 爱 中国 。我 是 中国 人 。
36+
我 爱 中国 。我 是 中国 人 。
37+
我 爱 中国 。我 是 中国 人 。
38+
我 爱 中国 。我 是 中国 人 。
39+
我 爱 中国 。

language_model/data/input.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
我 是
3+
我 是 中国
4+
我 爱
5+
我 是 中国 人。
6+
我 爱 中国
7+
我 爱 中国 。我
8+
我 爱 中国 。我 爱
9+
我 爱 中国 。我 是
10+
我 爱 中国 。我 是 中国

language_model/images/lstm.png

213 KB
Loading

language_model/images/ngram.png

67.1 KB
Loading

language_model/images/ps.png

1.85 KB
Loading

language_model/images/ps2.png

1.65 KB
Loading

language_model/images/rnn.png

335 KB
Loading

0 commit comments

Comments
 (0)