转自:http://blog.csdn.net/u010402786/article/details/70141261

前言

什么是模型的微调?

   
  使用别人训练好的网络模型进行训练,前提是必须和别人用同一个网络,因为参数是根据网络而来的。当然最后一层是可以修改的,因为我们的数据可能并没有1000类,而只有几类。把最后一层的输出类别和层的名称改一下就可以了。用别人的参数、修改后的网络和自己的数据进行训练,使得参数适应自己的数据,这样一个过程,通常称之为微调(fine tuning).

微调时候网络参数是否更新?

  
  更新,finetune的过程相当于继续训练,跟直接训练的区别是初始化的时候: 
   a. 直接训练是按照网络定义指定的方式初始化(如高斯随机初始化) 
  b. finetune是用你已经有的参数文件来初始化(就是之前训练好的caffemodel)


**第一部分:Caffe命令行解析** —————

一、训练模型代码

  脚本:

./build/tools/caffe train -solver models/finetune/solver.prototxt -weights models/vgg_face_caffe/VGG_FACE.caffemodel -gpu 0

  BAT命令:  

..\..\bin\caffe.exe train --solver=.\solver.prototxt -weights .\test.caffemodel
pause
二、caffe命令全解析

  http://www.cnblogs.com/denny402/p/5076285.html


第二部分:微调参数调整示例

一、各类模型finetune示例

Caffe finetune Resnet-50

http://blog.csdn.net/tangwenbo124/article/details/56070322

Caffe finetune googlenet

http://blog.csdn.net/sinat_30071459/article/details/51679995

Caffe finetune FCN

http://blog.csdn.net/zy3381/article/details/50458331

Caffe finetune Alexnet

                 

二、参数调整注意
  • 首先修改名字,这样预训练模型赋值的时候这里就会因为名字不匹配从而重新训练,也就达成了我们适应新任务的目的;
  • 调整学习速率,因为最后一层是重新学习,因此需要有更快的学习速率相比较其他层,因此我们将,weight和bias的学习速率加快10倍,目的是让非微调层学习更快;
  • finetune时将最后的全连接层的名字全部修改,需要根据自己数据集的类别数重新设置fc8层的output数;
  • 数据集的类别号从0开始,中间要连续,否则会造成意外的错误
  • 数据集记得打乱,不然很可能不收敛;
  • 如果出现不收敛的问题,可以把solver里的lr设的小一点,一般从0.01开始,如果出现loss=nan了就不断往小调整;
  • 可以把accuracy和loss的曲线画出来,方便设定stepsize,一般在accuracy和loss都趋于平缓的时候就可以减小lr了;
  • finetune时应该用自己的数据集生成的均值文件(是否正确?);

第三部分:fine-tune的选择经验

  在fine-tune时,究竟该选择哪种方式的Transfer Learning?需要考虑的因素有许多,其中最重要的两条是新数据库的规模和它与预训练数据库的相似程度,根据这两条因素的不同配置,存在四种场景: 
   
  新数据库小,和预训练数据库相似。因为数据库比较小,fine-tune的话可能会产生过拟合,比较好的做法是用预训练的网络作为特征提取器,然后训练线性分类器用在新的任务上。 
  新数据库比较大,和预训练数据库相似。这种情况下,不用担心过拟合,可以放心地微调整个网络。 
  新数据库小,和预训练数据库不相似。这时,既不能微调,用预训练网络去掉最后一层作为特征提取器也不合适,可行的方案是用预训练网络的前面几层的激活值作为特征,然后训练线性分类器。 
  新数据库大,和预训练数据库不相似。这时可以从头开始训练,也可以在预训练的基础上进行微调。 
   
   
  综述:做freeze操作时,通常还会根据数据集在不同情况进行有选择的性的finetune。如small datasets时,可以freeze前面conv layer-> fc4086来提取cnn在imagenet上的多类泛化特征来辅助作为分类的feature,再对如这边revise的fc-20->softmax进行training。以此类推,如果是medium datasets则freeze到一半的conv。个人理解这样做的很大原因在于lower level layer具有更强泛化的basic feature,同时记得考量你的数据来选择。


第四部分:如何针对上述不同的方式进行网络参数固定

