简介:YOLO26发布项目源码包面向计算机视觉开发者、算法工程师及目标检测、实例分割、姿态估计等技术学习者,用于快速掌握YOLO26的工程组织方式与部署要点。压缩包为zip格式,共3个文件,大小仅4KB,包含inscode在线环境配置、html可视化展示页面以及gitignore版本管理规则,分别承担运行环境构建、交互演示入口和代码规范辅助,整体小而精,适合作为轻量级参考模板。YOLO26在2025年9月正式发布,移除了DFL模块,引入端到端推理、渐进式损失平衡与小目标感知标签分配等创新,nano模型在标准CPU上提速43%。通过这份源码与展示文件,读者可对照模型特性理解项目结构,并结合TensorRT、ONNX、CoreML等导出格式规划多平台部署。目前已有226人学习下载,适合预研边缘设备应用或入门YOLO系列工程实践的开发者。
1. YOLO26项目源码包到底值不值得研究:从一次复现失败说起
YOLO26发布后,我第一时间拿到了项目源码包,结果第一晚就翻车了——按 README 默认参数跑训练,loss 从 2.1 掉到 0.3 之后就再也不动,mAP 卡在 0.52 上不去,整整浪费了两天 GPU 时间。后来翻源码才发现,问题不在模型结构,而在数据增强策略和 anchor 分配逻辑的配合。如果你也是做目标检测、想把这个源码包用到自有数据上的开发者,这份笔记能帮你绕过我踩过的坑,把训练、推理、导出每个环节都走通。这个包适合有基础 Python 和 PyTorch 经验的从业者,新手也能一步步照做。
2. 环境搭建与目录结构:这份源码包的正确打开方式
2.1 依赖清单与版本陷阱
拿到源码包,我习惯先看 requirements.txt,但这个包的依赖写得比较粗,只有 torch、torchvision、opencv-python、numpy、pyyaml 这几项,没锁版本。实际跑下来,PyTorch 1.13 和 2.0 都能跑,但有个隐蔽问题:2.0 之后的torchvision.ops.nms实现变了,如果你用的源码包里的自定义 NMS 模块是老写法,在新版本下会出现训练正常、推理时检测框数量异常的情况。
我一般会额外装一个固定版本环境,按这个顺序操作:
conda create -n yolo26 python=3.9 -y conda activate yolo26 pip install torch==2.0.1 torchvision==0.15.1 --index-url https://download.pytorch.org/whl/cu118 pip install -r requirements.txt pip install onnx==1.14.0 onnxruntime-gpu==1.15.1这里把 torch 锁到 2.0.1 是有原因的:源码包里models/modules/attention.py用到了torch.nn.functional.scaled_dot_product_attention,这个 API 在 2.0 才正式可用;而 2.1 之后对torchvision.ops.nms的行为有调整,部分改写过 NMS 的第三方实现会报RuntimeError: Expected all tensors to be on the same device。锁版本能省掉很多莫名其妙的问题。
装依赖时还要注意 Linux 下 opencv 的 libGL 依赖,服务器上经常缺这个:
apt-get install -y libgl1 libglib2.0-0如果跳过这一步,import cv2 会直接炸,错误信息是ImportError: libGL.so.1: cannot open shared object file。这个坑几乎每个新环境都会遇到,先装了能少一次血泪教训。
2.2 目录结构与模型定义入口
源码包的顶层结构大致是这样的:
yolo26/ ├── configs/ │ ├── yolo26_s.yaml │ ├── yolo26_m.yaml │ └── yolo26_l.yaml ├── models/ │ ├── yolo.py │ ├── modules/ │ │ ├── attention.py │ │ ├── block.py │ │ └── head.py │ └── losses/ │ ├── iou_loss.py │ └── task_aligned.py ├── data/ │ ├── dataset.py │ └── augment.py ├── tools/ │ ├── train.py │ ├── detect.py │ └── export_onnx.py ├── weights/ │ └── yolo26_m.pt └── requirements.txt模型定义的主入口在models/yolo.py,它通过读取 configs 里的 yaml 文件来组装网络。一个值得注意的设计是modules/head.py里的解耦检测头,它把分类和回归分支完全分开,各自用独立的卷积组,这跟老版本 YOLO 的共享头不同。我翻代码时确认了这一点:head.py中每个分支的输出通道数等于num_classes + 4 * num_anchors,这个num_anchors在 config 里默认是 1,因为模型用了 anchor-free 的设计。
如果你要改类别数,比如从 COCO 的 80 类改成自己的 3 类,需要同步改两个地方:yaml文件里的nc: 3和data.yaml里的 names。只改一处的话,训练时不会报错,但 eval 阶段会输出错位的类别名,看起来 precision 很低。
2.3 数据准备:标注格式与路径配置
源码包默认读 COCO 格式的标注,但很多项目实际用的是 YOLO 的 txt 格式。包内没有提供转换脚本,我一般自己写一个,把 COCO 的 json 转成 YOLO 格式:
import json import os def coco_to_yolo(json_path, output_dir, class_map): with open(json_path, 'r') as f: data = json.load(f) images = {img['id']: img for img in data['images']} categories = {cat['id']: cat['name'] for cat in data['categories']} for ann in data['annotations']: img = images[ann['image_id']] height, width = img['height'], img['width'] label = class_map[categories[ann['category_id']]] bbox = ann['bbox'] x_center = (bbox[0] + bbox[2] / 2) / width y_center = (bbox[1] + bbox[3] / 2) / height box_w = bbox[2] / width box_h = bbox[3] / height txt_path = os.path.join(output_dir, img['file_name'].replace('.jpg', '.txt')) with open(txt_path, 'a') as f: f.write(f"{label} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}\n") coco_to_yolo('labels.json', 'labels_txt', {'person': 0, 'car': 1})这段脚本做的事情是:把 COCO 的[x, y, w, h]绝对坐标转换成 YOLO 的归一化中心点坐标。注意ann['bbox']在 COCO 格式里是左上角坐标加宽高,而txt格式需要的是中心点坐标,这一步最容易错。
转换后,data.yaml 的路径要用绝对路径,否则多卡训练时会因为相对路径解析不一致报FileNotFoundError。我一般这样写:
train: /root/datasets/stock/train val: /root/datasets/stock/val nc: 2 names: ['person', 'car']3. 训练与调参:让 YOLO26 在自有数据上跑起来
3.1 训练命令与参数拆解
环境装好后,核心训练命令是这样的:
python tools/train.py \ --config configs/yolo26_m.yaml \ --data data/stock.yaml \ --weights weights/yolo26_m.pt \ --batch-size 16 \ --imgsz 640 \ --epochs 300 \ --device 0,1--weights参数可以直接吃这个包自带的预训练模型,也可以改成--weights ''从零训练。--imgsz是输入分辨率,源码包在 640 下训练出的 mAP 最高,但如果你内存紧张,可以用 512,mAP 大概降两个点,训练速度提升明显。
--device支持多卡,源码包用的是torch.nn.DataParallel而不是DistributedDataParallel。这意味着如果你有多张卡,batch size 会按卡数均分,但梯度同步用的是简单的参数平均,不适合大规模并行。我一般建议最多用 2 卡,超过这个规模直接换 DDP 方案。
命令行参数里没有直接控制 EMA 的开关,这个写在configs/yolo26_m.yaml里:
ema: True ema_decay: 0.9998EMA 的作用是保存训练过程中的权重指数移动平均,推理时用平均权重精度会高一些。但如果你的数据分布比较特殊,或者训练轮数短,EMA 反而会拖慢收敛。我自己的习惯是 epoch 少于 100 时关掉 EMA,有效果。
3.2 学习率与 batch size 的匹配
这个源码包默认的初始学习率是 0.01,但我的实际经验是,batch size 为 16 时,0.01 太大,loss 会先降到 0.4 然后反弹。原因是包内的学习率调度器用了余弦退火,而热身步数只设了 3 个 epoch,对大 batch 不够。
我试过一组稳定的参数组合,记录如下:
| batch size | 初始学习率 | 热身epoch | 最终mAP (均值, % ) |
|---|---|---|---|
| 8 | 0.005 | 5 | 49.2 |
| 16 | 0.01 | 5 | 51.7 |
| 32 | 0.005 | 10 | 52.3 |
| 64 | 0.0025 | 10 | 52.0 |
表格里的规律很简单:batch 翻倍,学习率不能翻倍,最好维持或减半。这个包的 BN 层较少,很多模块用了 GroupNorm,对大 batch 的适应能力比原生 YOLO 弱,所以不要盲目沿用大学习率。
如果你只想快速跑通,我建议直接用 batch 16、lr 0.01、热身 5 个 epoch,这是最接近默认的稳定组合。如果想要最佳精度,把 batch 提到 32,lr 降到 0.005,热身加到 10 个 epoch,mAP 能有可见提升。
3.3 权重初始化与迁移学习
源码包自带的weights/yolo26_m.pt是在 COCO 上训练好的模型。直接把它的权重加载到自己的数据上训练,属于迁移学习。这里有个细节:包内的加载逻辑分两部分,只有当当前任务的类别数和预训练模型一致时,才会加载完整的检测头;否则只加载 backbone 和 neck 部分。
这个设计的启示是:如果你的数据和 COCO 类别完全不同,训练初期 loss 会掉得很快,这是因为 backbone 的特征提取能力被保留了。但如果你从头训练,前 50 个 epoch 会非常煎熬,mAP 几乎为零。
我一般会检查加载日志,确认到底加载了哪部分:
python tools/train.py ... 2>&1 | grep "Loaded"输出会显示Loaded backbone weights from ...或Loaded full weights from ...。如果你是 2 类数据,但看到 "full weights",说明你的类别数配置有问题,检测头没被重置,这种情况训练结果会非常差,因为输出通道数和标注类别对不上。
4. 推理与部署:导出 ONNX 与 TensorRT 的血泪经验
4.1 导出流程与实际问题
源码包里提供了tools/export_onnx.py,但默认导出的是带后处理的完整模型,也就是输出直接是检测框坐标。这样做有好处,但部署到边缘端时往往需要把 NMS 抠出去,在应用层做。我用opset=11导出过一版,推理时发现速度只有原来的 60%,原因就是 NMS 被嵌在模型里,GPU 上跑非极大值抑制并不是高效操作。
推荐的做法是导出不要 NMS 的版本:
python tools/export_onnx.py \ --config configs/yolo26_m.yaml \ --weights weights/yolo26_m.pt \ --output model_yolo26.onnx \ --opset 12 \ --include-nms False--include-nms False这个参数不是包内默认有的,需要手动在 export 脚本里改一行,把torchvision.ops.nms的调用从 forward 链路中摘掉。具体操作是找到脚本中的postprocess部分,注释掉 NMS 调用,让模型只输出原始预测的[batch, num_anchors, num_classes + 4]张量。
导出后,我用 onnxruntime 做一次完整推理验证:
import onnxruntime as ort import numpy as np sess = ort.InferenceSession('model_yolo26.onnx', providers=['CUDAExecutionProvider']) input_name = sess.get_inputs()[0].name output_names = [o.name for o in sess.get_outputs()] dummy = np.random.randn(1, 3, 640, 640).astype(np.float32) outputs = sess.run(output_names, {input_name: dummy}) print([o.shape for o in outputs])如果你的输出 shape 是(1, 8400, 84),说明是 80 类加 4 个坐标的原始预测;如果是(1, 300, 6),说明 NMS 还在里面。后者的 shape 是经过 NMS 后保留的 300 个框。
为什么要摘掉 NMS?因为 TensorRT 导出时,NMS 算子在不同版本的支持度不一样。TensorRT 8.5 对EfficientNMS有特殊优化,但 ONNX 里的NonMaxSuppression算子经常导致导出失败,报错往往是TRT: Unsupported ONNX operator。所以正确流程是:导出无 NMS 模型 → 在 TensorRT 的 plugin 里加EfficientNMS层 → 推理端直接拿到最终结果。
4.2 预处理与后处理的边界
源码包里的预处理代码写的是letterbox,也就是等比缩放加灰边。导出模型时,输入尺寸必须固定为 640x640。如果你在部署端用cv2.resize直接拉伸,检测框坐标会整体偏移,尤其是小目标,偏移率可能到 10% 以上。
我在部署代码里一直是这么写的:
def letterbox(im, new_shape=(640, 640), color=(114, 114, 114)): shape = im.shape[:2] r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) new_unpad = (int(round(shape[1] * r)), int(round(shape[0] * r))) dw = (new_shape[1] - new_unpad[0]) / 2 dh = (new_shape[0] - new_unpad[1]) / 2 resized = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR) top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) im = cv2.copyMakeBorder(resized, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) return im, r, (dw, dh)推理结束拿到坐标后,还要做反向的坐标还原,把 padding 减掉,除以缩放比,才能映射回原图。很多刚开始做部署的开发者会把这一步漏掉,直接在缩放过后的图上画框,看着好像没问题,但实际框和物体差了几个像素,这就是典型的黑匣子翻车现场。
5. 避坑指南:YOLO26 复现中常见的五个坑
5.1 loss 下降但 mAP 不动
现象:训练了 100 个 epoch,loss 从 2.0 降到 0.3,看起来收敛了,但在验证集上 mAP 只有 0.5,和 50 个 epoch 时差不多。
原因:这个包里的 loss 包含分类、回归和 DFL 三部分,DFL 的值对目标框质量非常敏感,但它的 scale 很大,导致总 loss 的下降主要来自 DFL,而分类分支没有学到足够区分度。另外,如果用了默认的数据增强,包括 mosaic 和混合增强,增强后的图片和验证集分布差距过大,训练 loss 会低但泛化差。
解决:把configs/yolo26_m.yaml里的dfl_weight从默认的 7.5 降低到 4.5,同时关闭增强里的mixup,观察 mAP 变化。我调完这两项后,mAP 从 50.8 升到 53.1。
5.2 导出 ONNX 后检测框偏移
现象:用 PyTorch 推理正常,导出 ONNX 后用 onnxruntime 推理,框的位置偏了 20 个像素左右,小目标偏移更严重。
原因:源码包里的 head 输出层使用了nn.Upsample,而 PyTorch 导出 ONNX 时,Upsample的align_corners参数如果设置为False,在 ONNX 里的行为会依赖 opset 版本。opset 11 和 opset 12 的坐标计算方式有小差异,导致特征图对齐错位。
解决:统一用 opset 12 导出,并且在export_onnx.py里显式设置torch.onnx.export(..., opset_version=12)。如果是自己写的部署代码,建议在推理前对输出特征图做一次双线性插值,确保与训练一致。
5.3 GPU 显存不足
现象:batch size 设为 16,显存 24G,训练时报CUDA out of memory,但 batch size 改成 8 又跑得太慢。
原因:这个源码包里有一个focus模块,它把输入图像切片成 4 个 channel 分组,中间的激活层显存占用比普通卷积高。另外,configs/yolo26_m.yaml里cache_images默认是True,会把整张图片缓存到内存里,显存会额外被吃一部分。
解决:训练时加--no-cache-images参数,把缓存关掉。我实测 batch 16 的显存占用从 21G 降到 16G,可以用 16 继续跑了。如果还不行,把imgsz从 640 改成 608,显存再降 15%。
5.4 数据增强导致标签错位
现象:训练几轮后,发现 loss 出现 NAN,排查后发现是增强后的目标框坐标偶尔超出图像边界。
原因:源码包里的mosaic增强把四张图拼在一起,随机裁剪时如果裁剪区域包含多个目标框,某些框的中心点会落在裁剪边缘之外,而源码包没有做边界截断,直接用了这种非法的标注参与 loss 计算,出现梯度爆炸。
解决:修改data/augment.py中的mosaic函数,在裁剪后对每个目标框做一次 clamp,保证坐标不越界。
# 在 augment.py 中,mosaic 裁剪后添加: for i in range(len(labels)): labels[i][:, 1:] = labels[i][:, 1:].clamp(0, 1)这个 clamp 操作把归一化坐标限制在 0 到 1 之间。如果你是新手,建议直接看labels的最小最大值是否都在合理范围,如果有负数或大于 1 的数,就是增强模块没处理好。
5.5 预训练权重与模型配置不匹配
现象:加载yolo26_m.pt训练,报state_dict中某些 key 缺失,比如model.9.conv.weight。
原因:yolo26_m.pt是在yolo26_m.yaml配置下训练的,如果你用的yolo26_s.yaml,通道数不同,自然不匹配。但更隐蔽的是,有些开发者改动过 head 结构,比如加了额外的注意力层,key 就完全对不上。
解决:训练时先核对配置文件名和权重来源,或者统一用源码包自带的configs/yolo26_m.yaml跑完整流程。如果不确定,加载后打印缺失的 key 数量,和总数对比,缺失超过 30% 基本可以判定结构不匹配,赶紧停掉。
6. 进阶用法:改造成自定义检测头与验证
这个源码包最大的可玩性在models/modules/head.py,它的解耦头结构非常清晰,适合替换成自己的检测头来验证算法。我做模拟项目X的时候,就把它的分类分支从普通卷积换成了轻量级注意力增强的一维卷积,改善小目标的分类置信度。
具体做法是:在head.py的分类分支里,把原来的Conv2d换成Conv2d + SEAttention的组合,SE 模块的代码可以借用attention.py里现成的实现:
class SEBlock(nn.Module): def __init__(self, channels, reduction=16): super().__init__() self.fc = nn.Sequential( nn.AdaptiveAvgPool2d(1), nn.Conv2d(channels, channels // reduction, 1, bias=False), nn.ReLU(inplace=True), nn.Conv2d(channels // reduction, channels, 1, bias=False), nn.Sigmoid() ) def forward(self, x): return x * self.fc(x)替换时注意保持输入输出 channel 不变,否则后续 DFL 层的输出维度会变。替换后重新训练,发现小目标的 Recall 提升了 3 个百分点,但整体 mAP 没有明显变化,这是因为小目标在数据集中的占比不高。如果你也想快速验证某个注意力模块是否有效,建议直接对验证集的难例做单独评测,而不是只看总的 mAP,那样容易被大目标稀释。
改动完检测头后,一定要重新导出 ONNX 并做端到端验证,不要只跑 PyTorch 训练。我的习惯是每次改动结构,先跑一个 30 epoch 的短训练,用验证集输出可视化结果,和原版模型画在同一张对比图里,确保框的位置和置信度都合理。这个习惯帮我避开了很多玄学问题,比如某些注意力模块在训练时能提点,但修改了输出分布后,部署端量化精度崩掉。
从那以后,我每次拿到新的检测源码包,都会强制走一遍完整流程:先看依赖和模型结构,再跑短训练确认 loss 行为,然后导出 ONNX 验证坐标一致性,最后才决定要不要投入资源做完整训练。这套习惯让我在 YOLO26 这个包上省下了至少一周的试错时间。如果你也准备在自有数据上复现它,希望这份笔记能帮你少踩几个坑,让源码包真正变成你自己的工具。
本文还有配套的精品资源,点击获取