Word2vec
Table of Contents
1. Word2vec
在 的例子中, 使用了 word2vec
普通的 rnn 对单词的索引使用 one-hot 编码, 所以每个 feature 变成一个大小为 N (N 为单词的个数) 的 vector. 这种做法有两个问题:
- vector 太大且没有必要, 因为这个 vector 绝大部分都是 0
- 这个 vector 无法反映不同单词之间的相似性, 例如, apple 和 orange 很相似 (都是水果, 都可以吃,…), 相似表示两者可以互相替代, 机器学习时学习到的参数 (权重) 可以共享等
因此, 我们会使用一种称为 word2vec 或者叫 word embedding 的技术代替 one-hot 编码
word2vec 其实就是一个反映各个单词特征的 matrix, 例如:
king | queen | apple | orange | |
---|---|---|---|---|
human? | 0.99 | 0.98 | 0.01 | 0.01 |
fruit? | 0.01 | 0.02 | 0.99 | 0.98 |
food? | 0.01 | 0.01 | 0.99 | 0.99 |
size | ||||
… |
以上面特征 (human?, fruit?…) 是我们事先选定的, 但这个 matrix 实际上可以通过训练让机器自己学习到.
word embedding 和 CNN 中的卷积很像: 都是反映了数据的特征, 都可以通过训练学习到
1.1. 训练过程
word2vec 获得的 embedding 是通过训练得到的, 它是一个简单的使用非监督学习的网络:
从训练样本中选取一些词做为输入, 让它去预测另一个词, hidden layer 的输出即为 embedding
以 `the quick brown fox jumps over the lazy dog` 为例
1.1.1. n-gram
输入为连续 n 个词, 预测标签是第 n+1 个词:
当 n=3 时:
the quick brown -> fox quick brown fox -> jumps brown fox jumps -> over ...
由于训练时使用 3 个词做为输入, 但用来获得 embedding 时只使用 1 个词做为输入, 所以网络的设计也许可以这样:
def get_training_model(): input_1 = Input(N) input_2 = Input(N) input_3 = Input(N) embedding = Dense(EMBEDDING_SIZE) output_1 = embedding(input_1, name="output") output_2 = embedding(input_2) output_3 = embedding(input_3) output = Concatenate()[output_1, output_2, output_3] output = Dense(N)(output) output = Softmax()(output) return Model(input=[input_1, input_2, input_3], output=output) def get_eval_model(): model = get_training_model() model.load_weights("save.h5") return Model(input=model.inputs[0], output=model.get_layer("output").output)
1.1.2. cbow
用两边的词预测中间的词
the brown -> quick quick fox -> brown brown jumps -> fox ...
1.2. gensim
gensim 工具可以帮助我们进行上面的训练过程
from gensim.models import word2vec sentences = word2vec.Text8Corpus("../extra/xwz.txt") vec = word2vec.Word2Vec(sentences, size=50, iter=5, min_count=0) print(vec["我"]) print(vec["我"].shape) print(vec.wv.vocab["我"].index) print(vec.wv.vectors[5]) vocabulary = vec.wv.vocab.keys() #print(vocabulary)
[ 2.5379989e-01 -7.9855943e-01 2.1004373e-01 1.4060766e-01 1.5365046e+00 -1.2147485e-02 -1.1567525e+00 1.4223902e-01 -1.1346768e+00 6.0506749e-01 -8.8734490e-01 -5.5807270e-02 7.3605202e-02 -5.1732904e-01 8.1780031e-02 4.4866718e-02 -3.8633597e-01 -5.1058096e-01 -5.1415718e-01 -8.0242729e-01 -7.0677415e-02 2.1593498e-01 9.4420961e-05 1.5452372e-01 -4.0667549e-01 2.0172779e-01 -3.7259430e-01 -8.9318126e-01 1.7669131e-01 -6.7675710e-01 3.1780142e-01 -1.6200885e+00 6.8548656e-01 -2.7231857e-01 7.0585549e-01 3.9321697e-01 -8.2931936e-01 9.1785020e-01 -4.0526435e-01 1.2794651e-01 3.5713235e-01 6.9550622e-01 -3.1667909e-01 -4.8001361e-01 4.3599684e-02 -1.1073679e+00 9.8762310e-01 -4.1203447e-02 7.0740056e-01 5.6313020e-01] (50,) 5 [ 2.5379989e-01 -7.9855943e-01 2.1004373e-01 1.4060766e-01 1.5365046e+00 -1.2147485e-02 -1.1567525e+00 1.4223902e-01 -1.1346768e+00 6.0506749e-01 -8.8734490e-01 -5.5807270e-02 7.3605202e-02 -5.1732904e-01 8.1780031e-02 4.4866718e-02 -3.8633597e-01 -5.1058096e-01 -5.1415718e-01 -8.0242729e-01 -7.0677415e-02 2.1593498e-01 9.4420961e-05 1.5452372e-01 -4.0667549e-01 2.0172779e-01 -3.7259430e-01 -8.9318126e-01 1.7669131e-01 -6.7675710e-01 3.1780142e-01 -1.6200885e+00 6.8548656e-01 -2.7231857e-01 7.0585549e-01 3.9321697e-01 -8.2931936e-01 9.1785020e-01 -4.0526435e-01 1.2794651e-01 3.5713235e-01 6.9550622e-01 -3.1667909e-01 -4.8001361e-01 4.3599684e-02 -1.1073679e+00 9.8762310e-01 -4.1203447e-02 7.0740056e-01 5.6313020e-01] /usr/lib/python3.6/site-packages/ipykernel_launcher.py:4: DeprecationWarning: Call to deprecated `__getitem__` (Method will be removed in 4.0.0, use self.wv.__getitem__() instead). after removing the cwd from sys.path. /usr/lib/python3.6/site-packages/ipykernel_launcher.py:5: DeprecationWarning: Call to deprecated `__getitem__` (Method will be removed in 4.0.0, use self.wv.__getitem__() instead). """
more example about gensim and word2vec:
https://textminingonline.com/training-a-chinese-wikipedia-word2vec-model-by-gensim-and-jieba
1.3. pytorch.nn.Embedding
pytorch 的 nn.Embedding 是一个简单的 word2vec 的查找表, 可以支持 load 训练好的 word2vec weight:
self.encoder = torch.nn.Embedding(VOCABULARY_SIZE, FEATURE_SIZE) self.encoder.weight.data.copy_(torch.from_numpy(vec.wv.vectors)) self.encoder.requires_grad = False