Ядра

У каждой ускоренной операции в LibreYOLO есть переносимая реализация по умолчанию и иногда — более быстрый вариант, зарегистрированный поверх неё. Выбор происходит во время выполнения по предикату, отсутствующая необязательная зависимость — это откат на запасной путь, а не ошибка, и экспортированный граф всегда идёт переносимым путём.

Пакет
libreyolo.kernels
Необязательный extra
libreyolo[hub-kernels]
Принудительный эталонный путь
LIBREYOLO_KERNELS=off

Реестр

libreyolo/kernels/ — небольшой реестр подключаемых реализаций, работающий во время выполнения. Слот операции — это имя вроде fake_quant_fp8 или ms_deform_attn. Вызывающий код запрашивает у реестра слот и получает ту зарегистрированную реализацию, чей предикат сработал первым, причём выигрывает самая поздняя регистрация; если не подходит ничего, дело доходит до эталонной реализации.

Такая структура существует затем, чтобы необязательная зависимость никогда не превращалась в жёсткое требование. Машина без Triton, без CUDA или без пакета kernels выполняет тот же код и выдаёт те же числа, только медленнее.

ФункцияНазначение
active()Слот операции → имя выбранной реализации или "unavailable"
resolve(op)Вызываемый объект, который будет запущен, или None
register(op, impl, *, name, predicate=None)Добавляет реализацию, новые идут первыми
unregister(op, name)Удаляет одну реализацию
clear_cache()Сбрасывает запомненный результат разрешения

Просмотр выбранного
import libreyolo.kernels as kernels # Слот операции → имя выбранной реализации или "unavailable".print(kernels.active())
Принудительный эталонный путь
# off и reference означают одно и то же и вдобавок полностью# пропускают импорт ускоренных провайдеров.LIBREYOLO_KERNELS=off python train.py
Отключение ядер с Hub без удаления пакета
LIBREYOLO_HUB_KERNELS=0 python predict.py
Переключение семейства на слитое внимание
from libreyolo import LibreYOLOfrom libreyolo.kernels.attention import set_fused_attention model = LibreYOLO("LibreSwinIRs.pt") # Возвращает, сколько модулей внимания переключилось.print(set_fused_attention(model))
Регистрация своей реализации
import libreyolo.kernels as kernels kernels.register(    "fake_quant_fp8",    my_impl,    name="mybackend",    predicate=my_check,)

Исключение из предиката перехватывается и превращается в предупреждение, а дальше не пробрасывается, поэтому сломанная сторонняя реализация деградирует до переносимого пути, а не ломает предсказание.

Структура

Дерево организовано сначала по назначению и только потом по бэкенду, поэтому слот ищется по тому, что он вычисляет, а не по тому, какая библиотека реализует его сегодня.

КаталогСодержимое
kernels/quant/simulate/Triton-ядра фейковой квантизации, со straight-through-градиентом на обратном проходе, на любом устройстве. Используются одинаково и в QAT, и в симулированной квантизации после обучения
kernels/quant/execute/Пути в реальной точности, только для финализированных моделей, без обратного прохода: FP8-GEMM на тензорных ядрах, его слитые пролог и эпилог на Triton и ядра распаковки упакованных весов
kernels/attention/Операции внимания, общие для разных семейств: слот ms_deform_attn и политика слитого SDPA

Граница между simulate и execute проходит по тому, финализирована ли модель, а не по тому, идёт обучение или развёртывание. Эталонные реализации остаются в libreyolo/quant/, который задаёт смысл чисел; kernels/ только делает их быстрыми. У упаковки весов вариантов нет вовсе, потому что это контракт чекпойнта.

У слотов GEMM и внимания эталонной реализации нет. Вызывающий код обязан проверить, что resolve() что-то вернул, и держать собственный переносимый путь — поэтому графы ONNX, TensorRT и torch.export всегда содержат переносимую математику.

Переопределение выбора

LIBREYOLO_KERNELS=off или =reference принудительно включает эталонные реализации и полностью отменяет импорт ускоренных провайдеров. Любое другое значение ограничивает выбор реализациями, зарегистрированными под этим именем. LIBREYOLO_QUANT_KERNELS поддерживается как устаревший псевдоним со времён, когда реестр жил в libreyolo/quant/, и читается, только если LIBREYOLO_KERNELS не задана. Обе переменные перечислены вместе с остальными на странице настроек.

Ядра с Hub

Скомпилированные CUDA-ядра, опубликованные на Hugging Face Hub, загружаются во время выполнения через необязательный пакет kernels. В состав LibreYOLO ничего не копируется: артефакт скачивает и кэширует сам этот пакет, а каждый провайдер фиксирует проверенную ревизию коммита, поэтому смена такой привязки требует прогона на GPU для проверки соответствия, прежде чем попадёт в код.

Подключение — это установка extra:

bash
pip install "libreyolo[hub-kernels]"

Без этого пакета ничего не меняется и никаких сетевых запросов не делается. LIBREYOLO_HUB_KERNELS=0 отключает скачивание, ничего не удаляя. Ядро, которое не удалось загрузить или запустить, отключает себя до конца процесса и откатывается на запасной путь с одним предупреждением.

