Export để triển khai
Export best.pt sang ONNX, OpenVINO, TensorRT, CoreML, LiteRT hoặc QNN, sau đó chứng minh bản export khớp với model PyTorch trước khi triển khai.
best.pt cần Python và PyTorch để chạy; điện thoại, trình duyệt, Jetson và máy chủ production thường không có các thành phần này. Export mode chuyển model thành một tệp độc lập cho các runtime đó chỉ bằng một lệnh gọi. Tuy nhiên, tệp export tải được không có nghĩa là tệp đó chính xác; so sánh thiếu cẩn trọng có thể khiến bản export đúng trông như bị lỗi hoặc che giấu lỗi trong bản export.
Trong bài học này, bạn sẽ export model viên thuốc sang ONNX, chạy model qua cùng API YOLO, chứng minh kết quả khớp với PyTorch về bounding box và mAP trên tập validation khi các thiết lập được đồng bộ, rồi chọn định dạng phù hợp với mục tiêu triển khai: ONNX, OpenVINO, TensorRT, CoreML, LiteRT hoặc QNN.
Thực hành
Ví dụ minh họa: Export sang ONNX#

yolo export model=runs/detect/pills_v1/weights/best.pt format=onnxPyTorch: starting from 'runs/detect/pills_v1/weights/best.pt' with input shape (1, 3, 320, 320) BCHW and output shape(s) (1, 5, 2100) (5.2 MB)
ONNX: export success ✅ 0.9s, saved as 'runs/detect/pills_v1/weights/best.onnx' (9.3 MB)
Predict: yolo predict task=detect model=runs/detect/pills_v1/weights/best.onnx imgsz=320
Validate: yolo val task=detect model=runs/detect/pills_v1/weights/best.onnx imgsz=320 data=my_dataset/data.yamlGiải thích từng dòng:
input shape (1, 3, 320, 320): một ảnh, 3 kênh màu, hình vuông cố định 320×320 —imgszdùng khi huấn luyện được tích hợp sẵn trong tệp.output shape(s) (1, 5, 2100): 4 giá trị hộp cộng với 1 điểm số lớp cho 2.100 hộp ứng viên; theo mặc định, NMS chạy bên ngoài graph.9.3 MB: tệp ONNX lưu trọng số FP32 nên lớn hơn.ptFP16.Predict:/Validate:: các lệnh dựng sẵn cho tệp đã export, vớiimgszphù hợp.
Một vài tham số đáp ứng phần lớn nhu cầu; hướng dẫn tích hợp ONNX liệt kê các tham số còn lại.
| Đối số | Mặc định | Dùng để |
|---|---|---|
imgsz | Kích thước khi huấn luyện | Export với kích thước đầu vào cố định khác, ví dụ imgsz=640 |
dynamic | False | Chấp nhận kích thước đầu vào thay đổi thay vì một shape cố định |
quantize | Không có (FP32) | 16 cho trọng số FP16 (yolo26n.onnx giảm dung lượng từ 9.5 MB xuống 4.8 MB); 8 cho INT8 nếu định dạng hỗ trợ |
nms | Không có | nms=True tích hợp NMS trong graph, vì vậy runtime trả về các hộp cuối cùng |
Ví dụ minh họa: Chứng minh bản export khớp#
Lớp YOLO cũng tải được các tệp đã export, vì vậy mã predict ở phần trước hoạt động nguyên trạng. So sánh cả hai tệp trên cùng một ảnh validation:
from ultralytics import YOLO
image = "my_dataset/images/val/Frame_144.jpg"
pt = YOLO("runs/detect/pills_v1/weights/best.pt")(image, rect=False, verbose=False)[0] # square input, like ONNX
onnx = YOLO("runs/detect/pills_v1/weights/best.onnx")(image, verbose=False)[0]
print(f"pt: {len(pt.boxes)} pills, mean conf {pt.boxes.conf.mean():.3f}")
print(f"onnx: {len(onnx.boxes)} pills, mean conf {onnx.boxes.conf.mean():.3f}")
print(f"max box difference: {(pt.boxes.xyxy - onnx.boxes.xyxy).abs().max():.4f} px")pt: 25 pills, mean conf 0.870
onnx: 25 pills, mean conf 0.870
max box difference: 0.0002 pxSố lượng giống nhau, confidence giống nhau, các hộp giống nhau đến từng phần nhỏ của pixel. Tiếp theo là phép kiểm tra chặt chẽ hơn: validation trên toàn bộ tập:
from ultralytics import YOLO
pt = YOLO("runs/detect/pills_v1/weights/best.pt").val(data="my_dataset/data.yaml", rect=False, verbose=False)
onnx = YOLO("runs/detect/pills_v1/weights/best.onnx").val(data="my_dataset/data.yaml", verbose=False)
print(f".pt mAP50-95 {pt.box.map:.4f}")
print(f".onnx mAP50-95 {onnx.box.map:.4f}").pt mAP50-95 0.6570
.onnx mAP50-95 0.6570Giống hệt nhau. (Validation hình chữ nhật mặc định trên tệp .pt đạt 0.659: chênh lệch nhỏ do padding đầu vào, không phải do quá trình export.)
Sau khi khớp, hãy đo thời gian bằng yolo benchmark trên thiết bị mục tiêu để biết tốc độ thực tế trước khi triển khai.
Chọn định dạng cho mục tiêu triển khai#

