🤖 AI/ML

ONNX

Open Neural Network Exchange

프레임워크 간 모델 호환을 위한 개방형 포맷. PyTorch, TensorFlow 간 변환.

📖 상세 설명

ONNX(Open Neural Network Exchange)는 딥러닝 모델을 다양한 프레임워크와 하드웨어에서 실행할 수 있게 해주는 개방형 표준 포맷입니다. PyTorch에서 학습한 모델을 TensorFlow에서 추론하거나, 모바일/엣지 디바이스에 배포할 때 중간 포맷으로 활용됩니다.

2017년 Facebook과 Microsoft가 공동 발표했으며, 이후 Amazon, Google, NVIDIA 등 주요 기업이 참여하는 Linux Foundation 프로젝트가 되었습니다. 프레임워크 종속성 없이 모델을 이식할 수 있어, ML 생태계의 표준으로 자리잡았습니다.

ONNX는 모델의 계산 그래프와 연산자(Operator)를 표준화된 형식으로 저장합니다. ONNX Runtime은 Microsoft가 개발한 추론 엔진으로, CPU/GPU/NPU 등 다양한 하드웨어에서 최적화된 추론을 지원하며, 평균 2-3배 추론 속도 향상을 제공합니다.

실무에서 ONNX는 모델 서빙(배포) 단계에서 핵심입니다. PyTorch로 연구/개발하고, ONNX로 변환하여 TensorRT(NVIDIA), OpenVINO(Intel), CoreML(Apple) 등 타겟 플랫폼에 최적화해 배포하는 워크플로우가 일반적입니다.

💻 코드 예제

# ONNX 변환 및 추론 예제
# pip install torch onnx onnxruntime

import torch
import torch.nn as nn
import onnx
import onnxruntime as ort
import numpy as np

# ===== 1. PyTorch 모델 정의 =====
class SimpleModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10, 64)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(64, 2)

    def forward(self, x):
        x = self.relu(self.fc1(x))
        return self.fc2(x)

model = SimpleModel()
model.eval()

# ===== 2. ONNX로 변환 =====
dummy_input = torch.randn(1, 10)  # 예시 입력

torch.onnx.export(
    model,                        # 모델
    dummy_input,                  # 예시 입력
    "model.onnx",                 # 출력 파일
    export_params=True,           # 가중치 포함
    opset_version=17,             # ONNX opset 버전
    input_names=['input'],        # 입력 이름
    output_names=['output'],      # 출력 이름
    dynamic_axes={                # 동적 배치 크기
        'input': {0: 'batch_size'},
        'output': {0: 'batch_size'}
    }
)
print("ONNX 모델 저장 완료: model.onnx")

# ===== 3. ONNX 모델 검증 =====
onnx_model = onnx.load("model.onnx")
onnx.checker.check_model(onnx_model)
print("ONNX 모델 검증 통과!")

# 모델 구조 확인
print(onnx.helper.printable_graph(onnx_model.graph))

# ===== 4. ONNX Runtime으로 추론 =====
# 세션 생성 (GPU 사용시: providers=['CUDAExecutionProvider'])
session = ort.InferenceSession(
    "model.onnx",
    providers=['CPUExecutionProvider']
)

# 추론 실행
input_data = np.random.randn(5, 10).astype(np.float32)
outputs = session.run(None, {'input': input_data})
print(f"추론 결과 shape: {outputs[0].shape}")

# ===== 5. 성능 비교 =====
import time

# PyTorch 추론 시간
torch_input = torch.from_numpy(input_data)
start = time.time()
for _ in range(1000):
    _ = model(torch_input)
pytorch_time = time.time() - start

# ONNX Runtime 추론 시간
start = time.time()
for _ in range(1000):
    _ = session.run(None, {'input': input_data})
onnx_time = time.time() - start

print(f"PyTorch: {pytorch_time:.3f}s, ONNX Runtime: {onnx_time:.3f}s")
print(f"속도 향상: {pytorch_time/onnx_time:.2f}x")

🗣️ 실무에서 이렇게 말하세요

💬 배포 계획 회의에서
"PyTorch 모델을 프로덕션에 배포할 때 ONNX로 변환하면 ONNX Runtime으로 2-3배 빠른 추론이 가능합니다. NVIDIA GPU면 TensorRT, Intel CPU면 OpenVINO로 추가 최적화할 수 있고요."
💬 면접에서
"ONNX는 딥러닝 모델의 개방형 표준 포맷으로, 프레임워크 간 이식성을 제공합니다. 계산 그래프와 연산자를 표준화해서 저장하고, ONNX Runtime으로 다양한 하드웨어에서 최적화된 추론이 가능합니다. 실무에서는 주로 PyTorch 학습 후 서빙 단계에서 변환합니다."
💬 문제 해결 상황에서
"변환 중 에러가 나면 opset 버전 문제일 수 있어요. opset_version을 낮춰보거나, 지원 안 되는 연산자가 있으면 torch.onnx.register_custom_op_symbolic으로 커스텀 매핑을 해야 합니다."

⚠️ 흔한 실수 & 주의사항

모든 PyTorch 연산이 지원된다고 가정

일부 커스텀 연산이나 최신 연산자는 ONNX에서 지원되지 않을 수 있습니다. 변환 전 호환성을 확인하세요.

변환 후 정확도 검증 생략

변환 과정에서 수치 오차가 발생할 수 있습니다. 반드시 동일 입력에 대해 원본과 ONNX 모델의 출력을 비교하세요.

올바른 접근법

변환 전 onnx.checker로 검증하고, 동일 입력에 대한 출력 차이를 np.allclose()로 확인하세요. dynamic_axes를 설정해 배치 크기 유연성을 확보하세요.

🔗 관련 용어

📚 더 배우기