【EfficientDet入门系列】文章更新计划:
Part-1 EfficientDet简介
Part-2 项目实战(训练Pascal VOC 2012)
Part-3 项目实战(训练口罩检测)
Part-4 论文精读
Part-5 源码解读
本篇文章介绍使用VOC数据集从头开始训练EfficientDet,主要包括:
目录
欢迎关注本公众号“CV实战”,回复“实战voc”,获取EfficientDet官方源码、数据集、训练模型、COCO预训练模型、命令行参数示例的下载链接。
1. 搭建环境
官方推荐环境:
- absl-py>=0.7.1
- matplotlib >= 3.0.3
- numpy >= 1.16.4
- Pillow >= 6.0.0
- PyYAML >= 5.1
- six >= 1.12.0
- tensorflow >= 2.1.0 或tensorflow-gpu >= 2.1.0
- tensorflow-addons >= 0.9.1
- tensorflow-probability >= 0.9.0
- tensorflow_model_optimization
以上python依赖包均可采用pip install xxxx==version 的方式安装
另外需安装COCO API安装方法见【COCO API安装(Windows和Linux环境)】
2. 准备数据
Pascal VOC 数据集下载地址:
http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCtrainval_11-May-2012.tar
如上述地址无法下载,可关注本公众号“CV实战”,回复“voc数据集”,即可下载VOC数据集。
解压后VOC数据集目录结构
3. 生成tfrecord文件
假设EfficientDet源码根目录为EfficientDet,打开EfficientDet/dataset/目录下的
create_pascal_tfrecord.py
配置命令参数:
- data_dir:VOC数据集路径(到VOCdevkit这一级目录)
- set:数据集,可选参数train, trainval, val, test
- year:VOC2012
- output_path:tfrecord存储路径
- num_shards:tfrecord文件的数量(数据量小于10k时可设置为1)
命令参数示例:
生成训练tfrecord
--data_dir=D:/VOCtrainval_11-May-2012/VOCdevkit
--set=train
--year=VOC2012
--output_path=D:/VOCtrainval_11-May-2012/VOCdevkit/VOC2012/voc_2012_train
--num_shards=1
生成验证tfrecord
--data_dir=D:/VOCtrainval_11-May-2012/VOCdevkit
--set=val
--year=VOC2012
--output_path=D:/VOCtrainval_11-May-2012/VOCdevkit/VOC2012/voc_2012_val
--num_shards=1
注意:示例中的output_path设置到了VOC2012这一级目录,即存储到VOC2012文件夹下;
voc_2012_train和voc_2012_val是tfrecord的前缀名字,上述命令生成结果如下
运行方式:
- 方式-1:直接修改create_pascal_tfrecord.py中的代码,将命令行参数默认值设置为自己的参数,如下图
- 方式-2:命令窗方式(Linux环境)运行代码
运行命令:
python create_pascal_tfrecord.py --data_dir=D:/VOCtrainval_11-May-2012/VOCdevkit \
--set=train \
--year=VOC2012 \
--output_path=D:/VOCtrainval_11-May-2012/VOCdevkit/VOC2012/voc_2012_train \
--num_shards=1
注意每行命令参数后都有“空格+\”,这样可以换行输入,命令输入完毕后回车执行即可
- 方式-3:使用Pycharm,可以编辑 Run Configuration,直接将上述命令参数输入至Parameters中,点【OK】按钮,再运行即可
4. 训练和评估
(1)编辑超参数yaml文件
在EfficientDet源码根目录下新建configs文件夹,创建yaml文件voc_2012_config.yaml
目录结构:
EfficientDet/configs/voc_2012_config.yaml
yaml文件内容
num_classes: 20
var_freeze_expr: '(efficientnet|fpn_cells|resample_p6)'
label_map: {1: aeroplane, 2: bicycle, 3: bird, 4: boat, 5: bottle, 6: bus, 7: car, 8: cat,
9: chair, 10: cow,11: diningtable, 12: dog, 13: horse, 14: motorbike,
15: person, 16: pottedplant, 17: sheep, 18: sofa,19: train, 20: tvmonitor}
说明:
- num_classes:VOC2012数据集中类别数是20类,GitHub EfficientDet示例中设置的是21,这其实将背景background类考虑进去了,没有必要这么设置,直接设置为实际类别即可。具体原因有兴趣的小伙伴可以参看源码或者评论区留言,关注后续文章。
- var_freeze_expr:由于训练时采用COCO预训练模型,可以设置“冻结”efficientnet、fpn_cells、resample_p6的参数,这三部分不会得到更新;实测后发现,在使用COCO预训练模型训练VOC2012数据集时,设置“冻结”参数效果更好。如果应用到自己的数据集上时,根据迁移学习的任务差异性,建议不要设置“冻结”参数或少量“冻结”部分参数。
- label_map:类别的映射,从1开始,0已经被保留为background类
(2)运行训练代码
进入EfficientDet源码根目录下,运行main.py进行训练和评估
main.py主要命令参数解读:
- mode:可选参数train、val、train_and_eval;设置为train,则只进行训练(需提供training_file_pattern);设置为val,则只进行评估(需提供validation_file_pattern);设置为train_and_eval,则每个epoch训练结束后都会执行评估
- training_file_pattern:训练所用的tfrecord
- validation_file_pattern:评估所用的tfrecord
- model_name:网络名称,例如efficientdet-d0或efficientdet-d1等
- model_dir:训练得到的模型存储路径
- ckpt:COCO预训练模型路径
- train_batch_size:训练时的batch size
- eval_batch_size:评估时的batch size
- eval_samples:评估所用的样本数量,VOC2012验证集样本数量5823
- num_examples_per_epoch:每个epoch所用的样本数量,VOC2012训练集样本数量5717
- num_epochs:epoch总数
- hparams:超参数yaml文件
- run_epoch_in_child_process:是否采用子进程的方式运行训练或评估程序,默认是True;如果在Windows环境下运行代码,建议设置为False,否则会报错;Linux环境下可设置为True
运行示例:
--mode=train
--training_file_pattern=D:/VOCtrainval_11-May-2012/VOCdevkit/VOC2012/voc_2012_train*.tfrecord
--validation_file_pattern=D:/VOCtrainval_11-May-2012/VOCdevkit/VOC2012/voc_2012_val*.tfrecord
--model_name=efficientdet-d0
--model_dir=./tmp/efficientdet-d0-finetune
--ckpt=E:/pretrained_models/efficientdet/efficientdet-d0
--train_batch_size=64
--eval_batch_size=64
--eval_samples=5823
--num_examples_per_epoch=5717
--num_epochs=100
--hparams=./configs/voc_2012_config.yaml
--run_epoch_in_child_process=False
运行方式:参见【生成tfrecord文件】小节
训练后会得到一些ckpt文件
5. 测试
有两种测试方式:
- 直接使用ckpt方式,优点是命令参数配置简单,但速度很慢
- 先进行模型导出(ckpt转saved_model)再测试,这种方式推理速度快
强烈推荐第二种方式
进入EfficientDet源码根目录下,运行model_inspect.py进行模型导出和推理测试
(1)模型导出
model_inspect.py主要参数解读:
- runmode:运行的模式可选参数freeze、dry、saved_model等
- model_name:网络名称,例如efficientdet-d0或efficientdet-d1等
- ckpt_path:训练时存储的ckpt文件路径
- hparams:超参数yaml文件
- saved_model_dir:导出的模型存储路径
运行示例:
--runmode=saved_model
--model_name=efficientdet-d0
--ckpt_path=./tmp/efficientdet-d0-finetune
--hparams=./configs/voc_2012_config.yaml
--saved_model_dir=./tmp/saved_model/efficientdet-d0-finetune
运行结果:
(2)推理测试
model_inspect.py参数解读:
- runmode:运行的模式saved_model_infer(使用saved_model进行推理)
- model_name:网络名称,例如efficientdet-d0或efficientdet-d1等
- saved_model_dir:第一步导出的模型
- input_image:图像文件,可使用单个文件或利用通配符,例如*.jpg,表示所有的jpg文件
- output_image_dir:推理得到的结果
- hparams:超参数yaml文件
运行示例:
--runmode=saved_model_infer
--model_name=efficientdet-d0
--saved_model_dir=./tmp/saved_model/efficientdet-d0-finetune/efficientdet-d0_frozen.pb
--input_image=D:/dataset/test/course/efficientdet/voc/*.jpg
--output_image_dir=./tmp/infer
--hparams=./configs/voc_2012_config.yaml
效果展示:
网上找了一张图像做测试,检测效果如下图
附:
可能有些小伙伴对超参数yaml文件中的var_freeze_expr设置有所疑惑,下面给出“冻结”和“非冻结”两种方式的实验结果(VOC2012数据集):
var_freeze_expr | mAP(VOC2012 val) |
efficientnet fpn_cells resample_p6 | 0.7748 |
无 | 0.7135 |
除var_freeze_expr设置不同外,以上实验均采用相同的超参数和实验设置:
数据集:VOC2012 train和val
预训练模型:COCO efficientdet-d0
欢迎关注本公众号“CV实战”,回复“实战voc”,获取EfficientDet官方源码、数据集、训练模型、COCO预训练模型、命令行参数示例的下载链接。