深度學習系列七:LSTM神經網絡與RNN的對比及理解:基於tensorflow的MNIST例子

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]})))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章