
简介本资源面向计算机视觉方向的开发者与研究人员提供YOLO11目标检测从训练到TensorRT加速部署的完整实战方案帮助读者打通模型训练、格式转换与推理优化的全链路适合具备一定深度学习基础、希望掌握工程化落地技巧的中高级学习者。压缩包共67个文件约2.82MB以Python脚本、Shell执行脚本、模型配置yaml、示例图片及Git版本文件为主涵盖训练、预测、ONNX导出、TensorRT引擎构建与推理等模块并附README流程说明。已有1286人学习下载。读者可依据教程逐步完成coco_minitrain_10k数据集上的模型训练借助一键脚本完成ONNX导出与onnx2trt转换最终获得TensorRT优化后的加速推理效果同时理解层融合、混合精度等优化思路为自动驾驶、视频监控等实时视觉应用积累可复用的工程经验。1. YOLO11 训练到 TensorRT 部署一条能跑通的工程链路长什么样很多人第一次接触 YOLO11是在一台装了 4060 的 Windows 机器上跟着教程把yolo detect train跑通看到 loss 曲线往下掉觉得目标检测不过如此。然后到了部署环节把best.pt丢给推理代码发现单帧要 40 毫秒产线要求 10 毫秒以内于是开始翻 TensorRT 的文档翻到一半被 ONNX 导出、动态 shape、INT8 校准、插件版本这一堆东西劝退。这个标题讲的就是把「训练」和「TensorRT 部署」这两段接起来的那条工程链路——不是教你调包而是让你知道每一步为什么这么做、参数怎么定、哪里会翻车。适合两类人看一类是已经会用 Ultralytics 跑训练但部署还停留在 PyTorch 推理阶段的算法工程师另一类是拿到一个检测需求需要从数据集准备一路做到 TensorRT 引擎落地、并且要能复现的工程同学。整条链路的核心节点是数据 → 训练 → 验证 → 导出 ONNX → 构建 TensorRT 引擎 → 推理封装 → 精度与速度对齐。下面按这个顺序拆开讲重点放在那些教程里通常一笔带过、但实际会卡住你的地方。2. 训练前的数据与配置别让标注问题拖到部署才暴露2.1 数据集目录结构与 YOLO 格式的硬性约束YOLO11 沿用 Ultralytics 的数据组织方式目录结构必须是固定的三段式images和labels平行且文件名不含扩展名严格一一对应。常见做法是这样dataset/ ├── images/ │ ├── train/ │ │ ├── 0001.jpg │ │ └── 0002.jpg │ └── val/ │ ├── 0101.jpg │ └── 0102.jpg ├── labels/ │ ├── train/ │ │ ├── 0001.txt │ │ └── 0002.txt │ └── val/ │ ├── 0101.txt │ └── 0102.txt └── data.yamldata.yaml里三个字段必须写对path指向数据集根目录train和val写相对路径names用字典或列表都可以但索引必须从 0 开始连续。这里有个血泪经验如果names写成{1: cat, 2: dog}训练不会报错但类别索引会整体偏移验证时 mAP 看着正常部署后所有类别标签全错一位。标注文件每行是class_id cx cy w h坐标必须是归一化到 0~1 的浮点数不是像素值。用 LabelImg 或 X-AnyLabeling 导出时选 YOLO 格式导出后随手抽三个文件核对一下数值范围能省掉后面几小时的排查。2.2 训练参数怎么定从 yolov8 迁移过来的配置要改哪里YOLO11 的官方权重分 n/s/m/l/x 五档参数量和精度递增。选型上如果部署端是 Jetson 或 RK3588 这类边缘设备n 或 s 是现实选择如果是服务器 T4/A10m 起步。训练命令本身不复杂yolo detect train \ modelyolo11s.pt \ datadataset/data.yaml \ epochs200 \ imgsz640 \ batch16 \ device0 \ workers8 \ patience50 \ cacheram \ pretrainedTrue \ optimizerauto \ cos_lrTrue \ close_mosaic10逐项说imgsz640是训练分辨率也是后面导出 ONNX 和 TensorRT 的输入尺寸基准训练和部署必须一致否则精度会掉。batch16在 8G 显存上跑 s 模型基本够用显存不够就降到 8 并开ampTrue。patience50是早停200 epoch 里如果 50 轮没提升就停避免过拟合。cacheram把图片缓存进内存数据集小于 20G 时强烈建议开能省掉大量 IO 等待。close_mosaic10是最后 10 轮关闭 mosaic 增强让模型在接近真实分布的图像上收敛这个参数对最终精度影响比想象中大别省。从 yolov8 迁移过来的配置主要改两处一是模型权重换成yolo11*.pt二是 YOLO11 的 C3k2 模块对学习率更敏感optimizerauto会自动选但如果你手动设了lr0建议从 0.01 降到 0.005 起步。训练过程中重点看metrics/mAP50-95和val/box_loss两条曲线如果 box_loss 震荡剧烈先把lr0砍半。2.3 训练完先别急着导出验证集上的三个必查项训练结束runs/detect/train/weights/下会有best.pt和last.pt。导出前必须做三件事。第一用yolo detect val modelbest.pt datadataset/data.yaml跑一遍验证确认 mAP 和训练日志里最后一轮的数字对得上对不上说明验证集路径或类别配置有问题。第二抽 20 张验证集图片做可视化推理肉眼看框的位置和类别模型在验证集上的数字好看但框飘的情况并不少见尤其是小目标。第三检查best.pt的输入尺寸用model.model.args打印出来确认imgsz是 640 而不是训练中途被覆盖成别的值。这三步做完再进入导出环节否则后面 TensorRT 精度对不上时你分不清是训练的问题还是部署的问题。3. 从 pt 到 ONNX导出参数里藏着部署精度的第一道坎3.1 导出 ONNX 的最小命令与 opset 选择Ultralytics 把导出封装得很简单一行命令yolo export \ modelruns/detect/train/weights/best.pt \ formatonnx \ imgsz640 \ opset17 \ simplifyTrue \ dynamicFalse \ halfFalseopset17是当前 TensorRT 8.x/10.x 都稳定支持的版本别贪新用 19部分 TensorRT 版本对高 opset 的算子映射不完整会在构建引擎时报Unsupported ONNX op。simplifyTrue会调用 onnx-simplifier 做常量折叠和冗余节点消除能减少后续 TensorRT 解析的负担但注意它偶尔会把某些动态分支简化掉如果简化后推理结果异常把这项关掉重导。dynamicFalse表示固定 batch1、固定输入尺寸这是部署场景最常用的配置动态 shape 虽然灵活但会限制 TensorRT 的优化空间除非你的业务真的需要变长输入否则别开。halfFalse在导出阶段保持 FP32量化留到 TensorRT 构建时做这样精度损失可控。3.2 导出后的 ONNX 自检用 onnxruntime 对齐 PyTorch 输出导出完不能直接拿去构建引擎先用 onnxruntime 跑一遍和 PyTorch 的输出做数值对齐。这一步是排查精度问题的分水岭import numpy as np import onnxruntime as ort import torch from ultralytics import YOLO # PyTorch 推理 model YOLO(runs/detect/train/weights/best.pt) img np.random.randint(0, 255, (640, 640, 3), dtypenp.uint8) pt_out model.predict(img, imgsz640, verboseFalse)[0].boxes.data.cpu().numpy() # ONNX Runtime 推理 sess ort.InferenceSession(best.onnx, providers[CPUExecutionProvider]) input_name sess.get_inputs()[0].name blob img.astype(np.float32) / 255.0 blob blob.transpose(2, 0, 1)[None, ...] # 1x3x640x640 onnx_out sess.run(None, {input_name: blob})[0] print(PyTorch boxes:, pt_out.shape) print(ONNX output shape:, onnx_out.shape) print(Max abs diff:, np.abs(pt_out[:5, :4] - onnx_out[0, :5, :4]).max())逻辑说明PyTorch 侧用 Ultralytics 的predict拿到解码后的框ONNX 侧拿到的是原始输出张量形状通常是[1, 84, 8400]84 4 框坐标 80 类8400 是候选框数。两者不能直接逐元素比但可以比前几个框的坐标量级。如果 max abs diff 超过 1e-2说明导出过程有问题优先检查opset和simplify。参数上providers先用 CPU 跑通确认数值没问题再换 CUDA避免把 GPU 环境问题混进来。3.3 动态 shape 与静态 shape 的取舍静态 shape 的 ONNX 在 TensorRT 里能获得最好的优化kernel 可以针对固定尺寸做特化。动态 shape 的好处是同一引擎支持多种输入分辨率但代价是 TensorRT 需要为每个维度范围保留优化空间实际推理速度通常比静态慢 10%~20%。我一般会这样做如果业务输入尺寸固定比如摄像头固定 1080p 裁切成 640就用静态如果输入来自不同设备、尺寸不一先用静态跑通再评估是否值得为动态 shape 牺牲速度。动态 shape 导出时把dynamicTrue打开并在 TensorRT 构建时用--minShapes、--optShapes、--maxShapes指定范围这三个值设不好会直接导致构建失败或推理越界。4. TensorRT 引擎构建版本、精度与显存的三角博弈4.1 TensorRT 安装与版本匹配的坑TensorRT 的版本必须和 CUDA、cuDNN、显卡驱动四者对齐。常见组合是 CUDA 11.8 TensorRT 8.6或 CUDA 12.x TensorRT 10.x。这里有个高频翻车点TensorRT 10.x 对 GTX 10 系显卡的支持是有限的GTX 1070 这类 Pascal 架构在 TensorRT 10 下部分 FP16/INT8 算子会回退到 FP32甚至直接不支持。如果你手上是 1070/1080建议锁在 TensorRT 8.6 CUDA 11.8 这套组合别追新。安装方式上pip 安装tensorrt包最省事但要注意 pip 包里的libnvinfer.so版本必须和系统 CUDA 匹配用python -c import tensorrt; print(tensorrt.__version__)确认。4.2 用 trtexec 构建引擎一条命令与四个关键参数trtexec 是 TensorRT 自带的命令行工具构建引擎最直接trtexec \ --onnxbest.onnx \ --saveEnginebest_fp16.engine \ --fp16 \ --workspace4096 \ --minShapesimages:1x3x640x640 \ --optShapesimages:1x3x640x640 \ --maxShapesimages:1x3x640x640 \ --verbose--fp16开启半精度在支持 FP16 的显卡上图灵架构及以后能带来接近翻倍的速度提升精度损失通常在 0.5% mAP 以内。--workspace4096是构建时允许使用的显存上限单位 MB设太小会导致某些层无法选择最优 kernel设太大浪费4096 对 640 输入的 YOLO11 足够。三个 shape 参数在静态导出时都写同一个值动态导出时才需要拉开范围。--verbose会打印每一层的构建信息第一次构建建议开着能看到哪些层被 FP16 化、哪些回退到 FP32。构建完成后trtexec 会输出推理耗时统计重点看GPU Compute Time的 mean 值这是纯推理时间不含前后处理。4.3 INT8 量化校准集怎么选、精度掉多少算正常INT8 能再提速 30%~50%但需要校准。校准集的选取原则是从训练集里抽 200~500 张有代表性的图片覆盖所有类别和典型场景不要只用验证集验证集分布太窄会导致校准偏差。用 Ultralytics 直接导出 INT8 引擎yolo export \ modelbest.pt \ formatengine \ imgsz640 \ int8True \ datadataset/data.yaml \ workspace4 \ batch1data参数指向data.yamlUltralytics 会自动从训练集里抽图做校准。workspace4单位是 GB。INT8 之后必须重新跑验证集对比 FP16 的 mAP掉 1% 以内算正常掉超过 2% 说明校准集代表性不够需要手动指定校准图片目录。另外注意INT8 对小目标的精度影响通常比大目标大如果你的场景里小目标占比高INT8 要谨慎。4.4 引擎推理封装前后处理必须和训练对齐拿到.engine文件后推理代码的前后处理必须和训练时完全一致。前处理是 letterbox 缩放 归一化 BGR→RGB如果训练用的是 RGB后处理是解码 NMS。常见错误是推理时用了直接 resize 而不是 letterbox导致框的位置整体偏移。下面是一个最小封装import tensorrt as trt import pycuda.driver as cuda import pycuda.autoinit import numpy as np import cv2 def letterbox(img, new_shape640, color(114, 114, 114)): shape img.shape[:2] r min(new_shape / shape[0], new_shape / shape[1]) new_unpad (int(round(shape[1] * r)), int(round(shape[0] * r))) dw, dh new_shape - new_unpad[0], new_shape - new_unpad[1] dw, dh dw // 2, dh // 2 img cv2.resize(img, new_unpad, interpolationcv2.INTER_LINEAR) top, bottom dh, new_shape - new_unpad[1] - dh left, right dw, new_shape - new_unpad[0] - dw img cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, valuecolor) return img, r, (dw, dh) # 加载引擎 logger trt.Logger(trt.Logger.WARNING) with open(best_fp16.engine, rb) as f, trt.Runtime(logger) as runtime: engine runtime.deserialize_cuda_engine(f.read()) context engine.create_execution_context() # 分配显存 input_shape (1, 3, 640, 640) output_shape (1, 84, 8400) d_input cuda.mem_alloc(int(np.prod(input_shape)) * 4) d_output cuda.mem_alloc(int(np.prod(output_shape)) * 4) stream cuda.Stream() def infer(img_bgr): img, ratio, pad letterbox(img_bgr, 640) blob img[:, :, ::-1].astype(np.float32) / 255.0 # BGR-RGB blob blob.transpose(2, 0, 1)[None, ...] cuda.memcpy_htod_async(d_input, blob, stream) context.execute_async_v3(stream_handlestream.handle) cuda.memcpy_dtoh_async(np.empty(output_shape, dtypenp.float32), d_output, stream) stream.synchronize() return output逻辑说明letterbox保持长宽比缩放并填充灰边记录缩放比r和填充量pad后处理时用这两个值把框坐标映射回原图。execute_async_v3是 TensorRT 8.5 的异步接口比同步接口吞吐更高。参数上output_shape必须和 ONNX 输出严格一致不同模型版本可能是[1, 84, 8400]或[1, 8400, 84]用engine.get_tensor_shape打印确认写错会直接段错误。5. 部署避坑那些让精度和速度同时翻车的细节5.1 现象TensorRT 推理结果框全偏mAP 掉 30 个点原因前处理用了直接 resize 而不是 letterbox或者 BGR/RGB 通道顺序和训练不一致。Ultralytics 训练时默认把图片转成 RGB推理时如果喂 BGR颜色通道错位会让模型把红色当蓝色框的位置和类别都会乱。解决在推理代码里显式做img[:, :, ::-1]转 RGB并用 letterbox 替代 resize。验证方法很简单拿一张训练集里的图分别用 PyTorch 和 TensorRT 推理把两张结果图画出来叠在一起看框重合就说明前处理对了。5.2 现象trtexec 构建引擎时报Unsupported ONNX op: NonMaxSuppression原因导出 ONNX 时 Ultralytics 默认会把 NMS 也导出成 ONNX 算子但 TensorRT 对 NMS 的支持依赖插件部分版本不内置。这个报错在 opset 17 TensorRT 8.6 组合下出现频率较高。解决导出时加nmsFalse把 NMS 放到后处理里用 Python 或 CUDA 实现。代价是后处理耗时增加但换来的是引擎构建稳定。如果一定要把 NMS 放进引擎需要确认 TensorRT 版本自带EfficientNMS_TRT插件并在导出时指定nmsTrue且 opset 不低于 16。5.3 现象INT8 引擎推理速度没提升反而比 FP16 慢原因显卡不支持 INT8 的 DP4A 指令或者 TensorRT 在构建时因为校准数据不足把大部分层回退到了 FP32。GTX 10 系及更早的显卡没有 INT8 硬件加速强行开 INT8 只会增加量化/反量化开销。解决先确认显卡架构图灵RTX 20 系及以上才有可用的 INT8 加速。确认支持后检查校准集是否覆盖了所有类别校准图片少于 100 张时 TensorRT 的校准器容易给出保守的 scale导致层回退。把校准集加到 300 张以上再试。5.4 现象同一引擎在不同机器上推理结果不一致原因TensorRT 引擎和构建时的显卡架构、驱动版本、CUDA 版本绑定。在 A100 上构建的引擎拿到 4090 上跑可能因为 SM 版本不同导致 kernel 选择差异数值结果有微小偏差极端情况下直接报错。解决引擎在目标部署机器上构建或者用trtexec的--saveEngine时加上--timingCacheFile把 timing cache 一起保存迁移时带上。跨架构部署时老老实实在目标机器上重新构建别图省事直接拷引擎文件。5.5 现象batch 从 1 改成 4 后显存溢出或速度不升反降原因静态导出的 ONNX 固定了 batch1TensorRT 引擎也只能跑 batch1。强行喂 batch4 的数据会报 shape 不匹配。如果导出时用了动态 batchTensorRT 需要为最大 batch 预留显存--maxShapes设太大就会 OOM。解决需要多 batch 时导出 ONNX 用dynamicTrue并指定batch维度为动态构建引擎时--minShapesimages:1x3x640x640 --optShapesimages:4x3x640x640 --maxShapesimages:8x3x640x640optShapes 设成实际业务最常用的 batchTensorRT 会针对这个值做优化。显存不够就降 maxShapes别硬撑。6. 把整条链路串成一个可复现的脚本我的收尾习惯走到这里训练、导出、构建、推理四段都通了但每次手动敲命令容易漏参数。我一般会写一个run_all.sh把整条链路串起来关键是用变量控制路径和参数换数据集时只改开头几行#!/bin/bash set -e DATAdataset/data.yaml MODELyolo11s.pt IMGSZ640 EPOCHS200 BATCH16 NAMEyolo11s_exp # 1. 训练 yolo detect train model$MODEL data$DATA imgsz$IMGSZ epochs$EPOCHS batch$BATCH name$NAME # 2. 验证 yolo detect val modelruns/detect/$NAME/weights/best.pt data$DATA imgsz$IMGSZ # 3. 导出 ONNX yolo export modelruns/detect/$NAME/weights/best.pt formatonnx imgsz$IMGSZ opset17 simplifyTrue dynamicFalse # 4. 构建 FP16 引擎 trtexec --onnxruns/detect/$NAME/weights/best.onnx \ --saveEngineruns/detect/$NAME/weights/best_fp16.engine \ --fp16 --workspace4096 \ --minShapesimages:1x3x${IMGSZ}x${IMGSZ} \ --optShapesimages:1x3x${IMGSZ}x${IMGSZ} \ --maxShapesimages:1x3x${IMGSZ}x${IMGSZ} # 5. 构建 INT8 引擎可选 yolo export modelruns/detect/$NAME/weights/best.pt formatengine imgsz$IMGSZ int8True data$DATA workspace4 batch1set -e让脚本在任一步失败时立即停止避免带着错误往下跑。变量集中在开头换实验时只改NAME和DATA。INT8 那步单独注释掉因为不是每次都需要而且校准耗时较长。脚本跑通之后我习惯做一次端到端对齐验证从验证集里抽 50 张图分别用 PyTorch、ONNX Runtime、TensorRT FP16、TensorRT INT8 四个后端推理把每张图的检测框数量、类别分布、平均置信度记到一张表里。如果四个后端的框数量差异在 5% 以内、类别分布一致这条链路就算稳了。这个习惯帮我省过好几次「训练没问题、部署精度崩了」的排查时间——有一次就是 INT8 校准集里缺了一个稀有类别导致该类别的框在 INT8 引擎里全部消失表格一拉出来就定位到了。最后说一个参数上的个人偏好imgsz我通常不会为了提速降到 416 或 320除非业务明确允许小目标漏检。YOLO11 在 640 下的精度和速度平衡最好降到 416 速度提升约 40%但小目标 mAP 可能掉 10 个点以上这笔账要提前算清楚。部署这件事快不是唯一目标快且准才是。希望帮到你。本文还有配套的精品资源点击获取