比如有4个全连接层A->B->C->D:

  a. 你希望C层的参数不会改变,C前面的AB层的参数也不会改变,这种情况也就是D层的梯度不往前反向传播到D层的输入blob(也就是C层的输出blob 没有得到梯度),你可以通过设置D层的lr_mult: 0,layer的梯度就不会反向传播啦,前面的所有layer的参数也就不会改变了。 
  b. 你希望C层的参数不会改变,但是C前面的AB层的参数会改变,这种情况,只是固定了C层的参数,C层得到的梯度依然会反向传播给前面的B层。只需要将对应的参数blob的学习率调整为0: 
  在layer里面加上param { lr_mult: 0 }就可以了,比如全连接层里面:

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

第五部分:Caffe fine-tune常见问题

一、按照网上的教程微调alexnet,为什么loss一直是87.3365?

  解决办法:检查数据集的标签是否是从0开始,base_lr调低了一个数量级,batch_size调高一倍。 
   
  出现的原因:87.3365是个很特殊的数字,NAN经过SoftmaxWithLoss就产生了这个数字,所以就是你的FC8输出全是NAN; 
   
  具体分析: 
  http://blog.csdn.net/jkfdqjjy/article/details/52268565?locationNum=14

二、Loss下降了,但是准确率没有明显变化?

  解决办法:训练前首先shuffle,其次学习率是否合适。

三、Data augmentation 的技巧总结:

转自小白在闭关 https://www.zhihu.com/question/35339639

图像亮度、饱和度、对比度的变化; 
PCA Jittering 
Random resize 
Random crop 
Horizontal/vertical filp 
旋转仿射变换 
加高斯噪声、模糊处理 
Label shuffle:类别不平衡数据的扩增,参见海康威视ILSVRC2016的report

               

四、如何通过loss曲线判断网络训练的情况:

  单独的 loss 曲线能提供的信息很少的,一般会结合测试机上的 accuracy 曲线来判断是否过拟合; 
  关键是要看你在测试集上的acc如何; 
  如果你的 learning_rate_policy 是 step 或者其他变化类型的话, loss 曲线可以帮助你选择一个比较合适的 stepsize;

五、finetune_net.bin不能用之后,用新的方法做finetune会出问题,怎么解决? 

   
  给最后那个InnerProduct层换个名字。


第六部分:参考资料

1.http://caffe.berkeleyvision.org/gathered/examples/finetune_flickr_style.html 
2.https://www.zhihu.com/question/54775243 
3.http://blog.csdn.net/u012526120/article/details/49496617 
4.https://zhidao.baidu.com/question/363059557656952932.html

Caffe调参

一般fine tuning的方式,都是把learning rate(solver.prototxt)调低(为原来的十分之一),之后把训练模型的最后一层或者两层的学习速率调大一点————这就相当于,把模型的前面那些层的学习调低,使得参数更新的慢一点以达到微调的目的。但有可能会导致整个收敛速度变慢,因此还需要增加最大迭代次数。
关于调参,个人感觉很多时候都是经验,在这个情景下,增加一个模块效果是好的,在另一个场景可能就是不好的。没有一个很好的理论支持你,应该怎么调整。简单来讲就是修改学习速率、batchsize等参数。
需要调节的参数(solver.prototxt)主要包括:
base_lr:初始学习率,这个是非常重要的一个参数;momentum:一般设置为0.9,如果base_lr特别低的话也可以设置为0.99或0.999等 weight_decay:默认0.005,可以适当调整,类似于正则化项;
lr_policy:学习率变化策略,常见的有fixed(固定), inv,step等,详细的说明见http://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe
最后如果loss出现不收敛的情况,可以尝试一下以下几种方法:

  1. 调小solver里的初始学习率
  2. 数据量小的话,可以只对最后几层的权重进行调整,前面权重保持不变,即把前面的学习率置为0,一定程度上限制了激活的大小,这样就限制了某一过大的误差的影响,这样可以避免迭代方向出现过大的变化。
  3. 在GPU可承受的范围内调大batch_size的大小(贾扬清的解释:理论上batch小是不会影响收敛的。小batch主要的问题是在FC层的计算可能会不是很efficient,如果实在无计可施,可以试试 ;网上其他博主的解释:batch比较小 ,导致样本覆盖面过低,产生了非常多的局部极小点,在步长和方向的共同作用下,导致数据产生了震荡,导致了不收敛 )

总而言之,一般策略是先试一试参数,把display设小一点,多看看结果,找到合适的参数,再整个跑。这里有几篇关于调参的论文(),可以看一下,基于理解和有合理解释的调参才不会变为无意义的工作。

