YOLO 部署落地:模型导出与多平台部署

7 分钟阅读
模型导出(17 种格式支持) Ultralytics 统一导出 API python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 from ultralytics import YOLO model = YOLO("yolo26n.pt") # ========== 各种格式导出 ========== # 1. ONNX(跨平台通用) model.export(format="onnx", simplify=True, dynamic=True) # 2. TensorRT(NVIDIA GPU最佳) model.export(format="engine", half=True, workspace=4) # 3. OpenVINO(Intel CPU最佳) model.export(format="openvino", half=True) # 4. CoreML(Apple设备) model.export(format="coreml", int8=True) # 5. TFLite(Android/iOS移动端) model.export(format="tflite", int8=True) # 6. NCNN(移动端) model.export(format="ncnn") # 7. PaddlePaddle model.export(format="paddle") 各版本导出兼容性 格式 YOLOv8 YOLO11 YOLO26 ONNX ✅ ✅ ✅ 最佳 TensorRT ✅ ✅ ✅ 无 NMS 更简单 OpenVINO ✅ ✅ ✅ TFLite ✅ ✅ ✅ NCNN ✅ ✅ ✅ Python 部署实战 ONNX Runtime 部署 python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import onnxruntime as ort import cv2 import numpy as np # 加载ONNX模型 session = ort.InferenceSession( "yolo26n.onnx", providers=["CUDAExecutionProvider", "CPUExecutionProvider"] ) def preprocess(image, imgsz=640): """图片预处理""" img = cv2.resize(image, (imgsz, imgsz)) img = img.transpose(2, 0, 1) / 255.0 return img[np.newaxis].astype(np.float32) # 推理 image = cv2.imread("test.jpg") input_data = preprocess(image) outputs = session.run(None, {"images": input_data}) # YOLO26特别注意:无需NMS后处理! # 输出已是最终检测结果 TensorRT Python 部署 python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 import tensorrt as trt import pycuda.driver as cuda import pycuda.autoinit import numpy as np import time # ========== 1. 引擎加载与上下文创建 ========== TRT_LOGGER = trt.Logger(trt.Logger.WARNING) runtime = trt.Runtime(TRT_LOGGER) with open("yolo26n.engine", "rb") as f: engine = runtime.deserialize_cuda_engine(f.read()) context = engine.create_execution_context() # ========== 2. CUDA 内存分配 ========== stream = cuda.Stream() bindings = [] for i in range(engine.num_io_tensors): name = engine.get_tensor_name(i) shape = engine.get_tensor_shape(name) dtype = trt.nptype(engine.get_tensor_dtype(name)) size = trt.volume(shape) host_mem = cuda.pagelocked_empty(size, dtype) # 主机锁页内存 device_mem = cuda.mem_alloc(host_mem.nbytes) # 设备显存 bindings.append({"name": name, "host": host_mem, "device": device_mem, "shape": shape, "size": size, "dtype": dtype}) # ========== 3. 异步推理循环 ========== def async_infer(input_blob): # 输入拷贝:主机 → 设备 np.copyto(bindings[0]["host"], input_blob.ravel()) cuda.memcpy_htod_async(bindings[0]["device"], bindings[0]["host"], stream) # 设置张量地址并执行 context.set_tensor_address(bindings[0]["name"], int(bindings[0]["device"])) context.set_tensor_address(bindings[1]["name"], int(bindings[1]["device"])) context.execute_async_v3(stream.handle) # 输出拷贝:设备 → 主机 cuda.memcpy_dtoh_async(bindings[1]["host"], bindings[1]["device"], stream) stream.synchronize() return bindings[1]["host"].copy() # ========== 4. 性能基准测试 ========== def benchmark(warmup=10, runs=100): dummy = np.random.randn(1, 3, 640, 640).astype(np.float32) for _ in range(warmup): async_infer(dummy) latencies = [] for _ in range(runs): t0 = time.perf_counter() async_infer(dummy) latencies.append((time.perf_counter() - t0) * 1000) latencies.sort() print(f"TensorRT FP16 | 平均: {np.mean(latencies):.1f}ms | " f"P50: {latencies[runs//2]:.1f}ms | " f"P99: {latencies[int(runs*0.99)]:.1f}ms | " f"吞吐: {1000/np.mean(latencies):.0f} FPS") benchmark() OpenVINO 部署与性能基准 python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 import openvino as ov import cv2 import numpy as np import time # ========== 1. ONNX → OpenVINO 转换 ========== # Ultralytics 统一导出: # model.export(format="openvino", half=True) core = ov.Core() model = core.read_model("yolo26n_openvino/yolo26n.xml") # ========== 2. CPU 推理 ========== compiled_cpu = core.compile_model(model, device_name="CPU") infer_request = compiled_cpu.create_infer_request() def openvino_infer(image): img = cv2.resize(image, (640, 640)) blob = img.transpose(2, 0, 1)[np.newaxis].astype(np.float32) / 255.0 outputs = infer_request.infer({"images": blob}) return outputs[next(iter(outputs))] # ========== 3. 异步推理管线(提升吞吐)========== def async_pipeline(images, num_requests=4): """多请求异步推理管线""" requests = [core.compile_model(model, "CPU").create_infer_request() for _ in range(num_requests)] results = [None] * len(images) def completion_callback(request, userdata): idx = userdata results[idx] = request.get_output_tensor().data.copy() for req in requests: req.set_callback(completion_callback) for i, img in enumerate(images): req = requests[i % num_requests] req.start_async({"images": preprocess(img)}, userdata=i) for req in requests: req.wait() return results # ========== 4. CPU vs NPU 基准对比 ========== def benchmark_openvino(): dummy = np.random.randn(1, 3, 640, 640).astype(np.float32) for device in ["CPU", "AUTO"]: compiled = core.compile_model(model, device) req = compiled.create_infer_request() # 预热(避免首次 kernel 编译开销) for _ in range(20): req.infer({"images": dummy}) times = [] for _ in range(200): t0 = time.perf_counter() req.infer({"images": dummy}) times.append((time.perf_counter() - t0) * 1000) times.sort() print(f"OpenVINO {device}: " f"平均 {np.mean(times):.1f}ms | " f"P99 {times[int(199*0.99)]:.1f}ms | " f"{1000/np.mean(times):.0f} FPS") benchmark_openvino() NCNN 移动端部署 NCNN 是腾讯开源的移动端推理框架,支持 ARM NEON 和 Vulkan GPU 加速。
YOLO 模型部署 ONNX TensorRT 边缘计算
继续阅读 →

