惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Martin Fowler
Martin Fowler
人人都是产品经理
人人都是产品经理
Vercel News
Vercel News
Microsoft Security Blog
Microsoft Security Blog
A
About on SuperTechFans
GbyAI
GbyAI
酷 壳 – CoolShell
酷 壳 – CoolShell
NISL@THU
NISL@THU
TaoSecurity Blog
TaoSecurity Blog
Project Zero
Project Zero
M
MIT News - Artificial intelligence
Blog — PlanetScale
Blog — PlanetScale
Recorded Future
Recorded Future
Jina AI
Jina AI
H
Help Net Security
大猫的无限游戏
大猫的无限游戏
Scott Helme
Scott Helme
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
罗磊的独立博客
MyScale Blog
MyScale Blog
P
Privacy & Cybersecurity Law Blog
V
Visual Studio Blog
月光博客
月光博客
T
The Blog of Author Tim Ferriss
V
Vulnerabilities – Threatpost
Simon Willison's Weblog
Simon Willison's Weblog
C
Cybersecurity and Infrastructure Security Agency CISA
博客园 - 三生石上(FineUI控件)
F
Fortinet All Blogs
C
Check Point Blog
T
Threat Research - Cisco Blogs
IT之家
IT之家
P
Proofpoint News Feed
Y
Y Combinator Blog
T
Tor Project blog
T
The Exploit Database - CXSecurity.com
腾讯CDC
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
I
InfoQ
T
Troy Hunt's Blog
博客园 - 司徒正美
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - Franky
Hacker News: Ask HN
Hacker News: Ask HN
C
CERT Recently Published Vulnerability Notes
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园 - 聂微东
F
Full Disclosure
宝玉的分享
宝玉的分享
V
V2EX - 技术

魔改工程师

