本文是 tf.keras 系列文章的第五篇。通過手寫數字識別數據集介紹了 Keras 模型訓練中的 檢查點(checkpoint)
文件,.weights
文件,.pb
文件以及 .h5
文件等四種格式的文件保存以及加載方式。掌握這些方法可以很方便地在模型訓練期間保存模型以及在推斷時加載模型,可以從中斷的地方繼續訓練,避免重新開始訓練。
文章目錄
代碼環境:
python version: 3.7.6
tensorflow version: 2.1.0
導入必要的包:
import os
import tensorflow as tf
from tensorflow import keras
1. 構造模型並訓練
1.1 加載數據集
(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()
train_labels = train_labels[:1000]
test_labels = test_labels[:1000]
train_images = train_images[:1000].reshape(-1, 28 * 28) / 255.0 # -1 表示 unspecified value,即該維度不用指定,系統會自動計算。
test_images = test_images[:1000].reshape(-1, 28 * 28) / 255.0
1.2 定義一個簡單的模型並訓練
# 定義一個簡單的序列模型
def create_model():
model = tf.keras.models.Sequential([
keras.layers.Dense(512, activation='relu', input_shape=(784,)),
keras.layers.Dropout(0.2),
keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
return model
# 創建一個基本的模型實例
model = create_model()
# 顯示模型的結構
model.summary()
2. 將模型保存爲 checkpoint 文件格式
2.1 設置檢查點回調並保存模型
此舉主要是爲了在訓練過程中保存模型,以便在中斷的地方繼續訓練,從而避免從頭開始訓練的風險。使用 tf.keras.callbacks.ModelCheckpoint
來進行配置:
checkpoint_path = "training_1/cp.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)
# 創建callback來保存模型的權重
cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,
save_weights_only=True,
verbose=1)
# 在模型訓練時使用回調
model.fit(train_images,
train_labels,
epochs=10,
validation_data=(test_images,test_labels),
callbacks=[cp_callback])
2.2 從檢查點加載權重評估模型
通過 tf.keras.models.load_weights()
方法實現訓練模型的加載:
# 加載權重
model.load_weights(checkpoint_path)
# 重新評估模型
loss, acc = model.evaluate(test_images, test_labels, verbose=2)
print("Restored model, accuracy: {:5.2f}%".format(100*acc))
輸出:
1000/1000 - 0s - loss: 0.4213 - accuracy: 0.8670
Restored model, accuracy: 86.70%
2.3 設置回調函數實現多個epoch保存一次
# 使用 format()方法實現動態命名
checkpoint_path = "training_2/cp-{epoch:04d}.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)
# 定義一個回調函數實現每5個epoch保存一次檢查點文件
cp_callback = tf.keras.callbacks.ModelCheckpoint(
filepath=checkpoint_path,
monitor='val_loss',
verbose=1,
save_weights_only=True,
mode='auto',
period=5) # 根據警告,換爲save_freq,是逐個保存,可能存在bug;
# 創建一個新的模型實例
model = create_model()
# 傳入 checkpoint_path 參數,實現將檢查點文件保存到該路徑
model.save_weights(checkpoint_path.format(epoch=0))
# 使用自定義的回調函數訓練模型
model.fit(train_images,
train_labels,
epochs=50,
callbacks=[cp_callback],
validation_data=(test_images,test_labels),
verbose=0)
輸出:
WARNING:tensorflow:`period` argument is deprecated. Please use `save_freq` to specify the frequency in number of samples seen.
Epoch 00005: saving model to training_2/cp-0005.ckpt
Epoch 00010: saving model to training_2/cp-0010.ckpt
Epoch 00015: saving model to training_2/cp-0015.ckpt
Epoch 00020: saving model to training_2/cp-0020.ckpt
Epoch 00025: saving model to training_2/cp-0025.ckpt
Epoch 00030: saving model to training_2/cp-0030.ckpt
Epoch 00035: saving model to training_2/cp-0035.ckpt
Epoch 00040: saving model to training_2/cp-0040.ckpt
Epoch 00045: saving model to training_2/cp-0045.ckpt
Epoch 00050: saving model to training_2/cp-0050.ckpt
<tensorflow.python.keras.callbacks.History at 0x208224ccfc8>
2.4 加載最後保存的模型並測試
1.加載最後保存的檢查點文件
# 加載最後一個檢查點文件
latest = tf.train.latest_checkpoint(checkpoint_dir)
latest # 輸出:'training_2\\cp-0050.ckpt'
2.測試
# 創建一個新的模型實例
model = create_model()
# 加載之前保存的權重(檢查點文件)
model.load_weights(latest)
# 重新評估模型
loss, acc = model.evaluate(test_images, test_labels, verbose=2)
print("Restored model, accuracy: {:5.2f}%".format(100*acc))
輸出:
1000/1000 - 0s - loss: 0.4769 - accuracy: 0.8760
Restored model, accuracy: 87.60%
【說明】:
上面的代碼將權重存儲到檢查點格式的文件的集合中,這些文件僅包含二進制格式的經過訓練的權重。檢查點包含:
- 一個或多個包含模型權重的碎片。
- 一個索引文件,指示哪些權重存儲在哪個分片中。
- 如果僅在單臺機器上訓練模型,則後綴爲一個分片:
.data-00000-of-00001
。如圖所示:
2.5 手動保存檢查點文件
通過 .save_weights() 方法實現手動保存模型,來節省空間。
# 保存權重
model.save_weights('./checkpoints/my_checkpoint')
# 創建一個新的模型實例
model = create_model()
# 恢復模型
model.load_weights('./checkpoints/my_checkpoint')
# 評估模型
loss,acc = model.evaluate(test_images, test_labels, verbose=2)
print("Restored model, accuracy: {:5.2f}%".format(100*acc))
輸出:
1000/1000 - 0s - loss: 0.4769 - accuracy: 0.8760
Restored model, accuracy: 87.60%
3. 保存整個模型
調用 model.save
將模型的網絡架構、權重和訓練配置保存在單個文件/文件夾中。在使用時,通過 load_model
加載模型,這樣就可以不同重新訓練即可使用。加載模型的同時,會恢復優化器的狀態,因此可以從停止的位置恢復訓練。
整個模型可以保存爲兩種不同的文件格式(SavedModel和HDF5)。需要注意的是,TensorFlow saved model
格式是 TF2.x
中的默認文件格式。但是,模型可以保存爲 HDF5 格式。下面將詳細介紹如何以兩種文件格式保存整個模型。
保存整個模型非常有用,這可以在 TensorFlow.js(Saved model,HDF5)中加載,然後在web 瀏覽器中訓練和運行;或者使用 TensorFlow Lite(Saved model,HDF5)將其轉換爲在移動設備上運行的模型(.pb文件)。
注意:保存和加載時需要特別注意自定義對象(例如子類模型或層)。請參見下面的“保存自定義對象”部分。
3.1 保存模型
model.save()
方法在不指定文件擴展名時,默認保存爲 .pb
文件。
# 創建模型實例並訓練
model = create_model()
model.fit(train_images, train_labels, epochs=5)
# 使用 save 方法保存模型
path='saved_model'
isExists = os.path.exists(path)
if not isExists:
# 如果不存在則創建目錄
os.makedirs(path)
model.save(path)
查看文件:
items = os.listdir(os.chdir(path))
print(os.listdir('.'))
輸出:
['assets', 'saved_model.pb', 'variables']
3.2 加載模型
# 切換回根目錄
os.chdir('..')
# 加載保存的模型
new_model = tf.keras.models.load_model(path)
# 檢查保存模型的網絡架構
new_model.summary()
輸出:
Model: "sequential_29"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_58 (Dense) (None, 512) 401920
_________________________________________________________________
dropout_29 (Dropout) (None, 512) 0
_________________________________________________________________
dense_59 (Dense) (None, 10) 5130
=================================================================
Total params: 407,050
Trainable params: 407,050
Non-trainable params: 0
_________________________________________________________________
評估
# 評估恢復的模型
loss, acc = new_model.evaluate(test_images, test_labels, verbose=2)
print('Restored model, accuracy: {:5.2f}%'.format(100*acc))
print(new_model.predict(test_images).shape)
輸出:
1000/1000 - 0s - loss: 0.4197 - accuracy: 0.8680
Restored model, accuracy: 86.80%
(1000, 10)
4. 保存爲 HDF5 文件
4.1 保存
通過設置 .h5
擴展名實現保存爲 HDF5文件。
# 創建新的模型實例並訓練
model = create_model()
model.fit(train_images, train_labels, epochs=5)
# 將整個模型(包括網絡結構和權重)保存爲 HDF5 文件
# 使用save方法通過設置文件後綴名爲 '.h5' 來實現保存爲 HDF5 文件
path='h5_format_model'
isExists = os.path.exists(path)
if not isExists:
os.makedirs(path)
model_name = f'{path}/my_model.h5'
model.save(model_name)
4.2 加載模型
# 加載保存的整個模型
new_model = tf.keras.models.load_model(model_name)
# 打印網絡架構摘要
new_model.summary()
loss, acc = new_model.evaluate(test_images, test_labels, verbose=2)
print('Restored model, accuracy: {:5.2f}%'.format(100*acc))
輸出:
1000/1000 - 0s - loss: 0.4223 - accuracy: 0.8640
Restored model, accuracy: 86.40%
Summary
Keras 通過檢查架構來保存模型。該方法保存了所有內容:
- 權重值爲模型的體系結構;
- 模型的訓練配置(傳遞給編譯的內容);
- 優化器及其狀態(如果有),這使得可以在停止的地方重新開始訓練;
注意:Keras無法保存 TF1.x 版本中的優化器(來自tf.compat.v1.train),因爲它們與檢查點不兼容。對於TF1.x 版本中的優化器,需要在加載時丟棄優化器的狀態,然後重新編譯模型。
保存自定義對象如果使用的是SavedModel格式。HDF5和SavedModel的關鍵區別在於:HDF5使用對象配置保存模型體系結構,而SavedModel保存執行圖。因此,SavedModels能夠保存自定義對象,如子類模型和自定義層,而不需要原始代碼。
要將自定義對象保存到HDF5,必須通過 get_config
以及一個可選的from_config
類方法實現。這部分以後的文章再介紹。
參考:
https://www.tensorflow.org/tutorials/keras/save_and_load