在菠菜大佬的安利下,萌新的我开始研究模型剪枝,这个领域比较陌生,我会慢慢更新。这里感谢菠菜,松菇和漂大佬们对我的教导。
在这里为使用的是菠菜推荐的AlexeyAB版本的darknet训练框架,推荐理由是模型map训练精度高,emmm大佬说啥就是啥吧,以后我会测试下其它版本的效果。
git clone https://github.com/AlexeyAB/darknet
sudo apt-get install libopencv-dev
#安自己设备修改Makefile
mkdir build-release
cd build-release
cmake ..
make
make install
我使用的是coco2017数据集,通过提取其person类作为模型数据集
# 测试图片
./darknet detector test /home/xs/xs_train/data/coco/voc.data /home/xs/xs_train/data/coco/yolov3-spp-person.cfg backup/yolov3-spp-person_6000.weights /home/xs/xs_train/data/coco/JPEGImages/000000391895.jpg
# 训练模型
./darknet detector train /home/xs/xs_train/data/coco/voc.data /home/xs/xs_train/data/coco/yolov3-spp-person.cfg weights/darknet53.conv.74 -map
# 重训练模型
./darknet detector train /home/xs/xs_train/data/coco/voc.data /home/xs/xs_train/data/coco/yolov3-spp-person.cfg backup/yolov3-spp-person_10000.weights
# 测试模型
./darknet detector map /home/xs/xs_train/data/coco/voc.data /home/xs/xs_train/data/coco/yolov3-spp-person.cfg backup/yolov3-spp-person_10000.weights
我训练了30000轮,得到map 0.71的模型精度。
使用的是漂大佬的开源项目,yolov3-channel-and-layer-pruning
#测试原始模型
python3 test.py --cfg /home/xs/xs_train/data/coco/yolov3-spp-person.cfg --data /home/xs/xs_train/data/coco/voc.data --weights weights/yolov3-spp-person.weights
#初始训练稀疏模型
python3 train.py --cfg /home/xs/xs_train/data/coco/yolov3-spp-person.cfg --data /home/xs/xs_train/data/coco/voc.data --weights weights/yolov3-spp-person.weights --epochs 300 --batch-size 32 -sr --s 0.001 --prune 1
#重训练稀疏模型
python3 train.py --cfg /home/xs/xs_train/data/coco/yolov3-spp-person.cfg --data /home/xs/xs_train/data/coco/voc.data --weights weights/last.pt --epoch 70 --batch-size 16 -sr --s 0.001 --prune 1
#剪枝
python3 layer_channel_prune.py --cfg /home/xs/xs_train/data/coco/yolov3-spp-person.cfg --data /home/xs/xs_train/data/coco/voc.data --weights weights/last.pt --shortcuts 16 --global_percent 0.93 --layer_keep 0.01
#微调
python3 train.py --cfg /home/xs/xs_train/data/coco/yolov3-spp-person-prune.cfg --data /home/xs/xs_train/data/coco/voc.data --weights weights/prune_0.93_keep_0.01_16_shortcut_last.weights --epochs 70 --batch-size 32
首先进行模型稀疏化
我使用的都是默认值进行,这部分最为关键,整个效果好坏与其息息相关,当map在经历下降,回升,平稳后差不多就可以了。
第一次我使用的是默认的300轮,当我训练到43轮时,如下图所示loss与map趋于稳定,权重也相对归一化,我选择减小轮次以使用更小的学习率。
当我改为70批次训练,得到了较好的结果map: 64.2(原始65.9)。
其次是剪枝
我由于数据集和作者一样只有一个类,我选择了相同的剪枝策略,具体可以自由搭配
最后是微调
由于我数据集相较作者的非常大,warm up我调整为1,最后精度在62.4map
模型使用的推理工程是著名的ultralytics
模型在实际使用时从0.06一帧提高到0.02一帧,显卡占用率从1091M减少到743M。
通过u版的模型转换工具将模型转为weight格式,我在AB版继续训练10000轮
微调前精度54.64map,在AB版微调后达到69.1map,和原始相比下降2map。
这是剪枝后u版微调结果
这是原版结果
这是剪枝后AB版微调结果
总结:置信度下降严重,还在查找原因
#模型转为darknet权重
python3 -c "from models import *; convert('cfg/yolov3-spp-person-prune.cfg', 'weights/yolov3-spp-person-prune.pt')"
#darknet框架测试图片和模型
./darknet detector test ./cfg/person.data ./cfg/yolov3-spp-person-prune.cfg ./weights/yolov3-spp-person-prune.weights
./darknet detector map /home/xs/xs_train/data/coco/voc.data /home/xs/xs_train/data/coco/yolov3-spp-person-prune.cfg weights/yolov3-spp-person-prune.weights
#AB框架下模型再训练
./darknet detector train /home/xs/xs_train/data/coco/voc.data /home/xs/xs_train/data/coco/yolov3-spp-person-prune.cfg weights/yolov3-spp-person-prune.weights -map
#进一步调试,启用GIOU,修改anchors
./darknet detector calc_anchors /home/xs/xs_train/data/coco/voc.data -num_of_clusters 9 -width 608 -height 608
[yolo]
mask=6,7,8
anchors=12, 29, 33, 74, 55,152, 135,163, 84,298, 159,388, 418,181, 270,462, 487,505
classes=1
num=9
jitter=.3
ignore_thresh=.7
truth_thresh=1
random=1
iou_normalizer=0.25 #启用GIOU
cls_normalizer=1.0 #启用GIOU
iou_loss=giou #启用GIOU
./darknet detector train /home/xs/xs_train/data/coco/voc.data /home/xs/xs_train/data/coco/yolov3-spp-person-prune-giou.cfg weights/yolov3-spp-person-prune.weights -map
关于模型量化有两种方案,一个是使用平台自带的量化方法,如tensorrt,openvino,pytorch等等,它们大多是基于模型统一量化,优势在于简便,但是和平台绑定,可操作性少。另外一种量化方案是我YOLOv3-complete-pruning,他是通过修改层,根据不同层选择不同的量化方案,通过测试可以取舍达到满意效果。