计算机视觉——YOLO11原理代码分块解读与模型基准对比测试

一、概述

2024 年对 YOLO 而言是具有里程碑意义的一年。这一年,YOLO 系列在 9 月的最后一天推出了其年度第三部重磅之作。2024 年 2 月 21 日,距离 2023 年 1 月 YOLOv8 正式发布已过去一年有余,YOLOv9 终于问世。YOLOv9 创新性地提出了可编程梯度信息(Programmable Gradient Information,PGI)的概念。借助 PGI,模型能够获取完整信息,使得从头开始训练的模型,性能超越了基于大型数据集预训练的 SOTA 模型。同时,通过引入多级辅助网络分支和通用高效层聚合网络(Generalized Efficient Layer Aggregation Network,GELAN),YOLOv9 显著提升了 YOLO 检测器的信息提取能力。
随后,在 2024 年 5 月 25 日,清华大学研究团队发布了 YOLO 系列的最新版本 ——YOLOV10。该版本通过紧凑的倒置瓶颈层(Compact Inverted Bottleneck,CIB)和有效的部分自注意力(Partial Self-attention,PSA)模块增强了模型能力,实现了更高效率与精度的实时目标检测。此外,用于无 NMS 训练的一致双重分配策略,大幅降低了计算开销。最终,在 2024 年 9 月 30 日,YOLO11 震撼登场,再次吸引了学界和业界的广泛关注。

二、 YOLO11

YOLO11 是 Ultralytics 推出的 YOLO 系列的最新版本。YOLO11 拥有超轻量级的模型,比之前的 YOLO 模型更快、更高效。YOLO11 能够处理更广泛的计算机视觉任务。Ultralytics 根据模型大小发布了五款 YOLO11 模型,涵盖所有任务的模型共有 25 款:

  • YOLO11n:纳米级,适用于小型和轻量级任务。
  • YOLO11s:在纳米级基础上进行了小幅升级,提高了一定的准确性。
  • YOLO11m:中等规模,适用于通用用途。
  • YOLO11l:大型,在更高的计算量下实现更高的准确性。
  • YOLO11x:超大型,实现最高的准确性和性能。
    在这里插入图片描述

YOLO11 基于 Ultralytics YOLOv8 的代码库构建,并进行了一些架构修改。它还集成了之前 YOLO 版本(如 YOLOv9 和 YOLOv10)的新特性(并对这些特性进行了优化),以提升性能。

三、 YOLO11 的应用

YOLO 主要以其目标检测模型而闻名。然而,和 YOLOv8 一样,YOLO11 可以执行多种计算机视觉任务,包括:

  • 目标检测
  • 实例分割
  • 图像分类
  • 姿态估计
  • 旋转目标检测(OBB)

3.1 目标检测

YOLO11 通过将输入图像传入卷积神经网络(CNN)来提取特征,从而进行目标检测。然后,网络预测网格内目标的边界框和类别概率。为了处理多尺度检测,模型使用不同的层来确保能够检测到各种大小的目标。这些预测结果随后通过非极大值抑制(NMS)进行优化,以过滤掉重复或低置信度的边界框,从而实现更准确的目标检测。YOLO11 在目标检测任务上使用 MS - COCO 数据集进行训练,该数据集包含 80 个预训练类别。
在这里插入图片描述

3.2 实例分割

除了目标检测,YOLO11 还通过添加掩码预测分支扩展到了实例分割任务。这些模型同样在 MS - COCO 数据集上进行训练,包含 80 个预训练类别。该分支为每个检测到的目标生成逐像素的分割掩码,使模型能够区分重叠的目标,并精确描绘出它们的形状轮廓。头部的掩码分支处理特征图并输出目标掩码,从而在图像中实现像素级的目标识别和区分。
在这里插入图片描述

3.3 姿态估计

YOLO11 通过检测和预测目标上的关键点(如人体关节)来进行姿态估计。这些关键点连接起来形成骨骼结构,代表目标的姿态。这些模型在 COCO 数据集上进行训练,该数据集包含一个预训练类别“人”。在头部添加了姿态估计层,网络经过训练来预测关键点的坐标。后续的后处理步骤将这些点连接起来形成骨骼结构,实现实时姿态识别。
在这里插入图片描述

1.鼻子
2.左眼
3.右眼
4.左耳
5.右耳
6.左肩
7.右肩
8.左肘
9.右肘
10.左腕
11.右手腕
12.左髋关节
13.右髋关节
14.左膝
15.右膝盖
16.左脚踝
17.右脚踝

