知识点:TensorFlow训练模型的保存和恢复-灵析社区

GG

1. 为什么要保存模型数据?

人生重要的是积累,20岁到了什么程度,在此基础上30岁又达到什么境界,如此积累,不断进步。

你有没有想过,你花半天时间背诵了一页《三字经》,吃了个午饭后,全忘了。

于是,你加大投入,一天一夜背会了整篇《三字经》,结果睡了一觉后又全忘了。

是的,这肯定很痛苦。

同样,对于神经网络而言也一样。

刚刚耗费了200个小时,认识了30万张狗狗的图片,并计算出了他们的特征,能够轻松分辨出哈士奇和狼,结果计算机一断电,它又空白了。

这肯定不行。

因此,训练的结果要及时保存,保存的结果可以随时恢复。

当再次训练时,可以在上次成果的基础上继续累加。

就像一个人一样,研究学问到80岁,已经是满腹经纶了。

2. 训练结果的保存和恢复

2.1 新HelloWorld:fashion_mnist

我们拿人工智能的新HelloWorld来举例子。

原来人工智能的入门例子是mnist手写数据集。

后来改成fashion_mnist这个数据集了。

这个数据集,主要是10个品类的时尚装饰。

标签
0T恤/上衣
1裤子
2套头衫
3连衣裙
4外套
5凉鞋
6衬衫
7运动鞋
8
9短靴

通过训练它们,让神经网络认识他们,从而遇到一张图可以说出是衬衫还是裤子。

我们的重点主要是讲保存训练数据,所以训练相关的代码一笔带过。

from os import times
from re import T
import tensorflow as tf
from tensorflow import keras
import numpy as np
import cv2

# 分类名称
class_names = ["T恤/上衣","裤子","套头衫","连衣裙","外套","凉鞋","衬衫","运动鞋","包","短靴"]
# 读取数据集-构建网络模型-进行训练
fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
train_images = train_images/255.0
test_images = test_images/255.0
# 构建模型
model = keras.Sequential([
    keras.layers.Flatten(input_shape=(28,28)),
    keras.layers.Dense(128, activation='relu'),
    keras.layers.Dropout(0.2),
    keras.layers.Dense(10, activation='softmax')
])
# 配置训练
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
# 开始训练
model.fit(train_images, train_labels, epochs=50)

运行后是这样的效果:

Epoch 1/10
1875/1875 [======] - 1s 602us/step - loss: 0.5273 - accuracy: 0.8111
Epoch 2/10
1875/1875 [======] - 1s 594us/step - loss: 0.3994 - accuracy: 0.8554
Epoch 3/10
1875/1875 [======] - 1s 590us/step - loss: 0.3673 - accuracy: 0.8662
……

上面就训练完数据了。

2.2 内存中的数据

如果运行了上面的代码,那么其实两个关键数据(网络模型结构、训练的权重)就已经在内存中了,主要存在model中,因为刚刚就是训练的它,程序还没有关闭,它还是活的。

这时候,可以找一个验证数据试一试,这个验证数据是程序从没有见过的,比如说下面的img_2.png这个裤子。

通过代码识别一下:

img =cv2.imread('./img/img_2.png',0) 
img = img/255.0
img = np.expand_dims(img, 0)
p = model.predict(img)
print(p)
print(class_names[np.argmax(p[0])])

结果如下:

[[6.5590651e-11 1.0000000e+00 2.8622449e-13 6.2133689e-09 2.7508923e-10
  2.4884808e-19 7.4704088e-12 2.6084349e-25 3.8184945e-13 4.6570902e-23]]
裤子

上面输出了10个分类的可能性,其中第2个分类的可能性为100%,第2个分类索引为1。
class_names = ["T恤/上衣","裤子","套头衫","连衣裙","外套","凉鞋","衬衫","运动鞋","包","短靴"]

所以它是个裤子。

保存在内存中,很不稳定,关闭程序就丢失了。如果想要使用,必须重新进行训练。

2.3 模型保存为json、h5文件

一个训练完成的神经网络,包含结构和权重两个部分。

举个不恰当的例子,把下面这张图比喻成训练好的神经网络。其中的架子部分是每一层神经网络的结构。那么神经网络的权重,就表示里面存放的花盆等物品。

如果想从另一个地方、另一个时间还原上面的这个角落,就需要记录两个东西:一个是容纳物品的框架,另一个是被摆放的物品。对应到神经网络就是结构和权重。

神经网络的结构,可以通过json文件来存储。神经网络的权重,可以通过h5文件存储。

保存起来非常简单,代码如下:

# 保存训练的模型
model_json = model.to_json()
with open('./save/model.json', 'w') as file:
    file.write(model_json)
# 保存训练的权重
model.save_weights('./save/model.h5')

