使用caffe复现AlexNet
1.caffe安装
-
caffe 坑最多的就是编译安装了,每台机的情况不一样,只能是遇到什么问题去查对应的方法了
-
前置需求包
-
cuda, cudnn, opencv, etc... 这几个应该是最麻烦的了
-
makefilelist, makefile.configure 选择需要的
-
编译 pycaffe
2.数据准备
-
ILSVRC2012
-
因为是做分类,所以要利用xml文件切割出目标对象(图片)
-
最终会有 500k+ 个训练图片(没有使用ILSVRC2012额外训练集), 50k个校验图片
-
-
label文件,方便以后测试时得到index后找到对应的label
-
train 文件, 包含图片在磁盘的位置以及label(int 整形的label)
-
val 文件,类似 train 文件
-
(可选)利用$CAFFE_ROOT/build/tools/convert_imageset 建立lmdb文件
-
根据论文所述 要把图片resize 成 256 × 256
-
可以使用python代码生成lmdb文件用python读写lmdb数据库 既然是决定用python接口 那就多用python实现比较好。用图片生成lmdb的那段代码,需要修改label的生成方式。另外它做了直方图均衡化,我不太明白有什么用,如果测试数据没有做均衡化的话准确率会很低,loss会很高,所以删掉了那一段
-
因为可以直接使用图片作为输入,所以这一步可选
-
区别:lmdb的io更快,batch_size(下面解释)可以设得更大
-
-
-
(可选)使用$CAFFE_ROOT/build/tools/compute_image_mean 得到mean.binaryproto均值文件
-
要使用这一步的话就必须生成lmdb文件了
-
2.1 prototxt编写
-
train_val.prototxt
-
使用$CAFFE_ROOT/models/bvlc_alexnet/train_val.prototxt 即可(最好得备份一份)
-
修改 data 层 source 位置
-
修改 data 层 mean_file 位置
-
如果前一步没有生成mean.binaryproto文件的话 直接使用[104, 117, 123]作为均值
-
-
如果使用原始图片作为输入的话,在这一步resize图片,而batch_size大概只能设32或者16(2的指数倍有加速), 不然训练时会有大量的Waiting for data, 大部分时间都浪费在io上,如果数据存在固态硬盘的话会快一点。会快多少我也没试过,然而要从随机初始化训练ilsvrc的话是需要上百个epoch的,所以最好还是使用lmdb的格式训练减少io的时间浪费
-
(可选)可以把 Data 层中的TEST的部分删掉,TEST的作用是看校验集的loss变化能够帮助判断模型是否过拟合
-
关于 crop_size 当输入图片的size比crop_size大时会随机裁剪,注:这跟论文讲的crop的方法不一样,想要得到论文的效果就要改,具体要改底层,自己写一个层,修改crop的方式,重新编译caffe,也可以在训练图片之前就用论文所说的crop方法处理好。这里不推荐,因为这是针对ilsvrc数据集有用的trick,对于其他数据集不一定有用,而且最终能提高的准确率不多。
-
-
deploy.prototxt
-
直接使用$CAFFE_ROOT/models/bvlc_alexnet/deploy.prototxt 即可 这个不用改
-
-
solver.prototxt
-
大部分超参数是不用改的,都是AlexNet当时的训练参数
-
可以修改 test_iter 这个参数指(校验)测试时要跑多少个迭代,train_val.prototxt中,data TEST层中的batch_size 是50, 这2个默认值相乘等于50k,即校验集中所有图片的数量,但为了训练加速,可以把这个值设小10倍,这样就只校验了10%的数据
-
修改 test_interval 这个参数指每多少次迭代校验一次,默认值为1000, 是很频繁的,实际训练时,大部分时间都浪费在校验,特别是训练前期,校验根本没有意义,可以改成10000。如果有更智能调整这个参数的方法就好了,因为前期的校验没有意义,而后期需要更频繁的盯着校验集loss的变化防止过拟合,后面会提到一个trick可以达到这个效果
-
修改 snapshot_prefix 这个参数指模型的保存位置
-
stepsize 这个参数指每到 {stepsize} 次迭代后学习率 lr 会减小 这个值就不改了
-
snapshot 这个参数值每到 {snapshot} 次迭代后,保存一次模型和当前状态 这个参数也不改了
-
3.训练
-
注意随机打乱训练样本
-
可以在编写train文件的时候就打乱(推荐这种方法,这样用多种网络训练时可以保证它们的遍历顺序是一致,直接对比网络的效果,消除打乱的偶然性)
-
如果调用convert_imageset的话 加上shuffle参数就可以打乱
-
如果直接使用图片作为网络数据,在imagedataparam那里设置shuffle: true也可以打乱
-
-
断点训练,可以注意到每{snapshot}次迭代后会保存一份.solverstate文件,这个文件包含了当前状态还有模型参数,可以恢复到.solverstate的状态继续训练,不用从头再来,再也不怕断电死机了!
-
链接中还有关于.solverstate和.caffemodel文件关系的讨论
-
可以利用这个断点恢复功能,一开始先调较大的test_interval 等到迭代了100k次以后再把test_interval调小;对 display 的参数设置也是同理,一开始可以调小一点,确定模型在训练,训练速度是否合理(如果要好几个星期才能跑完,就去查查资料看看这个模型别人需要多长时间,如果差距较远肯定是设置有问题,或者你的机器就不适合跑这个,注:使用速度较快的GPU的话AlexNet的训练时间约为1天 Slide181 )
-
其他论文难以复现到论文所属准确率的原因大概也是研究者用了这个trick,他们观察train_loss, val_loss曲线有异样的时候立刻修改超参数,也即他们训练模型时超参数可能在每个阶段都不一样。
-
4.校验测试
-
在 $CAFFE_ROOT/models/bvlc_alexnet/readme.md 中给出了这个网络、solver的理想准确率,那么就只要测试自己的模型有没有达到这个准确率
-
我的结果如图
-
因为输出数据太长,前30k次迭代的log数据丢失; 断电中断,缺少了100k到120k次迭代的log数据,比较好的处理方法是把输出信息输出到一个文件中,如 python.py > train_log.txt
-
Iteration accuracy loss 35000 0.45704 2.42176 36000 0.46422 2.38812 37000 0.46158 2.41665 38000 -