3.5 图像分类

对于图像分类任务,YOLO11 使用其深度神经网络从输入图像中提取高级特征,并将其分配到几个预定义的类别之一。这些模型在 ImageNet 数据集上进行训练,该数据集包含 1000 个预训练类别。网络通过多层卷积和池化处理图像,在降低空间维度的同时增强重要特征。网络顶部的分类头输出预测类别,使其适用于需要识别图像整体类别的任务。
在这里插入图片描述

3.6 旋转目标检测(OBB)

YOLO11 通过引入旋转目标检测(OBB)扩展了常规的目标检测功能,使模型能够检测和分类旋转或不规则方向的目标。这在航空图像分析等应用中特别有用。这些模型在 DOTAv1 数据集上进行训练,该数据集包含 15 个预训练类别。

OBB 模型不仅输出边界框的坐标,还输出旋转角度(θ)或四个角点。这些坐标用于创建与目标方向对齐的边界框,提高旋转目标的检测准确性。
在这里插入图片描述

四、YOLO11 架构及新特性

YOLO11 架构是在 YOLOv8 架构基础上的升级,进行了一些新的集成和参数调整。YOLO11 的配置文件:

# 参数
nc: 80  # 类别数量
scales:  # 模型复合缩放常数,即 'model=yolo11n.yaml' 将调用 yolo11.yaml 并使用缩放 'n'
  # [深度, 宽度, 最大通道数]
  n: [0.50, 0.25, 1024]  # 总结: 319 层, 2624080 个参数, 2624064 个梯度, 6.6 GFLOPs
  s: [0.50, 0.50, 1024]  # 总结: 319 层, 9458752 个参数, 9458736 个梯度, 21.7 GFLOPs
  m: [0.50, 1.00, 512]  # 总结: 409 层, 20114688 个参数, 20114672 个梯度, 68.5 GFLOPs
  l: [1.00, 1.00, 512]  # 总结: 631 层, 25372160 个参数, 25372144 个梯度, 87.6 GFLOPs
  x: [1.00, 1.50, 512]  # 总结: 631 层, 56966176 个参数, 56966160 个梯度, 196.0 GFLOPs

# YOLO11n 主干网络
backbone:
  # [来源, 重复次数, 模块, 参数]
  - [-1, 1, Conv, [64, 3, 2]]  # 0 - P1/2
  - [-1, 1, Conv, [128, 3, 2]]  # 1 - P2/4
  - [-1, 2, C3k2, [256, False, 0.25]]
  - [-1, 1, Conv, [256, 3, 2]]  # 3 - P3/8
  - [-1, 2, C3k2, [512, False, 0.25]]
  - [-1, 1, Conv, [512, 3, 2]]  # 5 - P4/16
  - [-1, 2, C3k2, [512, True]]
  - [-1, 1, Conv, [1024, 3, 2]]  # 7 - P5/32
  - [-1, 2, C3k2, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]]  # 9
  - [-1, 2, C2PSA, [1024]]  # 10

# YOLO11n 头部网络
head:
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 6], 1, Concat, [1]]  # 拼接主干网络的 P4
  - [-1, 2, C3k2, [512, False]]  # 13
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 4], 1, Concat, [1]]  # 拼接主干网络的 P3
  - [-1, 2, C3k2, [256, False]]  # 16 (P3/8 - 小尺度)
  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 13], 1, Concat, [1]]  # 拼接头部的 P4
  - [-1, 2, C3k2, [512, False]]  # 19 (P4/16 - 中尺度)
  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 10], 1, Concat, [1]]  # 拼接头部的 P5
  - [-1, 2, C3k2, [1024, True]]  # 22 (P5/32 - 大尺度)
  - [[16, 19, 22], 1, Detect, [nc]]  # 检测层 (P3, P4, P5)

4.1 主干网络(Backbone)

主干网络是模型从输入图像中多尺度提取特征的部分。它通常通过堆叠卷积层和模块来创建不同分辨率的特征图。
- 卷积层(Conv Layers):YOLO11 具有类似的初始卷积层结构,用于对图像进行下采样:

