Meet YOLO26: next-gen vision AI.

Link to this sectionCách xuất các model PyTorch không phải YOLO bằng Ultralytics#

Ultralytics cung cấp các tiện ích xuất độc lập tại ultralytics.utils.export, gói gọn nhiều backend đằng sau một giao diện nhất quán. Bạn có thể xuất bất kỳ torch.nn.Module nào, bao gồm các model hình ảnh timm, các trình phân loại và phát hiện torchvision, hoặc kiến trúc tùy chỉnh của riêng bạn, sang ONNX, TorchScript, OpenVINO, CoreML, NCNN, PaddlePaddle, MNN, ExecuTorch, và TensorFlow SavedModel mà không cần tìm hiểu riêng từng backend.

Việc triển khai các model PyTorch vào môi trường production thường đòi hỏi phải sử dụng nhiều công cụ xuất khác nhau cho từng mục tiêu: torch.onnx.export cho ONNX, coremltools cho các thiết bị Apple, onnx2tf cho TensorFlow, pnnx cho NCNN, v.v. Mỗi công cụ đều có API riêng, các phụ thuộc phức tạp và quy ước đầu ra khác nhau. Các tiện ích này hợp nhất chúng thành một mẫu gọi duy nhất.

Link to this sectionTại sao nên sử dụng Ultralytics để xuất các model không phải YOLO?#

  • Một API duy nhất cho 10 định dạng: chỉ cần học một quy ước gọi hàm thay vì cả chục loại.
  • Bề mặt tiện ích dùng chung: các trình trợ giúp xuất nằm trong ultralytics.utils.export, vì vậy sau khi các gói backend đã được cài đặt, bạn có thể giữ nguyên mẫu gọi hàm trên khắp các định dạng.
  • Cùng một luồng code như các bản xuất YOLO: các trình trợ giúp tương tự cung cấp sức mạnh cho mọi bản xuất YOLO của Ultralytics.
  • Tích hợp sẵn lượng tử hóa FP16 và INT8 cho các định dạng hỗ trợ tính năng này (OpenVINO, CoreML, MNN, NCNN).
  • Hoạt động trên CPU: không yêu cầu GPU cho chính bước xuất, vì vậy bạn có thể chạy nó cục bộ trên bất kỳ laptop nào.

Link to this sectionBắt đầu nhanh#

Cách nhanh nhất là xuất hai dòng sang ONNX mà không cần code YOLO và không cần thiết lập gì thêm ngoài pip install ultralytics onnx timm:

import timm
import torch

from ultralytics.utils.export import torch2onnx

model = timm.create_model("resnet18", pretrained=True).eval()
torch2onnx(model, torch.randn(1, 3, 224, 224), output_file="resnet18.onnx")

Link to this sectionCác định dạng xuất được hỗ trợ#

Các hàm torch2* nhận một torch.nn.Module chuẩn và một tensor đầu vào ví dụ. MNN, TF SavedModel và TF Frozen Graph sẽ đi qua một artifact ONNX hoặc Keras trung gian. Trong cả hai trường hợp đều không yêu cầu các thuộc tính cụ thể của YOLO.

Định dạngHàmCài đặtĐầu ra
ONNXtorch2onnx()pip install onnxFile .onnx
TorchScripttorch2torchscript()đã bao gồm cùng PyTorchFile .torchscript
OpenVINOtorch2openvino()pip install openvinoThư mục _openvino_model/
CoreMLtorch2coreml()pip install coremltools.mlpackage
TF SavedModelonnx2saved_model()xem các yêu cầu chi tiết bên dướiThư mục _saved_model/
TF Frozen Graphkeras2pb()xem các yêu cầu chi tiết bên dướiFile .pb
NCNNtorch2ncnn()pip install ncnn pnnxThư mục _ncnn_model/
MNNonnx2mnn()pip install MNNFile .mnn
PaddlePaddletorch2paddle()pip install paddlepaddle x2paddleThư mục _paddle_model/
ExecuTorchtorch2executorch()pip install executorchThư mục _executorch_model/
ONNX như một định dạng trung gian

Các bản xuất MNN, TF SavedModel và TF Frozen Graph đều đi qua ONNX như một bước trung gian. Hãy xuất sang ONNX trước, sau đó mới chuyển đổi.

Nhúng metadata

Một số hàm xuất chấp nhận một dictionary metadata tùy chọn (ví dụ: torch2torchscript(..., metadata={"author": "me"})) để nhúng các cặp khóa-giá trị tùy chỉnh vào artifact đã xuất nếu định dạng đó hỗ trợ.

