【深度学习】使用预训练模型
主要有两种方法:
- 特征提取
- 微调模型
特征提取
特征提取就是使用已经训练好的网络在新的样本上提取特征,然后将这些特征输入到新的分类器,从头开始训练的过程。
卷积神经网络分为两个部分:
- 一系列池化层+卷积层,也叫卷积基
- 全连接层
特征提取就是去除之前训练好的网络的分类器,在卷积基之上运行新数据,训练新的分类器。
我们只是复用卷积基,而不用训练好的分类器的数据,这样做的原因是卷积基学到的表示更加通用,而分类器学到的表示则必然是针对模型已经训练的类别,只包含某个类别出现在整张图像中的概率信息。
另外,全连接层不包含物体在输入图像中的位置信息,因为接入全连接层的数据已经被展平,全连接层抛弃了空间的概念。
而使用卷积基,到底用多少层呢?这要看数据的特征。越往前,模型提取的特征越低级,也即是局部的,更通用的特征图,而越往后,则抽取的特征就越抽象。所以当新的数据集与原始模型训练的数据集差异较大时,可以只用模型的前几层来提取特征。
from keras.applications import VGG16
conv_base = VGG16(weights='imagenet',include_top=False,input_shape=(150, 150, 3))
conv_base.summary()
'''
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) (None, 150, 150, 3) 0
_________________________________________________________________
block1_conv1 (Conv2D) (None, 150, 150, 64) 1792
_________________________________________________________________
block1_conv2 (Conv2D) (None, 150, 150, 64) 36928
_________________________________________________________________
block1_pool (MaxPooling2D) (None, 75, 75, 64) 0
_________________________________________________________________
block2_conv1 (Conv2D) (None, 75, 75, 128) 73856
_________________________________________________________________
block2_conv2 (Conv2D) (None, 75, 75, 128) 147584
_________________________________________________________________
block2_pool (MaxPooling2D) (None, 37, 37, 128) 0
_________________________________________________________________
block3_conv1 (Conv2D) (None, 37, 37, 256) 295168
_________________________________________________________________
block3_conv2 (Conv2D) (None, 37, 37, 256) 590080
_________________________________________________________________
block3_conv3 (Conv2D) (None, 37, 37, 256) 590080
_________________________________________________________________
block3_pool (MaxPooling2D) (None, 18, 18, 256) 0
_________________________________________________________________
block4_conv1 (Conv2D) (None, 18, 18, 512) 1180160
_________________________________________________________________
block4_conv2 (Conv2D) (None, 18, 18, 512) 2359808
_________________________________________________________________
block4_conv3 (Conv2D) (None, 18, 18, 512) 2359808
_________________________________________________________________
block4_pool (MaxPooling2D) (None, 9, 9, 512) 0
_________________________________________________________________
block5_conv1 (Conv2D) (None, 9, 9, 512) 2359808
_________________________________________________________________
block5_conv2 (Conv2D) (None, 9, 9, 512) 2359808
_________________________________________________________________
block5_conv3 (Conv2D) (None, 9, 9, 512) 2359808
_________________________________________________________________
block5_pool (MaxPooling2D) (None, 4, 4, 512) 0
=================================================================
Total params: 14,714,688
Trainable params: 14,714,688
Non-trainable params: 0
'''
可以看出,最后的输出特征图的形状是(4,4,512),现在我们在这个基础上添加全连接层。现在有两种方式可选:
- 在自己的数据集上运行卷积基,将输出保存在硬盘上,然后用这个数据作为输入,输入到独立的全连接层分类器。这种方法速度快,代价低,但是不允许使用数据增强。
- 在卷积基的顶部添加Dense层来扩展已有模型,输入数据端到端运行整个模型,可以使用数据增强,但是计算代价更高。
# 使用预训练模型的卷积基提取特征
import os
import numpy as np
from keras.preprocessing.image import ImageDataGeneratorbase_dir = './data/cats_and_dogs_small'
train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')
test_dir = os.path.join(base_dir, 'test')datagen = ImageDataGenerator(rescale=1./255)
batch_size = 3def extract_features(directory, sample_count):features = np.zeros(shape=(sample_count, 4, 4, 512))labels = np.zeros(shape=sample_count)generator = datagen.flow_from_directory(directory,target_size=(150, 150),batch_size=batch_size,class_mode='binary')i = 0for inputs_batch, labels_batch in generator:features_batch = conv_base.predict(inputs_batch)features[i * batch_size: (i+1) * batch_size] = features_batchlabels[i * batch_size:(i+1) *batch_size] = labels_batchi += 1if i * batch_size >= sample_count:breakreturn features, labelstrain_features, train_labels = extract_features(train_dir, 2000)
validation_features, validation_labels = extract_features(validation_dir, 1000)
test_features, test_labels = extract_features(test_dir,1000)# 将卷积基的输出展平
train_features = np.reshape(train_features, (2000,4 * 4 * 512))
validation_features = np.reshape(validation_features, (1000, 4 * 4 * 512))
test_features = np.reshape(test_features,(1000, 4 * 4 * 512))# 定义自己的全连接分类器
from keras import models
from keras import layers
from keras import optimizersmodel = models.Sequential()
model.add(layers.Dense(256, activation='relu', input_dim=4 * 4 * 512))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(1, activation='sigmoid'))model.compile(optimizer=optimizers.RMSprop(lr=2e-5),loss='binary_crossentropy',metrics=['acc'])history = model.fit(train_features, train_labels,epochs=30, batch_size=20,validation_data=(validation_features, validation_labels))
# 绘制训练过程中的损失曲线和精度曲线
import matplotlib.pyplot as pltacc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']epochs = range(1, len(acc) + 1)plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'r', label='Validation acc')
plt.title('Training and Validation accuracy')
plt.legend()# 新加一个图
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'r', label='Validation loss')
plt.title('Training and Validation loss')
plt.legend()# plt.show() # python2环境下不需要
扩展卷积基
from keras import models
from keras import layersmodel = models.Sequential()
model.add(conv_base) # 将卷积基整个加进来
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))model.summary()
'''
Layer (type) Output Shape Param #
=================================================================
vgg16 (Model) (None, 4, 4, 512) 14714688
_________________________________________________________________
flatten_1 (Flatten) (None, 8192) 0
_________________________________________________________________
dense_7 (Dense) (None, 256) 2097408
_________________________________________________________________
dense_8 (Dense) (None, 1) 257
=================================================================
Total params: 16,812,353
Trainable params: 16,812,353
Non-trainable params: 0
'''
conv_base.trainable = False # 冻结卷积基
from keras.preprocessing.image import ImageDataGenerator
from keras import optimizerstrain_datagen = ImageDataGenerator(rescale=1./255,rotation_range=40,width_shift_range=0.2,height_shift_range=0.2,shear_range=0.2,zoom_range=0.2,horizontal_flip=True,fill_mode='nearest'
)test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(train_dir,target_size=(150, 150),batch_size=20,class_mode='binary'
)validation_generator = test_datagen.flow_from_directory(validation_dir,target_size=(150, 150),batch_size=20,class_mode='binary'
)# 编译训练模型
model.compile(loss='binary_crossentropy',optimizer=optimizers.RMSprop(lr=2e-5),metrics=['acc'])
history = model.fit_generator(train_generator,steps_per_epoch=100,epochs=30,validation_data=validation_generator,validation_steps=50
)# 绘制训练过程中的损失曲线和精度曲线
import matplotlib.pyplot as pltacc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']epochs = range(1, len(acc) + 1)plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'r', label='Validation acc')
plt.title('Training and Validation accuracy')
plt.legend()# 新加一个图
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'r', label='Validation loss')
plt.title('Training and Validation loss')
plt.legend()plt.show()
在编译和训练模型之前,一定要先冻结卷积基。
冻结的目的就是使得训练过程中提取特征的卷积基权重不变。因为全连接层的参数是随机初始化的,训练时在网络中传播的权重更新会很大,如果不把卷积基冻结,卷积基参数会被破坏掉。
Keras中冻结网络的方法很简单:将其trainable
属性设置为False
即可。
微调模型
用于特征提取的卷积基是需要被冻结的,而微调则是将顶部的几层解冻,将解冻的几层和新增的部分,如全连接层联合训练。之所以称之为微调,是因为我们只略微调整了复用的模型的更加抽象的表示部分,使得模型与当前求解问题更加相关。
需要注意的是,在微调这里,也需要先将卷积基全部冻结来训练自己的分类器,只有分类器训练完毕后,才能解冻卷积基的顶部几层,进行微调,如果分类器没有训练好,训练期间的传播误差信号很大,待微调的卷积部分会被破坏。
所以,微调的步骤总结如下:
- 在卷积基上(已训练好的网络)添加自定义网络
- 冻结基网络
- 训练所添加的部分
- 解冻基网络的一些层
- 联合训练解冻的层和添加的层
# conv_base.summary()
# 冻结知道某一层的所有层
conv_base.trainable = True
set_trainable = Falsefor layer in conv_base.layers:if layer.name == 'block5_conv1': # 从这一层开始往后均可训练set_trainable = Trueif set_trainable:layer.trainable = Trueelse:layer.trainable = False
# 微调模型
model.compile(loss='binary_crossentropy',optimizer=optimizers.RMSprop(lr=1e-5),metrics=['acc'])
history = model.fit_generator(train_generator,steps_per_epoch=100,epochs=100,validation_data=validation_generator,validation_steps=50
)
总结
- CNN是用于处理计算机视觉任务的最佳机器学习模型,即使在非常小的数据集上从零开始训练一个CNN模型,得到的结果都还不错
- 在小型数据集上的主要问题是过拟合,可用数据增强技术来降低过拟合
- 利用特征提取,可以很容易将现有的CNN网络用于新的数据集
- 微调技术是特征提取的补充,使用微调可以进一步提升模型的性能
END.
参考:
《Deep Learning with Python》
【深度学习】使用预训练模型相关推荐
- pytorch深度学习实战——预训练网络
来源:<Pytorch深度学习实战>,2.1,一个识别图像主体的预训练网络 from torchvision import models from torchvision import t ...
- 深度学习--使用预训练的卷积神经网络
文章目录 前言 一.使用预训练网络 二.将VGG16卷积基实例化 三.使用卷积基进行特征提取 1.不使用数据增强的快速特征提取 2.使用数据增强的特征提取 四.微调模型 前言 想要将深度学习应用于小型 ...
- 资源 | 李沐等人开源中文书《动手学深度学习》预览版上线
来源:机器之心 本文约2000字,建议阅读10分钟. 本文为大家介绍了一本交互式深度学习书籍. 近日,由 Aston Zhang.李沐等人所著图书<动手学深度学习>放出了在线预览版,以供读 ...
- 【深度学习】预训练的卷积模型比Transformer更好?
引言 这篇文章就是当下很火的用预训练CNN刷爆Transformer的文章,LeCun对这篇文章做出了很有深意的评论:"Hmmm".本文在预训练微调范式下对基于卷积的Seq2Seq ...
- 【深度学习】预训练语言模型-BERT
1.BERT简介 BERT是一种预训练语言模型(pre-trained language model, PLM),其全称是Bidirectional Encoder Represent ...
- Halcon学习---深度学习篇segment2~训练模型。
* *此示例是一系列示例的一部分,该示例总结了 * DL细分的工作流程. 它使用MVTec药丸数据集. * *四个部分是: * 1.数据集预处理. * 2.训练模型. * 3.评估训练后的模型. * ...
- 深度学习(预训练网络resnet18)
还是针对天气处理的图片的四个分类,使用这个网络模型resnet18 import torch import torch.nn as nn import torch.nn.functional as F ...
- 关于NLP相关技术全部在这里:预训练模型、图神经网络、模型压缩、知识图谱、信息抽取、序列模型、深度学习、语法分析、文本处理...
NLP近几年非常火,且发展特别快.像BERT.GPT-3.图神经网络.知识图谱等技术应运而生. 我们正处在信息爆炸的时代.面对每天铺天盖地的网络资源和论文.很多时候我们面临的问题并不是缺资源,而是找准 ...
- 详解预训练模型、图神经网络、模型压缩、知识图谱、信息抽取、序列模型、深度学习、语法分析、文本处理...
NLP近几年非常火,且发展特别快.像BERT.GPT-3.图神经网络.知识图谱等技术应运而生.我们正处在信息爆炸的时代.面对每天铺天盖地的网络资源和论文.很多时候我们面临的问题并不是缺资源,而是找准资 ...
- 华为云苏嘉:如何整合预训练模型和知识图谱做医疗推理?
本文约4100字,建议阅读8分钟 本文将讨论如何为AI+医疗提供一种行之有效的解决方案. [ 导读 ] 随着人工智能技术特别是深度学习的普及,医疗行业也迎来一波革命的热潮,本文将讨论如何利用AI技术将 ...
最新文章
- python3网络编程实战
- ES等待任务——是master节点上的task任务
- 2011年给力新作——《数据库系统工程师考试案例梳理、真题透解与强化训练》...
- C语言编译流程:预处理、编译、汇编、链接
- 微软发布全新3D Emoji表情系统:与Win11的UI风格一致
- 大数据_MapperReduce_Hbase_批处理batchMutate源码分析_数据的写入流程源码分析---Hbase工作笔记0032
- mysql上传到阿里云服务器地址_从0部署Web项目到阿里云服务器上
- 新出版书籍《Python预测之美:数据分析与算法实战》,送书活动!参与即可机会,获得一本实体书,中奖后可填写地址寄送。
- Rust: 如何运行你在Atom中写的Rust代码?
- c语言跑酷小游戏代码,跑酷游戏代码
- weui 加载提示_jquery weui 滚动加载不触发
- OpenCV: 读取图片中某个点的像素值
- CANoe CAPL文件操作目录合集
- 三级分销系统要如何进行推广以及提升曝光度?
- 嵌入式linux 系统支持usb wifi BL-R8723BT1
- (转)日语汉字音便规则
- Implement a customized pin code input control
- 上云之路之企业级云上网络解决方案
- 数字孪生城市技术图谱和平台架构
- 关于主播表现能力的调研
热门文章
- Ubuntu16.04+ROS Kinetic环境下svo编译运行
- 百度地图标点点击变色_原神wiki地图工具,原神全地图资源标记全览
- java 嵌套类implement_有关 C++ 嵌套类
- 绘制箱线图的标签python_利用Python - Matplotlib 绘制箱线图
- notepad++ 自动保存设置
- python数据库去重_python redis连接 有序集合去重的代码
- 在Java中将字符串转换为日期,将日期转换为字符串
- linux中sudo命令_Linux中的Sudo命令
- python pow_Python pow()
- python斐波那契递归_Python递归斐波那契示例