YOLO26 边缘部署实战:INT8 量化与 TensorRT 优化详解

YOLO26 边缘部署实战:INT8 量化与 TensorRT 优化详解

背景

YOLO26 是 Ultralytics 2025-2026 年旗舰模型,专为边缘部署优化,支持五种任务:检测、分割、姿态估计、旋转框检测、开放词汇检测。


YOLO26 架构创新

核心改进

改进 说明
NMS-free 移除非极大值抑制,端到端推理
DFL-free 移除分布焦点损失
MuSGD 优化器 稳定收敛
ProgLoss 渐进损失平衡
STAL 小目标感知标签分配

性能指标

模型 mAP50:95 延迟 (T4) 参数量
YOLO26n 40.9 1.7 ms 3.2M
YOLO26s 47.2 3.2 ms 11.2M
YOLO26m 52.5 5.8 ms 25.9M
YOLO26l 55.8 8.9 ms 43.7M
YOLO26x 57.5 11.8 ms 68.4M

边缘部署硬件支持

目标平台

平台 支持 延迟
NVIDIA Jetson Orin ✅ 优化 251 FPS (Nano)
Qualcomm Snapdragon AI ✅ 优化 实时
ARM CPU ✅ 支持 中等
Apple Silicon ✅ 支持 良好

YOLO26n Jetson Orin Nano 性能

1
2
3
TensorRT FP16: 251 FPS
TensorRT INT8: 280 FPS(Smart Quantizer)
模型大小: 6.4 MB (FP16), 1.6 MB (INT8)

TensorRT INT8 量化实战

1. 模型导出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# yolo26_export.py
from ultralytics import YOLO

# 加载模型
model = YOLO("yolo26n.pt")

# 导出为 ONNX
model.export(
format="onnx",
dynamic=False,
simplify=True,
opset=12,
imgsz=640
)

# 导出为 TensorRT
model.export(
format="engine",
device=0, # GPU
half=True, # FP16
imgsz=640
)

2. INT8 量化脚本

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# int8_quantization.py
import tensorrt as trt
import numpy as np
from PIL import Image
import os

class YOLO26Quantizer:
"""
YOLO26 INT8 量化器

使用 Smart Quantizer 恢复量化精度
"""

def __init__(self, onnx_path: str, calibration_data_dir: str):
self.onnx_path = onnx_path
self.calibration_dir = calibration_data_dir
self.logger = trt.Logger(trt.Logger.INFO)

def build_int8_engine(self, output_path: str):
"""
构建 INT8 TensorRT 引擎

Args:
output_path: 输出引擎路径
"""
# 创建构建器
builder = trt.Builder(self.logger)

# 创建网络
network = builder.create_network(
1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)
)

# 解析 ONNX
parser = trt.OnnxParser(network, self.logger)
with open(self.onnx_path, 'rb') as f:
parser.parse(f.read())

# 配置构建器
config = builder.create_builder_config()

# 设置精度
config.set_flag(trt.BuilderFlag.INT8)
config.set_flag(trt.BuilderFlag.FP16) # 混合精度

# 设置校准器
calibrator = self.create_calibrator()
config.int8_calibrator = calibrator

# 构建引擎
engine = builder.build_serialized_network(network, config)

# 保存引擎
with open(output_path, 'wb') as f:
f.write(engine)

print(f"INT8 引擎已保存: {output_path}")

def create_calibrator(self):
"""创建 INT8 校准器"""
return YOLO26Calibrator(self.calibration_dir)


class YOLO26Calibrator(trt.IInt8EntropyCalibrator2):
"""
YOLO26 INT8 校准器
"""

def __init__(self, data_dir: str):
super().__init__()
self.data_dir = data_dir
self.batch_files = self.load_calibration_images()
self.current_index = 0
self.batch_size = 1
self.input_shape = (1, 3, 640, 640)

