关于循环神经网络的介绍可以参考:
https://blog.csdn.net/lilong117194/article/details/82958326
这里强烈建议先搞明白上述参考链接中的一些基本概念和例子,再读下面的代码。

PTB 数据集下载:http://www.fit.vutbr.cz/~imikolov/rnnlm/simple-examples.tgz

1. 自然语言建模

简单的说,自然语言建模的目的就是为了计算一个句子出现的概率。在这里把句子看做是单词的序列,于是自然语言模型需要计算的就是p(w1,w2,..wn)p(w_1,w_2,..w_n)p(w1,w2,..wn)。然后利用语言模型,可以确定哪个单词序列出现的可能性更大,或者给定若干个单词,可以预测下一个最可能出现的词语。
举个音字转换的例子:假设输入的拼音字符串为“xianzaiquna”,它的输出可以是“西安在去哪”,同样也可以是“现在去哪”。根据语言常识可以知道,应该转换为后者的概率更大,而这时的语言模型就可以得到后者的概率大于前者,这就是语言模型的作用。

那么如何计算一个句子的概率呢?首先一个句子可以被看做单词组成的序列:
s=(w1,w2,w3...wm)s = (w_1,w_2,w_3 ... w_m)s=(w1,w2,w3...wm)
其中 m 是下标,表示句子的长度。那么,它的概率可以表示成:

p(s)=p(w1,w2,w3...wm)=p(w1)p(w2∣w1)p(w3∣w1,w2)...p(wm∣w1,w2,...,wm−1)p(s) = p(w_1,w_2,w_3 ... w_m) = p(w_1)p(w_2|w_1)p(w_3|w_1,w_2) ... p(w_m|w_1,w_2, ... ,w_{m-1})p(s)=p(w1,w2,w3...wm)=p(w1)p(w2w1)p(w3w1,w2)...p(wmw1,w2,...,wm1)

要计算句子出现的概率,就得知道上面公式中等式右边每一项的取值。但是任何一门语言的词汇量都是极大的,这样我们无法根据这个公式计算概率,因为计算复杂度无可估量。于是我们采用估算的方法,常用的是:n-gram方法、决策树、最大熵模型、条件随机场、神经网络语言模型。这里只介绍 n-gram 模型和循环神经网络的方法。

1.1 n-gram 模型的及其评价标准

