Exporting YOLOv8 to ONNX format allows a trained Ultralytics model to run outside the normal PyTorch environment. ONNX, or Open Neural Network Exchange, provides a standardized model representation supported by runtimes and deployment tools such as ONNX Runtime, OpenCV DNN, TensorRT conversion pipelines, and other inference systems.
Ultralytics provides built-in ONNX export through both the CLI and Python API. A basic export can be completed with:
yolo export model=yolov8n.pt format=onnx
or:
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
model.export(format="onnx")
Current Ultralytics ONNX export also supports options such as imgsz, batch, dynamic, simplify, opset, and optional NMS integration.
Introduction to YOLOv8 ONNX Export
YOLOv8 models are normally trained and saved as PyTorch .pt checkpoints. This format is convenient during training and development because it integrates directly with the Ultralytics Python package and PyTorch.
Deployment environments, however, may not always use PyTorch.
For example, you may want to run YOLOv8 inside:
ONNX Runtime
OpenCV
C++
C#
Java
cloud inference systems
edge applications
custom deployment engines
Exporting to ONNX converts the model into a more portable computational graph.
The general workflow is:
YOLOv8 .pt Model
↓
Ultralytics Export
↓
ONNX Graph
↓
model.onnx
↓
ONNX-Compatible Runtime
The exported file can then be loaded independently of the original PyTorch checkpoint, provided the deployment runtime supports the operators used by the exported graph.
What Is ONNX and Why Use It with YOLOv8?
ONNX is an open model format designed to make neural-network models portable across frameworks and inference engines.
Instead of keeping a model tied to one training framework, ONNX represents operations such as convolutions, activations, reshaping, concatenation, and other graph components in a standardized format.
Ultralytics describes ONNX as useful for interoperability, deployment flexibility, and hardware-specific optimization through runtimes such as ONNX Runtime.
Benefits of the ONNX Format
One of the biggest benefits is portability.
A YOLOv8 model exported to:
yolov8n.onnx
can potentially be used without directly loading:
yolov8n.pt
through PyTorch.
Other benefits include:
cross-platform deployment
runtime independence
CPU optimization
GPU execution providers
integration with non-Python applications
compatibility with deployment frameworks
ONNX can therefore act as an intermediate format between YOLOv8 training and production deployment.
When YOLOv8 ONNX Export Is Useful
ONNX export is useful when the deployment environment differs from the training environment.
For example:
Train:
Python + PyTorch
Deploy:
C++ + ONNX Runtime
or:
Train:
CUDA workstation
Deploy:
CPU server
or:
Train:
Ultralytics YOLOv8
Deploy:
OpenCV DNN application
It is also useful when comparing PyTorch inference against an optimized ONNX Runtime implementation.
Requirements for Exporting YOLOv8 to ONNX
Before exporting, you need the Ultralytics package and the dependencies required for ONNX generation.
You also need a valid YOLOv8 model checkpoint or architecture that Ultralytics can load.
Install Ultralytics and ONNX Dependencies
Install Ultralytics:
pip install -U ultralytics
If ONNX export dependencies are missing, Ultralytics may install or request additional packages depending on the environment.
You can also install ONNX-related packages manually:
pip install onnx onnxruntime
For GPU ONNX Runtime deployment, the appropriate GPU-enabled ONNX Runtime package and compatible CUDA environment are required.
A more complete export environment can also use Ultralytics export extras where appropriate.
Choose a Pretrained or Custom YOLOv8 Model
Pretrained detection model:
yolov8n.pt
Other standard variants include:
yolov8s.pt
yolov8m.pt
yolov8l.pt
yolov8x.pt
Custom-trained model:
runs/detect/train/weights/best.pt
Both can be exported using the same Ultralytics interface.
The export operation applies to the loaded model rather than requiring a special ONNX-specific version of YOLOv8.
How to Export YOLOv8 to ONNX
Ultralytics supports ONNX export through both CLI and Python.
The simplest configuration uses the default export settings.
Export YOLOv8 to ONNX Using the CLI
Basic command:
yolo export model=yolov8n.pt format=onnx
You can specify the image size:
yolo export \
model=yolov8n.pt \
format=onnx \
imgsz=640
A more customized export can be:
yolo export \
model=yolov8n.pt \
format=onnx \
imgsz=640 \
dynamic=True \
simplify=True
Ultralytics uses the normal CLI name=value syntax for export options.
Export YOLOv8 to ONNX Using Python
Load the model:
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
Export:
path = model.export(
format="onnx"
)
print(path)
Current Ultralytics’ model export method returns the path to the generated model file.
With options:
model.export(
format="onnx",
imgsz=640,
dynamic=True,
simplify=True
)
Export Custom-Trained YOLOv8 Weights
Load your custom checkpoint:
from ultralytics import YOLO
model = YOLO(
"runs/detect/train/weights/best.pt"
)
Then:
model.export(
format="onnx"
)
CLI equivalent:
yolo export \
model=runs/detect/train/weights/best.pt \
format=onnx
The custom class definitions and learned weights are preserved in the exported model behavior.
Important YOLOv8 ONNX Export Options
ONNX export has several options that affect compatibility and deployment flexibility.
Current Ultralytics ONNX options include:
imgsz
batch
dynamic
simplify
opset
nms
device
among other export-related arguments.
Image Size
The default export image size is commonly:
640
for standard YOLO detection workflows.
Example:
model.export(
format="onnx",
imgsz=640
)
A rectangular size can also be supplied where supported:
model.export(
format="onnx",
imgsz=(640, 960)
)
The export documentation describes imgsz as either an integer or a (height, width) tuple.
For static exports, this value generally determines the expected input dimensions.
Dynamic Input Shapes
By default:
dynamic=False
in current ONNX export settings.
Enable it with:
model.export(
format="onnx",
dynamic=True
)
or:
yolo export \
model=yolov8n.pt \
format=onnx \
dynamic=True
Dynamic export allows input dimensions or batch dimensions to vary instead of being completely fixed.
Conceptually:
Static model:
[1, 3, 640, 640]
Dynamic model may expose dimensions such as:
[batch, 3, height, width]
depending on the export graph.
Dynamic shapes are useful when deployment inputs vary in size, but some inference engines perform best with fixed dimensions.
Simplification
Current Ultralytics defaults:
simplify=True
for ONNX graph simplification using onnxslim.
Example:
model.export(
format="onnx",
simplify=True
)
Graph simplification may:
remove redundant operations
simplify graph structure
improve runtime compatibility
reduce unnecessary nodes
It does not mean the model becomes a smaller YOLO architecture. It simplifies the exported computational graph while preserving intended outputs.
ONNX Opset Version
ONNX operators evolve through different opset versions.
You can specify one manually:
model.export(
format="onnx",
opset=17
)
CLI:
yolo export \
model=yolov8n.pt \
format=onnx \
opset=17
Current Ultralytics defaults:
opset=None
which causes the exporter to select an appropriate supported opset rather than requiring the user to choose one manually.
The current exporter contains logic that selects an opset according to the installed PyTorch, ONNX, CUDA, and quantization configuration.
Therefore, manually setting an opset should usually be done for runtime compatibility rather than because one opset is universally best.
Understanding the Exported ONNX Model
The ONNX file stores a computational graph containing model inputs, model operations, trained parameters, and outputs.
A normal file might be:
yolov8n.onnx
You can inspect it using ONNX tools or visualization software such as Netron.
ONNX Input Shape
A typical static YOLOv8 detection model exported at 640 may use an input shaped approximately as:
[1, 3, 640, 640]
where:
1
→ batch size
3
→ RGB channels
640
→ height
640
→ width
With dynamic export, the shape may instead be represented conceptually as:
[batch, 3, height, width]
Ultralytics’ ONNX exporter uses the input name:
images
for its standard ONNX graph export utility.
ONNX Output Shape
YOLOv8 detection output shape depends on:
number of classes
input resolution
model task
whether NMS is included
dynamic or static export
A standard raw detection graph without embedded NMS typically produces a tensor containing detection channels and candidate locations.
For an 80-class YOLOv8 detection model, the raw channel dimension commonly reflects:
4 box values
+
80 class scores
=
84 channels
A dynamic ONNX example from Ultralytics shows an output shaped conceptually as:
[batch, 84, number_of_candidates]
for a detection graph without embedded NMS.
Do not hard-code an output shape without checking the actual exported model because task, class count, NMS configuration, and exporter version can change it.
Detection Predictions
Raw ONNX output is not always equivalent to the final Results object returned by the high-level Ultralytics API.
A raw model may require post-processing such as:
decode predictions
convert box format
apply confidence filtering
run NMS
scale coordinates back to source image
Current ONNX export supports:
nms=False
by default, with an option to include NMS where supported.
Therefore, if you call ONNX Runtime directly on a raw exported graph, you may need to implement post-processing yourself.
How to Run YOLOv8 ONNX Inference
There are two main approaches.
You can load the ONNX model through Ultralytics itself, or use ONNX Runtime directly.
Direct ONNX Runtime gives more control but requires careful preprocessing and post-processing.
Load the Model with ONNX Runtime
Install:
pip install onnxruntime
Then:
import onnxruntime as ort
session = ort.InferenceSession(
"yolov8n.onnx"
)
Check inputs:
for input_info in session.get_inputs():
print(
input_info.name,
input_info.shape,
input_info.type
)
Check outputs:
for output_info in session.get_outputs():
print(
output_info.name,
output_info.shape,
output_info.type
)
The standard Ultralytics export utility names the main input images and normally names the first output output0.
Prepare Input Images
A simplified ONNX Runtime preprocessing example is:
import cv2
import numpy as np
image = cv2.imread("image.jpg")
image = cv2.resize(
image,
(640, 640)
)
image = cv2.cvtColor(
image,
cv2.COLOR_BGR2RGB
)
image = image.astype(
np.float32
) / 255.0
image = np.transpose(
image,
(2, 0, 1)
)
image = np.expand_dims(
image,
axis=0
)
The tensor becomes:
[1, 3, 640, 640]
for a static 640 model.
However, a production-quality YOLO pipeline should reproduce Ultralytics preprocessing correctly, including aspect-ratio-preserving letterboxing rather than blindly resizing when matching original model behavior matters.
Process Model Predictions
Run:
input_name = session.get_inputs()[0].name
outputs = session.run(
None,
{
input_name: image
}
)
Then inspect:
predictions = outputs[0]
print(
predictions.shape
)
If the exported graph does not contain NMS, additional post-processing is required.
A simplified conceptual pipeline is:
ONNX Output
↓
Decode Box Coordinates
↓
Read Class Scores
↓
Apply Confidence Threshold
↓
Apply NMS
↓
Scale Boxes
↓
Final Detections
Using the exported model through Ultralytics can avoid having to manually reproduce all of these steps.
For example:
from ultralytics import YOLO
model = YOLO("yolov8n.onnx")
results = model("image.jpg")
Current Ultralytics tests explicitly export ONNX models and then load the exported file back through YOLO(file) for prediction validation.
YOLOv8 PyTorch vs ONNX
PyTorch and ONNX serve different purposes.
PyTorch is usually the best environment for model development and training.
ONNX is generally more attractive for deployment portability.
Inference Speed Differences
ONNX does not automatically guarantee faster inference.
Performance depends on:
CPU or GPU
ONNX Runtime execution provider
model graph
input size
batch size
precision
hardware
ONNX Runtime may outperform standard PyTorch on some CPUs or deployment systems because it applies runtime-specific optimizations.
On other systems, PyTorch may perform similarly or even better.
The correct approach is to benchmark both on the actual deployment hardware.
Model Portability
PyTorch:
.pt
depends on PyTorch-compatible model loading.
ONNX:
.onnx
can be consumed by many different runtimes and languages.
This portability is one of the strongest reasons to export.
For example:
Python
C++
C#
Java
applications can all potentially interact with ONNX-compatible runtimes.
Deployment Compatibility
ONNX can also serve as an intermediate step for deployment pipelines.
A common workflow is:
YOLOv8 .pt
↓
ONNX
↓
Deployment Runtime
or:
YOLOv8 .pt
↓
ONNX
↓
Vendor-specific optimization
Compatibility still depends on supported operators and opset versions.
How to Validate the Exported ONNX Model
An export should not be considered complete just because an .onnx file was created.
The model should also be tested.
A good validation workflow compares:
PyTorch predictions
vs
ONNX predictions
on the same images.
Compare ONNX and PyTorch Predictions
PyTorch:
from ultralytics import YOLO
pt_model = YOLO("yolov8n.pt")
pt_results = pt_model("test.jpg")
ONNX:
onnx_model = YOLO("yolov8n.onnx")
onnx_results = onnx_model(
"test.jpg"
)
Compare:
detected classes
confidence scores
bounding boxes
number of detections
Small numerical differences may occur due to backend implementation and numerical precision, but major prediction differences deserve investigation.
Check Accuracy After Export
For a custom model, validate the exported model using the same dataset used for PyTorch validation when supported by your workflow.
For example:
onnx_model = YOLO("best.onnx")
metrics = onnx_model.val(
data="data.yaml"
)
Then compare mAP, precision, and recall against the original PyTorch checkpoint.
Ultralytics’ export tests also explicitly run inference on generated ONNX models to confirm exported-model usability.
Test the Model on Sample Images
Use several representative samples rather than only one easy image.
Test:
large objects
small objects
crowded scenes
empty backgrounds
low confidence objects
different resolutions
A successful export should behave consistently across the kinds of inputs expected in production.
Common YOLOv8 ONNX Export Problems
ONNX export problems usually come from dependency mismatches, unsupported operators, incorrect assumptions about shapes, or runtime compatibility.
Missing ONNX Dependencies
A common error is that packages such as:
onnx
onnxruntime
onnxslim
are unavailable.
Install the necessary packages:
pip install onnx onnxruntime
and update Ultralytics:
pip install -U ultralytics
Current Ultralytics uses onnxslim when ONNX simplification is enabled.
Unsupported Operators
An ONNX runtime may not support every operator in every opset.
Possible solutions include:
change opset
update ONNX Runtime
update Ultralytics
disable or enable simplification
use a supported runtime
For example:
model.export(
format="onnx",
opset=17
)
Ultralytics documentation specifically notes that the opset option exists for compatibility with different ONNX parsers and runtimes.
Incorrect Input or Output Shapes
A static model may expect:
[1, 3, 640, 640]
while an application may send:
[1, 3, 1280, 1280]
This can fail if dynamic shapes were not enabled.
If varying shapes are required:
model.export(
format="onnx",
dynamic=True
)
Always inspect:
session.get_inputs()
session.get_outputs()
rather than assuming the graph shape.
ONNX Runtime Inference Errors
Common causes include:
wrong dtype
incorrect tensor layout
wrong image dimensions
missing batch dimension
unsupported execution provider
runtime/opset incompatibility
YOLO generally expects image tensor layout:
NCHW
rather than:
NHWC
for normal ONNX export.
Therefore:
[1, 3, 640, 640]
is appropriate for a standard static detection model, not:
[1, 640, 640, 3]
unless the graph explicitly says otherwise.
FAQs About Exporting YOLOv8 to ONNX
How do I export YOLOv8 to ONNX?
CLI:
yolo export \
model=yolov8n.pt \
format=onnx
Python:
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
model.export(
format="onnx"
)
ONNX is a directly supported Ultralytics export format.
Can I export custom YOLOv8 weights to ONNX?
Yes.
Load:
model = YOLO("best.pt")
then:
model.export(
format="onnx"
)
The same export interface works for trained custom checkpoints.
Does ONNX make YOLOv8 faster?
It can, but not always.
ONNX Runtime may provide better performance on some hardware because it can apply optimized execution providers.
Speed depends on:
CPU
GPU
execution provider
input size
batch size
model
precision
Benchmark PyTorch and ONNX on the actual deployment system rather than assuming ONNX will always be faster.
What does dynamic=True mean during ONNX export?
dynamic=True enables dynamic input dimensions rather than fixing all supported dimensions to the export-time shape.
Example:
model.export(
format="onnx",
dynamic=True
)
This can allow shapes represented conceptually as:
[batch, 3, height, width]
instead of a fixed:
[1, 3, 640, 640]
Current Ultralytics defaults dynamic=False.
What ONNX opset should I use for YOLOv8?
In most cases, leave:
opset=None
and allow Ultralytics to choose a compatible version.
Current exporter code selects an appropriate ONNX opset according to the installed PyTorch/ONNX environment and additional conditions.
Specify an explicit opset only when required by the deployment runtime:
model.export(
format="onnx",
opset=17
)
Can YOLOv8 ONNX run without PyTorch?
Yes, when you use an ONNX-compatible runtime directly.
For example:
import onnxruntime as ort
session = ort.InferenceSession(
"yolov8n.onnx"
)
This does not require PyTorch for model execution.
However, if you load the ONNX model through the Ultralytics YOLO() wrapper, the Ultralytics package is still part of the inference application.
How do I test a YOLOv8 ONNX model?
One simple method is:
from ultralytics import YOLO
model = YOLO("yolov8n.onnx")
results = model("image.jpg")
Ultralytics’ current test suite performs exported ONNX inference using the same pattern after export.
You can also test the graph directly through ONNX Runtime.
Conclusion
Exporting YOLOv8 to ONNX format is one of the most useful deployment options when a model needs to move beyond the standard PyTorch environment.
The simplest CLI command is:
yolo export \
model=yolov8n.pt \
format=onnx
and the equivalent Python code is:
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
model.export(
format="onnx"
)
Current Ultralytics ONNX export supports key options including:
imgsz
batch
dynamic
simplify
opset
nms
device
with current defaults including dynamic=False, simplify=True, opset=None, and nms=False.
A more customized export is:
model.export(
format="onnx",
imgsz=640,
dynamic=True,
simplify=True
)
The overall deployment process can be summarized as:
YOLOv8 .pt
↓
Export to ONNX
↓
Inspect Input / Output Shapes
↓
Load with ONNX Runtime
↓
Preprocess Image
↓
Run Inference
↓
Apply Post-Processing
↓
Compare with PyTorch
↓
Deploy
For static 640-pixel detection export, the input is commonly shaped like:
[1, 3, 640, 640]
while dynamic exports can expose variable batch, height, and width dimensions. The standard Ultralytics ONNX graph uses an input named images and normally an output named output0.
Do not assume a fixed output tensor shape for every YOLOv8 model. Output structure can change with the number of classes, task type, input dimensions, NMS configuration, and exporter version. Inspect the actual ONNX graph before writing deployment post-processing.
Finally, always validate the exported model against the original .pt checkpoint. Successful file creation only confirms that export finished; comparison on representative images and validation data confirms that the exported ONNX model behaves correctly in the intended deployment environment.
I’m Jane Austen, a skilled content writer with the ability to simplify any complex topic. I focus on delivering valuable tips and strategies throughout my articles.