3. 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')
运行与验证
- 安装依赖:
pip install ultralytics torch - 执行脚本:
python parse_yolov11.py - 通过条件:脚本正常输出各层名称与输出形状,且总参数量约为2.6M(yolo11n),Backbone占比约60%,Neck约25%,Head约15%。若输出维度中P3层为(1,64,80,80)、P5层为(1,128,20,20)等,说明结构解析正确。
结构可视化
常见问题
- 模型文件不存在:首次运行会自动下载yolo11n.pt,需保持网络畅通;也可手动下载后放置于脚本同目录。
- 参数量划分差异:不同版本YOLOv11的模块编号可能微调,若打印的模块路径与预期不符,可先打印完整结构后根据实际模块名调整划分逻辑。
- 后续剪枝关注点:Backbone中C3k2的bottleneck层与Neck中C3k2层是剪枝的主要候选,因其包含大量3×3卷积,冗余度较高。