一,关于网络融合
分别训练了两个caffemodle,如何使用这两个caffemodel初始化这个大的网络的不同子部分(fine-tuning)。请问该如何操作?
1)caffe -weights 可以跟多个caffemodel,用”,”隔开
2)读取caffemodel并合并两个model数据,可用于初始化两个不同子部分
1.python代码将caffemodel读取
参考链接:https://www.cnblogs.com/denny402/p/5686257.html
import caffe
import numpy as np
root='/home/xxx/' #根目录
deploy=root + 'mnist/deploy.prototxt' #deploy文件
caffe_model=root + 'mnist/lenet_iter_9380.caffemodel' #训练好的 caffemodel
net = caffe.Net(deploy,caffe_model,caffe.TEST) #加载model和network
[(k,v[0].data.shape) for k,v in net.params.items()] #查看各层参数规模
w1=net.params['Convolution1'][0].data #提取参数w
b1=net.params['Convolution1'][1].data #提取参数b
net.forward() #运行测试
[(k,v.data.shape) for k,v in net.blobs.items()] #查看各层数据规模
fea=net.blobs['InnerProduct1'].data #提取某层数据(特征)
代码解读:
deploy=root + 'mnist/deploy.prototxt' #deploy文件
caffe_model=root + 'mnist/lenet_iter_9380.caffemodel' #训练好的 caffemodel
net = caffe.Net(net_file,caffe_model,caffe.TEST) #加载model和network
#就把所有的参数和数据都加载到一个net变量里面了,但是net是一个很复杂的object, 想直接显示出来看是不行的。其中:
net.params: 保存各层的参数值(w和b)
net.blobs: 保存各层的数据值
#查看各层名的参数值,v[0].data就是各层的W值,而v[1].data是各层的b值。注意:并不是所有的层都有参数,只有卷积层和全连接层才有。
[(layer_name,v[0].data) for layer_name,v in net.params.items()]
[(layer_name,v[0].data.shape) for layer_name,v in net.params.items()] #查看各层shape
#已知层名查看层参数
w1=net.params['Convolution1'][0].data
b1=net.params['Convolution1'][1].data
#运行后,看查看net中层数据(特征)
net.forward()
#查看层数据
[(k,v.data.shape) for k,v in net.blobs.items()]
[(k,v.data) for k,v in net.blobs.items()]
#抽取某一全连接层特征
fea=net.blobs['InnerProduct1'].data
二,关于fune-tune
更多fune-tune详见:
http://blog.csdn.net/zchang81/article/details/73135954
https://www.cnblogs.com/dupuleng/articles/4312129.html
假设现在有一个20类的分类问题,那么最简单的方法就是重新训练一个基于该20类的分类问题。但如果我们已经有一个1000类的模型呢?
我们其实不必大费周张的重新训练一个20类的模型,其实两个模型只有最后一层不一样,即一个的输出为1000维,另一个为20维。那么我们完全可以将1000类模型除最后一层的其余层拿过来使用,然后再使用现有数据对原模型执行fine-tuning操作,这样可以大大提高训练速度。
执行命令:
./build/tools/caffe train -solver models/finetune_flickr_style/solver.prototxt -weights models/bvlc_reference_caffenet/caffenet.caffemodel -gpu 0
解读:
使用caffenet.caffemodel模型的时候会将层名相同的参数值作为初始值赋值给相应net.prototxt定义的层的参数,那么就要求层名相同的的层的定义要完全一致,假设输出不一致,那么赋值失败。如果在原模型中没有找到相应的层,该层初始化失败,那么该层的参数初始值与普通训练无异。
因此:
1)freeze指定层参数:在layer里面加上{lr_mult:0}就可以了,比如全连接层:
2)fune-tune指定层参数:将该层名改为与caffemodel中层名字不一样或者新添加该层;