Tìm hiểu về Phát hiện end-to-end trong Ultralytics YOLO26
Giới thiệu
Nếu bạn đang nâng cấp lên YOLO26 từ một model cũ hơn như YOLOv8 hoặc YOLO11, một trong những thay đổi lớn nhất mà bạn sẽ nhận thấy là việc loại bỏ Non-Maximum Suppression (NMS). Các model YOLO truyền thống tạo ra hàng nghìn dự đoán chồng chéo cần một bước hậu xử lý NMS riêng biệt để lọc ra các phát hiện cuối cùng. Điều này làm tăng độ trễ, làm phức tạp các đồ thị export và có thể hoạt động không nhất quán trên các nền tảng phần cứng khác nhau.
YOLO26 áp dụng một cách tiếp cận khác. Nó xuất ra các phát hiện cuối cùng trực tiếp từ model — không cần bộ lọc bên ngoài. Đây được gọi là end-to-end object detection, và nó được bật theo mặc định trong tất cả các model YOLO26. Kết quả là một pipeline triển khai đơn giản hơn, độ trễ thấp hơn và tốc độ inference nhanh hơn tới 43% trên CPU.
Hướng dẫn này sẽ giúp bạn hiểu những thay đổi, liệu bạn có cần cập nhật code của mình không, những định dạng export nào hỗ trợ inference end-to-end và cách di chuyển suôn sẻ từ các model YOLO cũ hơn.
Để có cái nhìn sâu hơn về động lực đằng sau sự thay đổi kiến trúc này, hãy xem bài đăng trên blog của Ultralytics về lý do tại sao YOLO26 loại bỏ NMS.
- Đang sử dụng Ultralytics API hoặc CLI? Không cần thay đổi — chỉ cần đổi tên model của bạn thành
yolo26n.pt. - Đang sử dụng code inference tùy chỉnh (ONNX Runtime, TensorRT, v.v.)? Cập nhật phần hậu xử lý của bạn — đầu ra phát hiện bây giờ là
(N, 300, 6)ở định dạngxyxy, không cần NMS. Các tác vụ khác sẽ đính kèm dữ liệu bổ sung (hệ số mask, keypoints hoặc góc). - Đang xuất model (Export)? Hầu hết các định dạng hỗ trợ đầu ra end-to-end một cách nguyên bản. Tuy nhiên, một vài định dạng (NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX, và Edge TPU) sẽ tự động quay lại đầu ra truyền thống do các hạn chế về toán tử không được hỗ trợ (ví dụ:
torch.topk).
Cách thức hoạt động của Phát hiện End-to-End
YOLO26 sử dụng kiến trúc dual-head trong quá trình training. Cả hai head đều chia sẻ cùng backbone và neck, nhưng tạo ra đầu ra theo những cách khác nhau:
| Head | Mục đích | Đầu ra phát hiện | Hậu xử lý |
|---|---|---|---|
| One-to-One (mặc định) | Inference end-to-end | (N, 300, 6) | Chỉ ngưỡng tin cậy (Confidence threshold) |
| One-to-Many | Đầu ra YOLO truyền thống | (N, nc + 4, 8400) | Yêu cầu NMS |
Các hình dạng (shape) trên dành cho phát hiện. Các tác vụ khác mở rộng đầu ra one-to-one với dữ liệu bổ sung cho mỗi phát hiện:
| Tác vụ | Đầu ra End-to-End | Dữ liệu bổ sung |
|---|---|---|
| Detection | (N, 300, 6) | — |
| Segmentation | (N, 300, 6 + nm) + proto (N, nm, H, W) | nm hệ số mask (mặc định 32) |
| Pose | (N, 300, 57) | 17 keypoints × 3 (x, y, độ hiển thị) |
| OBB | (N, 300, 7) | Góc xoay |
Trong quá trình training, cả hai head đều chạy đồng thời — head one-to-many cung cấp tín hiệu học tập phong phú hơn, trong khi head one-to-one học cách tạo ra các dự đoán sạch, không chồng chéo. Trong quá trình inference và export, chỉ head one-to-one hoạt động theo mặc định, tạo ra tối đa 300 phát hiện mỗi ảnh ở định dạng [x1, y1, x2, y2, confidence, class_id].
Khi bạn gọi model.fuse(), nó sẽ gộp các lớp Conv + BatchNorm để tăng tốc độ inference và trên các model end-to-end, nó cũng loại bỏ head one-to-many — giảm kích thước model và số lượng FLOPs. Để biết thêm chi tiết về kiến trúc dual-head, hãy xem trang model YOLO26.
Tôi có cần thay đổi code của mình không?
Sử dụng Ultralytics Python API hoặc CLI
Không cần thay đổi. Nếu bạn sử dụng Ultralytics Python API hoặc CLI tiêu chuẩn, mọi thứ sẽ hoạt động tự động — dự đoán, validation và export đều xử lý các model end-to-end ngay lập tức.
from ultralytics import YOLO
# Load a YOLO26 model
model = YOLO("yolo26n.pt")
# Predict — no NMS step, no code changes
results = model.predict("image.jpg")Sử dụng Code Inference tùy chỉnh
Có, định dạng đầu ra khác biệt. Nếu bạn đã viết logic hậu xử lý tùy chỉnh cho YOLOv8 hoặc YOLO11 (ví dụ: khi chạy inference với ONNX Runtime hoặc TensorRT), bạn sẽ cần cập nhật nó để xử lý hình dạng đầu ra mới:
| YOLOv8 / YOLO11 | YOLO26 (end-to-end) | |
|---|---|---|
| Đầu ra phát hiện | (N, nc + 4, 8400) | (N, 300, 6) |
| Định dạng Box | xywh (tâm x, tâm y, chiều rộng, chiều cao) | xyxy (trái trên x, trái trên y, phải dưới x, phải dưới y) |
| Bố cục | Tọa độ Box + điểm số lớp trên mỗi anchor | [x1, y1, x2, y2, conf, class_id] |
| Yêu cầu NMS | Có | Không |
| Hậu xử lý | NMS + bộ lọc tin cậy | Chỉ bộ lọc tin cậy |
Đối với các tác vụ segmentation, pose và OBB, YOLO26 đính kèm dữ liệu đặc thù của tác vụ vào mỗi phát hiện — hãy xem bảng hình dạng đầu ra ở trên.
Trong đó N là batch size và nc là số lượng lớp (ví dụ: 80 cho COCO).
Với các model end-to-end, việc hậu xử lý trở nên đơn giản hơn nhiều — ví dụ: khi sử dụng ONNX Runtime:
import onnxruntime as ort
# Load and run the exported end-to-end model
session = ort.InferenceSession("yolo26n.onnx")
output = session.run(None, {session.get_inputs()[0].name: input_tensor})
# End-to-end output: (batch, 300, 6) → [x1, y1, x2, y2, confidence, class_id]
detections = output[0][0] # first image in batch
detections = detections[detections[:, 4] > conf_threshold] # confidence filter — that's it!Chuyển sang Head One-to-Many
Nếu bạn cần định dạng đầu ra YOLO truyền thống (ví dụ: để tái sử dụng code hậu xử lý dựa trên NMS hiện có), bạn có thể chuyển sang head one-to-many bất kỳ lúc nào bằng cách thiết lập end2end=False:
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
# Prediction with NMS (traditional behavior)
results = model.predict("image.jpg", end2end=False)
# Validation with NMS
metrics = model.val(data="coco.yaml", end2end=False)
# Export without end-to-end
model.export(format="onnx", end2end=False)Khả năng tương thích định dạng Export
Hầu hết các định dạng export đều hỗ trợ inference end-to-end ngay lập tức, bao gồm ONNX, TensorRT, CoreML, OpenVINO, TFLite, TF.js và MNN.
Các định dạng sau đây không hỗ trợ end-to-end và tự động quay lại head one-to-many: NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX và Edge TPU.
TensorRT hỗ trợ end-to-end, nhưng nó bị tự động vô hiệu hóa khi export với int8=True trên TensorRT ≤10.3.0.
Sự đánh đổi về Độ chính xác và Tốc độ
Phát hiện end-to-end mang lại những lợi ích đáng kể về triển khai với tác động tối thiểu đến độ chính xác:
| Chỉ số | End-to-End (mặc định) | One-to-Many + NMS (end2end=False) |
|---|---|---|
| Tốc độ Inference CPU | Nhanh hơn tới 43% | Baseline |
| Tác động đến mAP | ~0.5 mAP thấp hơn | Bằng hoặc vượt qua YOLO11 |
| Hậu xử lý | Chỉ bộ lọc tin cậy | Pipeline NMS đầy đủ |
| Độ phức tạp khi triển khai | Tối thiểu | Yêu cầu thực thi NMS |
Đối với hầu hết các ứng dụng thực tế, sự khác biệt ~0.5 mAP là không đáng kể, đặc biệt khi cân nhắc đến các lợi ích về tốc độ và sự đơn giản. Nếu độ chính xác tối đa là ưu tiên hàng đầu của bạn, bạn luôn có thể quay lại head one-to-many bằng cách sử dụng end2end=False.
Xem các chỉ số hiệu suất YOLO26 để biết các điểm chuẩn chi tiết trên tất cả các kích thước model (n, s, m, l, x).
Di chuyển từ YOLOv8 hoặc YOLO11
Nếu bạn đang nâng cấp một dự án hiện có lên YOLO26, đây là danh sách kiểm tra nhanh để đảm bảo quá trình chuyển đổi suôn sẻ:
- Người dùng Ultralytics API / CLI: Không cần thay đổi — chỉ cần cập nhật tên model thành
yolo26n.pt(hoặcyolo26n-seg.pt,yolo26n-pose.pt,yolo26n-obb.pt) - Code hậu xử lý tùy chỉnh: Cập nhật để xử lý các hình dạng đầu ra mới —
(N, 300, 6)cho phát hiện, cộng với dữ liệu đặc thù tác vụ cho segmentation, pose và OBB. Cũng cần lưu ý sự thay đổi định dạng box từxywhsangxyxy - Export pipelines: Kiểm tra phần khả năng tương thích định dạng ở trên cho định dạng mục tiêu của bạn
- TensorRT + INT8: Xác minh phiên bản TensorRT của bạn là >10.3.0 để được hỗ trợ end-to-end
- FP16 exports: Nếu bạn cần tất cả các đầu ra ở định dạng FP16, hãy export với
end2end=False— xem tại sao output0 vẫn là FP32 - iOS / CoreML: End-to-end được hỗ trợ đầy đủ. Nếu bạn cần hỗ trợ Xcode Preview, hãy sử dụng
end2end=Falsevớinms=True - Edge devices (NCNN, RKNN): Các định dạng này tự động quay lại one-to-many, vì vậy hãy bao gồm NMS trong pipeline trên thiết bị của bạn
Câu hỏi thường gặp (FAQ)
Tôi có thể sử dụng đồng thời end2end=True và nms=True không?
Không. Các tùy chọn này loại trừ lẫn nhau. Nếu bạn thiết lập nms=True trên một model end-to-end trong quá trình export, nó sẽ tự động bị buộc thành nms=False kèm theo một cảnh báo. Head end-to-end đã tự xử lý việc lọc trùng lặp bên trong, vì vậy NMS bên ngoài là không cần thiết.
Tuy nhiên, end2end=False kết hợp với nms=True là một cấu hình hợp lệ — nó tích hợp NMS truyền thống vào đồ thị export. Điều này có thể hữu ích cho các bản export CoreML vì nó cho phép bạn sử dụng trực tiếp chức năng Preview trong Xcode với model phát hiện.
Tham số max_det kiểm soát điều gì trong các model end-to-end?
Tham số max_det (mặc định: 300) thiết lập số lượng phát hiện tối đa mà head one-to-one có thể xuất ra trên mỗi ảnh. Bạn có thể điều chỉnh nó tại thời điểm inference hoặc export:
model.predict("image.jpg", max_det=100) # fewer detections, slightly faster
model.export(format="onnx", max_det=500) # more detections for dense scenesLưu ý rằng các checkpoint YOLO26 mặc định đã được training với max_det=300. Mặc dù bạn có thể tăng giá trị này, head one-to-one đã được tối ưu hóa trong quá trình training để tạo ra tối đa 300 phát hiện sạch, vì vậy các phát hiện vượt quá giới hạn đó có thể có chất lượng thấp hơn. Nếu bạn cần nhiều hơn 300 phát hiện mỗi ảnh, hãy cân nhắc việc train lại với giá trị max_det cao hơn.
Model ONNX đã export của tôi xuất ra (1, 300, 6) — điều đó có đúng không?
Có, đó là định dạng đầu ra end-to-end dự kiến cho phát hiện: batch size là 1, tối đa 300 phát hiện, mỗi phát hiện có 6 giá trị [x1, y1, x2, y2, confidence, class_id]. Chỉ cần lọc theo ngưỡng tin cậy là xong — không cần NMS.
Đối với các tác vụ khác, hình dạng đầu ra sẽ khác:
| Tác vụ | Hình dạng đầu ra | Mô tả |
|---|---|---|
| Detection | (1, 300, 6) | [x1, y1, x2, y2, conf, class_id] |
| Segmentation | (1, 300, 38) + (1, 32, 160, 160) | 6 giá trị box + 32 hệ số mask, cộng thêm một tensor mask nguyên mẫu |
| Pose | (1, 300, 57) | 6 giá trị box + 17 keypoint × 3 (x, y, độ hiển thị) |
| OBB | (1, 300, 7) | 6 giá trị box + 1 góc xoay |
Làm thế nào để tôi kiểm tra xem model đã xuất của mình có phải là end-to-end hay không?
Bạn có thể kiểm tra bằng Ultralytics Python API hoặc trực tiếp kiểm tra metadata của model ONNX đã xuất:
from ultralytics import YOLO
model = YOLO("yolo26n.onnx")
model.predict(verbose=False) # run predict to setup predictor first
print(model.predictor.model.end2end) # True if end-to-end is enabledNgoài ra, hãy kiểm tra output shape — các model phát hiện end-to-end có output (1, 300, 6), trong khi các model truyền thống có output (1, nc + 4, 8400). Đối với các hình dạng tác vụ khác, hãy xem FAQ về output shape.
End-to-end có được hỗ trợ cho các tác vụ segmentation, pose và OBB không?
Có. Tất cả các biến thể tác vụ YOLO26 — detection, segmentation, pose estimation và oriented object detection (OBB) — đều hỗ trợ inference end-to-end theo mặc định. Tùy chọn fallback end2end=False cũng khả dụng trên tất cả các tác vụ.
Mỗi tác vụ mở rộng output phát hiện cơ bản bằng dữ liệu cụ thể cho tác vụ đó:
| Tác vụ | Model | Đầu ra End-to-End |
|---|---|---|
| Detection | yolo26n.pt | (N, 300, 6) |
| Segmentation | yolo26n-seg.pt | (N, 300, 38) + proto (N, 32, 160, 160) |
| Pose | yolo26n-pose.pt | (N, 300, 57) |
| OBB | yolo26n-obb.pt | (N, 300, 7) |