make all -j16 && make test -j16 && make runtest -j16 && make pycaffe -j16
系统:ubuntu 16.04
环境:caffe已编译安装
数据:图片已备好
先把图片分成两个文件夹,train和val(训练集与验证集),然后对他们生成文件名列表。分享一个python代码如下:
import os,sys
import argparse
def create_image_list(file_path,txtpath,cls):
if os.path.isfile(txtpath):
os.remove(txtpath)
image_name_list = os.listdir(file_path)
with open(txtpath,'a') as f:
print('saving to'+txtpath+'...')
for image_name in image_name_list:
image_data = image_name+' '+str(cls)
f.write(image_data+'\n')
print('done')
if __name__=='__main__':
ap = argparse.ArgumentParser()
ap.add_argument("-c","--cls",required=True,help="input class")
ap.add_argument("-d","--data",required=True,help="input pic dir")
args = vars(ap.parse_args())
create_image_list(os.path.dirname(os.path.realpath(__file__))+'/'+args['data'],'list'+'_'+args["cls"]+'.txt',args["cls"])
使用方法:
python create_image_list.py -c className -d input_image_dirName
# 例: python create_image_list.py -c 0 -d blue
caffe在/examples/imagenet/中提供了create_imagenet.sh作为生成LMDB的例子,我们可以对其进行更改来适用我们的训练。
EXAMPLE=examples/head/train # 稍后使用
DATA=examples/head # 图片目录
TOOLS=build/tools # 工具目录固定不变
TRAIN_DATA_ROOT=examples/head/train/train_image/ # 训练集目录
VAL_DATA_ROOT=examples/head/val/val_image/ # 测试集目录
# RESIZE 部分
如果图片大小不统一可以把RESIZE改成true。
# Create train lmdb...
创建lmdb文件
根据自己开头设置的定义进行微调
后三个含义:
训练数据根目录 \
图片list.txt文件目录 \
要保存的lmdb文件目录
# val lmdb 同理
命令行使用该.sh,很快即完成。
可能出现没有权限写入错误,需要提高文件夹权限
sudo chmod 777 -R ./PATH
看一下lmdb大小,我的是两千张图片的训练集,train的data.mdb大小约400M,一般应该只增不少。
Lmdb是一张图片一个标签,但是如果是人脸识别这样的,一张图片要输入4个,那么则需要使用h5py格式数据。
caffe使用h5py数据格式的话,需要自己在外部,进行数据扩充,数据归一化等相关的数据预处理操作,caffe比较麻烦。
暂不做深究,可参考博客:深度学习(十三)caffe之训练数据格式(http://www.voidcn.com/blog/garfielder007/article/p-5005545.html)
还有LEVELDB格式,根据自己需要。
caffe仍然为我们准备了例子,examples/imagenet/make_imagenet_mean.sh可以生成均值文件,我们只需要根据自己情况进行更改。
# 命令只有一句,调用compute_image_mean
该可执行文件在编译过程已经生成 命令解析如下
compute_image_mean路径(不用变) train_lmdb路径(看上一步生成在哪里) image_mean.binaryproto存放路径(根据自己需要)
caffe同样为我们提供例子,/examples/imagenet/train_caffenet.sh。
./build/tools/caffe train -solver models/bvlc_googlenet/solver.prototxt \
-weights models/bvlc_googlenet/bvlc_googlenet.caffemodel -gpu 1
-solver:solver地址(根据自己用的模型选择)
-weights:预训练模型(如果使用finetuning,下载好模型,即可添加本参数)
-gpu:如果有多块GPU可进行选择
solver提供超参数设置。
net:train_val.prototxt目录
...
base_lr:学习率
...
max_iter:迭代次数
snapshot:每多少次保存一次模型文件
snapshot_prefix:模型文件保存目录
solver_mode:GPU/CPU
这个文件是训练过程的重点,表述了网络的架构和设置,如果训练过程出错极有可能是该文件设置有问题。
更改内容如下:
13行:mean_value3行注释掉,换成mean_file
mean_file="examples/head/train/imagenet_mean.binaryproto"
18行:source:train_lmdb目录
35行:mean_file同上
39行:source:val_lmdb目录
...
919行:loss1/classifier层中,num_output:1000->4(自己的类别数)
957行:top_k:4(不能大于你的类别数)
...
1682行:loss2/classifier层中,num_output:1000->4(自己的类别数)
1720行:top_k:4(不能大于你的类别数)
...
2396行:loss3/classifier层中,num_output:1000->4(自己的类别数)
2433行:top_k:4(不能大于你的类别数)
此时开始执行训练命令,会出现shape mismatch错误:
Cannot copy param 0 weights from layer 'loss1/classifier';shape mismatch.Source param shape is 1 1 1000 1024;targe param shape is 4 1024....
这是因为原本的模型是设置的1000类,而我们为了实现自己的分类改成了4类,所以需要把loss层重命名。这是因为类别数不同,所以最后不再从预训练模型中读取参数,而是采用自己初始化的参数,故而采用重命名的方法。
再googleNet模型中,需要改三个名字,共计15个地方,在train_val.prototxt中搜索classifier,出现15次,即我们需要改的地方。改成你想要的名字,不过要保持统一。
现在可以执行命令,开始训练。
训练命令:
./build/tools/caffe train -solver examples/head4_start_end/models/bvlc_googlenet/solver.prototxt -weights examples/head4_start_end/models/bvlc_googlenet/bvlc_googlenet.caffemodel -gpu 1
caffe编译后产生可执行文件,执行train命令,-solver指示solver文件路径,-weights指示预训练模型路径,-gpu选择gpu。生成的模型保存路径在solver中设置
prototxt文件各参数含义:https://blog.csdn.net/sun7_she/article/details/52034691