- [-1, 1, Conv, [64, 3, 2]]  # 0 - P1/2
- [-1, 1, Conv, [128, 3, 2]]  # 1 - P2/4
- **C3k2 模块**:与 YOLOv8 中的 C2f 模块不同,YOLO11 引入了 C3k2 模块,它在计算效率上更高。该模块是 CSP 瓶颈的自定义实现,使用两个卷积层代替一个大的卷积层(如 YOLOv8 中那样)。
- **CSP(跨阶段部分连接)**:CSP 网络将特征图分割,一部分通过瓶颈层处理,另一部分与瓶颈层的输出合并。这减少了计算量并提高了特征表示能力。
- [-1, 2, C3k2, [256, False, 0.25]]
- C3k2 模块还使用了较小的核大小(由 k2 表示),在保持性能的同时提高了速度。
- **SPPF 和 C2PSA**:YOLO11 保留了 SPPF 模块,并在 SPPF 之后添加了新的 C2PSA 模块:
- [-1, 1, SPPF, [1024, 5]]
- [-1, 2, C2PSA, [1024]]
- C2PSA(带空间注意力的跨阶段部分连接)模块增强了特征图中的空间注意力,使模型能够更有效地关注图像中的重要部分。通过对特征进行空间池化,该模块让模型能够更有针对性地聚焦于感兴趣的特定区域。

4.2 颈部网络(Neck)

颈部网络负责聚合不同分辨率的特征,并将其传递给头部进行预测。它通常涉及对不同层次的特征图进行上采样和拼接操作。
- C3k2 模块:YOLO11 用 C3k2 模块取代了颈部网络中的 C2f 模块。如前所述,C3k2 是一个更快、更高效的模块。例如,在进行上采样和拼接操作后,YOLO11 中的颈部网络结构如下:

- [-1, 2, C3k2, [512, False]]  # P4/16 - 中尺度
- 这一改变提高了特征聚合过程的速度和性能。
- **注意力机制**:YOLO11 通过 C2PSA 模块更加注重空间注意力,这有助于模型聚焦于图像中的关键区域,从而实现更准确的检测。而 YOLOv8 中缺少这一机制,这使得 YOLO11 在检测较小或被遮挡的目标时可能更加准确。

4.3 头部网络(Head)

头部网络是模型负责生成最终预测结果的部分。在目标检测任务中,这通常意味着生成边界框并对框内的目标进行分类。
- C3k2 模块:与颈部网络类似,YOLO11 用 C3k2 模块取代了头部网络中的 C2f 模块。

- [-1, 2, C3k2, [512, False]]  # P4/16 - 中尺度
- **检测层(Detect Layer)**:最终的检测层与 YOLOv8 中的相同:
- [[16, 19, 22], 1, Detect, [nc]]  # 检测层 (P3, P4, P5)
- 使用 C3k2 模块使模型在推理速度上更快,并且在参数使用上更加高效。

看看这些新模块(层)在代码中的实现:

C3k2 模块(来自 blocks.py):C3k2 是 CSP 瓶颈的一个更快、更高效的变体。它使用两个卷积层代替一个大的卷积层,从而加快了特征提取的速度。

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

C3k 模块(来自 blocks.py):C3k 是一个更灵活的瓶颈模块,允许自定义核大小。这对于提取图像中更详细的特征非常有用。

