微调(fine-tuning)caffemodel来得到属于自己的高精度分类模型
2017-06-18 23:22
651 查看
当我们想自己训练一个图片分类模型时,最让我们头疼的问题就是数据集的收集。一般深度学习都要求样本量在一万以上,当我们的样本量不足时,训练出来的model的精度必然大打折扣。在这种情况下我们其实可以通过微调(fine tuning)别人的model来得到一个符合我们自己分类要求的model。
因为训练好的model里面存放的就是各种各样的参数,微调实际上就是用别人预先训练好的参数,来作为我们的初始化参数,而不需要再去随机初始化了。尤其是在做图像识别分类时,其实深度神经网络的的前面那些层都是时在提取图片特征,最后那些层,尤其是全连接层才开始组合前面提取到的特征来做分类。所以,微调从本质上讲就是改了网络的全连接层,来让它的输出达到我们自己的实际需求。
caffe团队用imagenet数据集中的图片进行训练,迭代30多万次,训练出来一个model,bvlc_reference_caffenet.caffemodel。这个model将图片分为1000类,是目前为止最好的图片分类model了。
一般情况下,我们自己的要用的分类器根本不需要分1000类,所以我们就把网络最后一层的输出数量改成我们需要的分类个数。但对于其他层的结构就要和原网络保持一致,因为参数是根据network而来的。
下面我们就用一个小数据集为例,来介绍一下具体步骤。数据集来源于denny的学习专栏,在此安利一下该博客,很全很详细,值得一看。数据集的下载地址为http://pan.baidu.com/s/1MotUe 这个数据集共有500张图片,分为大巴车、恐龙、大象、鲜花和马五个类,每个类100张。命名分别以3,4,5,6,7开头,各为一类。我从其中每类选出20张作为测试,其余80张作为训练。因此最终训练图片400张(放在train文件夹内,每个类一个子文件夹),测试图片100张(放在test文件夹内,每个类一个子文件夹)。
也可以运行脚本文件进行下载:
将图片下载下来后解压,有两个文件夹一个为训练样本train,一个为测试样本test。将其放在caffe的data文件夹中。
首先我们要我们生成图片清单,来表面每张图片属于哪一类。
我们可以通过创建sh脚本文件,调用linux命令来生成图片清单:
create_filelist_train.sh
create_filelist_test.sh
跳转到数据集所在目录,执行上面两个脚本文件。就会生成图片清单。
train和test文件夹就会生成图片清单。
而后就需要进行转化为lmdb操作。我们也是通过在re文件夹写两个脚本文件。
create_lmdb_train.sh
create_lmdb_test.sh
这样在re文件夹就会生成两个lmdb的文件夹。
最后在re文件夹下建立一个words.txt,用来描述分类对象。
将前面几层的数据接口改成我们自己的目录:
将全连接层重命名,并将输出个数改成5,再将accuracy和loss中全连接层的名字做相应的修改:
主要的调整有:100个测试数据,batch_size为50(见my_train_val.prototxt),因此test_iter设置为2,就能全cover了。base_lr从0.01变成了0.001,这个很重要,微调时的基本学习速率不能太大,学习策略没有改变,步长从原来的100000变成了100,最大的迭代次数也从450000变成了500,动量和权重衰减项都没有修改,依然是GPU模型,网络模型文件和快照的路径根据自己修改 。
训练过程中,loss逐渐减小,accuracy逐渐上升。最终结果如下所示,分类准确率100%!!!
这时候在caffe/models/bvlc_reference_caffenet中生成了一个caffenet_train_iter_500.caffemodel。这就是我们微调训练得到的模型。
就将最后的全连接层改成和my_train_val.prototxt一样的形式。
在caffe/python中建立一个python文件
我在网上下了一张花,来让我们的分类器判断一下。
在caffe的根目录运行:
结果如下,判断为花的可能性为100%。
http://blog.csdn.net/lanseyuansu/article/details/70937746
因为训练好的model里面存放的就是各种各样的参数,微调实际上就是用别人预先训练好的参数,来作为我们的初始化参数,而不需要再去随机初始化了。尤其是在做图像识别分类时,其实深度神经网络的的前面那些层都是时在提取图片特征,最后那些层,尤其是全连接层才开始组合前面提取到的特征来做分类。所以,微调从本质上讲就是改了网络的全连接层,来让它的输出达到我们自己的实际需求。
caffe团队用imagenet数据集中的图片进行训练,迭代30多万次,训练出来一个model,bvlc_reference_caffenet.caffemodel。这个model将图片分为1000类,是目前为止最好的图片分类model了。
一般情况下,我们自己的要用的分类器根本不需要分1000类,所以我们就把网络最后一层的输出数量改成我们需要的分类个数。但对于其他层的结构就要和原网络保持一致,因为参数是根据network而来的。
下面我们就用一个小数据集为例,来介绍一下具体步骤。数据集来源于denny的学习专栏,在此安利一下该博客,很全很详细,值得一看。数据集的下载地址为http://pan.baidu.com/s/1MotUe 这个数据集共有500张图片,分为大巴车、恐龙、大象、鲜花和马五个类,每个类100张。命名分别以3,4,5,6,7开头,各为一类。我从其中每类选出20张作为测试,其余80张作为训练。因此最终训练图片400张(放在train文件夹内,每个类一个子文件夹),测试图片100张(放在test文件夹内,每个类一个子文件夹)。
下载成型model
将bvlc_reference_caffenet.caffemodel(点此下载)下载到caffe根目录下的 models/bvlc_reference_caffenet/ 文件夹下面。也可以运行脚本文件进行下载:
sudo ./scripts/download_model_binary.py models/bvlc_reference_caffenet
收集数据集
根据自己的需求来寻找数据集,这里就以denny的学习专栏作者徐其华收集的数据集(点此下载)为例来讲解。将图片下载下来后解压,有两个文件夹一个为训练样本train,一个为测试样本test。将其放在caffe的data文件夹中。
将数据集转化为lmdb格式
为了便于神经网络模型读取数据,我们一般都是要将图片数据转化为lmdb格式的。首先我们要我们生成图片清单,来表面每张图片属于哪一类。
我们可以通过创建sh脚本文件,调用linux命令来生成图片清单:
create_filelist_train.sh
#!/usr/bin/env sh DATA=train echo "Create train.txt..." rm -rf $DATA/train.txt find $DATA -name 3*.jpg | cut -d '/' -f2 | sed "s/$/ 0/">>$DATA/train.txt find $DATA -name 4*.jpg | cut -d '/' -f2 | sed "s/$/ 1/">>$DATA/tmp.txt cat $DATA/tmp.txt>>$DATA/train.txt rm -rf $DATA/tmp.txt find $DATA -name 5*.jpg | cut -d '/' -f2 | sed "s/$/ 2/">>$DATA/tmp.txt cat $DATA/tmp.txt>>$DATA/train.txt rm -rf $DATA/tmp.txt find $DATA -name 6*.jpg | cut -d '/' -f2 | sed "s/$/ 3/">>$DATA/tmp.txt cat $DATA/tmp.txt>>$DATA/train.txt rm -rf $DATA/tmp.txt find $DATA -name 7*.jpg | cut -d '/' -f2 | sed "s/$/ 4/">>$DATA/tmp.txt cat $DATA/tmp.txt>>$DATA/train.txt rm -rf $DATA/tmp.txt echo "Done.."
create_filelist_test.sh
#!/usr/bin/env sh DATA=test echo "Create test.txt..." rm -rf $DATA/test.txt find $DATA -name 3*.jpg | cut -d '/' -f2 | sed "s/$/ 0/">>$DATA/test.txt find $DATA -name 4*.jpg | cut -d '/' -f2 | sed "s/$/ 1/">>$DATA/tmp.txt cat $DATA/tmp.txt>>$DATA/test.txt rm -rf $DATA/tmp.txt find $DATA -name 5*.jpg | cut -d '/' -f2 | sed "s/$/ 2/">>$DATA/tmp.txt cat $DATA/tmp.txt>>$DATA/test.txt rm -rf $DATA/tmp.txt find $DATA -name 6*.jpg | cut -d '/' -f2 | sed "s/$/ 3/">>$DATA/tmp.txt cat $DATA/tmp.txt>>$DATA/test.txt rm -rf $DATA/tmp.txt find $DATA -name 7*.jpg | cut -d '/' -f2 | sed "s/$/ 4/">>$DATA/tmp.txt cat $DATA/tmp.txt>>$DATA/test.txt rm -rf $DATA/tmp.txt echo "Done.."
跳转到数据集所在目录,执行上面两个脚本文件。就会生成图片清单。
train和test文件夹就会生成图片清单。
而后就需要进行转化为lmdb操作。我们也是通过在re文件夹写两个脚本文件。
create_lmdb_train.sh
#!/usr/bin/env sh DATA=/home/yangyuan/caffe/data/re/train rm -rf $DATA/../img_train_lmdb /home/yangyuan/caffe/build/tools/convert_imageset --shuffle \ --resize_height=256 --resize_width=256 \ /home/yangyuan/caffe/data/re/train/ $DATA/train.txt $DATA/../img_train_lmdb
create_lmdb_test.sh
#!/usr/bin/env sh DATA=/home/yangyuan/caffe/data/re/test rm -rf $DATA/../img_test_lmdb /home/yangyuan/caffe/build/tools/convert_imageset --shuffle \ --resize_height=256 --resize_width=256 \ /home/yangyuan/caffe/data/re/test/ $DATA/test.txt $DATA/../img_test_lmdb
这样在re文件夹就会生成两个lmdb的文件夹。
最后在re文件夹下建立一个words.txt,用来描述分类对象。
bus dinosaur elephant flower horse
计算图片数据的均值
图片减去均值后,再进行训练和测试,会提高速度和精度,所以我们要通过如下命令来生成我们训练样本的均值文件。sudo build/tools/compute_image_mean data/re/img_train_lmdb data/re/mean.binaryproto
调整网络参数
前面我们将bvlc_reference_caffenet.caffemodel下载到caffe根目录下的 models/bvlc_reference_caffenet/ 文件夹下面。在该文件夹下有一个train_val.prototxt,它是用来描述该网络的结构的。我们复制一份重命名为my_train_val.prototxt并对其进行修改。将前面几层的数据接口改成我们自己的目录:
name: "CaffeNet" layer { name: "data" type: "Data" top: "data" top: "label" include { phase: TRAIN } transform_param { mirror: true crop_size: 227 mean_file: "data/re/mean.binaryproto" } # mean pixel / channel-wise mean instead of mean image # transform_param { # crop_size: 227 # mean_value: 104 # mean_value: 117 # mean_value: 123 # mirror: true # } data_param { source: "data/re/img_train_lmdb" batch_size: 256 backend: LMDB } } layer { name: "data" type: "Data" top: "data" top: "label" include { phase: TEST } transform_param { mirror: false crop_size: 227 mean_file: "data/re/mean.binaryproto" } # mean pixel / channel-wise mean instead of mean image # transform_param { # crop_size: 227 # mean_value: 104 # mean_value: 117 # mean_value: 123 # mirror: false # } data_param { source: "data/re/img_test_lmdb" batch_size: 50 backend: LMDB } }
将全连接层重命名,并将输出个数改成5,再将accuracy和loss中全连接层的名字做相应的修改:
layer { name: "fc8_1" type: "InnerProduct" bottom: "fc7" top: "fc8_1" param { lr_mult: 1 decay_mult: 1 } param { lr_mult: 2 decay_mult: 0 } inner_product_param { num_output: 5 weight_filler { type: "gaussian" std: 0.01 } bias_filler { type: "constant" value: 0 } } } layer { name: "accuracy" type: "Accuracy" bottom: "fc8_1" bottom: "label" top: "accuracy" include { phase: TEST } } layer { name: "loss" type: "SoftmaxWithLoss" bottom: "fc8_1" bottom: "label" top: "loss" }
修改Solver文件参数
将caffe根目录下的 models/bvlc_reference_caffenet/ 文件夹下面的solver.prototxt,复制一份重命名为my_solver.prototxt并对其进行修改。主要的调整有:100个测试数据,batch_size为50(见my_train_val.prototxt),因此test_iter设置为2,就能全cover了。base_lr从0.01变成了0.001,这个很重要,微调时的基本学习速率不能太大,学习策略没有改变,步长从原来的100000变成了100,最大的迭代次数也从450000变成了500,动量和权重衰减项都没有修改,依然是GPU模型,网络模型文件和快照的路径根据自己修改 。
net: "models/bvlc_reference_caffenet/my_train_val.prototxt" test_iter: 2 test_interval: 50 base_lr: 0.001 lr_policy: "step" gamma: 0.1 stepsize: 100 display: 20 max_iter: 500 momentum: 0.9 weight_decay: 0.005 snapshot: 10000 snapshot_prefix: "models/bvlc_reference_caffenet/caffenet_train" solver_mode: GPU
训练
执行如下命令开始对bvlc_reference_caffenet.caffemodel 来进行微调训练sudo ./build/tools/caffe train --solver ./models/bvlc_reference_caffenet/my_solver.prototxt --weights ./models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel
训练过程中,loss逐渐减小,accuracy逐渐上升。最终结果如下所示,分类准确率100%!!!
这时候在caffe/models/bvlc_reference_caffenet中生成了一个caffenet_train_iter_500.caffemodel。这就是我们微调训练得到的模型。
用得到的模型来做分类
将caffe根目录下的 models/bvlc_reference_caffenet/ 文件夹下面的deploy.prototxt,复制一份重命名为my_deploy.prototxt并对其进行修改。就将最后的全连接层改成和my_train_val.prototxt一样的形式。
layer { name: "fc8_1" type: "InnerProduct" bottom: "fc7" top: "fc8_1" inner_product_param { num_output: 5 } } layer { name: "prob" type: "Softmax" bottom: "fc8_1" top: "prob" }
在caffe/python中建立一个python文件
#coding=utf-8 #加载必要的库 import numpy as np import sys,os #设置当前目录 caffe_root = '/home/yangyuan/caffe/' sys.path.insert(0, caffe_root + 'python') import caffe os.chdir(caffe_root) net_file=caffe_root + 'models/bvlc_reference_caffenet/my_deploy.prototxt' caffe_model=caffe_root + 'models/bvlc_reference_caffenet/caffenet_train_iter_500.caffemodel' #mean_file=caffe_root + 'python/caffe/imagenet/ilsvrc_2012_mean.npy' net = caffe.Net(net_file,caffe_model,caffe.TEST) transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape}) transformer.set_transpose('data', (2,0,1)) #transformer.set_mean('data', np.load(mean_file).mean(1).mean(1)) transformer.set_raw_scale('data', 255) transformer.set_channel_swap('data', (2,1,0)) im=caffe.io.load_image('/home/yangyuan/project/image/flower1.jpg') #im=caffe.io.load_image('/home/yangyuan/caffe/data/re/test/302.jpg') #im=caffe.io.load_image(caffe_root+'examples/images/cat.jpg') net.blobs['data'].data[...] = transformer.preprocess('data',im) out = net.forward() imagenet_labels_filename = caffe_root + 'data/re/words.txt' labels = np.loadtxt(imagenet_labels_filename, str, delimiter='\t') top_k = net.blobs['prob'].data[0].flatten().argsort()[-1:-6:-1] p= net.blobs['prob'].data print p print type(p) print p.shape for i in np.arange(top_k.size): print labels[top_k[i]],p[0][top_k[i]]
我在网上下了一张花,来让我们的分类器判断一下。
在caffe的根目录运行:
sudo python python/my_classify.py
结果如下,判断为花的可能性为100%。
参考文献
http://www.cnblogs.com/denny402/category/759199.htmlhttp://blog.csdn.net/lanseyuansu/article/details/70937746
相关文章推荐
- 微调︱caffe中fine-tuning模型三重天(函数详解、框架简述)+微调技巧
- Windows下caffe用fine-tuning训练好的caffemodel来进行图像分类
- 【object detection】RCNN 实践篇 - 使用 Alexnet 预训练 17-flower 数据集(17分类),使用 2-flower 数据集进行 fine-tuning
- DL学习笔记【15】使用训练好的模型得到分类结果
- Caffe fine-tuning 微调网络
- Caffe fine-tuning 微调网络
- 【object detection】RCNN 实践篇 - 使用 Alexnet 预训练 17-flower 数据集(17分类),使用 2-flower 数据集进行 fine-tuning
- 关于fine-tuning:利用已有模型训练其他数据集
- 【object detection】RCNN 实践篇 - 使用 Alexnet 预训练 17-flower 数据集(17分类),使用 2-flower 数据集进行 fine-tuning
- 【object detection】RCNN 实践篇 - 使用 Alexnet 预训练 17-flower 数据集(17分类),使用 2-flower 数据集进行 fine-tuning
- Caffe fine-tuning 微调网络
- 20140502-识别的微调阶段 (Fine-tuning for discrimination )
- 【object detection】RCNN 实践篇 - 使用 Alexnet 预训练 17-flower 数据集(17分类),使用 2-flower 数据集进行 fine-tuning
- [置顶] Caffe windows 下进行(微调)fine-tune 模型
- ###好好好######fine-tuning:利用已有模型训练其他数据集
- 【object detection】RCNN 实践篇 - 使用 Alexnet 预训练 17-flower 数据集(17分类),使用 2-flower 数据集进行 fine-tuning
- Caffe fine-tuning 微调网络
- caffe 框架下微调已有模型训练自己的数据实现图像分类
- caffe网络微调(fine-tuning)
- 14.4.3.6 Fine-tuning InnoDB Buffer Pool Flushing 微调 InnoDB Buffer Pool 刷新: