YOLO-NAS
A convolutional detector whose backbone and neck came out of Deci.AI's architecture search, built from quantization-aware RepVGG blocks. Its weights are Deci.AI's, licensed for non-commercial use only, and LibreYOLO publishes none of them.
- Tasks
- detection, pose, oriented boxes
- Sizes
- s, m, l at 640 px
- Install
pip install libreyolo- Support tier
- Core, since v1.1.0. Core trainable detectors: features follow the flagships in the same release wave.
- Licenses
- Code Apache-2.0, weights Deci.AI proprietary, non-commercial. Commercial use
Install
YOLO-NAS needs no extra beyond the base package.
pip install libreyoloPredict
A checkpoint name that is not already on disk is fetched from Deci's public CDN, not from the LibreYOLO org, which hosts none of these weights. Before the transfer starts the library prints Deci's license terms once per process, and before the downloaded file is opened its SHA-256 is checked against a pinned value. What those terms allow is in licensing.
from libreyolo import LibreYOLO, SAMPLE_IMAGE # A name not already on disk is fetched from Deci's CDN. The download# prints Deci's license terms first; taking the file accepts them.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 # The -pose suffix picks the pose head and its own set of weights.model = LibreYOLO("LibreYOLONASs-pose.pt")result = model(SAMPLE_IMAGE) print(result.keypoints.xy)The returned Results object is the one every family returns, so swapping in a
different detector is a one line change. conf sets the confidence threshold
and iou the NMS threshold. See prediction for sources,
streaming and result handling.
The oriented-box task returns result.obb. The published OBB graph uses a 1024-pixel canvas and its recorded 18-class label set.
Variants
Detection and pose are the same architecture under different heads, and they take the same arguments. The sizes in the table below are the detection ones; pose is published at those and at one smaller size. The pose head predicts the COCO keypoint set.
| Checkpoint | Input (px) | mAP 50-95 | Params (M) |
|---|---|---|---|
| LibreYOLONASl | 640 | 56.3 | 66.98 |
| LibreYOLONASm | 640 | 55.4 | 51.18 |
| LibreYOLONASs | 640 | 51.8 | 19.05 |
COCO val2017, 500 images. Measured by the LibreYOLO benchmark harness and published on Vision Analysis, where latency across hardware and runtimes is compared and the full run records live.
Train
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 # No Deci checkpoint is touched: the model starts from random weights,# so what comes out of the run derives only from your data.model = LibreYOLONAS(None, size="s")model.train(data="my-dataset.yaml", imgsz=640, batch=16)epochs, lr0 and amp are resolved per task when you leave them out, so a
pose run starts from different defaults than a detection run. The optimizer
defaults to AdamW. The class count comes from the dataset YAML and the head is
rebuilt for it before the first epoch; on the pose head the keypoint count is
handled the same way, so a COCO pose checkpoint can be fine-tuned onto a
skeleton of a different size.
Fine-tuning starts from Deci's weights, which is what Deci's license covers. Training from a randomly initialized model involves no Deci checkpoint at all, and that is the third snippet above.
See training for datasets, augmentation, multi-GPU and loggers.
Detection defaults to amp=True with amp_dtype="float16"; oriented-box training retains amp=False. The OBB head supports training, prediction and validation, uses flipped/HSV augmentation and selects checkpoints with metrics/mAP50-95(OBB). load_detect_weights_for_obb() initializes it from detection weights.
Validate
val() returns a dictionary of metrics/ keys covering precision, recall,
mAP 50 and mAP 50-95, measured against any dataset in the format you trained on.
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# The bundled COCO yaml carries an embedded download script, so it# needs explicit permission unless the dataset is already local.libreyolo val model=LibreYOLONASl.pt data=coco.yaml imgsz=640 \ allow_download_scripts=TrueExport
| Task | ONNX | TorchScript | ExecuTorch | TensorRT | OpenVINO | Paddle | MNN | RKNN | ncnn | TFLite | CoreML | Core AI |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Detection | Detection to ONNX: supported | Detection to TorchScript: supported | Detection to ExecuTorch: supported | Detection to TensorRT: supported | Detection to OpenVINO: supported | Detection to Paddle: supported | Detection to MNN: supported | Detection to RKNN: supported | Detection to ncnn: supported | Detection to TFLite: supported | Detection to CoreML: not supported | Detection to Core AI: supported |
| Pose | Pose to ONNX: supported | Pose to TorchScript: supported | Pose to ExecuTorch: supported | Pose to TensorRT: supported | Pose to OpenVINO: supported | Pose to Paddle: supported | Pose to MNN: not supported | Pose to RKNN: not supported | Pose to ncnn: supported | Pose to TFLite: not supported | Pose to CoreML: not supported | Pose to Core AI: not supported |
| Oriented boxes | Oriented boxes to ONNX: supported | Oriented boxes to TorchScript: supported | Oriented boxes to ExecuTorch: supported | Oriented boxes to TensorRT: supported | Oriented boxes to OpenVINO: supported | Oriented boxes to Paddle: not supported | Oriented boxes to MNN: not supported | Oriented boxes to RKNN: not supported | Oriented boxes to ncnn: supported | Oriented boxes to TFLite: not supported | Oriented boxes to CoreML: not supported | Oriented boxes to Core AI: not supported |
An exported artifact loads back through LibreYOLO() on its file suffix, so a
.onnx or .engine file behaves like a checkpoint and returns the same
Results. Running the graph in a bare runtime, with no LibreYOLO installed, is
also supported, but then preprocessing and postprocessing are yours to write.
Each format installs a different extra and takes a few arguments of its own.
Both are on that format's page.
An export is another copy of the same weights in a different container. Exporting a Deci checkpoint changes neither where the weights came from nor the license that covers them.
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 # The factory routes on the file suffix, so an exported artifact loads# like any checkpoint and returns the same Results object.model = LibreYOLO("LibreYOLONASs.onnx")result = model(SAMPLE_IMAGE) print(result.boxes.xyxy)ONNX inputs and outputs
LibreYOLONAS detect
| Tensor | images float32 [batch, 3, height, width] |
|---|---|
| Color | RGB |
| Scaling | pixel / 255 |
| Normalization | none |
| Resize | custom, Pillow bilinear |
How to reproduce Pillow's bilinear resize
LibreYOLO resizes with Pillow's BILINEAR filter (Image.resize). It is not OpenCV INTER_LINEAR or INTER_AREA: when shrinking, Pillow widens the filter by the shrink factor, and OpenCV's resizes change detections and move boxes by several pixels. To reproduce it without Pillow, resize one axis, round to 8 bits, then resize the other axis and round again. Per axis, let s = in_size / out_size and f = max(s, 1). Output pixel i has center c = (i + 0.5) * s and reads source pixels j from int(c - f + 0.5) to int(c + f + 0.5) - 1, clipped to the image, each with weight max(0, 1 - |j + 0.5 - c| / f), divided by the sum of the weights. Pillow works in fixed point and picks the axis order from the image shape, so float weights can differ from it by one level on a few pixels. That does not change the results in our checks.
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, default export
| Output | Shape | Meaning |
|---|---|---|
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. |
Postprocessing
- 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
| Tensor | images float32 [batch, 3, height, width] |
|---|---|
| Color | BGR |
| Scaling | pixel / 255 |
| Normalization | none |
| Resize | custom, Pillow bilinear |
How to reproduce Pillow's bilinear resize
LibreYOLO resizes with Pillow's BILINEAR filter (Image.resize). It is not OpenCV INTER_LINEAR or INTER_AREA: when shrinking, Pillow widens the filter by the shrink factor, and OpenCV's resizes change detections and move boxes by several pixels. To reproduce it without Pillow, resize one axis, round to 8 bits, then resize the other axis and round again. Per axis, let s = in_size / out_size and f = max(s, 1). Output pixel i has center c = (i + 0.5) * s and reads source pixels j from int(c - f + 0.5) to int(c + f + 0.5) - 1, clipped to the image, each with weight max(0, 1 - |j + 0.5 - c| / f), divided by the sum of the weights. Pillow works in fixed point and picks the axis order from the image shape, so float weights can differ from it by one level on a few pixels. That does not change the results in our checks.
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, default export
| Output | Shape | Meaning |
|---|---|---|
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. |
Postprocessing
- 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
| Tensor | images float32 [batch, 3, height, width] |
|---|---|
| Color | BGR |
| Scaling | pixel / 255 |
| Normalization | none |
| Resize | 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, default export
| Output | Shape | Meaning |
|---|---|---|
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. |
Postprocessing
- 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.
To check your own implementation, run the same file through LibreYOLO: LibreYOLO("model.onnx").predict("image.jpg") returns the reference results. Verified with LibreYOLO 1.7.0.
Checkpoints
There are none to list. Deci's license forbids redistribution, so the LibreYOLO
org publishes no YOLO-NAS weights and the download resolves elsewhere: a name
of the form LibreYOLONAS<size>.pt, LibreYOLONAS<size>-pose.pt for pose, or
LibreYOLONAS<size>-obb.pt (s, m, l) for oriented boxes, maps to the matching object on Deci's public CDN.
Only the checkpoints whose SHA-256 the library pins can be fetched that way.
Anything else fails closed rather than opening an unverified third-party
pickle, and has to be downloaded by hand and passed as a path. A file already
on disk loads from its path, with no download and no checksum gate. That
includes a Deci .pth under its original name, which the loader recognizes.
Licensing
Check the license on the Hugging Face repository of the specific weights you download. Every checkpoint in the LibreYOLO org carries one, and they are not always the same across a family. That repository is the authoritative source; the summary below describes what applied when this page was last verified.
This is a description of the licenses involved, not legal advice. If the answer matters commercially, read the licenses yourself and take your own counsel.
- Original work
- YOLO-NAS, Deci.AI
- Upstream license
- Deci.AI proprietary, non-commercial
- Upstream source
- github.com/Deci-AI/super-gradients
- LibreYOLO code
- MIT
- Weights
- Deci.AI proprietary, non-commercial, distributed by their authors. LibreYOLO does not host or mirror them.
- Interpretation
- 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 neither hosts nor mirrors these weights: nothing for this family exists in the LibreYOLO Hugging Face org. Every auto-download goes to Deci's public CDN instead, prints Deci's terms once per process before it starts, and is checked against a pinned SHA-256 before the file is opened.
Training from a randomly initialized model is the alternative. The architecture is Apache-2.0 upstream and MIT here, so a model trained that way on your own data derives from no Deci checkpoint.
Citation
YOLO-NAS was released without a paper. The entry below is the one its authors ask for, covering SuperGradients, the library it shipped in.
@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},
}Copied from the authors' citation block at github.com/Deci-AI/super-gradients#citing.