小型数据集卷积神经网络CNN训练策略
在很多场景下,我们都只有几千甚至几百个样本,而要使用这样的小样本来训练一个cnn网络又避免过拟合,需要采用一些策略,目前主要采用的策略主要有以下三种:
- 训练一个小型的模型
- 使用预训练的网络做特征提取
- 对预训练的网络进行微调
训练一个小型的模型
这种方案主要适用的场景是用于比较简单的任务场景情况,可以设计一个比较小的模型,并做相应的正则化避免过拟合,也可做些数据增强增加样本量,这样即使在较小的样本数量,也能得到较为不错的结果。
这些小型化策略包括不限于:
- 降低网络的深度
- 降低网络每层参数的数量
也可使用数据增强来增加样本集
datagen = ImageDataGenerator(
rotation_range, # rotation_range是角度值(在 0~180 范围内),表示图像随机旋转的角度范围
width_shift_range,
height_shift_range, # width_shift 和 height_shift 是图像在水平或垂直方向上平移的范围(相对于总宽度或总高度的比例)
shear_range, # shear_range是随机错切变换的角度
zoom_range, # zoom_range是图像随机缩放的范围
horizontal_flip, # horizontal_flip 是随机将一半图像水平翻转
fill_mode ) # fill_mode是用于填充新创建像素的方法,这些新像素可能来自于旋转或宽度/高度平移
使用预训练的网络做特征提取
这种方案是将一些已经经过大数据样本训练过的网络结构迁移到新的样本中进行训练。由于预训练的网络中保存了很多有用的特征提取信息,可以在小样本上有效的提取到有价值的特征信息,当然由于网络最终任务类型的区别,例如预训练的网络是1000种类型的分类,而我们只需要用于二分类,因此一般的做法是保留网络的CNN结构也就是卷积池化层,但后续的全连接层(分类层)需要重新设计和训练。
在keras中导入模型后,只需要设置include_top 即可指定是否包含全连接分类层
from keras.applications import VGG16
conv_base = VGG16(weights='imagenet',
include_top=False,
input_shape=(150, 150, 3))
使用下面类似的代码即可完成新的全连接分类层
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'))
需要注意的是:由于预训练卷积层存储了相关的特征提取参数信息,而新的全连接层则被随机初始化,所以不能全网络进行训练,一般的做法是“冻结”网络卷积层,也就是预训练的网络参数不会被反向传播调整,只调整新加入的全连接及分类层的参数,这样参数数量也较小,可以使用小样本获得不错的训练结果
对预训练的网络进行微调
类似于上面的做法,再进行延伸,当然我们也可以只冻结一部分的卷积层,例如只留下最后一层卷积层可以被训练,而冻结之前的所有层,如图所示。
使用下面的代码表示冻结指定名称层之前的所有层
conv_base.trainable = True
set_trainable = False
for layer in conv_base.layers:
if layer.name == 'block5_conv1':
set_trainable = True
if set_trainable:
layer.trainable = True
else:
layer.trainable = False
以下结论摘自《Python深度学习》,本文的内容也出自于对书中内容的理解。
-
卷积神经网络是用于计算机视觉任务的最佳机器学习模型。即使在非常小的数据集上也可以从头开始训练一个卷积神经网络,而且得到的结果还不错。
-
在小型数据集上的主要问题是过拟合。在处理图像数据时,数据增强是一种降低过拟合的强大方法。
-
利用特征提取,可以很容易将现有的卷积神经网络复用于新的数据集。对于小型图像数据集,这是一种很有价值的方法。
-
作为特征提取的补充,你还可以使用微调,将现有模型之前学到的一些数据表示应用于新问题。这种方法可以进一步提高模型性能。