接下来的内容,我们将详述这一神经网络的5大部分。占位符在这里用作模型的一个入口。LSTM神经元初始化后用于生成递归神经网络。
输出层各自相连,用于估量模型的误差。最后,我们会定义训练内容。
1)图形输入
with tf.name_scope("graph_inputs"):
inputs = tf.placeholder(tf.int32, [2, 10], name='placeholder_inputs')
targets = tf.placeholder(tf.int32, [2, 10], name='placeholder_targets')
keep_prob = tf.placeholder(tf.float32, name='placeholder_keep_prob')
这个批处理由两个大小为10的输入序列构成,因此输入的预期特征是[2, 10],批处理的每个入口都与单一输出相关联,目标的特征定义与此相同。最后,我们定义了一个用作概率值的占位符,用以表示后面的退出率(dropout)。
2)LSTM
with tf.name_scope("LSTM"):
def create_cell():
lstm = tf.contrib.rnn.BasicLSTMCell(4)
drop = tf.contrib.rnn.DropoutWrapper(lstm, output_keep_prob=keep_prob)
return drop
cell = tf.contrib.rnn.MultiRNNCell([create_cell() for _ in range(3)])
initial_state = cell.zero_state(2, tf.float32)
io_size = len(vocab)
x_one_hot = tf.one_hot(inputs, io_size)
cell_outputs, final_state = tf.nn.dynamic_rnn(cell, x_one_hot, initial_state=initial_state)
让我们来学习这份代码的每一部分:
create_cell() 用于生成由4个隐神经元所构成的LSTM神经元。在返回结果前,该函数还在cell输出中添加了一个退出项(dropout)。
tf.contrib.rnn.MultiRNNCell用于实例化递归神经网络。我们把给出的create_cell()数组作为参数,是因为我们希望得到由多层网络构成的递归神经网络。本例为三层。
initial_state:已知递归神经网络的每个神经元都依赖于先前的状态,因此我们必须实例化一个全是零的初始状态,它将作为批处理首批入口的输入。
x_one_hot将batch转化为独热编码。
cell_outputs给出递归神经网络每个细胞的输出。在本例中,每个输出由4个数值(隐神经元个数)构成。
final_state返回最后一个细胞的状态,在训练期间可用作下一个批处理的最新初始状态(假设下一个批处理是上一个批处理的逻辑延续)。
3)图形输出
with tf.name_scope("graph_outputs"):
seq_output_reshape = tf.reshape(cell_outputs, [-1, 4], name="reshape_x")
with tf.name_scope('output_layer'):
w = tf.Variable(tf.truncated_normal((4, io_size), stddev=0.1), name="weights")
b = tf.Variable(tf.zeros(io_size), name="bias")
logits = tf.add(tf.matmul(seq_output_reshape , w), b, name= "logits")
softmax = tf.nn.softmax(logits, name='predictions')
细胞的输出值被储存在一个三维特征表内[序列数,序列大小,神经元数],或为 [2, 10, 4]。我们无需按序列来分离输出。然后,改变输出值的维度以储存在seq_out_reshape的数组[20, 4]内。
最后,使用一个简单的线性运算:tf.matmul (..) + b。最后以softmax结尾,为的是用概率形式来表示输出。
4)损失
with tf.name_scope("Loss"):
y_one_hot = tf.one_hot(targets, io_size, name="y_to_one_hot")
y_reshaped = tf.reshape(y_one_hot, logits.get_shape(), name="reshape_one_hot")
loss = tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y_reshaped)
loss = tf.reduce_mean(loss)
为进行误差运算,我们的批处理目标必须要表示成跟模型输出值相同的方法和维度。使用与输入相同的编码方式,我们用tf.one_hot来表示输出值。然后将数组tf.reshape ()的维度重写为与tf.matmul (..) + b的线性输出一样。而后,我们就可以用该函数来计算模型的误差。
5)训练
with tf.name_scope("train"):
adam = tf.train.AdamOptimizer(0.0001)
optimizer = adam.minimize(loss)
我们简单用AdamOptimize来最小化误差。
结果
这是最值得庆祝的环节:训练结果。我所用到的参数如下:
序列大小:100
批处理大小:200
每个细胞的神经元数:512
递归神经网络深度:2
学习速度:0.0005
Dropout:0.5
在我的GPU(GeForce GTX 1060)上训练大约两小时后,所得结果如下图所示:
我们先来观察误差的变化: