标签(空格分隔): caffe Linux 深度学习
之前,我们已经完成了faster-rcnn的训练和测试工作,得到了person所在的区域。接下来我们将训练一个简单分类神经网络来对person进行简单地分类。
数据集准备
这里我们需要做类似于行人检测的工作,因此将INRIA Person Dataset中的某一部分行人样本图像进行训练。需要生成train.txt和val.txt,大家可以直接调用我的函数(注意,只是函数,不是完整的脚本哦),两者图像数量之比依旧是经典的1:1
def WriteText(trainfilename, valfilename, fileset, count):
rate = [0.5, 0.5]
trainset = []
valset = []
trainposset = set(random.sample(xrange(len(fileset)), int(len(fileset) * rate[0])))
valposset = set(xrange(len(fileset))) - trainposset
for pos in trainposset:
trainset.append(fileset[pos])
for pos in valposset:
valset.append(fileset[pos])
with open(trainfilename, 'a') as f:
for file in trainset:
writetext = file + " " + str(count)
writetext = writetext + "\n"
f.write(writetext)
with open(valfilename, 'a') as f:
for file in valset:
writetext = file + " " + str(count)
writetext = writetext + "\n"
f.write(writetext)
def ReadJpeg(srcdir, ext=".jpg"):
fileset = []
for file in os.listdir(srcdir):
absfilename = os.path.join(srcdir, file)
if os.path.isfile(absfilename) and os.path.splitext(absfilename)[1] == ext:
fileset.append(file)
return sorted(fileset)
def CreateTrainValTxt(imsetpath, fileset):
trainfilename = os.path.join(imsetpath, 'train.txt')
valfilename = os.path.join(imsetpath, 'val.txt')
if os.path.exists(trainfilename):
os.remove(trainfilename)
if os.path.exists(valfilename):
os.remove(valfilename)
clsset = []
count = -1
previousname = ''
for file in fileset:
personname = file[:-5]
if previousname == personname:
clsset.append(file)
else:
if 0 != len(clsset):
WriteText(trainfilename, valfilename, clsset, count)
clsset = []
clsset.append(file)
previousname = personname
count = count + 1
记住,为了后面训练的顺利进行,我们用脚本将图像规模统一调整为256*256,利用PIL的Image模块进行resize:
def ConvertImagesize(imsetpath, fileset):
for file in fileset:
print "Convert:" + file
filepath = os.path.join(imsetpath, file)
im = Image.open(filepath)
out = im.resize((256, 256), Image.ANTIALIAS)
out.save(filepath)
官方脚本的修改
这些脚本都是用来进行预处理的脚本,我们可以根据自身需求更改路径,或者重新写一个脚本即可。这些脚本都保存在examples/imagenet目录下。
1.create_imagenet.sh
该脚本主要利用build/tools目录下的convert_imageset工具生成lmdb,某些路径可以自己修改。这里我直接将其改写成了一个Python脚本函数:
def CreateImagenet(tooldir='build/tools', datadir='data/ilsvrc12/Persons', exampledir='examples/imagenet'):
imdbdir = exampledir + "/ilsvrc12_train_lmdb"
if os.path.exists(imdbdir):
shutil.rmtree(imdbdir)
cmd = tooldir + "/convert_imageset --shuffle " + datadir + "/ " + datadir + "/train.txt " + imdbdir
print cmd
os.system(cmd)
imdbdir = exampledir + "/ilsvrc12_val_lmdb"
if os.path.exists(imdbdir):
shutil.rmtree(imdbdir)
cmd = tooldir + "/convert_imageset --shuffle " + datadir + "/ " + datadir + "/val.txt " + imdbdir
print cmd
os.system(cmd)
2.make_imagenet.mean.sh
该脚本主要生成所有训练图像的平均值,利用到的是compute_image_mean工具,生成imagenet_mean.binaryproto。在这我也同样改成了一个Python脚本函数:
def MakeImagenetMean(tooldir='build/tools', datadir='data/ilsvrc12/Persons', exampledir='examples/imagenet'):
cmd = tooldir + "/compute_image_mean " + exampledir + "/ilsvrc12_train_lmdb " + datadir + "/imagenet_mean.binaryproto"
print cmd
os.system(cmd)
网络结构的修改
网络结构文件存放在models下,这里我使用的是bvlc_reference_caffenet,修改其train_val.prototxt文件:
layer {
name: "fc8"
type: "InnerProduct"
bottom: "fc7"
top: "fc8"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
inner_product_param {
num_output: 1000 #修改为需要输出的类别数
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
执行训练脚本
训练脚本路径为examples/imagenet/train_caffenet.sh目录下,这里为了方便同样的将shell脚本改写成Python脚本,为了方便起见,finetuning脚本也写在一起。
def TrainCaffeNet(mode=1):
tooldir = 'build/tools'
abspath = os.getcwd()
imsetpath = os.path.join(abspath, 'data/ilsvrc12/Persons')
fileset = ReadJpeg(imsetpath)
CreateTrainValTxt(imsetpath, fileset)
ConvertImagesize(imsetpath, fileset)
CreateImagenet()
MakeImagenetMean()
ChangePrototxt()
if 1==mode:
cmd = tooldir + "/caffe train --solver=models/bvlc_reference_caffenet/solver.prototxt"
else:
cmd = tooldir + "/caffe train --solver=examples/finetune_pascal_detection/pascal_finetune_trainval_test.prototxt"\
+" --weights models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel"
print cmd
os.system(cmd)
finetuning网络
按照官方教程介绍,finetuning的工作在网络上的修改只是最后一层,以AlexNet为例则是fc8,目录examples/finetune_pascal_detection下有以下用到的文件。
1.修改pascal_finetune_trainval_test.prototxt网络全连接层fc8
layer {
name: "fc8-finetune" # 要将本层改名,这样网络才会随机初始化权值
type: "InnerProduct"
bottom: "fc7"
top: "fc8-finetune" #改名
param {
lr_mult: 10 # 本层学习速率为以前的10倍
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
inner_product_param {
num_output: 246 # 类别数,按需修改
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layer {
name: "accuracy"
type: "Accuracy"
bottom: "fc8-finetune" # 本层学习速率为以前的10倍
bottom: "label"
top: "accuracy"
include {
phase: TEST
}
}
layer {
name: "loss"
type: "SoftmaxWithLoss"
bottom: "fc8-finetune" # 本层学习速率为以前的10倍
bottom: "label"
top: "loss"
}
2.修改pascal_finetune_solver.prototxt学习速率
net: "models/bvlc_reference_caffenet/fintune-train_val.prototxt"
test_iter: 100 #减少测试迭代次数
test_interval: 1000
base_lr: 0.001 #学习速率减小
lr_policy: "step"
gamma: 0.1
stepsize: 20000 #学习步长增加
display: 20
max_iter: 100000 #减少最大迭代次数
momentum: 0.9
weight_decay: 0.0005
snapshot: 10000
snapshot_prefix: "models/bvlc_reference_caffenet/caffenet_train"
solver_mode: GPU
3.执行训练脚本(见上文)