准备数据
1.准备图片
将本次实验命名为mytest。将准备好的图片按如下格式保存,只要注意train和val下的文件夹名要对应即可。 在接下来所有的操作中,文件存储的格式、位置其实都不是固定的,只要在后续操作中输入正确的地址即可。
data---mytest---train---class1---1.jpg
| | |
| | |-2.jpg
| | |
| | |-...
| |
| |-class2---1.jpg
| | |
| | |-2.jpg
| | |
| | |-...
| |
| |-...
|
|--val----class1---1.jpg
| |
| |-2.jpg
| |
| |-...
|
|-class2---1.jpg
| |
| |-2.jpg
| |
| |-...
|
|-...
2.生成清单文件
在data/mytest下创建genClassTxt.sh脚本并在该目录下执行 :
#!/bin/sh
TRAIN_SET_PATH="train"
VAL_SET_PATH="val"
class=-1
rm train.txt
for dir in ${TRAIN_SET_PATH}/*
do
if test -d ${dir}
then
echo "Generate *.jpg in ${dir} ..."
class=`expr ${class} + 1`
for file in ${dir}/*.jpg
do
#if test -f $file
#then
echo "${file} ${class}">>train.txt
#fi
done
echo "Success."
fi
done
class=-1
rm val.txt
for dir in ${VAL_SET_PATH}/*
do
if test -d ${dir}
then
echo "Generate *.jpg in ${dir} ..."
class=`expr ${class} + 1`
for file in ${dir}/*.jpg
do
#if test -f $file
#then
echo "${file} ${class}">>val.txt
#fi
done
echo "Success."
fi
done
这段脚本仅仅是针对这种目录结构写的,会在data/mytest目录下生成train.txt和val.txt。只要生成两个文件,分别对应训练集和测试集,每个文件内容为图片地址和对应的类别(从0开始)。
3.转换图片格式
caffe可以读取的文件格式如lmdb、leveldb等。这里采用lmdb。在caffe根目录的tools文件夹下有这样一个文件:convert_imageset.cpp。编译后生成对应的可执行文件在 build/tools/ 下,可将图片文件转换成caffe框架能直接使用的db文件。
该文件的使用格式参考: Caffe学习系列(11):图像数据转换成db(leveldb/lmdb)文件
在example/mytest下创建create_lmdb.sh并在caffe根目录下执行:
#!/usr/bin/env sh
CAFFE_PATH=/home/shengzh-dev/caffe
MYTEST_PATH=data/mytest
echo "Create train lmdb.."
rm -rf ${MYTEST_PATH}/img_train_lmdb
build/tools/convert_imageset \
--shuffle \
--resize_height=32 \
--resize_width=32 \
${CAFFE_PATH}/${MYTEST_PATH}/ \
${MYTEST_PATH}/train.txt \
${MYTEST_PATH}/img_train_lmdb
echo "Create test lmdb.."
rm -rf ${MYTEST_PATH}/img_val_lmdb
build/tools/convert_imageset \
--shuffle \
--resize_width=32 \
--resize_height=32 \
${CAFFE_PATH}/${MYTEST_PATH}/ \
${MYTEST_PATH}/val.txt \
${MYTEST_PATH}/img_val_lmdb
echo "All Done.."
其中CAFFE_PATH是你的caffe根目录的绝对路径(sheng-dev是我的用户名),MYTEST_PATH是刚才放图片的目录(相对caffe根目录的相对路径),两个目录用来找到刚刚放图片和清单文件的地方,以及输出的路径(为了方便就直接输出到也输出到data/mytest里)。我把图片缩放到32×32,精度要求不高的话足够了。在data/mytest下得到两个lmdb文件夹。我再将其移动到examples/mytest下。
也可以去example里找一个生成lmdb/leveldb文件的脚本,复制一份并修改相关路径,然后执行。
所有操作最好是相对caffe根目录的路径,并在根目录执行。caffe所有操作都在根目录做不容易出错。
训练
1.计算均值
减去均值再训练能提高训练速度和精度。
caffe提供了一个计算均值的文件compute_image_mean.cpp,带两个参数。第一个参数是lmdb训练数据位置,第二个参数设定均值文件的名字及保存路径。
sudo build/tools/compute_image_mean examples/mytest/img_train_lmdb examples/mytest/mean.binaryproto
运行成功后,会在 examples/mytest/ 下面生成一个mean.binaryproto的均值文件。
2.创建模型并编写配置文件
一开始不懂什么网络结构就去examples里面找一个模型好了,比如caffenet模型,在models/bvlc_reference_caffenet/。图片量比较少的话,可以去cifar10找找,我用了caffe/examples/cifar10/cifar10_quick*。将solver.prototxt和train_val.prototxt复制到examples/mytest下,修改solver.prototxt中的路径、batch_size、test_iter和学习率,test batch_size*test_iter >= 测试集大小,train_val.prototxt修改路径。
solver:
net:网络文件
test_interval: 每几次迭代测试一次base_lr: 学习率
display: 每几次迭代显示一次max_iter: 最大迭代数
solver_mode: CPU还是GPU
net:
crop_size:裁剪图片的大小
batch_size是一次读入图片的大小,CPU读入内存,GPU读入显存
除了accurcy和loss 层的最后一个num_output为输出的类别数
2.训练
build/tools/caffe train -solver examples/mytest/solver.prototxt
一开始iter 0有个准确率是随机未经过训练随机猜的,会接近于 1/类别数 ,如果有异常(比如是0)则停止训练检查异常。
第一次迭代出来如果准确率特别低,如小于60%则停止训练检查异常。
如果learning rate(学习率lr)没怎么变化,可能是步长设置有问题。
用训练来分类
1.准备文件
(1)caffemodel文件,_iter_500.caffemodel重命名为mytest.caffemodel,放在examples/mytest下
(2)均值文件
(3)synset_words.txt文件。每一行一个类别名称,为从0开始顺序对应的名称。注意最后一行不要换行。
(4)deploy文件。这个文件由定义网络的文件修改而来,可找一个example看看两者的区别和关系,也可参考:将train_val.prototxt 转换成deploy.prototxt
a.删除输入数据,增加数据维度(dim)描述。一般第一个维度为1,第二个为1或3(图片通道数),第三第四个为图片大小。
b.移除最后的“loss” 和“accuracy” 层,加入“prob”层。
layers {
name: "prob"
type: "Softmax"
bottom: "fc8"
top: "prob"
}
2.cpp文件
examples/cpp-classification/classification.cpp
3.测试图片 examples/mytest/image.jpg
./build/examples/cpp_classification/classification.bin \
examples/mytest/deploy.prototxt \
examples/mytest/mytest.caffemodel \
examples/mytest/mean.binaryproto \
examples/mytest/synset_words.txt \
examples/mytest/image.jpg