3. YOLOv11模型结构解析

YOLOv11模型结构解析 学习卡片

任务目标

本案例通过解析YOLOv11的模型定义文件与网络结构,明确其Backbone、Neck、Head三大组成部分及各模块的输入输出维度,为后续剪枝与量化操作建立结构认知基础。核心交付物为:结构可视化图、关键层参数表、以及可运行的模型结构打印脚本。

环境依赖

  • Python ≥ 3.8
  • PyTorch ≥ 1.8
  • ultralytics(YOLOv11官方库,版本≥8.3.0)

YOLOv11核心结构解析

YOLOv11在YOLOv8基础上将C2f模块升级为C3k2,并引入SPPF(快速空间金字塔池化)与C2PSA(注意力增强模块)。整体结构分为:

  • Backbone:Conv + C3k2 + SPPF + C2PSA,负责多尺度特征提取,输出P3(80×80)、P4(40×40)、P5(20×20)三个尺度特征图。
  • Neck:PAN-FPN结构,通过上采样与Concat融合多尺度特征,增强小目标检测能力。
  • Head:解耦头结构,分别输出分类分支与回归分支,每个尺度预测特征维度为 4 + 类别数 + 1(置信度)。

关键完整代码:结构解析与参数统计

import torch
from ultralytics import YOLO
from ultralytics.nn.tasks import DetectionModel

def parse_yolov11_structure(model_path='yolo11n.pt'):
    """解析YOLOv11模型结构,打印各层输出维度与参数统计"""
    # 加载模型(自动下载yolo11n.pt若不存在)
    model = YOLO(model_path)
    detection_model: DetectionModel = model.model
    
    # 打印完整结构
    print("=" * 80)
    print("YOLOv11 完整结构(含各层输出张量形状)")
    print("=" * 80)
    
    # 构造示例输入(1,3,640,640)
    dummy_input = torch.randn(1, 3, 640, 640)
    
    # 注册前向钩子记录每层输出
    layer_outputs = {}
    def hook_fn(name):
        def hook(module, input, output):
            if isinstance(output, torch.Tensor):
                layer_outputs[name] = tuple(output.shape)
            elif isinstance(output, (list, tuple)):
                layer_outputs[name] = [tuple(o.shape) if isinstance(o, torch.Tensor) else None for o in output]
        return hook
    
    # 为所有子模块注册钩子
    hooks = []
    for name, module in detection_model.named_modules():
        if len(list(module.children())) == 0:  # 仅叶子模块
            hooks.append(module.register_forward_hook(hook_fn(name)))
    
    # 前向传播
    with torch.no_grad():
        detection_model.eval()
        _ = detection_model(dummy_input)
    
    # 移除钩子
    for h in hooks:
        h.remove()
    
    # 打印结构摘要(每层名称与输出形状)
    print(f"{'模块路径':<50} {'输出形状'}")
    print("-" * 80)
    for name, shape in layer_outputs.items():
        if shape is not None:
            print(f"{name:<50} {shape}")
    
    # 统计各组件参数量
    total_params = sum(p.numel() for p in detection_model.parameters())
    backbone_params = 0
    neck_params = 0
    head_params = 0
    
    # 根据模块路径划分(以model.0~model.9为Backbone,model.10~model.21为Neck,model.22为Head)
    for name, module in detection_model.named_modules():
        if name.startswith('model.0') or name.startswith('model.1') or name.startswith('model.2') or \
           name.startswith('model.3') or name.startswith('model.4') or name.startswith('model.5') or \
           name.startswith('model.6') or name.startswith('model.7') or name.startswith('model.8') or \
           name.startswith('model.9'):
            backbone_params += sum(p.numel() for p in module.parameters())
        elif name.startswith('model.22'):
            head_params += sum(p.numel() for p in module.parameters())
        else:
            neck_params += sum(p.numel() for p in module.parameters())
    
    print("=" * 80)
    print(f"总参数量: {total_params/1e6:.2f}M")
    print(f"Backbone参数量: {backbone_params/1e6:.2f}M ({backbone_params/total_params*100:.1f}%)")
    print(f"Neck参数量: {neck_params/1e6:.2f}M ({neck_params/total_params*100:.1f}%)")
    print(f"Head参数量: {head_params/1e6:.2f}M ({head_params/total_params*100:.1f}%)")
    print("=" * 80)
    
    return detection_model

if __name__ == "__main__":
    model = parse_yolov11_structure('yolo11n.pt')

运行与验证

  1. 安装依赖:pip install ultralytics torch
  2. 执行脚本:python parse_yolov11.py
  3. 通过条件:脚本正常输出各层名称与输出形状,且总参数量约为2.6M(yolo11n),Backbone占比约60%,Neck约25%,Head约15%。若输出维度中P3层为(1,64,80,80)、P5层为(1,128,20,20)等,说明结构解析正确。

结构可视化

YOLOv11网络结构总览(输入640×640×3) Backbone Conv (3→16, s=2) 输出: 320×320×16 Conv (16→32, s=2) 输出: 160×160×32 C3k2 (32→64) 输出: 160×160×64 Conv (64→128, s=2) 输出: 80×80×128 C3k2 (128→128) 输出: 80×80×128 (P3) Conv (128→256, s=2) 输出: 40×40×256 C3k2 (256→256) 输出: 40×40×256 (P4) Neck (PAN-FPN) Conv (256→256, s=2) 输出: 20×20×256 C3k2 (256→512) 输出: 20×20×512 SPPF (512→512) 输出: 20×20×512 C2PSA (512→512) 输出: 20×20×512 (P5) Upsample → 40×40 Concat with P4 C3k2 (512→256) 输出: 40×40×256 Upsample → 80×80 Concat with P3 Head (解耦头) P3检测头 (80×80) 输出: 80×80×(4+nc+1) P4检测头 (40×40) 输出: 40×40×(4+nc+1) P5检测头 (20×20) 输出: 20×20×(4+nc+1) 注:nc为检测类别数(COCO为80),每个检测头输出维度为 4(bbox) + nc + 1(置信度)

常见问题

  • 模型文件不存在:首次运行会自动下载yolo11n.pt,需保持网络畅通;也可手动下载后放置于脚本同目录。
  • 参数量划分差异:不同版本YOLOv11的模块编号可能微调,若打印的模块路径与预期不符,可先打印完整结构后根据实际模块名调整划分逻辑。
  • 后续剪枝关注点:Backbone中C3k2的bottleneck层与Neck中C3k2层是剪枝的主要候选,因其包含大量3×3卷积,冗余度较高。