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.

Tóm tắt nhanh
  • Đ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ạng xyxy, 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:

HeadMục đíchĐầu ra phát hiệnHậ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-EndDữ 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 inferenceexport, 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, validationexport đều xử lý các model end-to-end ngay lập tức.

Không cần thay đổi code khi sử dụng Ultralytics API
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 / YOLO11YOLO26 (end-to-end)
Đầu ra phát hiện(N, nc + 4, 8400)(N, 300, 6)
Định dạng Boxxywh (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ụcTọa độ Box + điểm số lớp trên mỗi anchor[x1, y1, x2, y2, conf, class_id]
Yêu cầu NMSKhông
Hậu xử lýNMS + bộ lọc tin cậyChỉ bộ lọc tin cậy

Đối với các tác vụ segmentation, poseOBB, 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 đó Nbatch sizenc 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:

Sử dụng head one-to-many cho đầu ra dựa trên NMS truyền thống
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.jsMNN.

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, IMXEdge TPU.

Điều gì xảy ra khi end-to-end không được hỗ trợ

Khi bạn export sang một trong các định dạng này, Ultralytics tự động chuyển sang head one-to-many và ghi lại một cảnh báo — không cần can thiệp thủ công. Điều này có nghĩa là bạn sẽ cần NMS trong pipeline inference của mình cho các định dạng này, giống như với YOLOv8 hoặc YOLO11.

TensorRT + INT8

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 CPUNhanh hơn tới 43%Baseline
Tác động đến mAP~0.5 mAP thấp hơnBằng hoặc vượt qua YOLO11
Hậu xử lýChỉ bộ lọc tin cậyPipeline NMS đầy đủ
Độ phức tạp khi triển khaiTối thiểuYê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ặc yolo26n-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, poseOBB. Cũng cần lưu ý sự thay đổi định dạng box từ xywh sang xyxy
  • 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=False với nms=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 scenes

Lư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 raMô 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:

Kiểm tra xem model có phải là end-to-end hay không
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 enabled

Ngoà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 estimationoriented 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
Detectionyolo26n.pt(N, 300, 6)
Segmentationyolo26n-seg.pt(N, 300, 38) + proto (N, 32, 160, 160)
Poseyolo26n-pose.pt(N, 300, 57)
OBByolo26n-obb.pt(N, 300, 7)

Bình luận