其他分享
首页 > 其他分享> > Word2Vec

Word2Vec

作者:互联网

词嵌入

1.为什么使用词嵌入?

2.词嵌入的类比推理

1.观察向量man、woman、king和queen的嵌入向量,可以发现

$$
man-woman≈king-queen
$$

则可以知道单词之间的类比;同时根据向量差也可以看出,man和woman、king和queen在哪些特征上有差别(例如gender)
2.两个单词之间的相似度可以用余弦相似度衡量

3.学习词嵌入

学习词嵌入 -> 建立一个语言模型:

预测下一个单词 初始化一个参数矩阵,乘以各单词的one-hot向量,得到嵌入向量,把这些嵌入向量作为输入x放进神经网络,假设嵌入向量长度为n,句子已知单词数为m,则softmax分类器得到的向量维度是m×n,相当于把几个嵌入向量叠加在一起(实际中会设置一个固定的历史窗口,例如每次只看前/后k个词(也可同时看前和后),即窗口大小=k,,softmax层输入向量维度=k×n)
需要在m*n个可能的输出中预测这个单词(每个隐藏层包括softmax层都有自己的参数W和b)

4.Word2Vec:Skip-Gram(跳字模型)

采用Skip-Gram模型的Word2Vec算法: 基本步骤与3.学习词嵌入相同。不同之处在于,每次给定一个上下文词,然后选择目标词,但是每次并不只选前k个词,而是在一定词距内随机选择一个词
(从目标字词推测原始语句)

5.分级&负采样

由于softmax层向量维度过大,因此实践中往往会采用分级或负采样两种方法降低计算成本

分级

每次并不会直接精确到属于n个词中的哪一个词,而是采用二分类法,不断划分直至最后。分级方法的计算成本与log2(词汇表大小)成正比。
Tips:为了进一步降低成本,常用词往往会放到离树顶更近的位置。

负采样

对于每一个上下文词,在已选择正确的目标词,即有正类样本的基础上,会特意生成一系列负类样本。相当于一个样本一次迭代进行了多次训练。

# 
# code by Tae Hwan Jung @graykode
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt

def random_batch():
    random_inputs = []
    random_labels = []
    random_index = np.random.choice(range(len(skip_grams)), batch_size, replace=False)

    for i in random_index:
        random_inputs.append(np.eye(voc_size)[skip_grams[i][0]])  # target
        random_labels.append(skip_grams[i][1])  # context word

    return random_inputs, random_labels

# Model
class Word2Vec(nn.Module):
    def __init__(self):
        super(Word2Vec, self).__init__()
        # W and WT is not Traspose relationship
        self.W = nn.Linear(voc_size, embedding_size, bias=False) # voc_size > embedding_size Weight
        self.WT = nn.Linear(embedding_size, voc_size, bias=False) # embedding_size > voc_size Weight

    def forward(self, X):
        # X : [batch_size, voc_size]
        hidden_layer = self.W(X) # hidden_layer : [batch_size, embedding_size]
        output_layer = self.WT(hidden_layer) # output_layer : [batch_size, voc_size]
        return output_layer

if __name__ == '__main__':
    batch_size = 2 # mini-batch size
    embedding_size = 2 # embedding size

    sentences = ["apple banana fruit", "banana orange fruit", "orange banana fruit",
                 "dog cat animal", "cat monkey animal", "monkey dog animal"]

    word_sequence = " ".join(sentences).split()
    word_list = " ".join(sentences).split()
    word_list = list(set(word_list))
    word_dict = {w: i for i, w in enumerate(word_list)}
    voc_size = len(word_list)

    # Make skip gram of one size window
    skip_grams = []
    for i in range(1, len(word_sequence) - 1):
        target = word_dict[word_sequence[i]]
        context = [word_dict[word_sequence[i - 1]], word_dict[word_sequence[i + 1]]]
        for w in context:
            skip_grams.append([target, w])

    model = Word2Vec()

    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=0.001)

    # Training
    for epoch in range(5000):
        input_batch, target_batch = random_batch()
        input_batch = torch.Tensor(input_batch)
        target_batch = torch.LongTensor(target_batch)

        optimizer.zero_grad()
        output = model(input_batch)

        # output : [batch_size, voc_size], target_batch : [batch_size] (LongTensor, not one-hot)
        loss = criterion(output, target_batch)
        if (epoch + 1) % 1000 == 0:
            print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.6f}'.format(loss))

        loss.backward()
        optimizer.step()

    for i, label in enumerate(word_list):
        W, WT = model.parameters()
        x, y = W[0][i].item(), W[1][i].item()
        plt.scatter(x, y)
        plt.annotate(label, xy=(x, y), xytext=(5, 2), textcoords='offset points', ha='right', va='bottom')
    plt.show()

标签:嵌入,word,random,batch,Word2Vec,向量,size
来源: https://www.cnblogs.com/chengjunkai/p/16656849.html