前言 - 魔改工程师 前言 - 魔改工程师 前言 - 魔改工程师 前言 - 魔改工程师 前言 - 魔改工程师 YOLO26改进 – C3k2 C3k2 融合 LSConv (Large-Small Conv) 融合大核感知与小核聚合,提升小目标特征判别力 CVPR 2025 前言 - 魔改工程师 YOLO26改进 – C2PSA C2PSA融合Mona多认知视觉适配器:打破全参数微调的性能枷锁:即插即用的提点神器 CVPR 2025 前言 - 魔改工程师 YOLO26改进 – C2PSA C2PSA融合DiffAttention差分注意力:轻量级差分计算实现高效特征降噪,提升模型抗干扰能力 - 魔改工程师 YOLO26改进 – C2PSA C2PSA融合CPIASA跨范式交互与对齐自注意力机制 交互对齐机制,提升小目标与遮挡目标判别力 ACM MM2025 YOLO26 正式发布源代码!极致速度优化方案, 面向工业级落地的目标检测模型! - 魔改工程师 YOLO26 改进 – 注意力机制 MCAttn 蒙特卡洛注意力:全局上下文与局部细节协同建模,破解微小目标特征表达难题 YOLO26 改进 – 注意力机制 轴向注意力Axial Attention(Axial Attention)优化高分辨率特征提取 前言 - 魔改工程师 YOLO26 改进 – 注意力机制 二阶通道注意力SOCA 通过协方差建模与自适应重缩放实现判别性特征增强 YOLO26 改进 – 注意力机制 SCSA注意力通过双重注意力机制增强局部-全局特征交互 前言 - 魔改工程师 前言 - 魔改工程师 前言 - 魔改工程师 YOLO26 改进 – 注意力机制 HaloNet 局部自注意力 (Local Self-Attention) 以分块交互策略实现高效全局上下文建模 YOLO26 改进 – 注意力机制 DiffAttention差分注意力:轻量级差分计算实现高效特征降噪,提升模型抗干扰能力 TMLR 2025 前言 - 魔改工程师 YOLO26 改进 – 注意力机制 CAFM (Convolutional Block Attention Module) 卷积块注意力模块:轻量级设计优化特征提取流程,提升小目标感知 YOLO26 改进 – 注意力机制 ACmix自注意力与卷积混合模型:轻量级设计融合双机制优势,实现高效特征提取与推理加速 前言 - 魔改工程师 前言 - 魔改工程师 前言 - 魔改工程师 2026最新YOLO26改进:卷积层、轻量化、注意力机制、损失函数、Backbone、SPPF、Neck、检测头全方位优化汇总 - 魔改工程师 失灵的键盘 - 魔改工程师 **返回所有加载的AGENTS.md文件ID列表** - 魔改工程师 **资源二分类隔离判定** - 魔改工程师 **统计盈利目标区间** - 魔改工程师 物流仓库货物调货优化 - 魔改工程师 寻找重复子数据 - 魔改工程师 匹配命令行前缀关键字 - 魔改工程师 **魔法阵的能量收集** - 魔改工程师 **链表数字游戏** - 魔改工程师 **企业内部部门的最大层级** - 魔改工程师 前言 YOLOv11 改进 – SPPF模块 替代SPP,FFocal Modulation焦点调制:即插即用轻量设计优化全局语义捕获 前言 - 魔改工程师 YOLOv11 改进 – SPPF模块 SPPELAN 空间金字塔池化与增强局部注意力:替代SPPF增强多尺度上下文捕获,提升检测精度 YOLOv11 改进 – SPPF模块 AIFI基于注意力的尺度内特征交互:替代SPPF构建高效混合编码器,提升模型综合效能 YOLOv11 改进 – Mamba 集成Mamba-YOLO(AAAI 2025),Mamba-YOLOv11-T 替换骨干,破解全局依赖建模难题,实现高效实时检测 YOLOv11 改进 – Mamba 集成Mamba-YOLO(AAAI 2025),Mamba-YOLOv11-L 替换骨干,破解全局依赖建模难题,实现高效实时检测 YOLOv11 改进 – Mamba 集成Mamba-YOLO(AAAI 2025),Mamba-YOLOv11-B 替换骨干,破解全局依赖建模难题,实现高效实时检测 前言 - 魔改工程师 前言 - 魔改工程师 前言 - 魔改工程师 前言 - 魔改工程师 前言 - 魔改工程师 前言 - 魔改工程师 YOLOv11 改进 – C2PSA C2PSA融合DiffAttention差分注意力:轻量级差分计算实现高效特征降噪,提升模型抗干扰能力 YOLOv11 改进 – C2PSA C2PSA融合CPIASA跨范式交互与对齐自注意力机制(ACM MM2025) 交互对齐机制破解特征融合难题,提升小目标与遮挡目标判别力 麻将基本胡牌型判断 - 魔改工程师 IP地址分类识别 - 魔改工程师 **查找能被整除的最大整数** - 魔改工程师 数据包优先级窗口查找 - 魔改工程师 美观的灯笼 - 魔改工程师 配置操作失败数量统计 - 魔改工程师 计费时段计算 - 魔改工程师 计算数列位置N的值 - 魔改工程师 空间占用计算 - 魔改工程师
前言 - 魔改工程师
魔改工程师 · 2026-06-14 · via 魔改工程师

本文介绍了将自适应矩形卷积(ARConv)模块与YOLO26相结合的方法。ARConv是针对遥感图像全色锐化任务设计的创新卷积模块,可自适应调整卷积核形状与采样点数量,解决传统卷积刚性限制,实现高效特征提取。其工作流程包括学习卷积核高度和宽度、选择采样点数量、生成采样图、卷积实现与空间自适应增强。我们将集成ARConv的C3k2_ARConv模块引入YOLO26,对相关代码进行修改和注册,并配置了YOLO26 - C3k2_ARConv.yaml文件。实验脚本显示,该结合方式应用于目标检测任务。

文章目录: YOLO26改进大全:卷积层、轻量化、注意力机制、损失函数、Backbone、SPPF、Neck、检测头全方位优化汇总

专栏链接: YOLO26改进专栏

介绍

image-20251203210715540

摘要

文章链接

论文地址:论文地址

代码地址:代码地址

基本原理

ARConv(Adaptive Rectangular Convolution)是针对遥感图像全色锐化任务设计的创新卷积模块,核心优势是自适应调整卷积核形状与采样点数量,解决传统卷积的刚性限制,实现高效特征提取。


一、设计背景与核心目标

