提到LSTM,我们就应该想到RNN,LSTM是RNN的一种改进,是RNN的变种。比如前几篇文章中讲的Mnist数据集分类,都是一张图片一张图片的输入,然后进行分类,这仅仅是对于图像来说,那么,对于语音或一串文字来说怎么做?这个就需要网络具有记忆的功能,RNN和LSTM都有这种功能。
如果需要对语音或文字进行处理,就需要把网络看成是一个连续的整体,我们可以对网络加上一个反馈回路,如下图等号左边的图:
这个反馈回路会把上一次的输出信息作为下一次的输入信息来处理。如果是一段文字,我们把这段文字分成一个一个的词,然后一个一个的输入进LSTM网络中,比如,将第一个词输入进X0,得到一个结果h0,将第二个词输入h1,然后综合上一步的结果h0,输出h1,以此类推,知道这段文字全部输入网络中…
其实LSTM和BP神经网络差不多,但是BP网络会有一个梯度消失的问题。如下图中中间隐藏层的消失问题:
那么可能会有人想到用y=x这样的线性**函数**,这样梯度就不会消失了,但是它也会产生一些问题,它会记住很久以前的信息,包括主要特征和非主要特征,这些它全部都记住了,根本无法知道主要特征是什么,这个网络也就是废的。那么这样的做法很明显是错的,正确的做法就是有选择性的记忆,只记忆主要特征信息,这样就诞生了LSTM网络:
在LSTM中的隐层单元中,我们不叫神经元,我们叫它Block,如上图所示。上图中是什么意思呢?首先我们来这里:
输入的信息从山上图中输入,经过“Input Gate”进行判断是否是主要信息,如果不是主要信息,“Input Gate”的值就是0,通过与输入信息相乘,将非主要特征变为0。如果是主要特征,“Input Gate”放行,来到“Cell”部分:
“Cell”部分有一个“Forget Gate”,它可以选择性的忘记(忽略)非主要特征,再进一步的下采样,提取主要特征。一旦结果满意之后,到达这一层:
如果信息通过了“Output Gate”,则可以将信息输出,否则,将会在“Cell”部分循环,直至能够被“Output Gate”接受。
下面就是整个LSTM的网络示意图:
比如说下图中的Time 1有一个信号传入隐层,在隐层中可以不经过衰减往后传递信号,隐层中“-”的意思表示“不让它输出”,一直进行下去,直到输入结束。
下面进行代码实现(mnist数据集训练及测试):
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("mnist/", one_hot=True)
lstm_size=200 # 隐层100个block
n_class=10 # 10个分类
batch_size=128 #每次50个训练样本
n_inputs = 28 # 输入一行,一行有28个数据
max_time = 28 # 一共28行
x=tf.placeholder(shape=[None,784],dtype=tf.float32)
x_image=tf.reshape(x,shape=[-1,max_time,n_inputs])
y=tf.placeholder(shape=[None,n_class],dtype=tf.float32)
# 初始化权值
w=tf.Variable(tf.truncated_normal(shape=[lstm_size,n_class],stddev=0.1),dtype=tf.float32)
# 初始化偏执值
b=tf.Variable(tf.constant(0.1,shape=[10]),dtype=tf.float32)
lstm_cell=tf.nn.rnn_cell.BasicLSTMCell(lstm_size) #定义LSTM基本Cell,这里相当于有100个Cell
outputs,final_state=tf.nn.dynamic_rnn(lstm_cell,x_image,dtype=tf.float32) #返回两个值
# outputs default(False) outputs=[batch_size,max_time,cell.output_size]
# outputs (True) outputs=[max_time,batch_size,cell.output_size]
#--------------------------------
# final_state=[state,batch_size,cell.state_size]
# final_state[0]是cell state
# final_state[1]是hidden state
#------------------------------
out1=tf.add(tf.matmul(final_state[1],w),b)
y_=tf.nn.softmax(out1) # 预测值
loss=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y,logits=y_)) # 平均损失
step=tf.train.AdamOptimizer(1e-4).minimize(loss) #自适应梯度下降
acc_mat=tf.equal(tf.argmax(y,1),tf.argmax(y_,1))
acc=tf.reduce_mean(tf.cast(acc_mat,dtype=tf.float32)) # 准确率
init=tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
count=0
for i in range(10000):
batch_xs,batch_ys=mnist.train.next_batch(batch_size)
sess.run(step,feed_dict={x:batch_xs,y:batch_ys})
if (i+1)%100==0:
curr_acc,curr_loss=sess.run([acc,loss],feed_dict={x:mnist.test.images,y:mnist.test.labels})
print("第"+str(count+1)+"次","当前测试集准确率:",curr_acc,"损失值:",curr_loss)
count+=1
每训练100次就进行一次测试,得到的结果如下所示:
最终结果能够达到接近97%,这个网络代码很少,本身没有什么可以优化的地方,可以调调参数,看看准确值会不会往上走。