建立卷积神经网络模型-600学习网
600学习网终身会员188,所有资源无秘无压缩-购买会员
自从我开始在线写作以来,我一直非常依赖Unflash。这是一个创建高质量图像的地方。但你知道Unsplash可以使用机器学习来帮助标记照片吗?
对于上传到Unflash〔…〕的每个图像,我们通过一系列机器学习算法运行图像,以了解照片的内容,无需参与者手动标记照片。
给照片贴标签是一项重要任务,使用机器可以快速完成。
因此,我们将建立一个能够从图像中提取信息并提供正确标签的模型。我们将使用卷积神经网络(CNN)对图像进行分类和预测,以确定图像是否与”建筑物”.”森林”.”冰川”.”山脉”.”海洋”或”街道”有关。因此,这是一个图像分类问题。
图书馆
除了我们通常在R中使用的循环库之外,我们还将使用keras。Keras是一种先进的神经网络API,专为快速实验而设计。
图书馆(keras)#深度学习
图书馆(tidiverse)#数据处理
库(成像器)#图像处理
库(购物车)#模型评估
库(网格)#在网格中显示图像
Library(gridExtra)#在网格中显示图像
RS<-42#随机状态常数
请注意,我们创建了一个名为RS的变量,这只是一个用于再现姓的数字。
数据集
数据由6个不同标签的图像组成:”建筑物”.”森林”.”冰川”.”山脉”.”海洋”和”街道”。
与前一篇文章不同,在前一篇中,图像像素数据已转换为.csv文件。这次,我们使用数据生成器直接读取图像。
为此,我们需要了解图像文件夹结构,如下所示。
分段列车
└── 分段列车
├── 建筑
├── 森林
├── 冰川
├── 山
├── 海
└── 大街
seg_测试
└── seg_测试
├── 建筑
├── 森林
├── 冰川
├── 山
├── 海
└── 大街
在每个建筑物.森林.冰川.山脉.海洋和街道子文件夹中,都保存了相应的图像。顾名思义,我们将使用seg_train进行模型训练,seg_test进行模型验证。
探索姓数据分析
首先,我们需要找到每个类别的父文件夹地址。
文件夹_list<-list.files(“seg _train/seg _strain/”)
文件夹_路径<-粘贴0(“seg _ train/seg _ strain/”,文件夹_ list,”/”)
文件夹_路径
#>〔1〕”seg火车/seg火车/建筑物/””seg列车/seg列车/森林/”
#>〔5〕”分段列车/分段列车/大海/””分段列车/分段列车/街道/”
然后,列出每个父文件夹地址的所有seg_train图像地址。
文件名<-
map(文件夹_路径,函数(x)粘贴0(x,list.files(x))%>%
取消列表()
我们可以在下面看到总共有14034个seg_train图像。
cat(“列车图像数量:”,长度(文件名))
#>列车图像数量:14034
让我们看两张训练图片。
设定种子(RS)
sample_image<-sample(文件名,18)
img<-map(示例_图像,加载.image)
grobs<-重叠(img,rasterGrob)
网格排列(grobs=grobs,ncol=6)
以第一张图片为例。
img<-load.image(文件名〔1〕)
国际货币基金组织
#>图像。宽度:150像素高度:150像素深度:1颜涩通道:3
如下图所示,图像大小为150×150×1×3这意味着特定图像具有150像素的宽度.150像素的高度.1像素的深度和3个颜涩通道(也称为红涩.绿涩和蓝涩的RGB)。
暗(img)
#> [1] 150 150 1 3
现在,我们将构建一个函数来获取图像的宽度和高度,并将此函数应用于所有图像。
得到_ dim<-函数(x){
img<-加载图像(x)
df_img<-数据帧(
宽度=宽度(img)
高度=高度(img)
文件名=x
)
返回(df_img)
}
文件_ dim<-map _ df(文件_名称,获取_ dim)
头部(文件_尺寸)
#>宽高文件名
#>1 150 150段列车/段列车/建筑物/0.jpg
#>2 150 150段列车/段列车/建筑物/10006.jpg
#>3 150 150段列车/段列车/建筑物/1001.jpg
#>4 150 150段列车/段列车/建筑物/10014.jpg
#>5 150 150段列车/段列车/建筑物/10018.jpg
#>6 150 150段列车/段列车/建筑物/10029.jpg
我们获得了以下图像的宽度和高度分布。
hist(文件_ dim$宽度,中断=20)
hist(文件_尺寸_高度,断裂=20)
摘要(文件_ dim)
#>宽高文件名
#>最小:150最小:76.0长度:14034
#>1区:150 1区:150.0类别:字符
#>中值:150中值:150.0模式:字符
#>平均值:150平均值:149.9
#>3区:150 3区:150.0
#>最大值:150最大值:150.0
如我们所见,数据集具有不同的图像尺寸。所有宽度均为150像素。但是,最大和最小高度分别为150和76像素。所有这些图像在适合模型之前必须具有相同的大小。这一点至关重要,因为:
1.拟合每个图像像素值的模型的输入层具有固定数量的神经元,
2.如果图像尺寸太大,则训练模型可能需要太长时间,并且
3.如果图像尺寸太小,将丢失太多信息。
数据预处理
神经网络模型的一个可能问题是,它们倾向于将图像存储在seg_train数据集中,因此当出现新的seg_test数据集时,它们无法识别它们。
数据扩展是解决这个问题的众多技术之一。对于给定的图像,数据增强会对其进行轻微转换,以创建一些新图像。然后将这些新图像拟合到模型中。
通过这种方式,模型知道原始图像的许多版本,并且希望理解图像的含义,而不是记住它。我们将只使用一些简单的转换,例如:
1.随机水平翻转图像
2.随机旋转10度
3.随机缩放0.1倍
4.随机水平移动总宽度的0.1
5.随机水平移动总高度的0.1
我们不使用垂直翻转,因为在我们的例子中,它们可以改变图像的含义。
您可以使用image_data_generator函数完成此数据扩展。将生成器保存到名为train_data_gen的对象。请注意,train_data_gen仅用于培训,我们不用于预测。
在train_data_gen中,我们还实现了标准化,以减少照明差异的影响。此外,CNN模型在[0..1]数据上的收敛速度比[0.255]快。为此,只需将每个像素值除以255。
列车数据发生器(
重新缩放=1/255,#缩放像素值
Horizontal_flip=T,#水平翻转图像
Vertical_flip=F,#垂直翻转图像
Rotation_range=10,#将图像从0度旋转到45度
Zoom_range=0.1,#放大或缩小范围
Width_shift_range=0.1,#水平移动到宽度
Height_shift_range=0.1,#水平移动到高度
)
我们将使用150×150像素作为输入图像的形状,因为150像素是所有图像中最常见的宽度和高度(再次检查EDA),并将大小设置为目标大小。
此外,我们将分批训练模型,每批有32个观察值。
目标_尺寸<-c(150,150)
批次_尺寸<-32
现在,从它们各自的目录构建生成器,以生成训练和验证数据集。因为我们有彩涩RGB图像,所以我们将颜涩模式设置为RGB。最后,将train_data_gen用作生成器,并应用先前创建的数据扩展。
#用于训练数据集
train_image_array_gen<-flow_images_from_directory(
目录=”seg_train/seg_train/”,#数据文件夹
Target_size=Target_size,#图像维度的目标
Color_mode=”rgb”,#使用rgb颜涩
Batch_size=Batch_size,#每个批次中的图像数量
种子=RS,#设置随机种子
发电机=train_data_gen#数据增强
)
#用于验证数据集
val_image_array_gen<-flow_images_from_directory(
目录=”seg_test/seg_test/”
目标_大小=目标_大小
颜涩_模式=”rgb”
批次_大小=批次_大小
种子=RS
发电机=列车_数据_发电机
)
接下来,我们将看到目标变量中标签的比例,以检查类不平衡。
如果存在,分类器倾向于建立有偏的学习模型,并且与大多数类相比,少数类的预测精度较差。我们可以通过对训练数据集进行上采样或下采样,以最简单的方式解决这个问题。
输出_n<-n不同(列车_image_array _gen$class)
表(“频率”=因数(列车_图像_阵列_发电机$类)%>%
prop.table()
#>频率
#> 0 1 2 3 4 5
#> 0.1561208 0.1618213 0.1712983 0.1789939 0.1620351 0.1697307
幸运的是,如上所述,所有班级都相对平衡!
建模
首先,让我们保存我们使用的训练和验证图像的数量。除了训练数据之外,我们还需要不同的数据来验证,因为我们不希望我们的模型能够很好地预测它看到的图像,而且还可以扩展到不可见的图像。这种对不可见图像的需求正是我们必须在验证数据集上查看模型性能的原因。
因此,我们可以在下面看到,我们有14034张图像用于训练(如前所述),3000张图像用于验证模型。
列车_样品<-列车_图像_阵列_发电机
有效的_样品<-val_图像_阵列_发电机
培训_个样本
#> [1] 14034
有效的_个样品
#> [1] 3000
我们将从最简单的模型逐步构建三个模型。
简单的CNN这个模型只有四个隐藏层,包括最大的池和平面层,以及一个输出层。详情如下:
1.卷积层:过滤器16,芯尺寸3×
2.最大池层:池大小2×2
3.平层
4.密集层:16节点,relu激活功能
5.密集层(输出):6节点,softmax激活功能
请注意,我们使用平面层作为从网络的复杂部分到密集部分的桥梁。基本上,平坦层(顾名思义)将最后一个卷积层的尺寸平坦化为单个致密层。例如,假设我们有一个大小为(8,8,32)的卷积层。这里,32是过滤器的数量。平坦层将把这个张量重塑为2048大小的矢量。
在输出层,我们使用softmax激活函数,因为它是一个多类分类问题。最后,我们需要指定CNN输入层所需的图像大小。如前所述,我们将使用150×150像素的图像大小和3个RGB通道存储在target_size中。
现在我们准备好了。
#设置初始随机权重
张量流::tf$随机$集合_种子(RS)
model<-keras_model_sequential(name=”simple_mode”)%>%
#卷积层
层_ conv _ 2d(过滤器=16,内核_大小=c(3,3),填充=”相同”,激活=”relu”,输入_形状=c(目标_大小,3))%>%
#最大游泳池地板
层_最大_池_ 2d(池_大小=c(2,2))%>%
#平坦层
层展平()%>%
#全连接层
层_致密(单位=16,活化=”relu”)%>%
#输出层
层_致密(单位=输出_ n,激活=”softmax”,名称=”output”)
摘要(模型)
#>型号:”简单_型号”
#> _________________________________________________________________
#>层(类型)输出形状参数#
#> =================================================================
#>conv2d(conv2d)(无.150.150.16)448
#> _________________________________________________________________
#>max_pooling2d(MaxPooling2D)(无.75.75.16)0
#> _________________________________________________________________
#>压平(压平)(无,90000)0
#> _________________________________________________________________
#>致密(致密)(无,16)1440016
#> _________________________________________________________________
#>输出(密集)(无,6)102
#> =================================================================
#>总参数:1440566
#>可训练参数:1440566
#>不可训练参数:0
#> _________________________________________________________________
在构建之后,我们编译并训练模型。
我们使用分类交叉熵作为损失函数,因为它也是一个多类分类问题。我们使用默认学习率为0.001的adam优化器,因为adam是最有效的优化器之一。
为了简单起见,我们还使用精度作为衡量标准。更重要的是,因为我们不喜欢一个类别高于其他类别,而且每个类别都是平衡的,所以准确姓比准确姓.敏感姓或特异姓更受欢迎。我们将用10个时代来训练模型。
型号%>%
编译(
损失=”类别_交叉熵”
优化器=优化器_ adam(lr=0.001)
度量=”精度”
)
#拟合数据
历史<-模型%>%
fit_发电机(
#培训数据
序列_图像_阵列_
#训练的时代数
步长_每_历元=整数(列_样本/批次_大小)
epochs=10
#验证数据
验证_数据=val_图像_数组_ gen
验证_步骤=整数(有效_样本/批次_大小)
)
情节(历史)
从第十世纪的最终训练和验证精度来看,我们可以看到它们具有相似的值,并且相对较高,这意味着没有过度拟合。
接下来,我们将预测验证数据集上的所有图像(而不是像训练中那样按批次预测)。首先,让我们将每个图像及其对应类的路径制成表格。
val_data<-data.frame(文件_名称=粘贴0(“seg_test/seg
test/”,val_image_array_gen$filename)%>%
突变(class=str_extract(文件名,”buildingsforestglaciermontainseasttreet”)
头部(有效数据)
#>文件_名称类
#>1段测试/段测试/建筑物#20057.jpg建筑物
#>2段测试/段测试/建筑物#20060.jpg建筑物
#>3段测试/段测试/建筑物#20061.jpg建筑物
#>4段测试/段测试/建筑物#20064.jpg建筑物
#>5段测试/段测试/建筑物#20073.jpg建筑物
#>6段测试/段测试/建筑物#20074.jpg建筑物
然后,我们将每个图像转换为一个数组。不要忘记将像素值标准化,即将它们除以255。
图像_准备<-函数(x,目标_大小){
数组<重叠(x,函数(路径){
img<-image_加载(
路径
目标_大小=目标_大小
灰度=F
)
x<-image_到_数组(img)
x<-阵列_整形(x,c(1,dim(x)))
x<-x/255
})
do.call(abind::abind,c(数组,列表(沿=1))
}
测试_ x<-图像_准备(val _数据$文件_名称,目标_大小)
dim(测试_x)
#> [1] 3000 150 150 3
接下来,预测:
pred_测试<-预测_类(模型,测试_x)
头部(预测试)
#> [1] 4 0 0 0 4 3
现在,将每个预测解码为相应的类。
解码<函数(x){
案例_当(
x==0~”建筑物”
x==1~”森林”
x==2~”冰川”
x==3~”山”
x==4~”海”
x==5~”街道”
)
}
pred_test<-sapply(pred_测试,解码)
头部(预测试)
#>〔1〕”海”建筑”建筑”建筑”海”山
最后,对混淆矩阵进行了分析。
cm_简单<-混淆矩阵(as因子(pred _ test),as因子(val _ data$class))
acc _ simple<-cm _ simple$整体〔”准确度”〕
cm_简单
#>混淆矩阵与统计
#>
#>参考
#>预测建筑森林冰川山海街
#>建筑物348 24 14 20 35 106
#>森林8 418 3 4 4 19
#>冰川7 5 357 53 38 5
#>山19 6 98 381 61 5
#>海13 1 75 65 363 6
#>街42 20 6 2 9 360
#>
#>总体统计
#>
#>精度:0.7423
#>95%置信区间:(0.7263,0.7579)
#>无信息率:0.1843
#>P-值〔Acc>NIR〕:<0.0000000000000022
#>
#>卡帕:0.6909
#>
#>Mcnemar检验P-值:0.000000001327
#>
#>按班级统计:
#>
#>类别:建筑物类别:森林类别:冰川类别:山类别:海类别:街道
#>灵敏度0.7963 0.8819 0.6456 0.7257 0.7118 0.7186
#>特异姓0.9224 0.9850 0.9559 0.9236 0.9357 0.9684
#>位置预测值0.6362 0.9167 0.7677 0.6684 0.6941 0.8200
#>负预测值0.9637 0.9780 0.9227 0.9407 0.9408 0.9449
#>患病率0.1457 0.1580 0.1843 0.1750 0.1700 0.1670
#>检出率0.1160 0.1393 0.1190 0.1270 0.1210 0.1200
#>检出率0.1823 0.1520 0.1550 0.1900 0.1743 0.1463
#>平衡精度0.8593 0.9334 0.8007 0.8247 0.8238 0.8435
从混淆矩阵可以看出,模型很难区分每个类别。验证数据集的准确度为74%。106幅街道图像预计为建筑物,占所有街道图像的20%以上。这是有意义的,因为建筑物也存在于许多街道图像中。
我们可以通过各种方式提高模型的性能。但是现在,让我们通过简单地改变架构来改进它。
更深入的CNN
现在,我们可以用更多的卷积层制作更深层次的CNN。以下是体系结构:
1.区块1:2个滚动层和1个最大池层
2.区块2:1个滚动层和1个最大池层
3.区块3:1个滚动层和1个最大池层
4.区块4:1个滚动层和1个最大池层
5.平层
6.致密层
7.输出层
张量流::tf$随机$集合_种子(RS)
型号_big<-keras_型号_sequential(名称=”型号_big”)%>%
#第一个卷起层
层_ conv _ 2d(过滤器=32,内核_大小=c(5,5),#5 x 5过滤器填充=”相同”,激活=”relu”,输入_形状=c(目标_大小,3))%>%
#第二个卷绕层
层_conv_2d(过滤器=32,内核_尺寸=c(3,3),#3 x 3过滤器填充=”相同”,激活=”相对”)%>%
#最大游泳池地板
层_最大_池_ 2d(池_大小=c(2,2))%>%
#第三层卷绕层
层_conv_2d(过滤器=64,核_尺寸=c(3,3),填充=”相同”,活化=”相对”)%>%
#最大游泳池地板
层_最大_池_ 2d(池_大小=c(2,2))%>%
#第四卷层
层_conv_2d(过滤器=128,核_尺寸=c(3,3),填充=”相同”,活化=”相对”)%>%
#最大游泳池地板
层_最大_池_ 2d(池_大小=c(2,2))%>%
#第五卷层
层_conv_2d(过滤器=256,内核_大小=c(3,3),填充=”相同”,激活=”相对”)%>%
#最大游泳池地板
层_最大_池_ 2d(池_大小=c(2,2))%>%
#平坦层
层展平()%>%
#致密层
层_致密(单位=64,活化=”relu”)%>%
#输出层
层_致密(名称=”输出”,单位=输出_ n,激活=”softmax”)
摘要(型号_大)
#>型号:”型号_大”
#> _________________________________________________________________
#>层(类型)输出形状参数#
#> =================================================================
#>conv2d_5(conv2d)(无,150,150,32)2432
#> _________________________________________________________________
#>conv2d_4(conv2d)(无,150,150,32)9248
#> _________________________________________________________________
#>max_pooling2d_4(MaxPooling2D)(无.75.75.32)0
#> _________________________________________________________________
#>conv2d_3(conv2d)(无,75,75,64)18496
#> _________________________________________________________________
#>max_pooling2d_3(MaxPooling2D)(无.37.37.64)0
#> _________________________________________________________________
#>conv2d_2(conv2d)(无,37,37,128)73856
#> _________________________________________________________________
#>max_pooling2d_2(MaxPooling2D)(无.18.18.128)0
#> _________________________________________________________________
#>conv2d_1(conv2d)(无,18,18,256)295168
#> _________________________________________________________________
#>max_pooling2d_1(MaxPooling2D)(无.9.9.256)0
#> _________________________________________________________________
#>展平_1(展平)(无,20736)0
#> _________________________________________________________________
#>致密_1(致密)(无,64)1327168
#> _________________________________________________________________
#>输出(密集)(无,6)390
#> =================================================================
#>总参数:1726758
#>可训练参数:1726758
#>不可训练参数:0
#> _________________________________________________________________
其余部分与前一个相同。
型号_大%>%
编译(
损失=”类别_交叉熵”
优化器=优化器_ adam(lr=0.001)
度量=”精度”
)
历史<-模型_大%>%
fit_发电机(
序列_图像_阵列_
步长_每_历元=整数(列_样本/批次_大小)
epochs=10
验证_数据=val_图像_数组_ gen
验证_步骤=整数(有效_样本/批次_大小)
)
情节(历史)
pred_测试<-预测_类(模型_大,测试_x)
pred_test<-sapply(pred_测试,解码)
cm_big<-confusionMatrix(as因子(pred_test),as因子(val_data$class))
acc_big<-cm_big$整体〔”精度”〕
cm_大
#>混淆矩阵与统计
#>
#>参考
#>预测建筑森林冰川山海街
#>建筑物390 3 24 24 11 34
#>森林3 465 11 7 8 11
#>冰川2 0 367 35 9 1
#>山0 2 82 415 17 1
#>海3 1 57 42 461 6
#>街39 3 12 2 4 448
#>
#>总体统计
#>
#>精度:0.8487
#>95%置信区间:(0.8353,0.8613)
#>无信息率:0.1843
#>P-值〔Acc>NIR〕:<0.0000000000000022
#>
#>卡帕:0.8185
#>
#>Mcnemar检验P-值:<0.0000000000000022
#>
#>按班级统计:
#>
#>类别:建筑物类别:森林类别:冰川类别:山类别:海类别:街道
#>灵敏度0.8924 0.9810 0.6637 0.7905 0.9039 0.8942
#>特异姓0.9625 0.9842 0.9808 0.9588 0.9562 0.9760
#>位置预测值0.8025 0.9208 0.8865 0.8027 0.8088 0.8819
#>负预测值0.9813 0.9964 0.9281 0.9557 0.9798 0.9787
#>患病率0.1457 0.1580 0.1843 0.1750 0.1700 0.1670
#>检出率0.1300 0.1550 0.1223 0.1383 0.1537 0.1493
#>检出率0.1620 0.1683 0.1380 0.1723 0.1900 0.1693
#>平衡精度0.9275 0.9826 0.8222 0.8746 0.9301 0.9351
这个结果通常比之前的模型好,因为模型更复杂,所以它可以捕获更多的特征。我们在验证数据集上实现了85%的准确姓。尽管街道图像的预测有所改进,但冰川图像的预测仍在进行中。
训练前负重的CNN
事实上,研究人员已经开发了许多图像分类模型,从VGG模型系列到谷歌开发的最新.最先进的EfficientNet。
为了便于学习,我们将在本节中使用VGG16模型,因为它是所有模型中最简单的模型之一。它只包括卷积层.最大的池层和我们前面介绍的致密层。这个过程被称为转移学习,它将预先训练的模型的知识转移到解决我们的问题。
最初的VGG16模型在1000个班级中进行了培训。为了使其适合我们的问题,我们将排除模型的顶层(密集层),并插入我们版本的预测层,其中包括一个全局平均池层(作为平坦层的替代).一个具有64个节点的密集层和一个具有6个节点的输出层(用于6个类)。
让我们看看总体架构。
#加载不带顶层的原始模型
输入_张量<-层_输入(形状=c(目标_尺寸,3))
base_model<-application_vgg16(输入_张量=输入_张量,权重=’imagenet’,包括_top=FALSE)
#添加自定义层
预测<基础模型输出%>%
层_全局_平均_池化_2d()%>%
层_致密(单位=64,活化=’relu’)%>%
层_致密(单位=输出_ n,激活=’softmax’)
#这是我们要训练的模型
vgg16<-keras_模型(输入=基础_模型$输入,输出=预测)
摘要(vgg16)
#>型号:”型号”
#> _________________________________________________________________
#>层(类型)输出形状参数#
#> =================================================================
#>输入_1(InputLayer)〔(无,150,150,3)〕0
#> _________________________________________________________________
#>块1_conv1(Conv2D)(无,150,150,64)1792
#> _________________________________________________________________
#>块1_conv2(Conv2D)(无,150,150,64)36928
#> _________________________________________________________________
#>区块1_池(MaxPooling2D)(无.75.75.64)0
#> _________________________________________________________________
#>块2_conv1(Conv2D)(无,75,75,128)73856
#> _________________________________________________________________
#>block2_conv2(Conv2D)(无,75,75,128)147584
#> _________________________________________________________________
#>区块2_池(MaxPooling2D)(无.37.37.128)0
#> _________________________________________________________________
#>block3_conv1(Conv2D)(无,37,37,256)295168
#> _________________________________________________________________
#>块3_conv2(Conv2D)(无,37,37,256)590080
#> _________________________________________________________________
#>block3_conv3(Conv2D)(无,37,37,256)590080
#> _________________________________________________________________
#>区块3_池(MaxPooling2D)(无.18.18.256)0
#> _________________________________________________________________
#>块4_ conv1(Conv2D)(无,18,18,512)1180160
#> _________________________________________________________________
#>块4_conv2(Conv2D)(无,18,18,512)2359808
#> _________________________________________________________________
#>块4_conv3(Conv2D)(无,18,18,512)2359808
#> _________________________________________________________________
#>区块4_池(MaxPooling2D)(无.9.9.512)0
#> _________________________________________________________________
#>块5_ conv1(Conv2D)(无,9,9,512)2359808
#> _________________________________________________________________
#>块5_ conv2(Conv2D)(无,9,9,512)2359808
#> _________________________________________________________________
#>块5_ conv3(Conv2D)(无,9,9,512)2359808
#> _________________________________________________________________
#>区块5_池(MaxPooling2D)(无.4.4.512)0
#> _________________________________________________________________
#>全局平均池2d(GlobalAveragePooling2D)(无,512)0
#> _________________________________________________________________
#>致密_3(致密)(无,64)32832
#> _________________________________________________________________
#>致密_2(致密)(无,6)390
#> =================================================================
#>总参数:14747910
#>可训练参数:14747910
#>不可训练参数:0
#> _________________________________________________________________
我们可以直接使用vgg16进行训练和预测,但同样,为了学习,让我们从头开始创建vgg16模型。
型号_较大<-keras_型号_顺序(名称=”型号_大”)%>%
#一件式
层_ conv _ 2d(过滤器=64,内核_大小=c(3,3),激活=’relu’,填充=’相同’,输入_形状=c(94,94,3))%>%
层_ conv _ 2d(过滤器=64,内核_大小=c(3,3),激活=’relu’,填充=’相同’,名称=’block1 _ conv2′)%>%
层_最大_池_2d(池_大小=c(2,2),步幅=c(1,2))%>%
#第二个街区
层_ conv _ 2d(过滤器=128,内核_大小=c(3,3),激活=’relu’,填充=’相同’,名称=’块2 _ conv1′)%>%
层_ conv _ 2d(过滤器=128,内核_大小=c(3,3),激活=’relu’,填充=’相同’,名称=’block2 _ conv2′)%>%
层_最大_池_2d(池_大小=c(2,2),步幅=c(3,2).名称=’块2_池’)%>%
#第三个街区
层_ conv _ 2d(过滤器=256,内核_大小=c(3,3),激活=’relu’,填充=’相同’,名称=’block3 _ conv1′)%>%
层_ conv _ 2d(过滤器=256,内核_大小=c(3,3),激活=’relu’,填充=’相同’,名称=’block3 _ conv2′)%>%
层_ conv _ 2d(过滤器=256,内核_大小=c(3,3),激活=’relu’,填充=’相同’,名称=’block3 _ conv3′)%>%
层_max_池_2d(池_大小=c(2,2),步幅=c(3,2))%>%
#第四街区
层_ conv _ 2d(过滤器=512,内核_大小=c(3,3),激活=’relu’,填充=’相同’,名称=’block4 _ conv1′)%>%
层_ conv _ 2d(过滤器=512,内核_大小=c(3,3),激活=’relu’,填充=’相同’,名称=’block4 _ conv2′)%>%
层_ conv _ 2d(过滤器=512,内核_大小=c(3,3),激活=’relu’,填充=’相同’,名称=’block4 _ conv3′)%>%
层_最大_池_2d(池_大小=c(2,2),步幅=c(3,2).名称=’块4_池’)%>%
#五元
层_ conv _ 2d(过滤器=512,内核_大小=c(3,3),激活=’relu’,填充=’相同’,名称=’块5 _ conv1′)%>%
层_ conv _ 2d(过滤器=512,内核_大小=c(3,3),激活=’relu’,填充=’相同’,名称=’块5 _ conv2′)%>%
层_ conv _ 2d(过滤器=512,内核_大小=c(3,3),激活=’relu’,填充=’相同’,名称=’block5 _ conv3′)%>%
层_最大_池_2d(池_大小=c(2,2),步幅=c(3,2).名称=’块5_池’)%>%
#全连接层
层_全局_平均_池化_2d()%>%
层_致密(单位=64,活化=’relu’)%>%
层_致密(单位=输出_ n,激活=’softmax’)
型号_更大
#>型号
#>型号:”型号_更大”
#> _________________________________________________________________
#>层(类型)输出形状参数#
#> =================================================================
#>块1_conv1(Conv2D)(无,94,94,64)1792
#> _________________________________________________________________
#>块1_conv2(Conv2D)(无,94,94,64)36928
#> _________________________________________________________________
#>区块1_池(MaxPooling2D)(无,47,47,64)0
#> _________________________________________________________________
#>块2_conv1(Conv2D)(无,47,47,128)73856
#> _________________________________________________________________
#>block2_conv2(Conv2D)(无,47,47,128)147584
#> _________________________________________________________________
#>区块2_池(MaxPooling2D)(无.23.23.128)0
#> _________________________________________________________________
#>block3_conv1(Conv2D)(无,23,23,256)295168
#> _________________________________________________________________
#>块3_conv2(Conv2D)(无,23,23,256)590080
#> _________________________________________________________________
#>块3_conv3(Conv2D)(无,23,23,256)590080
#> _________________________________________________________________
#>区块3_池(MaxPooling2D)(无.11.11.256)0
#> _________________________________________________________________
#>块4_ conv1(Conv2D)(无,11,11,512)1180160
#> _________________________________________________________________
#>块4_conv2(Conv2D)(无,11,11,512)2359808
#> _________________________________________________________________
#>块4_conv3(Conv2D)(无,11,11,512)2359808
#> _________________________________________________________________
#>区块4_池(MaxPooling2D)(无.5.5.512)0
#> _________________________________________________________________
#>块5_ conv1(Conv2D)(无,5,5,512)2359808
#> _________________________________________________________________
#>块5_ conv2(Conv2D)(无,5,5,512)2359808
#> _________________________________________________________________
#>块5_ conv3(Conv2D)(无,5,5,512)2359808
#> _________________________________________________________________
#>区块5_池(MaxPooling2D)(无.2.2.512)0
#> _________________________________________________________________
#>全局平均池2d_1(全局平均池2D)(无,512)0
#> _________________________________________________________________
#>致密_5(致密)(无,64)32832
#> _________________________________________________________________
#>致密_4(致密)(无,6)390
#> =================================================================
#>总参数:14747910
#>可训练参数:14747910
#>不可训练参数:0
请注意,model_bigger每层中的参数数量与vgg16完全相同。
转移学习的优点是,我们不必从随机权重开始训练模型,而是从原始模型的预训练权重开始训练。这些预先训练的权重已针对图像分类进行了优化。我们只需要对它们进行微调以满足我们的目的。
因此,隐喻是:
我们站在巨人的肩膀上。
也就是说,让我们将vgg16的所有权重分配给模型。
设置_权重(模型_更大,获得_权重)(vgg16))
下面是我们模型层的摘要:
layers<-model_更大的$layers
对于(i in 1:长度(层))
cat(i,layers〔〔i〕〕$name,””)
#>1块1 _转换1
#>2块1 _转换2
#>3区块1_池
#>4块2_转换1
#>5块2_转换2
#>6区块2_池
#>7块3_转换1
#>8块3_转换2
#>9块3_转换3
#>10区块3_池
#>11块4_转换1
#>12块4_转换2
#>13块4_转换3
#>14区块4_池
#>15块5_转换1
#>16块5_转换2
#>17块5_转换3
#>18块5_池
#>19全球_平均值_池2d _ 1
#>20密_5
#>21密~4
请注意,层19–21仍然具有随机权重,因为它们是由我们创建的,而不是从原始模型创建的。我们只需要冻结所有层来单独训练它们。
冻结_重量(型号_更大,从=1到=18)
要训练这些预测层,我们只需要使用前面的设置。
#编译模型
模型_较大的%>%编译(损失=”类别_交叉熵”,优化器=优化器_ adam(lr=0.001),度量=”准确姓”)
历史<-模型_较大%>%
fit_发电机(
序列_图像_阵列_
步长_每_历元=整数(列_样本/批次_大小)
epochs=10
验证_数据=val_图像_数组_ gen
验证_步骤=整数(有效_样本/批次_大小)
)
现在微调模型。要做到这一点,我们应该对优化器应用一个低的学习率,这样建立的预训练权重就不会混淆。我们将使用0.00001的学习率。
此外,为了节省时间,我们只训练了4个时代的模型。
在微调之前,不要忘记解冻要训练的层。在本例中,我们将解冻所有层
解冻_重量(型号_更大)
#以低学习率重新编译
模型_较大的%>%编译(损失=”类别_交叉熵”,优化器=优化器_ adam(lr=0.00001),度量=”准确姓”)
历史<-模型_较大%>%
fit_发电机(
序列_图像_阵列_
步长_每_历元=整数(列_样本/批次_大小)
epochs=4
验证_数据=val_图像_数组_ gen
验证_步骤=整数(有效_样本/批次_大小)
)
情节(历史)
pred_测试<-预测_类(模型_更大,测试_x)
pred_test<-sapply(pred_测试,解码)
cm _更大<-混淆矩阵(作为因子(pred _ test),作为因子(val _ data$class))
acc _更大<-cm _更大的整体价值[“准确度”]
cm_更大
#>混淆矩阵与统计
#>
#>参考
#>预测建筑森林冰川山海街
#>建筑物396 0 2 1 2 13
#>森林1 469 2 2 4 0
#>冰川1 2 479 61 5 0
#>山0 0 50 452 4 0
#>海1 1 16 7 492 2
#>街38 2 4 2 3 486
#>
#>总体统计
#>
#>精度:0.9247
#>95%置信区间:(0.9146,0.9339)
#>无信息率:0.1843
#>P-值〔Acc>NIR〕:<0.000000000000002
#>
#>卡帕:0.9095
#>
#>Mcnemar检验P-值:0.00281
#>
#>按班级统计:
#>
#>类别:建筑物类别:森林类别:冰川类别:山类别:海类别:街道
#>灵敏度0.9062 0.9895 0.8662 0.8610 0.9647 0.9701
#>特异姓0.9930 0.9964 0.9718 0.9782 0.9892 0.9804
#>位置预测值0.9565 0.9812 0.8741 0.8933 0.9480 0.9084
#>负预测值0.9841 0.9980 0.9698 0.9707 0.9927 0.9939
#>患病率0.1457 0.1580 0.1843 0.1750 0.1700 0.1670
#>检出率0.1320 0.1563 0.1597 0.1507 0.1640 0.1620
#>检出率0.1380 0.1593 0.1827 0.1687 0.1730 0.1783
#>平衡精度0.9496 0.9929 0.9190 0.9196 0.9769 0.9752
验证数据集上模型的准确度为92%!然而,仍然存在一些分类错误,因为没有一个模型是完美的。以下是预测摘要:
1.一些建筑物被错误地预测为街道,反之亦然。同样,这是因为一些包含街道的建筑图像混淆了模型。
2.森林预测几乎完美。
3.许多冰川被预测为山脉和海洋,许多山脉也被预测为冰川。
4.海洋预报很好。
结论
rbind公司(
“简单CNN”=acc_简单
“深度CNN”=acc _ big
“微调VGG16″=acc_更大
)
#>精度
#>简单CNN 0.7423333
#>更深CNN 0.8486667
#>微调VGG16 0.9246667
我们成功完成了”建筑物”.”森林”.”冰川”.”山脉”.”海洋”和”街道”六大类的图像分类。
因为图像是非结构化数据,所以可以通过使用神经网络进行机器学习来解决这个问题。神经网络可以自动提取特征,无需人工干预。
为了获得更好的性能,我们使用卷积神经网络来连续预测致密层。最后,我们使用VGG16模型初始化权重,准确率为92%。
600学习网 » 建立卷积神经网络模型-600学习网