class C3k(C3):
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, k=3):
        super().__init__(c1, c2, n, shortcut, g, e)
        c_ = int(c```python
# 计算隐藏通道数
c_ = int(c2 * e)  
# 构建包含一系列瓶颈层的序列
self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, k=(k, k), e=1.0) for _ in range(n)))

C2PSA 模块(来自 blocks.py):C2PSA(具有空间注意力的跨阶段部分模块)增强了模型的空间注意力能力。该模块为特征图添加注意力机制,帮助模型聚焦于图像的重要区域。

class C2PSA(nn.Module):
    def __init__(self, c1, c2, e=0.5):
        super().__init__()
        # 计算隐藏通道数
        c_ = int(c2 * e)
        # 定义 1x1 卷积层 cv1
        self.cv1 = Conv(c1, c_, 1, 1)
        # 定义 1x1 卷积层 cv2
        self.cv2 = Conv(c1, c_, 1, 1)
        # 定义 1x1 卷积层 cv3,用于调整通道数
        self.cv3 = Conv(2 * c_, c2, 1)
    
    def forward(self, x):
        # 对输入特征图 x 进行处理,先通过 cv1 和 cv2 卷积,然后在通道维度上拼接,最后通过 cv3 卷积
        return self.cv3(torch.cat((self.cv1(x), self.cv2(x)), 1))

五、 YOLO11 代码流程

在 ultralytics GitHub 仓库中,主要关注以下内容:

  • nn/modules/ 中的模块
    • block.py
    • conv.py
    • head.py
    • transformer.py
    • utils.py
  • nn/tasks.py 文件

5.1 代码库概述

代码库由多个模块组成,这些模块定义了 YOLO11 模型中使用的各种神经网络组件。这些组件被组织在 nn/modules/ 目录下的不同文件中:

  • block.py:定义了模型中使用的各种构建模块(如瓶颈层、CSP 模块和注意力机制等)。
  • conv.py:包含卷积模块,包括标准卷积、深度可分离卷积和其他变体。
  • head.py:实现了模型的头部,负责生成最终的预测结果(如边界框、类别概率等)。
  • transformer.py:包含基于变压器的模块,用于注意力机制和高级特征提取。
  • utils.py:提供了在各个模块中使用的实用函数和辅助类。

nn/tasks.py 文件定义了不同的特定任务模型(如检测、分割、分类等),这些模型将上述模块组合在一起形成完整的架构。

5.2 nn/modules/ 中的模块

如前所述,YOLO11 基于 YOLOv8 代码库构建。因此,主要关注此处更新的脚本:block.pyconv.pyhead.py

block.py
此文件定义了 YOLO11 模型中使用的各种构建模块。这些模块是构成神经网络层的基本组件。

关键组件:瓶颈层模块(Bottleneck Modules)

  • Bottleneck:一种标准的瓶颈模块,带有可选的快捷连接。
  • Res:一个残差块,使用一系列卷积和恒等快捷连接。
class Bottleneck(nn.Module):
    def __init__(self, c1, c2, shortcut=True, g=1, e=0.5):
        super().__init__()
        # 计算隐藏通道数
        c_ = int(c2 * e)
        # 定义 1x1 卷积层 cv1
        self.cv1 = Conv(c1, c_, 1, 1)
        # 定义 3x3 卷积层 cv2,用于调整通道数并增加特征维度
        self.cv2 = Conv(c_, c2, 3, 1, g=g)
        # 判断是否添加快捷连接
        self.add = shortcut and c1 == c2

    def forward(self, x):
        # ### (续)
如果 `self.add` 为 `True`,则将原始输入 `x` 与经过 `cv1` 和 `cv2` 处理后的输出相加(残差连接);否则,仅返回经过 `cv1` 和 `cv2` 处理后的输出
```python
        return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
  • Bottleneck 类实现了一个瓶颈模块,它先减少通道数(降维),然后再增加通道数。
  • 组件
    • self.cv1:一个 1×1 卷积层,用于减少通道数。
    • self.cv2:一个 3×3 卷积层,用于将通道数恢复到原始数量。
    • self.add:一个布尔值,指示是否添加快捷连接。
  • 前向传播:输入 x 依次通过 cv1cv2。如果 self.addTrue,则将原始输入 x 与输出相加(残差连接)。

CSP(跨阶段部分)模块

  • BottleneckCSP:瓶颈模块的 CSP 版本。
  • CSPBlock:一个更复杂的 CSP 模块,包含多个瓶颈层。
class BottleneckCSP(nn.Module):
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
        super().__init__()
        # 计算隐藏通道数
        c_ = int(c2 * e)
        # 定义 1x1 卷积层 cv1
        self.cv1 = Conv(c1, c_, 1, 1)
        # 定义包含多个瓶颈层的序列 cv2
        self.cv2 = nn.Sequential(
            *[Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)]
        )
        # 定义 1x1 卷积层 cv3,用于调整通道数
        self.cv3 = Conv(2 * c_, c2, 1)
        # 判断是否添加快捷连接
        self.add = c1 == c2

    def forward(self, x):
        # 对输入特征图 x 进行处理,先通过 cv1 卷积,再通过 cv2 中的一系列瓶颈层
        y1 = self.cv2(self.cv1(x))
        # 如果 self.add 为 True,则将原始输入 x 赋值给 y2,否则 y2 为 None
        y2 = x if self.add else None
        # 如果 y2 不为 None,则将 y1 和 y2 在通道维度上拼接,然后通过 cv3 卷积;否则,直接将 y1 通过 cv3 卷积
        return self.cv3(torch.cat((y1, y2), 1)) if y2 is not None else self.cv3(y1)
  • CSPBottleneck 模块将特征图分为两部分。一部分通过一系列瓶颈层,另一部分直接连接到输出,从而降低计算成本并增强梯度流。
  • 组件
    • self.cv1:减少通道数。
    • self.cv2:一系列瓶颈层。
    • self.cv3:合并特征并调整通道数。
    • self.add:确定是否添加快捷连接。

