RNN學習歷程part2
#機器學習百日馬拉松11
今天的課程是關於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。
激活函數的選擇有一些小訣竅:
- 追求速度首選tanh
- 想要避免overfitting或者訓練一個稀疏神經網路,那就用relu
- sigmoid就是參考指標。
- 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 Modelmnist = 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()