【Caffe】快速上手训练自己的数据 《很认真的讲讲Caffe》

来源:互联网 发布:安多数据库工程师招聘 编辑:程序博客网 时间:2024/05/16 18:13


上手开始训练还是比较简单的,难得是如何调参。


1.准备数据集

如果你的数据集太少,会导致训练很快过拟合. 表现为 test loss 趋于不变, 而 train loss 还在下降.

可以看这篇博文增加数据集:

http://blog.csdn.net/renhanchi/article/details/75647347


训练集,验证集和测试集。举个例子做场景识别,

需要准备的第一个文档是words.txt:第一列是序号,第二列是类别。

0 balcony1 bathroom shower2 bedroom bedchamber3 childs_room

第二个文档是train.txt: 训练集文件路径和文件名 + 空格 + 类别序号。

第三个文档是val.txt,格式同上,只不过变成了验证集文件。

分享个生成脚本:

#!/bin/shclasses=(balcony bathroom shower bedroom bedchamber childs_room)num=0for class in ${classes[@]}do    ls $class/* > $class.txt    sed -i "s/$/ $num/g" $class.txt #末尾添加类别索引    let num+=1    cat $class.txt >> temp.txt    rm $class.txtdonecat temp.txt | awk 'BEGIN{srand()}{print rand()"\t"$0}' | sort -k1,1 -n | cut -f2- > train.txt #乱序

2. 准备lmdb文件

这个要分别给train,val和test都弄一下。

找到$ROOT/caffe/example/imagenet/create_imagenet.sh,改路径。下面是我的版本。

#!/bin/shset -eEXAMPLE=/path/to/lmdb   # 保存生成lmdb目录的位置DATA=/path/to/train.txt & val.txt & test.txt TOOLS=/path/to/caffe/build/toolsTRAIN_DATA_ROOT=/absolute/path/to/calss #到上面balcony等类别目录的路径,和train.txt里面凑成图片的完整绝对路径VAL_DATA_ROOT=/absolute/path/to/calssecho "Creating train lmdb..."GLOG_logtostderr=1 $TOOLS/convert_imageset \    --resize_height=0 \ #如果你的数据集图片大小不一致,需要根据train_val.prototxt网络结构将所有图片进行缩放。    --resize_width=0 \    --shuffle=false \    $TRAIN_DATA_ROOT \    $DATA/train.txt \    $EXAMPLE/train_lmdbecho "Creating val lmdb..."GLOG_logtostderr=1 $TOOLS/convert_imageset \    --resize_height=0 \    --resize_width=0 \    --shuffle=false \  #改成true后自动shuffle    $VAL_DATA_ROOT \    $DATA/val.txt \    $EXAMPLE/val_lmdbecho "Done."

3.准备均值文件(mean file)

找到$ROOT/caffe/example/imagenet/make_imagenet_mean.sh,改路径。下面是我的版本。

#!/bin/shEXAMPLE=/path/to/lmdbDATA=/path/to/your/train.txt & val.txt   # the path should be shortTOOLS=/path/to/caffe/build/tools$TOOLS/compute_image_mean $EXAMPLE/train_lmdb $DATA/mean.binaryprotoecho "Done."

4.修改配置文件

我用的alexnet。先修改train_val_alexnet.prototxt