其他模块

  • SPPF:快速空间金字塔池化模块,可在多个尺度上进行池化操作。
  • Concat:沿指定维度连接多个张量。
class SPPF(nn.Module):
    def __init__(self, c1, c2, k=5):
        super().__init__()
        # 计算中间通道数
        c_ = c1 // 2
        # 定义 1x1 卷积层 cv1
        self.cv1 = Conv(c1, c_, 1, 1)
        # 定义 1x1 卷积层 cv2,用于调整通道数
        self.cv2 = Conv(c_ * 4, c2, 1, 1)
        # 定义最大池化层 m
        self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)

    def forward(self, x):
        # 对输入特征图 x 进行处理,先通过 cv1 卷积
        x = self.cv1(x)
        # 对 x 进行最大池化操作得到 y1
        y1 = self.m(x)
        # 对 y1 进行最大池化操作得到 y2
        y2 = self.m(y1)
        # 对 y2 进行最大池化操作得到 y3
        y3 = self.m(y2)
        # 将 x、y1、y2 和 y3 在通道维度上拼接,然后通过 cv2 卷积
        return self.cv2(torch.cat([x, y1, y2, y3], 1))
  • SPPF 模块在不同尺度上执行最大池化,并将结果连接起来,以捕获多个空间尺度的特征。
  • 组件
    • self.cv1:减少通道数。
    • self.cv2:在连接后调整通道数。
    • self.m:最大池化层。
  • 前向传播:输入 x 先通过 cv1,然后经过三个连续的最大池化层(y1y2y3)。结果被连接起来并通过 cv2

conv.py
此文件包含各种卷积模块,包括标准卷积和特殊卷积。

关键组件:标准卷积模块(Conv)

class Conv(nn.Module):
    # 默认激活函数为 SiLU
    default_act = nn.SiLU()

    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True):
        super().__init__()
        # 定义卷积层 conv
        self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False)
        # 定义批量归一化层 bn
        self.bn = nn.BatchNorm2d(c2)
        # 根据 act 参数确定激活函数
        self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()

    def forward(self, x):
        # 对输入特征图 x 进行处理,先通过 conv 卷积,再通过 bn 批量归一化,最后通过 act 激活函数
        return self.act(self.bn(self.conv(x)))
  • 实现一个带有批量归一化和激活函数的标准卷积层。
  • 组件
    • self.conv:卷积层。
    • self.bn:批量归一化层。
    • self.act:激活函数(默认是 nn.SiLU())。
  • 前向传播:依次进行卷积、批量归一化和激活操作。

深度可分离卷积(DWConv)

class DWConv(Conv):
    def __init__(self, c1, c2, k=1, s=1, d=1, act=True):
        super().__init__(c1, c2, k, s, g=math.gcd(c1, c2), d=d, act=act)
  • 执行深度可分离卷积,其中每个输入通道单独进行卷积。
  • 组件
    • 继承自 Conv
    • groups 参数设置为 c1c2 的最大公约数,从而实现按通道分组卷积。

其他卷积模块

  • Conv2RepConv 的简化版本,用于模型压缩和加速。
  • GhostConv:实现 GhostNet 的幽灵模块,减少特征图中的冗余。
  • RepConv:可重新参数化的卷积层,可从训练模式转换为推理模式。

head.py
此文件实现了负责生成模型最终预测结果的头部模块。

关键组件:检测头部(Detect)

class Detect(nn.Module):
    def __init__(self, nc=80, ch=()):
        super().__init__()
        # 类别数量
        self.nc = nc
        # 检测层的数量
        self.nl = len(ch)
        # DFL 通道数
        self.reg_max = 16
        # 每个锚点的输出数量
        self.no = nc + self.reg_max * 4
        # 步长,在构建过程中计算
        self.stride = torch.zeros(self.nl)

        # 定义层
        self.cv2 = nn.ModuleList(
            nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3), nn.Conv2d(c2, 4 * self.reg_max, 1)) for x in ch
        )
        self.cv3 = nn.ModuleList(
            nn.Sequential(
                nn.Sequential(DWConv(x, x, 3), Conv(x, c3, 1)),
                nn.Sequential(DWConv(c3, c3, 3), Conv(c3, c3, 1)),
                nn.Conv2d(c3, self.nc, 1),
            )
            for x in ch
        )
        # 如果 reg_max 大于 1,则使用 DFL 模块进行边界框细化;否则,使用恒等映射
        self.dfl = DFL(self.reg_max) if self.reg_max > 1 else nn.Identity()
  • Detect 类定义了输出边界框坐标和类别概率的检测头部。
  • 组件
    • self.cv2:用于边界框回归的卷积层。
    • self.cv3:用于分类的卷积层。
    • self.dfl:用于边界框细化的分布焦点损失模块。
  • 前向传播:处理输入特征图并输出边界框和类别的预测结果。

