Архитектура YOLO: объяснение от YOLOv3 до YOLO26#
Каждая модель Ultralytics YOLO состоит из трёх этапов: backbone, который извлекает признаки, neck, который объединяет их в разных масштабах, и head, который предсказывает боксы и классы. В этом руководстве описаны модули каждого этапа и их изменения от YOLOv3 до YOLO26; каждый компонент прослеживается до его определения в конфигурационных файлах в ultralytics/cfg/models/ и классов модулей в ultralytics/nn/modules/.
Каждая модель декларативно определяется в YAML-файле как упорядоченный список слоёв, где каждый слой соответствует формату [from, repeats, module, args]: какие слои подают на него данные, сколько раз повторяется модуль, класс слоя (Conv, C3k2, SPPF, Detect, …) и аргументы его конструктора. В руководстве по конфигурации Model YAML описан этот формат, включая то, как repeats и args масштабируются с учётом множителей глубины и ширины варианта, а также подробно описана система разрешения модулей. Это руководство посвящено самим модулям и их изменениям от версии к версии.
Три этапа#
Каждая модель Ultralytics YOLO последовательно пропускает изображение через три этапа, у каждого из которых своя задача:
| Этап | Задача | Результат |
|---|---|---|
| Backbone | Извлечение признаков из входного изображения в нескольких разрешениях | Карты признаков со stride 8, 16 и 32 (P3, P4 и P5) |
| Neck | Объединение признаков в разных масштабах, чтобы и малые, и крупные объекты имели контекст | Объединённые многомасштабные карты признаков |
| Head | Предсказание ограничивающих боксов и оценок классов на основе объединённых признаков | Детекции для каждой опорной точки |
Фундаментальная единица — блок Conv (определённый в conv.py): двумерная свёртка, пакетная нормализация и активация SiLU, применяемые последовательно. Каждый более крупный модуль ниже строится композиционно из блоков Conv.
Диаграммы архитектуры#
В каждой версии сохраняется один и тот же каркас backbone → neck → head, но меняются отдельные этапы. Вкладки ниже показывают структуру каждой версии: этапы backbone и neck соответствуют конфигурациям в ultralytics/cfg/models/, а head YOLOv3 и YOLOv5 показаны в исходной anchor-based форме, а не в anchor-free форме head варианта u, которая фактически поставляется в конфигурациях их пакетов. Последовательный просмотр вкладок показывает, что добавила каждая генерация. Если кратко: YOLOv3 — детектор только на основе FPN и anchor-based; YOLOv5 добавляет восходящий путь PAN и SPPF; YOLOv8 переходит на блок C2f с anchor-free head и DFL; YOLO11 добавляет внимание C2PSA и блок C3k2; YOLO26 добавляет остаточную связь SPPF, а head становится свободным от NMS и DFL. Цвета узлов соответствуют принятому в документации стилю диаграмм: зелёный — вход, синий — backbone, серо-синий — пространственное объединение и внимание, оранжевый — neck, фиолетовый — head и выход.
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На диаграммах YOLOv3 и YOLOv5 показан исходный anchor-based head. Пакет ultralytics поставляет anchor-free конфигурации YOLOv3u и YOLOv5u — те же backbone Darknet-53 и C3 с head Detect от YOLOv8; они описаны в разделе Detection Head.
Блоки backbone: Bottleneck → C3 → C2f → C3k2#
Backbone объединяет повторяющийся блок CSP (частичный блок между этапами) между слоями понижения разрешения Conv со stride 2. Именно этот повторяющийся блок сильнее всего менялся между версиями. Все блоки ниже находятся в block.py; c1/c2 — это входные и выходные каналы, а c = 0.5 * c2 — скрытая ширина.
Bottleneck (YOLOv3)#
Базовая единица — Bottleneck: два слоя Conv (ядра по умолчанию (3, 3)) с необязательным добавлением остаточной связи, если shortcut=True и c1 == c2. Backbone Darknet-53 в YOLOv3 непосредственно объединяет эти блоки без разделения CSP и выполняет детекцию в трёх масштабах (stride 8, 16 и 32).
C3 (YOLOv5)#
C3 в YOLOv5 разделяет вход между двумя свёртками 1x1: cv1 передаёт данные в n последовательных блоков Bottleneck (ядра (1, 1), затем (3, 3)), а cv2 обходит их. Два пути объединяются и сливаются третьей свёрткой 1x1 Conv:
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))До свёртки слияния доходит только выход последнего bottleneck, поэтому cv3 получает 2 карты признаков.
C2f (YOLOv8)#
C2f в YOLOv8 ("CSP Bottleneck with 2 convolutions, faster") изменяет набор признаков, поступающих в свёртку слияния:
cv1 = Conv(c1, 2 * c, 1), затемchunk(2)разделяет выход на два тензора сcканалами.- Блоки
nBottleneck(c, c)(ядра(3, 3),(3, 3)) выполняются последовательно; каждый получает выход предыдущего блока. - Все промежуточные тензоры
n + 2объединяются и сливаются с помощьюcv2 = Conv((2 + n) * c, c2, 1).
Если C3 передаёт в свёртку слияния 2 карты признаков, то C2f передаёт n + 2 — используется каждый промежуточный выход bottleneck.
C3k2 (YOLO11 и YOLO26)#
YOLO11 и YOLO26 используют C3k2 — подкласс C2f, в котором заменён повторяющийся блок. Каждый из блоков n в зависимости от флагов конструктора превращается в:
- обычный
Bottleneck(по умолчанию,c3k=False), - блок
C3k(c3k=True) — вариантC3с настраиваемым размером ядра, или - пару
Bottleneck+PSABlock(attn=True).
Второй аргумент YAML задаёт c3k, кроме случаев, когда масштаб равен m, l или x: тогда принудительно используется True — так один yolo11.yaml обслуживает все пять вариантов. Поэтому [-1, 2, C3k2, [512, False]] создаёт внутренние блоки Bottleneck с каналами n и s, но внутренние блоки C3k с каналами m, l и x; значение 512 — это число каналов до масштабирования, которое множитель ширины варианта преобразует в 128 при n и в 768 при x. Для модулей CSP поле repeats — здесь 2 до масштабирования множителем глубины варианта — становится числом внутренних повторений блока, а не количеством последовательно объединённых отдельных модулей.
Пространственное объединение: SPP → SPPF#
В конце backbone блок пространственного пирамидального объединения расширяет рецептивное поле. YOLOv5 заменил исходный многоканальный SPP на SPPF (Spatial Pyramid Pooling - Fast): одна MaxPool2d(kernel_size=5, stride=1, padding=2), применённая последовательно n = 3 раз, причём вход и все три объединённых результата объединяются и сливаются свёрткой 1x1 Conv. Математически это эквивалентно SPP(k=(5, 9, 13)), но требует меньше вычислений, поскольку последовательные операции pooling 5x5 покрывают рецептивные поля более крупных ядер.
YOLO26 передаёт флаг shortcut (SPPF, [1024, 5, 3, True]); поскольку c1 == c2 == 1024 находится на самом глубоком слое, SPPF добавляет остаточную связь (return y + x).
Пространственное внимание: C2PSA (YOLO11+)#
YOLO11 добавил C2PSA после SPPF. Это блок CSP, активная ветвь которого представляет собой стек из n модулей PSABlock (Position-Sensitive Attention): cv1 = Conv(c1, 2 * c, 1) разделяет признаки, одна половина проходит через стек PSABlock, а cv2 = Conv(2 * c, c1, 1) объединяет конкатенацию. Каждый PSABlock применяет multi-head внимание, за которым следует двухслойная полносвязная сеть (Conv(c, 2 * c, 1) → Conv(2 * c, c, 1)); оба этапа имеют остаточную связь. YOLO26 сохраняет тот же backbone C3k2 + C2PSA.
Neck: FPN + PAN#
Neck объединяет карты признаков P3/P4/P5 из backbone с нисходящей сетью пирамиды признаков (FPN), за которой следует восходящая сеть агрегации путей (PAN). В разделе head YAML-файла FPN — это nn.Upsample + Concat (передача семантической информации к более высоким разрешениям), а PAN — это Conv + Concat со stride 2 (передача информации о локализации обратно к низким разрешениям):
# 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 повторно использует блок backbone своей версии — C3 в YOLOv5, C2f в YOLOv8, C3k2 в YOLO11 и YOLO26, — поэтому в каждой точке слияния выполняется тот же модуль, что и в backbone. Три объединённых выхода передаются в head. YOLOv3 — исключение: его neck содержит только нисходящий FPN (в его YAML head отсутствует понижение разрешения со stride 2), без восходящего пути PAN, который появился в YOLOv5.
Detection Head: Anchor-Based → Anchor-Free → NMS-Free#
Head преобразует три объединённые карты признаков в предсказания для задачи детекции. Его архитектура менялась от версии к версии: от anchor-based к anchor-free, а затем к NMS-free.
Anchor-free, раздельный Detect#
Исходные YOLOv3 и YOLOv5 использовали anchor-based head со связанными ветвями: заранее заданными anchor-боксами и общей ветвью для предсказания боксов и классов. Отдельные репозитории ultralytics/yolov3 и ultralytics/yolov5 сохраняют эту anchor-based архитектуру. Основной пакет ultralytics, напротив, поставляет anchor-free варианты YOLOv3u и YOLOv5u — те же backbone Darknet-53 и C3 с anchor-free head Detect от YOLOv8; конфигурации yolov3.yaml и yolov5.yaml, описанные здесь, относятся именно к этим вариантам u, а не к исторической архитектуре.
Head Detect (head.py) является anchor-free и раздельным: на каждом уровне пирамиды он запускает две параллельные ветви и выполняет предсказания непосредственно на узлах сетки, а не относительно anchor-боксов.
- Ветвь боксов (
cv2):Conv(x, c2, 3)→Conv(c2, c2, 3)→Conv2d(c2, 4 * reg_max, 1). - Ветвь классов (
cv3): в YOLO11 и YOLO26 два depthwise-separable блока (DWConv+1x1 Conv) →Conv2d(c3, nc, 1); YOLOv8 использует устаревший вариант: два слоя3x3 Conv→Conv2d(c3, nc, 1).
Таким образом, каждая опорная точка выдаёт no = nc + 4 * reg_max выходов. Удаление заранее заданных anchors исключает размеры и соотношения сторон anchor-боксов из гиперпараметров, которые нужно настраивать.
Distribution Focal Loss (DFL)#
YOLOv8 и YOLO11 регрессируют каждую из 4 координат бокса как распределение по reg_max = 16 бинам, а не как единственное скалярное значение (интегральная форма из Generalized Focal Loss). Модуль DFL изменяет форму 4 * reg_max каналов бокса на (4, reg_max), применяет softmax по reg_max бинам и получает ожидаемый индекс бина — каждый индекс взвешивается его вероятностью softmax, после чего результаты суммируются — как предсказанную координату. Это реализовано в виде свёртки 1x1 с фиксированными весами, равными индексам бинов arange(reg_max), поэтому взвешенная сумма вычисляется одним скалярным произведением.
YOLO26: NMS-free, DFL-free#
YOLO26 задаёт два параметра YAML, которые head считывает напрямую:
end2end: True—Detectглубоко копирует свои ветви в head один-к-одному (one2one_cv2/one2one_cv3), который выдаёт одно предсказание на объект, устраняя этап постобработки подавления немаксимумов (NMS). Подробности экспорта и миграции см. в руководстве по сквозной детекции.reg_max: 1— при одном бинеself.dflпревращается вnn.Identity()иno = nc + 4; head напрямую регрессирует координаты, и в экспортированном графе ONNX отсутствует операция DFL.
Во всех пяти вариантах размера модели (n/s/m/l/x) YOLO26 достигает 40,9–57,5 mAP на COCO при задержке TensorRT 1,7–11,8 мс на T4, как указано в статье о YOLO26.
Сводка по версиям#
| Версия | Блок backbone | Пространственное объединение | Внимание | Head детекции | DFL |
|---|---|---|---|---|---|
| YOLOv3 | Darknet-53 (Bottleneck) | отсутствует в базовой конфигурации | отсутствует | Исходный: anchor-based; вариант u: anchor-free | нет / да (u) |
| YOLOv5 | C3 (CSP) | SPPF | отсутствует | Исходный: anchor-based; вариант u: anchor-free | нет / да (u) |
| YOLOv8 | C2f | SPPF | отсутствует | Anchor-free, раздельный | да (reg_max=16) |
| YOLO11 | C3k2 | SPPF | C2PSA | Anchor-free, раздельный | да (reg_max=16) |
| YOLO26 | C3k2 | SPPF + shortcut | C2PSA | Anchor-free, NMS-free (end2end) | удалён (reg_max=1) |
Подробности по каждой модели, таблицы производительности и примеры использования см. на отдельных страницах YOLOv3, YOLOv5, YOLOv8, YOLO11 и YOLO26.
Изучи архитектуру самостоятельно#
Метод model.info() выводит сводку по слоям, параметрам и FLOPs, а список разобранных модулей доступен в 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)Запуск этого фрагмента для трёх поколений показывает изменения в числах. Это реальные результаты для объединённых моделей из пакета ultralytics, соответствующие опубликованным значениям параметров и FLOPs на каждой странице модели:
| Модель | Слои | Параметры | GFLOPs | reg_max | end2end | Слой 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.5 | 1 | True | Identity |
YOLO26n сообщает reg_max=1, end2end=True и слой DFL Identity — архитектурный признак его NMS-free и DFL-free head.
Значения параметров и FLOPs приводятся для объединённой модели (model.fuse()), в которой каждый Conv объединён со своим слоем пакетной нормализации. Это соответствует опубликованным спецификациям; только что загруженный checkpoint показывает немного большие значения до объединения.
Заключение#
В разных версиях архитектура YOLO менялась поэтапно: backbone перешёл от Darknet-53 к блокам C3, C2f и C3k2 на основе CSP с вниманием C2PSA; neck сохранил структуру FPN + PAN, а SPP превратился в SPPF; head прошёл путь от anchor-based к anchor-free, а затем к сквозной архитектуре YOLO26 без NMS и DFL.
Чтобы определить собственные архитектуры, см. руководство по конфигурации Model YAML или сравни модели на страницах моделей. Если у тебя есть вопросы, обратись к сообществу в GitHub или Discord.
Часто задаваемые вопросы#
У модели YOLO есть backbone, который извлекает признаки из изображения со stride 8, 16 и 32, neck, который объединяет эти признаки в разных масштабах с помощью FPN и PAN, и head, который предсказывает ограничивающие боксы и оценки классов. Каждая модель Ultralytics YOLO от YOLOv3 до YOLO26 соответствует этой трёхэтапной архитектуре.
C2f(YOLOv8) — это блок CSP, который конкатенирует выходы всех внутренних карт признаковBottleneck—n + 2перед своей свёрткой слияния, тогда как более старыйC3передаёт только 2.C3k2(YOLO11 и YOLO26) — это подклассC2f, который может заменять каждыйBottleneckблокомC3k(вариантомC3с настраиваемым размером ядра), если установлен флагc3k. Оба определены вblock.py.YOLO11 вносит три структурных изменения по сравнению с YOLOv8: заменяет блок
C2fв backbone и neck наC3k2, добавляет блокC2PSAс self-attention послеSPPFи заменяет классификационную ветвь head на более лёгкие depthwise-separable свёртки. В обеих моделях сохраняется одна и та же безанкорная раздельная headDetectс регрессиейreg_max=16DFL, поэтому эти изменения уменьшают количество параметров и FLOPs, одновременно повышая точность, а не меняя интерфейс детектирования.Современные модели Ultralytics YOLO работают без якорей. YOLOv8, YOLO11 и YOLO26 используют безанкорную раздельную head
Detectс отдельными ветвями для регрессии bbox и классификации. Исходные YOLOv3 и YOLOv5 использовали якоря, но Ultralytics выпускает их варианты YOLOv3u и YOLOv5u, конфигурации которых используют ту же безанкорную head, что и YOLOv8.Да — YOLO26 устанавливает
end2end=True, благодаря чемуDetectиспользует head с соответствием один к одному, выдающую одно предсказание для каждого объекта и устраняющую этап постобработки подавления немаксимумов, необходимый предыдущим моделям. Подробнее см. в руководстве End-to-End Detection.DFL регрессирует каждую координату bbox как распределение softmax по
reg_maxбинам (по умолчанию 16 в YOLOv8 и YOLO11) и использует математическое ожидание в качестве координаты вместо предсказания одного скалярного значения. YOLO26 устанавливаетreg_max=1, поэтому слой DFL становится тождественной операцией, head регрессирует координаты напрямую, а в экспортированных графах ONNX или TensorRT операция DFL отсутствует.Загрузи модель в Python и вызови
model.info(), чтобы получить сводку по слоям, параметрам и GFLOPs. Распознанные слои находятся вmodel.model.model— например,model.model.model[-1]— это headDetect, предоставляющая такие атрибуты, какreg_maxиend2end. Полная архитектура определена в YAML-файле конфигурации модели.