LabHub
배우기 러닝패스 코스

AI 다이어트 실패 사건 · 그래프 최적화가 바꾸는 것 · 이론

그래프 최적화가 바꾸는 것 — 노드를 세어 확인한다

LabHub 에서 이어서 보기

한 줄 요약

onnxruntime 은 세션을 열 때 그래프를 다시 쓴다. 무엇이 어디까지 바뀌는지는 최적화 단계가 정하고, 그 결과는 파일로 꺼내 노드를 세어 확인할 수 있다.

왜 이게 필요했나

양자화 전후의 속도를 견주는 실험에서 숫자가 도무지 안 맞는다. 같은 모델, 같은 기계인데 측정할 때마다 다르고, 때로는 양자화한 쪽이 더 느리다.

원인이 최적화 단계인 경우가 많다. 한쪽 측정은 기본값(전부 켬)으로 돌았고 다른 쪽은 어떤 이유로 최적화가 꺼진 채 돌았다면, 그 비교는 양자화를 잰 것이 아니라 최적화를 잰 것이다. 더 흔한 사고는 최적화된 파일을 저장해 배포하는 것이다 — 그 파일은 만든 환경 밖에서 열리지 않을 수 있다.

네 단계는 무엇을 하나

[Graph optimizations](https://onnxruntime.ai/docs/performance/model-optimizations/graph-optimizations.html) 문서가 단계를 넷으로 나눈다.

이 설명은 문서의 말이고, 실제로 어디까지 되는지는 모델과 기계가 정한다. 그래서 읽기보다 꺼내서 세는 편이 빠르고 정확하다.

꺼내서 세는 법

SessionOptions.optimized_model_filepath 에 경로를 주면, 세션을 열면서 다시 쓴 그래프가 그 경로에 저장된다. 그 파일을 onnx.load 로 열어 노드를 세면 무엇이 일어났는지 그대로 보인다.

원본                 Add(상수,상수) MatMul Add Relu Identity Mul   노드 6개ORT_DISABLE_ALL      Add MatMul Add Relu Identity Mul             노드 6개ORT_ENABLE_BASIC     Gemm Relu Mul                                노드 3개ORT_ENABLE_EXTENDED  FusedGemm Mul                                노드 2개

여기서 세 가지가 한꺼번에 보인다. 상수끼리 더하던 노드는 사라지고 그 결과가 initializer 로 들어앉는다. Identity 는 없어도 되므로 지워진다. MatMul 다음의 Add 는 [Gemm](https://onnx.ai/onnx/operators/onnx__Gemm.html) 하나로 묶이고, 그다음 단계에서 Relu 까지 삼켜 FusedGemm 이 된다.

노드가 줄었다고 답이 달라지지는 않는다. 같은 입력을 네 단계에 넣어 결과를 견주면 확인할 수 있다. 다만 float32 는 유효자리가 7자리뿐이라, 융합된 커널이 곱셈 순서를 바꾸면 마지막 자리가 흔들릴 수 있다. 그래서 "정확히 같은가" 가 아니라 허용 오차를 정해 두고 그 안인가로 묻는다.

현장에서 만나는 모습

첫째, 최적화된 파일을 배포한다. 꺼낸 파일은 작고 노드도 적어서 "이걸 보내면 되겠다" 는 생각이 든다. 그러나 그 파일에는 com.microsoft 같은 표준이 아닌 도메인의 노드가 들어 있다. 표준 연산자만 아는 다른 런타임은 그 파일을 열지 못한다. ORT 자신도 저장할 때 같은 환경에서만 쓰라고 경고를 낸다.

둘째, onnx.checker 가 그 파일을 통과시킨다. 검사기는 모르는 도메인을 누군가의 확장으로 보고 지나가기 때문이다. 그래서 "검사기 통과" 를 이식 가능의 근거로 쓰면 이 사고를 못 잡는다. 근거는 노드의 도메인 목록이다.

셋째, 비교의 기준선을 안 맞춘다. 양자화 효과를 재려면 두 측정이 같은 최적화 단계여야 한다. 기준선은 ORT_DISABLE_ALL 로 잡아 두면 흔들리지 않는다. 그리고 실제 운영에 나갈 숫자는 운영과 같은 단계로 따로 재야 한다.

넷째, 노드 수를 성능으로 읽는다. 노드가 줄었다고 반드시 빨라지지는 않는다. 이 맥처럼 에뮬레이션이 끼면 시간은 두 배까지 흔들린다. 그래서 이 실습은 시간을 재지 않는다 — 구조가 어떻게 바뀌었는지답이 같은지만 판정한다. 시간은 운영과 같은 기계에서 따로 잰다.

실무에서 진짜 중요한 것

다음 실습에서 할 것

상수 접기·없어도 되는 노드·융합될 세 노드를 한 그래프에 모아 직접 짓고, 도구 optlevel.py 를 한 단계씩 키운다. 네 단계를 모두 돌려 노드를 세어 나란히 놓고, 단계마다 무엇이 사라지고 무엇이 생겼는지 적고, 채점기가 정한 씨앗으로 같은 입력을 네 단계에 넣어 답이 같은지 잰다. 마지막에는 꺼낸 파일의 도메인 목록으로 이식 가능 여부를 판정한다. 채점기는 매번 다른 모양·가중치·씨앗으로 자기 그래프를 지어 여러분의 도구를 실제로 돌리고 답을 대조한다.