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 не требует ничего сверх базового пакета.

bash
pip install libreyolo

Предсказание

Имя чекпойнта, которого ещё нет на диске, скачивается с публичного CDN компании Deci, а не из организации LibreYOLO: она не хранит эти веса. Перед началом передачи библиотека один раз за процесс печатает условия лицензии Deci, а перед открытием скачанного файла его SHA-256 сверяется с зафиксированным значением. Что именно разрешают эти условия, описано в разделе лицензирование.

Python
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)
CLI
libreyolo predict model=LibreYOLONASs.pt save=True \  source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpg
Оценка позы
from 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Параметры (млн)
LibreYOLONASl64056.366.98
LibreYOLONASm64055.451.18
LibreYOLONASs64051.819.05

COCO val2017, 500 images. Измерено системой бенчмарков LibreYOLO и опубликовано на Vision Analysis, где сравниваются задержки на разном оборудовании и в разных средах выполнения и хранятся полные записи запусков.

Обучение

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLONASs.pt")model.train(data="my-dataset.yaml", epochs=100, imgsz=640, batch=16)
CLI
libreyolo train model=LibreYOLONASs.pt data=my-dataset.yaml \  epochs=100 imgsz=640 batch=16
Обучение с нуля
from 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, измеренные на любом датасете в том же формате, в котором вы обучали модель.

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLONASs.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/mAP50-95"])print(metrics["metrics/mAP50"])
CLI
libreyolo val model=LibreYOLONASs.pt data=my-dataset.yaml
Валидация на COCO
# В поставляемом YAML для COCO есть встроенный скрипт скачивания, поэтому# нужно явное разрешение, если датасет ещё не лежит локально.libreyolo val model=LibreYOLONASl.pt data=coco.yaml imgsz=640 \  allow_download_scripts=True

Экспорт

ЗадачаONNXTorchScriptExecuTorchTensorRTOpenVINOPaddleMNNRKNNncnnTFLiteCoreMLCore AI
DetectionDetection 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: поддерживается
PosePose 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 boxesOriented 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 не меняет ни того, откуда взялись веса, ни лицензии, которая на них распространяется.

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLONASs.pt")model.export(format="onnx", imgsz=640)
CLI
libreyolo export model=LibreYOLONASs.pt format=onnx imgsz=640
Использование экспортированного файла
from 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.

Постобработка

  1. 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).
  2. Take the best class per anchor: score = max over classes, class = argmax. One anchor yields at most one detection.
  3. Keep anchors whose score is strictly above the confidence threshold (0.25 by default).
  4. Keep the 1000 highest scoring candidates.
  5. 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.
  6. Run NMS per class with IoU 0.45 and keep at most 300 detections.
  7. 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.

Постобработка

  1. Take the best class per anchor: score = max over classes, class = argmax. With one class this is just the person score.
  2. Keep anchors whose score is at or above the confidence threshold (0.25 by default). This is >=, not > as in detection.
  3. Keep the 1000 highest scoring candidates.
  4. 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.
  5. Clip boxes to the image and drop boxes left with zero width or height. Keypoints are not clipped and can fall outside the image.
  6. Run NMS per class with IoU 0.45 and keep at most 300 detections. Keep each survivor's keypoints as (x, y, keypoints_conf).
  7. 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.

Постобработка

  1. Take the best class per anchor: score = max over classes, class = argmax. One anchor yields at most one detection.
  2. Keep anchors whose score is at or above the confidence threshold (0.25 by default). This is >=, not > as in detection.
  3. Keep the 1000 highest scoring candidates.
  4. 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.
  5. 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.
  6. 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.
  7. 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.
  8. 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.
  9. 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.

Проверено с LibreYOLO v1.6.0. Таблицы поддержки, чекпойнты и результаты бенчмарков на этой странице сгенерированы из выпущенной библиотеки и опубликованных весов, а не написаны вручную.