RNN介紹
在讀本文之前,讀者應該對全連接神經網絡(Fully Connected Neural Network, FCNN)和卷積神經網絡( Convolutional Neural Network, CNN)有一定的了解。對於FCNN和CNN來說,他們能解決很多實際問題,但是它們都只能單獨的取處理一個個的輸入,前一個輸入和后一個輸入是完全沒有關系的 。而在現實生活中,我們輸入的向量往往存在着前后聯系,即前一個輸入和后一個輸入是有關聯的,比如文本,語音,視頻等,因此,我們需要了解深度學習中的另一類重要的神經網絡,那就是循環神經網絡(Recurrent Neural Network,RNN).
循環神經網絡(Recurrent Neural Network,RNN)依賴於一個重要的概念:序列(Sequence),即輸入的向量是一個序列,存在着前后聯系。簡單RNN的結構示意圖如下:
相比於之前的FCNN,RNN的結構中多出了一個自循環部分,即W所在的圓圈,這是RNN的精華所在,它展開后的結構如下:
對於t時刻的輸出向量\(o_{t}\),它的輸出不僅僅依賴於t時刻的輸入向量\(x_{t}\),還依賴於t-1時刻的隱藏層向量\(s_{t-1}\),以下是輸出向量\(o_{t}\)的計算公式:
其中,第二個式子為輸出層的計算公式,輸出層為全連接層,V為權重矩陣,g為激活函數。第一個式子中,U是輸入x的權重矩陣,W是上一次隱藏層值s的輸入權重矩陣,f為激活函數。注意到,RNN的所有權重矩陣U,V,W是共享的,這樣可以減少計算量。
本文將會用TensorFlow中已經幫我們實現好的RNN基本函數tf.contrib.rnn.BasicRNNCell(), tf.nn.dynamic_rnn()來實現簡單RNN,並且用該RNN來識別MNIST數據集。
MNIST數據集
MNIST數據集是深度學習的經典入門demo,它是由6萬張訓練圖片和1萬張測試圖片構成的,每張圖片都是28*28大小(如下圖),而且都是黑白色構成(這里的黑色是一個0-1的浮點數,黑色越深表示數值越靠近1),這些圖片是采集的不同的人手寫從0到9的數字。
在TensorFlow中,已經內嵌了MNIST數據集,筆者已經下載下來了,如下:
接下來本文將要用MNIST數據集作為RNN應用的一個demo.
RNN大戰MNIST數據集
用CNN來識別MNIST數據集,我們好理解,這是利用了圖片的空間信息。可是,RNN要求輸入的向量是序列,那么,如何把圖片看成是序列呢?
圖片的大小為28*28,我們把每一列向量看成是某一時刻的向量,那么每張圖片就是一個序列,里面含有28個向量,每個向量含有28個元素,如下:
下面給出如何利用TensorFlow來搭建簡單RNN,用來識別MNIST數據集,完整的Python代碼如下:
# -*- coding: utf-8 -*-
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
# 獲取MNIST數據
mnist = input_data.read_data_sets(r"./MNIST_data", one_hot=True)
# 設置RNN結構
element_size = 28
time_steps = 28
num_classes = 10
batch_size = 128
hidden_layer_size = 150
# 輸入向量和輸出向量
_inputs = tf.placeholder(tf.float32, shape=[None, time_steps, element_size], name='inputs')
y = tf.placeholder(tf.float32, shape=[None, num_classes], name='inputs')
# 利用TensorFlow的內置函數BasicRNNCell, dynamic_rnn來構建RNN的基本模塊
rnn_cell = tf.contrib.rnn.BasicRNNCell(hidden_layer_size)
outputs, _ = tf.nn.dynamic_rnn(rnn_cell, _inputs, dtype=tf.float32)
Wl = tf.Variable(tf.truncated_normal([hidden_layer_size, num_classes], mean=0,stddev=.01))
bl = tf.Variable(tf.truncated_normal([num_classes],mean=0,stddev=.01))
def get_linear_layer(vector):
return tf.matmul(vector, Wl) + bl
# 取輸出的向量outputs中的最后一個向量最為最終輸出
last_rnn_output = outputs[:,-1,:]
final_output = get_linear_layer(last_rnn_output)
# 定義損失函數並用RMSPropOptimizer優化
softmax = tf.nn.softmax_cross_entropy_with_logits(logits=final_output, labels=y)
cross_entropy = tf.reduce_mean(softmax)
train_step = tf.train.RMSPropOptimizer(0.001, 0.9).minimize(cross_entropy)
# 統計准確率
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(final_output,1))
accuracy = (tf.reduce_mean(tf.cast(correct_prediction, tf.float32)))*100
sess=tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
# 測試集
test_data = mnist.test.images[:batch_size].reshape((-1, time_steps, element_size))
test_label = mnist.test.labels[:batch_size]
# 每次訓練batch_size張圖片,一共訓練3000次
for i in range(3001):
batch_x, batch_y = mnist.train.next_batch(batch_size)
batch_x = batch_x.reshape((batch_size, time_steps, element_size))
sess.run(train_step, feed_dict={_inputs:batch_x, y:batch_y})
if i % 100 == 0:
loss = sess.run(cross_entropy, feed_dict={_inputs: batch_x, y: batch_y})
acc = sess.run(accuracy, feed_dict={_inputs:batch_x, y: batch_y})
print ("Iter " + str(i) + ", Minibatch Loss= " + \
"{:.6f}".format(loss) + ", Training Accuracy= " + \
"{:.5f}".format(acc))
# 在測試集上的准確率
print("Testing Accuracy:", sess.run(accuracy, feed_dict={_inputs:test_data, y:test_label}))
運行上述代碼,輸出的結果如下:
Extracting ./MNIST_data\train-images-idx3-ubyte.gz
Extracting ./MNIST_data\train-labels-idx1-ubyte.gz
Extracting ./MNIST_data\t10k-images-idx3-ubyte.gz
Extracting ./MNIST_data\t10k-labels-idx1-ubyte.gz
Iter 0, Minibatch Loss= 2.301171, Training Accuracy= 11.71875
Iter 100, Minibatch Loss= 1.718483, Training Accuracy= 47.65625
Iter 200, Minibatch Loss= 0.862968, Training Accuracy= 71.09375
Iter 300, Minibatch Loss= 0.513068, Training Accuracy= 86.71875
Iter 400, Minibatch Loss= 0.570475, Training Accuracy= 83.59375
Iter 500, Minibatch Loss= 0.254566, Training Accuracy= 92.96875
Iter 600, Minibatch Loss= 0.457989, Training Accuracy= 85.93750
Iter 700, Minibatch Loss= 0.151181, Training Accuracy= 96.87500
Iter 800, Minibatch Loss= 0.171168, Training Accuracy= 94.53125
Iter 900, Minibatch Loss= 0.142494, Training Accuracy= 94.53125
Iter 1000, Minibatch Loss= 0.155114, Training Accuracy= 97.65625
Iter 1100, Minibatch Loss= 0.096007, Training Accuracy= 96.87500
Iter 1200, Minibatch Loss= 0.341476, Training Accuracy= 88.28125
Iter 1300, Minibatch Loss= 0.133509, Training Accuracy= 96.87500
Iter 1400, Minibatch Loss= 0.076408, Training Accuracy= 98.43750
Iter 1500, Minibatch Loss= 0.122228, Training Accuracy= 98.43750
Iter 1600, Minibatch Loss= 0.099382, Training Accuracy= 96.87500
Iter 1700, Minibatch Loss= 0.084686, Training Accuracy= 97.65625
Iter 1800, Minibatch Loss= 0.067009, Training Accuracy= 98.43750
Iter 1900, Minibatch Loss= 0.189703, Training Accuracy= 94.53125
Iter 2000, Minibatch Loss= 0.116077, Training Accuracy= 96.09375
Iter 2100, Minibatch Loss= 0.028867, Training Accuracy= 100.00000
Iter 2200, Minibatch Loss= 0.064198, Training Accuracy= 99.21875
Iter 2300, Minibatch Loss= 0.078259, Training Accuracy= 97.65625
Iter 2400, Minibatch Loss= 0.106613, Training Accuracy= 97.65625
Iter 2500, Minibatch Loss= 0.078722, Training Accuracy= 98.43750
Iter 2600, Minibatch Loss= 0.045871, Training Accuracy= 98.43750
Iter 2700, Minibatch Loss= 0.030953, Training Accuracy= 99.21875
Iter 2800, Minibatch Loss= 0.062823, Training Accuracy= 96.87500
Iter 2900, Minibatch Loss= 0.040367, Training Accuracy= 99.21875
Iter 3000, Minibatch Loss= 0.017787, Training Accuracy= 100.00000
Testing Accuracy: 97.6563
可以看到,用簡單RNN來識別MNIST數據集,也能取得很好的效果!
本次分享到此結束,歡迎大家交流~
注意:本人現已開通微信公眾號: 輕松學會Python爬蟲(微信號為:easy_web_scrape), 歡迎大家關注哦~~