本文爲《Python深度學習》的學習筆記。
第7章 高級的深度學習最佳實踐
Keras函數式API
使用Keras回調函數
使用Tensorboard可視化工具
開發最先進模型的重要實踐
7.1 不用Sequential模型的解決方案:Keras函數式API
之前6章所有神經網絡都是用Sequential模型實現的。Sequential模型假設,網絡只有一個輸入和輸出,且網絡是線性堆疊的。
有些任務需要多模態輸入,可以合併這些不同輸入源的數據。
同樣,有些任務需要預測輸入數據的多個目標屬性。
以及ResNet。
7.1.1 函數式API簡介
from keras import Input, layers
input_tensor = Input(shape = (322,))
dense = layers.Dense(32, activation = 'relu')
output_tensor = dense(input_tensor)
這裏可以直接操作張量,把層Dense當做函數使用,接受張量並返回張量。
from keras.models import Sequential, Model
from keras import layers
from keras import Input
seq_model = Sequential()
seq_model.add(layers.Dense(32, activation = 'relu', input_shape = (64,)))
seq_model.add(layers.Dense(32, activation = 'relu'))
seq_model.add(layers.Dense(10, activation = 'softmax'))
input_tensor = Input(shape=(64,))
x = layers.Dense(32, activation = 'relu')(input_tensor)
x = layers.Dense(32, activation = 'relu')(x)
output_tensor = layers.Dense(10, activation = 'softmax')(x)
model = Model(input_tensor, output_tensor)
model.summary()
這裏我們將Model對象實例化只用了一個輸入張量和一個輸出張量。
7.1.2 多輸入模型
API可用於構建多個輸入的模型。
- 下面示例如何用函數式API構建這樣的模型。
# 7-1 用函數式API實現雙輸入問答模型
from keras.models import Model
from keras import layers
from keras import Input
text_vocabulary_size = 10000
question_vocabulary_size = 10000
answer_vocabulary_size = 500
text_input = Input(shape=(None,), dtype='int32', name='text')
embedded_text = layers.Embedding(text_vocabulary_size, 64)(text_input) # 將輸入嵌入長度爲64的向量
encoded_text = layers.LSTM(32)(embedded_text)
question_input = Input(shape=(None,), dtype='int32', name='question') # 對問題進行相同的處理
embedded_question = layers.Embedding(text_vocabulary_size, 32)(question_input)
encoded_question = layers.LSTM(15)(embedded_question)
concatenated = layers.concatenate([encoded_text, encoded_question], axis = -1) # 將編碼後的問題和文本鏈接起來
answer = layers.Dense(answer_vocabulary_size, activation='softmax')(concatenated) # 在上面添加softmax分類器
model = Model([text_input, question_input], answer)
model.compile(optimizer='rmsprop', loss = 'categorical_crossentropy', metrics=['acc'])
- 可以向模型屬於一個numpy數組組成的列表,或者輸入一個名稱映射爲numpy的數組的字典。
# 7-2 將數據輸入到多輸入模型中
import numpy as np
from keras.utils import to_categorical
num_samples = 1000
max_length = 100
text = np.random.randint(1, text_vocabulary_size, size =(num_samples, max_length))
question = np.random.randint(1, question_vocabulary_size, size=(num_samples, max_length))
answers = np.random.randint(answer_vocabulary_size, size=(num_samples))
answers = to_categorical(answers, answer_vocabulary_size)
model.fit([text, question], answers, epochs=10, batch_size=128)
model.fit({'text': text, 'question':question}, answers, epochs=10, batch_size=128)
7.1.3 多輸出模型
- 使用函數式API構建多個輸出的模型。
# 7-3 用函數式API實現一個三輸出模型
from keras import layers
from keras import Input
from keras.models import Model
vocabulary_size = 50000
num_income_groups = 10
posts_input = Input(shape=(None,), dtype='int32', name='posts')
embedded_posts = layers.Embedding(256, vocabulary_size)(posts_input)
x = layers.Conv1D(128, 5, activation='relu')(embedded_posts)
x = layers.MaxPooling1D(5)(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.MaxPooling1D(5)(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.GlobalMaxPooling1D()(x)
x = layers.Dense(128, activation='relu')(x)
age_prediction = layers.Dense(1, name='age')(x)
income_prediction = layers.Dense(num_income_groups, activation='softmax',name='income')(x)
gender_prediction = layers.Dense(1, activation='sigmoid', name='gender')(x)
mdoel = Model(posts_input, [age_prediction, income_prediction, gender_prediction])
- 訓練這種模型需要對網絡各個頭制定不同的損失函數。
# 7-4 多輸出模型的編譯選項:多重損失
'''
model.compile(optimizer='rmsprop',
loss=['mse', 'categoracal_crossentropy', 'binary_crossentropy'])
'''
model.compile(optimizer='rmsprop',
loss={'age':'mse',
'income': 'categorical_crossentropy',
'gender': 'binary_crossentropy'})
- 爲了平衡不同損失的貢獻,讓交叉熵的損失權重取10,而MSE損失的權重取0.5。
# 7-5 多輸出模型的編譯選項:損失加權
model.compile(optimizer='rmsprop',
loss=['mse','categorical_crossentropy','binary_crossentropy'],
loss_weights = [0.25, 1., 10.])
# 與上面方法等效,且只有輸出層具有名稱時才採用這種寫法
model.compile(optimizer='rmsprop',
loss={'age':'mse',
'income': 'categorical_crossentropy',
'gender': 'binary_crossentropy'}
loss_weights = {'age': 0.25,
'income': 1.,
'gender': 10.})
# 7-6 將數據輸入到多輸出模型中
model.fit(posts, [age_targets, income_targets, gender_targets], epochs=10, batch_size=64)
mode.fit(posts, {'age': age_targets,
'income': income_targets,
'gender': gender_targets},
epochs=10, batch_size=64)
7.1.4 層組成的有向無環圖
利用Keras中的神經網絡可以是層組成的任意有向無環圖。兩個著名的模型是Inception模塊和殘差連接。
- Inception模塊
Google:模塊的堆疊,並行分支。InceptionV3:
- 1x1卷積的作用(點卷積):有助於區分開通道特徵學習和空間特徵學習。
7.1.5 共享層權重
函數APi能夠多次重複使用一個層的實例。每次調用可以重複使用相同的權重。
# 共享權重
from keras import layers
from keras import Input
from keras.models import Model
lstm = layers.LSTM(32)
# 構建模型的左右分支
left_input = Input(shape=(None, 128))
left_output = lstm(left_input)
right_input = Input(shape=(None, 128))
right_output = lstm(right_input)
# 在上面構建一個分類器
merged = layers.concatenate([left_output, right_output], axis = -1)
predictions = layers.Dense(1, activation = 'sigmoid')(merged)
# 模型實例化
model = Model([left_input, right_input], predictions)
model.fit([left_data, right_data], targets)
7.1.6 將模型作爲層
函數式APi中,可以像使用層一樣使用模型。
類似於y=model(x)
,如果模型具有多個輸入張量和多個輸出張量,那麼意味着可以在一個輸入張量上調用模型,並得到一個輸出張量。y1, y2 = model([x1, x2])
from keras import layers
from keras import applications
from keras import Input
xception_base = applications.Xception(weights=None, include_top = False)
left_input = Input(shape=(250, 250, 3))
right_input = Input(shape=(250, 250, 3))
left_features = xception_base(left_input)
right_input = xception_base(right_input)
merged_features = layers.concatenate([left_features, right_input], axis = -1)
7.2 使用Keras回調函數和TensorBoard來檢查並監控深度學習模型
本節介紹訓練過程中如何更好訪問並控制模型內部過程的方法。
7.2.1 訓練過程中將回調函數作用於模型
- 模型檢查點
- 提前終止
- 在訓練過程中動態調節某些函數值
- 在訓練過程中記錄訓練指標和驗證指標
- ModelCheckpoint與EarlyStoppping回調函數
如果監控的目標輪數不再改善,可以EarlyStopping來回調函數。
import keras
callback_list =[
keras.callbacks.EarlyStopping(
monitor = 'acc',
patience = 1,
),
keras.callbacks.ModelCheckpoint(
filepath = 'my_model.h5',
monitor = 'val_loss',
save_best_only = True,
)
]
model.compile(optimizer = 'rmsprop',
loss = 'binary_crossentropy',
metrics = ['acc'])
'''
model.fit(x, y, epochs=10,
batch_size = 32,
callbacks = callbacks_list,
validation_data = (x_val, y_val))
'''
這裏通過callback這個參數將earlystoppping和modelcheckpointliangge屬性加入模型。
- ReduceLROnPlateau回調函數
如果驗證損失不再改善,可以使用這個回調函數降低學習率。
callback_list =[
keras.callbacks.ReduceLROnPlateau(
monitor = 'val_loss',
factor = 0.1,
patience = 10,
)
]
- 編寫自己的回調函數
創建keras.callbacks.Callback類的子類,實現下面的方法:
on_epoch_begin 在每輪開始時被調用
on_epoch_end
on_batch_begin 在處理每個批量之前被調用
on_batch_end
on_train_begin 在訓練開始時被調用
on_train_end
import keras
import numpy as np
class ActivationLogger(keras.callbacks.Callback):
def set_model(self, model):
self.model = model
layer_outputs = [layer.output for layer in model.layers]
self.activations_model = keras.models.Model(model.input, layer_outputs)
def on_epoch_end(self, epoch, logs = None):
if self.validation_data is None:
raise RuntimeError('Requires validation_data.')
validation_sample = self.validation_data[0][0:1]
activations = self.activations_model.predict(validation_sample)
f = open('actifvations_at_epoch_' + str(epoch) + '.npz', 'w')
np.savez(f, activations)
f.close()
7.2.2 TensorBoard簡介:TensorFlow的可視化框架
想要做好研究或者開發出好的模型,需要知道模型內部發生了什麼。
# 7-7 使用了TensorBoard的文本分類模型
import keras
from keras import layers
from keras.datasets import imdb
from keras.preprocessing import sequence
max_features = 2000
max_len = 500
(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words = max_features)
x_train = sequence.pad_sequences(x_train, maxlen = max_len)
x_test = sequence.pad_sequences(x_test, maxlen = max_len)
model = keras.models.Sequential()
model.add(layers.Embedding(max_features, 128, input_length = max_len, name = 'embed'))
model.add(layers.Conv1D(32, 7, activation = 'relu'))
model.add(layers.MaxPooling1D(5))
model.add(layers.Conv1D(32, 7, activation = 'relu'))
model.add(layers.GlobalMaxPooling1D())
model.add(layers.Dense(1))
model.summary()
model.compile(optimizer = 'rmsprop',
loss = 'binary_crossentropy',
metrics = ['acc'])
在開始使用TensorBoard之前創建一個目錄,保存生成的日誌文件。在cmd窗口輸入。
# 7-8 爲TensorBoard日誌文件創建一個目標
$ mkdir my_log_dir
# 7-9 使用一個TensorBoard回調函數來訓練模型
callbacks = [
keras.callbacks.TensorBoard(
log_dir = 'my_log_dir',
histogram_freq = 1,
embeddings_freq = 1,
)
]
history = model.fit(x_train, y_train, epochs = 20,
batch_size = 128,
validation_split = 0.2,
callbacks = callbacks)
下面使用命令啓動TensorBoard服務器。
S tensorboard --logdir = my_log_dir4
7.3 讓模型性能發揮到極致
7.3.1 高級架構模式
- 批標準化BatchNorm:訓練過程中適應性將數據標準化。
- 深度可分離卷積:有一個層可以替代Conv2D,讓模型跟輕量。
7.3.2 超參數優化
hyperparameter
7.3.3 模型集成
將一組分類器的預測結果彙集在一起。