Ядра
У каждой ускоренной операции в 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.pyLIBREYOLO_HUB_KERNELS=0 python predict.pyfrom 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:
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 ROCm | Triton может включиться, поскольку в wheel-пакетах ROCm поставляется AMD-бэкенд Triton, но соответствие проверяется в CI только на NVIDIA |
Добавление реализации
Вызовите register() с именем и предикатом. Скомпилированные ядра, живущие вне
дерева, можно поставлять отдельным пакетом libreyolo_kernels, который
регистрирует себя при импорте, — так закрытый бэкенд вообще не попадает в дерево
LibreYOLO.
Для всего, что идёт в дерево, пропуском служит соответствие: точное совпадение прямого прохода с эталоном и градиенты в пределах 1e-6 от straight-through-оценки, на всём наборе форм, который есть в тестах.
Выбор ядра взаимодействует с графами CUDA:
матрица соответствия для инференса прогонялась без установленного пакета
kernels, поэтому безопасность захвата при активном скомпилированном ядре ею не
покрыта.