使用keras搭建模型,用imagenet的权重进行预训练。densenet169的layers数量未595,冻结模型前593,增加一个2分类的dense层,使用图片训练。
本篇文章是对上一篇DenseNet模型微调训练后的参数调优过程的记录和分析,对denseNet模型微调的方式和方法请参见另一篇博客:
https://blog.csdn.net/Labiod/article/details/105291403
模型训练结束后,在实际的测试过程中,发现模型仍然存在一些常见问题:比如:过拟合、误检、漏检等。
同时GPU的内存分配、利用率等也出现了一些问题。
因此,基于之前的问题,这里对相关的解决方法进行记录。目的在于对打通整个训练流程、并对训练的模型进行不断的调整和优化,降低过拟合,增强泛化能力。
这里对模型优化步骤和一些直观的结论做一些记录。
冻结模型的层数的分析
冻结模型的具体操作和分析结果,参见上一篇博客。
分析后结论如下:
模型冻结层数,经过分析输出原模型的结构、top层取消后的结构、微调后模型的结构,发现denseNet169原模型输出层数597,top层取消后输出层数595,微调后输出层数598。因此推论,实际训练参数,应该是595层之后,新加的部分。
冻结参数代码如下:
for layer in model.layers[:595]: # DenseNet169需要冻结前595层
layer.trainable = False # 冻结模型全连接层之前的参数
冻结后,使用model.sumary().最终输出:
的可见训练参数和不训练参数个数具体是多少。对比未冻结参数如下:
目前,各种主流的框架中,都包含了很多模型的框架、预训练参数等等相关信息。不考虑自己开发模型的情况下。主流框架下的模型,通过微调、训练等、已经足够大多数情况下使用。可以有很多参照步骤。
但对一些特定的问题,就需要自己去设计模型的架构并分析超参等参数对模型的影响了。
bachsize、learning_rate参数调优对精度影响的测试
但在实际的训练过程中,发现如下问题:测试集上精度不长,验证集上的精度忽上忽下。模型在数据集上无法收敛。
原因是batchsize设置小了,修改为30(原先为6)。模型拟合速度和精度有所增强。
这是因为,batchsize过小的,模型只会在小部分图像特征上进行梯度传递。对总体特征学习效果不明显。
因此需要选定合适的batch。对学习率也是一样。可以参照有关模型论文中的batchsize和学习率的设定,做一定调整。
在训练集中含有1300张左右的图片,将batchsize设定为30,learning_rate调到0.003。训练情况如下所示:
可以看出loss在不断下降,验证集精度在不断上升。最终模型早停于精度0.95处。
如果设置不合理的batchsize和learning_rate,比如:
为了快速学习到数据特征,增加了batchsize大小,提高了学习率。精度反而下降了一部分。
亲测,在将所有数据放到一个batchsize里后,将learning_rate调高到0.1(原先0.003),损失暴涨,精度大跌。
在训练集中含有1300张左右的图片,将batchsize设定为2000,learning_rate调高到0.1。训练情况如下所示:
训练损失一直在增加,最终训练早停与精度0.5左右处。
两种不同参数设定的的差距接近40%。
单纯降低学习率对模型的影响
在设定好一定的参数后,测试一下模型的实际效果。
在代码中,模型的reduceLROnPlateau在监视“val_accuracy“的值。
当验证精度在3个回合内不再上涨后,自动按照设定值,降低一个数量级的精度调整。
lr_reduce = ReduceLROnPlateau(monitor='val_accuracy', factor=0.1, epsilon=1e-5, patience=patience, verbose=1, min_lr = 0.00001)
# 该回调函数检测patience数量,如果没有看到epoch的“patience”数量的改善,那么学习率就会降低。
使用MTCNN人脸检测的基础上,使用DenseNet来对是否带口罩进行分类(口罩检测二分类, label设置为OK和NG)。
这个模型包含有denseNet下使用的imageNet冻结后预训练的参数,和使用口罩数据集训练全连接层的参数。
忽略人脸检测的错误,仅关注正常脸部使用DenseNet检测的分类结果。
可以看见,右上角两个人脸并未戴口罩。但仍然被错误的归到OK(蓝色框中)。
换一张图片,忽略MTCNN人脸检测的漏检,测试结果:
可见所有被检测出来的人脸,都被预训练后的DenseNet标记为了OK(即所有被检测到的人人都带了口罩)。
考虑到是学习率过大,对特征学习不明显的原因。降低学习率后,训练一次模型,再执行检测。结果如下:
可以看出,降低学习效率后,检测效果,有一点提升。
由此可以得出,适当的降低学习率,有利于模型对一些不明显特征得学习。
模型不冻结参数的效果
imageNet数据集训练的是10分类的模型,仅作2分类,使用之前的模型参数,可能会对模型(二分类)分类效果造成影响。
因此仅对模型做微调,不做参数迁移。对微调后所有参数都进行训练。
简单测试一下,忽略人脸的漏检与错检,检测效果如下:
可以看见,未做参数冻结。denseNet训练后模型的分类效果有所提升。
优化器、损失函数的调整对模型的影响
优化器、损失函数的选择,比较多。详细内容可看后续的更新。或其它人的文章。
https://www.jianshu.com/p/d99b83f4c1a6/
model.compile(optimizer=SGD(lr=learning_rate, momentum=0.9), loss=[mycrossentropy()], metrics=['accuracy'])
代码为上述所示。
该模型的训练的优化器和损失函数,选择主要为SGD和交叉损失熵。
数据增强对模型的影响
验证过之前的相关模型优化策略,可以观察到。将
denseNet169的微调并冻结之前的模型参数,在数据较少的情况下,模型的训练精度80%作用。
使用数据增强以后,模型的训练精度可以达到90%以上,但出现了过拟合的现象。
未冻结DenseNet169参数,训练效果。
可以使用数据增强后,出现了一定的过拟合。
在训练过程中,使用了数据增强后,也会出现精度一定程度的下降。
GPU训练、内存分配、GPU利用率问题
多GPU训练、GPU内存分配等设置问题可以看下面这篇文章:
https://blog.csdn.net/Labiod/article/details/105291041
GPU环境配置的其它问题,可以参照下面的文章:
https://blog.csdn.net/Labiod/article/details/105291240
配置驱动:
https://blog.csdn.net/Labiod/article/details/104981506