keras之resnet50迁移学习做分类

问题1描述:迁移学习用resnet50做分类,验证集上的准确率一直是一个大问题,有时候稳定在一个低的准确率,我的一次是一直在75%上下波动。

问题2描述:resnet50迁移学习,训练集上的准确率一直在攀升,但验证集上的准确率一直上不去,一定程度上出现了过拟合现象,但加很多的BN、dropout、l1和l2正则化手段都不能有效的解决问题。

***问题1答案:***这个问题网络设计没有问题的话,一般出现在训练的数据量上,数据量偏少就会出现验证集上准确率一直很低。

问题2答案:

2020/10/12更新

根本原因可参考:https://github.com/keras-team/keras/pull/9965
解决方案:在这里插入图片描述其实就是加一个参数:layers=tf.keras.layers

下面的采坑可不看

--------------------------------------------

-----------------------------------------------

先来看一下一般resnet50迁移学习的网络设计:

 base_model = ResNet50(weights='imagenet', include_top=False,
                              input_shape=(image_size, image_size, 3), )
x = base_model.output
x = GlobalAveragePooling2D(name='average_pool')(x)
x = Flatten(name='flatten')(x)

这是一个典型的残差网络做迁移学习的套路,很多人都是这么做的,但真的有很高的准确率吗?反正我试了很多次,一直出现验证集上的准确率很低上不去的问题。不管怎么用防止过拟合的手段,效果都不是很好。后来研究BN层看了几篇相关的论文,发现包括resnet,inception等模型都包含了Batch Normalization层,如果使用pretrained参数进行finetune,这些BN层一般情况下使用了K.learning_phase的值作为is_training参数的默认值,因此导致训练的时候使用的一直是mini batch的平均值 ,由于trainable在finetune时候一般设置为false了导致整个layer 不会update,因此moving_mean\variance根本没有更新。导致你在test时用的moving_mean\variance全是imagenet数据集上的值。
参考链接:https://github.com/keras-team/keras/pull/9965
修正后的代码:

K.set_learning_phase(0)
base_model = ResNet50(weights='imagenet', include_top=False,
                              input_shape=(image_size, image_size, 3), )
 K.set_learning_phase(1)
x = base_model.output
x = GlobalAveragePooling2D(name='average_pool')(x)
x = Flatten(name='flatten')(x)
x = Dense(2048, activation='relu', kernel_regularizer=regularizers.l2(0.0001), )(x)
x = BatchNormalization()(x)
x = Dense(1024, activation='relu', kernel_regularizer=regularizers.l2(0.0001))(x)
x = BatchNormalization(name='bn_fc_01')(x)
predictions = Dense(num_classes, activation='softmax')(x)
model = Model(inputs=base_model.input, outputs=predictions)

这样更正后可以使得准确率有一个良好的上升,但优化的不够彻底,再有一些小的技巧可以让你的验证集上的准确率有更好的提升。这是一个试验,没有理论支持,如果上述的方案不能满足你对准确率的要求,不妨试试下面这个方案:

K.set_learning_phase(0)
Inp = Input((224, 224, 3))
base_model = ResNet50(weights='imagenet', include_top=False,
                              input_shape=(image_size, image_size, 3), )
 K.set_learning_phase(1)
 x = base_model(Inp)
x = GlobalAveragePooling2D(name='average_pool')(x)
x = Flatten(name='flatten')(x)
...
predictions = Dense(num_classes, activation='softmax')(x)
model = Model(inputs=Inp, outputs=predictions)

可看出区别了吗?下面代码将输入变更了,不用resnet的输出做输入,直接定义自己的输入,我有测试过,这样做确实对准确率有一定的提升。基本上resnet50迁移学习的坑就踩到这里。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