NNLM初学习NNLM
在了解NNLM之前先了解一下词向量
词向量
我们人学过单词,汉字等等,能明白一句话。但是计算机只认识0和1,如何把语言让计算机看懂。将文本转化为向量。
词向量的方法是「one-hot(独热编码)表示法」
是最早的表示词向量的方法, 首先我们有一个词表,里面包括了我们可能会用到的所有词,每个词占据一个位置。那么词向量就是一个该词表维度大小的向量,词所在位置取值1,其它位置取值0。例如我们的词表有下面9个词:
你,我,他,是,谁,哪,里,来,自
“我”表示为向量[0, 1, 0, 0, 0, 0, 0, 0, 0],“是”表示为[0, 0, 0, 1, 0, 0, 0, 0, 0]
这样会可能会产生【维度灾难】和【语义鸿沟】
【维度灾难】:是因为如果词表过大,向量维度也过大,而且向量特别稀疏
【语义鸿沟】:因为每一个词向量1的位置不同,可以认为彼此相互正交(内积为0),任何两个内积为0,没有任何差别,体现不出来相似性。
为了弥补one-hot向量的这些缺陷,分布式向量(distributed representation) ,相似的词向量相似。这个与word enbedding关系, Representation → Distributed Reprensentation → word embedding ,词在基于神经网络的分布表示,好像同一个意思。
参考链接 (7 封私信 / 80 条消息) word2vec和word embedding有什么区别? – 知乎 (zhihu.com)
NNLM
Yoshua Bengio等人于2003年发表的《A Neural Probabilistic Language Model》针对N-gram模型的问题进行了解决。这是第一篇提出神经网络语言模型的论文,它在得到语言模型的同时也产生了副产品词向量。
论文链接:《A Neural Probabilistic Language Model》
输入层:
通过前n个词,来预测第n个单词
词向量W:是一个one-hot向量,大小=[10W,1],W(t)表示第t个词语的one hot(一个元素为1,其余全为0
投影矩阵C:维度[D*V],V=10W,参数D根据文本大小不同来设定:谷歌测试时选取D=300。
计算过程:
- 投影矩阵C[300 * 10W] X 词向量W(t)[10W *1] 得到= 矩阵[300 * 1]
- 比如根据前3个词来预测第4个词语,那么上述操作会重复三次,得到3个[300*1]的矩阵
- 将这3个[300*1]的矩阵按行拼接,得到[900×1]的矩阵。
形式类似:
隐藏层:
存在一个向量矩阵[Hx1],H根据文本集合情况设定(谷歌测试时选取H=500)
该层完成的功能主要是全连接!
说通俗一些:把输入层计算得到的矩阵[900×1],转换为矩阵[Hx1],完成输入层到隐藏层的数据传输,并且在全连接的过程中存在计算的权重。
最终得到矩阵[500×1]
输出层:
我们的词语大小为V=10W,隐藏层计算得到矩阵[500×1],要将这[500×1]的计算结果转化为[10Wx1],以此来预测第4个词语是什么?
得到矩阵[10Wx1],也就是所谓第4个词ont-hot,最终经过SoftMax激活函数,选取行向量最大值,就是预测词语。
# code by Tae Hwan Jung @graykodeimport torchimport torch.nn as nnimport torch.optim as optimdef make_batch(): input_batch = [] target_batch = [] for sen in sentences: word = sen.split() # space tokenizer input = [word_dict[n] for n in word[:-1]] # create (1~n-1) as input target = word_dict[word[-1]] # create (n) as target, We usually call this 'casual language model' input_batch.append(input) target_batch.append(target) return input_batch, target_batch# Modelclass NNLM(nn.Module): def __init__(self): super(NNLM, self).__init__() self.C = nn.Embedding(n_class, m) self.H = nn.Linear(n_step * m, n_hidden, bias=False) self.d = nn.Parameter(torch.ones(n_hidden)) self.U = nn.Linear(n_hidden, n_class, bias=False) self.W = nn.Linear(n_step * m, n_class, bias=False) self.b = nn.Parameter(torch.ones(n_class)) def forward(self, X): X = self.C(X) # X : [batch_size, n_step, m] X = X.view(-1, n_step * m) # resize [batch_size, n_step * m] tanh = torch.tanh(self.d + self.H(X)) # [batch_size, n_hidden] output = self.b + self.W(X) + self.U(tanh) # [batch_size, n_class] return outputif __name__ == '__main__': n_step = 2 # number of steps, n-1 in paper, n_hidden = 2 # number of hidden size, h in paper m = 2 # embedding size, m in paper sentences = ["i like dog", "i love coffee", "i hate milk"] word_list = " ".join(sentences).split() word_list = list(set(word_list)) word_dict = {w: i for i, w in enumerate(word_list)} number_dict = {i: w for i, w in enumerate(word_list)} n_class = len(word_dict) # number of Vocabulary model = NNLM() criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) input_batch, target_batch = make_batch() input_batch = torch.LongTensor(input_batch) target_batch = torch.LongTensor(target_batch) # Training for epoch in range(5000): optimizer.zero_grad() output = model(input_batch) # output : [batch_size, n_class], target_batch : [batch_size] loss = criterion(output, target_batch) if (epoch + 1) % 1000 == 0: print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.6f}'.format(loss)) loss.backward() optimizer.step() # Predict predict = model(input_batch).data.max(1, keepdim=True)[1] # Test print([sen.split()[:2] for sen in sentences], '->', [number_dict[n.item()] for n in predict.squeeze()])
nn.Embedding( num_embeddings , embedding_dim )详解:
num_embeddings – 词嵌入字典大小,即一个字典里要有多少个词
embedding_dim – 每个词嵌入向量的大小。
input_batch[3:2 ]——>C(X)——->[3,2,2],input_batch每个不相同数都有一个2维向量,相同数的向量相同。
nn.Linear(in_features,out_features,bias=False)详解:
in_features指的是输入的二维张量的大小,即输入的[batch_size, size]中的size。
out_features指的是输出的二维张量的大小,即输出的二维张量的形状为[batch_size,output_size],当然,它也代表了该全连接层的神经元个数。
从输入输出的张量的shape角度来理解,相当于一个输入为[batch_size, in_features]的张量变换成了[batch_size, out_features]的输出张量。
input = [1 , 100]nn.Linear(in_features = 100, out_features = 1)output = [1,1]
参考链接:
- 【语言模型】NNLM(神经网络语言模型)
- 神经网络语言模型NNLM
- 入门通俗易懂的神经网络语言模型(NNLM)详解
- 代码项目地址
- NN.linear