keras之迁移学习小demo(四)

0 概要

如果不懂迁移学习的概念——> 什么是迁移学习 (Transfer Learning)?
本篇文章的预训练模型是从keras之分类数字图片(二)内获取的。

要求:

“食用”方式

  • 先“食用” keras之分类数字图片(二) 再观看这篇文章,效果更佳(不是捆绑消费)
  • 或者通过网盘获取 h5 模型文件,直接看这篇文章,效果略差
  • h5 模型文件获取方式:百度网盘 提取码:gedt
    在这里插入图片描述

1 迁移学习

步骤:

  1. 载入模型,并了解该模型的基本信息
  2. 将该模型的网络层全部冻结
  3. 原模型选择训练层的两种方式
  4. 自定义自己的网络模型
  5. 加载数据并在新的模型基础上训练

1.1 模型基本信息

# 1、载入模型,并了解该模型的基本信息
# 由于原模型做的是识别手写数字图片的一个10分类任务,所以原模型最终的全连接层有10个神经元
from keras import models
model = models.load_model("dentify_writtern_number_20210129_1209/epoch:10-loss:0.2525.h5")

from keras.utils import plot_model
for (i,layer) in enumerate(model.layers):
  print (i,layer)
print (model.summary())
# plot_model(model,show_shapes="true")

运行效果:这个时候载入的模型,既包括网络结构也包括已经训练好的参数
在这里插入图片描述

1.2 冻结原模型

# 2、将该模型的网络层全部冻结
for layer in model.layers:
  layer.trainable = False
print (model.summary())

运行效果:将载入模型的参数设置为 “不训练”,之后训练模型的时候,这些参数就不会变化
在这里插入图片描述

1.3 选择训练层

关于选择 载入模型 的哪几个训练层,以下讲解了两种方式:

# 3、原模型选择训练层的两种方式
from keras.models import Model
from keras.models import Sequential

# 第一种 
# 选取原模型第一层至倒数第二层
model1 = Model(inputs=model.input, outputs=model.layers[-2].output)  

# 第二种
# 选取原模型第一层至倒数第二层
model2 = Sequential()
for layer in model.layers[:-1]:  # 跳过最后一层 
   model2.add(layer)

# 我尝试过使用这种方式model2.layers.pop()来删除最后一层训练层,毕竟model2.layers是list数据类型,但是无效
# 所以各位掌握以上两种方式就足够了
print (model.summary())
print (model1.summary())
print (model2.summary())

运行效果:可以相互比对下,更好理解
在这里插入图片描述在这里插入图片描述
在这里插入图片描述而且以上两种方式生成的新模型,参数和原模型的参数是保持一致的。

# 看以下输出就知道
w1,b1 = model.layers[1].weights
print (b1)
w,b = model1.layers[2].weights
print (b)
w2,b2 = model2.layers[1].weights
print (b2)

运行效果:
在这里插入图片描述

1.4 自定义网络模型

  • 由于原模型做的是识别手写数字图片的一个10分类任务,所以原模型最终的全连接层有10个神经元
  • 这个Demo目的是掌握迁移学习使用,所以我将该模型的最后的10个神经元的全连接层删除,换成自定义的500个神经元后面再接10个神经元
# 4、自定义自己的网络模型
from keras.layers import Dense 
model2.add(Dense(500,activation="relu"))
model2.add(Dense(10,activation="softmax"))
model2.compile(loss="categorical_crossentropy",optimizer="sgd",metrics="acc")
print (model2.summary())

运行效果:
在这里插入图片描述

1.5 训练模型

  1. 先加载数据
  2. 进行数据预处理
  3. 再训练模型
  4. keras之分类数字图片(二)处理数据一致。
# 5、加载数据并在新的模型基础上训练
from keras.datasets import mnist
from keras.utils import np_utils
import numpy as np

# 5.1 加载mnist数据集
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# train中有6万张手写数字图片,test中有1万张手写数字图片
print (x_train.shape)
print (x_test.shape)

# 5.2 数据预处理
# 进行one-hot(独热编码)
# 进行one-hot编码是因为损失函数需要使用交叉嫡函数(cross_entropy)
# 交叉嫡函数详解  https://zhuanlan.zhihu.com/p/35709485 
y_train = np_utils.to_categorical(y_train,10)
y_test = np_utils.to_categorical(y_test,10)
# 由于下载数据得到是uint类型,在神经网络无法进行合理运算,在这里将其转化为float32类型
x_train = x_train.astype(np.float32)
x_test = x_test.astype(np.float32)
# 由于conv2D函数需要这四维的图片数据,这里就reshape维度
x_train = x_train.reshape([-1,28,28,1])
x_test = x_test.reshape([-1,28,28,1])

