Repository: PaddlePaddle/models

Issue:
Add basic network configuration and training script for word embedding task
@lcy-seso 
Don't understand how to add prediction logic in the task.


Discussion:

Resolving patch:
diff --git a/word_embedding/hsigmoid_conf.py b/word_embedding/hsigmoid_conf.py
new file mode 100644
--- /dev/null
+++ b/word_embedding/hsigmoid_conf.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import math
+import paddle.v2 as paddle
+
+
+def network_conf(hidden_size, embed_size, dict_size, is_train=True):
+    first_word = paddle.layer.data(
+        name='firstw', type=paddle.data_type.integer_value(dict_size))
+    second_word = paddle.layer.data(
+        name='secondw', type=paddle.data_type.integer_value(dict_size))
+    third_word = paddle.layer.data(
+        name='thirdw', type=paddle.data_type.integer_value(dict_size))
+    fourth_word = paddle.layer.data(
+        name='fourthw', type=paddle.data_type.integer_value(dict_size))
+    target_word = paddle.layer.data(
+        name='fifthw', type=paddle.data_type.integer_value(dict_size))
+
+    embed_param_attr = paddle.attr.Param(
+        name="_proj", initial_std=0.001, learning_rate=1, l2_rate=0)
+    embed_first_word = paddle.layer.embedding(
+        input=first_word, size=embed_size, param_attr=embed_param_attr)
+    embed_second_word = paddle.layer.embedding(
+        input=second_word, size=embed_size, param_attr=embed_param_attr)
+    embed_third_word = paddle.layer.embedding(
+        input=third_word, size=embed_size, param_attr=embed_param_attr)
+    embed_fourth_word = paddle.layer.embedding(
+        input=fourth_word, size=embed_size, param_attr=embed_param_attr)
+
+    embed_context = paddle.layer.concat(input=[
+        embed_first_word, embed_second_word, embed_third_word, embed_fourth_word
+    ])
+
+    hidden_layer = paddle.layer.fc(
+        input=embed_context,
+        size=hidden_size,
+        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(embed_size * 8), learning_rate=1))
+
+    if is_train == True:
+        cost = paddle.layer.hsigmoid(
+            input=hidden_layer,
+            label=target_word,
+            num_classes=dict_size,
+            param_attr=paddle.attr.Param(name='sigmoid_w'),
+            bias_attr=paddle.attr.Param(name='sigmoid_b'))
+        return cost
+    else:
+        with paddle.layer.mixed(
+                size=dict_size - 1,
+                act=paddle.activation.Sigmoid(),
+                bias_attr=paddle.attr.Param(name='sigmoid_b')) as prediction:
+            prediction += paddle.layer.trans_full_matrix_projection(
+                input=hidden_layer,
+                param_attr=paddle.attr.Param(name='sigmoid_w'))
+        return prediction
diff --git a/word_embedding/hsigmoid_predict.py b/word_embedding/hsigmoid_predict.py
new file mode 100644
--- /dev/null
+++ b/word_embedding/hsigmoid_predict.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import paddle.v2 as paddle
+from hsigmoid_conf import network_conf
+import gzip
+
+
+def decode_res(infer_res, dict_size):
+    """
+    Inferring probabilities are orginized as a complete binary tree.
+    The actual labels are leaves (indices are counted from class number).
+    This function travels paths decoded from inferring results.
+    If the probability >0.5 then go to right child, otherwise go to left child.
+
+    param infer_res: inferring result
+    param dict_size: class number
+    return predict_lbls: actual class
+    """
+    predict_lbls = []
+    infer_res = infer_res > 0.5
+    for i, probs in enumerate(infer_res):
+        idx = 0
+        result = 1
+        while idx < len(probs):
+            result <<= 1
+            if probs[idx]:
+                result |= 1
+            if probs[idx]:
+                idx = idx * 2 + 2  # right child
+            else:
+                idx = idx * 2 + 1  # left child
+
+        predict_lbl = result - dict_size
+        predict_lbls.append(predict_lbl)
+    return predict_lbls
+
+
+def predict(batch_ins, idx_word_dict, dict_size, prediction_layer, parameters):
+    infer_res = paddle.infer(
+        output_layer=prediction_layer, parameters=parameters, input=batch_ins)
+
+    predict_lbls = decode_res(infer_res, dict_size)
+    predict_words = [idx_word_dict[lbl] for lbl in predict_lbls]  # map to word
+
+    # Ouput format: word1 word2 word3 word4 -> predict label
+    for i, ins in enumerate(batch_ins):
+        print(idx_word_dict[ins[0]] + ' ' + \
+            idx_word_dict[ins[1]] + ' ' + \
+            idx_word_dict[ins[2]] + ' ' + \
+            idx_word_dict[ins[3]] + ' ' + \
+         ' -> ' + predict_words[i])
+
+
+def main():
+    paddle.init(use_gpu=False, trainer_count=1)
+    word_dict = paddle.dataset.imikolov.build_dict(min_word_freq=2)
+    dict_size = len(word_dict)
+    prediction_layer = network_conf(
+        is_train=False, hidden_size=256, embed_size=32, dict_size=dict_size)
+
+    with gzip.open('./models/model_pass_00000.tar.gz') as f:
+        parameters = paddle.parameters.Parameters.from_tar(f)
+
+    idx_word_dict = dict((v, k) for k, v in word_dict.items())
+    batch_size = 64
+    batch_ins = []
+    ins_iter = paddle.dataset.imikolov.test(word_dict, 5)
+
+    for ins in ins_iter():
+        batch_ins.append(ins[:-1])
+        if len(batch_ins) == batch_size:
+            predict(batch_ins, idx_word_dict, dict_size, prediction_layer,
+                    parameters)
+            batch_ins = []
+
+    if len(batch_ins) > 0:
+        predict(batch_ins, idx_word_dict, dict_size, prediction_layer,
+                parameters)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/word_embedding/hsigmoid_train.py b/word_embedding/hsigmoid_train.py
new file mode 100644
--- /dev/null
+++ b/word_embedding/hsigmoid_train.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import paddle.v2 as paddle
+from hsigmoid_conf import network_conf
+import gzip
+
+
+def main():
+    paddle.init(use_gpu=False, trainer_count=1)
+    word_dict = paddle.dataset.imikolov.build_dict(min_word_freq=2)
+    dict_size = len(word_dict)
+    cost = network_conf(
+        is_train=True, hidden_size=256, embed_size=32, dict_size=dict_size)
+
+    def event_handler(event):
+        if isinstance(event, paddle.event.EndPass):
+            model_name = './models/model_pass_%05d.tar.gz' % event.pass_id
+            print("Save model into %s ..." % model_name)
+            with gzip.open(model_name, 'w') as f:
+                parameters.to_tar(f)
+
+        if isinstance(event, paddle.event.EndIteration):
+            if event.batch_id % 100 == 0:
+                result = trainer.test(
+                    paddle.batch(
+                        paddle.dataset.imikolov.test(word_dict, 5), 32))
+                print("Pass %d, Batch %d, Cost %f, Test Cost %f" %
+                      (event.pass_id, event.batch_id, event.cost, result.cost))
+
+    feeding = {
+        'firstw': 0,
+        'secondw': 1,
+        'thirdw': 2,
+        'fourthw': 3,
+        'fifthw': 4
+    }
+
+    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)
+
+    trainer.train(
+        paddle.batch(
+            paddle.reader.shuffle(
+                lambda: paddle.dataset.imikolov.train(word_dict, 5)(),
+                buf_size=1000), 64),
+        num_passes=30,
+        event_handler=event_handler,
+        feeding=feeding)
+
+
+if __name__ == '__main__':
+    main()


Test patch: