原文链接:http://tecdat.cn/?p=6714
原文出处:拓端数据部落公众号
必须应用非常少的数据训练图像分类模型是一种常见状况,如果您在业余环境中进行计算机视觉,则在实践中可能会遇到这种状况。“多数”样本能够示意从几百到几万个图像的任何中央。作为一个理论例子,咱们将重点放在将图像分类为狗或猫的数据集中,其中蕴含 4,000 张猫狗图片(2,000 只猫,2,000 只狗)。咱们将应用 2,000 张图片进行训练 - 1,000 张用于验证,1,000 张用于测试。
深度学习与小数据问题的相关性
您有时会听到深度学习仅在有大量数据可用时才无效。这部分是无效的:深度学习的一个基本特征是它能够本人在训练数据中找到乏味的特色,而不须要手动特色工程,这只有在有大量训练样例可用时能力实现。对于输出样本十分高维的问题(如图像)尤其如此。
让咱们从数据开始吧。
下载数据
应用 Dogs vs. Cats 数据集。
这里有些例子:
该数据集蕴含 25,000 张狗和猫的图像(每类 12,500 张),543 MB。下载并解压缩后,您将创立一个蕴含三个子集的新数据集:每个类蕴含 1,000 个样本的训练集,每个类 500 个样本的验证集,以及每个类 500 个样本的测试集。
以下是执行此操作的代码:
original\_dataset\_dir < -“〜/ Downloads / kaggle\_original\_data”base\_dir < -“〜/ Downloads / cats\_and\_dogs\_small”dir.create(base_dir)train\_dir < - file.path(base\_dir,“train”)dir.create(train_dir)validation\_dir < - file。path(base\_dir,“validation”)
应用预训练的 convnet
在小图像数据集上深刻学习的一种常见且高效的办法是应用预训练网络。一个预训练的网络是一个先前在大型数据集上训练的已保留网络,通常是在大规模图像分类工作上。如果这个原始数据集足够大且足够通用,则预训练网络学习的特色的空间层次结构能够无效地充当视觉世界的通用模型,因而其特色能够证实对许多不同的计算机视觉问题有用,甚至尽管这些新问题可能波及与原始工作齐全不同的类。
有两种办法能够应用预训练网络:特征提取和微调。让咱们从特征提取开始。
特征提取
特征提取包含应用先前网络学习的示意来从新样本中提取感兴趣的特色。而后,这些性能将通过一个新的分类器运行,该分类器从头开始训练。
为什么只重用卷积基数?您是否能够重复使用密集连贯的分类器?一般来说,应该防止这样做。起因是卷积根底学习的示意可能更通用,因而更具可重用性。
留神,由特定卷积层提取的示意的一般性(以及因而可重用性)的级别取决于模型中的层的深度。模型中较早呈现的图层会提取部分的,高度通用的特色贴图(例如可视边缘,色彩和纹理),而较高层的图层会提取更形象的概念(例如“猫耳朵”或“狗眼”)。因而,如果您的新数据集与训练原始模型的数据集有很大不同,那么最好只应用模型的前几层来进行特征提取,而不是应用整个卷积根底。
让咱们通过应用在 ImageNet 上训练的 VGG16 网络的卷积根底来实现这一点,从猫和狗图像中提取乏味的特色,而后在这些特色之上训练狗与猫的分类器。
让咱们实例化 VGG16 模型。
conv\_base < - application\_vgg16(weights =“imagenet”,include\_top = FALSE,input\_shape = c(150,150,3))
将三个参数传递给函数:
- weights 指定从中初始化模型的权重。
- include_top“密集连贯”是指在网络顶部包含(或不包含)密集连贯的分类器。默认状况下,此密集连贯的分类器对应于 ImageNet 的 1,000 个类。
- input_shape 是您将提供给网络的图像张量的形态。这个参数是可选的:如果你不传递它,网络将可能解决任何大小的输出。
它相似于你曾经相熟的简略的网络:
summary(conv_base)
Layer (type) Output Shape Param #
================================================================
input_1 (InputLayer) (None, 150, 150, 3) 0
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block1_conv1 (Convolution2D) (None, 150, 150, 64) 1792
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block1_conv2 (Convolution2D) (None, 150, 150, 64) 36928
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block1_pool (MaxPooling2D) (None, 75, 75, 64) 0
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block2_conv1 (Convolution2D) (None, 75, 75, 128) 73856
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block2_conv2 (Convolution2D) (None, 75, 75, 128) 147584
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block2_pool (MaxPooling2D) (None, 37, 37, 128) 0
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block3_conv1 (Convolution2D) (None, 37, 37, 256) 295168
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block3_conv2 (Convolution2D) (None, 37, 37, 256) 590080
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block3_conv3 (Convolution2D) (None, 37, 37, 256) 590080
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block3_pool (MaxPooling2D) (None, 18, 18, 256) 0
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block4_conv1 (Convolution2D) (None, 18, 18, 512) 1180160
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block4_conv2 (Convolution2D) (None, 18, 18, 512) 2359808
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block4_conv3 (Convolution2D) (None, 18, 18, 512) 2359808
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block4_pool (MaxPooling2D) (None, 9, 9, 512) 0
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block5_conv1 (Convolution2D) (None, 9, 9, 512) 2359808
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block5_conv2 (Convolution2D) (None, 9, 9, 512) 2359808
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
block5_conv3 (Convolution2D) (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
此时,有两种办法能够持续:
- 在数据集上运行卷积。
- conv_base 通过在顶部增加密集层来扩大您的模型()。
在这篇文章中,咱们将具体介绍第二种技术。请留神,只有在您能够拜访 GPU 时才应该尝试。
特征提取
因为模型的行为与图层相似,因而您能够像增加图层一样将模型(如 conv_base)增加到程序模型中。
model < - keras\_model\_sequential()%>%conv\_base%>%layer\_flatten()%>%layer\_dense(= 256,activation =“relu”)%>%layer\_dense(u its =,“sigmoid”)
这就是模型当初的样子:
summary(model)
Layer (type) Output Shape Param #
================================================================
vgg16 (Model) (None, 4, 4, 512) 14714688
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
flatten_1 (Flatten) (None, 8192) 0
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
dense_1 (Dense) (None, 256) 2097408
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
dense_2 (Dense) (None, 1) 257
================================================================
Total params: 16,812,353
Trainable params: 16,812,353
Non-trainable params: 0
如您所见,VGG16 的卷积基数有 14,714,688 个参数,十分大。
在 Keras 中,应用以下 freeze_weights() 函数解冻网络:
freeze\_weights(conv\_base)length(model $ trainable_weights)
应用数据裁减
适度拟合是因为过多的样本须要学习,导致无奈训练能够推广到新数据的模型。
在 Keras 中,这能够通过配置对读取的图像执行的多个随机变换来实现,image\_data\_generator()。例如:
train\_datagen = image\_data\_generator(rescale = 1/255,= 40,width\_shift\_range = 0.2,height\_shift\_range = 0.2,= 0.2,zoom\_range = 0.2,horizo = TRUE,fill_mode =“nearest”)
浏览一下这段代码:
- rotation_range 是一个度数(0-180)的值,一个随机旋转图片的范畴。
- width\_shift 并且 height\_shift 是在垂直或程度方向上随机平移图片的范畴。
- shear_range 用于随机利用剪切变换。
- zoom_range 用于随机缩放图片外部。
- horizontal_flip 用于程度地随机翻转一半图像 – 当没有程度不对称假如时相干(例如,真实世界的图片)。
- fill_mode 是用于填充新创建的像素的策略,能够在旋转或宽度 / 高度偏移后呈现。
当初咱们能够应用图像数据生成器训练咱们的模型:
model%>%compile(loss =“binary\_crossentropy”,optimizer = optimizer\_rmsprop(lr = 2e-5),metrics = c(“accuracy”))history < - model%>%fit\_generator(train\_generator,steps\_per\_epoch = 100,
绘制后果。准确率达到约 90%。
微调
另一种宽泛应用的模型重用技术,是对特征提取的补充,是微调,微调网络的步骤如下:
- 在曾经训练过的根底网络上增加自定义网络。
- 解冻根底网络。
- 训练你增加的局部。
- 冻结根底网络中的某些层。
- 联结训练这些层和您增加的局部。
在进行特征提取时,您曾经实现了前三个步骤。让咱们持续第 4 步:您将冻结您的内容 conv_base,而后解冻其中的各个图层。
当初您能够开始微调网络了。
model%>%compile(lo ropy”,optimizer = opt imizer_rmsprop(lr = 1e-5),metrics = c(“accuracy”))his el%>%fit\_generator(train\_ g steps\_per\_epoch = 100,epochs = 100,validation\_data = validation\_genera tor,validation_steps = 50)
让咱们绘制后果:
·
你能够看到准确度有 6%的晋升,从大概 90%到高于 96%。
您当初能够最终在测试数据上评估此模型:
test\_generator < -(test\_dir,test\_datagen,target\_size = c(150,150),batch_size = 20,=“binary”)model%>%evaluate_generator(,steps = 50)
$ loss
\[1\] 0.2158171
$ acc
\[1\] 0.965
在这里,您能够取得 96.5%的测试精度。