n-gram 模型基于一个重要的有限历史假设:当前单词出现的概率仅仅取决于它的前 n-1 个单词,即p(wm∣w1,w2,...,wm−1)≈p(wi∣wi−n+1,...,wi−1)p(w_m|w_1,w_2, ... ,w_{m-1})\approx p(w_i|w_{i-n+1}, ... ,w_{i-1})p(wmw1,w2,...,wm1)p(wiwin+1,...,wi1)因此上面的P(S)可以近似p(S)=p(w1,w2,w3...wm)=∏imp(wi∣wi−n+1,...,wi−1)p(S) = p(w_1,w_2,w_3 ... w_m) =\prod _i ^m p(w_i|w_{i-n+1}, ... ,w_{i-1})p(S)=p(w1,w2,w3...wm)=imp(wiwin+1,...,wi1),而这里通常 n 指的是当前单词依赖它前面的单词个数。通常可以取 1,2,3 对应的模型分别称为 unigram,bigram和 trigram 模型。所以n—gram模型需要估计的参数为条件概率:p(wi∣wi−n+1,...,wi−1)p(w_i|w_{i-n+1}, ... ,w_{i-1})p(wiwin+1,...,wi1),所以有:

  • 在1-gram模型下:
    P(w1,w2,w3,…,wn)=P(w1)P(w2∣w1)P(w3∣w1w2)P(w4∣w1w2w3)…P(wn∣w1w2…wn−1)≈P(w1)P(w2)P(w3)P(w4)…P(wn)P(w_1, w_2, w_3, … , w_n)=P(w_1)P(w_2|w_1)P(w_3|w_1w_2)P(w_4|w_1w_2w_3)…P(w_n|w_1w_2…w_{n-1})≈P(w_1)P(w_2)P(w_3)P(w_4)…P(w_n)P(w1,w2,w3,,wn)=P(w1)P(w2w1)P(w3w1w2)P(w4w1w2w3)P(wnw1w2wn1)P(w1)P(w2)P(w3)P(w4)P(wn)
  • 在2-gram模型下:
    P(w1,w2,w3,…,wn)=P(w1)P(w2∣w1)P(w3∣w1w2)P(w4∣w1w2w3)…P(wn∣w1w2…wn−1)≈P(w1)P(w2∣w1)P(w3∣w2)P(w4∣w3)…P(wn∣wn−1)P(w_1, w_2, w_3, … , w_n)=P(w_1)P(w_2|w_1)P(w_3|w_1w_2)P(w_4|w_1w_2w_3)…P(w_n|w_1w_2…w_{n-1})≈P(w_1)P(w_2|w_1)P(w_3|w_2)P(w_4|w_3)…P(w_n|w_{n-1})P(w1,w2,w3,,wn)=P(w1)P(w2w1)P(w3w1w2)P(w4w1w2w3)P(wnw1w2wn1)P(w1)P(w2w1)P(w3w2)P(w4w3)P(wnwn1)
  • 在3-gram模型下:
    P(w1,w2,w3,…,wn)=P(w1)P(w2∣w1)P(w3∣w1w2)P(w4∣w1w2w3)…P(wn∣w1w2…wn−1)≈P(w1)P(w2∣w1)P(w3∣w1w2)P(w4∣w2w3)…P(wn∣wn−2wn−1)P(w_1, w_2, w_3, … , w_n)=P(w_1)P(w_2|w_1)P(w_3|w_1w_2)P(w_4|w_1w_2w_3)…P(w_n|w_1w_2…w_{n-1}) ≈P(w_1)P(w_2|w_1)P(w_3|w_1w_2)P(w_4|w_2w_3)…P(w_n|w_{n-2}w_{n-1}) P(w1,w2,w3,,wn)=P(w1)P(w2w1)P(w3w1w2)P(w4w1w2w3)P(wnw1w2wn1)P(w1)P(w2w1)P(w3w1w2)P(w4w2w3)P(wnwn2wn1)
  • 在4-gram模型下:
    P(w1,w2,w3,…,wn)=P(w1)P(w2∣w1)P(w3∣w1w2)P(w4∣w1w2w3)…P(wn∣w1w2…wn−1)≈P(w1)P(w2∣w1)P(w3∣w1w2)P(w4∣w1w2w3)…P(wn∣wn−3wn−2wn−1)P(w_1, w_2, w_3, … , w_n)=P(w_1)P(w_2|w_1)P(w_3|w_1w_2)P(w_4|w_1w_2w_3)…P(w_n|w_1w_2…w_{n-1})≈P(w_1)P(w_2|w_1)P(w_3|w_1w_2)P(w_4|w_1w_2w_3)…P(w_n|w_{n-3}w_{n-2}w_{n-1})P(w1,w2,w3,,wn)=P(w1)P(w2w1)P(w3w1w2)P(w4w1w2w3)P(wnw1w2wn1)P(w1)P(w2w1)P(w3w1w2)P(w4w1w2w3)P(wnwn3wn2wn1)

假设某种语言的单词表大小为 k,那么我们可以计算出 n-gram 模型需要估计的不同参数数量为k的n次方(庆幸不是k的k次方)。高于四元的用的很少,因为训练它需要更庞大的语料,而且数据稀疏严重,时间复杂度高,精确度却提高的不多。而n-gram模型的参数估计一般采用最大似然估计(maximun likelihood estimation,MLE)的计算方法:
p(wi∣wi−n+1,...,wi−1)=C(wi,wi−n+1,...,wi−1)C(wi−n+1,...,wi−1)p(w_i|w_{i-n+1}, ... ,w_{i-1})=\frac{C(w_i,w_{i-n+1}, ... ,w_{i-1})}{C(w_{i-n+1}, ... ,w_{i-1})}p(wiwin+1,...,wi1)=C(win+1,...,wi1)C(wi,win+1,...,wi1)
其中C(X)C(X)C(X)表示单词序列X在训练语料中出现的次数。也就是说,训练语料越大,参数估计的结果越可靠。但是还有一个问题存在,那就是即使训练的语料再大,也会有在训练中没有出现过的n-gram 序列出现,这就会导致很多参数为0,为了避免乘以0而导致整个概率为0,使用最大似然估计方法时都需要加入平滑避免参数取值为 0 。
语言模型的好坏常用的评价指标是复杂度 perplexity 。perplexity 值刻画的就是通过某一个语言模型估计的一句话出现的概率。比如当已知(w1,w2,w3,…,Wm)这句话出现在语料库之中,那么通过语言模型计算得到这句话的概率就越高越好,也就是 perplexity 值越小越好。令 perplexity 为:
mperplexity(S)=p(w1,w2,w3...wm)−1m=1p(w1,w2,w3...wm)m=1∏i=1mp(wi∣w1,w2...,wi−1)m=1∏i=1mp(wi∣wi−n+1,...,wi−1)mmperplexity(S)= p(w_1,w_2,w_3 ... w_m)^{-\frac{1}{m}}=\sqrt[m]{\frac{1}{p(w_1,w_2,w_3 ... w_m)}}=\sqrt[m]{\frac{1}{\prod_{i=1}^mp(w_i|w_1,w_2 ... ,w_{i-1})}}=\sqrt[m]{\frac{1}{\prod_{i=1}^mp(w_i|w_{i-n+1}, ... ,w_{i-1})}}mperplexity(S)=p(w1,w2,w3...wm)m1=mp(w1,w2,w3...wm)1

