Meet YOLO26: next-gen vision AI.

Link to this sectionCách xuất mô hình PyTorch không phải YOLO bằng Ultralytics#

Việc triển khai các mô hình PyTorch vào môi trường production thường đòi hỏi phải sử dụng những trình xuất (exporter) 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 đặc thù về phụ thuộc và quy ước đầu ra khác nhau.

Ultralytics cung cấp các tiện ích xuất độc lập, bao bọc nhiều backend dưới 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 mô hình hình ảnh timm, các bộ phân loại và phát hiện torchvision, hoặc các kiến trúc tùy chỉnh của riêng bạn sang ONNX, TorchScript, OpenVINO, CoreML, NCNN, PaddlePaddle, MNN, ExecuTorchTensorFlow SavedModel mà không cần phải tìm hiểu riêng biệt từng backend.

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

  • Một API cho 10 định dạng: chỉ cần học một quy ước gọi hàm duy nhất thay vì hàng tá quy ước.
  • Bề mặt tiện ích chia sẻ: các trình hỗ trợ xuất nằm trong ultralytics.utils.export, vì vậy khi các gói backend đã được cài đặt, bạn có thể duy trì cùng một kiểu gọi hàm trên nhiều định dạng.
  • Cùng quy trình mã nguồn như xuất YOLO: các trình hỗ trợ tương tự cung cấp sức mạnh cho mọi tiến trình 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 cục bộ trên bất kỳ máy tính xách tay nào.

Link to this sectionBắt đầu nhanh#

Cách nhanh nhất là thực hiện xuất hai dòng lệnh sang ONNX mà không cần mã 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 tiêu chuẩn và một tensor đầu vào ví dụ. MNN, TF SavedModel và TF Frozen Graph đi qua một artifact trung gian là ONNX hoặc Keras. Không yêu cầu các thuộc tính cụ thể của YOLO trong cả hai trường hợp.

Định dạngHàmCài đặtĐầu ra
ONNXtorch2onnx()pip install onnxtệp .onnx
TorchScripttorch2torchscript()được bao gồm trong PyTorchtệp .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ướitệp .pb
NCNNtorch2ncnn()pip install ncnn pnnxthư mục _ncnn_model/
MNNonnx2mnn()pip install MNNtệp .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

Việc xuất MNN, TF SavedModel và TF Frozen Graph sẽ thông 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 siêu dữ liệu (metadata)

Một số hàm xuất chấp nhận một từ điển metadata tùy chọn (ví dụ: torch2torchscript(..., metadata={"author": "me"})) giúp 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 mô hình ResNet-18 tiền huấn luyệ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 lớp chỉ dành cho train khác sẽ hoạt động khác biệt trong quá trình inference. Việc bỏ qua .eval() sẽ dẫn đến các kết quả xuất 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 batch size động, hãy truyền một từ điển 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 đối số opset, input_names hoặc output_names.

Link to this sectionXuất sang TorchScript#

Không cần thêm phụ thuộc nào. 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 cặp tệp model.xmlmodel.bin với tên cố định:

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

Truyền dynamic=True cho hình dạng đầu vào động, half=True cho FP16, hoặc int8=True 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, output_file="resnet18.mlpackage")

Đối với các mô hình classification, hãy truyền một danh sách tên lớp vào classifier_names để thêm một đầu phân loại vào mô hình 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, tiện ích 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ẽ thông 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 mô hình Keras và cũng tạo các tệp 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.71
  • onnx>=1.12.0,<2.0.0
  • protobuf>=5

Link to this sectionXuất sang TensorFlow Frozen Graph#

Tiếp tục từ việc xuất SavedModel ở trên, chuyển đổi mô hình Keras trả về thành một đồ thị .pb đóng băng:

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 tệp param và bin có tên cố định cùng với một trình bao bọc 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#

Việc xuất MNN yêu cầu một tệp ONNX làm đầu vào. Hãy xuất sang ONNX trước, sau đó 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ợ half=True cho FP16 và int8=True 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 mô hình PaddlePaddle và các tệp tham số:

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

Yêu cầu x2paddle và bản phân phối PaddlePaddle chính xác 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 ARM64 CPU
  • paddlepaddle>=3.0.0,<3.3.0 trên các CPU khác

Không 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 được xuất sẽ 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ôi trường thực thi 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ề số học với mô hình PyTorch gốc trước khi triển khai. Một bài kiểm tra nhanh (smoke test) với ONNXBackend từ ultralytics.nn.backends sẽ so sánh kết quả đầu ra và gắn cờ các lỗi tracing hoặc quantization sớm:

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}")  # should be < 1e-5
Sai số dự kiến

Đối với xuất FP32, sai số tuyệt đối tối đa phải dưới 1e-5. Các sai số lớn hơn cho thấy các toán tử không được hỗ trợ, hình dạng đầu vào không chính xác hoặc mô hình không ở chế độ eval. Các bản xuất FP16 và INT8 có sai số cho phép nới lỏng hơn. Hãy xác thực trên dữ liệu thực 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 đối số forward của mô hình (thường là x cho 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ợ đa đầ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, torch2paddletorch2executorch giả định một tensor đầu vào duy nhất.
  • ExecuTorch cần flatc: Môi trường thực thi ExecuTorch yêu cầu trình biên dịch FlatBuffers. Hãy cài đặt bằng brew install flatbuffers trên macOS hoặc apt install flatbuffers-compiler trên Ubuntu.
  • Không hỗ trợ inference thông qua Ultralytics: Các mô hình không phải YOLO sau khi 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: Việc xuất sang 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 sectionCâu hỏi thường gặp (FAQ)#

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 đa đầ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ố chuẩn hóa 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, phát hiện và phân đoạn của torchvision xuất sang .mlpackage thông qua torch2coreml. Đối với các mô hình phân loại hình ảnh, hãy chuyển một danh sách tên lớp vào classifier_names để tích hợp classification head. Thực hiện 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 về triển khai trên iOS.

Link to this sectionTôi có thể lượng tử hóa (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. Chuyển half=True cho FP16 hoặc int8=True 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 để lượng tử hóa sau huấn luyện. Xem trang tích hợp của từng định dạng để biết các ưu nhược điểm về lượng tử hóa.

Bình luận