Link to this sectionVí dụ từng bước#

Mỗi ví dụ dưới đây đều sử dụng cùng một thiết lập, một ResNet-18 đã được huấn luyện sẵn từ timm ở chế độ evaluation:

import timm
import torch

model = timm.create_model("resnet18", pretrained=True).eval()
im = torch.randn(1, 3, 224, 224)
Luôn gọi `model.eval()` trước khi xuất

Dropout, batch normalization và các layer chỉ dùng cho huấn luyện khác sẽ hoạt động khác biệt trong quá trình inference. Việc bỏ qua .eval() sẽ tạo ra các bản xuất có kết quả đầu ra không chính xác.

Link to this sectionXuất sang ONNX#

from ultralytics.utils.export import torch2onnx

torch2onnx(model, im, output_file="resnet18.onnx")

Đối với kích thước batch động, hãy truyền vào một dictionary dynamic:

torch2onnx(model, im, output_file="resnet18_dyn.onnx", dynamic={"images": {0: "batch_size"}})

Opset mặc định là 14 và tên đầu vào mặc định là "images". Ghi đè bằng các tham số opset, input_names hoặc output_names.

Link to this sectionXuất sang TorchScript#

Không cần thêm phụ thuộc. Sử dụng torch.jit.trace ở phía sau.

from ultralytics.utils.export import torch2torchscript

torch2torchscript(model, im, output_file="resnet18.torchscript")

Link to this sectionXuất sang OpenVINO#

from ultralytics.utils.export import torch2openvino

ov_model = torch2openvino(model, im, output_dir="resnet18_openvino_model")

Thư mục chứa một cặp model.xmlmodel.bin có tên cố định:

resnet18_openvino_model/
├── model.xml
└── model.bin

Sử dụng dynamic=True cho các shape đầu vào động, quantize=16 cho FP16, hoặc quantize=8 cho lượng tử hóa INT8. INT8 yêu cầu thêm đối số calibration_dataset.

Yêu cầu openvino>=2024.0.0 (hoặc >=2025.2.0 trên macOS 15.4+) và torch>=2.1.

Link to this sectionXuất sang CoreML#

import coremltools as ct

from ultralytics.utils.export import torch2coreml

inputs = [ct.TensorType("input", shape=(1, 3, 224, 224))]
ct_model = torch2coreml(model, inputs, im, classifier_names=None, output_file="resnet18.mlpackage")

Đối với các model classification, hãy truyền một danh sách tên lớp vào classifier_names để thêm đầu phân loại vào model CoreML.

Yêu cầu coremltools>=9.0, torch>=1.11numpy<=2.3.5. Không hỗ trợ trên Windows.

Lỗi `BlobWriter not loaded`

coremltools>=9.0 cung cấp các wheel cho Python 3.10–3.13 trên macOS và Linux. Trên các phiên bản Python mới hơn, phần mở rộng C gốc sẽ không tải được. Hãy sử dụng Python 3.10–3.13 để xuất CoreML.

Link to this sectionXuất sang TensorFlow SavedModel#

Việc xuất TF SavedModel sẽ đi qua ONNX như một bước trung gian:

from ultralytics.utils.export import onnx2saved_model, torch2onnx

torch2onnx(model, im, output_file="resnet18.onnx")
keras_model = onnx2saved_model("resnet18.onnx", output_dir="resnet18_saved_model")

Hàm trả về một model Keras và cũng tạo các file TFLite (.tflite) bên trong thư mục đầu ra:

resnet18_saved_model/
├── saved_model.pb
├── variables/
├── resnet18_float32.tflite
├── resnet18_float16.tflite
└── resnet18_int8.tflite

