caffe训练模型需要三个文件,分别是solver.prototxt、train_val.prototxt、train.sh,下面我们依次介绍。
1、solver.prototxt
solver.prototxt这个文件主要存放模型训练所用到的一些超参数:
net := 指定待训练模型结构文件,即train_val.prototxt
test_interval := 测试间隔,即每隔多少次迭代进行一次测试。
test_initialization := 指定是否进行初始测试,即模型未进行训练时的测试
test_iteration := 指定测试时进行的迭代次数,即test_iter* batchsize(测试集的)=测试集的大小,测试集的 batchsize可以在prototx文件里设置。
base_lr := 指定基本学习率
lr_policy := 学习率变更策略,这个参数代表的是learning rate应该遵守什么样的变化规则,这个参数对应的是字符串,选项及说明如下:
“step” - 需要设置一个stepsize参数,返回base_lr * gamma ^ ( floor ( iter / stepsize ) ),iter为当前迭代次数
“multistep” - 和step相近,但是需要stepvalue参数,step是均匀等间隔变化,而multistep是根据stepvalue的值进行变化
“fixed” - 保持base_lr不变
“exp” - 返回base_lr * gamma ^ iter, iter为当前迭代次数
“poly” - 学习率进行多项式误差衰减,返回 base_lr ( 1 - iter / max_iter ) ^ ( power )
“sigmoid” - 学习率进行sigmod函数衰减,返回 base_lr ( 1/ 1+exp ( -gamma * ( iter - stepsize ) ) )
gamma := 学习率变更策略需要用到的参数
power := 同上
stepsize := 学习率变更策略Step的变更步长(固定步长),每stepsize次迭代减少学习率,这一项和lr_policy有关
stepvalue := 学习率变更策略Multistep的变更步长(可变步长)
iter_size: iter_size,iter_size:iter_size*batch size=实际使用的batch size。 相当于读取batchsize*itersize个图像才做一下gradient decent。 这个参数可以规避由于gpu不足而导致的batchsize的限制 因为你可以用多个iteration做到很大的batch 即使单次batch有限
max_iter := 模型训练的最大迭代次数
momentum := 动量,这是优化策略(Adam, SGD, … )用到的参数,灵感来自于牛顿第一定律,基本思路是为寻优加入了“惯性”的影响,这样一来,当误差曲面中存在平坦区的时候,SGD可以更快的速度学习。
momentum2 := 优化策略Adam用到的参数
weight_decay := 权重衰减率,用于防止过拟合。使用方式:样本越多,该值越小,模型参数越多,该值越大。一般建议值:weight_decay: 0.0005。
clip_gradients := 固定梯度范围
display := 每隔几次迭代显示一次结果
snapshot := 快照,每隔几次保存一次模型参数
snapshot_prefix := 保存模型文件的前缀,可以是路径
type := solver优化策略,即SGD、Adam、AdaGRAD、RMSProp、NESTROVE、ADADELTA等,在solver配置文件中,通过设置type类型来选择:
Stochastic Gradient Descent (type: "SGD"),
AdaDelta (type: "AdaDelta"),
Adaptive Gradient (type: "AdaGrad"),
Adam (type: "Adam"),
Nesterov’s Accelerated Gradient (type: "Nesterov") and
RMSprop (type: "RMSProp")
solver_mode := 指定训练模式,即GPU/CPU
debug_info := 指定是否打印调试信息,这里有对启用该功能的输出作介绍
device_id := 指定设备号(使用GPU模式),选择几块GPU,默认为0
2、train_val.prototxt
train_val文件是用来存放模型结构的地方,模型的结构主要以layer为单位来构建。下面我们以LeNet为例介绍网络层的基本组成:
name: "LeNet"
layer { # 这里为训练的数据层
name: "mnist" # 网络层名称
type: "Data" # 网络层类型,数据层
top: "data" # 这一层的输出,数据
top: "label" # 这一层的输出,标签
include { phase: TRAIN } # TRAIN:=用于训练,TEST:=用于测试,表明这是在训练阶段才包括进去
transform_param {
scale: 0.00390625 # 对数据进行scale
mirror: true # 是否做镜像
crop_size: 227 # 对图像做裁剪
mean_file: "data/ilsvrc12/imagenet_mean.binaryproto" # 减去均值文件
}
data_param { # 数据层配置
source: "examples/mnist/mnist_train_lmdb" # 数据存放路径
batch_size: 64 # 指定batch大小
backend: LMDB # 指定数据库格式,LMDB/LevelDB
}
}
layer { # 这里为测试的数据层
name: "mnist" # 网络层名称
type: "Data" # 网络层类型,数据层
top: "data" # 这一层的输出,数据
top: "label" # 这一层的输出,标签
include { phase: TEST } #TRAIN:=用于训练,TEST:=用于测试,表明这是在测试阶段才包括进去
transform_param {
scale: 0.00390625 # 对数据进行scale
mirror: true # 是否做镜像
crop_size: 227 # 对图像做裁剪
mean_file: "data/ilsvrc12/imagenet_mean.binaryproto" # 减去均值文件
}
data_param { # 数据层配置
source: "examples/mnist/mnist_test_lmdb" # 数据存放路径
batch_size: 100 # 指定batch大小
backend: LMDB # 指定数据库格式,LMDB/LevelDB
}
}
layer{ # 这里为第一个卷积层
name:"conv1" # 卷积层名
type:"Convolution" # 卷积层类型:卷积层
bottom:"data" # 上一层的输出作为输入
top:"conv1" # 这一层的输出,conv1
param{
name:"conv1_w" # 卷积层参数w(权重)的名称、
lr_mult:1 # 卷积层参数w学习率,最终的学习率需要乘以 solver.prototxt 配置文件中的base_lr
decay_mult:1 # 卷积层参数w的衰减率,最终的衰减率需要乘以 solver.prototxt 配置文件中的weight_decay
}
param{
name:"conv1_b" # 卷积层参数b(偏置)的名称,学习率和衰减率
lr_mult:2 # 偏置设为2倍学习率,能够加速收敛
decay_mult:0}
convolution_param{
num_output:20 # 卷积层输出的feature map数量
kernel_size:5 # 卷积层的大小
pad:0 # 卷积层的填充大小
stride:1 # 进行卷积的步长
weight_filler{type:"xavier" } # 参数w的初始话策略
weight_filler{type:"constant" value:0.1} # 参数b的初始化策略
}
}
layer { # BatchNorm层,对feature map进行批规范化处理
name:"bn1"
type:"BatchNorm"
bottom:"conv1"
top:"conv1"
batch_norm_param{ use_global_stats:false} #训练时为false,测试时为true
}
layer { # 池化层,即下采样层
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX # 最大值池化,还有AVE均值池化
kernel_size: 2
stride: 2
}
} # 第二个卷积层配置
layer {
name: "conv2"
type: "Convolution"
bottom: "pool1"
top: "conv2"
param { lr_mult: 1 }
param { lr_mult: 2 }
convolution_param {
num_output: 50
kernel_size: 5
stride: 1
weight_filler { type: "xavier" }
bias_filler { type: "constant" }
}
}
layer { # 第二个batchnorm层
name:"bn2"
type:"BatchNorm"
bottom:"conv2"
top:"conv2"
batch_norm_param{ use_global_stats:false}
}
layer { # 第二个池化层
name: "pool2"
type: "Pooling"
bottom: "conv2"
top: "pool2"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
layer { #全连接层
name: "ip1"
type: "InnerProduct"
bottom: "pool2"
top: "ip1"
param { lr_mult: 1 }
param { lr_mult: 2 }
inner_product_param {
num_output: 500
weight_filler { type: "xavier" }
bias_filler { type: "constant" }
}
}
layer { # 激活函数层,提供非线性能力
name: "relu1"
type: "ReLU"
bottom: "ip1"
top: "ip1"
}
layer { # 第二个全连接层
name: "ip2"
type: "InnerProduct"
bottom: "ip1"
top: "ip2"
param { lr_mult: 1 }
param { lr_mult: 2 }
inner_product_param {
num_output: 10
weight_filler { type: "xavier" }
bias_filler { type: "constant" }
}
}
layer { # 损失函数层
name: "prob"
type: "SoftmaxWithLoss"
bottom: "ip2"
bottom: "label"
top: "prob"
}
3、train.sh
这个脚本文件可写,可不写。每次运行需要写一样的命令,所以建议写一下。这里我们举个简单的例子,改代码是Caffe官方文档提供的,但只能用于单标签的任务,多标签得对源码进行修改。该脚本是对图片数据生成对应的lmdb文件,博主一般使用原图,即数据层类型用ImageData。
#!/usr/bin/env sh
# Create the imagenet lmdb inputs
# N.B. set the path to the imagenet train + val data dirs
set -e
EXAMPLE="" #存储路径
DATA="" #数据路径
TOOLS=/path/to/your/caffe/build/tools #caffe所在目录
TRAIN_DATA_ROOT="" #训练数据根目录
VAL_DATA_ROOT="" #测试数据根目录
# RESIZE=true to resize the images to 256x256. Leave as false if images have
# already been resized using another tool.
RESIZE=false #重新调整图片大小
if $RESIZE; then
RESIZE_HEIGHT=256
RESIZE_WIDTH=256
else
RESIZE_HEIGHT=0
RESIZE_WIDTH=0
fi
#检测路径是否存在
if [ ! -d "$TRAIN_DATA_ROOT" ]; then
echo "Error: TRAIN_DATA_ROOT is not a path to a directory: $TRAIN_DATA_ROOT"
echo "Set the TRAIN_DATA_ROOT variable in create_imagenet.sh to the path" \
"where the ImageNet training data is stored."
exit 1
fi
if [ ! -d "$VAL_DATA_ROOT" ]; then
echo "Error: VAL_DATA_ROOT is not a path to a directory: $VAL_DATA_ROOT"
echo "Set the VAL_DATA_ROOT variable in create_imagenet.sh to the path" \
"where the ImageNet validation data is stored."
exit 1
fi
echo "Creating train lmdb..."
GLOG_logtostderr=1 $TOOLS/convert_imageset \
--resize_height=$RESIZE_HEIGHT \
--resize_width=$RESIZE_WIDTH \
--shuffle \
$TRAIN_DATA_ROOT \
$DATA/train.txt \ #训练图片列表,运行时请把该行注释删除,否则会出错
$EXAMPLE/mnist_train_lmdb
echo "Creating val lmdb..."
GLOG_logtostderr=1 $TOOLS/convert_imageset \
--resize_height=$RESIZE_HEIGHT \
--resize_width=$RESIZE_WIDTH \
--shuffle \
$VAL_DATA_ROOT \
$DATA/val.txt \
$EXAMPLE/mnist_test_lmdb
echo "Done."