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, ExecuTorch và TensorFlow 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ạng | Hàm | Cài đặt | Đầu ra |
|---|---|---|---|
| ONNX | torch2onnx() | pip install onnx | tệp .onnx |
| TorchScript | torch2torchscript() | được bao gồm trong PyTorch | tệp .torchscript |
| OpenVINO | torch2openvino() | pip install openvino | thư mục _openvino_model/ |
| CoreML | torch2coreml() | pip install coremltools | .mlpackage |
| TF SavedModel | onnx2saved_model() | xem các yêu cầu chi tiết bên dưới | thư mục _saved_model/ |
| TF Frozen Graph | keras2pb() | xem các yêu cầu chi tiết bên dưới | tệp .pb |
| NCNN | torch2ncnn() | pip install ncnn pnnx | thư mục _ncnn_model/ |
| MNN | onnx2mnn() | pip install MNN | tệp .mnn |
| PaddlePaddle | torch2paddle() | pip install paddlepaddle x2paddle | thư mục _paddle_model/ |
| ExecuTorch | torch2executorch() | pip install executorch | thư mục _executorch_model/ |
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.
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)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.xml và model.bin với tên cố định:
resnet18_openvino_model/
├── model.xml
└── model.binTruyề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.11 và numpy<=2.3.5. Không hỗ trợ trên Windows.
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.tfliteYêu cầu:
tensorflow>=2.0.0,<=2.19.0onnx2tf>=1.26.3,<1.29.0tf_keras<=2.19.0sng4onnx>=1.0.1onnx_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.0trên macOS (ai-edge-litert>=1.2.0trên các nền tảng khác)onnxslim>=0.1.71onnx>=1.12.0,<2.0.0protobuf>=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.pytorch2ncnn() kiểm tra ncnn và pnnx 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.6 và torch>=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.pdiparamsYê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.0trên CUDApaddlepaddle==3.0.0trên ARM64 CPUpaddlepaddle>=3.0.0,<3.3.0trê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.pteYê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Đố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:
torch2onnxvàtorch2openvinochấ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,torch2paddlevàtorch2executorchgiả đị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ằngbrew install flatbufferstrên macOS hoặcapt install flatbuffers-compilertrê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 Axelera và Sony 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ânedgetpu_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.