| Mục tiêu | Định dạng | Ghi chú |
|---|---|---|
| Lựa chọn mặc định có tính di động cao: máy chủ và máy tính để bàn chạy Linux, Windows và Mac | onnx | ONNX Runtime trên CPU hoặc GPU; định dạng export dễ kiểm chứng nhất |
| GPU NVIDIA và Jetson | engine (TensorRT) | Nhanh nhất trên NVIDIA; export trực tiếp trên thiết bị. Xem Tối ưu hóa với TensorRT |
| CPU và iGPU Intel | openvino | Tăng tốc CPU thực sự nhờ kernel Intel. Xem OpenVINO trên CPU |
| Ứng dụng cho iPhone, iPad và Mac | coreml | Native; sử dụng Apple Neural Engine |
| Android và các thiết bị di động hoặc nhúng khác | litert | Khuyến nghị INT8 cho thiết bị di động |
| NPU Snapdragon | qnn | Tăng tốc Hexagon HTP; mặc định dùng trọng số INT8 với activation 16-bit; chọn kiến trúc HTP bằng name |
| Trình duyệt web | onnx với ONNX Runtime Web | Các model nhỏ hơn là lựa chọn khả thi: n và s |
from ultralytics import YOLO
model = YOLO("runs/detect/pills_v1/weights/best.pt")
model.export(format="onnx") # đa nền tảng: ONNX Runtime
model.export(format="openvino") # CPU / iGPU Intel
model.export(format="engine", quantize=16) # NVIDIA TensorRT, FP16 (chạy trên GPU đích)
model.export(format="coreml") # Apple iOS / macOS
model.export(format="litert", quantize=8, data="my_dataset/data.yaml") # Android / edge, INT8
model.export(format="qnn", name="73", data="my_dataset/data.yaml") # NPU Qualcomm Snapdragon (HTP v73); hiệu chỉnh trên dữ liệu của riêng bạnMỗi lần export sẽ ghi các tệp bên cạnh trọng số: best.onnx, best_openvino_model/, best.engine, v.v. Hãy bắt đầu với ONNX ngay cả khi cuối cùng bạn dùng định dạng khác: đây là định dạng dễ kiểm tra nhất và là đầu vào cho một số toolchain khác. Hướng dẫn các tùy chọn triển khai so sánh mọi định dạng, còn Chọn mục tiêu triển khai hướng dẫn bạn đưa ra quyết định.
Lượng tử hóa model đánh đổi độ chính xác để giảm kích thước và tăng tốc độ. FP16 (quantize=16) giảm một nửa dung lượng tệp mà hầu như không ảnh hưởng đến độ chính xác. INT8 (quantize=8) còn nhỏ và nhanh hơn, nhưng cần ảnh hiệu chỉnh — các frame đại diện được chạy qua trong quá trình export để chọn phạm vi giá trị; Ultralytics khuyến nghị tối thiểu 300 ảnh. Luôn đánh giá model INT8 trước khi phát hành: mức suy giảm có thể không đáng kể hoặc rất lớn, tùy thuộc vào model và tập hiệu chỉnh.
Tránh những lỗi này#
Triệu chứng: model .pt phát hiện 35 viên thuốc trong Frame_144.jpg, còn tệp ONNX phát hiện 25 viên, khiến bạn nghĩ export bị lỗi. Nguyên nhân: suy luận PyTorch padding mỗi ảnh thành hình chữ nhật nhỏ nhất có kích thước căn theo stride (192×320 cho các frame 16:9 này), trong khi model ONNX tĩnh luôn nhận ảnh vuông 320×320. Đầu vào khác nhau dẫn đến các detection có độ tin cậy thấp khác nhau. Cách khắc phục: truyền rect=False cho model .pt khi so sánh, như trong parity.py.
Triệu chứng: bạn truyền imgsz=640 cho best.onnx nhưng log vẫn ghi 320x320. Nguyên nhân: export tĩnh có một kích thước đầu vào duy nhất, được đặt tại thời điểm export. Cách khắc phục: export ở kích thước bạn sẽ dùng (imgsz=640) hoặc export với dynamic=True.
.engine được tạo trên A100 sẽ không chạy trên Jetson Orin và có thể không tương thích sau khi nâng cấp TensorRT. Hãy export trên thiết bị đích bằng phiên bản TensorRT mà thiết bị sẽ chạy. ONNX có tính di động; engine thì không.
Không truyền data khi export INT8, Ultralytics sẽ cảnh báo rồi hiệu chuẩn trên mẫu COCO8 mặc định — tám ảnh không giống các viên thuốc của bạn chút nào. Hãy truyền dataset của bạn: model.export(format="litert", quantize=8, data="my_dataset/data.yaml").
Bạn đã triển khai#
Giờ đây, bạn đã có một best.pt được huấn luyện, bằng chứng đánh giá đặt cạnh baseline, một tệp đã export cho runtime và xác nhận rằng bản export khớp với bản gốc. Đó là toàn bộ quy trình — dữ liệu, huấn luyện, đánh giá, export, triển khai — và các nhóm vận hành production thực hiện quy trình này theo lịch. Ultralytics YOLO trong môi trường production tiếp nối từ bản export đã được xác minh của bạn, bao quát các runtime được tối ưu hóa, pipeline tracking, phục vụ đa luồng và giám sát.
Hiển thị lời giải
from ultralytics import YOLO
# Train
model = YOLO("yolo26n.pt")
model.train(data="my_dataset/data.yaml", epochs=10, imgsz=320, name="pills_e2e")
# Validate
metrics = model.val()
print(f"mAP50-95 = {metrics.box.map:.3f}") # 0.659
# Export
model.export(format="onnx")parity.py: pt 25 pills, onnx 25 pills, max box difference 0.0002 px
without rect: pt 35 pills (192x320 input) vs onnx 25 (320x320): input mismatch, not an export bug
val_export.py: .pt 0.6570, .onnx 0.6570
Target: Intel laptop CPU -> openvino, for faster CPU inference than ONNX Runtime