最近解耦头训练后发现代码有问题 ,加上各种事情先搁置了, 因为有些朋友总是 提到SWIN-Transformer ,那么我决定先研读下,swin的代码,今天分享下昨晚上V5的新版V6.0的改动,同时说下我的个人理解。
(最近在研究人脸的东西,提供了一个即插即用的,当然很多地方需要补充,先放在GIT上了 可以直接使用要做业务的可以直接拿来主义,还有Deepstream的SDK详情关注------->face git repo)
Yolov5系列文章参考
如果是yolo5的粉丝,不难发现他们的SRS项目更新贼快(每周一更:主要是功能的完善和解决使用多种功能和框架扩展的程序BUG),作者一直和efficientDet对标,其实纵观这两年的几个比较大的改动就是多尺度模型,V5也好,现在大部分的SOTA检测都在做这NAS的事情,说明一个合适的网络结构是极其重要的!这也是我为什么从V5入手不断学习扩展的原因,因为YOLOV5的项目是与时俱进的,不废话了,来一览今天的Realsev6.0。
COCO AP val denotes [email protected]:0.95 metric measured on the 5000-image
COCO val2017 dataset over various inference sizes from 256 to 1536.
这里是作者提供的在V100的显卡上的32batch结果,复现操作:
Reproduce :
python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt
发布了支持CPU和移动端的强两级模型 nano版本 ,yolov5n(1.9M params):是针对640训练的P5(28.4
[email protected]:0.95) 、 yolov5n6 (7.5M params),基于1280分辨率的P6(34.0
mAP0.5:0.95),支持INT8的模型转换,opencv-dnn(支持ONNX 兼容) /tf(keras)等库的调用。
NANO模型的深度维持0.33,宽度从yolov5s的0.5缩小到了0.25,模型从7.5M缩到了1.9M
使用一个Conv(k=6, s=2, p=2) 替换掉backbone中的Focus层:
这个操作是来自一个git的网友的贡献,并且哥们提出了自己的观点且编码验证了,这里让我想到MLP和1X1卷积的故事。。。
import torch
from models.common import Focus, Conv
from utils.torch_utils import profile
focus = Focus(3, 64, k=3).eval()
conv = Conv(3, 64, k=6, s=2, p=2).eval()
# Express focus layer as conv layer
conv.bn = focus.conv.bn
conv.conv.weight.data[:, :, ::2, ::2] = focus.conv.conv.weight.data[:, :3]
conv.conv.weight.data[:, :, 1::2, ::2] = focus.conv.conv.weight.data[:, 3:6]
conv.conv.weight.data[:, :, ::2, 1::2] = focus.conv.conv.weight.data[:, 6:9]
conv.conv.weight.data[:, :, 1::2, 1::2] = focus.conv.conv.weight.data[:, 9:12]
# Compare
x = torch.randn(16, 3, 640, 640)
with torch.no_grad():
# Results are not perfectly identical, errors up to about 1e-7 occur (probably numerical)
assert torch.allclose(focus(x), conv(x), atol=1e-6)
# Profile
results = profile(input=torch.randn(16, 3, 640, 640), ops=[focus, conv, focus, conv], n=10, device=0)
为了充分理解,我们先来回顾以下Focus这个OP吧:
class Focus(nn.Module):
# Focus wh information into c-space
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
super().__init__()
self.conv = Conv(c1 * 4, c2, k, s, p, g, act)
def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2)
return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1))
从直观理解,其实就是将图像进行切片,类似于下采样取值,这样得到4个图像:
相当于是将空间信息咋绕到了通道信息中,cat后输入通道变成4倍,再通过conv得到新的featuremap,这样做的好处就是保持了下采样的信息没有丢失,图像的信息都保留了下来,但是在浅层中的应用,作者也表示了单纯是从计算量和参数量的角度上去设计,因为如上的所述的信息保存在浅层的意义并不大。所以后来查了下,作者的设计原因就是:为了减少浮点数和提高速度,而不是增加featuremap。
故,1个焦点模型可以替代更多的卷积层,而将空间信息聚焦到通道空间,这也会减少1像素的回归精度,而大部分的检测回归精度都不会接近1,这也是为什么FOCUS要放在输入的第一层上的原因。
一句话解释:focus为了压缩网络层去提速。
backbone:
# [from, number, module, args]
[[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 <--- update
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, C3, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 9, C3, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, C3, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 1, SPP, [1024, [5, 9, 13]]],
[-1, 3, C3, [1024, False]], # 9
]
言归正传,再经过作者的试验后,结论就是获得了更好的性能,且没有之前的一些局限性和副作用。
这个是代码再common.py里,一直就有的Module,也是为了提升推理性能,直接上作者图:
这里补充一下,用5*5大小的核去替代了之前的(5,9,13),首先类比和卷积层一样的及计算方式,那么小卷积核的计算量肯定是远小于大卷积核的。
C3是V5作者提供的CSP的结构精简版本,强大的backbone!作者非常擅于集百家所长,且融合贯通。
在Backbone中将C3层从9减少至6去提升速度,(是实验后对MAP没影响),将sppf放到最后这个改过问题,你如果你改过BIFPN那么就知道了,V5的网络结构尾部一直有点拧巴。。
之所以最后1层的C3改成shorcut,那是因为原先的骨干最后一层是C3,而现在是SPPF层,不管是之前版本还是当前版本,C3在网络过程中添加shortcut进行残差训练的,而原版由于在最后一层添加的C3所以取消了,那么先前的C3都要做残差,这才流畅。。最后我们以yolov5m6的改动,一览网络结构的调整:
作者在超参数文件中,将学习率0.2调为0.1;(3个超参文件,分别对应P5,NANO,P6三个版本模型)
在对应于P6的模型上,/data/hyps/hyp.scratch-high.yaml的超参文件中:
mixup: 0.1 # image mixup (probability)
copy_paste: 0.1 # segment copy-paste (probability)
意味着更复杂的大模型,开启一定的MIXUP和COPY-paste 会有提升?
总结下,这次V5 V6.0的算法核心修改可以说就是两个字:结构精简,不得不说效果OK,最近业余时间把swin研究透了 再进行下一步,明天我会merge下v6.0的git代码,别的开源项目也再更新中。