=mi=1mp(wiw1,w2...,wi1)1

=
mi=1mp(wiwin+1,...,wi1)1


其中n为n-gram模型中的n。
另一种表示方式:
log(perplexity(s))=−∑p(wi∣w1,w2...wi−1)mlog(perplexity(s))=\frac{-\sum p(w_i|w_1,w_2...w_{i-1})}{m}log(perplexity(s))=mp(wiw1,w2...wi1)
相比第一种乘积开根号的表示形式,这里使用加法的形式可以加速计算,这也有效的避免了概率为0时导致整个计算结果为0的问题。

复杂度perplexity表示的是平均分支系数(average branch factor),即模型预测下一个词时的平均可选择数量。

例如:考虑一个由0-9这10个数字随机组成的长度为m的序列。由于这10个数字出现的概率是随机的,所以每个数字出现的概率是110\frac{1}{10}101。因此在任意时刻,模型都有10个等概率的候选答案可以选择,于是perplexity的值就是10,计算过程:perplexity(s)=1∏i=1m110mperplexity(s)=\sqrt[m]{\frac{1}{\prod_{i=1}^m \frac{1}{10}}}perplexity(s)=mi=1m1011

。因此有一个语言模型的perplexity是89,就表示平均情况下,模型预测下一个词时,有89个词等可能地可以作为下一个词的选择。

1.2 rnn自然语言建模

除了 n-gram 模型,RNN 也可以用来对自然语言建模,如下图所示:

