迁移学习技巧以及如何更好的finetune 模型

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014381600/article/details/71511794

最近在finetune model的时候遇到了点问题,开贴记录一下。也算填自己踩过的坑。
文章参考翻译自cs231n
其实我们常用的直接finetune pre-trained model就属于迁移学习(Transfer Learning)的一种。因为我们很少在训练一个新任务时从零开始训练,一个是由于训练时间限制,另一个时训练样本过大存储空间也不一定允许,如ImageNet数据经济120万张图片,1000个类别,是很麻烦的从头开始训练(train from scratch)。因此我们的迁移学习通常有三种情况:
1:把预训练的CNN模型当做特征提取器:
得到在ImageNet数据库上pre-trained后的CNN模型,去掉最后一层全连接层(因为最后一层的输出是1000个类别的概率,在自己的问题上不适用,因为一般你的类别也并不是1000类),然后将剩下的全部网络结构当做一个特征提取器,原来的网络最后一层的输出就是你的特征,然后将该特征输入一个SVM分类器或者softmax分类器就可以快速实现你自己的分类任务。
2:finetune model
这也是最常用的,因为一般我们并不会简单的把模型像1一样当做特征提取器使用,而是让模型去fit我们的训练数据,使得性能更好。因此我们除了像第一步里面一样去掉最后一个FC层伊以外,在网络训练过程中还要更新权重,进行BP传导(方法见下文)。最简单粗暴的就是对修改后的全部网络层进行权重更新(当自己的数据库较大时),但是当我们本身任务的数据库较小时,为了避免过拟合,我们需要对网络的前几层固定参数(不更新权重),而只更新网络结构的后面几层。这是因为网络的前几层得到的特征是比较基础local的特征,基本适用于全部任务(边缘,角点特征),而网络层数越高的层,和数据库全局信息联系越紧密,(网络越靠后,信息越global,越靠前,越local,local的信息是多数情况共享的,而global的信息和原图紧密相关)。

下面根据你本身数据库的特点有几种情况可参考:
1:新的数据库较小,并且和pre-trained model所使用的训练数据库相似度较高:
由于数据库较小,在进行finetune存在overfit的风险,又由于数据库和原始数据库相似度较高,因此二者不论是local feature还是global feature都比较相近,所以此时最佳的方法是把CNN网络当做特征提取器然后训练一个分类器进行分类
2:新的数据库较大,并且和pre-trained model所使用的训练数据库相似度较高:
很明显,此时我们不用担心overfit,因此对全部网络结构进行finetune是较好的。
3:新的数据库较小,并且和pre-trained model所使用的训练数据库差异很大:
由于数据库较小,不适合进行finetune,由于数据库差异大,应该在单独训练网络结构中较高的层,前面几层local的就不用训练了,直接固定权值。在实际中,这种问题下较好的解决方案一般是从网络的某层开始取出特征,然后训练SVM分类器。
3:新的数据库较大,并且和pre-trained model所使用的训练数据库差异很大:
本来由于数据库较大,可以从头开始训练的,但是在实际中更偏向于训练整个pre-trained model的网络。

其他建议:
1:不要随意移除原始结构中的层或者更改其参数,因为网络结构传导是一层接着一层的,你改了某层的参数,在往后传导的过程中就可能得不到预想的结果。
2:Learning rates学习率:不应该设置的太大,因为我们finetune的前提就是这个模型的权重很多是有意义的,但是你学习率过大的话就会存在更新过快,破坏了原来好的权重信息,一般在finetune时学习率一般设置在1e-5,从头开始训练的话可以设置的大一点:1e-3.

翻译完成,接下来讲一下在tensorflow和caffe中如何实现只更新网络中的某些层的权重,而保持某些层参数固定:

A:caffe中一个较好的参考
不更新权重的意思就是改层的学习率始终为0,因此在网络中将对应的参数设置为0:

在layer里面加上param { lr_mult: 0 }就可以了,比如全连接层里面:
layer {
    type: "InnerProduct"
    param { # 对应第1个参数blob的配置,也就是全连接层的参数矩阵W的配置
         lr_mult: 0 # 学习率为0,其他参数可以看caffe.proto里面的ParamSpec这个类型
    }
    param { # 对应第2个参数blob的配置,也就是全连接层的偏置项b的配置
        lr_mult: 0 # 学习率为0
    }
}

B:tensorflow中

    train_params =network.all_params
    new_train_params=[]
    for ij in train_params:
        print ij
    new_train_params=train_params[3:]
    for kk in new_train_params:
        print kk
#    exit()
    optimizer = tf.train.AdamOptimizer(learning_rate=model_config['learning_rate']).minimize(cost,var_list=new_train_params)

在写优化函数时,var_list的含义就是需要BP更新权重的层,格式是list,可以根据网络结构自己指定,

new_train_params=train_params[3:]#指定只前三层不更新,只更新后面的层

参加比赛学到的深度学习调参trick:
1:多类问题考虑到样本不平衡问题
trian test split时候采用各个类别内部按比例分割的思路(StratifiedShuffleSplit)
2:数据预处理,
2.1:清理重复数据,使用dHash:差异值哈希。精确度较高,且速度也非常快来判断,参考博客这里写链接内容
后面数据增广,测试数据增广方案差不多前提下,这一步数据清洗能够提高1-2个百分点,很重要!!!
2.2:数据增强不只是有faster rcnn一种截取方式,还有(FCIS) https://github.com/msracver/FCIS (CAM) http://cnnlocalization.csail.mit.edu/

猜你喜欢

转载自blog.csdn.net/u014381600/article/details/71511794
今日推荐