diff --git a/word2vec/README.md b/word2vec/README.md
index 1a942f4ec26cf2763977a57b2b8e9232c95f521e..ab793e4538b6f00e344ce798ba475defa9726ebe 100644
--- a/word2vec/README.md
+++ b/word2vec/README.md
@@ -1,3 +1,4 @@
+
# 词向量
本教程源代码目录在[book/word2vec](https://github.com/PaddlePaddle/book/tree/develop/word2vec), 初次使用请参考PaddlePaddle[安装教程](http://www.paddlepaddle.org/doc_cn/build_and_install/index.html)。
@@ -209,7 +210,7 @@ N = 5 # 训练5-Gram
- 将$w_t$之前的$n-1$个词 $w_{t-n+1},...w_{t-1}$,通过$|V|\times D$的矩阵映射到D维词向量(本例中取D=32)。
-```python
+```python
def wordemb(inlayer):
wordemb = paddle.layer.table_projection(
input=inlayer,
@@ -225,54 +226,54 @@ def wordemb(inlayer):
- 定义输入层接受的数据类型以及名字。
```python
-def main():
- paddle.init(use_gpu=False, trainer_count=1) # 初始化PaddlePaddle
- word_dict = paddle.dataset.imikolov.build_dict()
- dict_size = len(word_dict)
- # 每个输入层都接受整形数据,这些数据的范围是[0, dict_size)
- firstword = paddle.layer.data(
- name="firstw", type=paddle.data_type.integer_value(dict_size))
- secondword = paddle.layer.data(
- name="secondw", type=paddle.data_type.integer_value(dict_size))
- thirdword = paddle.layer.data(
- name="thirdw", type=paddle.data_type.integer_value(dict_size))
- fourthword = paddle.layer.data(
- name="fourthw", type=paddle.data_type.integer_value(dict_size))
- nextword = paddle.layer.data(
- name="fifthw", type=paddle.data_type.integer_value(dict_size))
-
- Efirst = wordemb(firstword)
- Esecond = wordemb(secondword)
- Ethird = wordemb(thirdword)
- Efourth = wordemb(fourthword)
+paddle.init(use_gpu=False, trainer_count=3) # 初始化PaddlePaddle
+word_dict = paddle.dataset.imikolov.build_dict()
+dict_size = len(word_dict)
+# 每个输入层都接受整形数据,这些数据的范围是[0, dict_size)
+firstword = paddle.layer.data(
+ name="firstw", type=paddle.data_type.integer_value(dict_size))
+secondword = paddle.layer.data(
+ name="secondw", type=paddle.data_type.integer_value(dict_size))
+thirdword = paddle.layer.data(
+ name="thirdw", type=paddle.data_type.integer_value(dict_size))
+fourthword = paddle.layer.data(
+ name="fourthw", type=paddle.data_type.integer_value(dict_size))
+nextword = paddle.layer.data(
+ name="fifthw", type=paddle.data_type.integer_value(dict_size))
+
+Efirst = wordemb(firstword)
+Esecond = wordemb(secondword)
+Ethird = wordemb(thirdword)
+Efourth = wordemb(fourthword)
+
```
- 将这n-1个词向量经过concat_layer连接成一个大向量作为历史文本特征。
```python
- contextemb = paddle.layer.concat(input=[Efirst, Esecond, Ethird, Efourth])
+contextemb = paddle.layer.concat(input=[Efirst, Esecond, Ethird, Efourth])
```
- 将历史文本特征经过一个全连接得到文本隐层特征。
```python
- hidden1 = paddle.layer.fc(input=contextemb,
- size=hiddensize,
- act=paddle.activation.Sigmoid(),
- layer_attr=paddle.attr.Extra(drop_rate=0.5),
- bias_attr=paddle.attr.Param(learning_rate=2),
- param_attr=paddle.attr.Param(
- initial_std=1. / math.sqrt(embsize * 8),
- learning_rate=1))
+hidden1 = paddle.layer.fc(input=contextemb,
+ size=hiddensize,
+ act=paddle.activation.Sigmoid(),
+ layer_attr=paddle.attr.Extra(drop_rate=0.5),
+ bias_attr=paddle.attr.Param(learning_rate=2),
+ param_attr=paddle.attr.Param(
+ initial_std=1. / math.sqrt(embsize * 8),
+ learning_rate=1))
```
- 将文本隐层特征,再经过一个全连接,映射成一个$|V|$维向量,同时通过softmax归一化得到这`|V|`个词的生成概率。
```python
- predictword = paddle.layer.fc(input=hidden1,
- size=dict_size,
- bias_attr=paddle.attr.Param(learning_rate=2),
- act=paddle.activation.Softmax())
+predictword = paddle.layer.fc(input=hidden1,
+ size=dict_size,
+ bias_attr=paddle.attr.Param(learning_rate=2),
+ act=paddle.activation.Softmax())
```
- 网络的损失函数为多分类交叉熵,可直接调用`classification_cost`函数。
@@ -288,11 +289,11 @@ cost = paddle.layer.classification_cost(input=predictword, label=nextword)
- 正则化(regularization): 是防止网络过拟合的一种手段,此处采用L2正则化。
```python
- parameters = paddle.parameters.create(cost)
- adam_optimizer = paddle.optimizer.Adam(
- learning_rate=3e-3,
- regularization=paddle.optimizer.L2Regularization(8e-4))
- trainer = paddle.trainer.SGD(cost, parameters, adam_optimizer)
+parameters = paddle.parameters.create(cost)
+adam_optimizer = paddle.optimizer.Adam(
+ learning_rate=3e-3,
+ regularization=paddle.optimizer.L2Regularization(8e-4))
+trainer = paddle.trainer.SGD(cost, parameters, adam_optimizer)
```
下一步,我们开始训练过程。`paddle.dataset.imikolov.train()`和`paddle.dataset.imikolov.test()`分别做训练和测试数据集。这两个函数各自返回一个reader——PaddlePaddle中的reader是一个Python函数,每次调用的时候返回一个Python generator。
@@ -300,111 +301,93 @@ cost = paddle.layer.classification_cost(input=predictword, label=nextword)
`paddle.batch`的输入是一个reader,输出是一个batched reader —— 在PaddlePaddle里,一个reader每次yield一条训练数据,而一个batched reader每次yield一个minbatch。
```python
- def event_handler(event):
- if isinstance(event, paddle.event.EndIteration):
- if event.batch_id % 100 == 0:
- result = trainer.test(
+import gzip
+
+def event_handler(event):
+ if isinstance(event, paddle.event.EndIteration):
+ if event.batch_id % 100 == 0:
+ print "Pass %d, Batch %d, Cost %f, %s" % (
+ event.pass_id, event.batch_id, event.cost, event.metrics)
+
+ if isinstance(event, paddle.event.EndPass):
+ result = trainer.test(
paddle.batch(
paddle.dataset.imikolov.test(word_dict, N), 32))
- print "Pass %d, Batch %d, Cost %f, %s, Testing metrics %s" % (
- event.pass_id, event.batch_id, event.cost, event.metrics,
- result.metrics)
-
- trainer.train(
- paddle.batch(paddle.dataset.imikolov.train(word_dict, N), 32),
- num_passes=30,
- event_handler=event_handler)
+ print "Pass %d, Testing metrics %s" % (event.pass_id, result.metrics)
+ with gzip.open("model_%d.tar.gz"%event.pass_id, 'w') as f:
+ parameters.to_tar(f)
+
+trainer.train(
+ paddle.batch(paddle.dataset.imikolov.train(word_dict, N), 32),
+ num_passes=100,
+ event_handler=event_handler)
```
-训练过程是完全自动的,event_handler里打印的日志类似如下所示:
+ ...
+ Pass 0, Batch 25000, Cost 4.251861, {'classification_error_evaluator': 0.84375}
+ Pass 0, Batch 25100, Cost 4.847692, {'classification_error_evaluator': 0.8125}
+ Pass 0, Testing metrics {'classification_error_evaluator': 0.7417652606964111}
+
+
+训练过程是完全自动的,event_handler里打印的日志类似如上所示:
-```text
-.............................
-I1222 09:27:16.477841 12590 TrainerInternal.cpp:162] Batch=3000 samples=300000 AvgCost=5.36135 CurrentCost=5.36135 Eval: classification_error_evaluator=0.818653 CurrentEval: class
-ification_error_evaluator=0.818653
-.............................
-I1222 09:27:22.416700 12590 TrainerInternal.cpp:162] Batch=6000 samples=600000 AvgCost=5.29301 CurrentCost=5.22467 Eval: classification_error_evaluator=0.814542 CurrentEval: class
-ification_error_evaluator=0.81043
-.............................
-I1222 09:27:28.343756 12590 TrainerInternal.cpp:162] Batch=9000 samples=900000 AvgCost=5.22494 CurrentCost=5.08876 Eval: classification_error_evaluator=0.810088 CurrentEval: class
-ification_error_evaluator=0.80118
-..I1222 09:27:29.128582 12590 TrainerInternal.cpp:179] Pass=0 Batch=9296 samples=929600 AvgCost=5.21786 Eval: classification_error_evaluator=0.809647
-I1222 09:27:29.627616 12590 Tester.cpp:111] Test samples=73760 cost=4.9594 Eval: classification_error_evaluator=0.79676
-I1222 09:27:29.627713 12590 GradientMachine.cpp:112] Saving parameters to model/pass-00000
-```
经过30个pass,我们将得到平均错误率为classification_error_evaluator=0.735611。
## 应用模型
-训练模型后,我们可以加载模型参数,用训练出来的词向量初始化其他模型,也可以将模型参数从二进制格式转换成文本格式进行后续应用。
-
-### 初始化其他模型
+训练模型后,我们可以加载模型参数,用训练出来的词向量初始化其他模型,也可以将模型查看参数用来做后续应用。
-训练好的模型参数可以用来初始化其他模型。具体方法如下:
-在PaddlePaddle 训练命令行中,用`--init_model_path` 来定义初始化模型的位置,用`--load_missing_parameter_strategy`指定除了词向量以外的新模型其他参数的初始化策略。注意,新模型需要和原模型共享被初始化参数的参数名。
### 查看词向量
-PaddlePaddle训练出来的参数为二进制格式,存储在对应训练pass的文件夹下。这里我们提供了文件`format_convert.py`用来互转PaddlePaddle训练结果的二进制文件和文本格式特征文件。
-```bash
-python format_convert.py --b2t -i INPUT -o OUTPUT -d DIM
-```
-其中,INPUT是输入的(二进制)词向量模型名称,OUTPUT是输出的文本模型名称,DIM是词向量参数维度。
+PaddlePaddle训练出来的参数可以直接使用`parameters.get()`获取出来。例如查看单词的word的词向量,即为
-用法如:
-```bash
-python format_convert.py --b2t -i model/pass-00029/_proj -o model/pass-00029/_proj.txt -d 32
-```
-转换后得到的文本文件如下:
+```python
+embeddings = parameters.get("_proj").reshape(len(word_dict), embsize)
-```text
-0,4,62496
--0.7444070,-0.1846171,-1.5771370,0.7070392,2.1963732,-0.0091410, ......
--0.0721337,-0.2429973,-0.0606297,0.1882059,-0.2072131,-0.7661019, ......
-......
+print embeddings[word_dict['word']]
```
-其中,第一行是PaddlePaddle 输出文件的格式说明,包含3个属性:
-1) PaddlePaddle的版本号,本例中为0;
-2) 浮点数占用的字节数,本例中为4;
-3) 总计的参数个数, 本例中为62496(即1953*32);
-第二行及之后的每一行都按顺序表示字典里一个词的特征,用逗号分隔。
+ [-0.38961065 -0.02392169 -0.00093231 0.36301503 0.13538605 0.16076435
+ -0.0678709 0.1090285 0.42014077 -0.24119169 -0.31847557 0.20410083
+ 0.04910378 0.19021918 -0.0122014 -0.04099389 -0.16924137 0.1911236
+ -0.10917275 0.13068172 -0.23079982 0.42699069 -0.27679482 -0.01472992
+ 0.2069038 0.09005053 -0.3282454 0.12717034 -0.24218646 0.25304323
+ 0.19072419 -0.24286366]
+
+
### 修改词向量
-我们可以对词向量进行修改,并转换成PaddlePaddle参数二进制格式,方法:
+获得到的embedding为一个标准的numpy矩阵。我们可以对这个numpy矩阵进行修改,然后赋值回去。
-```bash
-python format_convert.py --t2b -i INPUT -o OUTPUT
-```
-其中,INPUT是输入的输入的文本词向量模型名称,OUTPUT是输出的二进制词向量模型名称
-
-输入的文本格式如下(注意,不包含上面二进制转文本后第一行的格式说明):
+```python
+def modify_embedding(emb):
+ # Add your modification here.
+ pass
-```text
--0.7444070,-0.1846171,-1.5771370,0.7070392,2.1963732,-0.0091410, ......
--0.0721337,-0.2429973,-0.0606297,0.1882059,-0.2072131,-0.7661019, ......
-......
+modify_embedding(embeddings)
+parameters.set("_proj", embeddings)
```
-
-
### 计算词语之间的余弦距离
两个向量之间的距离可以用余弦值来表示,余弦值在$[-1,1]$的区间内,向量间余弦值越大,其距离越近。这里我们在`calculate_dis.py`中实现不同词语的距离度量。
用法如下:
-```bash
-python calculate_dis.py VOCABULARY EMBEDDINGLAYER`
-```
-其中,`VOCABULARY`是字典,`EMBEDDINGLAYER`是词向量模型,示例如下:
+```python
+from scipy import spatial
+
+emb_1 = embeddings[word_dict['world']]
+emb_2 = embeddings[word_dict['would']]
-```bash
-python calculate_dis.py data/vocabulary.txt model/pass-00029/_proj.txt
+print spatial.distance.cosine(emb_1, emb_2)
```
+
+ 0.99375076448
## 总结