Yêu cầu:

  • tensorflow>=2.0.0,<=2.19.0
  • onnx2tf>=1.26.3,<1.29.0
  • tf_keras<=2.19.0
  • sng4onnx>=1.0.1
  • onnx_graphsurgeon>=0.3.26 (cài đặt với --extra-index-url https://pypi.ngc.nvidia.com)
  • ai-edge-litert>=1.2.0,<1.4.0 trên macOS (ai-edge-litert>=1.2.0 trên các nền tảng khác)
  • onnxslim>=0.1.82
  • onnx>=1.12.0,<2.0.0
  • protobuf>=5

Link to this sectionXuất sang TensorFlow Frozen Graph#

Tiếp tục từ bước xuất SavedModel ở trên, hãy chuyển đổi keras_model trả về thành một đồ thị .pb cố định (frozen):

from pathlib import Path

from ultralytics.utils.export import keras2pb

keras2pb(keras_model, output_file=Path("resnet18_saved_model/resnet18.pb"))

Link to this sectionXuất sang NCNN#

from ultralytics.utils.export import torch2ncnn

torch2ncnn(model, im, output_dir="resnet18_ncnn_model")

Thư mục chứa các file param và bin có tên cố định cùng với một wrapper Python:

resnet18_ncnn_model/
├── model.ncnn.param
├── model.ncnn.bin
└── model_ncnn.py

torch2ncnn() kiểm tra ncnnpnnx trong lần sử dụng đầu tiên.

Link to this sectionXuất sang MNN#

Xuất MNN yêu cầu file ONNX làm đầu vào. Hãy xuất sang ONNX trước, sau đó mới chuyển đổi:

from ultralytics.utils.export import onnx2mnn, torch2onnx

torch2onnx(model, im, output_file="resnet18.onnx")
onnx2mnn("resnet18.onnx", output_file="resnet18.mnn")

Hỗ trợ quantize=16 cho FP16 và quantize=8 cho lượng tử hóa INT8. Yêu cầu MNN>=2.9.6torch>=1.10.

Link to this sectionXuất sang PaddlePaddle#

from ultralytics.utils.export import torch2paddle

torch2paddle(model, im, output_dir="resnet18_paddle_model")

Thư mục chứa model PaddlePaddle và các file tham số:

resnet18_paddle_model/
├── model.pdmodel
└── model.pdiparams

Yêu cầu x2paddle và phiên bản PaddlePaddle phù hợp cho nền tảng của bạn:

  • paddlepaddle-gpu>=3.0.0,<3.3.0 trên CUDA
  • paddlepaddle==3.0.0 trên CPU ARM64
  • paddlepaddle>=3.0.0,<3.3.0 trên các CPU khác

Không được hỗ trợ trên NVIDIA Jetson.

Link to this sectionXuất sang ExecuTorch#

from ultralytics.utils.export import torch2executorch

torch2executorch(model, im, output_dir="resnet18_executorch_model")

Tệp .pte đã xuất được lưu bên trong thư mục đầu ra:

resnet18_executorch_model/
└── model.pte

Yêu cầu torch>=2.9.0 và một runtime ExecuTorch tương ứng (pip install executorch). Để biết cách sử dụng runtime, hãy xem Tích hợp ExecuTorch.

Link to this sectionXác minh mô hình đã xuất của bạn#

Sau khi xuất, hãy xác minh sự tương đương về mặt số học với model PyTorch gốc trước khi vận hành. Một bài kiểm tra nhanh (smoke test) với ONNXBackend từ ultralytics.nn.backends sẽ so sánh các kết quả đầu ra và cảnh báo sớm các lỗi tracing hoặc quantization:

import numpy as np
import timm
import torch

from ultralytics.nn.backends import ONNXBackend

model = timm.create_model("resnet18", pretrained=True).eval()
im = torch.randn(1, 3, 224, 224)
with torch.no_grad():
    pytorch_output = model(im).numpy()

onnx_model = ONNXBackend("resnet18.onnx", device=torch.device("cpu"))
onnx_output = onnx_model(im)[0]

diff = np.abs(pytorch_output - onnx_output).max()
print(f"Max difference: {diff:.6f}")  # typically ~1e-5, well under 1e-4 for FP32
Sai lệch kỳ vọng

Đối với các bản xuất FP32, sai số tuyệt đối tối đa thường ở mức khoảng 1e-5 và nên duy trì ở mức dưới 1e-4. Các sai số lớn hơn chỉ ra các toán tử không được hỗ trợ, sai hình dạng đầu vào hoặc model không ở chế độ eval. Các bản xuất FP16 và INT8 có ngưỡng dung sai lỏng hơn. Hãy xác thực trên dữ liệu thực tế thay vì các tensor ngẫu nhiên.

Đối với các runtime khác, tên tensor đầu vào có thể khác nhau. Ví dụ, OpenVINO sử dụng tên tham số forward của mô hình (thường là x đối với các mô hình chung), trong khi torch2onnx mặc định là "images".

Link to this sectionCác hạn chế đã biết#

  • Hỗ trợ nhiều đầu vào không đồng đều: torch2onnxtorch2openvino chấp nhận một tuple hoặc danh sách các tensor ví dụ cho các mô hình có nhiều đầu vào. torch2torchscript, torch2coreml, torch2ncnn, torch2paddle, và torch2executorch giả định một tensor đầu vào duy nhất.
  • ExecuTorch cần flatc: Runtime ExecuTorch yêu cầu trình biên dịch FlatBuffers. Hãy cài đặt bằng lệnh brew install flatbuffers trên macOS hoặc apt install flatbuffers-compiler trên Ubuntu.
  • Không suy luận thông qua Ultralytics: Các mô hình không phải YOLO đã xuất không thể được tải lại thông qua YOLO() để suy luận. Hãy sử dụng runtime gốc cho từng định dạng (ONNX Runtime, OpenVINO Runtime, v.v.).
  • Các định dạng chỉ dành cho YOLO: Các bản xuất AxeleraSony IMX500 yêu cầu các thuộc tính mô hình đặc thù của YOLO và không khả dụng cho các mô hình chung.
  • Các định dạng đặc thù nền tảng: TensorRT yêu cầu GPU NVIDIA. RKNN yêu cầu SDK rknn-toolkit2 (chỉ dành cho Linux). Edge TPU yêu cầu tệp nhị phân edgetpu_compiler (chỉ dành cho Linux).

Link to this sectionKết luận#

Các tiện ích này nhận bất kỳ model PyTorch nào từ torch.nn.Module cơ bản sang các artifact sẵn sàng triển khai trên ONNX, OpenVINO, CoreML, TensorFlow hoặc mobile-runtime thông qua một API nhất quán. Hãy chọn định dạng phù hợp với phần cứng mục tiêu của bạn, xác minh sự tương đương số học so với model gốc, sau đó làm theo hướng dẫn tích hợp phù hợp cho các bước triển khai cụ thể của từng runtime.

Link to this sectionCâu hỏi thường gặp#

Link to this sectionTôi có thể xuất những mô hình nào với Ultralytics?#

Bất kỳ torch.nn.Module nào. Điều này bao gồm các mô hình từ timm, torchvision hoặc bất kỳ mô hình PyTorch tùy chỉnh nào. Mô hình phải ở chế độ đánh giá (model.eval()) trước khi xuất. ONNX và OpenVINO cũng chấp nhận một tuple các tensor ví dụ cho các mô hình nhiều đầu vào.

Link to this sectionĐịnh dạng xuất nào hoạt động mà không cần GPU?#

Tất cả các định dạng được hỗ trợ (TorchScript, ONNX, OpenVINO, CoreML, TF SavedModel, TF Frozen Graph, NCNN, PaddlePaddle, MNN, ExecuTorch) đều có thể xuất trên CPU. Không cần GPU cho chính quá trình xuất. TensorRT là định dạng duy nhất yêu cầu GPU NVIDIA.

Link to this sectionTôi cần phiên bản Ultralytics nào?#

Hãy sử dụng Ultralytics >=8.4.38, bao gồm module ultralytics.utils.export và các đối số tiêu chuẩn output_file/output_dir.

Link to this sectionTôi có thể xuất mô hình torchvision sang CoreML để triển khai trên iOS không?#

Có. Các mô hình phân loại (classifiers), phát hiện (detectors) và phân đoạn (segmentation) của torchvision được xuất sang .mlpackage thông qua torch2coreml. Đối với các mô hình phân loại ảnh, hãy chuyển một danh sách tên lớp vào classifier_names để tích hợp đầu phân loại (classification head). Chạy quá trình xuất trên macOS hoặc Linux. CoreML không được hỗ trợ trên Windows. Xem Tích hợp CoreML để biết chi tiết triển khai trên iOS.

Link to this sectionTôi có thể định lượng (quantize) mô hình đã xuất của mình sang INT8 hoặc FP16 không?#

Có, đối với một số định dạng. Sử dụng quantize=16 cho FP16 hoặc quantize=8 cho INT8 khi xuất sang OpenVINO, CoreML, MNN hoặc NCNN. INT8 trong OpenVINO yêu cầu thêm đối số calibration_dataset cho post-training quantization. Xem trang tích hợp của từng định dạng để biết các đánh đổi về lượng tử hóa.

Link to this sectionLàm thế nào để xác minh một model đã xuất khớp với model gốc?#

Chạy model PyTorch gốc và model đã xuất trên cùng một đầu vào, sau đó so sánh kết quả đầu ra. Tải file đã xuất bằng backend tương ứng (ví dụ: ONNXBackend cho ONNX) và kiểm tra sai số tuyệt đối tối đa. Đối với các bản xuất FP32, sai số thường ở mức khoảng 1e-5 và nên duy trì ở mức dưới 1e-4; các khoảng cách lớn hơn chỉ ra các toán tử không được hỗ trợ, sai hình dạng đầu vào hoặc model không ở chế độ eval. Xem Xác minh Model đã xuất của bạn để có ví dụ chạy thử.

Bình luận