MaDi's Blog

一個紀錄自己在轉職軟體工程師路上的學習小空間

0%

[Keras] 深度學習模型

深度學習需要建立模型,建立的過程中常常會忽略某些細節以及語法,因此寫了一篇記錄方便自己未來查閱。

資料前處理

zero-padding

為了讓所有輸入序列的長度一致,zero-padding設定MAX_SEQUENCE_LENGTH作為容許的最大輸入長度,若長度超過此輸入序列的長度,爾後的資料會被刪掉;若長度不足輸入序列的長度,則在資料前面補零。

Keras內建有sequence.pad_sequences函式協助我們做到zero-padding的功能

1
X_train = keras.preprocessing.sequence.pad_sequences(train_data,maxlen=MAX_SEQUENCE_LENGTH)

One-Hot Encoding

又稱作一位有效編碼,舉例來說,有一個分類長這樣:

1
2
3
4
5
烏龜: 1, 烏賊: 2, 老虎: 3 

array([[1, 0, 0], // 烏龜
[0, 1, 0], // 烏賊
[0, 0, 1]]) // 老虎

轉換後的好處是更有機率的概念,且特徵能夠擴張。

Keras內建有utils.to_categorical函式協助我們做到One-Hot Encoding的功能

1
Y_train = keras.utils.to_categorical(train_labels)

<p.s> 用DataFrame做One-Hot Encoding

1
df = pd.DataFrame({'gender':['male','female','male','female'],'class':['Lion','Tiger','Fish','Tiger']})

pandas做One-Hot Encoding

1
pd.get_dummies(df)

選定某列作One-Hot Encoding

1
pd.get_dummies(df.gender)

如果今天資料長這樣,可以看到class欄位裡有"/"符號連結各種班級名稱,而我們希望將它切開來做One-Hot Encoding

1
df['class'].str.get_dummies('/')

切分訓練與測試資料

1
2
from sklearn.model_selection import train_test_split
x_train, x_val, y_train, y_val = train_test_split(X_train, Y_train, test_size=VALIDATION_RATIO, random_state=RANDOM_STATE)

模型建立

Define a set of function - Neural Network

Keras中有兩種建立模型的方式:

  1. Sequential Model:一種簡單的模型,單一輸入、單一輸出,按順序一層一層的由上往下執行。
  2. Functional API:支援多個輸入、多個輸出

1. Sequential Model

1
2
3
4
5
6
7
8
9
10
from keras.models import Sequential

#常用的layers
from keras.layers import Input, Embedding, LSTM, Dense, Dropout, Flatten

# 用add把層接在一起
model.add(keras.Input(shape=(250, 250, 3))) # 250x250 RGB images
model.add(layers.Conv2D(32, 5, strides=2, activation="relu"))
model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.MaxPooling2D(3))

2. Functional API

1
2
3
4
5
6
7
8
9
10
11
12
from keras.models import Model

#常用的layers
from keras.layers import Input, Embedding, LSTM, Dense, Dropout, Flatten

# 每一層都可以調用,接著串起來
inputs = Input(shape=(784,))
d1 = Dense(64, activation='relu')(inputs)
d2 = Dense(64, activation='relu')(d1)
predictions = Dense(10, activation='softmax')(d2)

model = Model(inputs=inputs, outputs=predictions)

Input(輸入層)

1
Input(shape=None, batch_size=None, name=None, dtype=None,...)

shape: tuple型態的輸入,不包含batch_size,ex: shape=(32,)
name: 自己命名
dtype: 預期進入輸入層的資料型態

ex: Input(shape=(100,), dtype='int32', name='main_input')

Embedding(嵌入層)

1
Embedding(input_dim, output_dim, input_length=None)
  1. 詞嵌入,把維度展開,ex: [[4], [20]] -> [[0.25, 0.1], [0.6, -0.2]]
  2. 只能用在模型的第一層

Dense(全連接層)

