YOLO-NAS
Свёрточный детектор, бэкбон и neck которого получены поиском архитектуры в Deci.AI и собраны из блоков RepVGG, рассчитанных на квантизацию. Веса принадлежат Deci.AI, лицензированы только для некоммерческого использования, и LibreYOLO их не публикует.
- Задачи
- detection, pose, oriented boxes
- Размеры
- s, m, l at 640 px
- Установка
pip install libreyolo- Уровень поддержки
- Основной, начиная с v1.1.0. Основные обучаемые детекторы: функции появляются вслед за флагманами в той же волне релиза.
- Исходный проект
- YOLO-NAS от Deci.AI, Deci.AI proprietary, non-commercial. Статья, исходный код
- Лицензии
- Код: Apache-2.0, веса: Deci.AI proprietary, non-commercial. Коммерческое использование
Установка
YOLO-NAS не требует ничего сверх базового пакета.
pip install libreyoloПредсказание
Имя чекпойнта, которого ещё нет на диске, скачивается с публичного CDN компании Deci, а не из организации LibreYOLO: она не хранит эти веса. Перед началом передачи библиотека один раз за процесс печатает условия лицензии Deci, а перед открытием скачанного файла его SHA-256 сверяется с зафиксированным значением. Что именно разрешают эти условия, описано в разделе лицензирование.
from libreyolo import LibreYOLO, SAMPLE_IMAGE # Имя, которого ещё нет на диске, скачивается с CDN компании Deci.# Перед скачиванием печатаются условия лицензии Deci; забирая файл, вы их принимаете.model = LibreYOLO("LibreYOLONASs.pt")result = model(SAMPLE_IMAGE, save=True) for box in result.boxes: print(box.cls, box.conf, box.xyxy)libreyolo predict model=LibreYOLONASs.pt save=True \ source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpgfrom libreyolo import LibreYOLO, SAMPLE_IMAGE # Суффикс -pose выбирает голову позы и её собственный набор весов.model = LibreYOLO("LibreYOLONASs-pose.pt")result = model(SAMPLE_IMAGE) print(result.keypoints.xy)Возвращаемый объект Results — тот же, что возвращает любое семейство, поэтому
замена на другой детектор занимает одну строку. conf задаёт порог
уверенности, а iou — порог NMS. Про источники, стриминг и обработку
результатов см. предсказание.
Задача повёрнутых рамок возвращает result.obb. Опубликованный граф OBB использует поле размером 1024 пикселя и записанный набор меток из 18 классов.
Варианты
Детекция и оценка позы — одна и та же архитектура под разными головами, и они принимают одни и те же аргументы. Размеры в таблице ниже относятся к детекции; для оценки позы опубликованы они же и ещё один, меньший. Голова позы предсказывает набор ключевых точек COCO.
| Чекпойнт | Вход (пикс.) | mAP 50-95 | Параметры (млн) |
|---|---|---|---|
| LibreYOLONASl | 640 | 56.3 | 66.98 |
| LibreYOLONASm | 640 | 55.4 | 51.18 |
| LibreYOLONASs | 640 | 51.8 | 19.05 |
COCO val2017, 500 images. Измерено системой бенчмарков LibreYOLO и опубликовано на Vision Analysis, где сравниваются задержки на разном оборудовании и в разных средах выполнения и хранятся полные записи запусков.
Обучение
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLONASs.pt")model.train(data="my-dataset.yaml", epochs=100, imgsz=640, batch=16)libreyolo train model=LibreYOLONASs.pt data=my-dataset.yaml \ epochs=100 imgsz=640 batch=16from libreyolo import LibreYOLONAS # Ни один чекпойнт Deci не задействован: модель стартует со случайных весов,# поэтому результат запуска получен только из ваших данных.model = LibreYOLONAS(None, size="s")model.train(data="my-dataset.yaml", imgsz=640, batch=16)epochs, lr0 и amp определяются под задачу, если вы их не задали, поэтому
запуск для оценки позы стартует с других значений по умолчанию, чем запуск для
детекции. Оптимизатор по умолчанию — AdamW. Число классов берётся из YAML
датасета, и перед первой эпохой голова пересобирается под него; на голове позы
число ключевых точек обрабатывается так же, поэтому чекпойнт позы COCO можно
дообучить под скелет другого размера.
Дообучение стартует с весов Deci — именно это и покрывает лицензия Deci. Обучение модели со случайной инициализацией вообще не задействует чекпойнт Deci, и это третий пример кода выше.
Про датасеты, аугментацию, multi-GPU и логгеры см. обучение.
Для детекции по умолчанию заданы amp=True и amp_dtype="float16"; обучение повёрнутых рамок сохраняет amp=False. Голова OBB поддерживает обучение, предсказание и валидацию, использует отражения и HSV-аугментацию и выбирает чекпойнты по metrics/mAP50-95(OBB). load_detect_weights_for_obb() инициализирует её весами детекции.
Валидация
val() возвращает словарь с ключами metrics/, покрывающими точность,
полноту, mAP 50 и mAP 50-95, измеренные на любом датасете в том же формате, в
котором вы обучали модель.
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLONASs.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/mAP50-95"])print(metrics["metrics/mAP50"])libreyolo val model=LibreYOLONASs.pt data=my-dataset.yaml# В поставляемом YAML для COCO есть встроенный скрипт скачивания, поэтому# нужно явное разрешение, если датасет ещё не лежит локально.libreyolo val model=LibreYOLONASl.pt data=coco.yaml imgsz=640 \ allow_download_scripts=TrueЭкспорт
| Задача | ONNX | TorchScript | ExecuTorch | TensorRT | OpenVINO | Paddle | MNN | RKNN | ncnn | TFLite | CoreML | Core AI |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Detection | Detection to ONNX: поддерживается | Detection to TorchScript: поддерживается | Detection to ExecuTorch: поддерживается | Detection to TensorRT: поддерживается | Detection to OpenVINO: поддерживается | Detection to Paddle: поддерживается | Detection to MNN: поддерживается | Detection to RKNN: поддерживается | Detection to ncnn: поддерживается | Detection to TFLite: поддерживается | Detection to CoreML: не поддерживается | Detection to Core AI: поддерживается |
| Pose | Pose to ONNX: поддерживается | Pose to TorchScript: поддерживается | Pose to ExecuTorch: поддерживается | Pose to TensorRT: поддерживается | Pose to OpenVINO: поддерживается | Pose to Paddle: поддерживается | Pose to MNN: не поддерживается | Pose to RKNN: не поддерживается | Pose to ncnn: поддерживается | Pose to TFLite: не поддерживается | Pose to CoreML: не поддерживается | Pose to Core AI: не поддерживается |
| Oriented boxes | Oriented boxes to ONNX: поддерживается | Oriented boxes to TorchScript: поддерживается | Oriented boxes to ExecuTorch: поддерживается | Oriented boxes to TensorRT: поддерживается | Oriented boxes to OpenVINO: поддерживается | Oriented boxes to Paddle: не поддерживается | Oriented boxes to MNN: не поддерживается | Oriented boxes to RKNN: не поддерживается | Oriented boxes to ncnn: поддерживается | Oriented boxes to TFLite: не поддерживается | Oriented boxes to CoreML: не поддерживается | Oriented boxes to Core AI: не поддерживается |
Экспортированный артефакт загружается обратно через LibreYOLO() по расширению
файла, поэтому файл .onnx или .engine ведёт себя как чекпойнт и возвращает
тот же Results. Запуск графа в голой среде выполнения, без установленной
библиотеки LibreYOLO, тоже поддерживается, но тогда предобработку и
постобработку вам придётся писать самостоятельно. Каждый формат ставится через
свой extra и принимает несколько собственных аргументов. И то и другое описано
на странице этого формата.
Экспорт — это ещё одна копия тех же весов в другом контейнере. Экспорт чекпойнта Deci не меняет ни того, откуда взялись веса, ни лицензии, которая на них распространяется.
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLONASs.pt")model.export(format="onnx", imgsz=640)libreyolo export model=LibreYOLONASs.pt format=onnx imgsz=640from libreyolo import LibreYOLO, SAMPLE_IMAGE # Фабрика выбирает путь по расширению файла, поэтому экспортированный артефакт# загружается как любой чекпойнт и возвращает тот же объект Results.model = LibreYOLO("LibreYOLONASs.onnx")result = model(SAMPLE_IMAGE) print(result.boxes.xyxy)Входы и выходы ONNX
LibreYOLONAS detect
| Тензор | images float32 [batch, 3, height, width] |
|---|---|
| Цвет | RGB |
| Масштабирование | пиксель / 255 |
| Нормализация | нет |
| Изменение размера | custom, Pillow bilinear |
Как воспроизвести билинейное изменение размера Pillow
LibreYOLO меняет размер фильтром BILINEAR из Pillow (Image.resize). Это не OpenCV INTER_LINEAR и не INTER_AREA: при уменьшении Pillow расширяет фильтр на коэффициент уменьшения, а изменение размера в OpenCV меняет детекции и сдвигает рамки на несколько пикселей. Чтобы воспроизвести его без Pillow, измените размер по одной оси, округлите до 8 бит, затем измените размер по другой оси и округлите снова. Для каждой оси пусть s = in_size / out_size и f = max(s, 1). Выходной пиксель i имеет центр c = (i + 0.5) * s и читает исходные пиксели j от int(c - f + 0.5) до int(c + f + 0.5) - 1, ограниченные изображением, каждый с весом max(0, 1 - |j + 0.5 - c| / f), деленным на сумму весов. Pillow считает в фиксированной точке и выбирает порядок осей по форме изображения, поэтому веса с плавающей точкой могут отличаться от него на один уровень на нескольких пикселях. Это не меняет результаты в наших проверках.
Square input only. Export rejects a non-square imgsz, and height equals width, 640 by default.
The image is not scaled to fill the canvas. The longest side goes to R = min(636, height, width), so 636 at 640 x 640.
Scale by r = min(R / h, R / w) and resize to (round(w * r), round(h * r)). The rounding is Python round, so an exact .5 goes to the even neighbor.
Paste the resized image onto a canvas filled with 114 at left = (width - new_w) // 2 and top = (height - new_h) // 2.
On the test image, cv2.resize with INTER_LINEAR loses two of the eight detections, and INTER_AREA moves boxes by up to 1.4 px.
Divide by 255 after the resize. There is no mean or std normalization.
Detection, экспорт по умолчанию
| Выход | Форма | Смысл |
|---|---|---|
pred_logits | [batch, anchors, 4] | Boxes, despite the name. x1, y1, x2, y2 in input-canvas pixels. anchors is the cell count over strides 8, 16 and 32, 8400 at 640 x 640. |
pred_boxes | [batch, anchors, nc] | Class scores, despite the name. Sigmoid already applied. 80 classes for the COCO checkpoints. |
Постобработка
- The output names are swapped relative to their content. Read boxes from pred_logits and scores from pred_boxes, or tell them apart by the last dimension (4 for boxes).
- Take the best class per anchor: score = max over classes, class = argmax. One anchor yields at most one detection.
- Keep anchors whose score is strictly above the confidence threshold (0.25 by default).
- Keep the 1000 highest scoring candidates.
- Map boxes back to the original image: subtract left from x and top from y, divide by r, clip to the image. Drop boxes left with zero width or height.
- Run NMS per class with IoU 0.45 and keep at most 300 detections.
- nms=True is not available for this family: export raises NotImplementedError.
LibreYOLONAS pose
| Тензор | images float32 [batch, 3, height, width] |
|---|---|
| Цвет | BGR |
| Масштабирование | пиксель / 255 |
| Нормализация | нет |
| Изменение размера | custom, Pillow bilinear |
Как воспроизвести билинейное изменение размера Pillow
LibreYOLO меняет размер фильтром BILINEAR из Pillow (Image.resize). Это не OpenCV INTER_LINEAR и не INTER_AREA: при уменьшении Pillow расширяет фильтр на коэффициент уменьшения, а изменение размера в OpenCV меняет детекции и сдвигает рамки на несколько пикселей. Чтобы воспроизвести его без Pillow, измените размер по одной оси, округлите до 8 бит, затем измените размер по другой оси и округлите снова. Для каждой оси пусть s = in_size / out_size и f = max(s, 1). Выходной пиксель i имеет центр c = (i + 0.5) * s и читает исходные пиксели j от int(c - f + 0.5) до int(c + f + 0.5) - 1, ограниченные изображением, каждый с весом max(0, 1 - |j + 0.5 - c| / f), деленным на сумму весов. Pillow считает в фиксированной точке и выбирает порядок осей по форме изображения, поэтому веса с плавающей точкой могут отличаться от него на один уровень на нескольких пикселях. Это не меняет результаты в наших проверках.
Square input only. Export rejects a non-square imgsz, and height equals width, 640 by default.
Channels are BGR, unlike detection. Pad value and position also differ from detection.
The longest side goes to R = min(640, height, width), so it fills the canvas.
Scale by r = min(R / h, R / w) and resize to (round(w * r), round(h * r)). The rounding is Python round, so an exact .5 goes to the even neighbor.
Paste the resized image in the top-left corner of a canvas filled with 127. All padding is on the bottom and the right.
On the test image, cv2.resize with INTER_LINEAR or INTER_AREA moves boxes by up to 5 px and keypoints by more than 10 px.
Divide by 255 after the resize. There is no mean or std normalization.
Pose, экспорт по умолчанию
| Выход | Форма | Смысл |
|---|---|---|
boxes | [batch, anchors, 4] | Person boxes as x1, y1, x2, y2 in input-canvas pixels. anchors is the cell count over strides 8, 16 and 32, 8400 at 640 x 640. |
scores | [batch, anchors, nc] | Class scores, sigmoid already applied. nc is 1 (person) for the COCO pose checkpoints. |
keypoints_xy | [batch, anchors, num_keypoints, 2] | Keypoint x, y in input-canvas pixels. num_keypoints is 17 (COCO order) for the COCO pose checkpoints. |
keypoints_conf | [batch, anchors, num_keypoints] | Per-keypoint visibility score, sigmoid already applied. |
Постобработка
- Take the best class per anchor: score = max over classes, class = argmax. With one class this is just the person score.
- Keep anchors whose score is at or above the confidence threshold (0.25 by default). This is >=, not > as in detection.
- Keep the 1000 highest scoring candidates.
- Map boxes and keypoints back to the original image: divide x and y by r. The image sits in the top-left corner, so there is no pad offset to subtract.
- Clip boxes to the image and drop boxes left with zero width or height. Keypoints are not clipped and can fall outside the image.
- Run NMS per class with IoU 0.45 and keep at most 300 detections. Keep each survivor's keypoints as (x, y, keypoints_conf).
- nms=True is not available for this family: export raises NotImplementedError.
LibreYOLONAS obb
| Тензор | images float32 [batch, 3, height, width] |
|---|---|
| Цвет | BGR |
| Масштабирование | пиксель / 255 |
| Нормализация | нет |
| Изменение размера | custom, bilinear |
Square input only. Export rejects a non-square imgsz, and height equals width, 1024 by default.
Channels are BGR, unlike detection. The resize filter and the pad position also differ from detection.
The longest side goes to R = min(1024, height, width), so it fills the canvas.
Scale by r = min(R / h, R / w) and resize to (round(w * r), round(h * r)). The rounding is Python round, so an exact .5 goes to the even neighbor.
The resize is cv2.resize with INTER_LINEAR, not Pillow as in detection and pose. It is skipped when the image already has that size. On the test image, Pillow's filter here changes the detection count.
Paste the resized image in the top-left corner of a canvas filled with 114. All padding is on the bottom and the right.
Divide by 255 after the resize. There is no mean or std normalization.
Oriented boxes, экспорт по умолчанию
| Выход | Форма | Смысл |
|---|---|---|
boxes | [batch, anchors, 5] | Rotated boxes as cx, cy, w, h, angle. cx, cy, w and h are in input-canvas pixels. The angle is in radians. The graph computes it as (sigmoid(logit) - 0.25) x pi, so it lies between -pi/4 and 3pi/4 and is not wrapped yet. The w side points along (cos angle, sin angle) in image coordinates, y down. anchors is the cell count over strides 8, 16 and 32, 21504 at 1024 x 1024. |
scores | [batch, anchors, nc] | Class scores, sigmoid already applied. 18 classes (DOTA 2.0) for the published checkpoints. |
Постобработка
- Take the best class per anchor: score = max over classes, class = argmax. One anchor yields at most one detection.
- Keep anchors whose score is at or above the confidence threshold (0.25 by default). This is >=, not > as in detection.
- Keep the 1000 highest scoring candidates.
- Map boxes back to the original image: divide cx, cy, w and h by r. The image sits in the top-left corner, so there is no pad offset, and the angle does not change.
- Clip cx to 0 to the image width and cy to 0 to the image height. w and h are not clipped. Drop boxes with w or h at or below 0.
- Put the long side first: if h > w, swap w and h and add pi/2 to the angle. Then wrap the angle to [-pi/2, pi/2) with angle = ((angle + pi/2) mod pi) - pi/2.
- Run greedy NMS per class on exact rotated-box IoU (polygon intersection area over union, for example cv2.rotatedRectangleIntersection) with IoU 0.45, and keep at most 300 detections. LibreYOLO does not use upstream's matrix soft-NMS.
- LibreYOLO also reports an axis-aligned box per detection. With ex = abs(cos angle) * w / 2 + abs(sin angle) * h / 2 and ey = abs(sin angle) * w / 2 + abs(cos angle) * h / 2, it is cx - ex, cy - ey, cx + ex, cy + ey, clipped to the image.
- nms=True is not available for this family: export raises NotImplementedError.
Чтобы проверить собственную реализацию, пропустите тот же файл через LibreYOLO: LibreYOLO("model.onnx").predict("image.jpg") возвращает эталонные результаты. Проверено на LibreYOLO 1.7.0.
Чекпойнты
Перечислять нечего. Лицензия Deci запрещает распространение, поэтому
организация LibreYOLO не публикует веса YOLO-NAS и скачивание уходит в другое
место: имя вида LibreYOLONAS<size>.pt, LibreYOLONAS<size>-pose.pt для
оценки позы или LibreYOLONAS<size>-obb.pt (s, m, l) для повёрнутых рамок
отображается на соответствующий объект на публичном CDN компании Deci.
Так скачиваются только те чекпойнты, чей SHA-256 зафиксирован в библиотеке. Всё
остальное завершается отказом, а не открытием непроверенного стороннего
pickle-файла, и такой файл придётся скачать вручную и указать путь к нему.
Файл, уже лежащий на диске, загружается по своему пути, без скачивания и без
проверки контрольной суммы. Это касается и файла .pth от Deci под его исходным именем:
загрузчик его распознаёт.
Лицензирование
Проверяйте лицензию в репозитории конкретных весов на Hugging Face. Она указана для каждого чекпойнта в организации LibreYOLO и может различаться даже внутри одного семейства. Этот репозиторий считается авторитетным источником, а сводка ниже описывает условия на момент последней проверки страницы.
Это описание соответствующих лицензий, а не юридическая консультация. Если ответ важен для коммерческого использования, прочитайте лицензии самостоятельно и проконсультируйтесь с юристом.
- Оригинальная работа
- YOLO-NAS, Deci.AI
- Лицензия исходного проекта
- Deci.AI proprietary, non-commercial
- Исходный код проекта
- github.com/Deci-AI/super-gradients
- Код LibreYOLO
- MIT
- Веса
- Deci.AI proprietary, non-commercial, распространяются авторами. LibreYOLO не размещает и не зеркалирует их.
- Толкование
- Two licenses apply here and they are not the same. The SuperGradients source this port follows is Apache-2.0 and LibreYOLO's own implementation is MIT, so nothing restricts the architecture or the training code. Deci's published checkpoints are a different matter: the YOLO-NAS license grants a revocable, non-transferable right to use them and nothing more. It forbids redistribution and sublicensing, forbids offering them as a managed or remote service, restricts modification and reverse engineering, and rules out commercial use, including any model running in a production environment, unless you hold a separate agreement with Deci. LibreYOLO therefore does not mirror them, and prints those terms once before the download starts. Weights trained from a randomly initialized model on your own data derive from no Deci checkpoint.
LibreYOLO не размещает эти веса у себя и не делает их зеркал: в организации LibreYOLO на Hugging Face для этого семейства нет ничего. Каждое автоматическое скачивание вместо этого идёт на публичный CDN компании Deci, один раз за процесс печатает условия Deci перед началом и сверяется с зафиксированным SHA-256 до открытия файла.
Альтернатива — обучение модели со случайной инициализацией. Архитектура в апстриме под Apache-2.0, а здесь под MIT, поэтому модель, обученная так на ваших данных, не происходит ни от одного чекпойнта Deci.
Цитирование
YOLO-NAS вышел без статьи. Запись ниже — та, о которой просят его авторы; она относится к SuperGradients, библиотеке, в составе которой он вышел.
@misc{supergradients,
doi = {10.5281/ZENODO.7789328},
url = {https://zenodo.org/record/7789328},
author = {Aharon, Shay and {Louis-Dupont} and {Ofri Masad} and Yurkova, Kate and {Lotem Fridman} and {Lkdci} and Khvedchenya, Eugene and Rubin, Ran and Bagrov, Natan and Tymchenko, Borys and Keren, Tomer and Zhilko, Alexander and {Eran-Deci}},
title = {Super-Gradients},
publisher = {GitHub},
journal = {GitHub repository},
year = {2021},
}Скопировано из блока цитирования авторов на странице github.com/Deci-AI/super-gradients#citing.