MiBeeNvr v0.3.0: 小米摄像头一键接入,录像永不丢失

2 分钟阅读
家里有小米摄像头?想把录像存到自己手里,不靠云存储? 作为一个家里装了几个小米摄像头的用户,我一直有个烦恼:每次想看门口的录像,都得先登录小米云,加载半天还经常转圈。而且云存储按天收费,一个月下来也不是小数目。有时候换摄像头,之前的录像就全没了,想想都觉得可惜。
NVR 小米摄像头 智能家居 录像 开源
继续阅读 →

嵌入式 ANC:STM32 实战

9 分钟阅读
硬件架构 实现实时 ANC 首先要选择合适的硬件平台。控制器需要在微秒级完成自适应滤波运算,同时管理多路音频数据流。 模块 功能 典型选型 主控制器 执行自适应算法 STM32F4/F7, ESP32-S3, nRF5340 参考麦克风 采集环境噪声 Knowles SPH0645, Infineon IM69D130 误差麦克风 采集残余噪声 Knowles SPH0645, TDK ICS-43434 音频 DAC 输出抗噪声信号 ES9218, PCM5102 功放 驱动扬声器 Class-D 参考麦克风位于耳罩外侧,采集外部环境噪声作为算法参考输入。误差麦克风位于耳罩内侧,采集扬声器附近的残余噪声,用于评估降噪效果并驱动自适应更新。音频 DAC 将数字抗噪声信号转为模拟量,经功放放大后驱动扬声器。
STM32 CMSIS-DSP DFSDM MEMS 嵌入式 ANC
继续阅读 →

YOLO 进阶优化:轻量化、量化与精度提升

