1、数据准备
对于训练,需要两个数据集:一个用于train,一个用于validation(边训练边测试,用于检测模型变化)。
具体过程参考博文caffe学习系列:训练自己的图片集(超详细教程),简要步骤如下:
(1)准备好训练和测试样本。
可以先准备好一个一样的数据集,然后从中每一类抽取一定的比例作为测试样本。如取5个类别的图片,每一类100张,共500张。每一类随机抽取20张作为测试,于是训练集为80*5=400张,测试集为20*5=100张。把训练集和测试集的图片分别放在一个单独的文件夹中,如trian_img和test_img。
(2)生成lmdb文件。
首先,新建两个txt文件train.txt和test.txt,列出train_img和test_img的文件名和对应的label(如分类数为5,则取label为0,1,2,3,4,不要取别的,否则会影响训练的精度)。可以参考上述博文的shell脚本:
#!/usr/bin/env sh DATA=data/re/ MY=examples/myfile echo "Create train.txt..." rm -rf $MY/train.txt for i in 3 4 5 6 7 do find $DATA/train -name $i*.jpg | cut -d '/' -f4-5 | sed "s/$/ $i/">>$MY/train.txt done echo "Create test.txt..." rm -rf $MY/test.txt for i in 3 4 5 6 7 do find $DATA/test -name $i*.jpg | cut -d '/' -f4-5 | sed "s/$/ $i/">>$MY/test.txt done echo "All done"其中,可以把第8行的
sed "s/$/ $i/"
换成
sed "s/$/ $((i-3))/"
就可以直接生成label为0-4的txt,而不用像博客里的再手动更改。
其次,也可以用python代码来执行这个过程,甚至可以手动编写,只要能生成这两个txt文件就可以了,生成后的格式如下:
train/348.jpg 0 train/360.jpg 0 train/374.jpg 0 ... ...
test/303.jpg 0 test/317.jpg 0 test/316.jpg 0 ... ...
然后,调用caffe自带的convert_imageset工具来生成lmdb文件。可以参考博文里的shell脚本:
#!/usr/bin/env sh MY=examples/myfile echo "Create train lmdb.." rm -rf $MY/img_train_lmdb build/tools/convert_imageset \ --shuffle \ --resize_height=256 \ --resize_width=256 \ /home/xxx/caffe/data/re/ \ $MY/train.txt \ $MY/img_train_lmdb echo "Create test lmdb.." rm -rf $MY/img_test_lmdb build/tools/convert_imageset \ --shuffle \ --resize_width=256 \ --resize_height=256 \ /home/xxx/caffe/data/re/ \ $MY/test.txt \ $MY/img_test_lmdb echo "All Done.."
实际上,这一段脚本执行的核心内容是调用了下面的命令。(同样的,也可以使用python来做这个步骤,或者直接手动在终端执行这些命令行)
build/tools/convert_imageset \ --shuffle \ --resize_height=256 \ --resize_width=256 \ /home/xxx/caffe/data/re/ \ $MY/train.txt \ $MY/img_train_lmdb
其中的参数主要有:
shuffle:乱序;
resize_height、resize_width:把图片变换到需要的大小;
图片源文件所在的目录;
上一步生成的txt描述文件的路径;
目标lmdb的路径。
执行完上述脚本后,会在指定的目录下生成两个文件夹:img_train_lmdb和img_test_lmdb,里面就是进行训练和测试所需的lmdb文件。
2、计算均值,生成均值文件
之所以要计算均值,是为了在后面进行训练和测试的输入时,先把数据减去这个均值,即把数据进行中心化,使数据分布在原点附近,从而加快训练的速度和精度。
caffe自带了计算均值的工具compute_image_mean,使用方法为:
build/tools/compute_image_mean examples/myfile/img_train_lmdb examples/myfile/mean.binaryproto
其中,我们只计算train数据集的均值,在validation中也是直接使用这个值,因为train和validation是同源的图片,它们的均值是很接近的。
3、创建模型,并编辑配置文件
一个caffe模型主要有以下几个配置文件:
solver.prototxt:指定模型的训练参数
train_val.prototxt:指定train和validation的具体网络结构
deploy.prototxt:指定模型使用时的网络结构(这个结构和train_val的结构基本相似,只是train_val输入的是一个个批次的训练数据,输出的是accuracy和loss,而deploy输入的一般是单个图片,输出的类别编号和概率,里面的网络结构是一样的)
其中,solver.prototxt的内容如下:
net: "examples/my_file/train_val.prototxt" test_iter: 2 #2 iteration every test test_interval: 50 #Test every 50 iteration(batch) base_lr: 0.001 lr_policy: "step" gamma: 0.1 stepsize: 100 display: 50 max_iter: 200 momentum: 0.9 weight_decay: 0.005 solver_mode: CPU snapshot: 50 snapshot_prefix: "examples/my_file/minemodel"
具体参数意义如下:
net:指定train_val.prototxt的路径
test_iter:每次validation时,执行测试的iteration数(一个iteration就是输入一个batch的数据,进行一次迭代),一般一次测试要覆盖一次测试集的大小,即根据训练集大小和batchsize(在train_val.prototxt中设置)来确定
test_interval:validation的间隔,如该数值为50就是说每训练50个iteration就进行一次test
base_lr:基本学习率,与后面的lr_policy配合使用
lr_policy:学习率的下降策略,可用的策略和学习率的计算方式如下
- fixed: 保持base_lr不变. - step: 如果设置为step,则还需要设置一个stepsize, 返回 base_lr * gamma ^ (floor(iter / stepsize)),其中iter表示当前的迭代次数 - exp: 返回base_lr * gamma ^ iter, iter为当前迭代次数 - inv: 如果设置为inv,还需要设置一个power, 返回base_lr * (1 + gamma * iter) ^ (- power) - multistep: 如果设置为multistep,则还需要设置一个stepvalue。这个参数和step很相似,step是均匀等间隔变化,而multistep则是根据 stepvalue值变化 - poly: 学习率进行多项式误差, 返回 base_lr (1 - iter/max_iter) ^ (power) - sigmoid: 学习率进行sigmod衰减,返回 base_lr ( 1/(1 + exp(-gamma * (iter - stepsize))))
还有人做了学习率的变化图,膜拜一下:
gamma、stepsize:学习率下降策略的参数,不同的策略可能参数不太一样
display:每隔多少次iteration输出一次执行结果
max_iter:训练的迭代次数,实测可以随时按control+c终止训练,并不会崩溃,而且还会把最后一次训练的结果保存到指定目录。一般需要对训练集进行100个epoch左右,如有10000张训练图片,batchsize为100(即一次iteration就会使用100张图片),那么iteration的次数应该为:100*n/batchsize = 100 * 10000 / 100 = 10000(n为训练集大小)
momentum:动量,类似于物理的动量,使参数不会剧烈变化。如一般的SGD更新参数的方式为x = x - α * dx,而带momentum的更新方式为v = β * v − α * dx,x = x + v
weight_decay:参数衰减比例,防止过拟合
solve_mode:训练的模式,CPU或GPU(没有GPU训练速度比TensorFlow慢)
snapshot:存储训练快照的频率,如该参数为50,表示每隔50次iteration会自动存储一次模型快照
snapshot_prefix:模型快照的存储路径
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: "examples/my_file/mean.binaryproto" } data_param { source: "examples/my_file/img_train_lmdb" batch_size: 50 backend: LMDB } } layer { name: "data" type: "Data" top: "data" top: "label" include { phase: TEST } transform_param { mirror: false crop_size: 227 mean_file: "examples/my_file/mean.binaryproto" } data_param { source: "examples/my_file/img_test_lmdb" batch_size: 50 backend: LMDB } } layer { 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: 5 weight_filler { type: "gaussian" std: 0.01 } bias_filler { type: "constant" value: 0 } } } layer { name: "accuracy" type: "Accuracy" bottom: "fc8" bottom: "label" top: "accuracy" include { phase: TEST } } layer { name: "loss" type: "SoftmaxWithLoss" bottom: "fc8" bottom: "label" top: "loss" }
其中,网络的第一个layer是data,即数据输入层,配置文件指定了两个data层,一个用于train,一个用于validation的test,分别用include { phase: TRAIN }和include { phase: TEST }来区分。
cov1后面的就是具体的网络层,常用的层有:
Convolution:卷积层
Pooling:池化层
LRN:局部归一化
ReLU:激活函数
InnerProduct:全连接层
Dropout:随机丢弃
最后的是InnerProduct全连接层,Accuracy层、SoftmaxWithLoss层,分别输出分类编号、准确率、损失值。其中,最后一个InnerProduct的num_output应该设置为实际类别的数量,如图片分为5类,则该值为5
其他的参数意义如下:
transform_param:对数据做预处理的相关参数
data_param:数据源的相关参数
mirror:是否做镜像,如果为true,会对输入的图像随机进行左右对称变换
crop_size:剪切成指定大小
mean_file:指定均值文件的路径,就是上面第2步生成的文件路径
source:数据源的路径,就是第1步生成的lmdb文件夹的路径
batch_size:一个batch的大小。一次iteration实际上是对一个batch的数据进行处理,并根据它们的平均结果来更新参数
backend:数据源的格式
param:本层的参数变化,如果一层有两个param,则第一个指定weight,第二个指定bias
weight_filler:该层的weight参数初始化方法,(据说gaussian配合softmax使用,xavier配合relu使用,未验证)
bias_filler:该层的bias参数初始化方法
lr_mult:用lr_base乘以lr_mult作为该层的参数学习率下降比例
decay_mult:用weith_dacay乘以decay_mult作为该层的weight_decay
4、进行训练
准备好数据,编辑好配置文件,就可以开始训练了,命令如下
build/tools/caffe train -solver examples/myfile/solver.prototxt
训练过程会根据指定的参数,每隔一定的iteration就会输出训练和测试的结果,并把快照存储到指定的目录
至此,训练步骤完成。