Model Export with Ultralytics YOLO
Introduction#
The goal of training a model is usually to deploy it in real-world applications. Export mode in Ultralytics YOLO26 converts your trained model to different formats so it can run across various platforms and devices. This guide covers export usage, arguments, supported formats, and quantization options.
See the unreleased YOLO27 preview for planned export support.
Watch: How to Export Ultralytics YOLO26 in different formats for Deployment | ONNX, TensorRT, CoreML 🚀
Why Choose YOLO26's Export Mode?#
- Versatility: Export to multiple formats including ONNX, TensorRT, CoreML, and more.
- Performance: Gain up to 5x GPU speedup with TensorRT and 3x CPU speedup with ONNX or OpenVINO.
- Compatibility: Deploy your model across a wide range of hardware and software environments.
- Ease of Use: Export with a single CLI command or Python call.
Usage Examples#
Export a YOLO26n model to a different format like ONNX or TensorRT.
from ultralytics import YOLO
# Load a model
model = YOLO("yolo26n.pt") # load an official model
model = YOLO("path/to/best.pt") # load a custom-trained model
# Export the model
model.export(format="onnx")Arguments#
This table lists the arguments available for exporting YOLO models to different formats. They control the exported model's performance, size, and compatibility with the target platform and environment.
| Argument | Type | Default | Description |
|---|---|---|---|
format | str | 'torchscript' | Target format for the exported model, such as 'onnx', 'torchscript', 'engine' (TensorRT), or others. Each format enables compatibility with different deployment environments. |
name | str | None | Hardware target name for the formats that require one: Hailo architecture ('hailo8', 'hailo8l', 'hailo10h', 'hailo15h', 'hailo15l'; defaults to 'hailo8l'), Rockchip RKNN chip (defaults to 'rk3588'), Huawei Ascend SoC (a CANN --soc_version; defaults to 'Ascend310B4'), Qualcomm QNN HTP target (defaults to '73'), or AMD Xilinx Versal AI Edge Series Gen 2 device (defaults to 've2-xc2ve3858', the VEK385 evaluation kit). Distinct from the project/name run-naming pair used by other modes. |
imgsz | int or tuple | 640 | Desired image size for the model input. Can be an integer for square images (e.g., 640 for 640×640) or a tuple (height, width) for specific dimensions. When not passed, an export reuses the training size recorded in the loaded checkpoint: the official YOLO26 checkpoints record 768 for depth, 224 for classify, 1024 for OBB and 640 for the other tasks, while a fine-tune records whatever imgsz it was trained at. A model built from a YAML has no recorded training size and uses 640. |
optimize | bool | False | Enables higher compiler optimization for DEEPX, reducing inference latency while increasing compilation time. |
quantize | int or str | None | Quantization precision: 16 (FP16, reduces model size and can speed up inference on supported hardware) or 8 (INT8/PTQ, further compresses the model with minimal accuracy loss, primarily for edge devices; needs calibration data/fraction); 32 selects FP32 where supported; unset uses FP32 unless the target requires quantization, such as INT8 for NXP. A checkpoint trained with quantize=8 always exports INT8: onnx and engine export from the ranges it carries without calibration, and other formats or precisions are rejected. 'w8a8' and 'w16a16' are aliases for 8 and 16; the mixed precisions 'w8a16' (INT8 weights with 16-bit activations: CoreML, LiteRT, QNN) and 'w8a32' (dynamic INT8: LiteRT) are accepted only by those formats. Replaces the deprecated half/int8 flags (half=True → 16, int8=True → 8, still accepted with a deprecation warning). Only precisions supported by the target format are allowed (see below). |
dynamic | bool | False | Allows dynamic input sizes for TorchScript, ONNX, OpenVINO, TensorRT, CoreML, and MNN exports, enhancing flexibility in handling varying image dimensions. |
simplify | bool | True | Simplifies the intermediate ONNX graph with onnxslim for the exports that build one (see Export Formats), potentially improving performance and compatibility with inference engines. |
opset | int | None | Specifies the ONNX opset version for the exports that build an ONNX graph (see Export Formats), for compatibility with different ONNX parsers and runtimes. If not set, uses opset 18 (lower on PyTorch < 2.4), capped at the installed onnx version. RKNN, Ascend, AMD Xilinx, Hailo and RT-DETR TensorFlow exports set their own opset. |
workspace | float or None | None | Sets the maximum workspace size in GiB for TensorRT optimizations, balancing memory usage and performance. Use None for auto-allocation by TensorRT up to device maximum. |
nms | bool, optional | None | None exports raw one-to-many predictions for external NMS (YOLO26 keeps its NMS-free head on Axelera); True embeds NMS where supported; False selects the NMS-free head when available. CoreML embedded NMS supports detect, segment and pose with static shapes. See the End-to-End Detection guide. |
conf | float | None | Confidence threshold used wherever export-time NMS is generated: nms=True exports; Hailo's non-end-to-end detect exports; and IMX's detect, pose, and segment exports, which force nms=True internally. Defaults to 0.25 when unset. |
iou | float | 0.7 | IoU threshold used wherever export-time NMS is generated: nms=True exports; Hailo's non-end-to-end detect exports; and IMX's detect, pose, and segment exports, which force nms=True internally. |
max_det | int | 300 | Maximum number of detections kept in the exported model's output. Applies to nms=True exports on every format except CoreML detection, whose native NMS pipeline has no detection cap, plus NMS-free end-to-end detection exports (YOLO26, YOLOv10, clamped to the number of available anchors) and IMX's detect, pose, and segment exports. |
agnostic_nms | bool | False | Enables class-agnostic NMS wherever export-time NMS is generated through the standard nms=True pipeline, including CoreML's own NMS stage, suppressing lower-scoring overlapping boxes across different classes rather than only within the same class. Not honored by Hailo's or IMX's own generated NMS configs, which have no class-agnostic option and remain class-aware regardless of this flag. Also baked into NMS-free end-to-end exports (YOLO26, YOLOv10), where it only prevents the same detection from appearing under multiple class labels (IoU=1.0 duplicates), not IoU-threshold suppression between distinct boxes. |
batch | int | 1 | Specifies export model batch inference size or the maximum number of images the exported model will process concurrently in predict mode. Formats without batch in their export arguments (Edge TPU, IMX500, DEEPX, Hailo, AMD Xilinx, NXP) export batch 1 and reject other values. |
device | str | None | Specifies the device for exporting: GPU (device=0), CPU (device=cpu), MPS for Apple silicon (device=mps), Huawei Ascend NPU (device=npu or device=npu:0), or DLA for NVIDIA Jetson (device=dla:0 or device=dla:1). TensorRT exports automatically use GPU, but TensorRT 11 does not support DLA. |
verbose | bool | False | Raises the TensorRT builder log to VERBOSE severity during format='engine' export. Other export formats ignore it. |
data | str | None | Path to the dataset YAML, essential for INT8 quantization calibration; classification instead takes a dataset directory or a built-in dataset name. If not specified with INT8 enabled, Ultralytics selects a task-specific calibration dataset where required, or falls back to the default dataset for the model task. A checkpoint trained with quantize=8 carries its own INT8 ranges and needs no calibration data. |
split | str | 'val' | Dataset split ('train', 'val', or 'test') used to build the INT8 quantization calibration dataloader from data. |
fraction | float, int, or list | 1.0 | Dataset subset used for INT8 calibration: a ratio, an image count, or [train, val, test] values. 1 means the full split, integers above 1 are image counts, and only the optional test entry accepts 0/0.0 to mean none. Two-item lists leave test full. |
Choose the format and settings that fit your deployment environment, hardware constraints, and performance targets to get the best balance between model size, speed, and accuracy.
Export Formats#
Available YOLO26 export formats are in the table below. You can export to any format using the format argument, e.g., format='onnx' or format='engine'. You can predict or validate directly on exported models, e.g., yolo predict model=yolo26n.onnx. Usage examples are shown for your model after export completes. Models can also be exported directly from the browser on Ultralytics Platform without any local setup.
| Format | format Argument | Model | Metadata | Arguments |
|---|---|---|---|---|
| PyTorch | - | yolo26n.pt | ✅ | - |
| TorchScript | torchscript | yolo26n.torchscript | ✅ | imgsz, quantize, dynamic, nms, batch, device |
| ONNX | onnx | yolo26n.onnx | ✅ | imgsz, quantize, dynamic, simplify, opset, nms, batch, data, fraction, device |
| OpenVINO | openvino | yolo26n_openvino_model/ | ✅ | imgsz, quantize, dynamic, nms, batch, data, fraction, device |
| TensorRT | engine | yolo26n.engine | ✅ | imgsz, quantize, dynamic, simplify, opset, workspace, nms, batch, data, fraction, device |
| CoreML | coreml | yolo26n.mlpackage | ✅ | imgsz, dynamic, quantize, nms, batch, device |
| Apple Core AI | coreai | yolo26n.aimodel | ✅ | imgsz, batch, quantize |
| TF SavedModel | saved_model | yolo26n_saved_model/ | ✅ | imgsz, quantize, opset, nms, batch, data, fraction, device |
| TF GraphDef | pb | yolo26n.pb | ❌ | imgsz, opset, batch, device |
| TF Edge TPU | edgetpu | yolo26n_edgetpu.tflite | ✅ | imgsz, quantize, opset, data, fraction, device |
| LiteRT | litert | yolo26n.tflite | ✅ | imgsz, quantize, batch, data, fraction, device |
| PaddlePaddle | paddle | yolo26n_paddle_model/ | ✅ | imgsz, batch, device |
| MNN | mnn | yolo26n.mnn | ✅ | imgsz, batch, dynamic, quantize, simplify, opset, nms, device |
| NCNN | ncnn | yolo26n_ncnn_model/ | ✅ | imgsz, quantize, batch, device |
| IMX500 | imx | yolo11n_imx_model/ | ✅ | imgsz, quantize, data, fraction, nms, device |
| RKNN | rknn | yolo26n_rknn_model/ | ✅ | imgsz, batch, name, quantize, simplify, opset, data, fraction, device |
| ExecuTorch | executorch | yolo26n_executorch_model/ | ✅ | imgsz, batch, device |
| Axelera | axelera | yolo26n_axelera_model/ | ✅ | imgsz, batch, quantize, data, fraction, device |
| DEEPX | deepx | yolo26n_deepx_model/ | ✅ | imgsz, quantize, simplify, opset, data, optimize, device |
| Qualcomm QNN | qnn | yolo26n_qnn.onnx | ✅ | imgsz, batch, name, quantize, simplify, opset, data, fraction, device |
| Hailo | hailo | yolo26n_hailo_model/ | ✅ | imgsz, name, quantize, data, fraction, simplify, conf, iou, device |
| Huawei Ascend | ascend | yolo26n_ascend_model/ | ✅ | imgsz, batch, name, quantize, opset, simplify, nms, device |
| AMD Xilinx | xilinx | yolo26n_xilinx_model/ | ✅ | imgsz, name, quantize, data, fraction, opset, simplify, device |
| NXP | nxp | yolo26n_nxp.tflite | ✅ | imgsz, quantize, data, fraction, device |
nms=None defaults to raw outputs for external NMS (YOLO26 keeps its NMS-free head on Axelera). Set nms=False to select an available NMS-free head; unsupported formats fall back to their native output path. The nms entries above identify formats that can embed NMS with nms=True.
Most formats need packages that are not installed with ultralytics. When one is missing, export installs it at runtime with uv or pip, and on Linux with apt for system packages such as Java for IMX. The Edge TPU compiler is downloaded without apt or sudo. To keep the environment fixed, for example in a container image, CI job, or production service, set YOLO_AUTOINSTALL=False. Export then still checks for the missing packages and reports them, but leaves the environment unchanged and fails until they are installed.
export YOLO_AUTOINSTALL=FalseQuantization Options#
Use the quantize argument to request the export precision. String values are case-insensitive, and Ultralytics canonicalizes accepted aliases before export:
| Request values | Canonical value | Meaning |
|---|---|---|
8, "8", "int8", "w8a8" | 8 | INT8 weights and activations |
16, "16", "fp16", "w16a16" | 16 | FP16 weights and activations |
32, "32", "fp32", "w32a32" | 32 | FP32 export; same as unset except CoreML NMS ML Programs, which default to FP16 |
"w8a16" | "w8a16" | INT8 weights with 16-bit activations (FP16; INT16 on LiteRT) |
"w8a32" | "w8a32" | INT8 weights with FP32 activations (LiteRT dynamic INT8, no calibration needed) |
The legacy half=True and int8=True flags are still accepted with deprecation warnings and forward to quantize=16 and quantize=8.
Not every export format supports every precision. Explicit quantize requests either produce that precision or fail before export:
| Format | FP32 (32/unset) | FP16 (16) | INT8 (8) | W8A16 ("w8a16") | Notes |
|---|---|---|---|---|---|
| PyTorch | ✅ | N/A | N/A | N/A | Native training/checkpoint format. |
| TorchScript | ✅ | ✅ GPU only | ❌ | ❌ | FP16 TorchScript export requires device=0; CPU export is FP32. |
| ONNX | ✅ | ✅ | ✅ | ❌ | INT8 uses ONNX Runtime static quantization and calibration data. |
| OpenVINO | ✅ | ✅ | ✅ | ❌ | INT8 uses NNCF post-training quantization. |
| TensorRT | ✅ | ✅ | ✅ | ❌ | INT8 needs representative calibration data. |
| CoreML | ✅¹ | ✅ | ✅ | ✅ | CoreML INT8 is weight quantization; W8A16 uses INT8 weights with FP16 activations. ¹Unset NMS ML Programs default to FP16, and segment/pose nms=True exports are always FP16. |
| Core AI | ✅ | ✅ | ❌ | ❌ | FP32 by default or an FP16 .aimodel asset with quantize=16; no INT8 path. |
| TF SavedModel | ✅ | ❌ | ✅ | ❌ | INT8 goes to .tflite files beside an FP32 SavedModel. |
| TF GraphDef | ✅ | ❌ | ❌ | ❌ | No export-time precision conversion. |
| Edge TPU | ❌ | ❌ | ✅ auto | ❌ | Edge TPU requires INT8; it is auto-enabled when unset. |
| LiteRT | ✅ | ❌ | ✅ | ✅ | Static INT8 (8) and "w8a16" (int8 weights + int16 activations) use calibration data; also supports "w8a32" dynamic INT8 (no calibration). quantize=16 is not a separate export; an FP32 model runs in FP16 at runtime via the GPU delegate. |
| PaddlePaddle | ✅ | ❌ | ❌ | ❌ | No export-time precision conversion. |
| MNN | ✅ | ✅ | ✅ | ❌ | INT8 is weight quantization through MNN conversion. |
| NCNN | ✅ | ✅ | ❌ | ❌ | Mobile/embedded runtime format. |
| IMX500 | ❌ | ❌ | ✅ auto | ❌ | IMX500 requires quantization; INT8 is auto-enabled when unset. |
| RKNN | ❌ | ✅ chip-dependent | ✅ | ❌ | RK3588/RK3576/RK3566/RK3568/RK3562/RK2118/RV1126B support FP16 or INT8; RV1103/RV1106 variants are INT8-only. |
| ExecuTorch | ✅ | ❌ | ❌ | ❌ | No export-time precision conversion. |
| Axelera | ❌ | ❌ | ✅ auto | ❌ | Axelera export requires INT8; it is auto-enabled when unset. |
| DEEPX | ❌ | ❌ | ✅ auto | ❌ | DEEPX export requires INT8; it is auto-enabled when unset. |
| Qualcomm QNN | ❌ | ❌ | ❌ | ✅ auto | QNN HTP export is fixed to INT8 weights with 16-bit activations. |
| Hailo | ❌ | ❌ | ✅ auto | ❌ | Hailo export requires INT8; it is auto-enabled when unset. |
| Huawei Ascend | ❌ | ✅ auto | ❌ | ❌ | Ascend AI Core convolutions accept only FP16/INT8 inputs, so ATC compiles FP16; it is auto-enabled when unset. |
| AMD Xilinx | ❌ | ❌ | ✅ auto | ❌ | AMD Xilinx export requires Vitis AI INT8 (VINT8); it is auto-enabled when unset. |
| NXP | ❌ | ❌ | ✅ auto | ❌ | NXP i.MX95 export requires INT8 with Neutron SDK 3.3.0; it is auto-enabled when unset. |
For INT8 and W8A16 exports, provide representative calibration data with data, such as data="coco8.yaml", unless the target integration documents a default or auto-enabled behavior. The LiteRT "w8a32" (dynamic INT8) scheme needs no calibration data.
Quantization-Aware Training#
The INT8 exports above are post-training quantization (PTQ): ranges are observed in a single calibration pass over data. Quantization-aware training (QAT) instead learns weights that tolerate INT8 by fine-tuning with fake-quantization in the loop, which recovers accuracy that calibration alone loses. Pass quantize=8 to train to fine-tune a pretrained checkpoint, then export it as usual:
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
model.train(
data="coco.yaml",
quantize=8,
epochs=5,
batch=64,
optimizer="AdamW",
lr0=0.00001,
lrf=0.1,
warmup_epochs=0.5,
cos_lr=True,
mosaic=0.0,
)
model.export(format="engine", quantize=8) # ranges travel with the checkpoint, no calibration data neededUse a small learning rate when fine-tuning a pretrained checkpoint. QAT can initially reduce accuracy, and its benefit over post-training quantization depends on the model, dataset, and training budget. Validate the exported model against both the original checkpoint and a post-training quantized export; fake-quantization scores during training do not establish deployment accuracy.
How much QAT is worth depends on how well the export backend's own calibration handles the model. The values below are mAP50-95 on COCO val2017, measured with TensorRT 10.16 engines at imgsz=640 and batch 1, where each QAT checkpoint was trained with epochs=20 patience=3:
| Model | FP32 engine | PTQ INT8 engine | QAT INT8 engine |
|---|---|---|---|
yolo26n | 0.4032 | 0.3934 | 0.3935 |
yolo26s | 0.4794 | 0.4412 | 0.4711 |
yolo26m | 0.5269 | 0.4696 | 0.5137 |
yolo26l | 0.5440 | 0.4889 | 0.5307 |
yolo26x | 0.5701 | 0.5138 | 0.5527 |
QAT costs 0.008 to 0.017 mAP50-95 against FP32 across the range, while post-training quantization costs 0.010 on yolo26n and 0.038 to 0.057 on the larger models. So QAT buys almost nothing on the smallest model, where calibration already works well, and 0.030 to 0.044 on the rest. Expect different figures on another dataset, export format, or TensorRT version, and measure your own.
QAT models require compile=False; ModelOpt's quantized modules do not support torch.compile.
The head's final output convolutions are deliberately left in float to limit INT8 accuracy loss; TensorRT enables FP16 mixed precision for its unquantized layers. QAT runs through NVIDIA TensorRT Model Optimizer, installed automatically on first use, and the resulting checkpoint needs it installed to load. Those ranges travel with the checkpoint and onnx and engine exports emit them as Q/DQ nodes; other formats read calibration instead and reject a QAT checkpoint.
What's Next#
Find your deployment target's integration guide — ONNX, TensorRT, CoreML, and more are on the full integrations list — for how to run the exported model.
FAQ#
Export a YOLO26 model to ONNX with either the Python API or the CLI:
Examplefrom ultralytics import YOLO # Load a model model = YOLO("yolo26n.pt") # load an official model model = YOLO("path/to/best.pt") # load a custom-trained model # Export the model model.export(format="onnx")For more details on the process, including advanced options like handling different input sizes, refer to the ONNX integration guide.
Using TensorRT for model export offers significant performance improvements on NVIDIA GPUs. YOLO26 models exported to TensorRT can achieve up to a 5x GPU speedup, making TensorRT well suited to real-time inference applications.
- Versatility: Optimize models for a specific hardware setup.
- Speed: Achieve faster inference through advanced optimizations.
- Compatibility: Integrate smoothly with NVIDIA hardware.
To learn more about integrating TensorRT, see the TensorRT integration guide.
INT8 quantization compresses the model and speeds up inference, especially on edge devices. Enable it with
quantize=8:Examplefrom ultralytics import YOLO model = YOLO("yolo26n.pt") # Load a model model.export(format="onnx", quantize=8, data="coco8.yaml")INT8 quantization can be applied to formats such as ONNX, TensorRT, OpenVINO, CoreML, Rockchip RKNN, and AMD Xilinx. For optimal quantization results, provide a representative dataset using the
dataparameter. See Quantization Options for acceptedquantizevalues and supported formats.Dynamic input size allows the exported model to handle varying image dimensions, providing flexibility and optimizing processing efficiency for different use cases. When exporting to formats like ONNX or TensorRT, enabling dynamic input size lets the model accept different input shapes.
To enable this feature, use the
dynamic=Trueflag during export:Examplefrom ultralytics import YOLO model = YOLO("yolo26n.pt") model.export(format="onnx", dynamic=True)Dynamic input sizing is particularly useful for applications where input dimensions may vary, such as video processing or when handling images from different sources.
A dynamic export loaded with
YOLO()predicts and validates at its exportimgsz(the longer side of a non-square export), as a PyTorch model uses its trainingimgsz. Passimgszto run it at another size.PyTorch models and dynamic exports use minimum-rectangle padding by default, while static exports pad to the full
imgsz, so detections near the confidence threshold can differ. Userect=Falsefor native inference to match a static export, or export withdynamic=Truewhere supported.These export arguments have the most impact on model performance:
format:The target format for the exported model (e.g.,onnx,torchscript,saved_model).imgsz:Desired image size for the model input (e.g.,640or(height, width)).quantize:Quantization precision, such as8/"int8",16/"fp16",32/"fp32", or the mixed weight/activation schemes"w8a16"and"w8a32"(LiteRT dynamic INT8) on supported formats. See Quantization Options.dynamic:Accepts variable input sizes on formats that support dynamic shapes, such as ONNX, OpenVINO, and TensorRT.nms:Selects raw outputs for external NMS (None; YOLO26 keeps its NMS-free head on Axelera), embedded NMS (True), or the NMS-free head (False).device:Device used to trace the model during export, such ascpuor0for the first CUDA GPU; FP16 TorchScript requires a GPU.
For deployment on specific hardware platforms, consider using specialized export formats like TensorRT for NVIDIA GPUs, CoreML for Apple devices, or Edge TPU for Google Coral devices.
When you export a YOLO model to formats like ONNX or TensorRT, the output tensor structure depends on the model task. Understanding these outputs is important for custom inference implementations.
For YOLO26 detection models (e.g.,
yolo26n.pt) exported withnms=False, supported formats produce NMS-free output shaped like(batch_size, max_detections, 6)with[x1, y1, x2, y2, confidence, class_id]values. With the defaultmax_det=300, this is commonly(batch_size, 300, 6). Some constrained formats automatically fall back to the traditional output layout when end-to-end operators are unsupported.By default (
nms=None), detection models including YOLO26 export raw one-to-many predictions (YOLO26 keeps its NMS-free head on Axelera). The output is typically a single tensor shaped like(batch_size, 4 + num_classes, num_predictions)where the channels represent box coordinates plus per-class scores, andnum_predictionsdepends on the export input resolution (and can be dynamic). The End-to-End Detection guide covers which formats keep the end-to-end output.For segmentation models (e.g.,
yolo26n-seg.pt), you'll typically get two outputs: the first tensor shaped like(batch_size, 4 + num_classes + mask_dim, num_predictions)(boxes, class scores, and mask coefficients), and the second tensor shaped like(batch_size, mask_dim, proto_h, proto_w)containing mask prototypes used with the coefficients to generate instance masks. Sizes depend on the export input resolution (and can be dynamic).For pose models (e.g.,
yolo26n-pose.pt), the output tensor is typically shaped like(batch_size, 4 + num_classes + keypoint_dims, num_predictions), wherekeypoint_dimsdepends on the pose specification (e.g., number of keypoints and whether confidence is included), andnum_predictionsdepends on the export input resolution (and can be dynamic).The examples in the ONNX inference examples demonstrate how to process these outputs for each model type.
Ultralytics does not currently provide a dedicated C++ inference API for YOLO models. For C++ deployments, export the model to a runtime format such as ONNX, TensorRT, TorchScript, or MNN, then load the exported artifact with that runtime's native C++ API.
For example, export a detection model with
yolo export model=yolo26n.pt format=onnxand run the.onnxfile with ONNX Runtime C++, or export withformat=engineand run the TensorRT engine from a TensorRT C++ application. When you use custom C++ post-processing, match the output tensor layout for your task and export settings; default YOLO26 detection exports return raw prediction tensors that require external NMS. Export withnms=Falsefor NMS-free detections shaped(batch, max_det, 6), ornms=Trueto embed NMS in supported formats.When exporting with
quantize=16(FP16) orquantize=8(INT8), most tensors are converted to lower precision to reduce model size and improve performance. However, whennms=Falseis enabled, post-processing (including class indices) is embedded directly in the exported graph.The
output0tensor contains class indices, which are internally represented as floating-point values. FP16 cannot reliably represent integer values above 2048 due to its limited mantissa precision. To avoid potential precision loss or incorrect class IDs,output0is intentionally kept in FP32.If full FP16 outputs are required, export with
nms=Noneon a GPU and perform post-processing externally. FP16 ONNX exports on CPU keep FP32 inputs and outputs regardless, converting only the internal graph.
Comments447
Ask a question, share your results, or help someone else.
yubaobao-GPU
你好,请问为什么我转onnx的时候会显示end2end参数非法 (ywh_26) root@ai-avcon:/data/ywh_folder/yolo/yolo26# python to_onnx.py WARNING ⚠️ Ultralytics settings reset to default values. This may be due to a possible problem with your settings or a recent ultralytics package update. View Ultralytics Settings with 'yolo settings' or at '/root/.config/Ultralytics/settings.json' Update Settings with 'yolo settings key=value', i.e. 'yolo settings runs_dir=path/to/dir'. For help see https://docs.ultralytics.com/quickstart/#ultralytics-settings. Traceback (most recent call last): File "/data/ywh_folder/yolo/yolo26/to_onnx.py", line 12, in model.export( File "/data/ywh_folder/yolo/yolo26/ultralytics/engine/model.py", line 710, in export return Exporter(overrides=args, _callbacks=self.callbacks)(model=self.model) File "/data/ywh_folder/yolo/yolo26/ultralytics/engine/exporter.py", line 312, in init self.args = get_cfg(cfg, overrides) File "/data/ywh_folder/yolo/yolo26/ultralytics/cfg/init.py", line 308, in get_cfg check_dict_alignment(cfg, overrides) File "/data/ywh_folder/yolo/yolo26/ultralytics/cfg/init.py", line 505, in check_dict_alignment raise SyntaxError(string + CLI_HELP_MSG) from e SyntaxError: 'end2end' is not a valid YOLO argument.
我是用的8.4.6版本的ultralytics
1
Glenn JocherUltralyticsultralytics==8.4.6还不支持end2end这个导出参数(它是给支持 NMS-free 的新模型/新版本用的),所以你这边要么把model.export()里的end2end=...去掉,要么升级到最新 Ultralytics;另外你的报错路径显示实际导入的是本地仓库.../yolo26/ultralytics,建议先跑一次yolo checks并把文本输出贴上来确认是否存在多套安装/路径冲突(参数列表可参考 Model.export() 参考文档)。pip install -U ultralytics yolo checks
qcname
您好,使用.pt和导出为.onnx进行yolov8模型的图片中目标检测时,参数设置一致,但是最终检测框数量,位置不完全一致。比如.onnx比.pt多画一个或者检测到.pt检测不出来的类别,请问是什么问题导致的呢?
1
Paula DerrengerUltralytics@nacenace 您好,
感谢您提出这个问题!在导出模型时遇到检测结果不一致的情况确实令人困惑。以下是一些可能的原因和解决方法:
-
版本一致性:请确保您使用的是最新版本的
torch和ultralytics。您可以通过以下命令进行升级:pip install --upgrade torch ultralytics -
模型导出参数:导出为 ONNX 时,某些参数可能会影响模型的行为。请确保在导出时使用了适当的参数,例如
dynamic、simplify等。以下是一个导出为 ONNX 的示例:from ultralytics import YOLO # 加载模型 model = YOLO("path/to/best.pt") # 导出模型 model.export(format="onnx", dynamic=True, simplify=True) -
推理设置:在进行推理时,确保使用相同的图像尺寸和其他推理参数。以下是一个推理示例:
# 使用 .pt 模型进行推理 results_pt = model.predict(source="path/to/image.jpg", imgsz=640) # 使用 .onnx 模型进行推理 model_onnx = YOLO("path/to/model.onnx") results_onnx = model_onnx.predict(source="path/to/image.jpg", imgsz=640) -
最小可复现示例:为了更好地帮助您解决问题,请提供一个最小可复现的代码示例。您可以参考我们的最小可复现示例指南来创建一个示例。
请尝试以上建议,如果问题仍然存在,请提供更多详细信息和代码示例,以便我们进一步调查。
希望这些信息对您有所帮助!如果有任何其他问题,请随时告知。
祝好, Ultralytics 团队
-
Lbj4175
你好,我和你有相同的问题,问题解决了吗
qcname
没有
Glenn JocherUltralytics您好,感谢您的反馈。导出为不同格式(如ONNX)时,检测结果可能会有所不同,通常是由于模型转换过程中精度损失或推理引擎差异导致的。建议您确保使用最新版本的Ultralytics和相关库,并尝试调整导出参数,如
dynamic=True或half=True。更多详情请参考导出文档。
Ibraheem-Ahmad
Hello! Would anyone be able to tell me why this code does not work: model.export(format=='onnx', int8 = True, dyamic = True, imgsz = (width,height))
the error I get is "TypeError: Model.export() takes 1 positional argument but 2 were given"
1
Glenn JocherUltralytics@Ibraheem-Ahmad hello! It looks like there's a small typo in your code that's causing the issue. In Python, when you're calling a function and passing arguments, you should use
=for assignment rather than==, which is used for comparison. Also, there's a typo indyamic, it should bedynamic. Here's the corrected line of code:model.export(format='onnx', int8=True, dynamic=True, imgsz=(width, height))This should work without any errors. If you have any more questions or run into issues, feel free to ask. Happy coding! 😊
Aisha-Hassan1
How can I path pictures and how many pictures?
Glenn JocherUltralytics@Aisha-Hassan1 hey there! 🌟 To pass multiple pictures for processing, you can use a directory, list, or wildcard as your
source. For example:# For a directory full of images model.predict(source='path/to/images/') # For specific images model.predict(source=['path/to/image1.jpg', 'path/to/image2.jpg']) # Using a wildcard model.predict(source='path/to/images/*.jpg')As for how many pictures, there's no strict limit—it depends on your system's capabilities. Just ensure your images comply with the model's input size, which you can adjust with the
imgszparameter if necessary. Happy coding! 😊1Aisha-Hassan1
When I don't put batch_size, the result is batch_size=1 .... code => [ Ultralytics YOLOv8.1.29 🚀 Python-3.11.5 torch-2.2.1+cpu CPU (Intel Core(TM) i5-3320M 2.60GHz) YOLOv8n summary (fused): 168 layers, 3151904 parameters, 0 gradients, 8.7 GFLOPs
PyTorch: starting from 'yolov8n.pt' with input shape (1, 3, 640, 640) BCHW and output shape(s) (1, 84, 8400) (6.2 MB)
ONNX: starting export with onnx 1.15.0 opset 17... ONNX: export success ✅ 2.1s, saved as 'yolov8n.onnx' (12.1 MB)
Export complete (5.9s) Results saved to C:\Users\shosho Predict: yolo predict task=detect model=yolov8n.onnx imgsz=640 int8 Validate: yolo val task=detect model=yolov8n.onnx imgsz=640 data=coco.yaml int8 Visualize: https://netron.app
] .........batch_size = 4 model.export(format='onnx', int8=True, dynamic=True, batch=batch_size) res=>[Ultralytics YOLOv8.1.29 🚀 Python-3.11.5 torch-2.2.1+cpu CPU (Intel Core(TM) i5-3320M 2.60GHz) YOLOv8n summary (fused): 168 layers, 3151904 parameters, 0 gradients, 8.7 GFLOPs
PyTorch: starting from 'yolov8n.pt' with input shape (4, 3, 640, 640) BCHW and output shape(s) (4, 84, 8400) (6.2 MB)
ONNX: starting export with onnx 1.15.0 opset 17... ONNX: export success ✅ 3.6s, saved as 'yolov8n.onnx' (12.1 MB)
Export complete (11.2s) Results saved to C:\Users\shosho Predict: yolo predict task=detect model=yolov8n.onnx imgsz=640 int8 Validate: yolo val task=detect model=yolov8n.onnx imgsz=640 data=coco.yaml int8 Visualize: https://netron.app 'yolov8n.onnx'] Is this the number of photos I should enter?
Aisha-Hassan1
import cv2 from ultralytics import YOLO
model = YOLO('yolov8n.pt') model.export(format='onnx', int8=True, dynamic=True) predicted_images = model.predict(source='G:/img') for i, result in enumerate(predicted_images): print(result) image = result.orig_img save_path = f'predicted_image_{i}.jpg'
cv2.imwrite(save_path, image)
print(f"Done{save_path}")The code works for me and saves the images, but I have two questions
1- How will i deal with an onnx file with JS and send it an array of images? 2- I want to export yolov5n-seg.pt to onnx to put a mask on the images?
Glenn JocherUltralytics@Aisha-Hassan1 hey there! 😊
- To deal with an ONNX file in JS and send it an array of images, you can use onnxjs for browser environments or onnxruntime-node for Node.js. Here’s an example using onnxjs:
async function runModel(inputImages) { const session = new onnx.InferenceSession(); await session.loadModel("path/to/your/model.onnx"); const inputTensors = inputImages.map(image => // convert your images to tensors); // Assuming you're working with one input named 'input' const feeds = { input: inputTensors }; const results = await session.run(feeds); return results; }- For exporting
yolov5n-seg.ptto ONNX with a mask, ensure your model supports segmentation tasks, then follow similar steps to exporting a detection model but make sure the output includes the segmentation masks. Your export code seems fine, but replaceyolov8n.ptwithyolov5n-seg.pt. Check model compatibility and output processing as per your needs!
If you need any more guidance, don't hesitate to ask. Have fun coding! ✨
1Aisha-Hassan1
The yolov5n-seg.pt export part show this error........[ ModuleNotFoundError Traceback (most recent call last) File G:\anaconda3\Lib\site-packages\ultralytics\nn\tasks.py:714, in torch_safe_load(weight) 707 with temporary_modules( 708 { 709 "ultralytics.yolo.utils": "ultralytics.utils", (...) 712 } 713 ): # for legacy 8.0 Classify and Pose models --> 714 ckpt = torch.load(file, map_location="cpu") 716 except ModuleNotFoundError as e: # e.name is missing module name
File G:\anaconda3\Lib\site-packages\torch\serialization.py:1026, in load(f, map_location, pickle_module, weights_only, mmap, **pickle_load_args) 1025 raise pickle.UnpicklingError(UNSAFE_MESSAGE + str(e)) from None -> 1026 return _load(opened_zipfile, 1027 map_location, 1028 pickle_module, 1029 overall_storage=overall_storage, 1030 **pickle_load_args) 1031 if mmap:
File G:\anaconda3\Lib\site-packages\torch\serialization.py:1438, in _load(zip_file, map_location, pickle_module, pickle_file, overall_storage, **pickle_load_args) 1437 unpickler.persistent_load = persistent_load -> 1438 result = unpickler.load() 1440 torch._utils._validate_loaded_sparse_tensors()
File G:\anaconda3\Lib\site-packages\torch\serialization.py:1431, in _load..UnpicklerWrapper.find_class(self, mod_name, name) 1430 mod_name = load_module_mapping.get(mod_name, mod_name) -> 1431 return super().find_class(mod_name, name)
ModuleNotFoundError: No module named 'models'
The above exception was the direct cause of the following exception:
TypeError Traceback (most recent call last) Cell In[2], line 1 ----> 1 model = YOLO('yolov5n-seg.pt')
File G:\anaconda3\Lib\site-packages\ultralytics\models\yolo\model.py:23, in YOLO.init(self, model, task, verbose) 20 self.dict = new_instance.dict 21 else: 22 # Continue with default YOLO initialization ---> 23 super().init(model=model, task=task, verbose=verbose)
File G:\anaconda3\Lib\site-packages\ultralytics\engine\model.py:142, in Model.init(self, model, task, verbose) 140 self._new(model, task=task, verbose=verbose) 141 else: --> 142 self._load(model, task=task) 144 self.model_name = model
File G:\anaconda3\Lib\site-packages\ultralytics\engine\model.py:229, in Model._load(self, weights, task) 227 suffix = Path(weights).suffix 228 if suffix == ".pt": --> 229 self.model, self.ckpt = attempt_load_one_weight(weights) 230 self.task = self.model.args["task"] 231 self.overrides = self.model.args = self._reset_ckpt_args(self.model.args)
File G:\anaconda3\Lib\site-packages\ultralytics\nn\tasks.py:788, in attempt_load_one_weight(weight, device, inplace, fuse) 786 def attempt_load_one_weight(weight, device=None, inplace=True, fuse=False): 787 """Loads a single model weights.""" --> 788 ckpt, weight = torch_safe_load(weight) # load ckpt 789 args = {**DEFAULT_CFG_DICT, **(ckpt.get("train_args", {}))} # combine model and default args, preferring model args 790 model = (ckpt.get("ema") or ckpt["model"]).to(device).float() # FP32 model
File G:\anaconda3\Lib\site-packages\ultralytics\nn\tasks.py:718, in torch_safe_load(weight) 716 except ModuleNotFoundError as e: # e.name is missing module name 717 if e.name == "models": --> 718 raise TypeError( 719 emojis( 720 f"ERROR ❌️ {weight} appears to be an Ultralytics YOLOv5 model originally trained " 721 f"with https://github.com/ultralytics/yolov5.\nThis model is NOT forwards compatible with " 722 f"YOLOv8 at https://github.com/ultralytics/ultralytics." 723 f"\nRecommend fixes are to train a new model using the latest 'ultralytics' package or to " 724 f"run a command with an official YOLOv8 model, i.e. 'yolo predict model=yolov8n.pt'" 725 ) 726 ) from e 727 LOGGER.warning( 728 f"WARNING ⚠️ {weight} appears to require '{e.name}', which is not in ultralytics requirements." 729 f"\nAutoInstall will run now for '{e.name}' but this feature will be removed in the future." 730 f"\nRecommend fixes are to train a new model using the latest 'ultralytics' package or to " 731 f"run a command with an official YOLOv8 model, i.e. 'yolo predict model=yolov8n.pt'" 732 ) 733 check_requirements(e.name) # install missing module
TypeError: ERROR yolov5n-seg.pt appears to be an Ultralytics YOLOv5 model originally trained with https://github.com/ultralytics/yolov5. This model is NOT forwards compatible with YOLOv8 at https://github.com/ultralytics/ultralytics. Recommend fixes are to train a new model using the latest 'ultralytics' package or to run a command with an official YOLOv8 model, i.e. 'yolo predict model=yolov8n.pt'
] part of the code in JS ...[
] show erro .........Access to fetch at 'file:///G:/pg_betch/yolov8n.onnx' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, isolated-app, chrome-extension, chrome, https, chrome-untrusted. session.ts:61GET file:///G:/pg_betch/yolov8n.onnx net::ERR_FAILED(anonymous) @ session.ts:61 (anonymous) @ onnx.min.js:14 (anonymous) @ onnx.min.js:14 a @ onnx.min.js:14 Promise.then (async) s @ onnx.min.js:14 (anonymous) @ onnx.min.js:14 r @ onnx.min.js:14 (anonymous) @ session.ts:48 t.event @ instrument.ts:294 (anonymous) @ session.ts:48 (anonymous) @ onnx.min.js:14 (anonymous) @ onnx.min.js:14 (anonymous) @ onnx.min.js:14 r @ onnx.min.js:14 e.loadModel @ onnx.min.js:14 t.loadModel @ inference-session-impl.ts:27 runModel @ index.html:11 (anonymous) @ index.html:27 session.ts:61
Uncaught (in promise) TypeError: Failed to fetch at e.<anonymous> (session.ts:61:34) at onnx.min.js:14:255680 at Object.next (onnx.min.js:14:255785) at a (onnx.min.js:14:254499)(anonymous) @ session.ts:61 (anonymous) @ onnx.min.js:14 (anonymous) @ onnx.min.js:14 a @ onnx.min.js:14 Promise.then (async) (anonymous) @ index.html:27
Glenn JocherUltralyticsHey there! It looks like you're encountering two different issues here:
-
Using an ONNX model with JavaScript: For running ONNX models in a browser with JavaScript, you're on the right track with onnx.js. However, loading local files directly can lead to CORS policy violations, as seen in your error. To fix this, serve your ONNX model from a server or use a cloud storage URL with proper CORS settings. Ensure your server or cloud storage is configured to allow such requests.
-
Exporting YOLOv5n-seg.pt to ONNX: The error suggests that the file
yolov5n-seg.ptmight be confused as a YOLOv5 model and you're trying to load it using YOLOv8, which leads to compatibility issues. Ifyolov5n-seg.ptis indeed a YOLOv5 model, ensure you're using the correct toolchain for export. For segmentation models with YOLOv8 (assumingyolov8n-seg.ptexists and it's what you meant), the export command you've used seems correct. Make sure you're within the Ultralytics ecosystem for YOLOv8 and its segmentation models, and check if there's a typo in the filename or a version mismatch. Correct model paths and compatible Ultralytics YOLO versions are crucial.
For working with segmentation models and applying masks to images post-export, you'll typically handle the output tensors from the ONNX model to extract segmentation masks and overlay them on the original images. This step will heavily depend on the output structure of your specific model.
Hope that helps! Keep experimenting, and feel free to reach out if you hit more snags. 😊
1-
Aisha-Hassan1
Can you help me how to handle the output tensors from the ONNX model to extract segmentation masks and overlay them on the original images ?
Glenn JocherUltralyticsHey there! 🙌 To handle output tensors from an ONNX model for segmentation tasks, you'll typically:
-
Run the Model: First, feed your input image to the ONNX model using your preferred ONNX runtime environment. This step returns the output tensors.
-
Process Output Tensors: For segmentation models, the output tensor usually represents either a pixel-wise class prediction or a set of masks for each detected object. You'll need to decode these tensors to get the segmentation masks. The exact processing will depend on your model's output format.
-
Overlay Masks on Original Images: Once you have the segmentation masks, you can overlay them on your original images. Here's a quick example in Python, assuming you have a mask:
import cv2 import numpy as np # Assuming 'image' is your original image and 'mask' is the segmentation mask # Ensure the mask is a binary mask (0 or 1) where 1 represents the segmented object overlay = cv2.addWeighted(image, 1, np.dstack((mask, mask, mask)) * 255, 0.5, 0) cv2.imwrite('segmented_image.jpg', overlay)For exporting
yolov5n-seg.ptor similar models to ONNX, you seem to have encountered an incompatibility issue indicating that you might be trying to load a YOLOv5 model with a YOLOv8 setup. Ensure you're using the proper version and tools for your specific YOLO model. YOLOv8 now has its dedicated ecosystem and might not directly support models trained with previous versions without conversion or specific handling.If YOLOv5 segmentation is what you need and you're dealing with
yolov5n-seg.pt, consider checking the YOLOv5 documentation for the precise export guidance. For segmentation tasks, you might need to adjust your approach tailored to the model's specific output layer design.Hope this helps! Let me know if there's anything else I can do for you. 😊
-
Aisha-Hassan1
Thank you very much for your help 1-Using an ONNX model with JavaScript:
Document<script> const labels = [ "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush", ]; const modelName = "yolov8n-seg.onnx"; const modelInputShape = [4, 3, 640, 640]; let mySession; const useState = (defaultValue) => { let value = defaultValue; const getValue = () => value; const setValue = (newValue) => (value = newValue); return [getValue, setValue]; }; const numClass = labels.length; const [session, setSession] = useState(null); cv["onRuntimeInitialized"] = async () => { // create session const [yolov8] = await Promise.all([ ort.InferenceSession.create(modelName), ]); mySession = setSession({ net: yolov8 }); const inputImages = [ "img/bb.jpg", "img/iam.jpg" ]; const inputTensors = await Promise.all(inputImages.map(async (imageUrl) => { const response = await fetch(imageUrl); if (!response.ok) { throw new Error(`Failed to fetch image: ${imageUrl}`); } const blob = await response.blob(); const image = await cv.imreadAsync(blob); const tensor = cv.tensorFromImageData(image); image.delete(); return tensor; })); // Assuming you're working with one input named 'input' const feeds = { input: inputTensors }; const results = await yolov8.run(feeds); console.log(results); // Assuming you need to handle the results here // Handle results... }; </script>problem of code In partial convert your images to tensors
Do you have a solution to the problem?
Glenn JocherUltralytics@Aisha-Hassan1 hey there! Thanks for reaching out 🌟. It looks like you're having a bit of trouble converting images to tensors in your JavaScript code while working with an ONNX model.
For the conversion part, using OpenCV.js to convert images to tensors might not directly align with the expected input format for ONNX models. Instead, you'll typically need to preprocess the images into a format that matches the expected input tensor of your ONNX model, including resizing images and normalizing pixel values if required.
A simplified approach (without OpenCV.js) could involve using standard JavaScript or browser APIs to load and preprocess your images before converting them into tensors. Unfortunately, detailed code for image preprocessing highly depends on the specific requirements of your ONNX model, such as input dimensions and pixel-value scaling.
Regarding overlaying segmentation masks (like from
yolov5n-seg.ptexported as ONNX) onto images using JavaScript:- Once you have your segmentation output from the model, it'll typically be a tensor where each value corresponds to a class prediction per pixel or a probability distribution across classes for each pixel.
- Convert this segmentation mask tensor back into an image format, applying any necessary thresholding to identify your classes of interest.
- Overlay this processed mask onto your original image. You can achieve this by manipulating the DOM directly in JavaScript or using canvas operations to blend images.
Both the conversion and overlay steps are somewhat intricate and depend heavily on the details of your model's output format as well as the web environment you're working in (pure JavaScript in the browser, Node.js, etc.).
For precise assistance, we might need more details on the output format of your segmentation model and the specific environment you're working in. Meanwhile, the Ultralytics Docs and YOLOv8's export mode provide a great starting point for deploying models efficiently across various platforms 🚀.
Hope this helps a bit! Keep exploring and don't hesitate to share more details or ask further questions. Happy coding!
Aisha-Hassan1
I would like answers to two other questions, please
1- If I want to enter an array of images in js to use batch, should I export onnx this way ? model.export(format='onnx', int8=True, dynamic=True) or Do I have to limit the number of photos like this? model.export(format='onnx', int8=True, dynamic=True, batch =number of images)
2- I want to run onnx in the GPU, what should I do?
Glenn JocherUltralyticsHey there! 😀 Glad you're exploring YOLOv8's capabilities. Let's dive into your questions:
-
Array of Images for Batch Inference in JS:
- Utilizing
dynamic=Trueduring export is the way to go if you plan on varying the batch size dynamically. There's no need to specify the batch size at export time for ONNX models, asdynamic=Trueenables the model to handle variable batch sizes. So, your first export command is spot on:model.export(format='onnx', int8=True, dynamic=True) - This setup allows you to feed different batch sizes at runtime without having to re-export the model for each specific batch size.
- Utilizing
-
Running ONNX on GPU:
- To run ONNX models on the GPU, ensure you have an ONNX runtime that supports GPU inference, such as ONNX Runtime-GPU. When initializing your inference session in your code, specify the GPU device. Here's a quick example if you're using Python:
import onnxruntime as ort # Specify the GPU device ort_session = ort.InferenceSession("your_model.onnx", providers=['CUDAExecutionProvider']) # Now you can run inference with ort_session and it should use the GPU - For JavaScript, the availability of GPU inference might be limited and typically runs on the CPU. ONNX.js primarily supports WebGL for some level of GPU acceleration in the browser, but true GPU computing might not be feasible directly in JS as it depends on the browser's capabilities and the onnxruntime-web package's support.
- To run ONNX models on the GPU, ensure you have an ONNX runtime that supports GPU inference, such as ONNX Runtime-GPU. When initializing your inference session in your code, specify the GPU device. Here's a quick example if you're using Python:
I hope this clears up your questions! Keep experimenting with YOLOv8, and don't hesitate to reach out if you have more questions. Happy coding! 🚀
-
Aisha-Hassan1
thank you so much code
 <script> var inputTensors=[]; const modelInputShape = [1, 3, 640, 640]; const divStride = (stride, width, height) => { if (width % stride !== 0) { if (width % stride >= stride / 2) width = (Math.floor(width / stride) + 1) * stride; else width = Math.floor(width / stride) * stride; } if (height % stride !== 0) { if (height % stride >= stride / 2) height = (Math.floor(height / stride) + 1) * stride; else height = Math.floor(height / stride) * stride; } return [width, height]; }; const preprocessing = (source, modelWidth, modelHeight, stride = 32) => { //const mat = cv.imread(source); // read from img tag const mat = cv.imread(document.getElementById(source)); const matC3 = new cv.Mat(mat.rows, mat.cols, cv.CV_8UC3); // new image matrix cv.cvtColor(mat, matC3, cv.COLOR_RGBA2BGR); // RGBA to BGR const [w, h] = divStride(stride, matC3.cols, matC3.rows); cv.resize(matC3, matC3, new cv.Size(w, h)); // padding image to [n x n] dim const maxSize = Math.max(matC3.rows, matC3.cols); // get max size from width and height const xPad = maxSize - matC3.cols, // set xPadding xRatio = maxSize / matC3.cols; // set xRatio const yPad = maxSize - matC3.rows, // set yPadding yRatio = maxSize / matC3.rows; // set yRatio const matPad = new cv.Mat(); // new mat for padded image cv.copyMakeBorder( matC3, matPad, 0, yPad, 0, xPad, cv.BORDER_CONSTANT, [0, 0, 0, 255] ); // padding black const input = cv.blobFromImage( matPad, 1 / 255.0, // normalize new cv.Size(modelWidth, modelHeight), // resize to model input size new cv.Scalar(0, 0, 0), true, // swapRB false // crop ); // preprocessing image matrix // release mat opencv mat.delete(); matC3.delete(); matPad.delete(); return [input, xRatio, yRatio]; }; const inputImages = [ "image1", "image2" ]; async function runModel(inputImages) { const [yolov8] = await Promise.all([ ort.InferenceSession.create("yolov8n-seg.onnx") ]); const [modelWidth, modelHeight] = modelInputShape.slice(2); for(let i=0 ; i<inputImages.length; i++){ const [input, xRatio, yRatio] = preprocessing( inputImages[i], modelWidth, modelHeight ); const tensor = new ort.Tensor("float32", input.data32F, modelInputShape); inputTensors[i]=tensor; console.log(inputTensors) } const { output0, output1 } = await yolov8.run({images:inputTensors}); console.log(output0); }; runModel(inputImages) </script>In the runModel function, I send it an array of images, and it makes an error in part
const { output0, output1 } = await yolov8.run({images:inputTensors})
Because inputTensors is an array
This is the form of error Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'byteLength') at t.run (wasm-core-impl.ts:219:31) at t.run (proxy-wrapper.ts:215:17) at t.OnnxruntimeWebAssemblySessionHandler.run (session-handler.ts:84:15) at i.run (inference-session-impl.js:94:44) at runModel (main.html:94:55) t.run@wasm-core-impl.ts:219 t.run@proxy-wrapper.ts:215 run@session-handler.ts:84 run@inference-session-impl.js:94 runModel@main.html:94 await in runModel (async) (anonymous)@main.html:97
What is the solution to enter an array of images into the model?
Aisha-Hassan1
When using a array of objects, the first is taken only object
Glenn JocherUltralyticsHey there! Thanks for bringing this to our attention 🌟. When using an array of objects for inference with YOLOv8 in JavaScript, you'd typically batch the input images before sending them to the model. If you find that only the first object in your array is being processed, it might be related to how you're structuring the input data for the ONNX model.
For batch processing, ensure all your images are preprocessed (resized and normalized) correctly and then stacked into a single tensor that matches the ONNX model's expected input shape. The shape for a batch of images usually follows the format
[batch_size, channels, height, width]. It sounds like you might need to adjust how you're constructinginputTensorsto fit this expectation.Regarding running ONNX on a GPU, note that ONNX.js primarily targets web environments where direct access to the GPU through Web APIs (e.g., WebGL) might not fully leverage all GPU capabilities like a desktop environment would. If you're using ONNX in a server-side JavaScript environment (like with Node.js and onnxruntime-node), specifying the GPU for inference would depend on the capabilities of your specific backend setup and the ONNX runtime you're using. Onnxruntime-web currently doesn't offer direct control over executing models on GPU vs. CPU—it automatically utilizes available hardware acceleration like WebGL.
Here's a simplified structure for how you might handle batching:
async function runBatchModel(session, inputTensors) { // Ensure inputTensors is a batched tensor of the right shape const results = await session.run({input: inputTensors}); // Process results... }Remember to adjust the
runBatchModelfunction based on how your specific model expects inputs. Happy coding and don't hesitate to reach out if you have more questions! 😊Aisha-Hassan1
How to handle inputTensors in array of images?
Aisha-Hassan1
what is the datatybe of inputTensors
Glenn JocherUltralytics@Aisha-Hassan1 hey there! 🌟 The
inputTensorsis expected to be an array ofort.Tensorobjects where each tensor represents an image that has been correctly processed (resized, normalized) to match the input shape that your model expects.For instance, if you're preprocessing images for batch inference, each
ort.Tensorwould hold image data shaped according to the model's input specifications, typically[batch_size, channels, height, width]. If your model expects a single image of shape[1, 3, 640, 640], preprocess each image accordingly, and then stack them into an array.Here's a quick example on how you might prepare a single image:
const imageTensor = new ort.Tensor("float32", processedImageData, [1, 3, height, width]);And when you have multiple images prepared as tensors (
imageTensor1,imageTensor2, ...), you can put them in an array:const inputTensors = [imageTensor1, imageTensor2];Make sure each tensor in
inputTensorsfollows the model's expected input shape. Keep up the great work with ONNX models, and happy coding! 😄Aisha-Hassan1
erro ... wasm-core-impl.ts:219 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'byteLength') at t.run (wasm-core-impl.ts:219:31) at t.run (proxy-wrapper.ts:215:17) at t.OnnxruntimeWebAssemblySessionHandler.run (session-handler.ts:84:15) at i.run (inference-session-impl.js:94:44) at runModel (main.html:96:55) ........
when inputTensors => array const inputTensors = [imageTensor1, imageTensor2];
Aisha-Hassan1
[batch_size, channels, height, width]. If your model expects not a single image of shape ???
Glenn JocherUltralyticsHey there! 👋 When converting a YOLOv8 model for batch processing, you generally don't need to specify the batch size during export, especially with dynamic batching enabled. 🔄 Your export command:
model.export(format='onnx', int8=True, dynamic=True)is perfectly fine for creating an ONNX model that can handle arrays of images. Just ensure your data is prepped correctly when making actual predictions! 📊
For GPU acceleration with ONNX, leveraging frameworks like ONNX Runtime with CUDA support would be the way to go! 🔥 Make sure your environment is set up for GPU use, and you're specifying the execution provider accordingly.
Feel free to check out more on dynamic batching and ONNX export on the Ultralytics docs page! Hope this helps, and happy coding! 🚀
Aisha-Hassan1
code
const inputs = { images: [inputTensors[0], inputTensors[1]] };
const { output0, output1 } = await yolov8.run(inputs);
erro
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'byteLength') at t.run (wasm-core-impl.ts:219:31) at t.run (proxy-wrapper.ts:215:17) at t.OnnxruntimeWebAssemblySessionHandler.run (session-handler.ts:84:15) at i.run (inference-session-impl.js:94:44) at runModel (main.html:107:53)
Glenn JocherUltralyticsHey there! 👋 It looks like there might be a slight mix-up in how you're constructing the input to your model run. When dealing with arrays of tensors in ONNX.js, you should pass a single tensor that concatenates your image tensors along the batch dimension if the model is set up for batch processing.
For your issue with
inputTensorscausing an error aboutbyteLength, it's likely because the model expects one tensor that combines all input images. Instead of:const inputs = { images: [inputTensors[0], inputTensors[1]] };You should concatenate your
inputTensorsinto one tensor if your model expects a batch input. Unfortunately, directly passing an array like this might not work as expected with ONNX.js since it seems to expect the input as a single tensor representing the batch. The error you're encountering (TypeError: Cannot read properties of undefined (reading 'byteLength')) usually occurs when the input format to thesession.runmethod is not as expected.This could look different based on how your model is trained and how
ort.Tensorhandles batches. Ensure your model is trained with dynamic batch size if you want to process multiple images in a single forward pass. If you're not sure how to concatenate tensors in JavaScript (as direct tensor concatenation might not be as straightforward as in Python), you might have to loop over your images and process them one at a time, or look into adjusting your model to accept variable batch sizes more gracefully.Given your current setup, if your model does not explicitly support batched inputs, you might need to process each image individually:
for(const tensor of inputTensors) { const inputs = { images: tensor }; const outputs = await yolov8.run(inputs); // Process the outputs for each image here }Remember, different models expect the input in specific formats, including batch size. Ensure your preprocessing aligns with these expectations! 🚀
SugarSol
请问一下,YOLO26 在导出 onnx 时,imgsz参数取(384, 672)和(640, 640) 推理结果差异很大,是什么原因导致的呢?
Glenn JocherUltralyticsSugarSol
我使用的是官方提供的coco预训练权重直接导出onnx的,导出和预测都是使用的官方提供的代码,并未做任何修改,不同之处只有导出时的尺寸不同。奇怪的是,这种现象在YOLOv8中并未发现。
Glenn JocherUltralytics(edited)这更像是 YOLO26 的导出特性而不是 ONNX 本身的问题:YOLO26 的检测头是原生端到端(NMS-free)的,而 YOLOv8 是传统 NMS 流程,所以更换
imgsz时两者的一致性表现不一定相同;建议先在相同imgsz下对比.pt与.onnx的结果。end2end参数现已弃用并映射为nms:默认(不设置nms)导出与 YOLOv8 类似的原始预测,nms=False导出 NMS-free 输出,nms=True在支持的格式中内置 NMS,详见 导出文档 和 End-to-End 检测指南;如果方便,请贴出完整的导出/推理命令和yolo checks输出,我们再继续定位。SugarSol
YOLO26导出的onnx在相同形状下end2end与非end2end的推理输出是一致的。而.pt与.onnx的结果只有在导出为(640,640)的情况下一致,在此形状下的输出也与YOLOv8是一致的。下面是我的导出和预测脚本: from ultralytics import YOLO model = YOLO("./yolo26n.pt") path = model.export(format="onnx", imgsz=(384, 672), end2end=False) model = YOLO("./yolo26n.onnx") results = model("../../coco128/train2017/000000000049.jpg") results[0].save() 下面是不同形状的推理结果: (384,672): image 1/1 /home/easyits/ai/wpf/Employee/100/ultralytics/tools/../../coco128/train2017/000000000049.jpg: 384x672 1 person, 2 horses, 1 potted plant, 136.5ms Speed: 18.2ms preprocess, 136.5ms inference, 47.0ms postprocess per image at shape (1, 3, 384, 672) (640,640): image 1/1 /home/easyits/ai/wpf/Employee/100/ultralytics/tools/../../coco128/train2017/000000000049.jpg: 640x640 4 persons, 2 horses, 103.7ms Speed: 7.5ms preprocess, 103.7ms inference, 16.5ms postprocess per image at shape (1, 3, 640, 640)
Glenn JocherUltralytics你这个脚本里最需要先排除的是“对比条件不一致”:
.pt推理如果没显式传imgsz=(384, 672),通常还是按默认640跑,而导出的.onnx输入已经固定成(384, 672),所以这不算同尺度对比;建议先让.pt和.onnx在完全相同的imgsz下分别执行predict或直接val,导出模型本身也支持直接验证,可参考 检测任务中的导出说明;如果这样仍只有 YOLO26 在非640下不一致,请把两边的完整日志和yolo checks输出贴上来,我们继续查。SugarSol
抱歉,表达不是很清楚,我想表达的是导出和预测使用的是这样的命令,我在不同imgsz和end2end的组合下都对同一张图片进行了预测,确实是只有YOLO26在非640形状下与640形状下的结果不一致,只与imgsz有关,与是否为end2end无关。
Glenn JocherUltralytics感谢补充,这里基本可以定位到“矩形 ONNX 导出”的当前限制了:从当前 Exporter 实现参考 看,非 PyTorch 后端对非方形
imgsz不保证与.pt完全一致,导出完成时也会提示非方形imgsz的 non-PyTorchval不可用,所以你看到(384, 672)与640,640结果分叉、且与end2end无关,是符合现状的;如果目标是尽量和.pt对齐,建议优先用方形尺寸导出,例如imgsz=640或672,如果你希望我们继续跟进矩形输入场景,也请新开一个 issue 并附上完整日志和yolo checks输出。SugarSol
感谢您的回复,我提了issue#24428,并附上了完整日志和yolo checks输出。
Glenn JocherUltralytics感谢,已收到;这个问题我们就集中在
#24428里继续跟进,后续如能补充同一张图在.pt/.onnx下显式指定相同imgsz的model.predict()或model.val()对比结果,会更有助于确认是否是矩形导出的边界情况。
nwpu-caikun
I trained an image classification model. How can I perform incremental learning to add new class? Are there any methods other than retraining the model? big thanks
908637049 @.***
Glenn JocherUltralyticsAdding a new class changes the classifier head, so there isn’t a “no-training” way to truly add classes incrementally in Ultralytics YOLO classification; the recommended approach is to fine-tune from your existing checkpoint on a dataset that includes both the original classes and the new class to avoid catastrophic forgetting (see the Classification docs). Please remove the phone/email and keep details here in the discussion (public) so the team can help.
from ultralytics import YOLO model = YOLO("path/to/best.pt") # your previous classifier model.train(data="path/to/cls_dataset") # dataset now includes the new class
nwpu-caikun
we use a customed dataset to train a image classify model,when calculate the result conf,we meet a problem。 in the last layer, we manualy calculate the conf by logits output, and then ,softmax to generate the conf ,but the conf number is very low。 however,we try to print the rusult.prob, (results = model(image_path, verbose=False),results_probs_obj = results[0].probs ) we found the result.probs is not equal to manualy conf we calculate. the result.probs is much higher than manualy conf. result.probs is 99.998%, and manualy conf is only 6.1982%. what the difference between them? how the model calculate the conf, and get the 99.998% conf?
Glenn JocherUltralyticsresults[0].probsis already the final per-class probability vector (Softmax has been applied in the classification head during inference), so if you “manual softmax” a tensor that’s already probabilities you’ll get very different (often much smaller) numbers like your ~6%; if you want to reproduce Ultralytics’ confidence from logits, make sure you’re using the raw logits output (the classification head returns(probs, logits)in inference) and computetorch.softmax(logits, dim=1)once—see the Results/Probs API reference and the Classify head forward behavior.nwpu-caikun
how do I get the raw logits output after model(image), has any methods? when I get the raw logits output ,I can manual calculate the probs? thanks!
Glenn JocherUltralyticsmodel(image_path)goes throughClassificationPredictor.postprocess(), which intentionally keeps only the first element (preds[0]) when the model returns a tuple, so the raw logits aren’t exposed inResults; to get logits you need to run a PyTorch forward pass on the preprocessed tensor. (docs.ultralytics.com)import cv2 import torch from ultralytics import YOLO model = YOLO("path/to/best.pt") # classification .pt _ = model("path/to/image.jpg", verbose=False) # init predictor/transforms once img0 = cv2.imread("path/to/image.jpg") # BGR im = model.predictor.preprocess([img0]) with torch.no_grad(): probs, logits = model.model(im) # head returns (probs, logits) in inference probs_manual = torch.softmax(logits, dim=1)Note this tuple output is only available for PyTorch models; in export mode the head returns probabilities only. (docs.ultralytics.com)
sidshete
I have trained model for instance segmentation and I ma trying to export to run on DPU. Here is the code mentioned below
from ultralytics import YOLO
best_weights_path = "../weights/yolo11_s/yolo11_s.pt" data_yaml = "../yolo_seg/dataset.yaml"
model = YOLO(best_weights_path)
Export for DPU (INT8)
model.export( format="onnx", data=data_yaml,
int8=True,
simplify=True, nms=False
)I get the following error.
UnpicklingError Traceback (most recent call last) Cell In[18], line 6 3 best_weights_path = "../weights/yolo11_s/yolo11_s.pt" 4 calib_data_yaml = "../dataset.yaml" ----> 6 model = YOLO(best_weights_path) 8 # Export for DPU (INT8) 9 model.export( 10 format="onnx", 11 data=calib_data_yaml, # calibration dataset required for INT8 (...) 14 nms=False # often applied post-inference 15 )
File ~/testing_env/lib/python3.10/site-packages/ultralytics/models/yolo/model.py:23, in YOLO.init(self, model, task, verbose) 20 self.dict = new_instance.dict 21 else: 22 # Continue with default YOLO initialization ---> 23 super().init(model=model, task=task, verbose=verbose)
File ~/testing_env/lib/python3.10/site-packages/ultralytics/engine/model.py:151, in Model.init(self, model, task, verbose) 149 self._new(model, task=task, verbose=verbose) 150 else: --> 151 self._load(model, task=task)
File ~/testing_env/lib/python3.10/site-packages/ultralytics/engine/model.py:240, in Model._load(self, weights, task) 237 weights = checks.check_model_file_from_stem(weights) # add suffix, i.e. yolov8n -> yolov8n.pt 239 if Path(weights).suffix == ".pt": --> 240 self.model, self.ckpt = attempt_load_one_weight(weights) 241 self.task = self.model.args["task"] 242 self.overrides = self.model.args = self._reset_ckpt_args(self.model.args)
File ~/testing_env/lib/python3.10/site-packages/ultralytics/nn/tasks.py:806, in attempt_load_one_weight(weight, device, inplace, fuse) 804 def attempt_load_one_weight(weight, device=None, inplace=True, fuse=False): 805 """Loads a single model weights.""" --> 806 ckpt, weight = torch_safe_load(weight) # load ckpt 807 args = {**DEFAULT_CFG_DICT, **(ckpt.get("train_args", {}))} # combine model and default args, preferring model args 808 model = (ckpt.get("ema") or ckpt["model"]).to(device).float() # FP32 model
File ~/testing_env/lib/python3.10/site-packages/ultralytics/nn/tasks.py:732, in torch_safe_load(weight) 724 try: 725 with temporary_modules( 726 { 727 "ultralytics.yolo.utils": "ultralytics.utils", (...) 730 } 731 ): # for legacy 8.0 Classify and Pose models --> 732 ckpt = torch.load(file, map_location="cpu") 734 except ModuleNotFoundError as e: # e.name is missing module name 735 if e.name == "models":
File ~/testing_env/lib/python3.10/site-packages/torch/serialization.py:1524, in load(f, map_location, pickle_module, weights_only, mmap, **pickle_load_args) 1516 return _load( 1517 opened_zipfile, 1518 map_location, (...) 1521 **pickle_load_args, 1522 ) 1523 except pickle.UnpicklingError as e: -> 1524 raise pickle.UnpicklingError(_get_wo_message(str(e))) from None 1525 return _load( 1526 opened_zipfile, 1527 map_location, (...) 1530 **pickle_load_args, 1531 ) 1532 if mmap:
UnpicklingError: Weights only load failed. This file can still be loaded, to do so you have two options, do those steps only if you trust the source of the checkpoint. (1) In PyTorch 2.6, we changed the default value of the
weights_onlyargument intorch.loadfromFalsetoTrue. Re-runningtorch.loadwithweights_onlyset toFalsewill likely succeed, but it can result in arbitrary code execution. Do it only if you got the file from a trusted source. (2) Alternatively, to load withweights_only=Trueplease check the recommended steps in the following error message. WeightsUnpickler error: Unsupported global: GLOBAL ultralytics.nn.modules.block.C3k2 was not an allowed global by default. Please usetorch.serialization.add_safe_globals([ultralytics.nn.modules.block.C3k2])or thetorch.serialization.safe_globals([ultralytics.nn.modules.block.C3k2])context manager to allowlist this global if you trust this class/function.
Glenn JocherUltralytics(edited)That error is coming from PyTorch 2.6's new default
torch.load(weights_only=True), which blocks custom Ultralytics layers likeultralytics.nn.modules.block.C3k2. First upgrade withpip install -U ultralytics; if you still hit it and trust the checkpoint, either pin PyTorch<2.6or allowlistC3k2before callingYOLO():import torch from ultralytics import YOLO from ultralytics.nn.modules.block import C3k2 torch.serialization.add_safe_globals([C3k2]) # only if you trust the .pt source model = YOLO("../weights/yolo11_s/yolo11_s.pt")Also note that INT8 ONNX export is supported in current Ultralytics: use
quantize=8(the olderint8=Trueis mapped to it) together withdatapointing to your calibration dataset. If your DPU toolchain needs its own quantizer, you can instead export FP32 ONNX and quantize with your vendor toolchain; see the supported export args in the Export mode docs and ONNX export guide.If you paste
!yolo checks(and restart the notebook kernel if you recently upgraded PyTorch/Ultralytics), I can confirm the exact version combo that's triggering this on your side.
GeThi255
Hi, export to "tflite" and other is not working with python 3.13, 3.10. or 3.08 due to incompatibility of e.g. tensorflow version (Ultralytics requirement ['tensorflow>=2.0.0,<=2.19.0'] ). Tested on windows 11 and Raspi. Could you please check. Thanks Gerd
404-NOTFOUND-Coder
Title: int8 argument not supported when exporting to ONNX in Ultralytics 8.3.162
Description:
I encountered an error when trying to export a trained YOLOv8 model to ONNX format with the following code:
model = YOLO('/kb210/wrs/tennis-analysis/tennis_analysis/training/runs/detect/train27/weights/best.pt') model.export(format="onnx", imgsz=(1024,1280), nms=True, int8=True, dynamic=True) The error traceback is as follows:
Traceback (most recent call last): File "/kb210/wrs/tennis-analysis/tennis_analysis/yolo_inference.py", line 15, in model.export(format="onnx", imgsz=(1024,1280), nms=True, int8=True, dynamic=True) File "/kb210/conda/envs/tennis_analysis/lib/python3.9/site-packages/ultralytics/engine/model.py", line 819, in export return Exporter(overrides=args, _callbacks=self.callbacks)(model=self.model) File "/kb210/conda/envs/tennis_analysis/lib/python3.9/site-packages/ultralytics/engine/exporter.py", line 311, in call validate_args(fmt, self.args, fmt_keys) File "/kb210/conda/envs/tennis_analysis/lib/python3.9/site-packages/ultralytics/engine/exporter.py", line 171, in validate_args assert arg in valid_args, f"ERROR ❌️ argument '{arg}' is not supported for format='{format}'" AssertionError: ERROR ❌️ argument 'int8' is not supported for format='onnx' From the error message, it seems that the int8=True argument is not supported for ONNX export. However, I believe INT8 quantization could be useful for optimizing models even before deployment to certain runtimes (e.g., TensorRT).
Question:
Is there any plan to support INT8 during ONNX export? If not, what would be the recommended way to apply INT8 quantization after exporting to ONNX?
Environment:
Ultralytics version: 8.3.162 Python version: 3.9.19 PyTorch version: 1.13.1 OS: Linux Hardware: Intel Xeon E5-2680 v4 2.40GHz Thanks for your help!
rememberBr
Does using dynamic=True on Nvidia's Jetson development board not include batch dimension? It seems that only w and h have become dynamic dimensions, while batch is fixed at 1?