def load_calibration_images(self):
"""加载校准图像"""
files = [os.path.join(self.data_dir, f)
for f in os.listdir(self.data_dir)
if f.endswith(('.jpg', '.png'))]
return files[:500] # 500 张校准图像

def get_batch_size(self):
return self.batch_size

def get_batch(self, names):
if self.current_index >= len(self.batch_files):
return None

# 加载图像
img_path = self.batch_files[self.current_index]
img = Image.open(img_path).resize((640, 640))
img_array = np.array(img).transpose(2, 0, 1) / 255.0
img_array = img_array.astype(np.float32)

# 创建 batch
batch = np.expand_dims(img_array, axis=0)

self.current_index += 1

return [batch]

def read_calibration_cache(self):
return None

def write_calibration_cache(self, cache):
with open("yolo26_calibration.cache", 'wb') as f:
f.write(cache)


# 运行量化
if __name__ == "__main__":
quantizer = YOLO26Quantizer(
onnx_path="yolo26n.onnx",
calibration_data_dir="/data/calibration_images"
)
quantizer.build_int8_engine("yolo26n_int8.engine")

3. Smart Quantizer 精度恢复

根据 EdgeFirst Perception Index 报告:

模型 FP32 mAP INT8 mAP (默认) INT8 mAP (Smart Quantizer)
YOLO26n 40.9 38.5 (-2.4) 40.2 (-0.7)
YOLO26s 47.2 44.1 (-3.1) 46.5 (-0.7)
YOLO26m 52.5 48.2 (-4.3) 51.8 (-0.7)

Smart Quantizer 关键技术:

  • 混合精度选择(敏感层保持 FP16)
  • 激活分布校准
  • 感知训练微调

TensorRT 推理代码

C++ 推理

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
71
// yolo26_inference.cpp
#include <NvInfer.h>
#include <NvOnnxParser.h>
#include <cuda_runtime_api.h>
#include <opencv2/opencv.hpp>
#include <iostream>
#include <fstream>

class YOLO26Inference {
public:
YOLO26Inference(const std::string& engine_path) {
// 加载引擎
loadEngine(engine_path);
}

std::vector<Detection> infer(const cv::Mat& image) {
// 预处理
float* input_data = preprocess(image);

// 推理
cudaMemcpy(d_input, input_data, input_size, cudaMemcpyHostToDevice);
context->enqueueV2(&d_input, 0, nullptr);
cudaMemcpy(output_data, d_output, output_size, cudaMemcpyDeviceToHost);

// 后处理
return postprocess(output_data);
}

private:
void loadEngine(const std::string& engine_path) {
// 读取引擎文件
std::ifstream file(engine_path, std::ios::binary);
file.seekg(0, std::ios::end);
size_t size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<char> buffer(size);
file.read(buffer.data(), size);

// 反序列化
runtime = nvinfer1::createInferRuntime(gLogger);
engine = runtime->deserializeCudaEngine(buffer.data(), size);
context = engine->createExecutionContext();

// 分配显存
cudaMalloc(&d_input, input_size);
cudaMalloc(&d_output, output_size);
}

float* preprocess(const cv::Mat& image) {
cv::Mat resized;
cv::resize(image, resized, cv::Size(640, 640));
resized.convertTo(resized, CV_32F, 1.0 / 255.0);

// HWC -> CHW
float* data = new float[3 * 640 * 640];
std::vector<cv::Mat> channels(3);
cv::split(resized, channels);
for (int i = 0; i < 3; i++) {
memcpy(data + i * 640 * 640, channels[i].data, 640 * 640 * sizeof(float));
}

return data;
}

nvinfer1::IRuntime* runtime;
nvinfer1::ICudaEngine* engine;
nvinfer1::IExecutionContext* context;
void* d_input;
void* d_output;
float* output_data;
};

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# yolo26_trt_inference.py
import tensorrt as trt
import pycuda.driver as cuda
import pycuda.autoinit
import numpy as np
import cv2

