Переглянути як Markdown

Квантування

Квантування в LibreYOLO повністю виконується у PyTorch: model.quantize() замінює модулі Conv2d і Linear моделі квантованими еквівалентами та калібрує їх. Результат зберігає звичайний контракт predict, val, train і save, тому квантовану модель оцінюють ті самі валідатори, що й модель із рухомою комою.

Виклик
model.quantize(recipe="int8", calib="coco128.yaml")
Команда
libreyolo quantize --model M.pt --recipe int8 --calib coco128.yaml
Додатково
Нічого. Квантування виконується у PyTorch.
Сімейства
yolo9, rfdetr, birefnet, feynobg
Рецепти
fp16, bf16, fp8, int8, w4a16, w4a8, nvfp4, mxfp4, int2
Артефакти розгортання
export(format="pt") для упакованої контрольної точки, export(format="onnx") для графа QDQ INT8

Встановлення

Квантування не потребує додаткових пакетів. Заміна модулів, прохід калібрування та імітована арифметика повністю виконуються у PyTorch, тому достатньо pip install libreyolo. Для артефактів розгортання потрібні залежності їхніх форматів, зокрема libreyolo[onnx] для шляху ONNX.

Квантування

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt") # Заміна структури та калібрування. calib є невеликим набором зображень БЕЗ МІТОК,# який читається лише у прямому проході для визначення діапазонів і масштабів активацій.qmodel = model.quantize(recipe="int8", calib="coco128.yaml", samples=128) print(qmodel.quant_info())qmodel.val(data="coco8.yaml")          # ті самі валідатори, що й для моделі з рухомою комоюqmodel.save("LibreYOLO9s-int8.pt")     # контрольна точка містить маніфест квантування
CLI
libreyolo quantize --model LibreYOLO9s.pt --recipe int8 --calib coco128.yaml
Аргументи
model.quantize(    recipe="int8",    calib="coco128.yaml",      # шлях до data.yaml або вбудована назва; None пропускає калібрування    samples=128,               # максимальна кількість калібрувальних зображень    batch=8,                   # розмір калібрувального батча    algorithm="auto",          # auto та minmax однакові; альтернативою є percentile    keep_high_precision=None,  # None використовує політику сімейства    verbose=True,)

Метод quantize() перетворює завантажену модель на місці та повертає її. Градієнти не залучаються: під час заміни встановлюються квантовані модулі, а калібрувальний прохід виконується лише вперед.

Отримана контрольна точка є звичайною контрольною точкою LibreYOLO з доданим маніфестом quant, тому вона повторно завантажується зі збереженням структури та масштабів:

Квантована контрольна точка повторно завантажується як квантована
from libreyolo import LibreYOLO # Маніфест квантування відтворює квантовану структуру та масштаби# до завантаження ваг.qmodel = LibreYOLO("LibreYOLO9s-int8.pt")print(qmodel.quant_info())

Контрольні точки тренера, записані під час запуску QAT, також містять маніфест, тому best.pt із такого запуску сам є квантованою контрольною точкою.

Рецепти

Підтримуються чотири сімейства: yolo9, rfdetr, birefnet і feynobg.

РецептДіяСімействаКалібрування
fp16Приведення до половинної точності з контрактом вхідних і вихідних даних float32. Лише інференс.усі чотирине потрібне
bf16Приведення до bfloat16, що зберігає діапазон експоненти float32. Виправлення переповнення fp16 у моделі в стилі DETR. Лише інференс.усі чотирине потрібне
fp8Ваги й активації E4M3 у Conv2d та Linear: масштаби ваг для кожного каналу, калібровані масштаби активацій для кожного тензора.усі чотириобов'язкове
int8W8A8 у Conv2d та Linear: симетричні ваги для кожного каналу, афінні активації для кожного тензора.усі чотириобов'язкове або calib=None лише для ваг
w4a16Згруповані симетричні ваги INT4, група 128 уздовж in_features, активації з рухомою комою у Linear.rfdetr, birefnet, feynobgне потрібне
w4a8Згруповані ваги INT4 і калібровані активації INT8 у Linear.rfdetr, birefnet, feynobgобов'язкове
nvfp4W4A4 NVFP4 у Linear: елементи E2M1, блоки з 16 елементів, масштаби блоків FP8 E4M3, масштаб тензора FP32. Динамічне масштабування активацій.rfdetr, birefnet, feynobgне потрібне
mxfp4OCP MXFP4 у Linear: елементи E2M1, блоки з 32 елементів, масштаби блоків E8M0 у степенях двійки. Динамічне масштабування активацій.rfdetr, birefnet, feynobgне потрібне
int2Лише для досліджень: згруповані 2-бітові ваги, група 64 та активації INT8 у Linear. Самого післянавчального квантування недостатньо, тому потрібне QAT або QAD.rfdetrобов'язкове

Рецепти з менш ніж 8 бітами націлені на nn.Linear і навмисно відхиляються для yolo9: на сучасному обладнанні таке прискорення доступне лише для GEMM, тому згортки залишаються з вищою точністю. Модель YOLO9 використовує int8 або fp8. Рецепт int2 відхиляється для birefnet і feynobg, оскільки ці сімейства призначені лише для інференсу, тож потрібне рецепту відновлення за допомогою QAT для них недоступне.

Типові налаштування кожного сімейства залишають перший шар і голови з рухомою комою, а згортка DFL у YOLO9 ніколи не квантується: це фіксований оператор інтегрального математичного сподівання. Якщо маєте на те причину, змініть налаштування за допомогою keep_high_precision=("head.",).

Калібрувальні дані не є навчальними даними

Параметр calib= приймає кількасот зображень, не читає міток і виконує лише прямий прохід для оцінювання діапазонів активацій. Параметр data= у train() та val() містить розмічений датасет, який використовується для градієнтів і метрик. Ці аргументи мають різне призначення, а типовим значенням calib є coco128.yaml.

Алгоритм algorithm="minmax" зберігає абсолютні крайні значення, побачені в усіх калібрувальних батчах, і саме його вибирає "auto". Алгоритм "percentile" використовує середнє 0.1-го та 99.9-го процентилів кожного батча; вимірювання показали, що він руйнує правильність сімейств DETR, оскільки викиди активацій трансформера мають критичне значення. Чутливість малих моделей до INT8 фактично усуває калібрування на достатній кількості батчів: із типовим coco128 модель YOLO9-t відстає від оцінки з рухомою комою приблизно на один пункт mAP. Вибраний алгоритм записується в маніфест контрольної точки.

Відновлення правильності

QAT є звичайним train() для квантованої моделі
from libreyolo import LibreYOLO qmodel = LibreYOLO("LibreYOLO9s-int8.pt") # Це донавчання, а не запуск із нуля: використовуйте швидкості донавчання.qmodel.train(data="coco8.yaml", epochs=5, lr0=1e-4)
QAD додає наявні аргументи дистиляції
qmodel.train(    data="coco8.yaml",    epochs=5,    lr0=1e-4,    distill_model="LibreYOLO9m.pt",)
CLI
libreyolo train --model LibreYOLO9s-int8.pt --data coco8.yaml --epochs 5 --lr0 1e-4

Квантовані модулі зберігають головні ваги fp32 і застосовують імітаційне квантування з прямим оцінювачем, тому градієнти доходять до головних ваг, а наявні тренери працюють без змін: EMA, AMP, відновлення з контрольної точки та аргументи дистиляції поєднуються між собою.

QAT є донавчанням уже навченої моделі. Використовуйте швидкості донавчання замість типових значень для запуску з нуля, інакше короткий запуск зруйнує попередньо навчені ваги незалежно від квантування. Доступність QAD відповідає підтримці дистиляції сімейств, що наразі охоплює yolo9 і rfdetr.

Моделі, квантовані у fp16 та bf16, призначені лише для інференсу, і тренер відхиляє їх із посиланням на amp=True.

Експорт

Упакована контрольна точка PyTorch
from libreyolo import LibreYOLO qmodel = LibreYOLO("LibreYOLO9s-int8.pt") # Записує LibreYOLO9s-int8-final.pt: упаковані малобітові ваги й масштаби,# вилучені головні копії fp32, неквантований залишок приведено до fp16.qmodel.export(format="pt") # remainder="fp32" точно зберігає неквантовані тензори.qmodel.export(format="pt", remainder="fp32")
QDQ INT8 ONNX
from libreyolo import LibreYOLO qmodel = LibreYOLO("LibreYOLO9s-int8.pt") # Внутрішньографові пари QuantizeLinear/DequantizeLinear з власними# каліброваними або навченими за допомогою QAT масштабами моделі.qmodel.export(format="onnx")
CLI
libreyolo export --model LibreYOLO9s-int8.pt --format onnx

Параметр format="pt" фіксує модель. Упаковані малобітові ваги й масштаби замінюють головні копії, а неквантований залишок приводиться до fp16, якщо не передано remainder="fp32". Інваріант пакування полягає в тому, що розпакування біт у біт відтворює симуляцію на пристрої, де виконано фіналізацію, тому фіналізований файл отримує саме ту оцінку, яку ви валідували. Виміряно: розмір YOLO9-s int8 зменшується з 29.5 MB до 9.6 MB, а RF-DETR-n nvfp4 зі 122 MB до 26 MB. Після завантаження модель готова до інференсу, а виклик train() для неї автоматично відтворює головні копії з упакованих ваг.

Параметр format="onnx" застосовується до моделей int8 і створює граф QDQ із власними каліброваними або навченими за допомогою QAT масштабами моделі, який ONNX Runtime і TensorRT виконують за допомогою справжніх ядер INT8. Це інший шлях, ніж export(format="onnx", int8=True) для моделі з рухомою комою, де ONNX Runtime сам визначає масштаби.

Рецепти приведення не потребують квантованого експортера:

Повернення до рухомої коми зі збереженням навчених за допомогою QAT ваг
from libreyolo import LibreYOLO qmodel = LibreYOLO("LibreYOLO9s-int8.pt")qmodel.dequantize() # Тепер можна застосувати будь-який експортер рухомої коми з будь-якою підтримуваною точністю.qmodel.export(format="tensorrt", half=True)

Обмеження

Квантована арифметика виконується в симуляції, тобто імітаційне квантування обчислюється в острівцях float32 навіть під AMP. Симуляція точно відтворює числові властивості, тому оцінка val() на будь-якому пристрої є справжнім твердженням про квантовану арифметику. Вона не є твердженням про швидкість.

Два винятки виконуються нативно. fp16 і bf16 є звичайними приведеннями. Фіналізовані модулі fp8 виконують GEMM безпосередньо для упакованих ваг E4M3 через torch._scaled_mm на обладнанні класів Ada, Hopper і Blackwell, використовуючи ті самі калібровані масштаби активацій, що й симуляція; значення LIBREYOLO_KERNELS=off відновлює точний симульований шлях усюди.

Покриття розгортання вужче за перелік рецептів. Лише int8 має тут придатну до розгортання форму ONNX; fp8 та малобітові лінійні рецепти виконуються у PyTorch і фіксуються через format="pt". Запит експорту ONNX для них спричиняє помилку з цією вказівкою, як і запит будь-якого формату, крім ONNX, для моделі int8: будуйте подальші рушії з графа QDQ.

Під час експорту моделі int8, активації якої ніколи не калібрувалися, записується попередження та створюється граф лише з квантуванням ваг.

Перевірено за файлами libreyolo/quant/api.py, libreyolo/models/base/model.py, libreyolo/cli/commands/quantize.py та docs/quantization.md у гілці dev. Значення розміру контрольних точок взято з вимірювань, зафіксованих у docs/quantization.md.