YOLO Vision 2026:

Giải thích về kiến trúc YOLO: Từ YOLOv3 đến YOLO26#

Mỗi model Ultralytics YOLO được xây dựng từ ba giai đoạn: backbone trích xuất đặc trưng, neck hợp nhất chúng trên nhiều scale, và head dự đoán các box và class. Hướng dẫn này mô tả các module tạo nên từng giai đoạn và cách chúng thay đổi từ YOLOv3 đến YOLO26, truy nguyên từng thành phần đến định nghĩa của nó trong các file cấu hình tại ultralytics/cfg/models/ và các class module trong ultralytics/nn/modules/.

Mỗi model được định nghĩa khai báo trong một file YAML dưới dạng danh sách layer có thứ tự, trong đó mỗi layer tuân theo định dạng [from, repeats, module, args]: layer nào cung cấp đầu vào, module lặp lại bao nhiêu lần, class của layer (Conv, C3k2, SPPF, Detect, …) và các đối số khởi tạo. Hướng dẫn cấu hình YAML cho Model mô tả định dạng này — bao gồm cách repeatsargs scale theo depth và width multiple của variant — cùng toàn bộ hệ thống phân giải module. Hướng dẫn này tập trung vào bản thân các module và cách chúng thay đổi qua từng version.

Ba giai đoạn#

Mỗi model Ultralytics YOLO đưa ả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ạnNhiệm vụĐầu ra
BackboneTrích xuất đặc trưng từ ảnh đầu vào ở nhiều độ phân giảiCác feature map tại stride 8, 16 và 32 (P3, P4, P5)
NeckHợp nhất đặc trưng trên nhiều scale để cả object nhỏ và lớn đều có ngữ cảnhCác feature map hợp nhất đa scale
HeadDự đoán bounding box và class score từ các đặc trưng đã hợp nhấtCác detection trên mỗi anchor point

Đơn vị nền tảng là block Conv (được định nghĩa trong conv.py): một phép tích chập 2D, batch normalization và activation SiLU, được áp dụng tuần tự. Mọi module lớn hơn bên dưới đều được xây dựng bằng cách kết hợp các block Conv.

Sơ đồ kiến trúc#

Mỗi version giữ nguyên 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 version: các giai đoạn backbone và neck tuân theo config trong ultralytics/cfg/models/, trong khi head của YOLOv3 và YOLOv5 được vẽ theo dạng anchor-based nguyên bản thay vì head biến thể u anchor-free thực sự được cung cấp trong config của package. Chuyển qua các tab cho thấy mỗi thế hệ đã bổ sung gì. Tóm lại: YOLOv3 là detector anchor-based chỉ dùng FPN; YOLOv5 bổ sung nhánh PAN bottom-up và SPPF; YOLOv8 chuyển sang block C2f với head anchor-free, DFL; YOLO11 chèn attention C2PSA và block C3k2; còn YOLO26 bổ sung residual SPPF và khiến head không cần NMS cũng như DFL. Màu node tuân theo quy ước của sơ đồ tài liệu: input màu xanh lá, backbone màu xanh dương, pooling không gian và attention màu slate, neck màu cam, head và output màu tím.

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:#fff

Các sơ đồ YOLOv3 và YOLOv5 hiển thị head anchor-based nguyên bản. Package ultralytics cung cấp config anchor-free YOLOv3uYOLOv5u — sử dụng cùng backbone Darknet-53 và C3 với head Detect của YOLOv8 — được mô tả trong Detection Head.

Các block backbone: Bottleneck → C3 → C2f → C3k2#

Backbone xếp chồng một block CSP (Cross-Stage Partial) lặp lại giữa các layer downsampling Conv stride-2. Block lặp lại này là thành phần thay đổi nhiều nhất qua các version. Tất cả block bên dưới nằm trong block.py; c1/c2 là số channel đầu vào/đầu ra và c = 0.5 * c2 là width ẩn.

Bottleneck (YOLOv3)#

Đơn vị cơ sở là Bottleneck: hai layer Conv (kernel mặc định (3, 3)) với phép cộng residual tùy chọn khi shortcut=Truec1 == c2. Backbone Darknet-53 của YOLOv3 xếp chồng trực tiếp các đơn vị này, không tách CSP, và thực hiện detection ở ba scale (stride 8, 16, 32).

C3 (YOLOv5)#

C3 của YOLOv5 chia input qua hai phép tích chập 1x1: cv1 đưa đầu vào các block Bottleneck tuần tự của n (kernel lần lượt (1, 1)(3, 3)), còn cv2 bypass chúng. Hai nhánh được nối 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ỉ output bottleneck cuối cùng đi tới fusion conv, vì vậy cv3 nhận 2 feature map.

