Ultralytics:解读CBLinear模块

Ultralytics:解读CBLinear模块

前言

相关介绍

Ultralytics 简介

Ultralytics 基于多年的计算机视觉和人工智能基础研究,创建了最先进的 (SOTA) YOLO 模型。我们的模型不断更新性能和灵活性,快速、准确且易于使用。他们擅长对象检测、跟踪、实例分割、语义分割、图像分类和姿势估计任务。

前提条件

  • 熟悉Python、Pytorch

实验环境

bash 复制代码
Package                  Version
------------------------ ------------
Python                   3.11.8
absl-py                  2.4.0
accelerate               1.13.0
annotated-doc            0.0.4
anyio                    4.13.0
calflops                 0.3.2
certifi                  2026.4.22
charset-normalizer       3.4.7
click                    8.3.3
colorama                 0.4.6
contourpy                1.3.3
cycler                   0.12.1
filelock                 3.29.0
flatbuffers              25.12.19
fonttools                4.62.1
fsspec                   2026.4.0
grpcio                   1.80.0
h11                      0.16.0
hf-xet                   1.5.0
httpcore                 1.0.9
httpx                    0.28.1
huggingface_hub          1.14.0
idna                     3.15
Jinja2                   3.1.6
kiwisolver               1.5.0
Markdown                 3.10.2
markdown-it-py           4.2.0
MarkupSafe               3.0.3
matplotlib               3.10.9
mdurl                    0.1.2
ml_dtypes                0.5.0
mpmath                   1.3.0
networkx                 3.6.1
numpy                    1.26.4
nvidia-cublas-cu12       12.8.3.14
nvidia-cuda-cupti-cu12   12.8.57
nvidia-cuda-nvrtc-cu12   12.8.61
nvidia-cuda-runtime-cu12 12.8.57
nvidia-cudnn-cu12        9.7.1.26
nvidia-cufft-cu12        11.3.3.41
nvidia-cufile-cu12       1.13.0.11
nvidia-curand-cu12       10.3.9.55
nvidia-cusolver-cu12     11.7.2.55
nvidia-cusparse-cu12     12.5.7.53
nvidia-cusparselt-cu12   0.6.3
nvidia-nccl-cu12         2.26.2
nvidia-nvjitlink-cu12    12.8.61
nvidia-nvtx-cu12         12.8.55
onnx                     1.19.0
onnxruntime-gpu          1.26.0
onnxslim                 0.1.94
opencv-python            4.6.0.66
packaging                26.2
pillow                   12.2.0
pip                      24.0
polars                   1.40.1
polars-runtime-32        1.40.1
protobuf                 7.34.1
psutil                   7.2.2
pycocotools              2.0.11
Pygments                 2.20.0
pyparsing                3.3.2
python-dateutil          2.9.0.post0
PyYAML                   6.0.3
regex                    2026.5.9
requests                 2.34.1
rich                     15.0.0
safetensors              0.7.0
scipy                    1.16.0
setuptools               65.5.0
shellingham              1.5.4
six                      1.17.0
sympy                    1.14.0
tabulate                 0.10.0
tensorboard              2.20.0
tensorboard-data-server  0.7.2
tokenizers               0.22.2
torch                    2.7.1+cu128
torchaudio               2.7.1+cu128
torchvision              0.22.1+cu128
tqdm                     4.67.3
transformers             5.8.1
triton                   3.3.1
typer                    0.25.1
typing_extensions        4.15.0
ultralytics              8.4.58
ultralytics-thop         2.0.19
urllib3                  2.7.0
Werkzeug                 3.1.8

CBLinear(多分支卷积模块)

CBLinear 是一个用于生成 多个不同通道数的特征图 的卷积模块。它通过一个共享的卷积层同时输出总通道数为 sum(c2s) 的特征图,然后按指定的通道尺寸列表 c2s 沿通道维度拆分为多个张量。这种设计在需要 多任务输出多尺度特征分支 的网络中非常有用,例如 YOLOv9 中的某些跨层连接结构。


代码实现

python 复制代码
import cv2
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
import matplotlib.pyplot as plt

def autopad(k, p=None, d=1):  # kernel, padding, dilation
    """Pad to 'same' shape outputs."""
    if d > 1:
        k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k]  # actual kernel-size
    if p is None:
        p = k // 2 if isinstance(k, int) else [x // 2 for x in k]  # auto-pad
    return p

class CBLinear(nn.Module):
    """CBLinear."""

    def __init__(self, c1: int, c2s: list[int], k: int = 1, s: int = 1, p: int | None = None, g: int = 1):
        """Initialize CBLinear module.

        Args:
            c1 (int): Input channels.
            c2s (list[int]): List of output channel sizes.
            k (int): Kernel size.
            s (int): Stride.
            p (int | None): Padding.
            g (int): Groups.
        """
        super().__init__()
        self.c2s = c2s
        self.conv = nn.Conv2d(c1, sum(c2s), k, s, autopad(k, p), groups=g, bias=True)

    def forward(self, x: torch.Tensor) -> list[torch.Tensor]:
        """Forward pass through CBLinear layer."""
        return self.conv(x).split(self.c2s, dim=1)