每个时刻的输入为一个句子中的单词,而每个时刻的输出为一个概率分布,表示句子中下一个位置为不同单词的概率。通过这种方式,对于给定的句子,就可以通过RNN的前向传播计算出p(wi∣w1,w2...wi−1)p(w_i|w_1,w_2...w_{i-1})p(wiw1,w2...wi1)
比如 “大海的颜色是蓝色” 这句话的概率,知道第一个单词是 “大海” 后,计算 p(“的”|“大海”) = 0.8,然后计算 p(x|“大海”,"的“) 、p(x|“大海”,“的”,“颜色”)、p(x|“大海”,“的”,“颜色”,“是”)。以此类推,就可以求出整句话 “大海的颜色是蓝色” 的概率。

2. 基于PTB文本数据集的自然语言模型

PTB(penn treebank dataset)文本数据集是语言模型学习中最广泛使用的数据集。下载 PTB 数据集:http://www.fit.vutbr.cz/~imikolov/rnnlm/simple-examples.tgz 解压后获取 data 目录下的三个文件:
ptb.train.txt 训练集
ptb.valid.txt 验证集
ptb.test.txt 测试集
这三个数据文件夹中的数据已经经过了预处理,包含了1000个不同的词语和语句结束标记符。TensorFlow 提供了 ptb_raw_data函数来读取PTB的数据,并将原始数据中的单词转换成单词 ID。

代码:

from tensorflow.models.tutorials.rnn.ptb import readerDATA_PATH="PTB_data"
train_data,valid_data,test_data,_=reader.ptb_raw_data(DATA_PATH)# 读取数据原始数据
print(len(train_data))
print(train_data[:100])

结果:

929589
[9970, 9971, 9972, 9974, 9975, 9976, 9980, 9981, 9982, 9983, 9984, 9986, 9987, 9988, 9989, 9991, 9992, 9993, 9994, 9995, 9996, 9997, 9998, 9999, 2, 9256, 1, 3, 72, 393, 33, 2133, 0, 146, 19, 6, 9207, 276, 407, 3, 2, 23, 1, 13, 141, 4, 1, 5465, 0, 3081, 1596, 96, 2, 7682, 1, 3, 72, 393, 8, 337, 141, 4, 2477, 657, 2170, 955, 24, 521, 6, 9207, 276, 4, 39, 303, 438, 3684, 2, 6, 942, 4, 3150, 496, 263, 5, 138, 6092, 4241, 6036, 30, 988, 6, 241, 760, 4, 1015, 2786, 211, 6, 96, 4]

训练数据总共包括929589个单词,而这些单词被组成了一个很长的序列。这个序列通过特殊的标识符给出了每句话结束的位置。而这个数据集中,句子结束的标识符id为2,从运行结果可以看出句子结束的位置。

构造训练集需要的batch:

import tensorflow as tf
from tensorflow.models.tutorials.rnn.ptb import readerDATA_PATH = "PTB_data"
train_data, valid_data, test_data, _ = reader.ptb_raw_data(DATA_PATH)
print ('Total length:',len(train_data))
print (train_data[:100])
print('..........................')tt=train_data[:100]
print(len(tt))
# 100个id分成4组,每组就是25个,截断长度为5,也就是25/5=5每组5批id,第25个id是9256
print('id:',tt[25])  """
将训练数据组织成batch大小为4、截断长度为5的数据组。并使用队列读取前3个batch。
即是:把原始的序列从第一个算起,平均分成4组,每组的大小是平均后的长度。而截断长度是从每组中从第一个开始截取长度为5
"""
# ptb_producer返回的为一个二维的tuple数据。
result = reader.ptb_producer(tt, 4, 5)
print(type(result))
# 通过队列依次读取batch。
with tf.Session() as sess:coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=sess, coord=coord)for i in range(5):x, y = sess.run(result)print ("X%d: "%i, x)print ("Y%d: "%i, y)coord.request_stop()coord.join(threads)

运行结果:

Total length: 929589
[9970, 9971, 9972, 9974, 9975, 9976, 9980, 9981, 9982, 9983, 9984, 9986, 9987, 9988, 9989, 9991, 9992, 9993, 9994, 9995, 9996, 9997, 9998, 9999, 2, 9256, 1, 3, 72, 393, 33, 2133, 0, 146, 19, 6, 9207, 276, 407, 3, 2, 23, 1, 13, 141, 4, 1, 5465, 0, 3081, 1596, 96, 2, 7682, 1, 3, 72, 393, 8, 337, 141, 4, 2477, 657, 2170, 955, 24, 521, 6, 9207, 276, 4, 39, 303, 438, 3684, 2, 6, 942, 4, 3150, 496, 263, 5, 138, 6092, 4241, 6036, 30, 988, 6, 241, 760, 4, 1015, 2786, 211, 6, 96, 4]
..........................
100
id: 9256
<class 'tuple'>
X0:  [[9970 9971 9972 9974 9975][9256    1    3   72  393][1596   96    2 7682    1][3684    2    6  942    4]]
Y0:  [[9971 9972 9974 9975 9976][   1    3   72  393   33][  96    2 7682    1    3][   2    6  942    4 3150]]
X1:  [[9976 9980 9981 9982 9983][  33 2133    0  146   19][   3   72  393    8  337][3150  496  263    5  138]]
Y1:  [[9980 9981 9982 9983 9984][2133    0  146   19    6][  72  393    8  337  141][ 496  263    5  138 6092]]
X2:  [[9984 9986 9987 9988 9989][   6 9207  276  407    3][ 141    4 2477  657 2170][6092 4241 6036   30  988]]
Y2:  [[9986 9987 9988 9989 9991][9207  276  407    3    2][   4 2477  657 2170  955][4241 6036   30  988    6]]
X3:  [[9991 9992 9993 9994 9995][   2   23    1   13  141][ 955   24  521    6 9207][   6  241  760    4 1015]]
Y3:  [[9992 9993 9994 9995 9996][  23    1   13  141    4][  24  521    6 9207  276][ 241  760    4 1015 2786]]
X4:  [[9970 9971 9972 9974 9975][9256    1    3   72  393][1596   96    2 7682    1][3684    2    6  942    4]]
Y4:  [[9971 9972 9974 9975 9976][   1    3   72  393   33][  96    2 7682    1    3][   2    6  942    4 3150]]