C2f (YOLOv8)#

C2f của YOLOv8 ("CSP Bottleneck với 2 phép tích chập, nhanh hơn") thay đổi các feature được đưa tới fusion conv:

  1. cv1 = Conv(c1, 2 * c, 1), sau đó chunk(2) chia output thành hai tensor có c channel.
  2. Các block Bottleneck(c, c) n (kernel (3, 3), (3, 3)) chạy tuần tự, mỗi block nhận output của block trước đó.
  3. Tất cả tensor trung gian n + 2 được nối lại và hợp nhất bởi cv2 = Conv((2 + n) * c, c2, 1).

Trong khi C3 đưa 2 feature map vào fusion conv, C2f đưa n + 2 — mọi output bottleneck trung gian đều được tái sử dụng.

C3k2 (YOLO11 và YOLO26)#

YOLO11YOLO26 sử dụng C3k2, một subclass của C2f thay thế đơn vị lặp lại. Tùy thuộc vào các cờ khởi tạo, mỗi block n trở thành:

  • một Bottleneck thuần túy (mặc định, c3k=False),
  • một block C3k (c3k=True) — một biến thể C3 với kernel size 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, trừ khi scale là m, l hoặc x, các giá trị này buộc nó thành True — đây là cách một yolo11.yaml phục vụ cả năm variant. Vì vậy, [-1, 2, C3k2, [512, False]] xây dựng các thành phần nội bộ Bottleneck tại ns, nhưng các thành phần nội bộ C3k tại m, lx; 512 là số channel trước khi scale, được width multiple của variant chuyển thành 128 tại n và 768 tại x. Đối với module CSP, trường repeats — ở đây là 2, trước khi được scale bởi depth multiple của variant — trở thành số lần lặp nội bộ của block thay vì xếp chồng các module riêng biệt.

Pooling không gian: SPP → SPPF#

Ở cuối backbone, một block spatial-pyramid-pooling mở rộng receptive field. YOLOv5 thay SPP đa kernel nguyên bản bằng SPPF (Spatial Pyramid Pooling - Fast): một MaxPool2d(kernel_size=5, stride=1, padding=2) duy nhất được áp dụng tuần tự n = 3 lần, trong đó input và cả ba output pooled được nối lại rồi hợp nhất bởi 1x1 Conv. Về mặt toán học, cách này tương đương với SPP(k=(5, 9, 13)) nhưng rẻ hơn, vì các phép pooling 5x5 nối tiếp bao phủ receptive field của các kernel lớn hơn.

YOLO26 truyền một cờ shortcut (SPPF, [1024, 5, 3, True]); vì c1 == c2 == 1024 ở layer sâu nhất, SPPF thêm một kết nối residual (return y + x).

Attention không gian: C2PSA (YOLO11+)#

YOLO11 bổ sung C2PSA sau SPPF. Đây là một block CSP có nhánh hoạt động là một chuỗi gồm n module PSABlock (Position-Sensitive Attention): cv1 = Conv(c1, 2 * c, 1) chia các đặc trưng, một nửa đi qua chuỗi PSABlock, rồi cv2 = Conv(2 * c, c1, 1) hợp nhất phần nối. Mỗi PSABlock áp dụng attention đa head, sau đó là mạng feed-forward hai layer (Conv(c, 2 * c, 1)Conv(2 * c, c, 1)), mỗi phần đều có kết nối residual. YOLO26 giữ nguyên backbone C3k2 + C2PSA.

Neck: FPN + PAN#

Neck hợp nhất các feature map P3/P4/P5 của backbone bằng Feature Pyramid Network (FPN) top-down, sau đó là Path Aggregation Network (PAN) bottom-up. Trong phần head của YAML, FPN là nn.Upsample + Concat (truyền thông tin ngữ nghĩa xuống các độ phân giải cao hơn) và PAN là Conv + Concat stride-2 (truyền thông tin định vị trở 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]] # 19

Neck tái sử dụng block backbone của thế hệ tương ứng — C3 trong YOLOv5, C2f trong YOLOv8, C3k2 trong YOLO11 và YOLO26 — vì vậy mỗi điểm hợp nhất chạy cùng module mà backbone sử dụng. Ba output đã hợp nhất được đưa vào head. YOLOv3 là ngoại lệ: neck của nó chỉ có FPN top-down (head YAML không có downsampling stride-2), không có nhánh PAN bottom-up mà YOLOv5 giới thiệu.

Detection head: Anchor-Based → Anchor-Free → NMS-Free#

