文章目录
- 前言
- 神经语言模型(NNLM)
- 代码简析
- 结果
- 总结
- 参考
前言
最近看到一个Github内容不错,就当做个笔记。
神经语言模型(NNLM)
2003年,NNLM首次将神经网络应用到语言模型的问题中,从此深度学习就登上了NLP的舞台,并有把传统模型赶下去的趋势。
语言模型可以说是用前n-1个单词做为输入去预测第n个单词,也就是说第n个词是哪个单词的时候,才使得这句话像是正常的话,有正常的语序,使用正确且恰当的词。
下面我将结合代码理解NNLM。
代码简析
- 导入要用到的库。
import tensorflow as tf
import numpy as np
print(tf.__version__)
tf.reset_default_graph() # 重置图
- 使用三句话做为数据集,将数据集分词,每个词对应一个自然数形成word_dict字典。
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)}
- NNLM模型用到的参数。
n_class = len(word_dict) # 字典中词的种类
# NNLM Parameter
n_step = 2 # number of steps ['i like', 'i love', 'i hate']
n_hidden = 2 # number of hidden units
- 数据集中都是三个单词组组成,输入为前两个单词,标签是后一个单词。对数据进行one-hot编码,长度为n_class。
# 训练集是前两个词 标签是最后一个词 相当于one_hot
def make_batch(sentences):
input_batch = []
target_batch = []
for sen in sentences:
word = sen.split()
input = [word_dict[n] for n in word[:-1]]
target = word_dict[word[-1]]
input_batch.append(np.eye(n_class)[input])
target_batch.append(np.eye(n_class)[target])
return input_batch, target_batch
- 模型的初始化,单层二个神经元的全连接前馈网络。
# Model 初始化
X = tf.placeholder(tf.float32, [None, n_step, n_class]) # [batch_size, number of steps, number of Vocabulary]
Y = tf.placeholder(tf.float32, [None, n_class])
input = tf.reshape(X, shape=[-1, n_step * n_class]) # [batch_size, n_step * n_class]
H = tf.Variable(tf.random_normal([n_step * n_class, n_hidden]))
d = tf.Variable(tf.random_normal([n_hidden]))
U = tf.Variable(tf.random_normal([n_hidden, n_class]))
b = tf.Variable(tf.random_normal([n_class]))
tanh = tf.nn.tanh(d + tf.matmul(input, H)) # [batch_size, n_hidden]
model = tf.matmul(tanh, U) + b # [batch_size, n_class]
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=model, labels=Y))
optimizer = tf.train.AdamOptimizer(0.001).minimize(cost)
prediction =tf.argmax(model, 1) # 得到每行的最大值
- 训练
# Training
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
input_batch, target_batch = make_batch(sentences) # 得到数据
print("input_batch ",input_batch,len(input_batch),"\n","target_batch", target_batch,len(target_batch))
for epoch in range(5000):
_, loss = sess.run([optimizer, cost], feed_dict={X: input_batch, Y: target_batch})
if (epoch + 1)%1000 == 0:
print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.6f}'.format(loss))
- 验证结果
predict = sess.run([prediction], feed_dict={X: input_batch})
# Test
input = [sen.split()[:2] for sen in sentences]
print([sen.split()[:2] for sen in sentences], '->', [number_dict[n] for n in predict[0]])
结果
我们发现最终预测的结果和之前标签完全符合。
总结
- 本文实现的是简化版的NNLM,输入数据只是用了one-hot编码,缺点是当字典变得更长的时候one-hot的维度会非常大,NNLM使用了Embedding会减少维度,但是在优化参数的同时优化Embedding会导致参数变多。
- 还有一点而且最后softmax得到的输出和之前的Embeddign也可以当做词向量。词向量可以说是语言模型的副产品,最终青出于蓝而胜于蓝了。
- NNLM的缺点没有考虑词的顺序,也就是说两个词可能形成词组的问题。
- 个人理解,欢迎指出错误
参考
参考的Github:https:///graykode/nlp-tutorial 详细总结的代码:https:///Clayygou/NLP/blob/master/NNLM.ipynb