tensorflow2.0 下keras模型的保存与加载

在前面的博文tensorflow2.0自制神经网络数据集及预测结果(混淆矩阵)可视化中,我们用了谷歌训练好的网络模型DesNet121来训练我们的图片,当用自己的电脑和自写的网络架构来训练图片时,我们需要及时的保存我们训练好的网络,以便以后测试或者接着训练。现在网上有很多的博客介绍了在keras框架下如何保存和加载训练好的模型,在此我做一个总结吧,也方便我以后查看,不用到处去别的地方找了。
我将DesNet网络换为自己的resnet18以后开始训练,训练结束后在代码的最后加了一行

model.save('my_model.h5')#保存整个模型和权重

但是却报错了:
在这里插入图片描述这样报错的原因是HDF5格式要求模型是函数式(Functional)模型或者是顺序式(Sequential)模型,它不适用于子类化模型。什么意思?举例说明:

#顺序式模型
model=tf.keras.models.Sequential()
model.add(tf.keras.layres.Dense(128,activation='relu'))
model.add(tf.keras.layres.Dense(256,activation='relu'))
model.add(tf.keras.layres.Dense(10,activation='softmax'))
model.compile(optimizer=optimizers.Adam(lr=0.01),loss=losses.CategoricalCrossentropy(from_logits=True),metrics=['accuracy'])
model.fit(x_train,y_yrain,validation_data=(x_test, y_test),epochs=20)
model.evaluate(x_test, y_test)
model.save('my_model.h5')
#在这样的顺序式下可以直接保存模型的架构和整个训练的权重

#函数式模型
inputs=tf.keras.layers.Input(shape=(28,28))
x=tf.keras.layers.Dense(32,activation='relu')(inputs)
x=tf.keras.layers.Dense(64,activation='relu')(x)
logits=tf.keras.layers.Dense(10,activation='softmax')(x)
model=tf.tf.keras.Model(inputs=inputs,outputs=logits)
model.compile(optimizer=optimizers.Adam(lr=0.01),loss=losses.CategoricalCrossentropy(from_logits=True),metrics=['accuracy'])
model.fit(x_train,y_yrain,validation_data=(x_test, y_test),epochs=20)
model.evaluate(x_test, y_test)
model.save('my_model.h5')
#这两种结构的网络都可以直接model.save,保存整个模型和权重

#在调用保存的模型时只需要添加一行代码
model = tf.keras.models.load_model('my_model.h5')
#然后就可以继续训练模型或者评估模型了
model.fit()#继续训练模型
model.evaluate()#直接评估模型

但是像下面的这个resnet18就不属于以上两种结构了,它属于子类式的

import  os
import  tensorflow as tf
import  numpy as np
from    tensorflow import keras
from    tensorflow.keras import layers
#定义一个类
class ResnetBlock(keras.Model):
    def __init__(self, channels, strides=1):
    super(ResnetBlock, self).__init__()
        self.channels = channels
        self.strides = strides
        self.conv1 = layers.Conv2D(channels, 3, strides=strides,
                                   padding=[[0,0],[1,1],[1,1],[0,0]])
        self.bn1 = keras.layers.BatchNormalization()
        self.conv2 = layers.Conv2D(channels, 3, strides=1,
                                   padding=[[0,0],[1,1],[1,1],[0,0]])
        self.bn2 = keras.layers.BatchNormalization()
        
        if strides!=1:
            self.down_conv = layers.Conv2D(channels, 1, strides=strides, padding='valid')
            self.down_bn = tf.keras.layers.BatchNormalization()
         def call(self, inputs, training=None):
        residual = inputs
        x = self.conv1(inputs)
        x = tf.nn.relu(x)
        x = self.bn1(x, training=training)
        x = self.conv2(x)
        x = tf.nn.relu(x)
        x = self.bn2(x, training=training)
        # 残差连接
        if self.strides!=1:
            residual = self.down_conv(inputs)
            residual = tf.nn.relu(residual)
            residual = self.down_bn(residual, training=training)
        x = x + residual
        x = tf.nn.relu(x)
        return x
class ResNet(keras.Model):
    def __init__(self, num_classes, initial_filters=16, **kwargs):
        super(ResNet, self).__init__(**kwargs)
        self.stem = layers.Conv2D(initial_filters, 3, strides=3, padding='valid')
        self.blocks = keras.models.Sequential([
            ResnetBlock(initial_filters * 2, strides=3),
            ResnetBlock(initial_filters * 2, strides=1),
            # layers.Dropout(rate=0.5),
            ResnetBlock(initial_filters * 4, strides=3),
            ResnetBlock(initial_filters * 4, strides=1),
            ResnetBlock(initial_filters * 8, strides=2),
            ResnetBlock(initial_filters * 8, strides=1),
            ResnetBlock(initial_filters * 16, strides=2),
            ResnetBlock(initial_filters * 16, strides=1),
        ])
        self.final_bn = layers.BatchNormalization()
        self.avg_pool = layers.GlobalMaxPool2D()
        self.fc = layers.Dense(num_classes)
    def call(self, inputs, training=None):
        # print('x:',inputs.shape)
        out = self.stem(inputs,training=training)
        out = tf.nn.relu(out)
        # print('stem:',out.shape)
        out = self.blocks(out, training=training)
        # print('res:',out.shape)
        out = self.final_bn(out, training=training)
        # out = tf.nn.relu(out)
        out = self.avg_pool(out)
        # print('avg_pool:',out.shape)
        out = self.fc(out)
        # print('out:',out.shape)
        return out
def main():
    model = ResNet(10)#参数10被赋予num_classes
    model.build(input_shape=(4,28,28,1))
    model.summary()
    model.compile()
    model.fit()
    model.evaluate()
    #model.save()#直接这么写会报错,在这种子类式的情况下我们可以保存训练好的权重
    model.save_weights('/添加自己的路径/my_weight')
if __name__ == '__main__':
    main()

权重保存好了,下次可以加载进来用了。注意,在这种情况下我们在加载权重之前要构建一个和之前的模型一样的架构,不然会出错

def main():
    model=ResNet(10)
    model.built(input_shape=(4,28,28,1))
    model.compile()
    model.load_weights('/添加自己的路径/my_weight')
    #model.fit() #要是模型没有训练好,可以继续接着训练模型
    model.evaluate()#不用训练模型,直接加载权重以后评估测试集数据

本文到此结束

你可能感兴趣的:(tensorflow2.0 下keras模型的保存与加载)