当训练完成之后,所有的信息都保存在了model中,但此时只在内存里。通过model.to_json()以及model.save_weights可以把信息提取成数据持久化到文件里。

2.4 读取json、h5文件恢复模型

想使用的时候,也很简单,直接加载并使用就可以:

# 读取训练的模型结果
with open('./save/model.json', 'r') as file:
    model_json_from = file.read()
new_model = keras.models.model_from_json(model_json_from)
new_model.load_weights('./save/model.h5')

# 进行预测
img =cv2.imread('./img/img_2.png',0) 
img = img/255.0
img = np.expand_dims(img, 0)
p = model.predict(img)
print(p)
print(class_names[np.argmax(p[0])])

输出的结果,也是:裤子。

同上面2.2章节中预测不同的是,你不用先执行训练的代码了。

这时,你可以新建一个文件单纯只做识别的任务,因为训练好的信息已经存储到json和h5里了,你读取出来使用就可以了。

2.5 恢复模型继续训练

如果某次你训练了2天数据,还没有结束,但是你要提着鸡蛋去走亲戚,因为没有人看护服务器,你需要先暂停。正好你看过上面的教程,先把模型保存成json和h5了。

去到亲戚家,住了5天,临走前亲戚送你一些小鸡仔,并且又给你了一些训练数据。你回到家,需要继续训练。

这时候怎么办?

我们看一下。

还是fashion_mnist的训练,我们训练了20轮,训练结果是这样的:

Epoch 1/20
1875/1875 [======] - 1s 579us/step - loss: 0.5342 - accuracy: 0.8096
……
Epoch 20/20
1875/1875 [======] - 1s 560us/step - loss: 0.2347 - accuracy: 0.9102

训练集的正确率从0.80到0.91。

假设我们中断了训练,并且依照2.3保存了模型。

后来,我们又想继续训练。

# 读取训练的模型结果
with open('./save/model.json', 'r') as file:
    model_json_from = file.read()
new_model = keras.models.model_from_json(model_json_from)
new_model.load_weights('./save/model.h5')

# 训练模型
new_model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
new_model.fit(train_images, train_labels, epochs=10)

训练结果是这样的:

Epoch 1/10
1875/1875 [======] - 1s 604us/step - loss: 0.2313 - accuracy: 0.9128
Epoch 2/10
1875/1875 [======] - 1s 602us/step - loss: 0.2275 - accuracy: 0.9136
……

我们看到,本次训练第1轮准确率就是0.91。这和上次训练结束时的准确率是对应的。这说明本次是在一定准确率的基础上继续训练的。

2.6 保存最优权重

上面讲了如何保存训练结果,那是保存最后训练的结果。

悄悄问一句,最后一次训练就是最好的结果吗?

未必!

如果说最低点就是最好的训练结果,那么在某个区间内,最低点可能会被误判。


所以,你保存的只是最后结果,并不是最优的结果。

那么如何保存最优结果呢?

filePath = 'best_weights.h5'
checkpoint = tf.keras.callbacks.ModelCheckpoint(filepath=filePath, monitor='val_accuracy', verbose=1, save_best_only=True, mode = 'max',varbose=1)
callback_list = [checkpoint]
model.fit(train_images, train_labels, validation_split=0.2 ,epochs = 30, batch_size = 64, verbose = 0, callbacks = callback_list)

打印结果如下:

Epoch 00001: val_accuracy improved from -inf to 0.89317, saving model to best_weights.h5
Epoch 00002: val_accuracy improved from 0.89317 to 0.89617, saving model to best_weights.h5
Epoch 00003: val_accuracy did not improve from 0.89617

通过以上例子可以看出,当准确率有提高时,会把文件保存起来。即便是后面有最新的训练结果,但是准确率并没有提高,是不会保存的。

如果你不想只保存最好的,也想了解它是如何一次改善的,可以调用如下代码:

filePath = 'weights-improvement-{epoch:02d}-{val_accuracy:2f}.h5'
checkpoint = tf.keras.callbacks.ModelCheckpoint(filepath=filePath, monitor='val_accuracy', verbose=1, save_best_only=True, mode = 'max',varbose=1)
callback_list = [checkpoint]
model.fit(train_images, train_labels, validation_split=0.2 ,epochs = 30, batch_size = 64, verbose = 0, callbacks = callback_list)

打印结果如下:

Epoch 00001: val_accuracy improved from -inf to 0.89417, saving model to weights-improvement-01-0.894167.h5
Epoch 00002: val_accuracy improved from 0.89417 to 0.89475, saving model to weights-improvement-02-0.894750.h5
Epoch 00003: val_accuracy did not improve from 0.89475

它会把准确率升高的每次都记录下来。

有了上面的方法,训练数据就有了记忆。

可以随时停,随时续,随时用。想想还有点小激动呢!

阅读量:2008

点赞量:0

收藏量:0