Technology
안녕하세요. AI 추론 최적화 엔진을 만들고 있는 Optimium 팀의 모세웅(Sewoong Moh)입니다. 다양한 프레임워크를 지원한다고 할 때, TensorFlow 및 PyTorch는 알겠지만 ONNX라는 낯선 이름 때문에 당황한 적 있으신가요? Come on Come on! 오늘은 ONNX가 정확하게 무엇인지 알아보도록 하겠습니다.
Sewoong Moh
2024년 2월 5일
안녕하세요. AI 추론 최적화 엔진을 만들고 있는 Optimium 팀의 모세웅(Sewoong Moh)입니다. 다양한 프레임워크를 지원한다고 할 때, TensorFlow 및 PyTorch는 알겠지만 ONNX라는 낯선 이름 때문에 당황한 적 있으신가요? Come on Come on! 오늘은 ONNX가 정확하게 무엇인지 알아보도록 하겠습니다.
ONNX란?
ONNX는 Open Neural Network Exchange의 약자로 서로 다른 ML 프레임워크에서 개발된 모델을 서로 호환할 수 있도록 하는 표준 모델 포맷입니다. ONNX는 Meta와 MicroSoft가 주도하여 개발한 오픈 소스 표준으로, 현재는 여러 회사와 연구 기관이 참여하여 공동으로 개발하고 있습니다. PyTorch나 TensorFlow와 같은 다양한 ML 프레임워크와 NVIDIA의 Jetson 플랫폼에서 적극적으로 지원되는 등 다양한 곳에서 활용도가 높아져 사실상 AI 모델 표준으로 인정받고 있습니다.
ONNX vs NNEF
ONNX 이전에 NNEF가 표준으로 제안된 바 있습니다. 둘은 유사한 목표를 가지고 있지만 아래와 같은 차이점이 있습니다.
그래프 접근 방식
ONNX: ONNX의 Protobuf는 정적 그래프 접근 방식에 더 적합합니다.
NNEF: NNEF의 절차적 구문은 동적 그래프 접근 방식에 더 적합합니다.
양자화된 네트워크 표현 방식
ONNX: 다양한 비트 폭의 정수 및 부동 소수점과 같은 활성화 Tensor에 대한 다양한 데이터 유형이 포함 됩니다.
NNEF: Independent Of Machine Representation에 초점을 맞추어 의도적으로 ONNX에서 사용 가능한 복합 유형을 지원하지 않습니다.
네트워크 표현 방식
ONNX: Single Protobuf로 표현합니다.
NNEF: 구조와 데이터를 분리하는 방식으로 데이터 매개변수는 별도의 바이너리 파일로 보내집니다.
ONNX는 NNEF와 달리, S/W 회사뿐 아니라 Intel, NVIDIA와 같은 H/W 회사도 참여하고 있습니다. 덕분에 ONNX는 다수의 ML 프레임워크를 지원합니다. 또한, ONNX는 NNEF에 비해 다수의 툴들이 존재하며, 코드 및 전체적인 활용도 면에서 우위를 점하고 있기 때문에 자연스럽게 많은 사용자들을 가지고 있습니다
ONNX 특징
사용자 편의 인터페이스
ONNX는 다른 ML 프레임워크와 마찬가지로 사용자들에게 최적화된 실행 시간과 Computation 그래프를 쉽게 구성할 수 있는 인터페이스를 제공합니다. 이러한 기본적인 기능과 더불어 다양한 프레임워크를 호환하여 사용자 편의 인터페이스가 뛰어난 편이며 수 년간 구축된 생태계 덕분에 다양한 툴과 기능들이 존재합니다.
ONNX-MLIR
해당 기능을 파악하기 위해서는 MLIR에 대한 이해가 필요합니다.
MLIR
Multi-Level Intermediate Representation의 줄임말로, LLVM 프로젝트에서 개발 중인, 컴파일러 개발 프레임워크입니다. 프로그래밍 언어를 LLVM 중간 언어(IR)로 변환하기 이전, 사용자가 직접 IR을 Multi-Level로 정의할 수 있도록 도구와 편리한 방법론을 제공합니다. 사용자들은 직접 정의한 IR로 범용 프로그래밍 언어에서 구현하기 어려운 고수준(High Level)의 최적화를 진행함으로써, 보다 높은 성능의 언어 개발을 목표로 합니다. 이후 블로그 게시물을 통해 MLIR에 대해서 보다 더 자세하게 설명드리겠습니다.
ONNX에서 제공하는 기능 중 하나는 ONNX Dialect를 정의하여 ONNX를 MLIR IR, LLVM IR 등의 중간 IR로 Lowering하고 Object 파일로 빌드할 수 있는 기능입니다. 이를 통해 사용자는 사용자의 ONNX 모델을 최소한의 Runtime 지원을 통해 사용자의 타겟 하드웨어에 탑재할 수 있습니다. 생성된 중간 IR을 토대로 사용자가 고유의 최적화 Pass를 구현하고 적용할 수 있어 백엔드 처리의 자유도를 제공할 수 있습니다.

