lmdb是caffe训练网络用的数据格式,因此我们需要将原始的图片数据转换成lmdb(当然caffe中也可以直接用jpg进行训练)。利用上文Caffe | 你的第一个分类网络之数据准备中得到的train.txt和test.txt结合GitHub上caffe自带的批处理文件create_imagenet.sh就可以生成lmdb文件,该批处理文件存在如下所示的路径中。
基于train.txt,test.txt以及原始的图片,并根据下面代码所示修改后在命令窗口使用sh create_imagenet.sh就可以生成赌对应的lmdb文件了(具体修改策略看下边代码中的中文注释)。
#!/usr/bin/env sh
# Create the imagenet lmdb inputs
# N.B. set the path to the imagenet train + val data dirs
set -e
EXAMPLE=/home/YL/DataSet #该路径为lmdb存储路径
DATA=/home/YL/DataSet #该路径为train.txt所在路径
TOOLS=/home/caffe/build/tools #该路径为编译完caffe的路径(就是你安装的caffe路径)
TRAIN_DATA_ROOT=/home/YL/DataSet/
VAL_DATA_ROOT=/home/YL/DataSet/
# Set 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..."
rm -rf $EXAMPLE/train_lmdb #这两句表示在生成lmdb前先把老的删除
rm -rf $EXAMPLE/test_lmdb #因为生成lmdb时,若同路径下有同名文件会出错
GLOG_logtostderr=1 $TOOLS/convert_imageset \
--resize_height=$RESIZE_HEIGHT \
--resize_width=$RESIZE_WIDTH \
--shuffle \
$TRAIN_DATA_ROOT \
$DATA/train.txt \
$EXAMPLE/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/test.txt \
$EXAMPLE/test_lmdb
echo "Done."
该过程中可能会遇到的问题:
图片减去均值后,归一化后,再进行训练和测试,会提高速度和精度。因此,一般在各种模型中都会有这个操作。那么这个均值怎么来的呢,主要有两种方式第一种就是直接将均值设置为128,但若遇到一些填充过的样本,那么均值就会和128相差较多,这种情况下就要用第二种方法。第二种方法:实际上就是计算所有训练样本的平均值,计算出来后,保存为一个均值文件,在以后的测试中,就可以直接使用这个均值来相减,而不需要对测试图片重新计算。而利用第二种方法时,可以用caffe自带的策略。当然某些场景下需要得到Python中可用的均值文件,那也可以用Python脚本自己计算。
(1)caffe计算均值文件
caffe中使用的均值数据格式是binaryproto, caffe的作者为我们提供了一个计算均值的文件compute_image_mean.cpp,放在caffe根目录下的tools文件夹里面。编译后的可执行体放在 build/tools/ 下面,安装如下mnist实例所示调用即可。
#注意下面3句话要写在一行上,用空格分开(此处便于展示,进行了分段)
sudo
build/tools/compute_image_mean examples/mnist/mnist_train_lmdb
examples/mnist/mean.binarypro
主要就是两个参数:
(2)Python计算均值文件
如果我们要进行特征可视化等操作,可能就会用到npy形式的文件。整体思路为:先用lmdb格式的数据,计算出对应的二进制格式的均值,最后再转换成npy格式的均值。首先先将下述代码保存为convert_mean.py。
#!/usr/bin/env python
import numpy as np
import sys,caffe
if len(sys.argv)!=3:
print "Usage: python convert_mean.py mean.binaryproto mean.npy"
sys.exit()
blob = caffe.proto.caffe_pb2.BlobProto()
bin_mean = open( sys.argv[1] , 'rb' ).read()
blob.ParseFromString(bin_mean)
arr = np.array( caffe.io.blobproto_to_array(blob) )
npy_mean = arr[0]
np.save( sys.argv[2] , npy_mean )
在得到convert_mean.py文件后,在命令行输入如下所示的指令即可生成对应的npy格式的均值文件了。
sudo python convert_mean.py mean.binaryproto mean.npy
得到lmdb或者均值文件之后,就可以构建如下所示的train_test.prototxt文件了。该文件需要更改的就是lmdb文件,若要添加均值文件,就把下述的mean_file:中的128改成对应的均值文件。还需要修改的就是最后输出的类别个数,分几类就可写几类。该prototxt文件其实就是网络的整体结构,根据下面的prototxt文件就可以得到对应的网络(比如lenet,vgg,mobilenet等等),我们用不同的网络结构就会有不同的train_test.prototxt。下述的网络为lenet的网络结构。
name: "LeNet"
layer {
name: "Input"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
scale: 0.00390625
mean_file:128
}
data_param {
source: "/home/YL/DataSet/train_lmdb"
batch_size: 64
backend: LMDB
}
}
layer {
name: "Input"
type: "Data"
top: "data"
top: "label"
include {
phase: TEST
}
transform_param {
scale: 0.00390625
mean_file:128
}
data_param {
source: "/home/YL/DataSet/test_lmdb"
batch_size: 100
backend: LMDB
}
}
layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
convolution_param {
num_output: 20
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
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: "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: 4
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "accuracy"
type: "Accuracy"
bottom: "ip2"
bottom: "label"
top: "accuracy"
include {
phase: TEST
}
}
layer {
name: "loss"
type: "SoftmaxWithLoss"
bottom: "ip2"
bottom: "label"
top: "loss"
}
就想上面说到的,我们可以利用train_test.prototxt文件得到对应的网络结构。具体操作为我们可以打开链接:http://ethereon.github.io/netscope/#/editor
https://dgschwend.github.io/netscope/#/editor
进入下述链接后,会展示出如下所示的界面:
得到该界面后,将上述的train_test.prototxt复制到界面左边黑色的部分。将鼠标的光标定位在黑色部分,并同时按下Enter和Shift就会显示出网络结构图了,如下图所示。
构建完train_test.prototxt,也就是网络输入和结构之后,就需要构建solver.prototxt文件。solver算是caffe的核心的核心,它协调着整个模型的运作。该文件主要包含的是一些深度网络训练的超参数。比如学习率,学习率下降规则,优化器,多少步训练后展示一次,多少步训练后进行一次测试。下面将详细解释各个参数的作用。
#train_test.prototxt的路径
net: "/home/YL/DataSet/train_test.prototxt"
#测试间隔和每batch图片数
test_iter: 100
test_interval: 500
# 基础学习率和学习率策略
base_lr: 0.01
lr_policy: "inv"
gamma: 0.0001
power: 0.75
base_lr: 0.01
momentum: 0.9
weight_decay: 0.0005
# 下面是multistep的示例
#lr_policy: "multistep"
#gamma: 0.9
#stepvalue: 5000
#stepvalue: 7000
#stepvalue: 8000
#stepvalue: 9000
#stepvalue: 9500
#优化器选择
type:"SGD"
# momentum and the weight decay of the network.
momentum: 0.9
weight_decay: 0.0005
# Display every 100 iterations
display: 100
# The maximum number of iterations
max_iter: 10000
# snapshot intermediate results
snapshot: 5000
snapshot_prefix: "/home/YL/DataSet"
# solver mode: CPU or GPU
solver_mode: GPU
(1)test_iter和test_interval
(2)base_lr和lr_policy
[外链图片转存失败(img-nhLPEvaC-1562394236232)(https://upload-images.jianshu.io/upload_images/5529997-fbea01f9edd3ea62.png?imageMogr2/auto-orient/strip|imageView2/2/w/500)]
(3)type
优化器的选择。因为默认值就是SGD,所以可以不写,但选择其他优化器时就要写了。到目前的版本,caffe提供了六种优化算法来求解最优参数,在solver配置文件中,通过设置type类型来选择。
(4)其他参数
构建完train_test.prototxt和solver.prototxt两个文件后,基本网络和解决策略就搭建完了。就可以利用如下代码进行训练了。
#!/usr/bin/env sh
./build/tools/caffe train --solver=examples/mnist/lenet_solver.prototxt
caffe的c++主程序(caffe.cpp)放在根目录下的tools文件夹内, 当然还有一些其它的功能文件,如:convert_imageset.cpp, train_net.cpp, test_net.cpp等也放在这个文件夹内。经过编译后,这些文件都被编译成了可执行文件,放在了 ./build/tools/ 文件夹内。因此我们要执行caffe程序,都需要加 ./build/tools/ 前缀。
caffe程序的命令行执行格式如下:
caffe
其中的有这样四种:
其中的参数有:
./build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt
./build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt -gpu 2
./build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt
-snapshot examples/mnist/lenet_iter_5000.solverstate
./build/tools/caffe train -solver examples/finetuning_on_flickr_style/solver.prototxt
-weights models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel
发现一篇写caffe写的很好的博客,强烈推荐!:地址