Ultralytics로 YOLO가 아닌 PyTorch 모델 내보내기#
Ultralytics는 ultralytics.utils.export 아래에 독립형 내보내기 유틸리티를 제공하며, 여러 백엔드를 하나의 일관된 인터페이스로 통합합니다. timm 이미지 모델, torchvision 분류기 및 검출기, 자체 맞춤 아키텍처 등 모든 torch.nn.Module를 각 백엔드를 별도로 익히지 않고도 TorchScript, ONNX, OpenVINO, CoreML, Core AI, TensorFlow SavedModel, TensorFlow Frozen Graph, PaddlePaddle, MNN, NCNN 및 ExecuTorch로 내보낼 수 있습니다.
PyTorch 모델을 프로덕션 환경에 배포하려면 일반적으로 대상 플랫폼마다 다른 내보내기 도구를 사용해야 합니다. ONNX에는 torch.onnx.export, Apple 기기에는 coremltools, TensorFlow에는 onnx2tf, NCNN에는 pnnx 등을 사용합니다. 도구마다 API, 종속성 관련 특이 사항 및 출력 규칙이 다릅니다. 이러한 유틸리티는 이 모든 과정을 하나의 호출 패턴으로 통합합니다.
YOLO가 아닌 모델 내보내기에 Ultralytics를 사용하는 이유#
- 11개 형식에서 하나의 API 사용: 여러 호출 규칙을 익히는 대신 하나만 익히면 됩니다.
- YOLO 내보내기와 동일한 코드 경로: 모든 Ultralytics YOLO 내보내기에 동일한 헬퍼가 사용됩니다.
- FP16 및 INT8 양자화: 이를 지원하는 형식에서는
quantize인수 하나로 처리할 수 있습니다. - CPU에서 작동: 내보내기 단계 자체에는 GPU가 필요하지 않으므로 로컬 노트북에서 실행할 수 있습니다. CoreML 내보내기는 Windows에서 지원되지 않으며, Core AI 내보내기는 macOS 26 이상이 설치된 Apple silicon 또는 glibc 2.34 이상을 사용하는 x86_64 Linux에서 Python 3.11~3.14로 실행해야 합니다.
빠른 시작#
가장 빠른 방법은 YOLO 코드 없이 pip install ultralytics onnx timm만 설치하여 ONNX로 두 줄의 코드를 사용해 내보내는 것입니다.
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")지원되는 내보내기 형식#
torch2* 함수는 표준 torch.nn.Module과 예제 입력 텐서를 받습니다. MNN, TF SavedModel 및 TF Frozen Graph는 중간 단계에서 ONNX 또는 Keras 아티팩트를 사용합니다. 두 경우 모두 YOLO 전용 속성은 필요하지 않습니다.
| 형식 | 함수 | 설치 | 출력 |
|---|---|---|---|
| TorchScript | torch2torchscript() | PyTorch에 포함됨 | .torchscript 파일 |
| ONNX | torch2onnx() | pip install onnx | .onnx 파일 |
| OpenVINO | torch2openvino() | pip install openvino | _openvino_model/ 디렉터리 |
| CoreML | torch2coreml() | pip install coremltools | .mlpackage |
| Core AI | torch2coreai() | pip install coreai-torch (Apple silicon macOS 26+, x86_64 Linux glibc 2.34+; Python 3.11-3.14) | .aimodel 디렉터리 |
| TF SavedModel | onnx2saved_model() | 아래에서 자세한 요구 사항 확인 | _saved_model/ 디렉터리 |
| TF Frozen Graph | keras2pb() | 아래에서 자세한 요구 사항 확인 | .pb 파일 |
| PaddlePaddle | torch2paddle() | pip install paddlepaddle x2paddle | _paddle_model/ 디렉터리 |
| MNN | onnx2mnn() | pip install MNN | .mnn 파일 |
| NCNN | torch2ncnn() | pip install ncnn pnnx | _ncnn_model/ 디렉터리 |
| ExecuTorch | torch2executorch() | pip install executorch | _executorch_model/ 디렉터리 |
일부 내보내기 함수는 선택적인 metadata 딕셔너리(예: torch2torchscript(..., metadata={"author": "me"}))를 받아 형식에서 지원하는 경우 내보낸 아티팩트에 사용자 지정 키-값 쌍을 임베딩합니다.
단계별 예제#
아래 예제는 모두 동일한 설정을 사용합니다. 평가 모드의 사전 학습된 timm ResNet-18입니다.
import timm
import torch
model = timm.create_model("resnet18", pretrained=True).eval()
im = torch.randn(1, 3, 224, 224)Dropout, 배치 정규화 및 기타 학습 전용 레이어는 추론 중에 다르게 동작합니다. .eval()을 건너뛰면 출력이 잘못된 내보내기 결과가 생성됩니다.
ONNX로 내보내기#
from ultralytics.utils.export import torch2onnx
torch2onnx(model, im, output_file="resnet18.onnx")동적 배치 크기를 사용하려면 dynamic 딕셔너리를 전달합니다.
torch2onnx(model, im, output_file="resnet18_dyn.onnx", dynamic={"images": {0: "batch_size"}})기본 opset은 14이고 기본 입력 이름은 "images"입니다. opset, input_names 또는 output_names 인수로 재정의할 수 있습니다.
TorchScript로 내보내기#
추가 종속성은 필요하지 않습니다. 내부적으로 torch.jit.trace을 사용합니다.
from ultralytics.utils.export import torch2torchscript
torch2torchscript(model, im, output_file="resnet18.torchscript")OpenVINO로 내보내기#
from ultralytics.utils.export import torch2openvino
ov_model = torch2openvino(model, im, output_dir="resnet18_openvino_model")디렉터리에는 이름이 고정된 model.xml 및 model.bin 쌍이 포함됩니다.
resnet18_openvino_model/
├── model.xml
└── model.bin동적 입력 형태에는 dynamic=True, FP16에는 quantize=16, INT8 양자화에는 quantize=8를 전달합니다. INT8에는 calibration_dataset 인수도 필요합니다.
openvino>=2024.0.0(또는 macOS 15.4 이상에서는 >=2025.2.0) 및 torch>=2.1가 필요합니다.
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")분류 모델의 경우 클래스 이름 목록을 classifier_names에 전달하여 CoreML 모델에 분류 헤드를 추가합니다.
coremltools>=9.0, torch>=1.11 및 numpy<=2.3.5가 필요합니다. Windows에서는 지원되지 않습니다.
coremltools>=9.0은 macOS 및 Linux용 Python 3.10~3.13 휠을 제공합니다. 더 최신 Python 버전에서는 네이티브 C 확장 모듈을 불러오지 못합니다. CoreML 내보내기에는 Python 3.10~3.13을 사용하세요.
Core AI로 내보내기#
from ultralytics.utils.export import torch2coreai
torch2coreai(model, im, output_file="resnet18.aimodel").aimodel 에셋은 디렉터리입니다.
resnet18.aimodel/
├── main.mlirb
├── main.hash
└── metadata.json내보내기는 Apple silicon의 macOS 26 이상 또는 glibc 2.34 이상을 사용하는 x86_64 Linux에서 Python 3.11~3.14(pip install coreai-torch)로 실행됩니다. quantize=16은 float16 입력을 받는 FP16 에셋을 작성하며, 이 에셋은 iOS 27 및 macOS 27에서 실행됩니다. 로드 중 중단되는 FP16 에셋에 대한 설명을 포함한 Core AI 통합을 참고하세요.
TensorFlow SavedModel로 내보내기#
TF SavedModel 내보내기는 중간 단계에서 ONNX를 사용합니다.
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")이 함수는 Keras 모델을 반환하고 출력 디렉터리 내에 FP32 및 FP16 LiteRT 파일(.tflite)도 생성합니다.
resnet18_saved_model/
├── saved_model.pb
├── variables/
├── assets/
├── fingerprint.pb
├── resnet18_float32.tflite
└── resnet18_float16.tflitequantize=8을 전달하면 해당 파일과 함께 INT8 .tflite이 추가됩니다.
TensorFlow 내보내기는 Python 3.13 이상이 설치된 macOS에서 실행되지 않습니다. macOS에서는 Python 3.12 이하를 사용하거나 Linux에서 실행하세요.
Python 3.12 이하에서의 요구 사항(Python 3.13 이상에서는 내보내기에 대신 tensorflow>2.19.0, tf_keras>2.19.0, onnx2tf>=2.3.0,<2.3.16 및 protobuf>=6.31.1,<7.0.0이 필요합니다):
tensorflow>=2.0.0,<=2.19.0onnx2tf>=1.26.3,<1.29.0tf_keras<=2.19.0sng4onnx>=1.0.1onnx_graphsurgeon>=0.3.26- macOS에서는
ai-edge-litert>=1.2.0,<1.4.0(다른 플랫폼에서는ai-edge-litert>=1.2.0) onnxslim>=0.1.82onnx>=1.12.0,<2.0.0protobuf>=5
TensorFlow Frozen Graph로 내보내기#
위에서 내보낸 SavedModel을 이어서 사용하여 반환된 keras_model을 frozen .pb 그래프로 변환합니다.
from pathlib import Path
from ultralytics.utils.export import keras2pb
keras2pb(keras_model, output_file=Path("resnet18_saved_model/resnet18.pb"))NCNN으로 내보내기#
from ultralytics.utils.export import torch2ncnn
torch2ncnn(model, im, output_dir="resnet18_ncnn_model")디렉터리에는 이름이 고정된 param 및 bin 파일과 Python 래퍼가 포함됩니다.
resnet18_ncnn_model/
├── model.ncnn.param
├── model.ncnn.bin
└── model_ncnn.pyMNN으로 내보내기#
MNN으로 내보내려면 입력으로 ONNX 파일이 필요합니다. 먼저 ONNX로 내보낸 다음 변환합니다.
from ultralytics.utils.export import onnx2mnn, torch2onnx
torch2onnx(model, im, output_file="resnet18.onnx")
onnx2mnn("resnet18.onnx", output_file="resnet18.mnn")FP16의 경우 quantize=16, INT8 양자화의 경우 quantize=8을 지원합니다. MNN>=2.9.6와 torch>=1.10이 필요합니다.
PaddlePaddle로 내보내기#
from ultralytics.utils.export import torch2paddle
torch2paddle(model, im, output_dir="resnet18_paddle_model")디렉터리에는 PaddlePaddle 모델과 파라미터 파일이 포함됩니다:
resnet18_paddle_model/
├── inference_model/
│ ├── model.json
│ └── model.pdiparams
├── model.pdparams
└── x2paddle_code.pyx2paddle과 플랫폼에 맞는 PaddlePaddle 배포판이 필요합니다:
- CUDA에서
paddlepaddle-gpu>=3.0.0,<3.3.0 - ARM64 CPU에서
paddlepaddle==3.0.0 - 기타 CPU에서
paddlepaddle>=3.0.0,<3.3.0
NVIDIA Jetson에서는 지원되지 않습니다.
ExecuTorch로 내보내기#
from ultralytics.utils.export import torch2executorch
torch2executorch(model, im, output_dir="resnet18_executorch_model")내보낸 .pte 파일은 출력 디렉터리에 저장됩니다:
resnet18_executorch_model/
└── model.ptetorch>=2.9.0과 호환되는 ExecuTorch 런타임(pip install executorch)이 필요합니다. 런타임 사용법은 ExecuTorch 통합 가이드를 참조하세요.
내보낸 모델 확인#
내보낸 후 배포하기 전에 원본 PyTorch 모델과 수치적 일치 여부를 확인하세요. ultralytics.nn.backends의 ONNXBackend을 사용한 간단한 스모크 테스트로 출력을 비교하고 트레이싱 또는 양자화 오류를 조기에 확인할 수 있습니다:
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}") # ~1e-5 for an FP32 ONNX exportResNet-18의 경우 대부분의 FP32 내보내기 결과는 PyTorch와 비교해 약 1e-5 이내의 차이를 보이며, TorchScript는 정확히 일치합니다. 하지만 세 가지 런타임은 FP32 내보내기를 낮은 정밀도로 계산해 1e-2에서 1e-1 사이의 차이를 보일 수 있습니다. NCNN은 지원하는 CPU에서 FP16 연산을 활성화하고, MNNBackend은 precision="low"로 모델을 로드하며, OpenVINO CPU 플러그인은 Apple 실리콘과 같은 일부 하드웨어에서 기본 PERFORMANCE 실행 모드로 FP16을 자동 실행합니다. 해당 형식 자체의 기준치보다 훨씬 큰 차이는 지원되지 않는 연산, 잘못된 입력 형태 또는 평가 모드가 아닌 모델을 가리킵니다. FP16 및 INT8 내보내기에는 더 넓은 허용 오차가 적용됩니다. 무작위 텐서가 아닌 실제 데이터로 검증하세요.
다른 런타임에서는 입력 텐서 이름이 다를 수 있습니다. 예를 들어 OpenVINO는 모델의 forward 인자 이름(일반 모델에서는 보통 x)을 사용하지만, torch2onnx의 기본값은 "images"입니다.
내보낸 모델 실행#
내보낸 비-YOLO 모델은 일반 YOLO() API를 통해 다시 로드할 수 있습니다. 위의 내보내기 결과에는 Ultralytics 작업 또는 입력 크기 메타데이터가 포함되지 않으므로, task을 명시적으로 전달하고 imgsz에는 내보내기에 사용한 예제 텐서에 맞는 값을 전달하세요:
from ultralytics import YOLO
results = YOLO("resnet18.onnx", task="classify")("path/to/image.jpg", imgsz=224)
print(results[0].probs.top1)내보내기에 고정 입력 형태가 있는 경우 imgsz이 중요합니다. 위의 ONNX 및 TF SavedModel 내보내기는 기본값 640을 거부합니다. 위의 TorchScript 및 NCNN 내보내기는 다른 크기도 허용하지만, 두 내보내기 도구 모두 이를 보장하지는 않습니다. 둘 다 예제 텐서로 트레이싱하므로, Linear 레이어로 평탄화되는 모델은 고정된 상태로 유지됩니다. 직접 내보내기 결과를 확인하세요.
이 값은 모델 스트라이드의 배수로 올림 처리됩니다. 메타데이터가 없으면 스트라이드는 32입니다. 따라서 200x200 크기의 고정 형태 내보내기에는 224x224가 입력되어 거부됩니다. imgsz=200이 일치하더라도 마찬가지입니다. 32의 배수가 아닌 입력 크기를 사용하려면 백엔드를 직접 호출하세요.
백엔드 직접 호출#
Ultralytics 전처리 및 후처리를 거치지 않은 원시 텐서를 사용하려면 위의 검증 예제처럼 ultralytics.nn.backends에 있는 형식별 클래스를 사용하세요. 각 클래스에는 내보낸 아티팩트와 디바이스를 전달하며, 호출할 수 있습니다:
| 형식 | 백엔드 | 입력 레이아웃 |
|---|---|---|
| TorchScript | TorchScriptBackend | BCHW |
| ONNX | ONNXBackend | BCHW |
| OpenVINO | OpenVINOBackend | BCHW |
| CoreML | CoreMLBackend | BHWC |
| Core AI | CoreAIBackend | BCHW |
| TF SavedModel, Frozen Graph | TensorFlowBackend | BHWC |
| LiteRT | LiteRTBackend | BCHW |
| PaddlePaddle | PaddleBackend | BCHW |
| MNN | MNNBackend | BCHW |
| NCNN | NCNNBackend | BCHW |
| ExecuTorch | ExecuTorchBackend | BCHW |
TensorFlowBackend은 두 형식을 지원하며 기본값은 format="saved_model"이므로, Frozen Graph에는 format="pb"를 전달하세요.
YOLO() 경로에서 처리하지만 직접 호출할 때는 처리하지 않는 사항은 다음 세 가지입니다:
- 입력 레이아웃:
CoreMLBackend과TensorFlowBackend은 BHWC를 기대합니다. 먼저im.permute(0, 2, 3, 1)로 전치하세요. BCHW 텐서를 전달하면 형태 불일치 오류가 발생합니다. - Autograd: 호출을
torch.inference_mode()으로 감싸세요.TorchScriptBackend은 그래디언트 그래프가 여전히 연결된 텐서를 반환합니다. - 후처리: 메타데이터가 없으면 백엔드는
task을None로 남기고names는 비워 둡니다.LiteRTBackend은 3차원 출력이 YOLO 박스를 담고 있다고 가정하여 이미지 크기로 역정규화합니다. 따라서 3차원 출력을 가진 비-YOLO 모델에서는 잘못된 결과가 됩니다. 분류 로짓과 같은 2차원 출력은 영향을 받지 않습니다.
알려진 제한 사항#
- 다중 입력 지원은 형식마다 다릅니다:
torch2onnx,torch2openvino,torch2torchscript는 입력이 여러 개인 모델을 위해 예제 텐서의 튜플을 받습니다.torch2coreml,torch2coreai,torch2ncnn,torch2paddle,torch2executorch은 단일 입력 텐서를 전제로 합니다. - YOLO 전용 형식: Axelera 및 Sony IMX500 내보내기에는 YOLO 전용 모델 속성이 필요하므로 일반 모델에서는 사용할 수 없습니다.
- 플랫폼별 형식: TensorRT에는 NVIDIA GPU가 필요합니다. RKNN에는
rknn-toolkit2SDK가 필요합니다(Linux만 지원). Edge TPU에는edgetpu_compiler바이너리가 필요합니다(x86_64 Linux만 지원).
결론#
이 유틸리티를 사용하면 일반 torch.nn.Module의 PyTorch 모델을 일관된 API를 통해 배포 가능한 ONNX, OpenVINO, CoreML, TensorFlow 또는 모바일 런타임 아티팩트로 변환할 수 있습니다. 대상 하드웨어에 맞는 형식을 선택하고 원본 모델과 수치적 일치 여부를 확인한 다음, 런타임별 배포 단계는 해당 통합 가이드를 따르세요.
자주 묻는 질문#
모든
torch.nn.Module을 지원합니다. 여기에는 timm, torchvision 또는 사용자 지정 PyTorch 모델이 포함됩니다. 내보내기 전에 모델을 평가 모드(model.eval())로 설정해야 합니다. ONNX, OpenVINO 및 TorchScript는 다중 입력 모델을 위해 예제 텐서의 튜플도 지원합니다.지원되는 모든 형식(TorchScript, ONNX, OpenVINO, CoreML, Core AI, TF SavedModel, TF Frozen Graph, PaddlePaddle, MNN, NCNN, ExecuTorch)은 CPU에서 내보낼 수 있습니다. 내보내기 과정 자체에는 GPU가 필요하지 않습니다. TensorRT만 NVIDIA GPU가 필요합니다.
최신 릴리스를 사용하세요.
quantize인자에는 Ultralytics>=8.4.81이 필요하며, Core AI 내보내기에는>=8.4.131가 필요합니다(Linux 또는coreai-torch>=0.4.3를 사용하는 경우>=8.4.163).예. torchvision 분류, 탐지 및 세그멘테이션 모델은
torch2coreml을 통해.mlpackage으로 내보낼 수 있습니다. 이미지 분류 모델의 경우 분류 헤드를 내장하려면 클래스 이름 목록을classifier_names에 전달하세요. macOS 또는 Linux에서 내보내기를 실행하세요. CoreML은 Windows에서 지원되지 않습니다. iOS 배포 세부 정보는 CoreML 통합 가이드를 참조하세요.예, 여러 형식에서 가능합니다. OpenVINO, CoreML 또는 MNN으로 내보낼 때 FP16에는
quantize=16, INT8에는quantize=8을 전달하세요.onnx2saved_model는 INT8 LiteRT 파일에quantize=8을 받습니다. NCNN과 Core AI는 기본적으로 FP32로 내보내며, FP16에는quantize=16를 전달할 수 있지만 INT8 경로는 없습니다. OpenVINO의 INT8에는 학습 후 양자화를 위한calibration_dataset인자도 필요합니다. 양자화의 장단점은 각 형식의 통합 페이지를 참조하세요.동일한 입력을 사용해 원본 PyTorch 모델과 내보낸 모델을 실행한 다음 출력을 비교하세요. 해당 백엔드(예: ONNX용
ONNXBackend)로 내보낸 파일을 로드하고 최대 절대 차이를 확인하세요. 차이를 해당 형식의 자체 기준치와 비교해 판단하세요. NCNN,MNNBackend, 일부 CPU에서 실행되는 OpenVINO는 FP32 내보내기를 낮은 정밀도로 실행해1e-2에서1e-1사이의 차이를 보일 수 있습니다. 반면 대부분의 다른 형식은1e-5에 가까운 차이를 보입니다. 훨씬 큰 차이는 지원되지 않는 연산, 잘못된 입력 형태 또는 평가 모드가 아닌 모델을 가리킵니다. 실행 가능한 예제는 내보낸 모델 확인을 참조하세요.