功能

  • 多输出分支 :将输入特征通过一个卷积层,生成总通道数为 sum(c2s) 的特征图,然后按照 c2s 列表中的数值,沿通道维拆分成多个张量。
  • 共享卷积权重:所有分支共享同一个卷积核,减少参数量,同时能够并行计算。
  • 灵活配置 :通过 c2s 可以灵活指定每个分支的输出通道数,适应不同任务需求(如目标检测中的分类头、回归头等)。

初始化参数

参数 类型 说明
c1 int 输入特征图的通道数
c2s listint 各分支的输出通道数列表,长度表示分支数
k int 卷积核大小(默认 1)
s int 卷积步长(默认 1)
p int | None 填充,若为 None 则自动计算
g int 分组卷积的组数(默认 1)
  • 卷积层 self.conv 的输出通道数为 sum(c2s),偏置 bias=True
  • 填充 p 通过 autopad 自动计算(保持输出尺寸不变)。

前向方法

  • forward(x):输入 x 形状 [B, c1, H, W],返回一个张量列表,每个张量形状为 [B, c2_i, H, W],其中 c2_i 对应 c2s[i]

使用示例

python 复制代码
if __name__ == '__main__':
    # 1. 随机输入
    B, c1, H, W = 2, 16, 32, 32
    x = torch.randn(B, c1, H, W)

    # 2. 定义各分支输出通道数
    c2s = [8, 16, 32]  # 三个分支

    # 3. 创建 CBLinear 模块
    cbl = CBLinear(c1=c1, c2s=c2s, k=3, s=1)

    # 4. 前向传播
    with torch.no_grad():
        outputs = cbl(x)  # outputs 是一个长度为3的列表

    print("输入形状:", x.shape)  # [2, 16, 32, 32]
    for i, out in enumerate(outputs):
        print(f"分支 {i} 输出形状:", out.shape)  # [2, 8, 32, 32], [2, 16, 32, 32], [2, 32, 32, 32]
    print("总参数量:", sum(p.numel() for p in cbl.parameters()))

输出示例

复制代码
输入形状: torch.Size([2, 16, 32, 32])
分支 0 输出形状: torch.Size([2, 8, 32, 32])
分支 1 输出形状: torch.Size([2, 16, 32, 32])
分支 2 输出形状: torch.Size([2, 32, 32, 32])
总参数量: 16*56*9 + 56 = 8120

流程示意图

#mermaid-svg-TrFRx0DEs44YgqHK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TrFRx0DEs44YgqHK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TrFRx0DEs44YgqHK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TrFRx0DEs44YgqHK .error-icon{fill:#552222;}#mermaid-svg-TrFRx0DEs44YgqHK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TrFRx0DEs44YgqHK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TrFRx0DEs44YgqHK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TrFRx0DEs44YgqHK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TrFRx0DEs44YgqHK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TrFRx0DEs44YgqHK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TrFRx0DEs44YgqHK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TrFRx0DEs44YgqHK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TrFRx0DEs44YgqHK .marker.cross{stroke:#333333;}#mermaid-svg-TrFRx0DEs44YgqHK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TrFRx0DEs44YgqHK p{margin:0;}#mermaid-svg-TrFRx0DEs44YgqHK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-TrFRx0DEs44YgqHK .cluster-label text{fill:#333;}#mermaid-svg-TrFRx0DEs44YgqHK .cluster-label span{color:#333;}#mermaid-svg-TrFRx0DEs44YgqHK .cluster-label span p{background-color:transparent;}#mermaid-svg-TrFRx0DEs44YgqHK .label text,#mermaid-svg-TrFRx0DEs44YgqHK span{fill:#333;color:#333;}#mermaid-svg-TrFRx0DEs44YgqHK .node rect,#mermaid-svg-TrFRx0DEs44YgqHK .node circle,#mermaid-svg-TrFRx0DEs44YgqHK .node ellipse,#mermaid-svg-TrFRx0DEs44YgqHK .node polygon,#mermaid-svg-TrFRx0DEs44YgqHK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TrFRx0DEs44YgqHK .rough-node .label text,#mermaid-svg-TrFRx0DEs44YgqHK .node .label text,#mermaid-svg-TrFRx0DEs44YgqHK .image-shape .label,#mermaid-svg-TrFRx0DEs44YgqHK .icon-shape .label{text-anchor:middle;}#mermaid-svg-TrFRx0DEs44YgqHK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-TrFRx0DEs44YgqHK .rough-node .label,#mermaid-svg-TrFRx0DEs44YgqHK .node .label,#mermaid-svg-TrFRx0DEs44YgqHK .image-shape .label,#mermaid-svg-TrFRx0DEs44YgqHK .icon-shape .label{text-align:center;}#mermaid-svg-TrFRx0DEs44YgqHK .node.clickable{cursor:pointer;}#mermaid-svg-TrFRx0DEs44YgqHK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-TrFRx0DEs44YgqHK .arrowheadPath{fill:#333333;}#mermaid-svg-TrFRx0DEs44YgqHK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-TrFRx0DEs44YgqHK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-TrFRx0DEs44YgqHK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TrFRx0DEs44YgqHK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TrFRx0DEs44YgqHK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TrFRx0DEs44YgqHK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-TrFRx0DEs44YgqHK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-TrFRx0DEs44YgqHK .cluster text{fill:#333;}#mermaid-svg-TrFRx0DEs44YgqHK .cluster span{color:#333;}#mermaid-svg-TrFRx0DEs44YgqHK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-TrFRx0DEs44YgqHK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TrFRx0DEs44YgqHK rect.text{fill:none;stroke-width:0;}#mermaid-svg-TrFRx0DEs44YgqHK .icon-shape,#mermaid-svg-TrFRx0DEs44YgqHK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TrFRx0DEs44YgqHK .icon-shape p,#mermaid-svg-TrFRx0DEs44YgqHK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-TrFRx0DEs44YgqHK .icon-shape .label rect,#mermaid-svg-TrFRx0DEs44YgqHK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TrFRx0DEs44YgqHK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-TrFRx0DEs44YgqHK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-TrFRx0DEs44YgqHK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 输入 x (B, c1, H, W)
Conv2d: c1 → sum(c2s), k, s, p
输出 (B, sum(c2s), H, W)
split(dim=1, split_sizes=c2s)
分支 0 (B, c2s0, H, W)
分支 1 (B, c2s1, H, W)
...
分支 n-1 (B, c2s-1, H, W)