class YOLO26TRT:
"""
YOLO26 TensorRT 推理类
"""

def __init__(self, engine_path: str):
self.logger = trt.Logger(trt.Logger.INFO)
self.engine = self.load_engine(engine_path)
self.context = self.engine.create_execution_context()

# 分配显存
self.inputs, self.outputs = self.allocate_buffers()

def load_engine(self, engine_path: str):
"""加载 TensorRT 引擎"""
with open(engine_path, 'rb') as f:
runtime = trt.Runtime(self.logger)
return runtime.deserialize_cuda_engine(f.read())

def allocate_buffers(self):
"""分配输入输出缓冲区"""
inputs = []
outputs = []

for binding in self.engine:
size = trt.volume(self.engine.get_binding_shape(binding))
dtype = trt.nptype(self.engine.get_binding_dtype(binding))

# 分配 host 和 device 内存
host_mem = cuda.pagelocked_empty(size, dtype)
device_mem = cuda.mem_alloc(host_mem.nbytes)

if self.engine.binding_is_input(binding):
inputs.append({'host': host_mem, 'device': device_mem})
else:
outputs.append({'host': host_mem, 'device': device_mem})

return inputs, outputs

def infer(self, image: np.ndarray) -> list:
"""
执行推理

Args:
image: BGR 图像 (H, W, 3)

Returns:
detections: 检测结果列表
"""
# 预处理
input_tensor = self.preprocess(image)

# 拷贝到显存
np.copyto(self.inputs[0]['host'], input_tensor.ravel())
cuda.memcpy_htod(self.inputs[0]['device'], self.inputs[0]['host'])

# 执行推理
self.context.execute_v2([inp['device'] for inp in self.inputs] +
[out['device'] for out in self.outputs])

# 拷贝回 host
cuda.memcpy_dtoh(self.outputs[0]['host'], self.outputs[0]['device'])

# 后处理
return self.postprocess(self.outputs[0]['host'])

def preprocess(self, image: np.ndarray) -> np.ndarray:
"""预处理"""
# 缩放
resized = cv2.resize(image, (640, 640))

# 归一化
normalized = resized.astype(np.float32) / 255.0

# HWC -> CHW
transposed = normalized.transpose(2, 0, 1)

return np.expand_dims(transposed, 0)

def postprocess(self, output: np.ndarray) -> list:
"""后处理"""
# 解析输出
detections = []

# YOLO26 输出格式: [batch, num_detections, 6]
# 6 = [x, y, w, h, conf, class]

for det in output[0]:
x, y, w, h, conf, cls = det
if conf > 0.25: # 置信度阈值
detections.append({
'bbox': [x - w/2, y - h/2, x + w/2, y + h/2],
'confidence': float(conf),
'class': int(cls)
})

return detections


# 使用示例
if __name__ == "__main__":
# 加载模型
model = YOLO26TRT("yolo26n_int8.engine")

# 读取图像
image = cv2.imread("test.jpg")

# 推理
detections = model.infer(image)