1
Dense(units, activation=None, ...)

units: 輸出的維度
activation: 預設None為線性

若Dense是輸入層,則要給定input_dim or input_shape,否則就會自動抓上一層的output當作這層的input

1
2
model.add(Dense(32, input_dim=784))
model.add(Dense(32, input_shape=(784,)))
1
2
3
4
5
# Dense作為輸入層,輸入維度128,輸出維度256,活化函數為relu
model.add(Dense(units=256, input_dim=128, activation='relu'))

# Dense作為隱藏層,自動抓上一層為這層的輸入維度,輸出維度10,活化函數為softmax
model.add(Dense(units=10, activation='softmax'))

LSTM(長短期記憶網路層)

1
LSTM(units, activation='tanh', recurrent_activation='hard_sigmoid', dropout=0.0 ...)

units: 輸出的維度
activation: 活化函數,預設None為線性
dropout: 丟棄比例,0~1
如果想要串接多層的LSTM,則前一層需要加上return_sequences=True

Dropout

1
Dropout(rate)

Dropout會在訓練中每次更新時,都以一定比例將輸入的神經元丟棄掉(設置為0),有助於防止over-fitting,尤其是LSTM更需要這個步驟。rate: 0~1之間

Flatten

1
Flatten()

把輸入展開,不影響總神經元數量

模型編譯

Step2. Goodness of function - cross entropy (loss)

值得注意的是,cross entropy在Keras裏頭的寫法是categorical_crossentropy

Step3. Pick the best function (optimizer、metrics)

其中,optimizer有Adam、RMSprop…,但其實都是Gradien Descent的方法

程式碼:

model.compile(優化器, 損失函數, 衡量標準)

多分類問題

1
2
3
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])

二分類問題

1
2
3
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['accuracy'])

回歸問題

1
2
model.compile(optimizer='rmsprop',
loss='mse')

訓練

一般的訓練方法:

1
history = model.fit(x, y, batch_size=32, epochs=10, verbose=1, validation_split=0.0, shuffle=True, ...)

x: input
y: label
batch_size: 每次訓練看幾筆訓練資料
epochs: 模型訓練過程中總共要看幾次
verbose=1 代表輸出進度條紀錄, 0則代表不紀錄

訓練完會返回一個history物件,紀錄訓練過程中每個epoch的acc,val..等資訊

除此之外,訓練完也可以用evaluate去判斷訓練的好壞

1
model.evaluate(x, y, batch_size=32, verbose=1...)

生成器(generate)的訓練方法:

1
model.fit_generator(generator, steps_per_epoch=None, epochs=1, verbose=1, validation_data=None, validation_steps=None, shuffle=True...)

使用生成器(generate)逐批生成的數據,按批次訓練模型。生成器與模型並行可以提高效率

generator: 一個生成器,生成器的輸出應為(inputs, targets)

steps_per_epoch: 在一個epoch完成並開始下一個epoch之前從generator產生的總步數,即資料數量/batch大小

generator常搭配yield使用,在使用BERT模型時需要使用model.fit_generator()

繪圖觀察loss/acc

1
2
3
4
5
6
7
8
9
10
import matplotlib.pyplot as plt
%matplotlib inline

# 從history中撈取每個epoch的資料
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(1, len(acc) + 1)

繪圖函式

1
2
3
4
5
6
7
def plot_fig(epochs,train,val,train_label,val_label,type):
plt.plot(epochs, train, 'bo', label=train_label)
plt.plot(epochs, val, 'b', label=val_label)
plt.title('Training and validation '+type)
plt.xlabel('Epochs')
plt.ylabel(type)
plt.legend()

loss圖

1
plot_fig(epochs,loss,val_loss,'train loss','validation loss','loss')

acc圖

1
plot_fig(epochs,acc,val_acc,'train acc','validation acc','acc')

預測

1
model.predict(x, batch_size=32, verbose=0)

返回預測值的numpy array

參考