参考: http://blog.csdn.net/xjz18298268521/article/details/53176152
现在随着深度学习技术的迅速发展,深度学习技术在图像和语音方向的应用已经很成熟了。目前工程上应用深度学习一般源于数据的限制都是在ImageNet pre-trained model的基础上进行微调—fine-tune。由于ImageNet数以百万计带标签的训练集数据,使得如CaffeNet之类的预训练的模型具有非常强大的泛化能力,这些预训练的模型的中间层包含非常多一般性的视觉元素,我们只需要对他的后几层进行微调,在应用到我们的数据上,通常就可以得到非常好的结果。
微调的目的是使别人训练好的模型更适合自己的数据,因此,微调的数据一般都是适合自己应用的数据。但是,大牛建议,在微调是不要全部使用自己的数据,应该将自己的数据和原始训练数据混合在一起,并逐步增加自己的数据的比例,这样效果可能会好一些。
下面给出一个比较经典的微调策略的网站:
http://lamda.nju.edu.cn/weixs/project/CNNTricks/CNNTricks.html
另外看了一篇博客记录微调的一些参数解释:
- finetune的过程相当于继续训练,跟直接训练的区别是初始化的时候:
直接训练是按照网络定义指定的方式初始化(如高斯随机初始化);
finetune是用你已经有的参数文件来初始化(就是之前训练好的caffemodel); - 这个问题有两种情况:比如有4个全连接层A->B->C->D
你希望C层的参数不会改变,C前面的AB层的参数也不会改变,这种情况也就是D层的梯度不往前反向传播到D层的输入blob(也就是C层的输出blob 没有得到梯度),你可以通过设置D层的propagate_down为false来做到。propagate_down的数量与输入blob的数量相同,假如你某个层有2个输入blob,那么你应该在该layer的Param里面写上两行:
propagate_down : 0 # 第1个输入blob不会得到反向传播的梯度
propagate_down : 0 # 第2个输入blob不会得到反向传播的梯度
这样的话,你这个layer的梯度就不会反向传播啦,前面的所有layer的参数也就不会改变了。
你希望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
}
训练代码可以参考:
http://blog.csdn.net/sinat_26917383/article/details/54999868
end-to-end 完全训练:
end_to_end_net=style_net(train=True, learn_all=True)
style_solver_filename =solver(end_to_end_net,base_lr=base_lr)
style_solver = caffe.get_solver(style_solver_filename)
weights = caffe_root +'models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel'
assert os.path.exists(weights)
style_solver.net.copy_from(weights)
solvers = [('pretrained', style_solver)]
niter=200
loss, acc, weights =run_solvers(niter, solvers)