参考博客:https://blog.csdn.net/cham_3/article/details/72141753
利用Caffe进行深度神经网络训练第一步需要搞懂几个重要文件:
- solver.prototxt
- train_val.prototxt
- train.sh
接下来我们按顺序一个个说明。
solver.prototxt
solver这个文件主要存放模型训练所用到的一些超参数:
- net := 指定待训练模型结构文件,即train_val.prototxt
- test_interval := 测试间隔,即每隔多少次迭代进行一次测试
- test_initialization := 指定是否进行初始测试,即模型未进行训练时的测试
- test_iteration := 指定测试时进行的迭代次数
- base_lr := 指定基本学习率
- lr_policy := 学习率变更策略,这里有介绍,可供参考
- gamma := 学习率变更策略需要用到的参数
- power := 同上
- stepsize := 学习率变更策略Step的变更步长(固定步长)
- stepvalue := 学习率变更策略Multistep的变更步长(可变步长)
- max_iter := 模型训练的最大迭代次数
- momentum := 动量,这是优化策略(Adam, SGD, … )用到的参数
- momentum2 := 优化策略Adam用到的参数
- weight_decay := 权重衰减率
- clip_gradients := 固定梯度范围
- display := 每隔几次迭代显示一次结果
- snapshot := 快照,每隔几次保存一次模型参数
- snapshot_prefix := 保存模型文件的前缀,可以是路径
- type := solver优化策略,即SGD、Adam、AdaGRAD、RMSProp、NESTROVE、ADADELTA等
- solver_mode := 指定训练模式,即GPU/CPU
- debug_info := 指定是否打印调试信息,这里有对启用该功能的输出作介绍
- device_id := 指定设备号(使用GPU模式),默认为0
用户根据自己的情况进行相应设置,黑体参数为必须指定的,其余参数为可选(根据情况选择)。
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 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 } transform_param { scale: 0.00390625 } data_param { source: "examples/mnist/mnist_test_lmdb" batch_size: 100 backend: LMDB } } layer{ name:"conv1" type:"Convolution" #卷积层 bottom:"data" #上一层的输出作为输入 top:"conv1" param{name:"conv1_w" lr_mult:1 decay_mult:1} #卷积层参数w的名称,学习率和衰减率(相对于base_lr和weight_decay的倍数) param{name:"conv1_b" lr_mult:2 decay_mult:0} #卷积层参数b的名称,学习率和衰减率 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 { 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" }
网络结构和超参数都设计完了,接下来就可以进行模型训练了。这里我介绍最常用的模型训练脚本,也是Caffe官方文档给的例子。
train.sh
这个脚本文件可写,可不写。每次运行需要写一样的命令,所以建议写一下。
TOOLS=/path/to/your/caffe/build/tools GLOG_logtostderr=0 GLOG_log_dir=log/ #该行用于调用glog进行训练日志保存,使用时请把该行注释删除,否则会出错 $TOOLS/caffe train --solver=/path/to/your/solver.prototxt #--snapshot=/path/to/your/snapshot or --weights=/path/to/your/caffemodel ,snapshot和weights两者只是选一,两个参数都可以用来继续训练,区别在于是否保存solver状态
数据准备
这里我们举个简单的例子,改代码是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."
这样,我们就可以愉快的开始训练啦。