8 分钟阅读
模型轻量化策略 模型尺寸选择 模型 参数 (M) mAP CPU 推理 适用场景 YOLO26n 2.8 38.9 最快 边缘设备、嵌入式 YOLO26s 9.4 48.2 很快 移动端、Web YOLO26m 21.8 53.1 中等 服务器、高性能 YOLO11n 2.6 39.6 快 轻量部署 YOLOv8n 3.2 37.3 基准 通用 知识蒸馏 python 1 2 3 4 5 6 7 8 9 10 # 大模型作为教师,小模型作为学生 teacher = YOLO("yolo26x.pt") student = YOLO("yolo26n.yaml") # 蒸馏训练(Ultralytics内置支持) student.train( data="data.yaml", distill="yolo26x.pt", # 教师模型 distill_ratio=0.5, # 蒸馏损失比例 ) 模型剪枝 结构化剪枝 vs 非结构化剪枝 类型 方法 稀疏模式 硬件加速 压缩率 非结构化 权重剪枝 随机稀疏 困难(需专用硬件) 高 结构化 通道剪枝 规整稀疏 原生加速 中等 Torch Prune 通道剪枝示例 python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import torch import torch.nn.utils.prune as prune # 对卷积层进行 L1 非结构化剪枝 model = YOLO("yolo26n.pt") for name, module in model.model.named_modules(): if isinstance(module, torch.nn.Conv2d): prune.l1_unstructured(module, name="weight", amount=0.3) prune.remove(module, "weight") # 使剪枝永久化 # 通道剪枝使用 torch-pruning 库 # pip install torch-pruning import torch_pruning as tp model = YOLO("yolo26n.pt").model DG = tp.DependencyGraph() DG.build_dependency(model, example_inputs=torch.randn(1, 3, 640, 640)) # 按 L1 范数剪枝 20% 通道 pruning_plan = DG.get_pruning_plan( model.model[4], tp.prune_conv, pruning_dim=0, # 输出通道维度 idxs=list(range(0, 64, 5)) # 每 5 个通道保留一个 ) pruning_plan.exec() 剪枝比例指南 模型 安全剪枝比例 激进剪枝比例 mAP 损失 YOLO26n ≤20% 20-40% <1% / 2-5% YOLO26s ≤30% 30-50% <1% / 3-6% YOLO26m ≤40% 40-60% <1% / 3-8% YOLOv8n ≤20% 20-35% <1% / 2-4% 模型剪枝与量化 导出时量化 python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 model = YOLO("yolo26n.pt") # INT8量化(需要校准数据) model.export( format="engine", # TensorRT int8=True, data="data.yaml", # 校准数据集 batch=8, ) # ONNX动态量化 model.export( format="onnx", dynamic=True, simplify=True, ) TensorRT INT8 校准流程详解 校准数据集准备 INT8 量化需要代表性校准数据来确定激活值的动态范围:
YOLO 模型优化 知识蒸馏 模型量化 边缘部署
继续阅读 →

从Hashmod到Jump Consistent Hash——stream-metrics-route哈希算法升级实录

11 分钟阅读
前言 在 上一篇 中,我们回顾了 stream-metrics-route 三年来的演进,提到了"双重hashmod调度"是整个网关的核心调度机制。但在生产环境持续运行中,hashmod 的一个致命缺陷暴露得越来越明显——每次扩缩容都引发全量数据重分配。
VictoriaMetrics Prometheus 一致性哈希 Stream-Metrics-Route 分布式系统
继续阅读 →

变步长与频域自适应算法

6 分钟阅读
固定步长的收敛矛盾 标准 LMS 算法和 NLMS 算法都使用固定的步长参数 $\mu$。步长大小的选择直接影响算法性能,但存在一个根本矛盾: 大步长:收敛速度快,能够快速追踪环境变化,但稳态误差大,滤波精度低 小步长:稳态误差小,滤波精度高,但收敛速度慢,对突变响应迟缓 这个矛盾在回声消除、主动噪声控制等应用中尤为突出——系统启动时需要快速收敛,稳态后则希望维持低误差。固定步长无法同时满足两阶段的需求。
自适应滤波 变步长 频域算法 FDAF DSP
继续阅读 →

YOLO 模型训练:自定义数据集完整流程

10 分钟阅读
自定义数据集完整训练流程 Ultralytics 统一训练代码 python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 from ultralytics import YOLO # 加载模型 # model = YOLO("yolov8n.yaml") # 从头训练 # model = YOLO("yolo11n.pt") # 基于预训练权重 model = YOLO("yolo26n.pt") # 2026推荐,边缘部署首选 # 开始训练 results = model.train( # 基础配置 data="data.yaml", # 数据集配置 epochs=100, # 训练轮数 imgsz=640, # 输入尺寸 batch=16, # 批次大小 workers=8, # 数据加载线程数 # 优化器配置 optimizer="auto", # YOLO26自动使用MuSGD lr0=0.01, # 初始学习率 lrf=0.01, # 最终学习率因子 momentum=0.937, # SGD动量 weight_decay=0.0005, # 权重衰减 # 数据增强 mosaic=1.0, mixup=0.1, copy_paste=0.1, # 其他配置 device=0, # GPU设备,"cpu"为CPU project="runs/train", # 保存路径 name="yolo26_exp1", # 实验名称 exist_ok=False, # 是否覆盖 pretrained=True, # 使用预训练 verbose=True, # 详细日志 seed=42, # 随机种子 ) # 验证模型 metrics = model.val() print(f"mAP50: {metrics.box.map50:.3f}") print(f"mAP50-95: {metrics.box.map:.3f}") 各版本训练参数差异 参数 YOLOv8 YOLO11 YOLO26 默认优化器 SGD SGD MuSGD DFL 损失 ✅ ✅ ❌ 已移除 NMS 后处理 ✅ ✅ ❌ 原生无 NMS 小目标优化 一般 较好 最佳 (STAL) CPU 推理速度 基准 +25% +43% 损失函数详解 YOLO 的损失函数由三部分组成,每部分针对不同的学习目标:
YOLO 模型训练 深度学习 调优
继续阅读 →