这里主要是为了送入循环神经网络而做的数据处理。将一个长序列分成batch并截断的操作示意图如下:

注意:
报错信息:
'AttributeError: module 'tensorflow.models.tutorials.rnn.ptb.reader' has no attribute 'ptb_iterator'
把读取 PTB 数据集的 reader的 ptb_iterator() 修改成ptb_producer()。

但还是会报错:
AttributeError: 'tuple' object has no attribute 'next',这是因为 ptb_producer() 返回的是 tuple,这时可以使用上述的方式通过建立session,使用队列来解决。

完整的RNN语言模型为:

import numpy as np
import tensorflow as tf
from tensorflow.models.tutorials.rnn.ptb import readerDATA_PATH = "PTB_data" # 数据存储路径
HIDDEN_SIZE = 200      # 隐藏层规模
NUM_LAYERS = 2         # 深层循环网络中lstm结构的层数
VOCAB_SIZE = 10000     # 词典规模,加上语句结束标示符和稀有单词标示符,总共一万多个单词LEARNING_RATE = 1.0    # 学习速率
TRAIN_BATCH_SIZE = 20  # 训练数据batch的大小
TRAIN_NUM_STEP = 35    # 截断长度# 在测试时不需要使用截断,可以将测试数据看成一个超长的序列
EVAL_BATCH_SIZE = 1    # 测试数据batch的大小
EVAL_NUM_STEP = 1      # 测试数据截断的长度
NUM_EPOCH = 2          # 使用训练数据的轮数
KEEP_PROB = 0.5        # 节点不被dropout的概率
MAX_GRAD_NORM = 5      # 用于控制梯度膨胀的参数# 通过一个PTBModel类来描述模型,这样方便维护循环神经网络中的状态
class PTBModel(object):# 记录使用的batch的大小和截断长度def __init__(self, is_training, batch_size, num_steps):# 使用batch的大小和截断长度self.batch_size = batch_sizeself.num_steps = num_steps    # 定义输入层:维度为batch_size x num_steps,这和ptb_producer的函数输出的数据batch是一致的。self.input_data = tf.placeholder(tf.int32, [batch_size, num_steps])# 定义预期输出:它和输入是对应的,标签就是该词汇对应的下一个词汇self.targets = tf.placeholder(tf.int32, [batch_size, num_steps])# 定义一个基础的LSTM结构作为循环体的基础结构,深层循环神经网络也支持使用其他的循环体。lstm_cell = tf.contrib.rnn.BasicLSTMCell(HIDDEN_SIZE)if is_training:# 训练时使用dropout的深层循环神经网络lstm_cell = tf.contrib.rnn.DropoutWrapper(lstm_cell, output_keep_prob=KEEP_PROB)# 通过MultiRNNCell类实现深层循环网络中的每一个时刻的前向传播过程cell = tf.contrib.rnn.MultiRNNCell([lstm_cell]*NUM_LAYERS)# 初始化最初的状态:也就是全0的向量self.initial_state = cell.zero_state(batch_size, tf.float32)"""下面是tensorflow中word2vec的构建"""# 将单词id转换为单词向量:因为总共有VOCAB_SIZE个单词,每个单词的向量维度为hidde_size,# 所以embedding参数的维度为10000x200embedding = tf.get_variable("embedding", [VOCAB_SIZE, HIDDEN_SIZE])        # 将原本batch_size x numk_steps个单词ID转为单词向量,# 转化后的输入层维度为batch_sizexnum_stepsxhidden_sizeinputs = tf.nn.embedding_lookup(embedding, self.input_data)# 只在训练时使用dropoutif is_training:inputs = tf.nn.dropout(inputs, KEEP_PROB)# 定义输出列表:在这里先将不同时刻的lstm结构的输出列表收集起来,再通过一个全连接层得到最终的输出outputs = []# state存储不同batch中lstm的“状态”,将其初始化为0state = self.initial_statewith tf.variable_scope("RNN"):# 这里num_steps是截断长度为35:为了避免梯度消散问题,会规定一个最大的序列长度,就是num_stepsfor time_step in range(num_steps): # 在第一个时刻需要声明网络中的变量,在之后的时刻都需要复用之前定义好的变量。if time_step > 0: tf.get_variable_scope().reuse_variables()# 每一步处理时间序列中的一个时刻。将当前的输入和前一时刻状态传入定义好的网络结构,# 可以得到当前的输出和更新的状态cell_output, state = cell(inputs[:, time_step, :], state)# 将当前输出加入到输出队列outputs.append(cell_output) # 把输出队列展开成[batch,hidden_size*num_steps]的形状,然后再reshape成[batch*num_steps,hidden_size]的形状# tf.concat(concat_dim, values, name='concat'),这里完全是为了后面全连接层的运算(3D化为2D)output = tf.reshape(tf.concat(outputs, 1), [-1, HIDDEN_SIZE])# 将从lstm中得到的输出再经过一个全连接层得到最后的预测结果,# 最终的预测结果在每一个时刻上都是一个长度为vocab_size的数组,经过softamx层之后表示下一个位置是不同单词的概率weight = tf.get_variable("weight", [HIDDEN_SIZE, VOCAB_SIZE])bias = tf.get_variable("bias", [VOCAB_SIZE])logits = tf.matmul(output, weight) + bias # [20x35,200]*[200x10000]+[10000]# 定义交叉熵损失函数:tf使用sequence_loss_by_example函数来计算一个序列的交叉熵的和loss = tf.contrib.legacy_seq2seq.sequence_loss_by_example([logits],                           # 预测的结果[tf.reshape(self.targets, [-1])],   # 期望的正确答案,这里将[batch,num_step]的二维数组压缩成一维数组# 损失的权重:这里所有的权重都为1,也就是说不同batch和不同时刻的重要程度是一样的[tf.ones([batch_size * num_steps], dtype=tf.float32)])# 计算得到每个batch的平均损失self.cost = tf.reduce_sum(loss) / batch_size self.final_state = state# 只在训练模型时定义反向传播操作。if not is_training: return trainable_variables = tf.trainable_variables()# 通过clip_by_global_norm函数控制梯度大小,避免梯度膨胀的问题。grads, _ = tf.clip_by_global_norm(tf.gradients(self.cost, trainable_variables), MAX_GRAD_NORM)# 定义优化方法optimizer = tf.train.GradientDescentOptimizer(LEARNING_RATE)# 定义训练步骤self.train_op = optimizer.apply_gradients(zip(grads, trainable_variables))# 使用给定的模型model在数据data上运行train_op并返回在全部数据上的perolexity值
def run_epoch(session, model, data, train_op, output_log, epoch_size):# 计算perplexity的辅助变量total_costs = 0.0iters = 0state = session.run(model.initial_state)# 使用当前数据训练或者测试模型for step in range(epoch_size):x, y = session.run(data)# 在当前batch上运行train_op并计算损失值,交叉熵损失函数计算的就是下一个单词为给定单词的概率cost, state, _ = session.run([model.cost, model.final_state, train_op],{model.input_data: x, model.targets: y, model.initial_state: state})    # 将不同时刻、不同batch的概率加起来再将这个和做指数运算就可以得到perplexity值(公式二)total_costs += costiters += model.num_steps# 只有在训练时输出日志if output_log and step % 100 == 0:print("After %d steps, perplexity is %.3f" % (step, np.exp(total_costs / iters)))# 返回给定模型在给定数据上的perplexity值return np.exp(total_costs / iters)def main():# 获得原始数据train_data, valid_data, test_data, _ = reader.ptb_raw_data(DATA_PATH)print ('length of traindata:',len(train_data))# 计算一个epoch需要训练的次数train_data_len = len(train_data)# 这里的‘//’是取整的意思train_batch_len = train_data_len // TRAIN_BATCH_SIZE# 这里得到的是每个batch可以分成多少个steptrain_epoch_size = (train_batch_len - 1) // TRAIN_NUM_STEPprint('train_epoch_size:',train_epoch_size)# 同上valid_data_len = len(valid_data)valid_batch_len = valid_data_len // EVAL_BATCH_SIZEvalid_epoch_size = (valid_batch_len - 1) // EVAL_NUM_STEPprint('valid_epoch_size:',valid_epoch_size)# 同上test_data_len = len(test_data)test_batch_len = test_data_len // EVAL_BATCH_SIZEtest_epoch_size = (test_batch_len - 1) // EVAL_NUM_STEPprint('test_epoch_size:',test_epoch_size)# 定义初始化函数initializer = tf.random_uniform_initializer(-0.05, 0.05)# 定义训练用的循环神经网络模型with tf.variable_scope("language_model", reuse=None, initializer=initializer):train_model = PTBModel(True, TRAIN_BATCH_SIZE, TRAIN_NUM_STEP)# 定义测试用的循环神经网络模型with tf.variable_scope("language_model", reuse=True, initializer=initializer):eval_model = PTBModel(False, EVAL_BATCH_SIZE, EVAL_NUM_STEP)# 训练模型。with tf.Session() as session:tf.global_variables_initializer().run()train_queue = reader.ptb_producer(train_data, train_model.batch_size, train_model.num_steps)eval_queue = reader.ptb_producer(valid_data, eval_model.batch_size, eval_model.num_steps)test_queue = reader.ptb_producer(test_data, eval_model.batch_size, eval_model.num_steps)coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=session, coord=coord)# 使用训练数据训练模型for i in range(NUM_EPOCH):print("In iteration: %d" % (i + 1))# 在所有的训练数据上训练循环神经网络run_epoch(session, train_model, train_queue, train_model.train_op, True, train_epoch_size)# 使用验证数据集评测数据效果valid_perplexity = run_epoch(session, eval_model, eval_queue, tf.no_op(), False, valid_epoch_size)print("Epoch: %d Validation Perplexity: %.3f" % (i + 1, valid_perplexity))# 使用测试数据集测试模型效果test_perplexity = run_epoch(session, eval_model, test_queue, tf.no_op(), False, test_epoch_size)print("Test Perplexity: %.3f" % test_perplexity)coord.request_stop()coord.join(threads)"""
主函数入口
"""
if __name__ == "__main__":main()

运行结果:

length of traindata: 929589
train_epoch_size: 1327
valid_epoch_size: 73759
test_epoch_size: 82429
In iteration: 1
After 0 steps, perplexity is 9980.495
After 100 steps, perplexity is 1389.408
After 200 steps, perplexity is 1021.756
After 300 steps, perplexity is 853.102
After 400 steps, perplexity is 746.115
After 500 steps, perplexity is 673.331
After 600 steps, perplexity is 621.486
After 700 steps, perplexity is 577.891
After 800 steps, perplexity is 538.988
After 900 steps, perplexity is 508.633
After 1000 steps, perplexity is 485.270
After 1100 steps, perplexity is 462.591
After 1200 steps, perplexity is 443.829
After 1300 steps, perplexity is 426.913
Epoch: 1 Validation Perplexity: 244.784
In iteration: 2
After 0 steps, perplexity is 370.560
After 100 steps, perplexity is 259.848
After 200 steps, perplexity is 264.565
After 300 steps, perplexity is 265.816
After 400 steps, perplexity is 263.193
After 500 steps, perplexity is 260.594
After 600 steps, perplexity is 260.226
After 700 steps, perplexity is 257.938
After 800 steps, perplexity is 253.309
After 900 steps, perplexity is 250.747
After 1000 steps, perplexity is 249.277
After 1100 steps, perplexity is 246.004
After 1200 steps, perplexity is 243.725
After 1300 steps, perplexity is 241.052
Epoch: 2 Validation Perplexity: 198.344
Test Perplexity: 191.840

通过输出可以看出,在迭代开始时perplexity值为9980.495,这也就是说相当于从10000个单词中随机选择下一个单词,而在训练结束后,perplexity的值降低到了 ,这说明通过训练将选择下一个单词的范围从10000个减少到大约190,当然还可以通过修改参数,把perplexity降低到更低。

基于tensorflow的RNN自然语言建模相关推荐

  1. 【深度学习系列(六)】:RNN系列(3):基于Tensorflow的RNN的实战之英文名字生成

    了解RNN的基本单元及其改进之后,接下来我们使用RNN进行一个简单的名字生成实战来了解实际使用中需要注意的地方及要点,废话不多说... 目录 一.数据预处理及加载 1.数据预处理 2.数据加载 二.R ...

  2. RNN循环神经网络的自我理解:基于Tensorflow的简单句子使用(通俗理解RNN)

    解读tensorflow之rnn: 该开始接触RNN我们都会看到这样的张图:  如上图可以看到每t-1时的forward的结果和t时的输入共同作为这一次forward的输入 所以RNN存在一定的弊端, ...

  3. TF之LSTM:基于Tensorflow框架采用PTB数据集建立LSTM网络的自然语言建模

    TF之LSTM:基于Tensorflow框架采用PTB数据集建立LSTM网络的自然语言建模 目录 关于PTB数据集 代码实现 关于PTB数据集 PTB (Penn Treebank Dataset)文 ...

  4. 利用Tensorflow构建RNN并对序列数据进行建模

    利用Tensorflow构建RNN并对序列数据进行建模 对文本处理处理任务的方法中,一般将TF-IDF向量作为特征输入.显然的缺陷是:这种方法丢失了输入的文本序列中每个单词的顺序. 对一般的前馈神经网 ...

  5. RNN循环神经网络的直观理解:基于TensorFlow的简单RNN例子

    RNN 直观理解 一个非常棒的RNN入门Anyone Can learn To Code LSTM-RNN in Python(Part 1: RNN) 基于此文章,本文给出我自己的一些愚见 基于此文 ...

  6. 基于tensorflow+RNN的MNIST数据集手写数字分类

    2018年9月25日笔记 tensorflow是谷歌google的深度学习框架,tensor中文叫做张量,flow叫做流. RNN是recurrent neural network的简称,中文叫做循环 ...

  7. TensorFlow练手项目二:基于循环神经网络(RNN)的古诗生成器

    基于循环神经网络(RNN)的古诗生成器 2019.01.02更新: 代码比较老了,当时的开发环境为Python 2.7 + TensorFlow 1.4,现在可能无法直接运行了.如果有兴趣,可以移步我 ...

  8. 【自然语言处理】3. NMT机器翻译案例实战(基于TensorFlow Addons Networks with Attention Mechanism)

    NLP系列讲解笔记 本专题是针对NLP的一些常用知识进行记录,主要由于本人接下来的实验需要用到NLP的一些知识点,但是本人非NLP方向学生,对此不是很熟悉,也是因为本人对NLP灰常感兴趣,想扎进去好好 ...

  9. 使用PaddleFluid和TensorFlow训练RNN语言模型

    专栏介绍:Paddle Fluid 是用来让用户像 PyTorch 和 Tensorflow Eager Execution 一样执行程序.在这些系统中,不再有模型这个概念,应用也不再包含一个用于描述 ...

最新文章

  1. 如何在StackOverflow上获得第一个标签徽章-以及为什么它很重要。
  2. Android WindowManager 解析与骗取 QQ 密码案例分析
  3. java.net.SocketException四大异常解决方案
  4. 使用mac 终端利用alias设置快捷命令
  5. 工业串口服务器如何使用
  6. [置顶]千年潜规则一语道破
  7. 大并发服务器不得不说的技术--TCP_CORK
  8. HoverTree.Model.ArticleSelect类的作用
  9. 计算机技能培训工作计划,计算机培训教学计划范文
  10. 叉车式AGV 时间窗问题
  11. 2017年第八届CSTQB®国际软件测试高峰论坛日程发布
  12. jupyter notebook如何导入excel数据
  13. K41H 老笔记本维修升级记
  14. Resource leak解决办法
  15. 「镁客·请讲」小库科技何宛余:用人工智能去更高效的协助建筑设计工作
  16. Android箭头图标移动动画实现
  17. VGG论文原文重点提炼解析
  18. 【面试准备】MySQL索引篇
  19. JAVA大数据需要学什么
  20. matlab图像处理--Otsu阈值分割

热门文章

  1. OpenCV高效准确的场景文本检测器(EAST)(附完整代码)
  2. OpenCV图像修补
  3. C++图形着色graph coloring算法(附完整源码)
  4. QT实现Three.js将Qt Quick项目用作纹理
  5. C语言编写扫雷小游戏
  6. 计算机办公应用高级教案,办公自动化高级应用电子教案.pdf
  7. Hadoop - YARN NodeManager 剖析、NodeManger内部架构、分布式缓存、目录结构、状态机管理、Container 生命周期剖、资源隔离
  8. 08_sklearn数据集,数据集划分train_test_split,sklearn.datasets及其api,sklearn分类数据集,sklearn回归数据集,转换器与预估器
  9. Spark远程调试配置,在IDEA中的配置
  10. Java 中按文件名称分类,按文件大小分类,按照文件类型分类,按照最后修改时间分类的工具类