name: "AlexNet"layer {  name: "data"  type: "Data"  top: "data"  top: "label"  include {    phase: TRAIN  }  transform_param {    crop_size: 227    mean_file: "/path/to/mean.binaryproto" #改    mirror: true  }  data_param {    source: "/path/to/train_lmdb" #改    backend: LMDB    batch_size: 32 #改  }}layer {  name: "data"  type: "Data"  top: "data"  top: "label"  include {    phase: TEST  }  transform_param {    mirror: false    crop_size: 227    mean_file: "/path/to/mean.binaryproto" #改  }  data_param {    source: "/path/to/val_lmdb" #改    batch_size: 16 #改    backend: LMDB  }.........layer {  name: "fc8" #最后一层全连接层  type: "InnerProduct"  bottom: "fc7"  top: "fc8"  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    }  }}.........


然后修改超参数,solver_alexnet.prototxt

net: "/path/to/alexnet.prototxt"test_iter: 500  #一次测试时迭代次数,这个数值乘以test batch size是你验证集所有样本的数量test_interval: 200  #训练时迭代多少次进行一次测试base_lr: 0.001  #基础学习率lr_policy: "step"  #学习策略,步进式gamma: 0.1 #学习率衰减系数stepsize: 140000 #学习率衰减步长display: 200 #训练时迭代多少次在terminal显示一次数据max_iter: 420000 #最大训练迭代次数momentum: 0.9 #冲量,不要改weight_decay: 0.0005 #权重衰减量,不要改snapshot: 1000 #训练迭代多少次保存一次快照结果snapshot_prefix: "/path/" #快照路径solver_mode: GPU #模式

5.开始训练

直接运行:

./build/tools/caffe train --solver=/path/to/solver.prototxt


----------[2017.07.20 更新]----------finetune-------------------------------

之前一直做类别不是很多的训练, 直接训练效果就还好.

昨儿试了下20+, 30+ 类别的训练, 一晚上10W多次迭代loss居高不下, accuracy稳定在很低的值.

改了两次学习率问题没解决后, 脑子里就冒出finetune这个词. 抱着尝试的心态, 结果成功了.

我是在这里http://dl.caffe.berkeleyvision.org/       下载的bvlc_googlenet.caffemodel

模型参考caffe/model/bvlc_googlenet/train_val.prototxt

超参数参考caffe/model/bvlc_googlenet/solver.prototxt

需要修改的内容有:

1. 删掉三行mean_value, 改成meanfile=/path/to/your/meanfile.prototxt

2. 修改训练和测试source路径

3. 删掉所有带有 loss1 的层, 删掉所有带有 loss2 的层

4. 删掉最后 name: "loss3/top-5" 这一层.

5. 所有loss3/loss3 改为 loss

6. 所有loss3/top-1 改为 loss

7. num_output: 1000 将1000改成你的类别数

8. 所有loss3/classifier 随便改个名字, 比如改成 loss3


以上内容修改好之后, 就可以运行下面代码进行finetune了, 准确率上升很快.

./build/tools/caffe train -solver /path/to/solver.prototxt -weights /path/to/bvlc_googlenet.caffemodel


6.loss可视化

运行:

script loss_acc.txt./build/tools/caffe train --solver=/path/to/solver.prototxt

训练结束后记得ctrl+d退出屏幕录像。

下面是可视化用的matlab代码,这段代码参照了《深度学习:21天实战Caffe》中学习曲线可视化方法修改的。

clear;clc;close all;train_log_file = 'loss_acc.txt';display=20;  %对应solver中的值test_interval=20;  %同上[~, string_output] = dos(['cat ', train_log_file, ' | grep "Train net output #0" | awk ''{print $11}''']);train_loss = str2num(string_output);n = 1:length(train_loss);idx_train = (n-1)*display;[~, string_output] = dos(['cat ', train_log_file, ' | grep "Test net output #1" | awk ''{print $11}''']);test_loss = str2num(string_output);m = 1:length(test_loss);idx_test = (m - 1)*test_interval;figure;plot(idx_train, train_loss);hold on;plot(idx_test, test_loss,'--r');grid on;legend('Train Loss', 'Test Loss');xlabel('iterations');ylabel('loss');title(' Train & Test Loss Curve');[~, acc_output] = dos(['cat ', train_log_file, ' | grep "Test net output #0" | awk ''{print $11}''']);test_acc = str2num( acc_output);k = 1:length(test_acc);idx_acc = (k - 1)*test_interval;figure;plot(idx_acc, test_acc);grid on;box = legend('Test Accuracy');set(box,'Location','southeast');xlabel('iterations');ylabel('Accuracy');title(' Test Accuracy Curve');


-------【2017.09.26】------更新python的可视化代码, 不过还是用digits最方便------------

#!/usr/bin/env python2# -*- coding: utf-8 -*-"""Created on Tue Aug 29 10:05:13 2017@author: hanshttp://blog.csdn.net/renhanchi"""import matplotlib.pyplot as pltimport numpy as npimport commandsimport argparseparser = argparse.ArgumentParser()parser.add_argument(    '-p',    type = str,    default = '',    help = """\    path to log file\    """)FLAGS = parser.parse_args()train_log_file = FLAGS.pdisplay = 10 #solvertest_interval = 100 #solvertrain_output = commands.getoutput("cat " + train_log_file + " | grep 'Train net output #0' | awk '{print $11}'")  #train losstest_output = commands.getoutput("cat " + train_log_file + " | grep 'Test net output #1' | awk '{print $11}'")  #test lossaccu_output = commands.getoutput("cat " + train_log_file + " | grep 'Test net output #0' | awk '{print $11}'") #test accuracytrain_loss = train_output.split("\n")test_loss = test_output.split("\n")test_accu = accu_output.split("\n")l = len(test_accu)_,ax1 = plt.subplots()ax2 = ax1.twinx()l1, = ax1.plot(display*np.arange(len(train_loss)), train_loss)l2, = ax1.plot(test_interval*np.arange(l), test_loss, 'g')l3, = ax2.plot(test_interval*np.arange(l), test_accu, 'r')ax1.set_xlabel('Iteration')ax1.set_ylabel('Loss')ax2.set_ylabel('Test Accuracy')plt.legend([l1, l2, l3], ['Train Loss', 'Test Loss', 'Test Accu'], loc = 'upper left')plt.show()







上面这些都简单,最难的是调参!!调参!!!调参!!!

7.测试模型

运行:

./build/tools/caffe test \--model=/path/to/train_val_alexnet.prototxt \--weights=path/to/xxxxxxxxxx.caffemodel

这里注意一下,正常这么运行是用val数据集进行测试的。如果你准备了自己的测试集,按照上面步骤生成test_lmdb文件夹,然后在train_val_alexnet.prototxt文件中,将val_lmdb改成test_lmdb。在运行面上命令就好了。

8.使用classify.py调用模型进行分类

参考http://blog.csdn.net/renhanchi/article/details/71713227

修改132行的labels.txt路径就好了。

但是!!!注意!!!!

运行命令中的--model_def我们不能直接选择train_val_alexnet.prototxt,会报错的。

新建一个内容和train_val_alexnet.prototxt一样的文件名字叫deploy_alexnet.prototxt

然后删掉data层,accuracy层,修改loss层。具体看下面。

name: "AlexNet"input: "data"input_dim: 1input_dim: 3input_dim: 227input_dim: 227layer {  name: "conv1"  type: "Convolution"  bottom: "data"  top: "conv1"  param {    lr_mult: 1    decay_mult: 1  }  param {    lr_mult: 2    decay_mult: 0  }  convolution_param {    num_output: 96    kernel_size: 11    stride: 4    weight_filler {      type: "gaussian"      std: 0.01    }    bias_filler {      type: "constant"      value: 0    }  }}.........layer {  name: "fc8"  type: "InnerProduct"  bottom: "fc7"  top: "fc8"  param {    lr_mult: 1    decay_mult: 1  }  param {    lr_mult: 2    decay_mult: 0  }  inner_product_param {    num_output: 10    weight_filler {      type: "gaussian"      std: 0.01    }    bias_filler {      type: "constant"      value: 0    }  }}layer {  name: "prob"  type: "Softmax"  bottom: "fc8"  top: "prob"}

修改好后,运行:

cd $ROOT/caffe/pythonpython classify.py /path/to/image.jpg result.npy \--model_def  /path/to/deploy_alexnet.prototxt--pretrained_model /path/to/xxxxxx.caffemodel

当然大家也可以通过修改classify.py中前面model_def和pretrained_model的默认值来简化运行命令。