接着上一篇,我们知道用caffe训练神经网络时,对于数据集的格式,它只支持lmdb或leveldb,因此我们用caffe训练神经网络的过程中第一步就是用原始的数据集来制作imdb或leveldb类型的数据,生成lmdb默认调用的是opencv的cv.imread()函数来读取图片的。
1、生成Imdb的脚本介绍
生成Imdb的这个过程一般由caffe的工具convert_imageset完成,该工具源码路径为caffe/tools/convert_imageset.cpp,在编译过后位于caffe/build/tools目录下,我们在创建过程中一般是写一个create_lmdb.sh,在脚本中调用convert_imageset来生成对应的imdb文件,这个脚本有一个模板,位于caffe/examples/imagenet/create_imagenet.sh,我们在这个模板脚本基础上进行进行更改即可。首先我们介绍convert_imageset这个工具的用法:
命令行的格式如下:
convert_imageset [FLAGS] ROOTFOLDER/ LISTFILE DB_NAME
其中DB_NAME后面还可以跟一些可选的参数设置,具体有哪些可选的参数参见“可选参数设置部分” 。ROOTFOLDER为图像集的根目录,LISTFILE 为一个文件的路径,该文件中记录了图像集中的各图样的路径和相应的标注 ,DB_NAME为要生成的数据库的名字。可选参数设置
gray:bool类型,默认为false,如果设置为true,则代表将图像当做灰度图像来处理,否则当做彩色图像来处理
shuffle:bool类型,默认为false,如果设置为true,则代表将图像集中的图像的顺序随机打乱
backend:string类型,可取的值的集合为{"lmdb", "leveldb"},默认为"lmdb",代表采用何种形式来存储转换后的数据
resize_width:int32的类型,默认值为0,如果为非0值,则代表图像的宽度将被resize成resize_width
resize_height:int32的类型,默认值为0,如果为非0值,则代表图像的高度将被resize成resize_height
check_size:bool类型,默认值为false,如果该值为true,则在处理数据的时候将检查每一条数据的大小是否相同
encoded:bool类型,默认值为false,如果为true,代表将存储编码后的图像,具体采用的编码方式由参数encode_type指定
encode_type:string类型,默认值为"",用于指定用何种编码方式存储编码后的图像,取值为编码方式的后缀(如'png','jpg',...)
而create_imagenet.sh模板脚本文件如下:
#!/usr/bin/env sh
# Create the imagenet lmdb inputs
# N.B. set the path to the imagenet train + val data dirs
set -e
EXAMPLE=examples/imagenet
DATA=data/ilsvrc12
TOOLS=build/tools
TRAIN_DATA_ROOT=/path/to/imagenet/train/ # 训练集所在路径
VAL_DATA_ROOT=/path/to/imagenet/val/ # 验证集所在路径
# 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..."
GLOG_logtostderr=1 $TOOLS/convert_imageset \
--resize_height=$RESIZE_HEIGHT \
--resize_width=$RESIZE_WIDTH \
--shuffle \
$TRAIN_DATA_ROOT \ # 训练集所在路径
$DATA/train.txt \ # 训练集的文件名列表文件
$EXAMPLE/ilsvrc12_train_lmdb # 生成的训练集Imdb文件路径
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/ilsvrc12_val_lmdb # 生成的验证集Imdb文件路径
echo "Done."
其中,TRAIN_DATA_ROOT和VAL_DATA_ROOT是训练集和验证集的原始图像目录,而train.txt和val.txt是训练和验证过程中用到的图像名的列表,txt文件中每行代表一张图像的图像名,下面我们详细介绍这两个文件。
2、train.txt和val.txt
(1)如果为图像分类任务:
此时仅需要两个Imdb文件,因此需要两个txt文件:train.txt和val.txt,图片列表清单txt文件格式如下: 图片文件名 标签
train.txt可以为:
train/T10034.jpg 1
train/096377_01M36.JPG 0
train/T580.jpg 1
train/T4151.jpg 1
train/100333_00F42.JPG 0
train/076902_04M36.JPG 0
val.txt可以为:
val/T10034.jpg 1
val/221169_02M52.JPG 0
val/T580.jpg 1
val/T4694.jpg 1
val/332136_01M17.JPG 0
val/181085_02M28.JPG 0
val/133417_02M37.JPG 0
当图片规模达到上千万级别,上述两个文件的生成需要程序实现 。此时的train.prototxt文件定义为(前面的数据层定义如下,其中图像做了减去均值和裁剪的预处理):
layer {
name: "data"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
mirror: true
crop_size: 224
mean_value: 104.0
mean_value: 117.0
mean_value: 123.0
}
data_param {
source: "xxxxx/train_lmdb"
batch_size: 8
backend: LMDB
}
}
layer {
name: "data"
type: "Data"
top: "data"
top: "label"
include {
phase: TEST
}
transform_param {
mirror: false
crop_size: 448
mean_value: 104.0
mean_value: 117.0
mean_value: 123.0
}
data_param {
source: "xxxxx/val_lmdb"
batch_size: 1
backend: LMDB
}
}
(2)如果为语义分割任务:
此时训练集和验证集均为图片,这时需要4个Imdb文件,因此需要4个txt文件:Img_train.txt、Label_train.txt、Img_val.txt、Label_val.txt,在转换语义分割数据集的label图片时,需要将convert_imageset工具中的的参数gray设为True。
Img_train.txt:
SegmentationImage/002120.png
SegmentationImage/002132.png
SegmentationImage/002142.png
SegmentationImage/002212.png
SegmentationImage/002234.png
SegmentationImage/002260.png
SegmentationImage/002266.png
Label_train.txt:
SegmentationClass/002120.png
SegmentationClass/002132.png
SegmentationClass/002142.png
SegmentationClass/002212.png
SegmentationClass/002234.png
SegmentationClass/002260.png
SegmentationClass/002266.png
Img_val.txt:
SegmentationImage/002268.png
SegmentationImage/002273.png
SegmentationImage/002281.png
SegmentationImage/002284.png
SegmentationImage/002293.png
Label_val.txt:
SegmentationClass/002268.png
SegmentationClass/002273.png
SegmentationClass/002281.png
SegmentationClass/002284.png
SegmentationClass/002293.png
此时的train.prototxt定义为(其中source为生成的Imdb文件路径,mean_file为图像三个通道均值文件路径):
layer {
name: "data"
type: "Data"
top:"data"
include {
phase: TRAIN
}
transform_param {
scale: 0.00390625
mean_file: "xxxxx/Img_train_mean.binaryproto"
}
data_param {
source: "xxxxx/Img_train_lmdb"
batch_size: 1
backend: LMDB
}
}
layer {
name: "label"
type: "Data"
top:"label"
include {
phase: TRAIN
}
transform_param {
scale: 0.00390625
mean_file: "xxxxx/Label_train_mean.binaryproto"
}
data_param {
source: "xxxxx/Label_train_lmdb"
batch_size: 1
backend: LMDB
}
}
layer {
name: "data"
type: "Data"
top: "data"
include {
phase: TEST
}
transform_param {
scale: 0.00390625
mean_file: "xxxxx/Img_val_mean.binaryproto"
}
data_param {
source: "xxxxx/Img_val_lmdb"
batch_size: 1
backend: LMDB
}
}
layer {
name: "label"
type: "Data"
top: "label"
include {
phase: TEST
}
transform_param {
scale: 0.00390625
mean_file: "xxxxx/Label_val_mean.binaryproto"
}
data_param {
source: "xxxxx/Label_val_lmdb"
batch_size: 1
backend: LMDB
}
}