Giải thích Kiến trúc YOLO: Từ YOLOv3 đến YOLO26#
Mỗi mô hình Ultralytics YOLO được xây dựng từ ba giai đoạn: một backbone (thân mạng) trích xuất đặc trưng, một neck (cổ mạng) kết hợp các đặc trưng qua các tỷ lệ khác nhau, và một head (đầu ra) dự đoán hộp giới hạn và lớp. Hướng dẫn này ghi lại các mô-đun tạo nên từng giai đoạn và sự thay đổi của chúng từ YOLOv3 đến YOLO26, truy xuất từng thành phần đến định nghĩa của chúng trong các tệp cấu hình dưới ultralytics/cfg/models/ và các lớp mô-đun trong ultralytics/nn/modules/.
Mỗi mô hình được định nghĩa khai báo trong một tệp YAML dưới dạng một danh sách các lớp có thứ tự, trong đó mọi lớp tuân theo định dạng [from, repeats, module, args]: lớp (các lớp) nào cung cấp đầu vào cho nó, số lần mô-đun lặp lại, lớp mô-đun (Conv, C3k2, SPPF, Detect, …), và các đối số hàm tạo của nó. Hướng dẫn Cấu hình YAML của Mô hình tài liệu hóa định dạng này — bao gồm cách repeats và args co giãn theo các hệ số độ sâu và chiều rộng của biến thể — cùng với hệ thống phân giải mô-đun một cách đầy đủ. Hướng dẫn này tập trung vào bản thân các mô-đun và cách chúng thay đổi qua từng phiên bản.
Ba Giai đoạn#
Mỗi mô hình Ultralytics YOLO định tuyến hình ảnh qua ba giai đoạn tuần tự, mỗi giai đoạn có một nhiệm vụ riêng biệt:
| Giai đoạn | Công việc | Đầu ra |
|---|---|---|
| Backbone | Trích xuất đặc trưng từ hình ảnh đầu vào ở nhiều độ phân giải | Bản đồ đặc trưng (feature map) ở các stride 8, 16, và 32 (P3, P4, P5) |
| Neck | Kết hợp các đặc trưng qua các quy mô để cả đối tượng nhỏ và lớn đều có ngữ cảnh | Bản đồ đặc trưng đã được kết hợp đa quy mô |
| Head | Dự đoán các bounding box và điểm số lớp từ các đặc trưng đã kết hợp | Số lần phát hiện trên mỗi điểm neo (anchor point) |
Đơn vị cơ bản là khối Conv (được định nghĩa trong conv.py): một phép tích chập 2 chiều, chuẩn hóa theo lô, và một hàm kích hoạt SiLU, được áp dụng theo trình tự. Mọi mô-đun lớn hơn bên dưới đều được xây dựng bằng cách kết hợp các khối Conv.
Sơ đồ Kiến trúc#
Mỗi phiên bản giữ nguyên bộ khung backbone → neck → head và thay đổi các giai đoạn cụ thể. Các tab bên dưới hiển thị cấu trúc theo từng phiên bản: các giai đoạn backbone và neck tuân theo cấu hình trong ultralytics/cfg/models/, trong khi các head YOLOv3 và YOLOv5 được vẽ theo dạng dựa trên neo (anchor-based) ban đầu thay cho head biến thể không dùng neo u mà cấu hình gói của chúng thực tế sử dụng. Việc chuyển đổi qua các tab cho thấy những gì mỗi thế hệ đã bổ sung. Tóm lại, tiến trình là: YOLOv3 là bộ phát hiện chỉ dùng FPN, dựa trên neo; YOLOv5 bổ sung đường dẫn PAN từ dưới lên và SPPF; YOLOv8 chuyển sang khối C2f với head không dùng neo, DFL; YOLO11 chèn cơ chế chú ý C2PSA và khối C3k2; và YOLO26 bổ sung phần dư SPPF và làm cho head không cần NMS và không cần DFL. Màu sắc các nút tuân theo quy ước sơ đồ tài liệu: màu xanh lục là đầu vào, màu xanh lam là backbone, màu xám xanh là gộp không gian và chú ý, màu cam là neck, màu tím là head và đầu ra.
flowchart TD
IN[Input 640x640]:::start --> ST[Conv stem<br/>5x stride-2 down to P1-P5]:::proc
ST --> BB[Darknet-53 backbone<br/>stacked Bottleneck]:::proc
BB --> FPN[Neck FPN only<br/>top-down Upsample + Concat]:::decide
FPN --> HD[Detect head<br/>3 scales, anchor-based]:::out
HD --> O[Predictions + NMS]:::out
classDef start fill:#4CAF50,color:#fff
classDef proc fill:#2196F3,color:#fff
classDef decide fill:#FF9800,color:#fff
classDef out fill:#9C27B0,color:#fffCác sơ đồ YOLOv3 và YOLOv5 hiển thị head dựa trên neo ban đầu. Gói ultralytics cung cấp các cấu hình YOLOv3u và YOLOv5u không dùng neo — cùng các backbone Darknet-53 và C3 với head Detect của YOLOv8 — được mô tả tại phần Đầu dò Phát hiện.
Khối Backbone: Bottleneck → C3 → C2f → C3k2#
Backbone xếp chồng một khối CSP (Cross-Stage Partial) lặp lại giữa các lớp giảm mẫu stride-2 Conv. Khối lặp lại đó là phần thay đổi nhiều nhất giữa các phiên bản. Tất cả các khối dưới đây nằm trong block.py; c1/c2 là các kênh đầu vào/đầu ra và c = 0.5 * c2 là chiều rộng ẩn.
Bottleneck (YOLOv3)#
Đơn vị cơ sở là Bottleneck: hai lớp Conv (kernel mặc định (3, 3)) với một phép cộng phần dư tùy chọn khi shortcut=True và c1 == c2. Backbone Darknet-53 của YOLOv3 xếp chồng các thành phần này trực tiếp, không phân tách CSP, và phát hiện ở ba tỷ lệ (stride 8, 16, 32).
C3 (YOLOv5)#
C3 của YOLOv5 chia đầu vào qua hai phép tích chập 1x1: cv1 cấp cho các khối Bottleneck tuần tự n (kernel (1, 1) rồi (3, 3)), cv2 bỏ qua chúng. Hai đường dẫn được nối (concatenate) và hợp nhất bởi 1x1 Conv thứ ba:
def forward(self, x):
# C3: bottleneck path m(cv1(x)) concatenated with bypass cv2(x), then fused by cv3
return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1))Chỉ đầu ra bottleneck cuối cùng mới đến được phép tích chập hợp nhất, do đó cv3 nhìn thấy 2 bản đồ đặc trưng.
C2f (YOLOv8)#
C2f của YOLOv8 ("CSP Bottleneck với 2 phép tích chập, nhanh hơn") thay đổi các đặc trưng nào đến được phép tích chập hợp nhất:
cv1 = Conv(c1, 2 * c, 1), sau đóchunk(2)chia đầu ra thành hai tensor cóckênh.- Các khối
nBottleneck(c, c)(kernel(3, 3),(3, 3)) chạy tuần tự, mỗi khối nhận đầu ra của khối trước đó. - Tất cả các tensor trung gian của
n + 2được nối lại và hợp nhất bởicv2 = Conv((2 + n) * c, c2, 1).
Nơi C3 chuyển 2 bản đồ đặc trưng vào phép tích chập hợp nhất của nó, C2f chuyển n + 2 — mọi đầu ra bottleneck trung gian đều được tái sử dụng.
C3k2 (YOLO11 và YOLO26)#
YOLO11 và YOLO26 sử dụng C3k2, một lớp con của C2f thay thế đơn vị lặp lại. Mỗi khối trong số các khối n trở thành, tùy thuộc vào các cờ hàm tạo:
- một
Bottleneckthông thường (mặc định,c3k=False), - một khối
C3k(c3k=True) — một biến thểC3với kích thước kernel có thể cấu hình, hoặc - một cặp
Bottleneck+PSABlock(attn=True).
Đối số YAML thứ hai thiết lập c3k; ví dụ [-1, 2, C3k2, [512, True]] xây dựng một mô-đun C3k2 tại 512 kênh đầu ra có các khối bên trong là C3k (vì c3k=True). Đối với các mô-đun CSP, trường repeats — ở đây là 2, trước khi được co giãn bởi hệ số độ sâu của biến thể — trở thành số lần lặp lại bên trong của khối thay vì xếp chồng các mô-đun riêng biệt.
Spatial Pooling: SPP → SPPF#
Ở cuối backbone, một khối gộp kim tự tháp không gian (spatial-pyramid-pooling) mở rộng trường tiếp nhận (receptive field). YOLOv5 đã thay thế SPP đa kernel ban đầu bằng SPPF (Spatial Pyramid Pooling - Fast): một MaxPool2d(kernel_size=5, stride=1, padding=2) duy nhất được áp dụng n = 3 lần liên tiếp, với đầu vào và cả ba đầu ra gộp được nối lại và hợp nhất bởi một 1x1 Conv. Điều này tương đương về mặt toán học với SPP(k=(5, 9, 13)) nhưng chi phí thấp hơn, bởi vì các phép gộp 5x5 chuỗi bao phủ các trường tiếp nhận của các kernel lớn hơn.
YOLO26 truyền một cờ đường tắt (SPPF, [1024, 5, 3, True]); kể từ c1 == c2 == 1024 ở lớp sâu nhất, SPPF bổ sung một kết nối phần dư (return y + x).
Spatial Attention: C2PSA (YOLO11+)#
YOLO11 đã bổ sung C2PSA sau SPPF. Đây là một khối CSP có nhánh hoạt động là một chồng các mô-đun n PSABlock (Position-Sensitive Attention): cv1 = Conv(c1, 2 * c, 1) chia các đặc trưng, một nửa đi qua chồng PSABlock, và cv2 = Conv(2 * c, c1, 1) hợp nhất phép nối. Mỗi PSABlock áp dụng cơ chế chú ý đa đầu theo sau bởi mạng chuyển tiếp hai lớp (Conv(c, 2 * c, 1) → Conv(2 * c, c, 1)), mỗi lớp có một kết nối phần dư. YOLO26 giữ nguyên backbone C3k2 + C2PSA đó.
Neck: FPN + PAN#
Cổ mạng (neck) hợp nhất các bản đồ đặc trưng P3/P4/P5 của backbone với một Mạng Kim tự tháp Đặc trưng (FPN) từ trên xuống theo sau bởi Mạng Tổng hợp Đường dẫn (PAN) từ dưới lên. Trong phần head của YAML, FPN là nn.Upsample + Concat (mang thông tin ngữ nghĩa xuống các độ phân giải cao hơn) và PAN là Conv + Concat stride-2 (mang thông tin định vị ngược lên):
# YOLO11 head (FPN top-down, then PAN bottom-up)
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 2, C3k2, [512, False]] # 13
# ... second upsample + concat to P3 ...
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 13], 1, Concat, [1]] # cat head P4 (PAN)
- [-1, 2, C3k2, [512, False]] # 19Neck tái sử dụng khối backbone của thế hệ đó — C3 trong YOLOv5, C2f trong YOLOv8, C3k2 trong YOLO11 và YOLO26 — do đó mỗi điểm hợp nhất chạy cùng một mô-đun mà backbone sử dụng. Ba đầu ra hợp nhất cấp cho head. YOLOv3 là ngoại lệ: neck của nó chỉ có FPN từ trên xuống (head YAML của nó không có giảm mẫu stride-2), không có đường dẫn PAN từ dưới lên mà YOLOv5 đã giới thiệu.
Detection Head: Dựa trên Anchor → Không Anchor → Không NMS#
Head chuyển đổi ba bản đồ đặc trưng được hợp nhất thành các dự đoán cho tác vụ phát hiện. Thiết kế của nó đã thay đổi qua các phiên bản, từ dựa trên neo sang không dùng neo và không cần NMS.
Không dùng neo, Detect tách rời#
YOLOv3 và YOLOv5 gốc sử dụng head dựa trên neo, kết cặp: các hộp neo được định nghĩa trước và một nhánh chung cho các dự đoán hộp và lớp. Các kho lưu trữ độc lập ultralytics/yolov3 và ultralytics/yolov5 giữ lại thiết kế dựa trên neo đó. Gói ultralytics chính thay vào đó cung cấp các biến thể YOLOv3u và YOLOv5u không dùng neo — cùng các backbone Darknet-53 và C3 với head Detect không dùng neo của YOLOv8 — và các cấu hình yolov3.yaml và yolov5.yaml được tài liệu hóa ở đây là các biến thể u này, không phải thiết kế lịch sử.
Head Detect (head.py) không dùng neo và được tách rời: trên mỗi cấp độ kim tự tháp, nó chạy hai nhánh song song, và dự đoán trực tiếp trên các điểm lưới thay vì dựa trên các hộp neo.
- Nhánh hộp (
cv2):Conv(x, c2, 3)→Conv(c2, c2, 3)→Conv2d(c2, 4 * reg_max, 1). - Nhánh lớp (
cv3): trong YOLO11 và YOLO26, hai khối tách sâu (DWConv+1x1 Conv) →Conv2d(c3, nc, 1); YOLOv8 sử dụng biến thể cũ, hai lớp3x3 Conv→Conv2d(c3, nc, 1).
Do đó, mỗi điểm neo phát ra no = nc + 4 * reg_max đầu ra. Việc loại bỏ các neo được định nghĩa trước sẽ loại bỏ kích thước và tỷ lệ khung hình của hộp neo khỏi các siêu tham số cần phải tinh chỉnh.
Distribution Focal Loss (DFL)#
YOLOv8 và YOLO11 hồi quy từng tọa độ trong số 4 tọa độ hộp dưới dạng một phân phối trên các thùng reg_max = 16 thay vì một vô hướng đơn lẻ (dạng tích phân từ Generalized Focal Loss). Mô-đun DFL định hình lại các kênh hộp 4 * reg_max thành (4, reg_max), áp dụng hàm softmax trên các thùng reg_max, và lấy chỉ mục thùng kỳ vọng — mỗi chỉ mục thùng được trọng số bởi xác suất softmax của nó, sau đó được cộng lại — làm tọa độ được dự đoán. Điều này được triển khai dưới dạng một phép tích chập 1x1 cố định có trọng số là các chỉ mục thùng arange(reg_max), do đó tổng có trọng số là một tích vô hướng duy nhất.
YOLO26: Không NMS, Không DFL#
YOLO26 thiết lập hai tham số YAML mà head đọc trực tiếp:
end2end: True—Detectsao chép sâu các nhánh của nó thành một head một-một (one2one_cv2/one2one_cv3) tạo ra một dự đoán duy nhất cho mỗi đối tượng, loại bỏ bước hậu xử lý Triệt tiêu Không Tối đa (NMS). Xem Hướng dẫn Phát hiện Đầu-cuối để biết chi tiết xuất và di chuyển.reg_max: 1— với một thùng,self.dfltrở thànhnn.Identity()vàno = nc + 4; head hồi quy tọa độ trực tiếp và không có thao tác DFL nào xuất hiện trong đồ thị ONNX được xuất.
Trên năm kích thước mô hình của mình (n/s/m/l/x), YOLO26 đạt 40.9-57.5 mAP trên COCO ở độ trễ T4 TensorRT 1.7-11.8 ms, như được báo cáo trong bài báo YOLO26.
Tóm tắt theo Phiên bản#
| Phiên bản | Khối Backbone | Spatial pooling | Cơ chế chú ý | Detection head | DFL |
|---|---|---|---|---|---|
| YOLOv3 | Darknet-53 (Bottleneck) | không có trong cấu hình cơ bản | không | Gốc: dựa trên neo; biến thể u: không dùng neo | không / có (u) |
| YOLOv5 | C3 (CSP) | SPPF | không | Gốc: dựa trên neo; biến thể u: không dùng neo | không / có (u) |
| YOLOv8 | C2f | SPPF | không | Không dùng anchor, tách biệt | có (reg_max=16) |
| YOLO11 | C3k2 | SPPF | C2PSA | Không dùng anchor, tách biệt | có (reg_max=16) |
| YOLO26 | C3k2 | SPPF + đường tắt | C2PSA | Không dùng neo, không cần NMS (end2end) | đã bị loại bỏ (reg_max=1) |
Để biết chi tiết về từng mô hình, bảng hiệu suất và ví dụ sử dụng, hãy xem các trang riêng lẻ cho YOLOv3, YOLOv5, YOLOv8, YOLO11, và YOLO26.
Tự Kiểm tra Kiến trúc#
Phương thức model.info() in ra bản tóm tắt lớp, tham số và FLOPs, và danh sách mô-đun đã phân tích cú pháp có sẵn trên model.model.model.
from ultralytics import YOLO
# Load a pretrained model
model = YOLO("yolo11n.pt")
# Fuse Conv + BatchNorm layers so counts match the published specs
model.fuse()
# Print a summary: layers, parameters, gradients, GFLOPs
model.info()
# Inspect the detection head (the last module in the network)
head = model.model.model[-1]
print(type(head).__name__, "| reg_max:", head.reg_max, "| end2end:", head.end2end)Chạy đoạn mã qua ba thế hệ cho thấy các thay đổi bằng số. Đây là các đầu ra mô hình đã hợp nhất thực tế từ gói ultralytics, khớp với số lượng tham số và FLOPs được công bố trên mỗi trang mô hình:
| Mô hình | Các lớp | Tham số | GFLOPs | reg_max | end2end | Lớp DFL |
|---|---|---|---|---|---|---|
| YOLOv8n | 72 | 3,151,904 | 8.7 | 16 | False | DFL |
| YOLO11n | 100 | 2,616,248 | 6.5 | 16 | False | DFL |
| YOLO26n | 122 | 2,408,932 | 5.4 | 1 | True | Identity |
YOLO26n báo cáo reg_max=1, end2end=True, và một lớp DFL Identity — chữ ký kiến trúc của head không cần NMS, không cần DFL của nó.
Giá trị tham số và FLOPs được báo cáo cho mô hình đã hợp nhất (model.fuse()), hợp nhất từng Conv và lớp chuẩn hóa theo lô của nó. Điều này khớp với các thông số kỹ thuật được công bố; một điểm kiểm tra (checkpoint) mới được tải báo cáo số lượng cao hơn một chút trước khi hợp nhất.
Kết luận#
Qua các phiên bản, kiến trúc YOLO thay đổi từng giai đoạn một: backbone chuyển từ Darknet-53 sang các khối C3, C2f, và C3k2 dựa trên CSP với cơ chế chú ý C2PSA; neck giữ nguyên cấu trúc FPN + PAN trong khi SPP trở thành SPPF; và head chuyển từ dựa trên neo sang không dùng neo, sau đó sang thiết kế đầu-cuối không cần NMS, không cần DFL của YOLO26.
Để định nghĩa các kiến trúc tùy chỉnh, hãy xem Hướng dẫn Cấu hình YAML của Mô hình, hoặc so sánh các mô-đun trên các trang mô hình. Nếu có thắc mắc, hãy liên hệ trên GitHub hoặc Discord.
Câu hỏi thường gặp#
Một mô hình YOLO có backbone giúp trích xuất các đặc trưng từ hình ảnh ở các stride 8, 16 và 32, một neck giúp hợp nhất các đặc trưng đó qua các thang đo với FPN và PAN, và một head giúp dự đoán BBox và điểm số lớp. Mọi mô hình Ultralytics YOLO từ YOLOv3 đến YOLO26 đều tuân theo thiết kế ba giai đoạn này.
C2f(YOLOv8) là một khối CSP nối các đầu ra của mọiBottleneckbên trong —n + 2bản đồ đặc trưng — trước phép tích chập hợp nhất của nó, trong khiC3cũ hơn chỉ chuyển 2.C3k2(YOLO11 và YOLO26) là một lớp con củaC2fcó thể thay thế mỗiBottleneckbằng một khốiC3k(biến thểC3với kích thước kernel có thể cấu hình) khi cờc3kcủa nó được đặt. Cả hai đều được định nghĩa trongblock.py.YOLO11 thực hiện ba thay đổi cấu trúc đối với YOLOv8: nó thay thế khối backbone và neck
C2fbằngC3k2, chèn một khối tự chú ýC2PSAsauSPPF, và chuyển nhánh phân loại của head sang các phép tích chập tách sâu nhẹ hơn. Cả hai đều giữ nguyên headDetecttách rời, không dùng neo với hồi quy DFLreg_max=16, do đó các thay đổi làm giảm số lượng tham số và FLOPs đồng thời nâng cao độ chính xác thay vì thiết kế lại giao diện phát hiện.Các mô hình Ultralytics YOLO hiện đại không dùng neo. YOLOv8, YOLO11 và YOLO26 sử dụng head
Detectkhông dùng neo, tách rời với các nhánh riêng biệt cho hồi quy hộp và phân loại. YOLOv3 và YOLOv5 ban đầu sử dụng neo, nhưng Ultralytics cung cấp chúng dưới dạng các biến thể YOLOv3u và YOLOv5u, có cấu hình sử dụng cùng head không dùng neo như YOLOv8.Có — YOLO26 thiết lập
end2end=True, cung cấp choDetectmột head một-một tạo ra một dự đoán duy nhất cho mỗi đối tượng và loại bỏ bước hậu xử lý Triệt tiêu Không Tối đa được yêu cầu bởi các mô hình trước đó. Xem Hướng dẫn Phát hiện Đầu-cuối để biết chi tiết.DFL hồi quy mỗi tọa độ hộp dưới dạng một phân phối softmax trên các thùng
reg_max(mặc định là 16 trong YOLOv8 và YOLO11) và lấy giá trị kỳ vọng làm tọa độ, thay vì dự đoán một vô hướng đơn lẻ. YOLO26 thiết lậpreg_max=1, do đó lớp DFL trở thành một phép toán đồng nhất, head hồi quy tọa độ trực tiếp và không có toán tử DFL nào xuất hiện trong đồ thị ONNX hoặc TensorRT được xuất.Tải mô hình trong Python và gọi
model.info()để xem bản tóm tắt lớp, tham số và GFLOPs. Các lớp đã phân tích cú pháp nằm trongmodel.model.model— ví dụ,model.model.model[-1]là headDetect, phơi bày các thuộc tính nhưreg_maxvàend2end. Toàn bộ kiến trúc được định nghĩa trong tệp cấu hình YAML của mô hình.