Head chuyển ba feature map đã hợp nhất thành các prediction cho detection task. Thiết kế này đã thay đổi qua các version, từ anchor-based sang anchor-free rồi đến NMS-free.

Detect anchor-free, decoupled#

YOLOv3 và YOLOv5 nguyên bản sử dụng head coupled anchor-based: các anchor box được định nghĩa trước và một nhánh dùng chung cho prediction box và class. Các repository độc lập ultralytics/yolov3ultralytics/yolov5 giữ thiết kế anchor-based đó. Thay vào đó, package ultralytics chính cung cấp các variant YOLOv3uYOLOv5u anchor-free — cùng backbone Darknet-53 và C3 với head Detect anchor-free của YOLOv8 — và các config yolov3.yamlyolov5.yaml được mô tả ở đây là các variant u này, không phải thiết kế lịch sử.

Head Detect (head.py) là anchor-free và decoupled: tại mỗi level của pyramid, head chạy hai nhánh song song và dự đoán trực tiếp trên các grid point thay vì dựa trên anchor box.

  • Nhánh box (cv2): Conv(x, c2, 3)Conv(c2, c2, 3)Conv2d(c2, 4 * reg_max, 1).
  • Nhánh class (cv3): trong YOLO11 và YOLO26, hai block depthwise-separable (DWConv + 1x1 Conv) → Conv2d(c3, nc, 1); YOLOv8 sử dụng biến thể legacy, gồm hai layer 3x3 ConvConv2d(c3, nc, 1).

Do đó, mỗi anchor point phát ra no = nc + 4 * reg_max output. Việc loại bỏ anchor định nghĩa trước sẽ loại bỏ kích thước và aspect ratio của anchor box khỏi các hyperparameter cần tuning.

Distribution Focal Loss (DFL)#

YOLOv8 và YOLO11 hồi quy mỗi tọa độ trong 4 tọa độ box dưới dạng một phân phối trên reg_max = 16 bin thay vì một scalar duy nhất (dạng tích phân từ Generalized Focal Loss). Module DFL reshape 4 * reg_max box channel thành (4, reg_max), áp dụng softmax trên reg_max bin và lấy chỉ số bin kỳ vọng — mỗi chỉ số bin được cân theo xác suất softmax tương ứng rồi cộng lại — làm tọa độ dự đoán. Cơ chế này được triển khai dưới dạng một convolution 1x1 cố định với weight là các chỉ số bin arange(reg_max), vì vậy tổng có trọng số chỉ là một dot product.

YOLO26: NMS-free, DFL-free#

YOLO26 thiết lập hai parameter YAML mà head đọc trực tiếp:

  • end2end: TrueDetect deep-copy các nhánh của nó vào một head one-to-one (one2one_cv2/one2one_cv3) tạo ra một prediction duy nhất cho mỗi object, loại bỏ bước post-processing Non-Maximum Suppression (NMS). Xem Hướng dẫn End-to-End Detection để biết chi tiết về export và migration.
  • reg_max: 1 — với một bin, self.dfl trở thành nn.Identity()no = nc + 4; head hồi quy trực tiếp các tọa độ và không có operation DFL nào xuất hiện trong graph ONNX được export.

Trên năm kích thước model (n/s/m/l/x), YOLO26 đạt 40.9–57.5 mAP trên COCO với độ trễ TensorRT T4 1.7–11.8 ms, theo bài báo YOLO26.

Tóm tắt theo từng version#

VersionBlock backbonePooling không gianAttentionDetection headDFL
YOLOv3Darknet-53 (Bottleneck)không có trong config cơ sởkhông cóNguyên bản: anchor-based; biến thể u: anchor-freekhông / có (u)
YOLOv5C3 (CSP)SPPFkhông cóNguyên bản: anchor-based; biến thể u: anchor-freekhông / có (u)
YOLOv8C2fSPPFkhông cóAnchor-free, decoupledcó (reg_max=16)
YOLO11C3k2SPPFC2PSAAnchor-free, decoupledcó (reg_max=16)
YOLO26C3k2SPPF + shortcutC2PSAAnchor-free, NMS-free (end2end)đã loại bỏ (reg_max=1)

Để xem chi tiết theo từng model, bảng hiệu năng và ví dụ sử dụng, hãy xem các trang riêng cho YOLOv3, YOLOv5, YOLOv8, YOLO11YOLO26.

Tự kiểm tra kiến trúc#

Method model.info() in ra bản tóm tắt về layer, parameter và FLOPs, còn danh sách module đã parse có tại model.model.model.

Kiểm tra kiến trúc của một model YOLO
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 snippet trên ba thế hệ cho thấy các thay đổi dưới dạng số liệu. Đây là output thực từ các model đã fuse của package ultralytics, khớp với số parameter và FLOPs được công bố trên từng trang model:

