ONNX 개념

ONNX 개념 (ONNX Concepts)

ONNX를 처음 마주하면 "그래프", "노드", "opset" 같은 용어가 낯설 수 있어요. ONNX는 수학 함수에 특화된 프로그래밍 언어쯤으로 생각하면 이해가 빨라져요. 머신러닝 모델이 추론 함수를 구현하는 데 필요한 모든 연산을 이 언어(ONNX 연산자)로 정의하는 방식이죠.

출처: ONNX 공식 문서 — ONNX Concepts

입력·출력·노드·이니셜라이저·속성

ONNX 그래프를 만든다는 것은 ONNX 연산자로 함수를 구현하는 거예요. 예를 들어 선형 회귀 y = x @ a + c 는 이렇게 표현돼요. 여기서 x, a, c입력(input), y출력(output), r 은 중간 결과예요. MatMul 이나 Add노드(node) 인데, 노드도 입력과 출력을 가지며 자신만의 타입(ONNX 연산자 중 하나)을 가져요.

Input : float [M, K] x, float [K, N] a, float [N] c
Output : float [M, N] y
r = onnx.MatMul(x, a)
y = onnx.Add(r, c)

한 번도 바뀌지 않는 입력(예: 선형 회귀의 계수)이 있으면 가장 효율적으로 이니셜라이저(initializer) 로 만들어 그래프에 상수로 저장할 수 있어요. 또 속성(attribute) 은 연산자의 고정 파라미터예요. 예를 들어 Gemm 연산자는 alpha, beta, transA, transB 네 가지 속성을 가져요. 런타임이 API로 허용하지 않는 한, 그래프가 로드된 뒤에는 이 값들이 바뀌지 않고 모든 예측에 그대로 적용돼요.

protobuf로 직렬화

모델을 배포하려면 ONNX 그래프를 저장해야 해요. ONNX는 protobuf 를 사용해 그래프를 하나의 블록으로 직렬화해요. 목표는 모델 크기를 최대한 최적화하는 것이에요. 덕분에 배포 환경은 학습에 쓰인 전체 생태계를 복제할 필요 없이 런타임 하나만 있으면 돼요.

메타데이터

머신러닝 모델은 계속 갱신되기 때문에 버전, 작성자, 학습 방식을 추적하는 게 중요해요. ONNX는 모델 자체에 추가 데이터를 저장할 수 있어요.

  • doc_string: 모델에 대한 사람이 읽을 수 있는 문서. Markdown 허용.
  • domain: 모델의 네임스페이스·도메인을 나타내는 리버스 DNS 이름. 예: 'org.onnx'.
  • metadata_props: map<string,string> 형태의 명명된 메타데이터.
  • model_author: 작성자나 기관의 이름을 쉼표로 구분한 목록.
  • model_license: 모델이 제공되는 라이선스의 잘 알려진 이름 또는 URL.

Opset 버전

ONNX는 major.minor.fix 버전으로 배포돼요. 매번 minor 업데이트는 연산자 목록이 달라지거나 시그니처가 바뀌는 것을 뜻해요. 각 opset은 버전 번호와 연결돼요. 예를 들어 버전 1.10 은 opset 15, 1.11 은 opset 16이에요. 모든 ONNX 그래프는 자신이 따르는 opset을 정의해야 해요. opset을 바꾸는 것은 라이브러리를 업그레이드하는 것과 비슷하고, onnx와 런타임은 하위 호환성을 지원해야 해요. 변환 라이브러리마다 특정 opset용 그래프를 만드는 옵션, 보통 target_opset 이 있어요.

함수

함수(function)를 쓰면 코드가 짧아지고 읽기 쉬워지는 장점이 있어요. 또 어떤 onnxruntime은 그 정보를 활용해 함수에 특화된 구현으로 예측을 더 빠르게 실행할 수도 있어요.

모양(형) 추론

결과의 모양을 아는 것은 실행에 필수는 아니지만 성능을 높이는 데 쓸 수 있어요. 예를 들어 Add(x, y) -> z, Abs(z) -> w 그래프에서 x와 y 모양이 같다면 z와 w도 같은 모양이라, z에 할당된 버퍼를 w를 계산하는 데 재사용할 수 있어요. ONNX 패키지는 대부분의 표준 연산자에서 입력 모양을 알면 출력 모양을 계산할 수 있어요. 공식 목록 밖의 커스텀 연산자에 대해서는 그럴 수 없어요.

더 알아보기