1. 解决的关键问题

  • 传统卷积缺陷:采样窗口固定为方形、采样点数量预设,无法适配遥感图像中物体的尺度差异(如小型车辆与大型建筑)。
  • 现有改进方法不足:可变形卷积参数量随核尺寸二次增长,多尺度卷积核尺寸固定,空间自适应卷积未充分考虑尺度信息。

    2. 核心目标

  • 动态适配不同物体的尺度与形状,优化采样位置。
  • 灵活调整采样点数量,平衡细节捕捉与噪声抑制。
  • 控制计算复杂度,避免参数冗余导致的收敛困难。

二、核心设计与工作流程

ARConv的实现分为4个关键步骤,全程仅学习2个核心参数(卷积核的高度和宽度),计算效率优异。

1. 学习卷积核的高度和宽度

  • 通过两个子网(共享特征提取器+独立高/宽学习器)预测高/宽特征图((y_1)、(y_2)),输出经Sigmoid激活后范围为(0,1)。
  • 用调制因子((a_i)、(b_i))约束实际范围:核高∈( (b_1), (a_1+b_1) ),核宽∈( (b_2), (a_2+b_2) ),避免取值无界。
  • 核心优势:仅学习2个参数,计算量不随核尺寸增长。

2. 选择采样点数量

  • 计算高/宽特征图的均值,通过调制系数((m)、(n))映射为垂直((k_h))和水平((k_w))方向的采样点数量。
  • 仅选择奇数采样点(偶数时取邻近更小奇数),保证采样对称性。
  • 采样点总数= (k_h \times k_w),随核高宽均值动态调整(均值越大,采样点越多)。

3. 生成采样图

  • 基于标准卷积偏移矩阵((G))和学习到的尺度矩阵((Z_0)),计算ARConv的偏移矩阵((R)),实现采样位置自适应。
  • 采样点可能不落在网格中心,采用双线性插值估计像素值,保证采样精度。
  • 通过扩展技术将每个像素的采样窗口组装为新网格,生成最终采样图((S \in \mathbb{R}^{(k_h H) \times (kw W) \times C{in}}))。

4. 卷积实现与空间自适应增强

  • 对采样图用尺寸和步长均为((k_h)、(k_w))的卷积核进行特征提取。
  • 引入仿射变换(AT):通过两个子网预测调制矩阵((M))和偏置矩阵((B)),提升空间适应性。
  • 最终输出:(y = (S \star SK) \odot M \oplus B)((\star)为卷积,(\odot)为逐元素乘法,(\oplus)为逐元素加法)。

三、关键创新与优势

创新点 具体说明 对比优势(vs 传统/改进卷积)
自适应矩形核 核形状为矩形(非固定方形),随物体尺寸动态调整 解决标准卷积“方形窗口不匹配物体形状”的问题
动态采样点 采样点数量随核高宽均值变化,避免固定数量的冗余或不足 优于可变形卷积(采样点数量固定)和多尺度卷积(核尺寸固定)
低计算复杂度 仅学习2个核参数,仿射变换无额外计算负担 可变形卷积参数随核尺寸二次增长,小数据集难收敛
空间自适应增强 仿射变换优化输出特征图的空间灵活性 优于无仿射变换的卷积模块,提升复杂场景适应性

核心代码

import torch
import torch.nn as nn

