How to Export YOLOv8 to ONNX Format

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.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top