# 绘制结果
for det in detections:
x1, y1, x2, y2 = det['bbox']
cv2.rectangle(image, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
cv2.putText(image, f"{det['class']}: {det['confidence']:.2f}",
(int(x1), int(y1) - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)

cv2.imwrite("result.jpg", image)
print(f"检测到 {len(detections)} 个目标")

IMS 应用场景

1. DMS 目标检测

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
# dms_detection.py
class DMSDetector:
"""
DMS 目标检测模块

检测:手机、水瓶、食物、香烟等
"""

CLASSES = {
0: "phone",
1: "bottle",
2: "food",
3: "cigarette",
4: "face",
5: "hand"
}

def __init__(self, engine_path: str):
self.model = YOLO26TRT(engine_path)

def detect_distraction_objects(self, frame: np.ndarray) -> dict:
"""
检测分心相关物体

Args:
frame: BGR 图像

Returns:
result: 检测结果
"""
detections = self.model.infer(frame)

# 筛选分心物体
distraction_objects = []
for det in detections:
if det['class'] in [0, 1, 2, 3]: # phone, bottle, food, cigarette
distraction_objects.append(det)

return {
"has_distraction": len(distraction_objects) > 0,
"objects": distraction_objects
}

2. OMS 姿态估计

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
# oms_pose.py
class OMSPoseEstimator:
"""
OMS 姿态估计模块

使用 YOLO26-pose 检测人体关键点
"""

# COCO 17 关键点
KEYPOINTS = [
"nose", "left_eye", "right_eye", "left_ear", "right_ear",
"left_shoulder", "right_shoulder", "left_elbow", "right_elbow",
"left_wrist", "right_wrist", "left_hip", "right_hip",
"left_knee", "right_knee", "left_ankle", "right_ankle"
]

def __init__(self, engine_path: str):
self.model = YOLO26TRT(engine_path)

def estimate_pose(self, frame: np.ndarray) -> dict:
"""
估计乘客姿态

Args:
frame: BGR 图像

Returns:
pose: 姿态关键点
"""
# 推理
keypoints = self.model.infer_pose(frame)

# 判定 OOP
is_oop = self.check_out_of_position(keypoints)

return {
"keypoints": keypoints,
"is_oop": is_oop
}

def check_out_of_position(self, keypoints: np.ndarray) -> bool:
"""判定是否异常姿态"""
# 检查脚是否在仪表台上
left_ankle = keypoints[15] # left_ankle
right_ankle = keypoints[16] # right_ankle

# 简单规则:脚踝高度超过肩膀高度
left_shoulder = keypoints[5]
right_shoulder = keypoints[6]

if left_ankle[1] < left_shoulder[1] or right_ankle[1] < right_shoulder[1]:
return True

return False

性能优化技巧

1. 批处理优化

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
# 批处理推理
def batch_infer(model, images: list, batch_size: int = 4):
"""
批处理推理

Args:
model: YOLO26 TRT 模型
images: 图像列表
batch_size: 批大小

Returns:
results: 批处理结果
"""
results = []

for i in range(0, len(images), batch_size):
batch = images[i:i+batch_size]

# 预处理批
batch_tensor = np.stack([model.preprocess(img) for img in batch])

# 批推理
batch_results = model.infer_batch(batch_tensor)
results.extend(batch_results)

return results

2. 异步推理

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
import threading
import queue

class AsyncYOLO26:
"""异步 YOLO26 推理"""

def __init__(self, engine_path: str):
self.model = YOLO26TRT(engine_path)
self.queue = queue.Queue(maxsize=10)
self.running = True

# 启动推理线程
self.thread = threading.Thread(target=self._infer_loop)
self.thread.start()

def _infer_loop(self):
"""推理循环"""
while self.running:
try:
frame = self.queue.get(timeout=0.1)
result = self.model.infer(frame)
# 处理结果...
except queue.Empty:
continue

def submit(self, frame):
"""提交帧"""
if not self.queue.full():
self.queue.put(frame)

总结

YOLO26 边缘部署要点

要点 建议
模型选择 YOLO26n/s 适合边缘
量化方式 Smart Quantizer INT8
精度损失 < 1% mAP
速度提升 10-15% FPS
部署平台 Jetson Orin / Snapdragon

IMS 应用建议

场景 模型 延迟
DMS 物体检测 YOLO26n 1.7 ms
OMS 姿态估计 YOLO26-pose 3.5 ms
安全带检测 YOLO26-seg 2.1 ms

结论: YOLO26 是 IMS 边缘部署的最佳选择,INT8 量化后精度损失 <1%,延迟满足实时要求。


YOLO26 边缘部署实战:INT8 量化与 TensorRT 优化详解
https://dapalm.com/2026/07/13/2026-07-13-yolo26-edge-deployment-tensorrt-int8-quantization-guide/
作者
Mars
发布于
2026年7月13日
许可协议