代码解读

  • __init__
    • 存储 c2s 列表供 forward 使用。
    • 创建 nn.Conv2d,输出通道数为 sum(c2s),其他参数(核大小、步长、填充、分组)透传。
    • 使用 autopad 自动计算填充,保证输出空间尺寸不变(除非步长不为 1)。
  • forward
    • 对输入 x 应用卷积,得到总输出。
    • 使用 torch.split 沿通道维(dim=1)按 c2s 拆分,返回张量列表。

注意事项

  1. 输出通道总和sum(c2s) 必须与卷积层的输出通道数一致(实际上代码直接使用该值,因此无冲突)。
  2. 空间尺寸变化 :若步长 s 不为 1,则所有分支的空间尺寸会同步缩小(步长共享),且填充自动调整。
  3. 权重共享:所有分支共享同一个卷积核,这意味着它们提取的是相同的底层特征,只是输出通道数不同。如果希望各分支独立学习,应使用多个卷积层。
  4. 应用场景:常用于需要同时输出不同维度特征(如多个检测头)的网络结构,例如 YOLOv9 中的某些模块。

优缺点

优点
  1. 参数高效:共享卷积权重,相比多个独立卷积层,参数量大幅减少。
  2. 计算高效:一次卷积即可生成所有分支输出,计算量远低于多次卷积。
  3. 灵活配置 :通过 c2s 可任意调整各分支的通道数,适应多任务或多尺度需求。
  4. 易于集成 :与普通 Conv 接口相似,可直接替换标准卷积层。
缺点
  1. 表达能力受限:所有分支共享相同的卷积核,无法针对每个分支学习独立的特征变换。
  2. 输出尺寸绑定:所有分支共享相同的空间尺寸(由步长决定),无法分别控制不同分支的分辨率。
  3. 分组卷积的限制g 参数作用于整个卷积,所有分支共享相同的分组数,若各分支需要不同分组则无法实现。

在 YOLOv9 等网络结构中,CBLinear 常用于高效地生成多个特征分支,以便后续进行不同的处理(如不同尺度的检测)。使用时需权衡共享权重带来的效率提升与表达能力下降之间的关系。若任务对分支独立性要求较高,可考虑使用多个独立卷积代替。

参考文献

1 https://docs.ultralytics.com/

2 https://github.com/ultralytics/ultralytics.git

相关推荐
光锥智能8 小时前
AI应用WAIC“抢跑”:热闹是真,但差异化是假
大数据·人工智能
某林2128 小时前
履带小车底盘stm32F103RCT6开发
人工智能·stm32·单片机·嵌入式硬件·架构·人机交互·ros2
逸模8 小时前
多业态连锁,如何同步铺开各类门店
大数据·人工智能·笔记·工程·公装·连锁店
音视频牛哥8 小时前
AI浪潮下,实时音视频SDK正在经历怎样的价值重构?
人工智能·音视频·实时音视频·rtmp推流·低延迟rtsp播放器·低延迟rtmp播放器·rtsp转rtmp推流
ShallWeL8 小时前
Orin 上用 Docker 跑通目标检测功能
人工智能·目标检测·docker·容器
xd1855785558 小时前
家电选购参谋 —— 鸿蒙AI智能助手开发全流程解析
人工智能·华为·harmonyos·鸿蒙
秦先生在广东8 小时前
Moonshine Voice:专为实时语音而生的端侧 ASR 工具包
人工智能
不爱记笔记8 小时前
2026 WAIC大会亮点解析!超节点、机器人与AI应用全面开花
人工智能·ai·机器人·具身智能·deepseek
lichenyang4538 小时前
AI 入门看了很多,为什么还是不懂?从 Prompt、AI 工具到大模型原理一次讲清楚
人工智能