사용 단계
ONNX 그래프가 입력되면 ONNX 연산자로 표현되는 ONNX IR을 생성합니다.
ONNX IR은 도구를 통해 (LLVM에 의해) 사전 정의된 MLIR로 변환됩니다.
MLIR로 변한 된 코드는 LLVM 도구를 이용하여 LLVM IR로 변환될 수 있고, 하드웨어 백엔드에 따라 기계어로 출력이 가능합니다.
매우 다양한 하드웨어에서 ONNX를 실행할 수 있는 Runtime을 제공합니다. ONNX Runtime과 관련된 내용은 하단에 설명 드리겠습니다.
다수의 프레임워크 지원
Pytorch, TensorFlow, Mxnet 등 26개의 ML 프레임워크를 지원합니다. 또한, Export 하는 방식도 매우 간편하게 되어있습니다. VeriSilicon, Hailo 등 대부분의 NPU 회사에서도 ONNX Input을 지원합니다. 아래는 다수의 프레임워크를 ONNX에 맞게 사용하는 법에 대한 내용입니다.
Custom Vision Service
Chainer, Caffee2, PyTorch와 같은 여러 Training 프레임워크를 ONNX로 Export 기능을 지원하므로 훈련된 모델을 특정 버전의 ONNX 형식으로 저장할 수 있습니다.
ONNXMLTOOLS(ONNX Converter)
이 Python 패키지를 사용하면 모델을 여러 Training 프레임워크 형식에서 ONNX로 변환할 수 있습니다.
개발자는 애플리케이션이 대상으로 하는 Windows 빌드에 따라 모델을 변환할 ONNX 버전을 지정할 수 있습니다.
ONNX용 Model Zoo 제공
ONNX도 TF Hub와 같이 사용할 수 있는 ONNX Model Zoo가 있습니다.
Computer Vision, NLP, 생성 AI 모델와 같은 다양한 유형의 작업에 대해 미리 학습된 여러 ONNX 모델이 포함되어 있습니다.
ONNX Runtime
ONNX가 지원하는 광범위한 프레임워크, 운영 체제 및 하드웨어 플랫폼에서 기계 학습을 가속화하도록 설계되었습니다. 또한 다양한 하드웨어 및 Accelerator와 쉽게 통합할 수 있습니다.