分割头部(Segment)

class Segment(Detect):
    def __init__(self, nc=80, nm=32, npr=256, ch=()):
        super().__init__(nc, ch)
        # 掩码数量
        self.nm = nm
        # 原型数量
        self.npr = npr
        # 生成掩码原型的模块
        self.proto = Proto(ch[0], self.npr, self.nm)

        # 计算通道数 c4
        c4 = max(ch[0] // 4, self.nm)
        self.cv4 = nn.ModuleList(nn.Sequential(Conv(x, c4, 3), Conv(c4, c4, 3), nn.Conv2d(c4, self.nm, 1)) for x in ch)
  • 继承自 Detect 类,增加了分割功能。
  • 组件
    • self.proto:生成掩码原型。
    • self.cv4:用于掩码系数的卷积层。
  • 前向传播:输出边界框、类别概率和掩码系数。

姿态估计头部(Pose)

class Pose(Detect):
    def __init__(self, nc=80, kpt_shape=(17, 3), ch=()):
        super().__init__(nc, ch)
        # 关键点形状(关键点数量,每个关键点的维度)
        self.kpt_shape = kpt_shape
        # 关键点输出的总数
        self.nk = kpt_shape[0] * kpt_shape[1]

        # 计算通道数 c4
        c4 = max(ch[0] // 4, self.nk)
        self.cv4 = nn.ModuleList(nn.Sequential(Conv(x, c4, 3), Conv(c4, c4, 3), nn.Conv2d(c4, self.nk, 1)) for x in ch)
  • 继承自 Detect 类,用于人体姿态估计任务。
  • 组件
    • self.kpt_shape:关键点的形状(关键点数量,每个关键点的维度)。
    • self.cv4:用于关键点回归的卷积层。
  • 前向传播:输出边界框、类别概率和关键点坐标。

5. 3. nn/tasks.py

nn/tasks.py 是执行所有 YOLO11 模型以完成计算机视觉任务的主代码,包括检测、分割、姿态估计和分类模型。

# 这是原始脚本的简化版本
class BaseModel(nn.Module):
    # YOLOv8 模型的基础模型类
    def forward(self, x, *args, **kwargs):
        # 前向传播:处理训练(损失)和推理(预测)
        if isinstance(x, dict):
            return self.loss(x, *args, **kwargs)  # 训练:计算损失
        return self.predict(x, *args, **kwargs)  # 推理:进行预测

class DetectionModel(BaseModel):
    # YOLOv8 检测模型类
    def __init__(self, cfg="yolov8n.yaml", ch=3, nc=None, verbose=True):
        super().__init__()
        # 模型设置(配置解析、层设置等)
        self.yaml = cfg if isinstance(cfg, dict) else yaml_model_load(cfg)
        self.model, self.save = parse_model(deepcopy(self.yaml), ch=ch, verbose=verbose)
        # 步长和偏置初始化(为简洁起见省略细节)
        m = self.model[-1]
        if isinstance(m, Detect):
            s = 256
            m.stride = torch.tensor([s / x.shape[-2] for x in self._predict_once(torch.zeros(1, ch, s, s))])
            self.stride = m.stride
            m.bias_init()

class SegmentationModel(DetectionModel):
    # YOLOv8 分割模型类
    def __init__(self, cfg="yolov8n - seg.yaml", ch=3, nc=None, verbose=True):
        super().__init__(cfg=cfg, ch=ch, nc=nc, verbose=verbose)

    def init_criterion(self):
        # 返回特定于分割的损失函数
        return v8SegmentationLoss(self)

class PoseModel(DetectionModel):
    # YOLOv8 姿态估计模型类
    def __init__(self, cfg="yolov8n - pose.yaml", ch=3, nc=None, data_kpt_shape=(None, None), verbose=True):
        if not isinstance(cfg, dict):
            cfg = yaml_model_load(cfg)
        if list(data_kpt_shape) != list(cfg["kpt_shape"]):
            cfg["kpt_shape"] = data_kpt_shape
        super().__init__(cfg=cfg, ch=ch, nc=nc, verbose=verbose)

    def init_criterion(self):
        # 返回特定于姿态估计的损失函数
        return v8PoseLoss(self)

class ClassificationModel(BaseModel):
    # YOLOv8 分类模型类
    def __init__(self, cfg="yolov8n - cls.yaml", ch=3, nc=None, verbose=True):
        super().__init__()
        self._from_yaml(cfg, ch, nc, verbose)

    def _from_yaml(self, cfg, ch, nc, verbose):
        # 解析配置并设置模型层
        self.yaml = cfg if isinstance(cfg, dict) else yaml_model_load(cfg)
        self.model, self.save = parse_model(deepcopy(self.yaml), ch=ch, verbose=verbose)
        self.names = {i: f"{i}" for i in range(self.yaml["nc"])}

class Ensemble(nn.ModuleList):
    # 集成类,用于合并多个模型的输出
    def __init__(self):
        super().__init__()

    def forward(self, x, augment=False, profile=False, visualize=False):
        # 集成的前向传播,合并所有模型的输出
        y = [module(x, augment, profile, visualize)[0] for module in self]
        return torch.cat(y, 2), None

代码首先定义了 BaseModel 类,它作为所有模型的基础,其 forward 方法可处理训练(通过损失函数)和推理(通过预测函数)。DetectionModel 类继承自 BaseModel,专门用于目标检测,通过 fuse 方法实现步长初始化和层融合以提高效率。SegmentationModelPoseModel 进一步继承自 DetectionModel,分别添加了分割和姿态估计任务的特定功能,并且各自初始化了像 v8SegmentationLossv8PoseLoss 这样的损失函数。ClassificationModel 处理分类任务,并根据类别数量(nc)重塑输出层。此外,还包含了 Ensemble 类,用于合并多个模型的输出。辅助函数如 parse_modelyaml_model_loadfuse_conv_and_bn 用于模型解析、配置加载和推理层优化。

六、YOLO11 推理

使用来自 Ultralytics GitHub 的 YOLO11 预训练权重进行推理实验。要进行推理,需要使用以下命令克隆 Ultralytics 仓库:

git clone https://github.com/ultralytics/ultralytics.git
cd ultralytics

然后,使用以下命令设置环境:

conda create -n yolo11 python=3.11
conda activate yolo11
pip install ultralytics

6.1 目标检测

目标检测:

yolo detect predict model=yolo11x.pt source='./path/to/your/video.mp4' save=True classes=[0]

6.2 实例分割

对于实例分割,运行以下命令:

yolo segment predict model=yolo11x.pt source='./path/to/your/video.mp4' save=True classes=[0]

6.3 姿态估计

对于姿态估计,运行:

yolo pose predict model=yolo11x-pose.pt source='./path/to/your/video.mp4' save=True classes=[0]

6.4 旋转目标检测(OBB)

运行以下命令:

yolo obb predict model=yolo11x-obb.pt source='./path/to/your/video.mp4' save=True

七、 YOLO11 与 YOLOv10 对比

从图表上看,似乎 YOLO11l 和 YOLO11x 比 YOLOv10 慢,而 YOLO11n 和 YOLOv10n 速度相同。那么,为什么不通过实际对比这两个模型来消除争议呢?

所以,将比较 YOLO11 和最新发布的 YOLOv10,并查看两者的性能基准。在 Nvidia Geforce RTX 4060 笔记本 GPU 上运行了所有推理。

首先,将比较 YOLOv10n(2.3M 参数)和 YOLO11n(2.6M 参数)模型在同一个视频上进行推理,并比较了延迟和帧率。以下是为你提供的基准测试结果:

  • YOLOv11n
    • 速度:预处理 1.4ms,推理 3.9ms,后处理 1.2ms(每张图像,形状为 (1, 3, 384, 640))
    • FPS(推理):256
  • YOLOv10n
    • 速度:预处理 1.4ms,推理 4.5ms,后处理 0.4ms(每张图像,形状为 (1, 3, 384, 640))
    • FPS(推理):222

现在,将比较 YOLOv10x(29.5M 参数)和 YOLO11x(56.9M 参数)。在同一个视频上进行推理,并比较了延迟和帧率。得到的基准测试结果如下:

  • YOLOv11x
    • 速度:预处理 1.4ms,推理 18.5ms,后处理 1.6ms(每张图像,形状为 (1, 3, 384, 640))
    • FPS(推理):54
  • YOLOv10x
    • 速度:预处理 1.4ms,推理 16.8ms,后处理 0.6ms(每张图像,形状为 (1, 3,384, 640))
    • FPS(推理):59

对于n模型,YOLO11 即使参数更多但表现更好。此外,和 YOLOv10 一样,Ultralytics 团队计划很快推出端到端模型。
在这里插入图片描述

八、总结

  1. 轻量高效:YOLO11 是 YOLO 家族中最轻量且最快的模型。它具有五种不同尺寸(微小、小型、中型、大型和超大型),适用于从轻量级任务到高性能应用的各种用例。
  2. 新架构:YOLO11 引入了如 C3k2 模块、SPPF 和 C2PSA 等新的架构改进,使模型在提取和处理特征方面更高效,并增强了对图像关键区域的关注。
  3. 多任务能力:除了目标检测,YOLO11 还能处理实例分割、图像分类、姿态估计和旋转目标检测(OBB),使其在计算机视觉任务中具有高度通用性。
  4. 增强的注意力机制:架构中像 C2PSA 这样的空间注意力机制的集成,帮助 YOLO11 更有效地聚焦于图像中的关键区域,提高了其检测准确性,特别是对于复杂或遮挡的物体。
  5. 基准优势:与 YOLOv10 直接比较,YOLO11 表现出更优越的性能,特别是在n模型系列中。尽管参数更多,但 YOLO11n 在推理速度和 FPS 方面优于 YOLOv10n,使其成为实时应用中高效的模型,且不牺牲准确性或计算效率。
### 配置 YOLOv11 使用 CUDA 对于配置YOLOv11使用CUDA的过程,当前的信息主要集中在YOLOv5的配置上。然而,可以推测YOLOv11的配置流程可能此相似。 #### 创建Anaconda虚拟环境并激活 为了确保依赖项不会其他项目冲突,建议创建一个新的Anaconda虚拟环境,并指定Python版本为3.8: ```bash conda create -n yolov11 python=3.8 conda activate yolov11 ``` #### 安装PyTorch及其依赖库 考虑到不同版本的CUDA对应特定版本的PyTorch,在安装前需确认所使用的GPU支持哪个版本的CUDA。假设目标是使用CUDA 11.x,则应按照如下方式安装兼容版次的PyTorch: 如果采用的是类似于RTX 3060或RTX 3070这样的较新型号显卡,推荐尝试最新的稳定版CUDA(比如11.8),此时可执行以下命令来获取相应版本的PyTorch包[^3]: ```bash pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu118/ ``` 请注意,上述URL中的`cu118`代表CUDA 11.8;如果有其他需求或者不同的硬件条件,请调整此参数以匹配实际可用的CUDA版本。 #### 下载YOLOv11源码 由于官方并未提供名为“YOLOv11”的模型,这里假定是指向某个基于YOLO架构改进后的变体或是社区开发的新版本。通常情况下,可以从GitHub仓库或其他公开资源处克隆该项目至本地机器: ```bash git clone https://github.com/someone/yolov11.git cd yolov11 ``` 请替换上面链接中的`https://github.com/someone/yolov11.git`为你想要部署的具体YOLOv11项目的地址。 #### 设置环境变量 为了让程序能够找到已安装好的CUDA工具链,默认情况下Windows系统的路径应该已经包含了必要的目录。但对于某些特殊情况而言,可能还需要手动设置一些额外的环境变量指向CUDA SDK的位置。例如,在Windows环境下可以通过编辑系统属性->高级系统设置->环境变量来进行操作,添加类似下面的内容到PATH中去[^2]: ``` C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\bin; C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\libnvvp; ... ``` 以上步骤完成后重启计算机使更改生效即可。 #### 测试安装情况 最后一步就是验证整个环境是否搭建成功。可以在命令提示符下运行简单的测试脚本来检查PyTorch能否正常调用GPU加速功能: ```python import torch print(torch.cuda.is_available()) print(torch.__version__) ``` 这段代码会打印出True表示存在可用的CUDA设备以及PyTorch的实际版本号。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知来者逆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值