运行效果:
在这里插入图片描述

# 由于新增加的Dense层没有训练,其结果也是极差的
eva = model2.evaluate(x_test,y_test,batch_size=1000)
print (eva)

运行效果:
在这里插入图片描述

# 开始对自定义的Dense训练
model2.fit(x_train,y_train,batch_size=128,epochs=20)

运行效果:

  • 由于在原模型的基础上,做出了一定的改动,现在模型仍保有原模型的一定特征。
  • 在这个基础上,再进行训练,效果就会更好。
  • 一般来说,手写数字项目第一个epoch的准确度大概是百分之10到20。
  • 而这个第一个epoch就有将近百分之90

在这里插入图片描述

# 使用测试集合检验模型性能
loss = model2.evaluate(x_test,y_test)
print (loss)

运行效果:准确度大概百分之98,哟西,不错!!!
在这里插入图片描述

2 源代码汇总

# 1、载入模型的基本信息
# 由于原模型做的是识别手写数字图片的一个10分类任务,所以原模型最终的全连接层有10个神经元
from keras import models
model = models.load_model("dentify_writtern_number_20210129_1209/epoch:10-loss:0.2525.h5")
from keras.utils import plot_model
for (i,layer) in enumerate(model.layers):
  print (i,layer)
print (model.summary())
# plot_model(model,show_shapes="true")


# 2、将该模型的网络层全部冻结
for layer in model.layers:
  layer.trainable = False
print (model.summary())


# 3、原模型选择训练层的两种方式
from keras.models import Model
from keras.models import Sequential

# 第一种 
model1 = Model(inputs=model.input, outputs=model.layers[-2].output)  

# 第二种
model2 = Sequential()
for layer in model.layers[:-1]:  # 跳过最后一层 
   model2.add(layer)

# 我尝试过使用这种方式model2.layers.pop()来删除最后一层训练层,毕竟model2.layers是list数据类型,但是无效
# 所以各位掌握以上两种方式就足够了
print (model.summary())
print (model1.summary())
print (model2.summary())

# 而且以上两种方式生成的新模型,参数和原模型是保持一致的
# 看以下输出就知道
w1,b1 = model.layers[1].weights
print (b1)
w,b = model1.layers[2].weights
print (b)
w2,b2 = model2.layers[1].weights
print (b2)


# 4、自定义自己的网络模型
# 由于原模型做的是识别手写数字图片的一个10分类任务,所以原模型最终的全连接层有10个神经元
# 这个Demo目的是掌握迁移学习使用,所以我将该模型的最后的10个神经元的全连接层删除,换成自定义的500个神经元后面再接10个神经元
from keras.layers import Dense 
model2.add(Dense(500,activation="relu"))
model2.add(Dense(10,activation="softmax"))
model2.compile(loss="categorical_crossentropy",optimizer="sgd",metrics="acc")
print (model2.summary())


# 5、加载数据并在新的模型基础上训练
from keras.datasets import mnist
from keras.utils import np_utils
import numpy as np

# 加载mnist数据集
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# train中有6万张手写数字图片,test中有1万张手写数字图片
print (x_train.shape)
print (x_test.shape)

# 进行one-hot(独热编码)
# 进行one-hot编码是因为损失函数需要使用交叉嫡函数(cross_entropy)
# 交叉嫡函数详解  https://zhuanlan.zhihu.com/p/35709485 
y_train = np_utils.to_categorical(y_train,10)
y_test = np_utils.to_categorical(y_test,10)
# 由于下载数据得到是uint类型,在神经网络无法进行合理运算,在这里将其转化为float32类型
x_train = x_train.astype(np.float32)
x_test = x_test.astype(np.float32)
# 由于conv2D函数需要这四维的图片数据,这里就reshape维度
x_train = x_train.reshape([-1,28,28,1])
x_test = x_test.reshape([-1,28,28,1])

# 由于新增加的Dense层没有训练,其结果也是极差的
eva = model2.evaluate(x_test,y_test,batch_size=1000)
print (eva)

# 开始对自定义的Dense训练
model2.fit(x_train,y_train,batch_size=128,epochs=20)

# 使用测试集合检验模型性能
loss = model2.evaluate(x_test,y_test)
print (loss)

如有疑惑,以下评论区留言。力所能及,必答之。

猜你喜欢

转载自blog.csdn.net/weixin_41466575/article/details/113524043
今日推荐