對比學習用 Keras 搭建 CNN RNN 等常用神經網絡
Keras 是一個兼容 Theano 和 Tensorflow 的神經網絡高級包, 用他來組件一個神經網絡更加快速, 幾條語句就搞定了. 而且廣泛的兼容性能使 Keras 在 Windows 和 MacOS 或者 Linux 上運行無阻礙.
今天來對比學習一下用 Keras 搭建下面幾個常用神經網絡:
- 回歸
- RNN回歸
- 分類
- CNN分類
- RNN分類
- 自編碼分類
它們的步驟差不多是一樣的:
- [導入模塊並創建數據]
- [建立模型]
- [定義優化器]
- [激活模型]
- [訓練模型]
- [檢驗模型]
- [可視化結果]
為了對比學習,用到的數據也差不多是一樣的,
所以本文只把註意力放在 2. [建立模型] 上面,其它步驟大同小異,可以去參考裏提到的教學網站觀看或者直接看源代碼。
1. 回歸
目的是對一組數據進行擬合。
1. 用 Sequential 建立 model
2. 再用 model.add 添加神經層,添加的是 Dense 全連接神經層。
參數有兩個,一個是輸入數據和輸出數據的維度,本代碼的例子中 x 和 y 是一維的。
如果需要添加下一個神經層的時候,不用再定義輸入的緯度,因為它默認就把前一層的輸出作為當前層的輸入。在這個例子裏,只需要一層就夠了。
# build a neural network from the 1st layer to the last layer model = Sequential() model.add(Dense(output_dim=1, input_dim=1))
2. RNN回歸
我們要用 sin 函數預測 cos 數據,會用到 LSTM 這個網絡。
RNN vs LSTM1. 搭建模型,仍然用 Sequential。
2. 然後加入 LSTM 神經層。
- batch_input_shape 就是在後面處理批量的訓練數據時它的大小是多少,有多少個時間點,每個時間點有多少個數據。
- output_dim 意思是 LSTM 裏面有二十個 unit。
- return_sequences 意思是在每個時間點,要不要輸出output,默認的是 false,現在我們把它定義為 true。如果等於 false,就是只在最後一個時間點輸出一個值。
- stateful,默認的也是 false,意義是批和批之間是否有聯系。直觀的理解就是我們在讀完二十步,第21步開始是接著前面二十步的。也就是第一個 batch中的最後一步與第二個 batch 中的第一步之間是有聯系的。
3. 有個不同點是 TimeDistributed。
在上一個回歸問題中,我們是直接加 Dense 層,因為只在最後一個輸出層把它變成一個全連接層。
今天這個問題是每個時間點都有一個 output,那需要 dense 對每一個 output 都進行一次全連接的計算。
model = Sequential() # build a LSTM RNN model.add(LSTM( batch_input_shape=(BATCH_SIZE, TIME_STEPS, INPUT_SIZE), # Or: input_dim=INPUT_SIZE, input_length=TIME_STEPS, output_dim=CELL_SIZE, return_sequences=True, # True: output at all steps. False: output as last step. stateful=True, # True: the final state of batch1 is feed into the initial state of batch2 )) # add output layer model.add(TimeDistributed(Dense(OUTPUT_SIZE))) adam = Adam(LR) model.compile(optimizer=adam, loss=‘mse‘,)
3. 分類
數據用的是 Keras 自帶 MNIST 這個數據包,再分成訓練集和測試集。x 是一張張圖片,y 是每張圖片對應的標簽,即它是哪個數字。
簡單介紹一下相關模塊:
- models.Sequential,用來一層一層一層的去建立神經層;
- layers.Dense 意思是這個神經層是全連接層。
- layers.Activation 激活函數。
- optimizers.RMSprop 優化器采用 RMSprop,加速神經網絡訓練方法。
import numpy as np np.random.seed(1337) # for reproducibility from keras.datasets import mnist from keras.utils import np_utils from keras.models import Sequential from keras.layers import Dense, Activation from keras.optimizers import RMSprop
在回歸網絡中用到的是 model.add 一層一層添加神經層,今天的方法是直接在模型的裏面加多個神經層。好比一個水管,一段一段的,數據是從上面一段掉到下面一段,再掉到下面一段。
- 第一段就是加入 Dense 神經層。32 是輸出的維度,784 是輸入的維度。
第一層傳出的數據有 32 個feature,傳給激活單元. - 激活函數用到的是 relu 函數。
經過激活函數之後,就變成了非線性的數據。 - 然後再把這個數據傳給下一個神經層,這個 Dense 我們定義它有 10 個輸出的 feature。同樣的,此處不需要再定義輸入的維度,因為它接收的是上一層的輸出。
- 接下來再輸入給下面的 softmax 函數,用來分類。
# Another way to build your neural net model = Sequential([ Dense(32, input_dim=784), Activation(‘relu‘), Dense(10), Activation(‘softmax‘), ])
4. CNN分類
CNN數據仍然是用 mnist。
1. 建立網絡第一層,建立一個 Convolution2D,參數有 filter 的數量。
- filter 就是濾波器,用32個濾波器掃描同一張圖片,每個濾波器會總結出一個 feature。每個濾波器會生成一整張圖片,有32個濾波器就會生成32張代表不同特征的圖片,
- nb_row nb_col 代表這個濾波器有多少行多少列。
- border_mode 代表這個濾波器在過濾時候用什麽方式,這裏我們用 same。
因為是第一層,所以需要定義輸入數據的維度,1, 28, 28 就是圖片圖片的維度。
濾波器完成之後,會生成32層的數據,但是圖片的長和寬是不變的,仍然是28×28。 - 之後再加一個 relu 激活函數。
# Another way to build your CNN model = Sequential() # Conv layer 1 output shape (32, 28, 28) model.add(Convolution2D( nb_filter=32, nb_row=5, nb_col=5, border_mode=‘same‘, # Padding method dim_ordering=‘th‘, # if use tensorflow, to set the input dimension order to theano ("th") style, but you can change it. input_shape=(1, # channels 28, 28,) # height & width )) model.add(Activation(‘relu‘))
2. Pooling 是一個向下取樣的過程.
它可以縮小生成出來的長和寬,高度不需要被壓縮。
- pool_size 是向下取樣的時候,考慮多長多寬的圖片。
- strides 步長,是取完一個樣之後要跳幾步再取樣,再跳幾步再取樣。
# Pooling layer 1 (max pooling) output shape (32, 14, 14) model.add(MaxPooling2D( pool_size=(2, 2), strides=(2, 2), border_mode=‘same‘, # Padding method ))
3. 接下來建立第二個神經層
- 有 64 個 filter,5, 5 的長寬,再跟著一個激活函數。
- 再跟著一個 MaxPooling2D 取樣。
# Conv layer 2 output shape (64, 14, 14) model.add(Convolution2D(64, 5, 5, border_mode=‘same‘)) model.add(Activation(‘relu‘)) # Pooling layer 2 (max pooling) output shape (64, 7, 7) model.add(MaxPooling2D(pool_size=(2, 2), border_mode=‘same‘))
4. 接下來進入全聯接層
- 用 Flatten 把卷出來的三維的層,抹平成二維的。
- 接下來就加一個 Dense 全聯接層,抹平就是為了可以把這一個一個點全連接成一個層.
- 接著再加一個激活函數。
# Fully connected layer 1 input shape (64 * 7 * 7) = (3136), output shape (1024) model.add(Flatten()) model.add(Dense(1024)) model.add(Activation(‘relu‘))
5. 在第二個全連接層,輸出 10 個 unit, 用 softmax 作為分類。
# Fully connected layer 2 to shape (10) for 10 classes model.add(Dense(10)) model.add(Activation(‘softmax‘))
5. RNN分類
RNN分類RNN 是一個序列化的神經網,我們處理圖片數據的時候,也要以序列化的方式去考慮。
圖片是由一行一行的像素組成,我們就一行一行地去序列化地讀取數據。最後再進行一個總結,來決定它到底是被分辨成哪一類。
用到的參數含義:
- TIME_STEPS 是要讀取多少個時間點的數據,如果一次讀一行需要讀28次。
- INPUT_SIZE 每次每一行讀取多少個像素。
- BATCH_SIZE 每一批訓練多少張。
- BATCH_INDEX 用來生成數據。
- OUTPUT_SIZE 分類結果的長度,0到9,所以長度為 10。
- CELL_SIZE 網絡中隱藏層要放多少個 unit。
LR 是學習率。
1. 用 Sequential 建立模型,就是一層一層地加上神經層。
# build RNN model model = Sequential()
2. 加上 SimpleRNN。
batch_input_shape 就是在後面處理批量的訓練數據時它的大小是多少,有多少個時間點,每個時間點有多少個像素。
# RNN cell model.add(SimpleRNN( # for batch_input_shape, if using tensorflow as the backend, we have to put None for the batch_size. # Otherwise, model.evaluate() will get error. batch_input_shape=(None, TIME_STEPS, INPUT_SIZE), # Or: input_dim=INPUT_SIZE, input_length=TIME_STEPS, output_dim=CELL_SIZE, unroll=True, ))
3. 加 Dense 輸出層。
輸出 output 長度為 10,接著用 softmax 激活函數用於分類。
# output layer model.add(Dense(OUTPUT_SIZE)) model.add(Activation(‘softmax‘))
4. 在訓練的時候有一個小技巧,就是怎麽去處理批量。
輸出結果時每 500 步輸出一下測試集的準確率和損失。
需要用到 BATCH_INDEX,一批批地截取數據,下一批的時候,這個 BATCH_INDEX 就需要累加,後面的時間點和步長沒有變化都是28。
y 的批量和 x 的處理是一樣的,只不過 y 只有二維,所以它只有兩個參數。
後面有一個判斷語句,如果這個 index 大於訓練數據的總數,index 就變為 0,再從頭開始一批批處理。
# training for step in range(4001): # data shape = (batch_num, steps, inputs/outputs) X_batch = X_train[BATCH_INDEX: BATCH_INDEX+BATCH_SIZE, :, :] Y_batch = y_train[BATCH_INDEX: BATCH_INDEX+BATCH_SIZE, :] cost = model.train_on_batch(X_batch, Y_batch) BATCH_INDEX += BATCH_SIZE BATCH_INDEX = 0 if BATCH_INDEX >= X_train.shape[0] else BATCH_INDEX if step % 500 == 0: cost, accuracy = model.evaluate(X_test, y_test, batch_size=y_test.shape[0], verbose=False) print(‘test cost: ‘, cost, ‘test accuracy: ‘, accuracy)
6. 自編碼分類
自編碼自編碼,簡單來說就是把輸入數據進行一個壓縮和解壓縮的過程。
原來有很多 Feature,壓縮成幾個來代表原來的數據,解壓之後恢復成原來的維度,再和原數據進行比較。
做的事情是把 datasets.mnist
數據的 28×28=784 維的數據,壓縮成 2 維的數據,然後在一個二維空間中可視化出分類的效果。
模型結構:
encoding_dim
,要壓縮成的維度。
# in order to plot in a 2D figure encoding_dim = 2 # this is our input placeholder input_img = Input(shape=(784,))
建立 encoded
層和 decoded
層,再用 autoencoder
把二者組建在一起。訓練時用 autoencoder
層。
1. encoded
用4層 Dense
全聯接層
激活函數用 relu
,輸入的維度就是前一步定義的 input_img
。
接下來定義下一層,它的輸出維度是64,輸入是上一層的輸出結果。
在最後一層,我們定義它的輸出維度就是想要的 encoding_dim=2
。
2. 解壓的環節,它的過程和壓縮的過程是正好相反的。
相對應層的激活函數也是一樣的,不過在解壓的最後一層用到的激活函數是 tanh
。因為輸入值是由 -0.5 到 0.5 這個範圍,在最後一層用這個激活函數的時候,它的輸出是 -1 到 1,可以是作為一個很好的對應。
# encoder layers encoded = Dense(128, activation=‘relu‘)(input_img) encoded = Dense(64, activation=‘relu‘)(encoded) encoded = Dense(10, activation=‘relu‘)(encoded) encoder_output = Dense(encoding_dim)(encoded) # decoder layers decoded = Dense(10, activation=‘relu‘)(encoder_output) decoded = Dense(64, activation=‘relu‘)(decoded) decoded = Dense(128, activation=‘relu‘)(decoded) decoded = Dense(784, activation=‘tanh‘)(decoded) # construct the autoencoder model autoencoder = Model(input=input_img, output=decoded)
接下來直接用 Model
這個模塊來組建模型
輸入就是圖片,輸出是解壓的最後的結果。
# construct the encoder model for plotting encoder = Model(input=input_img, output=encoder_output)
當我們想要看由 784 壓縮到 2維後,這個結果是什麽樣的時候,也可以只單獨組建壓縮的板塊,此時它的輸入是圖片,輸出是壓縮環節的最後結果。
最後分類的可視化結果:
對比學習用 Keras 搭建 CNN RNN 等常用神經網絡