ONNX Runtime 특징
그래프 최적화
많은 추론 엔진이 제공하는 최적화 기법들을 ONNX Runtime도 지원합니다.
Node Elimination과 Node Fusion을 사용하여 불필요한 연산을 제거하거나 줄여줍니다.
Constant Folding을 통해 컴파일 타임에 계산할 수 있는 것들을 미리 계산함으로써 Runtime의 실행 시간을 최소화합니다.
Model Partitioning
Greedy 알고리즘을 통해서 모델을 여러 개로 나누어 Parallel 실행을 지원합니다.
ONNX Runtime 장점
자체적으로 모델을 최적화 할 수 있으며 그 단계 및 최적화 방법들을 지정할 수 있습니다.
Arena라는 자체적으로 메모리를 관리하는 풀이 존재하여 사용자가 모델 로드 여부에 따라 GPU 메모리를 관리합니다.
바이너리 크기가 250MB 정도로 크지 않은 편이어서 배포 및 업데이트에 용이합니다.
ONNX Runtime 단점
GPU 메모리를 직접 관리해주기 때문에 사용자가 직접 메모리를 건드리기가 어렵습니다.
ONNX로 변환시 지원하지 않는 Layer를 회피해서 만들어야 합니다.
ONNX 구성요소
ONNX는 Machine Learning 모델을 지원하기 위해 만들어졌기 때문에 구성 요소 또한 대분의 딥러닝 그래프와 마찬가지로 크게 Tensor와 Operation으로 구성되어 있습니다. 이 밖에 Loop, Function 등도 지원하지만 이는 추후 다른 글에서 따로 설명드리도록 하겠습니다. 최종적으로 이러한 구성 요소들로 만들어진 그래프를 (TensorFlowlite 소개글에 언급되었던) Protocol Buffer를 이용하여 Serialize합니다.
1.Tensor
Type: Tensor의 데이터 타입을 의미합니다
Shape: Tensor의 Shape을 의미합니다. Empty Shape도 지원합니다.
Data: Tensor의 Data를 뜻합니다. ONNX에서 표현하는 Tensor는 기본적으로 Dense Array이고 stride를 표현할 수는 없습니다. 즉, 어떤 Dense Array의 Subview (예를 들면, 바로 아래와 같은 Python Numpy 표현)를 표현할 수는 없습니다. 하지만 Sparse Array는 지원합니다. 많은 부분이 Null 또는 0인 경우 Sparse Array를 사용하면 Memory를 절약할 수 있습니다.
Operator
Operator는 Add, Sub과 같은 연산 자체를 의미합니다. 각 연산에 필요한 Attribute (예를 들면, Conv2d에서 Padding Size)를 가지고 있습니다.
각 Operator는 Opset Version이라고 불리는 Version에 따라서 Attribute나 지원되는 Input Type 등의 성질들이 업데이트가 됩니다. 여기서 한 가지 문제가 발생하는데 이러한 Opset Version에 따라서 Operator들이 호환되지 않는 경우가 비일비재합니다. 따라서 사용자가 ONNX로 사용자의 Machine Learning 모델을 ONNX로 변환할 때 Opset Version을 주의해야 합니다.
ONNX의 경우에는 150개가 넘는 Layer을 지원하지만 사용자의 모든 상황에 맞게 Layer가 지원되지 않습니다. ONNX의 주된 목표는 가능한 모든 Layer를 추가하는 것이 아닙니다. 따라서 TFLite와 다르게 사용자가 직접 Layer를 추가하는 방식이 아닌 ONNX에서 내부 검토를 통하여 지원 하는 방식을 사용합니다. 내부 검토를 요청하기 위해서는 ONNX에서 제시한 총 7개의 단계를 거쳐 PR을 제공해야 합니다.
ONNX 한계
위에서 언급드렸듯이 ONNX는 다양한 ML 프레임워크로부터 손쉽게 변환할 수 있고 Runtime을 통해 다양한 하드웨어 플랫폼에서 최적화된 방식으로 실행할 수 있다는 장점을 가지고 있습니다. 이는 ML 프레임워크 전환에 따른 오버헤드를 줄이고 표준화된 생태계 구축에 따른 효율화라는 이점을 제공합니다. 하지만 아래와 같은 한계점을 가지고 있습니다.
정확도 저하
가끔씩 ONNX는 정확도의 저하를 일으키는 경우가 있습니다. 예를 들어, Interpolation 값과 resize/crop 값을 일관되게 처리하지 못하여 정확도가 저하될 수 있습니다. 따라서 이미지의 크기를 조정할 때 원본 이미지와 변환된 이미지의 결과가 다를 수 있습니다.
Operator의 서로 다른 구현으로 인하여 Runtime에서 동작하는 Exported Model은 다른 결과를 도출하기도 합니다. 이 차이는 각 Layer 단위로 보았을 때는 수치적으로 매우 작으나, 많은 Layer가 쌓인 Machine Learning 모델에서는 이 작은 차이도 중요한 상황에서는 문제가 될 수 있습니다.
학습 성능 저하
ONNX는 PyTorch와 Backend 구현이 다르기 때문에 모델 구조에 따라 학습 성능이 저하될 수 있습니다.
사전 훈련된 가중치 사용 불가
ONNX는 메타데이터가 부족하여 사전 훈련된 가중치를 여러 개 사용할 수 없습니다.
크기 및 속도 저하
ONNX Runtime은 Python 기반으로 개발하기엔 편리하지만, 임베디드 기기에 내장하기엔 크기가 매우 크고 느립니다.
Olive
MicroSoft에서 진행중인 Hardware-Aware 모델 최적화 솔루션입니다. Olive내에 모델 Compression, Compilation 관련된 기능들이 포함되어 있습니다.