ModelLayerSố tham sốGFLOPsreg_maxend2endLayer DFL
YOLOv8n723,151,9048.716FalseDFL
YOLO11n1002,616,2486.516FalseDFL
YOLO26n1222,408,9325.51TrueIdentity

YOLO26n báo cáo reg_max=1, end2end=True và một layer DFL Identity — dấu hiệu kiến trúc của head NMS-free, DFL-free.

Số liệu fused và unfused

Các giá trị parameter và FLOPs được báo cáo cho model fused (model.fuse()), trong đó hợp nhất mỗi Conv với layer batch normalization tương ứng. Điều này khớp với thông số được công bố; checkpoint vừa load sẽ báo số lượng cao hơn một chút trước khi fuse.

Kết luận#

Qua các version, kiến trúc YOLO thay đổi từng giai đoạn một: backbone chuyển từ Darknet-53 sang các block C3, C2fC3k2 dựa trên CSP với attention C2PSA; neck giữ cấu trúc FPN + PAN trong khi SPP trở thành SPPF; còn head chuyển từ anchor-based sang anchor-free, rồi đến thiết kế end-to-end NMS-free, DFL-free của YOLO26.

Để định nghĩa kiến trúc tùy chỉnh, hãy xem Hướng dẫn cấu hình YAML cho Model, hoặc so sánh các model trên trang model. Nếu có câu hỏi, hãy liên hệ trên GitHub hoặc Discord.

FAQ#

  • Một model YOLO có backbone trích xuất đặc trưng từ ảnh tại các stride 8, 16 và 32, neck hợp nhất các đặc trưng đó trên nhiều scale bằng FPN và PAN, cùng head dự đoán bounding box và class score. Mọi model Ultralytics YOLO từ YOLOv3 đến YOLO26 đều tuân theo thiết kế ba giai đoạn này.

  • C2f (YOLOv8) là một block CSP nối các đầu ra của mọi feature map Bottleneck nội bộ — n + 2 — trước convolution hợp nhất, trong khi C3 cũ chỉ truyền 2 feature map. C3k2 (YOLO11 và YOLO26) là một subclass của C2f, có thể thay thế mỗi Bottleneck bằng một block C3k (một biến thể C3 với kích thước kernel có thể cấu hình) khi cờ c3k được bật. Cả hai được định nghĩa trong block.py.

  • YOLO11 thực hiện ba thay đổi cấu trúc so với YOLOv8: thay block backbone và neck C2f bằng C3k2, chèn một block self-attention C2PSA sau SPPF, và chuyển nhánh classification của head sang các convolution depthwise-separable nhẹ hơn. Cả hai vẫn giữ head Detect anchor-free, tách biệt với hồi quy DFL reg_max=16, vì vậy các thay đổi này giảm số lượng parameter và FLOPs đồng thời tăng độ chính xác, thay vì thiết kế lại interface detection.

  • Các model Ultralytics YOLO hiện đại không sử dụng anchor. YOLOv8, YOLO11 và YOLO26 sử dụng head Detect anchor-free, tách biệt, với các nhánh riêng cho hồi quy box và classification. YOLOv3 và YOLOv5 ban đầu dựa trên anchor, nhưng Ultralytics cung cấp chúng dưới dạng các biến thể YOLOv3uYOLOv5u, có config sử dụng cùng head anchor-free như YOLOv8.

  • Có — YOLO26 thiết lập end2end=True, cung cấp cho Detect một head one-to-one tạo ra một prediction duy nhất cho mỗi object và loại bỏ bước hậu xử lý Non-Maximum Suppression cần có ở các model trước đây. Xem hướng dẫn Detection end-to-end để biết chi tiết.

  • DFL hồi quy từng tọa độ box dưới dạng phân phối softmax trên các bin reg_max (mặc định là 16 trong YOLOv8 và YOLO11), rồi lấy giá trị kỳ vọng làm tọa độ, thay vì dự đoán một scalar duy nhất. YOLO26 thiết lập reg_max=1, do đó layer DFL trở thành phép toán identity, head hồi quy trực tiếp các tọa độ và không có op DFL nào xuất hiện trong graph ONNX hoặc TensorRT được export.

  • Load model trong Python và gọi model.info() để nhận bản tóm tắt về layer, parameter và GFLOPs. Các layer đã parse nằm trong model.model.model — ví dụ, model.model.model[-1] là head Detect, cung cấp các attribute như reg_maxend2end. Kiến trúc đầy đủ được định nghĩa trong file cấu hình YAML của model.

Cộng tác viên

Bình luận