我们已经知道了如何将模型序列化到硬盘中,也知道了如何监控一个模型是否过拟合,以便于我们及时停止训练。这时候我们就会想到,有没有可能将这两种方法组合起来?当loss/accrucy有所提升的时候我们将模型序列化到硬盘中存储?答案是肯定的。
根据模型是否提升
一个很好的应用就是在训练的过程中,每当我们的模型有所进步的时候,我们将其序列化到硬盘。所谓进步,我们将其定义为loss降低或者accuracy升高。
接下来我们会在CIFAR-10数据集上训练MiniVGG网络,每当模型有所进步的时候将其序列化到硬盘中保存。
创建cifar10_checkpoint_improvements.py
文件,写入如下代码
from sklearn.preprocessing import LabelBinarizer
from nn.conv.minivggnet import MiniVGGNet
from tensorflow.keras.callbacks import ModelCheckpoint
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.datasets import cifar10
import os
# 定义输出权重信息的路径
weights = "/Users/liushanlin/PycharmProjects/DLstudy/result/weight/improvement"
# 载入训练和验证数据,并将他们缩放至[0, 1]的范围
((trainX, trainY), (testX, testY)) = cifar10.load_data()
trainX = trainX.astype("float") / 255.0
testX = testX.astype("float") / 255.0
# 将标签从整数转化为向量
lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)
# 初始化optimizer和模型
opt = SGD(learning_rate=0.01, decay=0.01/40, momentum=0.9, nesterov=True)
model = MiniVGGNet.build(width=32, height=32, depth=3, classes=10)
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])
# 构建回调函数来根据验证loss将最好的模型保存至硬盘
fname = os.path.sep.join([weights, "weights-{epoch:03d}-{val_loss:.4f}.hdf5"])
checkpoint = ModelCheckpoint(fname, monitor="val_loss", mode="min", save_best_only=True, verbose=1)
callbacks = [checkpoint]
# 训练网络
H = model.fit(trainX ,trainY, validation_data=(testX, testY), batch_size=64,
epochs=40, callbacks=callbacks, verbose=2)
运行代码,我们可以看到目录下生成了很多.hdf5文件

这些文件的名字由三部分组成:一个固定的字符串“weights” ,当前epoch 以及验证loss的值
只检查最好的模型
上面的做法保存了太多文件,有很大一部分是我们用不到的,我们对他们并不感兴趣。那么我们希望最好能只保存一个模型,当我们的模型有所提升的时候,我们将旧的文件“覆盖”掉。
创建cifar10_chechpoint_best.py
文件,写入如下代码
from sklearn.preprocessing import LabelBinarizer
from nn.conv.minivggnet import MiniVGGNet
from tensorflow.keras.callbacks import ModelCheckpoint
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.datasets import cifar10
import os
# 定义输出权重信息的路径
weights = "/Users/liushanlin/PycharmProjects/DLstudy/result/weight/best/cifar10_best_weights.hdf5"
# 载入训练和验证数据,并将他们缩放至[0, 1]的范围
((trainX, trainY), (testX, testY)) = cifar10.load_data()
trainX = trainX.astype("float") / 255.0
testX = testX.astype("float") / 255.0
# 将标签从整数转化为向量
lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)
# 初始化optimizer和模型
opt = SGD(learning_rate=0.01, decay=0.01/40, momentum=0.9, nesterov=True)
model = MiniVGGNet.build(width=32, height=32, depth=3, classes=10)
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])
# 构建回调函数来根据验证loss将最好的模型保存至硬盘
# 注意我们这次没有定义文件名格式,也没使用参数mode="min"
checkpoint = ModelCheckpoint(weights, monitor="val_loss", save_best_only=True, verbose=1)
callbacks = [checkpoint]
# 训练网络
H = model.fit(trainX, trainY, validation_data=(testX, testY), batch_size=64,
epochs=40, callbacks=callbacks, verbose=2)
我们仅仅改变了ModelCheckpoint回调函数的初始化方法,并未再向其提供文件名格式,也没有使用参数mode=“min”
因为没有提供文件名格式,所以在保存的路径中要指定保存在cifar10_best_weights.hdf5
文件中。
结果:

可以看到相比于之前,我们这次的目录中只有一个保存模型权重的文件。