http://bealin.github.io/2016/10/23/Caffe%E5%AD%A6%E4%B9%A0%E7%B3%BB%E5%88%97%E2%80%94%E2%80%943Fine-tuning%E5%BE%AE%E8%B0%83%E7%BD%91%E7%BB%9C/

DL开源框架Caffe | 模型微调 (finetune)的场景、问题、技巧以及解决方案的更多相关文章

  1. 【实践】如何利用tensorflow的object_detection api开源框架训练基于自己数据集的模型(Windows10系统)

    如何利用tensorflow的object_detection api开源框架训练基于自己数据集的模型(Windows10系统) 一.环境配置 1. Python3.7.x(注:我用的是3.7.3.安 ...

  2. Pyhton开源框架(加强版)

    info:Djangourl:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC)风格的 ...

  3. Python开源框架

    info:更多Django信息url:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC) ...

  4. Caffe fine-tuning 微调网络

    转载请注明出处,楼燚(yì)航的blog,http://www.cnblogs.com/louyihang-loves-baiyan/ 目前呢,caffe,theano,torch是当下比较流行的De ...

  5. 值得学习的C/C++开源框架(转)

    值得学习的C语言开源项目 - 1. Webbench Webbench是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的 ...

  6. 2018年终总结之AI领域开源框架汇总

    2018年终总结之AI领域开源框架汇总 [稍显活跃的第一季度] 2018.3.04——OpenAI公布 “后见之明经验复现(Hindsight Experience Reply, HER)”的开源算法 ...

  7. Deep learning深度学习的十大开源框架

    Google开源了TensorFlow(GitHub),此举在深度学习领域影响巨大,因为Google在人工智能领域的研发成绩斐然,有着雄厚的人才储备,而且Google自己的Gmail和搜索引擎都在使用 ...

  8. 值得推荐的C/C++开源框架和库

    值得推荐的C/C++开源框架和库  转自:http://www.cnblogs.com/lidabo/p/5514155.html   - 1. Webbench Webbench是一个在Linux下 ...

  9. C++的一些不错开源框架,可以学习和借鉴

    from https://www.cnblogs.com/charlesblc/p/5703557.html [本文系外部转贴,原文地址:http://coolshell.info/c/c++/201 ...

随机推荐

  1. Discuptor入门(二)-实例

    前言:最近在项目中看到有人使用的discuptor框架,因为没有接触过所以网上找了些资料.但最终发现开荒者太少,好像没什么人用那.最后感觉还是官方入门文档靠谱点.所以自己翻译了下(翻译器~),希望能帮 ...

  2. iview中tree的事件运用

    iview中的事件和方法如下: 案例说明: html代码 <Tree :data="data4" @on-check-change="choiceAll" ...

  3. 使用img标签能使用background-size:conver一样的效果

    使用css img { object-fit: cover; object-position:left center; } 就可以达到 和 background-size:cover; 一样的效果 共 ...

  4. 弹性布局解决ios输入框遮挡input

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. PyAutoGui 中遇到的KeyError : DISPLAY

    实际情形有可能是: tests/test_enlighten.py:: in <module> import re, sys, signal, logging, argparse, pya ...

  6. [译]C语言实现一个简易的Hash table(5)

    上一章中,我们使用了双重Hash的技术来处理碰撞,并用了C语言实现,贲张我们将实现Hash表中的插入.搜索和删除接口. 实现接口 我们的hash函数将会实现如下的接口: // hash_table.h ...

  7. Linux内核程序的编译:模块化编译

    内核在编译的时候,可以支持单独模块化编译,只需要一个小小的Makefile即可搞定. 步骤如下: 1.在任意位置创建目录 vim Makefile 2.在Makefile中添加如下代码(我的kerne ...

  8. 第一节 如何用Go实现单链表

    一.概念介绍 下面这副图是我们单链表运煤车队. 每节运煤车就是单链表里的元素,每节车厢里的煤炭就是元素中保存的数据.前后车通过锁链相连,作为单链表运煤车,从1号车厢开始,每节车厢都知道后面拉着哪一节车 ...

  9. 自定义udf添加一列

    //创建得分窗口字典 var dict= new mutable.HashMap[Double, Int]() ){ dict.put(result_Score(i),i) } //自定义Udf函数 ...

  10. 20155216 2016-2017-2《Java程序设计》课程总结

    20155216 2016-2017-2<Java程序设计>课程总结 (按顺序)每周作业链接汇总 预备作业1:简要内容:我对师生关系的见解 预备作业2:简要内容:有关C语言学习调查以及学习 ...