class ARConv(nn.Module):
    def __init__(self, inc, outc, kernel_size=3, padding=1, stride=1, l_max=9, w_max=9, flag=False, modulation=True):
        super(ARConv, self).__init__()
        self.lmax = l_max
        self.wmax = w_max
        self.inc = inc
        self.outc = outc
        self.kernel_size = kernel_size
        self.padding = padding
        self.stride = stride
        self.zero_padding = nn.ZeroPad2d(padding)
        self.flag = flag
        self.modulation = modulation
        self.i_list = [33, 35, 53, 37, 73, 55, 57, 75, 77]
        self.convs = nn.ModuleList(
            [
                nn.Conv2d(inc, outc, kernel_size=(i // 10, i % 10), stride=(i // 10, i % 10), padding=0)
                for i in self.i_list
            ]
        )
        self.m_conv = nn.Sequential(
            nn.Conv2d(inc, outc, kernel_size=3, padding=1, stride=stride),
            nn.LeakyReLU(),
            nn.Dropout2d(0.3),
            nn.Conv2d(outc, outc, kernel_size=3, padding=1, stride=stride),
            nn.LeakyReLU(),
            nn.Dropout2d(0.3),
            nn.Conv2d(outc, outc, kernel_size=3, padding=1, stride=stride),
            nn.Tanh()
        )
        self.b_conv = nn.Sequential(
            nn.Conv2d(inc, outc, kernel_size=3, padding=1, stride=stride),
            nn.LeakyReLU(),
            nn.Dropout2d(0.3),
            nn.Conv2d(outc, outc, kernel_size=3, padding=1, stride=stride),
            nn.LeakyReLU(),
            nn.Dropout2d(0.3),
            nn.Conv2d(outc, outc, kernel_size=3, padding=1, stride=stride)
        )
        self.p_conv = nn.Sequential(
            nn.Conv2d(inc, inc, kernel_size=3, padding=1, stride=stride),
            nn.BatchNorm2d(inc),
            nn.LeakyReLU(),
            nn.Dropout2d(0),
            nn.Conv2d(inc, inc, kernel_size=3, padding=1, stride=stride),
            nn.BatchNorm2d(inc),
            nn.LeakyReLU(),
        )
        self.l_conv = nn.Sequential(
            nn.Conv2d(inc, 1, kernel_size=3, padding=1, stride=stride),
            nn.BatchNorm2d(1),
            nn.LeakyReLU(),
            nn.Dropout2d(0),
            nn.Conv2d(1, 1, 1),
            nn.BatchNorm2d(1),
            nn.Sigmoid()
        )
        self.w_conv = nn.Sequential(
            nn.Conv2d(inc, 1, kernel_size=3, padding=1, stride=stride),
            nn.BatchNorm2d(1),
            nn.LeakyReLU(),
            nn.Dropout2d(0),
            nn.Conv2d(1, 1, 1),
            nn.BatchNorm2d(1),
            nn.Sigmoid()
        )
        self.dropout1 = nn.Dropout(0.3)
        self.dropout2 = nn.Dropout2d(0.3)
        self.hook_handles = []
        self.hook_handles.append(self.m_conv[0].register_full_backward_hook(self._set_lr))
        self.hook_handles.append(self.m_conv[1].register_full_backward_hook(self._set_lr))
        self.hook_handles.append(self.b_conv[0].register_full_backward_hook(self._set_lr))
        self.hook_handles.append(self.b_conv[1].register_full_backward_hook(self._set_lr))
        self.hook_handles.append(self.p_conv[0].register_full_backward_hook(self._set_lr))
        self.hook_handles.append(self.p_conv[1].register_full_backward_hook(self._set_lr))
        self.hook_handles.append(self.l_conv[0].register_full_backward_hook(self._set_lr))
        self.hook_handles.append(self.l_conv[1].register_full_backward_hook(self._set_lr))
        self.hook_handles.append(self.w_conv[0].register_full_backward_hook(self._set_lr))
        self.hook_handles.append(self.w_conv[1].register_full_backward_hook(self._set_lr))

        self.reserved_NXY = nn.Parameter(torch.tensor([3, 3], dtype=torch.int32), requires_grad=False)

    @staticmethod
    def _set_lr(module, grad_input, grad_output):
        grad_input = tuple(g * 0.1 if g is not None else None for g in grad_input)
        grad_output = tuple(g * 0.1 if g is not None else None for g in grad_output)
        return grad_input

    def remove_hooks(self):
        for handle in self.hook_handles:
            handle.remove()  # 移除钩子函数
        self.hook_handles.clear()  # 清空句柄列表

    def forward(self, x, epoch, hw_range):
        assert isinstance(hw_range, list) and len(hw_range) == 2, "hw_range should be a list with 2 elements, represent the range of h w"
        scale = hw_range[1] // 9
        if hw_range[0] == 1 and hw_range[1] == 3:
            scale = 1
        m = self.m_conv(x)
        bias = self.b_conv(x)
        offset = self.p_conv(x * 100)
        l = self.l_conv(offset) * (hw_range[1] - 1) + 1  # b, 1, h, w
        w = self.w_conv(offset) * (hw_range[1] - 1) + 1  # b, 1, h, w
        if epoch <= 100:
            mean_l = l.mean(dim=0).mean(dim=1).mean(dim=1)
            mean_w = w.mean(dim=0).mean(dim=1).mean(dim=1)
            N_X = int(mean_l // scale)
            N_Y = int(mean_w // scale)
            def phi(x):
                if x % 2 == 0:
                    x -= 1
                return x
            N_X, N_Y = phi(N_X), phi(N_Y)
            N_X, N_Y = max(N_X, 3), max(N_Y, 3)
            N_X, N_Y = min(N_X, 7), min(N_Y, 7)
            if epoch == 100:
                self.reserved_NXY = self.reserved_NXY = nn.Parameter(
                    torch.tensor([N_X, N_Y], dtype=torch.int32, device=x.device),
                    requires_grad=False
                )
        else:
            N_X = self.reserved_NXY[0]
            N_Y = self.reserved_NXY[1]

        N = N_X * N_Y
        # print(N_X, N_Y)
        l = l.repeat([1, N, 1, 1])
        w = w.repeat([1, N, 1, 1])
        offset = torch.cat((l, w), dim=1)
        dtype = offset.data.type()
        if self.padding:
            x = self.zero_padding(x)
        p = self._get_p(offset, dtype, N_X, N_Y)  # (b, 2*N, h, w)
        p = p.contiguous().permute(0, 2, 3, 1)  # (b, h, w, 2*N)
        q_lt = p.detach().floor()
        q_rb = q_lt + 1
        q_lt = torch.cat(
            [
                torch.clamp(q_lt[..., :N], 0, x.size(2) - 1),
                torch.clamp(q_lt[..., N:], 0, x.size(3) - 1),
            ],
            dim=-1,
        ).long()
        q_rb = torch.cat(
            [
                torch.clamp(q_rb[..., :N], 0, x.size(2) - 1),
                torch.clamp(q_rb[..., N:], 0, x.size(3) - 1),
            ],
            dim=-1,
        ).long()
        q_lb = torch.cat([q_lt[..., :N], q_rb[..., N:]], dim=-1)
        q_rt = torch.cat([q_rb[..., :N], q_lt[..., N:]], dim=-1)
        # clip p
        p = torch.cat(
            [
                torch.clamp(p[..., :N], 0, x.size(2) - 1),
                torch.clamp(p[..., N:], 0, x.size(3) - 1),
            ],
            dim=-1,
        )
        # bilinear kernel (b, h, w, N)
        g_lt = (1 + (q_lt[..., :N].type_as(p) - p[..., :N])) * (
                1 + (q_lt[..., N:].type_as(p) - p[..., N:])
        )
        g_rb = (1 - (q_rb[..., :N].type_as(p) - p[..., :N])) * (
                1 - (q_rb[..., N:].type_as(p) - p[..., N:])
        )
        g_lb = (1 + (q_lb[..., :N].type_as(p) - p[..., :N])) * (
                1 - (q_lb[..., N:].type_as(p) - p[..., N:])
        )
        g_rt = (1 - (q_rt[..., :N].type_as(p) - p[..., :N])) * (
                1 + (q_rt[..., N:].type_as(p) - p[..., N:])
        )
        # (b, c, h, w, N)
        x_q_lt = self._get_x_q(x, q_lt, N)
        x_q_rb = self._get_x_q(x, q_rb, N)
        x_q_lb = self._get_x_q(x, q_lb, N)
        x_q_rt = self._get_x_q(x, q_rt, N)
        # (b, c, h, w, N)
        x_offset = (
                g_lt.unsqueeze(dim=1) * x_q_lt
                + g_rb.unsqueeze(dim=1) * x_q_rb
                + g_lb.unsqueeze(dim=1) * x_q_lb
                + g_rt.unsqueeze(dim=1) * x_q_rt
        )
        x_offset = self._reshape_x_offset(x_offset, N_X, N_Y)
        x_offset = self.dropout2(x_offset)
        x_offset = self.convs[self.i_list.index(N_X * 10 + N_Y)](x_offset)
        out = x_offset * m + bias
        return out

    def _get_p_n(self, N, dtype, n_x, n_y):
        p_n_x, p_n_y = torch.meshgrid(
            torch.arange(-(n_x - 1) // 2, (n_x - 1) // 2 + 1),
            torch.arange(-(n_y - 1) // 2, (n_y - 1) // 2 + 1),
        )
        p_n = torch.cat([torch.flatten(p_n_x), torch.flatten(p_n_y)], 0)
        p_n = p_n.view(1, 2 * N, 1, 1).type(dtype)
        return p_n

    def _get_p_0(self, h, w, N, dtype):
        p_0_x, p_0_y = torch.meshgrid(
            torch.arange(1, h * self.stride + 1, self.stride),
            torch.arange(1, w * self.stride + 1, self.stride),
        )
        p_0_x = torch.flatten(p_0_x).view(1, 1, h, w).repeat(1, N, 1, 1)
        p_0_y = torch.flatten(p_0_y).view(1, 1, h, w).repeat(1, N, 1, 1)
        p_0 = torch.cat([p_0_x, p_0_y], 1).type(dtype)
        return p_0

    def _get_p(self, offset, dtype, n_x, n_y):
        N, h, w = offset.size(1) // 2, offset.size(2), offset.size(3)
        L, W = offset.split([N, N], dim=1)
        L = L / n_x
        W = W / n_y
        offsett = torch.cat([L, W], dim=1)
        p_n = self._get_p_n(N, dtype, n_x, n_y)
        p_n = p_n.repeat([1, 1, h, w])
        p_0 = self._get_p_0(h, w, N, dtype)
        p = p_0 + offsett * p_n
        return p

    def _get_x_q(self, x, q, N):
        b, h, w, _ = q.size()
        padded_w = x.size(3)
        c = x.size(1)
        x = x.contiguous().view(b, c, -1)
        index = q[..., :N] * padded_w + q[..., N:]
        index = (
            index.contiguous()
            .unsqueeze(dim=1)
            .expand(-1, c, -1, -1, -1)
            .contiguous()
            .view(b, c, -1)
        )
        x_offset = x.gather(dim=-1, index=index).contiguous().view(b, c, h, w, N)
        return x_offset

    @staticmethod
    def _reshape_x_offset(x_offset, n_x, n_y):
        b, c, h, w, N = x_offset.size()
        x_offset = torch.cat([x_offset[..., s:s + n_y].contiguous().view(b, c, h, w * n_y) for s in range(0, N, n_y)],
                             dim=-1)
        x_offset = x_offset.contiguous().view(b, c, h * n_x, w * n_y)
        return x_offset

实验

脚本

import warnings
warnings.filterwarnings('ignore')
from ultralytics import YOLO

if __name__ == '__main__':
#     修改为自己的配置文件地址
    model = YOLO('./ultralytics/cfg/models/26/yolo26-C3k2_ARConv.yaml')
#     修改为自己的数据集地址
    model.train(data='./ultralytics/cfg/datasets/coco8.yaml',
                cache=False,
                imgsz=640,
                epochs=10,
                single_cls=False,  # 是否是单类别检测
                batch=8,
                close_mosaic=10,
                workers=0,
                optimizer='MuSGD',  
                # optimizer='SGD',
                amp=False,
                project='runs/train',
                name='yolo26-C3k2_ARConv',
                )

结果

参数量太大,4060跑不起来, 可以直接参考yolo11的代码

class Bottleneck_ARConv(Bottleneck):
    def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5):
        super().__init__(c1, c2, shortcut, g, k, e)
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = ARConv(c1, c_)
        self.cv2 = ARConv(c_, c2)

class C3k_ARConv(C3k):
    def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5, k=3):
        super().__init__(c1, c2, n, shortcut, g, e, k)
        c_ = int(c2 * e)  # hidden channels
        self.m = nn.Sequential(*(Bottleneck_ARConv(c_, c_, shortcut, g, k=(k, k), e=1.0) for _ in range(n)))

class C3k2_ARConv(C3k2):
    def __init__(self, c1, c2, n=1, c3k=False, e=0.5, g=1, shortcut=True):
        super().__init__(c1, c2, n, c3k, e, g, shortcut)
        self.m = nn.ModuleList(C3k_ARConv(self.c, self.c, 2, shortcut, g) if c3k else Bottleneck_ARConv(self.c, self.c, shortcut, g) for _ in range(n))