前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >YOLOv8、v7、v5独家改进:上采样算子 | 超轻量高效动态上采样DySample,效果秒杀CAFFE,助力小目标检测

YOLOv8、v7、v5独家改进:上采样算子 | 超轻量高效动态上采样DySample,效果秒杀CAFFE,助力小目标检测

原创
作者头像
AI小怪兽
发布2024-02-01 09:33:32
发布2024-02-01 09:33:32
4.3K00
代码可运行
举报
文章被收录于专栏:YOLO大作战YOLO大作战
运行总次数:0
代码可运行

​1.DySample介绍

论文:https://arxiv.org/pdf/2308.15085.pdf

摘要:我们介绍DySample,一个超轻量和有效的动态上采样器。虽然最近基于内核的动态上采样器(如CARAFE、FADE和SAPA)的性能提升令人印象深刻,但它们带来了大量的工作负载,主要是由于耗时的动态卷积和用于生成动态内核的额外子网络。此外,对高特征指导的需求在某种程度上限制了它们的应用场景。为了解决这些问题,我们绕过动态卷积并从点采样的角度制定上采样,这更节省资源,并且可以很容易地使用PyTorch中的标准内置函数实现。我们首先展示了一个朴素的设计,然后演示了如何逐步加强其上采样行为,以实现我们的新上采样器DySample。与以前基于内核的动态上采样器相比,DySample不需要定制CUDA包,并且具有更少的参数、FLOPs、GPU内存和延迟。除了轻量级的特点,DySample在五个密集预测任务上优于其他上采样器,包括语义分割、目标检测、实例分割、全视分割和单目深度估计。

图1所示。不同上采样器的性能、推理速度和GFLOPs的比较。圆圈的大小表示GFLOPs的开销。通过×2上采样大小为256 × 120 × 120的特征图来测试推理时间。在ADE20K数据集[42]上使用SegFormer-B1[40]测试了mIoU性能和额外的gflop。

在几何信息建模的基础上,回归到上采样的本质,即点采样。对于PyTorch中的内置函数,我们首先提供了一个简单的实现来演示基于采样的动态上采样的可行性

图3。初始采样位置和偏移范围。点和彩色遮罩分别表示初始采样位置和偏移范围。考虑采样4个点(s = 2), (a)在最接近初始化的情况下,4个偏移共享相同的初始位置,忽略位置关系;在双线性初始化(b)中,我们分离初始位置,使它们均匀分布。如果没有偏移调制(b),偏移范围通常会重叠,因此在(c)中,我们局部约束偏移范围以减少重叠。

​图4。由于偏移重叠造成的预测伪影。如果偏移量重叠(a),边界附近的点值可能是无序的(b),误差会逐层传播,最终导致预测伪影(c)。

图7。DySample中上采样过程的可视化。红色框中的部分边界被高亮显示,以便近距离观察。我们生成内容感知偏移来构造新的采样点,用双线性插值对输入特征映射进行重采样。新的采样位置由箭头表示。选择低分辨率特征中的黄色框点来说明双线性插值过程。

2.如何加入到YOLO

核心代码:

代码语言:python
代码运行次数:0
复制

class DySample(nn.Module):
    def __init__(self, in_channels, scale=2, style='lp', groups=4, dyscope=False):
        super().__init__()
        self.scale = scale
        self.style = style
        self.groups = groups
        assert style in ['lp', 'pl']
        if style == 'pl':
            assert in_channels >= scale ** 2 and in_channels % scale ** 2 == 0
        assert in_channels >= groups and in_channels % groups == 0
 
        if style == 'pl':
            in_channels = in_channels // scale ** 2
            out_channels = 2 * groups
        else:
            out_channels = 2 * groups * scale ** 2
 
        self.offset = nn.Conv2d(in_channels, out_channels, 1)
        normal_init(self.offset, std=0.001)
        if dyscope:
            self.scope = nn.Conv2d(in_channels, out_channels, 1)
            constant_init(self.scope, val=0.)
 
        self.register_buffer('init_pos', self._init_pos())
 
    def _init_pos(self):
        h = torch.arange((-self.scale + 1) / 2, (self.scale - 1) / 2 + 1) / self.scale
        return torch.stack(torch.meshgrid([h, h])).transpose(1, 2).repeat(1, self.groups, 1).reshape(1, -1, 1, 1)
 
    def sample(self, x, offset):
        B, _, H, W = offset.shape
        offset = offset.view(B, 2, -1, H, W)
        coords_h = torch.arange(H) + 0.5
        coords_w = torch.arange(W) + 0.5
        coords = torch.stack(torch.meshgrid([coords_w, coords_h])
                             ).transpose(1, 2).unsqueeze(1).unsqueeze(0).type(x.dtype).to(x.device)
        normalizer = torch.tensor([W, H], dtype=x.dtype, device=x.device).view(1, 2, 1, 1, 1)
        coords = 2 * (coords + offset) / normalizer - 1
        coords = F.pixel_shuffle(coords.view(B, -1, H, W), self.scale).view(
            B, 2, -1, self.scale * H, self.scale * W).permute(0, 2, 3, 4, 1).contiguous().flatten(0, 1)
        return F.grid_sample(x.reshape(B * self.groups, -1, H, W), coords, mode='bilinear',
                             align_corners=False, padding_mode="border").view(B, -1, self.scale * H, self.scale * W)
 
    def forward_lp(self, x):
        if hasattr(self, 'scope'):
            offset = self.offset(x) * self.scope(x).sigmoid() * 0.5 + self.init_pos
        else:
            offset = self.offset(x) * 0.25 + self.init_pos
        return self.sample(x, offset)
 
    def forward_pl(self, x):
        x_ = F.pixel_shuffle(x, self.scale)
        if hasattr(self, 'scope'):
            offset = F.pixel_unshuffle(self.offset(x_) * self.scope(x_).sigmoid(), self.scale) * 0.5 + self.init_pos
        else:
            offset = F.pixel_unshuffle(self.offset(x_), self.scale) * 0.25 + self.init_pos
        return self.sample(x, offset)
 
    def forward(self, x):
        if self.style == 'pl':
            return self.forward_pl(x)
        return self.forward_lp(x)

by AI小怪兽

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ​1.DySample介绍
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档