ONNX 기반으로 구현되었기 때문에 ONNX Runtime 설치를 필요로 합니다.
Vitis EP(AMD), OpenVINO(Intel), QNN EP(Qualcomm), DirectML EP(Windows)과 같은 다양한 H/W에서의 최적화를 지원합니다.
2023년 3월 부터 Github에서 공개되었고 지금도 많은 Contributor를 모집하고 있습니다.
Optimium 장점
Custom Layer 지원
Optimium은 Meta Programming 기반의 자체 개발된 언어를 가지고 있어서 Custom Layer를 손쉽게 구현할 수 있습니다. 이번 베타 테스트에서는 해당 언어가 공개 대상이 아니지만 향후 공개 예정으로 사용자가 이를 사용하여 필요에 맞게 다양한 Operator를 구현할 수 있습니다.
이번 베타 테스트에서는 컴퓨터 비전 모델과 관련된 Operator를 주로 지원하지만 베타 테스트 사용자가 사용하는 Operator에 대한 정보를 알려주시면 컴퓨터 비전 이외의 모델도 부분적으로 지원 가능합니다.
연산 최적화
ONNX Runtime에서 제공하는 것보다 훨씬 많은 Optimization을 수행합니다. 대표적인 예로 Low Level Hyperparameter Tuning을 통해 각 Layer와 Target Device에 최적화된 Low Level Source Code를 생성합니다. 또한 대부분 추론 엔진에서 지원하지 않는 Quantization Fusion 기능도 개발 중입니다.
더 빠른 속도
ONNX Runtime 실행 속도보다 월등히 빠른 속도로 추론 작업을 수행할 수 있습니다.
MLIR 기반 제작으로 더 높은 간편성
LLVM보다 더 편리하게 Customizing을 할 수 있는 자체적인 언어를 만들어서 최적화 Pass의 간편성을 높였습니다. 해당 언어에 대해서는 추후 게시물에서 보다 더 자세하게 말씀드리겠습니다.
Life is too short, you need Optimium
Reference
https://manuscriptlink-society-file.s3-ap-northeast-1.amazonaws.com/kips/conference/2020fall/presentation/KIPS_C2020B0124.pdf
https://www.khronos.org/blog/nnef-and-onnx-similarities-and-differences
https://ettrends.etri.re.kr/ettrends/178/0905178003/34-4_23-31.pdf
https://onnx.ai/onnx/repo-docs/Overview.html
https://ettrends.etri.re.kr/ettrends/189/0905189004/032-042_%EA%B9%80%EC%A7%84%EA%B7%9C.pdf
https://ettrends.etri.re.kr/ettrends/189/0905189004/032-042_%EA%B9%80%EC%A7%84%EA%B7%9C.pdf
https://mlir.llvm.org/
https://onnx.ai/onnx/repo-docs/AddNewOp.html
https://onnx.ai/onnx/repo-docs/ManagingExperimentalOps.html
https://microsoft.github.io/Olive/overview/olive.html
https://www.youtube.com/watch?v=Qj-l0tGKPf8