Сегодня через Hub работает один слот: ms_deform_attn — скомпилированные прямой и обратный проходы многомасштабного деформируемого внимания из Deformable DETR, под Apache 2.0. Он подключён ко всей деформируемой линейке: RF-DETR, Deformable DETR, DINO-DETR, LW-DETR, Grounding DINO, RT-DETR, RT-DETRv2, D-FINE, RT-DETRv4, DEIM, DEIMv2, EC и OV-DEIM. Поскольку обратный проход тоже скомпилирован, выигрывает не только предсказание, но и обучение.

Условия применимости намеренно узкие. Входы должны быть на CUDA и в float32, а выполнение — в eager-режиме: провайдер отказывается работать под torch.jit.is_tracing(), torch.compiler.is_compiling(), torch.compiler.is_exporting() и torch.onnx.is_in_onnx_export(). Ещё две раскладки входов уходят на переносимый путь: число точек на уровень, различающееся между уровнями, и выборка по дискретным целочисленным индексам. Вариант EC для позы не подключён.

Это ядро стало достижимо только сейчас

Прочитайте это, прежде чем ставить extra в существующий проект.

В v1.4.0 к слоту обращались изнутри вспомогательной функции, за условием, которое требовало отсутствия пар пространственных размеров. RF-DETR всегда протаскивает эти пары через свой декодер, поэтому условие никогда не выполнялось и ядро ни разу не запускалось ни в одном eager-проходе. В v1.5.0 обращение переехало, и теперь ядро действительно работает.

Практическое следствие: обновление до v1.5.0 и установка libreyolo[hub-kernels] на CUDA означают, что RF-DETR и вся его линейка впервые берут прямой проход из скомпилированного бинарника. Из-за этого предсказания и метрики могут сдвинуться в пределах точности чисел с плавающей точкой. Обычной установки, без extra, это не касается. Если вы сравниваете метрики до и после обновления, оставьте extra неизменным или выставьте LIBREYOLO_HUB_KERNELS=0 с обеих сторон.

Слитое внимание

Слитому вниманию scaled dot-product не нужны необязательные зависимости — достаточно стандартного PyTorch, поэтому им управляет политика, а не доступность. Действуют два правила.

Во-первых, при захвате графа оно не используется никогда. Каждая заменённая точка вызова держит наготове запись через примитивные операции за проверкой на экспорт — это покрывает экспорт в ONNX, у которого в опсете по умолчанию нет символьной функции для SDPA, и torch.jit.trace, через который проходят TorchScript, CoreML и NCNN. Захваты Dynamo намеренно оставлены вне этой проверки, потому что torch.compile компилирует SDPA лучше, чем ручную математику, а Core AI и ExecuTorch и сами раскладывают SDPA в базовые операции ATen.

Во-вторых, планка соответствия для включения по умолчанию — побайтовое совпадение. Семейства, которые её проходят, используют SDPA по умолчанию: SegFormer, Depth Anything и MoGe-2, BERT, Grounding DINO, SwinIR и PP-OCR. Те, что не проходят, остаются на ручной математике и вместо этого выставляют флаг fused_attn — именно его переключает set_fused_attention(model): Swin, Swin-бэкбон в DINO-DETR, BiRefNet и FeyNobg, OWLv2, LW-DETR, SigLIP 2, ZipDepth и MobileSAM. В ViT и DeiT флаг тот же, но по умолчанию он включён, вслед за оригинальной реализацией, поэтому тот же вызов с enabled=False их выключает.

Там, где это применимо, оно того стоит. На RTX 5070 Ti под fp16-autocast оконное внимание Swin ускоряется с 1.278 мс до 0.721 мс — выигрыш в 1.77 раза, а зрительное внимание OWLv2 с 6.483 мс до 1.735 мс, в 3.74 раза.

Оборудование

ПлатформаПоведение
CPU и MPSНи один предикат CUDA или Triton не срабатывает, поэтому всё идёт по эталонному пути
NVIDIA CUDAВключаются Triton-ядра, а также подходящие ядра с Hub и GEMM-ядра
AMD ROCmTriton может включиться, поскольку в wheel-пакетах ROCm поставляется AMD-бэкенд Triton, но соответствие проверяется в CI только на NVIDIA

Добавление реализации

Вызовите register() с именем и предикатом. Скомпилированные ядра, живущие вне дерева, можно поставлять отдельным пакетом libreyolo_kernels, который регистрирует себя при импорте, — так закрытый бэкенд вообще не попадает в дерево LibreYOLO.

Для всего, что идёт в дерево, пропуском служит соответствие: точное совпадение прямого прохода с эталоном и градиенты в пределах 1e-6 от straight-through-оценки, на всём наборе форм, который есть в тестах.

Выбор ядра взаимодействует с графами CUDA: матрица соответствия для инференса прогонялась без установленного пакета kernels, поэтому безопасность захвата при активном скомпилированном ядре ею не покрыта.

API реестра прочитан из libreyolo/kernels/__init__.py на v1.5.0, API внимания — из libreyolo/kernels/attention/__init__.py и sdpa.py, провайдер Hub — из libreyolo/kernels/attention/ms_deform_attn.py, включая зафиксированную ревизию и предикат применимости. Структура каталогов перечислена по libreyolo/kernels/. Определение extra — из pyproject.toml. Замечания о поведении и цифры бенчмарков — из docs/kernels.md. История ограничения в v1.4.0 — из коммита, подключившего слот в RF-DETR, и записи в CHANGELOG для 1.5.0.