# yolov5模型剪枝
**`2022-1-4`**: 已更新v5.0版本m/l/x模型剪枝,理论上yolov5l6等模型也支持.
**`2022-1-1`**: 已更新v6.0版本剪枝:https://github.com/midasklr/yolov5prune/tree/v6.0
**`2021-12-14`**:近期会更新v6.0版本剪枝和蒸馏.
基于yolov5最新v5.0进行剪枝,采用yolov5s模型,目前仅支持s模型。
相关原理:
Learning Efficient Convolutional Networks Through Network Slimming(https://arxiv.org/abs/1708.06519)
Pruning Filters for Efficient ConvNets(https://arxiv.org/abs/1608.08710)
相关原理见https://blog.csdn.net/IEEE_FELLOW/article/details/117236025
这里实验了三种剪枝方式
## 剪枝方法1
基于BN层系数gamma剪枝。
在一个卷积-BN-激活模块中,BN层可以实现通道的缩放。如下:
<p align="center">
<img src="img/Screenshot from 2021-05-25 00-26-23.png">
</p>
BN层的具体操作有两部分:
<p align="center">
<img src="img/Screenshot from 2021-05-25 00-28-15.png">
</p>
在归一化后会进行线性变换,那么当系数gamma很小时候,对应的激活(Zout)会相应很小。这些响应很小的输出可以裁剪掉,这样就实现了bn层的通道剪枝。
通过在loss函数中添加gamma的L1正则约束,可以实现gamma的稀疏化。
<p align="center">
<img src="img/Screenshot from 2021-05-25 00-28-52.png">
</p>
上面损失函数L右边第一项是原始的损失函数,第二项是约束,其中g(s) = |s|,λ是正则系数,根据数据集调整
实际训练的时候,就是在优化L最小,依据梯度下降算法:
𝐿′=∑𝑙′+𝜆∑𝑔′(𝛾)=∑𝑙′+𝜆∑|𝛾|′=∑𝑙′+𝜆∑𝛾∗𝑠𝑖𝑔𝑛(𝛾)
所以只需要在BP传播时候,在BN层权重乘以权重的符号函数输出和系数即可,对应添加如下代码:
```python
# Backward
loss.backward()
# scaler.scale(loss).backward()
# # ============================= sparsity training ========================== #
srtmp = opt.sr*(1 - 0.9*epoch/epochs)
if opt.st:
ignore_bn_list = []
for k, m in model.named_modules():
if isinstance(m, Bottleneck):
if m.add:
ignore_bn_list.append(k.rsplit(".", 2)[0] + ".cv1.bn")
ignore_bn_list.append(k + '.cv1.bn')
ignore_bn_list.append(k + '.cv2.bn')
if isinstance(m, nn.BatchNorm2d) and (k not in ignore_bn_list):
m.weight.grad.data.add_(srtmp * torch.sign(m.weight.data)) # L1
m.bias.grad.data.add_(opt.sr*10 * torch.sign(m.bias.data)) # L1
# # ============================= sparsity training ========================== #
optimizer.step()
# scaler.step(optimizer) # optimizer.step
# scaler.update()
optimizer.zero_grad()
```
这里并未对所有BN层gamma进行约束,详情见yolov5s每个模块 https://blog.csdn.net/IEEE_FELLOW/article/details/117536808
分析,这里对C3结构中的Bottleneck结构中有shortcut的层不进行剪枝,主要是为了保持tensor维度可以加:
<p align="center">
<img src="img/Screenshot from 2021-05-27 22-20-33.png">
</p>
实际上,在yolov5中,只有backbone中的Bottleneck是有shortcut的,Head中全部没有shortcut.
如果不加L1正则约束,训练结束后的BN层gamma分布近似正太分布:
<p align="center">
<img src="img/Screenshot from 2021-05-23 20-19-08.png">
</p>
是无法进行剪枝的。
稀疏训练后的分布:
<p align="center">
<img src="img/Screenshot from 2021-05-23 20-19-30.png">
</p>
可以看到,随着训练epoch进行,越来越多的gamma逼近0.
训练完成后可以进行剪枝,一个基本的原则是阈值不能大于任何通道bn的最大gamma。然后根据设定的裁剪比例剪枝。
剪掉一个BN层,需要将对应上一层的卷积核裁剪掉,同时将下一层卷积核对应的通道减掉。
这里在某个数据集上实验。
首先使用train.py进行正常训练:
```
python train.py --weights yolov5s.pt --adam --epochs 100
```
然后稀疏训练:
```
python train_sparsity.py --st --sr 0.0001 --weights yolov5s.pt --adam --epochs 100
```
sr的选择需要根据数据集调整,可以通过观察tensorboard的map,gamma变化直方图等选择。
在run/train/exp*/目录下:
```
tensorboard --logdir .
```
然后点击出现的链接观察训练中的各项指标.
训练完成后进行剪枝:
```
python prune.py --weights runs/train/exp1/weights/last.pt --percent 0.5 --cfg models/yolov5s.yaml
```
裁剪比例percent根据效果调整,可以从小到大试。注意cfg的模型文件需要和weights对应上,否则会出现[运行prune 过程中出现键值不对应的问题](https://github.com/midasklr/yolov5prune/issues/65),裁剪完成会保存对应的模型pruned_model.pt。
微调:
```
python finetune_pruned.py --weights pruned_model.pt --adam --epochs 100
```
在VOC2007数据集上实验,训练集为VOC07 trainval, 测试集为VOC07 test.作为对比,这里列举了faster rcnn和SSD512在相同数据集上的实验结果, yolov5输入大小为512.为了节省时间,这里使用AdamW训练100 epoch.
| model | optim&epoch | sparity | mAP@.5 | mode size | forward time |
| ----------------- | ----------- | ------- | ----------- | --------- | ------------ |
| faster rcnn | | - | 69.9(paper) | | |
| SSD512 | | - | 71.6(paper) | | |
| yolov5s | sgd 300 | 0 | 67.4 | | |
| yolov5s | adamw 100 | 0 | 66.3 | | |
| yolov5s | adamw 100 | 0.0001 | 69.2 | | |
| yolov5s | sgd 300 | 0.001 | Inf. error | | |
| yolov5s | adamw 100 | 0.001 | 65.7 | 28.7 | 7.32 ms |
| 55% prune yolov5s | | | 64.1 | 8.6 | 7.30 ms |
| fine-tune above | | | 67.3 | | 7.21 ms |
| yolov5l | adamw 100 | 0 | 70.1 | | |
| yolov5l | adamw 100 | 0.001 | 0.659 | | 12.95 ms |
在自己数据集上的实验结果:
| model | sparity | map | mode size |
| --------------------- | ------- | ----- | --------- |
| yolov5s | 0 | 0.322 | 28.7 M |
| sparity train yolov5s | 0.001 | 0.325 | 28.7 M |
| 65% pruned yolov5s | 0.001 | 0.318 | 6.8 M |
| fine-tune | 0 | 0.325 | 6.8 M |
## 剪枝方法2
对于Bottleneck结构:
<p align="center">
<img src="img/Screenshot from 2021-06-05 00-06-27.png">
</p>
如果有右边的参差很小,那么就只剩下左边shortcut连接,相当于整个模块都裁剪掉。可以进行约束让参差逼近0.见train_sparsity2.py。
backbone一共有3个bottleneck,裁剪全部bottleneck:
| model | sparity | map | model size |
| --------------------------- | ------- | ----- | ---------- |
| yolov5s-prune all bottlenet | 0.001 | 0.167 | 28.7 M |
| 85%+Bottlenet | | 0.151 | 1.1 M |
| finetune | | 0.148 | |
| 裁剪Bottleneck数 | map |
| ----------------- | ----- |
| 所有bottle res | 0.167 |
| 第2,3的bottle res | 0.174 |
| 第3的bottle res | 0.198 |
可以看到实际效果并不好,从bn层分布也可以看到,浅层特征很少被裁减掉。
## 剪枝方法3
卷积核剪枝,那些权重很小的卷积核对应输出也较小,那么对kernel进行约束,是可以对卷积核进行裁剪的。
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
无_说明_yolov5prune_No_Description_yolov5prune.zip (115个子文件)
Dockerfile 2KB
Dockerfile 821B
.dockerignore 4KB
.gitignore 4KB
tutorial.ipynb 384KB
bus.jpg 476KB
zidane.jpg 165KB
README.md 11KB
READMEYolov.md 11KB
README.md 1KB
yolov5prune.md 361B
yolov5s-opt.param 13KB
Screenshot from 2021-05-25 00-26-23.png 285KB
Screenshot from 2021-05-23 20-19-08.png 243KB
Screenshot from 2021-05-31 22-29-12.png 220KB
Screenshot from 2021-05-25 00-26-45.png 138KB
Screenshot from 2021-05-23 20-19-30.png 121KB
Selection_007.png 97KB
Screenshot from 2021-05-31 22-30-21.png 91KB
Screenshot from 2021-05-27 22-20-33.png 61KB
Screenshot from 2021-05-24 22-17-16.png 55KB
Screenshot from 2021-05-25 00-28-52.png 49KB
Screenshot from 2021-05-25 00-28-15.png 38KB
Screenshot from 2021-06-05 00-06-27.png 34KB
Screenshot from 2021-05-28 08-33-25.png 18KB
prune_convbn.py 44KB
datasets.py 44KB
prune_conv.py 41KB
prune.py 40KB
prune2.py 40KB
reprune.py 39KB
yolo.py 39KB
train_sparsity4.py 37KB
train_sparsity2.py 37KB
train_prune_sparsity.py 36KB
train_sparsity.py 36KB
train_sparsity3.py 36KB
train.py 33KB
finetune_prune_conv.py 32KB
finetune_pruned2.py 32KB
finetune_pruned.py 32KB
general.py 28KB
plots.py 18KB
testprune.py 17KB
test.py 17KB
common.py 16KB
wandb_utils.py 16KB
torch_utils.py 12KB
modelparse.py 10KB
detect.py 9KB
detect_prune.py 9KB
loss.py 9KB
metrics.py 9KB
autoanchor.py 7KB
export.py 6KB
experimental.py 5KB
hubconf.py 5KB
google_utils.py 5KB
showbn.py 4KB
activations.py 4KB
pruned_common.py 2KB
prune_utils.py 2KB
resume.py 1KB
restapi.py 1KB
log_dataset.py 800B
example_request.py 299B
getweight.py 164B
__init__.py 0B
__init__.py 0B
__init__.py 0B
__init__.py 0B
get_voc.sh 4KB
get_argoverse_hd.sh 2KB
userdata.sh 1KB
get_coco.sh 962B
mime.sh 780B
get_coco128.sh 618B
download_weights.sh 277B
allbn.txt 16KB
model_change.txt 10KB
modul.txt 9KB
map.txt 7KB
requirements.txt 599B
additional_requirements.txt 105B
objects365.yaml 7KB
anchors.yaml 3KB
VisDrone.yaml 3KB
yolov5-p7.yaml 2KB
GlobalWheat2020.yaml 2KB
yolov5x6.yaml 2KB
yolov5s6.yaml 2KB
yolov5m6.yaml 2KB
yolov5l6.yaml 2KB
yolov5-p6.yaml 2KB
yolov5-p2.yaml 2KB
coco.yaml 2KB
hyp.scratch.yaml 2KB
coco128.yaml 2KB
yolov3-spp.yaml 1KB
yolov3.yaml 1KB
共 115 条
- 1
- 2
资源评论
好家伙VCC
- 粉丝: 1985
- 资源: 9142
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功