LSTM(long-short term memory)networks 是一种特殊的RNN网络,整体思维一致,具体区别和原理可以参考:http://colah.github.io/posts/2015-08-Understanding-LSTMs/
上文对于LSTM阐述非常清晰,这里就不多赘述了,主要记录下自己在学习过程中遇到的一些问题和不清晰的点,以及我自己的理解。
RNN与常规网络的区别
从输入来说,常规网络的输入被一次性输入网络,在训练和推导阶段只需要进行一次前向传播就可以得到结果,如图所示:
RNN的输入必须是一个序列(常规网络的输入需要被分割为序列输入RNN),序列的每个元素被依次输入网络进行前向传播,这样的输入方式由RNN的计算方式决定:首元素与一个初始hidden层一起进行前向传播后得到首元素对应的hidden层,该层与下一个元素一起作为输入再次输入网络进行前向传播得到第二元素的hidden层,以此类推,最终得到最后元素的hidden层,并与一个权重向量和偏置向量进行计算得到最后的输出。
从特性上来说,常规网络每个输入元素彼此之间并无关联,在计算过程中彼此不交叉,每个元素对于结果的影响完全由计算过程中的参数决定;RNN的计算方式决定了序列前的元素将对序列后的元素造成影响,前方元素计算得到的结果将影响后方元素的计算结果,这也就使得网络在合理训练后有“记忆”效应。
LSTM与RNN的区别
LSTM作为一种特殊的RNN,它的整体实现机制与RNN相同,但在元素之间如何互相影响上有一些不同,它建立了一个专用的通道(下图上方的通道)用以存储“记忆”,形象点说,任何元素在输入网络时,可选择性遗忘部分前方元素遗留的”记忆“,并可选择性存储部分新的“记忆”,经过遗忘和存储后更新的“记忆”与新的输入元素一起计算得到输出。
与RNN相比,LSTM在元素间互相影响的机制上更加复杂,解决了RNN Long-Term dependencies问题(当输入的两个元素距离较远时,后方元素能从前方元素提取的信息很少,导致无法有效根据前方元素的信息作出相应的判断),具体原理这里不作深究。
下面贴一个LSTM网络解决tensorflow基础教程中MNIST分类问题的代码:
import argparse
import sys
import tempfile
from tensorflow.examples.tutorials.mnist import input_data
import numpy as np
import tensorflow as tf
# lstm_size可以认为是hidden层神经元数量
lstm_size=20
batch_size=50
test_size=100
def model(x,W,B,lstm_size):
# 建立LSTM记忆层,即hidden层
lstm=tf.contrib.rnn.BasicLSTMCell(lstm_size)
# 将输入的第一维与第二维交换,是由tf.contrib.rnn.static_rnn函数的计算方式决定的,其输入形状为(time_size,batch_size,input_size),
# 在本次计算中,即(28,50,28),在计算时,每张图为28×28的序列,该函数第一步分别将50张图的第一个元素输入网络,得到50张图第一次计算的
# hidden层(大小为50×lstm_size),结合该层和50张图的第二个元素进行第二次计算,得到第二次计算的hidden层,以此类推,最终得到(28,50,lstm_size)
# 的结果,即每一次计算的hidden层
xt=tf.transpose(x,[1,0,2])
xr=tf.reshape(xt,[-1,28])
x_split=tf.split(xr,28,axis=0)
outputs,_states = tf.contrib.rnn.static_rnn(lstm,x_split,dtype=tf.float32)
# 以上output只是所有图所有计算得到的hidden层合集,要得到最终的计算结果,需要最后一次计算得到的hidden层(即outputs[-1])结合权重和偏置计算
return tf.matmul(outputs[-1],W) + B,lstm.state_size
# 得到训练和测试数据
mnist=input_data.read_data_sets("./MNIST_data/",one_hot=True)
trX, trY, teX, teY = mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels
# tensorflow官方教程中输入大小是(-1,784),每张图片的784像素被一次输入网络进行前向传播得到结果;输入LSTM网络时将每张图的像素切割为28×28的序列,
# 进行28次前向传播,每次输入28个元素,最终得到结果
trX = trX.reshape(-1, 28, 28)
teX = teX.reshape(-1, 28, 28)
X = tf.placeholder("float", [None, 28, 28])
Y = tf.placeholder("int64", [None, 10])
# LSTM最后一个元素输出的hidden层需要进行向量和偏置的计算得到真正的输出,由于每个元素输出hidden层包含lstm_size个神经元,
# 因此W的第一个维度为lstm_size
W=tf.Variable(tf.random_normal([lstm_size,10]))
B=tf.Variable(tf.random_normal([10]))
py_x,state_size=model(X,W,B,lstm_size)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=py_x, labels=Y))
train_op = tf.train.RMSPropOptimizer(0.001, 0.9).minimize(cost)
predict_op = tf.argmax(py_x, 1)
with tf.name_scope('accuracy'):
correct_prediction = tf.equal(tf.argmax(py_x, 1), Y)
correct_prediction = tf.cast(correct_prediction, tf.float32)
accuracy = tf.reduce_mean(correct_prediction)
with tf.Session() as sess:
tf.global_variables_initializer().run()
for i in range(100):
for start, end in zip(range(0, len(trX), batch_size), range(batch_size, len(trX)+1, batch_size)):
sess.run(train_op, feed_dict={X: trX[start:end], Y: trY[start:end]})
s=len(teX)
test_indices = np.arange(len(teX)) # Get A Test Batch
np.random.shuffle(test_indices)
test_indices = test_indices[0:test_size]
print(i, np.mean(np.argmax(teY[test_indices], axis=1) ==
sess.run(predict_op, feed_dict={X: teX[test_indices]})))