1. 关于卷积运算、密集连接层、池化与小样本
密集连接层与卷积层的根本区别在于,密集连接层从输入特征中学到的是全局模式,在计算机视觉领域对应着的是高级语义特征(全局模式就是涉及所有像素的模式,如 狗,耳朵,向日葵等)。卷积层学到的是局部模式,学到的就是输入图像二维图像小窗口中发现的模式,对应低级语义特征(局部模式就是卷积覆盖的区域,3*3,5*5...,如边缘、纹理等)。
正是因为这样的特性,使得卷积神经网络具有两个有趣的特性:
- 卷积神经网络学到的模式具有平移不变性。卷积神经网络在图像某个区域学习到某个模式之后,可以在任何地方识别这个模式(其实质就是低级特征提取器,后续应用时相当于对每一个候选模式进行判别)。
- 卷积神经网络可以学习到模式的空间层次结构。例如,第一个卷基层可以学到较小的图像特征(如边缘、纹理、色度);第二个卷积层讲学习由第一特征层组成更大的模式(如猫的耳朵形状、眼睛纹理等),以此类推。这就使得卷及神经网络可以有效地学习越来越复杂、越来越抽象的视觉概念。(视觉世界从根本上也具有空间层次结构)
池化也是卷积网络中常使用的一种技巧。与跨步卷积类似的是,池化也是下采样的一种操作。但是相比之下,最大池化操作往往可以取得更好而效果,这主要在于最大池化保留了卷积滤波器的最大响应值(我们也可以理解为最有效益的特征值),更具体的效益如下:
- 减少了需要处理的特征图的元素个数
- 通过让连续卷积层的观察窗口越来越大(即串口覆盖原始输入的比例越来越大)从而引入空间过滤器的层级结构
很多时候我们会听说,只有在大量数据可以使用的情况下,深度学习才会有效。这种观点只能说是部分正确:深度学习的一个基本特性就是能够独立地[更特别地我希望数据局限在某个domain中,以提高鲁棒性]在训练数据中找到有趣的特征,不需要人为的特征工程,而这只能在拥有大量训练样本的情况下才能实现。对于输入样本维度非常高的情况下更是这样,比如说图像。只能说他是部分正确,是因为还存在如下两种更可能出现的情况:
- 模型本身就很小,正则化做的也很好,同时任务也是非常的简单。这种情况下几百个样本就足够了。
- 深度学习模型本质上具有高度可重复使用性。正如上面所分析的那样,浅层卷积网络提取的是诸如边缘、纹理、色度等低级视觉特征;深层卷积网络/全连接层提取的是诸如鼻子、桌子、打太极、奔跑的马等高级的视觉特征。低级特征是可以重复使用的,所以我们可以在已经训练好的大型卷积网络中仅裁剪出浅层卷积网络,再结合小样本进行特征网络的微调,同样可以取得非常可观的效果(与之相比较的是,利用小样本和深层模型从参数初始化阶段进行训练)。
2. 使用预训练卷积神经网络实现小样本任务
数据增强技术不是这里讨论的核心,这里不进行重点讨论。
预训练网络是一个已经在大型数据集上(如ImageNet等大规模图像分类任务)训练好的深度神经网络结构,正如在上面1中讨论的,如果提供训练的数据集足够大而且通用,那么预先训练的网络学到的空间层次特征提取结构可以有效的作为视觉世界的通用模型。即使视觉任务之间存在差异,但是预先训练的网络也给我们给拱了更好的初始化参数选择。例如,在ImageNet训练好的网络Alexnet、ResNet等,其虽然原本出发点是对动物和生活中的物品进行分类,但是如果将其应用于不同类型的植物种类判别,这依然可以取得不错的效果。这足以说明,深度卷积神经网络学习到的特征确实的不同视觉问题之间具备可移植性。这也是深度学习与其他传统的特征工程方法的优势所在:深度学习在小样本学习问题上更有效(高效的特征可移植性)。
2.1 对比试验
数据集:kaggle2013猫狗分类任务,构造小样本:1000张猫/狗图像作为训练集,500张猫/狗图像作为验证数据集,500张猫/狗图像作为测试数据集。
- 方法一:浅层卷积神经网络 - training from scratch
网络结构:
实验结果:
vvvvv
评价:
通过accuracy和loss评价,我们能够看出模型已经出现了过拟合的特征。训练精度随着时间几乎线性增加,直到接近100%,而验证数据集的精度停留在65%-72%;验证数据集仅仅在7轮迭代之后就达到了最小值,但是训练集的损失却一直在下降,最后趋近0.
训练样本少是很常见的,如果贸然采用深度学习并且training from scratch明显是不合理的,因为过拟合问题很难避免。这时候就不得不考虑dropout、L2-norm(权重衰减)、数据增强、pre-trained、tuning等操作。
- 方法二:预训练深层卷积神经网络 - training from pretrained model [VGG16]
Note 1:虽然VGG16相比较VGG19、Xception、Inception V3、 ResNet50、ResNet101等是一个比较老古董的结构了,但是VGG16比较简单,与方法一中训练的网络结构具有高度相似性,所以实验结果更有说服力。
Note 2:用于图像分类的卷积神经网络包括低级视觉特征抽取[pooling+convolution]和高级语义特征综合[fullyconnection]两个部分。对于预训练网络处理小样本问题,实际上就是直接应用pretained模型的低级视觉特征抽取部分,然后重新构造数据domain-self的高级语义特征。
ThinKing:为什么仅仅重复卷积操作,是否也可以重复使用密集连接层[全连接层]?
因为卷积操作学习到的表示是低级视觉特征抽取器,在处理视觉任务上更加通用;而全连接层是高级予以特征综合,直接与任务挂钩,类似于决策部分。此外,高级语义抽取器[全连接层]不在包含物体在输入图像中的位置信息,空间分别率很差。如果位置信息对于视觉任务是很重要的,如分割、检测、跟踪等,那么密集连接层的特征很大程度上是没有用处的。
此外,即使对于卷积操作而言,其特征通用性也是存在差别的,这很大程度上取决于该卷积层在模型中的深度。 模型中更靠近底部的层提取出来是局部的、高度通用的特征图,就像我们说的边缘、文理、色度;而更靠近顶部的层提取出来的特征将会是更加抽象的概念。所以我更倾向于使用pretrained模型前3-4层的卷积参数。
Feature Extraction + Classification = NOT End-to-End [运行成本极低] 实验结果:
我先采用VGG16的卷积网络提取特征,然后将特征输入到全连接层,很明显这并不是End-to-End的过程。
def 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 = 0
for inputs_batch, labels_batch in generator:
features_batch = conv_base.predict(inputs_batch)
features[i * batch_size : (i + 1) * batch_size] = features_batch
labels[i * batch_size : (i + 1) * batch_size] = labels_batch
i += 1
if i * batch_size >= sample_count:
break
return features, labels
train_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))
model = 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=100,
batch_size=20,
validation_data=(validation_features, validation_labels))
实验结果:
vvvv
虽然仍然存在过拟合现象,但是在验证数据集上,精度得到了非常大的提升,大约为90%-92%.
Expanding vgg16-cnn with dense net = End-to-End [运行成本极高] 实验结果:
网络结构:
这里需要注意的是,在编译和训练模型之前,一定要‘冻结’VGG卷积网络中的权重参数,也就是说保持他的权重值不变。因为我们添加的Dense层是随机初始化的,如果不冻结VGG中的权重值,将会导致非常大的权重更新在网络中进行传播,这对于VGG中已经学习好的特征提取参数将会造成非常严重的破坏。
conv_base = VGG16(weights = 'imagenet',
include_top = False,
input_shape = (150,150,3))
model = models.Sequential()
model.add(conv_base)
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
conv_base.trainable = False
实验结果:
vvvv
End-to-End训练之后,精度进一步得到了提升,大约94%-95%。
数据增强技术的引入,不仅仅解决了‘过拟合’现象,是使得验证数据集的精度得到了进一步提升,最终约为96%-97.4%。
3. 微调模型实现小样本数据的深度训练
pretrained模型还有一种更为常用的方法-模型微调 fine-tuning。前面是对特征提取的卷积神经网络进行完全的冻结,微调是指将与预先训练的网络模型的顶部几层进行'解冻'[因为越是底层,视觉特征越基础,特征越通用;越靠近顶部,特征越容易聚合成针对任务的更高级语义特征,所以更好的办法是对顶层特征提取器参数进行微调,使其更适应特定的任务]。
上一节说过,冻结VGG16的卷积特征提取层,是为了能够基于卷积特征,训练一个分类器(也就是形成高级语义特征用于分类)。同理,只有上面的分类器训练好了,才可能微调卷积特征提取网络的顶部几层。如果分类器没有训练好,那么训练期间通过网络传播的误差信号就会特别大,微调的几层之前好不容易学习到的有效的表达能力,也会被破坏掉。
- 微调的步骤如下:
- 在已经训练好的based-network基础之上添加自定义的网络;
- 冻结based-network网络参数,训练自定义网络参数;
- 解冻based-network的一些层;
- 联合训练解冻的这些层和刚刚训练的自定义网络
我们能够发现,fine tuning其实是对pretraining的一种优化,使得网络更加具备‘个性化’能力。
核心代码+网络结构:
conv_base = VGG16(weights = 'imagenet',
include_top = False,
input_shape = (150,150,3))
model = models.Sequential()
model.add(conv_base)
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
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
实验结果:
vvvv
实验结果更加的精确,精度提高到了~98%.
Note:我们应不应该调整更多的层?
- 特征提取卷积网络中,更靠底部的层编码的是更加通用的视觉基础特征,而更更靠顶部的层编码的针对特定任务的更为高级的语义特征 [更专业化,更针对任务]。 微调更专业化的高级视觉特征使其适应于我们的个性化任务是明智的;然而,对所有的pretrained模型进行整体的调整,是不理智的。
- 调整的参数越多,训练的参数越多,过拟合的风险越大。
4. 参考资料
1. Simonyan K, Zisserman A. Very Deep Convolutional Networks for Large-Scale Image Recognition[J]. international conference on learning representations, 2015.
2. python3-wih-deep-learning.