RNN(遞迴神經網路)技術說明

王柏鈞
8 min readFeb 19, 2020

--

RNN學習歷程part2

#機器學習百日馬拉松11

menu

今天的課程是關於RNN或者說深度學習在訓練的方法以及流程,裡面會有滿多小細節我會特別標註出來,那些都是在自行編寫程式碼時很容易卡住而且找不到答案的部分。

今天的整個模型建立會以Keras 的Functional API來進行,比起Keras較常使用的Sequence Model模型建立法,他看似較為複雜的運作卻可以減少需要調整的參數,少了一些自動化的步驟反而更能看到細節。

如果還沒看過上一篇的建議先去看一下(RNN(遞迴神經網路)全面認識)會有比較好的認識喔。

Functional API的RNN模型架構

如上所示,我們要實作的就是這樣一個神經層,程式碼我會放在最後面,環境是用Tensorflow2.0。為了下一篇能跟上實作,本篇會介紹神經層之間的關係、傳遞,以及神經層自身的作用、參數。

Functional API與Sequential Model

Keras的模型建立有兩種方法:Functional API與Sequential Model,他們之間最大的不同就是Functional API需要自己定義輸入和輸出的框架,有了框架才能承接數據,而Sequential Model則會自動處理這個部分。

看似複雜的Functional API卻保留了能夠製造多個輸入和輸出的能力,雖然在這個範例沒用到,不過在經典的RNN問題:sequence to sequence中,為了使用decoder輸出的hidden state來重新產生新的Input,多個輸入就變成必要條件。

Input

batch_shape: 一個tuple,tuple內第一項是batch_size,其餘項表示資料維度。
shape: 一個tuple,tuple內所有項用以表示資料維度。

簡單的說,Input函數就是用來製造一個能夠承接數據的框架,他的語法範例如下:

inputs = Input(batch_shape=(32, 28, 28)) 或是

inputs = Input(shape=(28, 28))

基本上他們有同樣的作用,他們都需要輸入一個tuple(tuple就是用括號包起來的東西)用來表示將會輸入的資料其維度,但差異在於:

shape參數所設定的tuple就只是輸入的資料其維度。batch_size不做控制。

batch_shape參數所設定的tuple的第一項,會是batch_size,而後面的部份就是輸入的資料其維度。

所以:
第一個語句中,我們設定了一個batch_size為32,資料維度為(28, 28)的輸入框架。
第二個語句中,我們設定了一個batch_size為任意數(受其他函數控制,通常是fit()),資料維度為(28, 28)的輸入框架。

batch_size

batch_size表示我們每訓練一次需要看多少筆資料。

參考DNN(深度神經網路)的全面認識的部分你會知道,把一群資料從輸入層流到輸出層就是訓練一次,而這一群資料的集合被稱為batch,而batch裡面有多少筆資料,就是batch_size。

而epoch則表示整個神經網路要訓練幾次,比如說10個epoch就是要訓練10次的意思。

batch越大模型訓練的越快,但也會占用更多記憶體。所以batch的設置是在記憶體和效率之間取得一個最佳解。(但考慮到梯度下降的原理其實正確率會有有點下降喔)

SimpleRNN

units: 此層神經元的數量
activation: 此層神經元所使用的激活函數
return_sequences: RNN家族獨有的參數,決定是否回傳sequence。
return_state: RNN家族獨有的參數,決定是否回傳state。

units(神經元)和activation(激勵函數)的部分請參考DNN(深度神經網路)的全面認識

return_sequences是用來回傳序列(sequences),如我們的範例設定return_sequences = False的情況下,他只會傳出最後一個時間步(TimeStep)的數值,如果為True,他會把整個序列往下傳遞。如果後面還有其他RNN層就需要把他設定為True

return_state是用來回傳hidden state,預設為False,如果想要把hidden state也輸出就必須設為True。

序列與時間步

RNN是用來處理時間相關問題,所以我們應該知道,輸入的資料不會是單一的一個數值,而是在某一段時間中,每個時間點的資料,所以會是一個序列。

而RNN預設必須接收一個序列,所以當return_sequences = False,他會讓輸入的序列消失,只保留最後一個時間步的輸出值。

時間步就代表了現在是在序列中的第幾個資料,最後一個時間步就代表了序列中最後一個被輸入RNN的資料。

Dense

units = 此層神經元的數量
activation= 此層神經元所使用的激活函數

神經元的數量越多,應該就會有越好的模型複雜度,讓模型能夠解決更複雜的問題,但需要訓練更長的時間。也可能會造成Overfitting。

激活函數的選擇有一些小訣竅:

  1. 追求速度首選tanh
  2. 想要避免overfitting或者訓練一個稀疏神經網路,那就用relu
  3. sigmoid就是參考指標。
  4. softmax經常用於最後一層(輸出層),用來讓該層所有神經元的輸出總合為1,進而擬似機率。

Shape說明

在深度學習的計算中,我們會用到非常高維的向量,而高維向量的單字,就是Tensor,或者說中文的張量。

shape就表示了張量的形狀,包括他有幾個維度,每個維度的長度分別為多少。舉例來說:

shape = (128,) 就是一維張量。
shape = (128, 32, 28, 28) 就是四維張量。

結論:

今天的部分是針對明天會用到的一些函數做解釋,讓明天實作的過程可以更加順利。

而今天的學習評鑑就是下面這份程式碼,你可以先試著理解一下Functional API的運作流程,其實並不困難。明天會解說的程式碼如下,

import tensorflow as tf
from tensorflow.python import keras
from keras.layers import Input, Dense, SimpleRNN, RNN
from keras.models import Model
mnist = tf.keras.datasets.mnist
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# 標準化數據
X_train = X_train/255.0
X_test = X_test/255.0
print(X_train.shape)
print(X_train[0].shape)
batchs_size = 32inputs = Input(batch_shape=(batchs_size, 28, 28))
RNN1 = SimpleRNN(units=128, activation='tanh', return_sequences=False, return_state=False)
RNN1_output = RNN1(inputs)
Dense1 = Dense(units=128, activation='relu')(RNN1_output)
Dense2 = Dense(units=64, activation='relu')(Dense1)
output = Dense(units=10, activation='softmax')(Dense2)
rnn = Model(inputs=inputs, outputs=output)opt = tf.keras.optimizers.Adam(lr=0.001, decay=1e-6)
rnn.compile(optimizer=opt,
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
rnn.summary()rnn.fit(X_train, y_train, epochs=1, batch_size = batchs_size, validation_data=(X_test, y_test))
rnn.summary()

--

--

No responses yet