ONNX Runtime : High-performance deep learning inference.

2 months ago   •   10 min read

By mAsh

안녕하세요.
지난 포스트에서 TensorRT의 기초적인 사용법을 소개 드렸던 mAy-I research 팀의 정재민 입니다. 이전 TensorRT 포스트에서는 Unsupported Operator 가 없는 간단한 PyTorch MNIST 분류기 모델을 TensorRT로 동작시키기 위해 필요한 과정을 살펴보았고, 그 결과 별도의 처리 없이도 Inference 속도가 5~6배 상승하는 놀라운 결과를 확인할 수 있었습니다!

👇이전 포스팅 보기

TensorRT : High-performance deep learning inference
딥러닝 모델을 가속화 하는 TensorRT에 대해 소개하고 추론하고자 하는 모델에 대한 작업 방법을 소개 합니다. 딥러닝 모델을 리얼타임 서비스에 적용하려면 필수적인 요소인 TensorRT 에 대해 지금 바로 알아보세요!

물론 이전 포스팅에서 살펴본 MNIST 모델은 굳이 TensorRT의 도움을 받지 않더라도 충분히 빠르게 동작하는 모델이긴 합니다. 다만, 실제 현장에서 사용하는 딥러닝 모델은 이와 비교가 되지 않을 정도로 크고 복잡합니다. 따라서 이러한 큰 딥러닝 모델을 이용하기 위해서는 CUDA 연산이 필수적이며, 당연히 CUDA 연산 처리에 최적화 되어있는 TensorRT를 이용하는 것이 추천됩니다.

하지만 TensorRT에는 커다란 문제점이 하나 있는데, 바로 앞에서도 잠시 언급되었던 Unsupported Operator입니다. TensorRT가 지원하는 연산자들은 꽤나 한정되어 있습니다. 문제는 TensorRT가 미지원하는 연산자들 중 몇몇 연산자들은 모델을 구현하기 위해 필수적으로 포함되어야 한다는 점이 있습니다. 예를 들자면 FPN (Feature Pyramid Network)을 구현하기 위해 쓰이는 resize 함수 등이 바로 그러한 함수들입니다.

그렇다고 TensorRT를 쓰지 않기로 결정하기에는 TensorRT가 주는 속도의 장점이 너무나 눈에 밟힙니다. 저희는 TensorRT를 꼭 쓰고 싶습니다. 하지만 TensorRT의 operator만으로는 모델을 구현할 수가 없습니다. 흠, 그렇다면 만약 또 다른 무언가가 TensorRT의 unsupported operator를 대신 처리해준다면 어떨까요?

이번 포스트에서는 그 역할을 완벽하게 수행할 수 있는 ONNX Runtime 에 대해 알아보려 합니다.

ONNX Runtime

ONNX Runtime은 다양한 플랫폼과 프레임워크에서 DNN의 추론과 학습을 가속시키기 위한 고성능 배포 엔진으로 소개되고 있습니다. 기본적으로 ONNX 형식의 모델을 사용하며, PyTorch, TensorFlow 등 기존의 메이저한 프레임워크들과도 문제없이 호환된다고 합니다. ONNX Runtime이 할 수 있는 것들은 크게 아래와 같습니다.

1. High performance runtime for ONNX models
2. Supports full ONNX-ML spec
3. Available for Linux, Windows, and Mac
4. Runs with CPU and GPU, with extensible architecture to plug-in additional hardware accelerators
5. Get an ONNX model from the zoo model or by converting from various frameworks

그럼 위의 5개 항목 중 첫 번째, 즉 우리가 가장 관심을 가지고 있는 ‘High performance runtime’에 대해서 알아보겠습니다. 이 ‘High Performance’를 가능하게 하는 것은 ONNX Runtime의 Execution Provider입니다. Execution Provider는 plug-in hardware accelator로, ONNX model 을 다양한 환경에서 가속할 수 있도록 하는 것입니다.

예를 들어, TensorRT에서는 아래와 같이 동작할 수 있습니다.

TensorRT의 Unsupported Operator 가 포함되어 있는 ONNX 모델을 ONNX Runtime으로 실행할 때, 해당 Unsupported Operator들과 Supported Operator를 각각의 다른 sub-graph로 작성한 후 Supported Operator들은 TensorRT로, 나머지는 ONNX로 추론할 수 있습니다.

즉, 저희가 앞서 간략히 설명드린 방법과 동일한 방법으로 TensorRT의 Unsupported Operator 문제를 해결할 수 있습니다.

추가적으로, ONNX Runtime에는 아래와 같이 TensorRT 뿐만 아니라 다양한 환경에서의 Supported Accelerators들이 있습니다. 따라서 꼭 TensorRT가 아니더라도, 여러 디바이스와 플랫폼에 동일한 모델을 배포해야 할 때, ONNX 모델을 고려해 보는 것도 좋은 선택지가 될 것입니다.

출처 : https://github.com/microsoft/onnxruntime

그렇다면 위에서 언급한 예시를 직접 실행해보죠!

여러가지 모델 중, 이번 예시에서는 object detection(객체 검출) 분야에서 YOLO 계열(one-stage)과 더불어 가장 기초적이면서도 범용적으로 사용되고 있는 two-stage 계열 모델, Faster R-CNN의 실행 방법을 살펴보겠습니다.

예제에서 사용할 Faster R-CNN 모델은 앞서 언급되었던 FPN 구조를 추가적으로 사용하고 있기 때문에 TensorRT 단독으로는 실행시킬 수 없습니다. 일단 Faster R-CNN ONNX model을 일단 1) ONNX Runtime만을 이용하여 실행해보고, 2) 앞서 설명한 방법대로 TensorRT와 함께 실행해본 후 비교해보기로 하겠습니다.

(예제의 환경은 NGC (Nvidia GPU Cloud)에 있는 nvcr.io/nvidia/pytorch:20.02-py3 컨테이너를 사용했습니다)

Faster R-CNN ONNX model 실행

1. ONNX Runtime repo

가장 처음에 할 일은 당연히 ONNX Runtime을 설치하는 일이겠죠. 아래 명령어로 ONNX Runtime repo를 clone합니다.

https://github.com/microsoft/onnxruntime

2. ONNX Runtime TensorRT build

Repo clone이 완료된 후에는 아래 명령어를 통해 build 해 줍니다. 꽤나 오래 걸리는 작업이니, 잠시 커피 한 잔의 여유를 즐기셔도 됩니다.

3. Faster R-CNN model download

예제에 사용하기 위해 Faster R-CNN의 onnx 모델이 필요합니다. 직접 구현하시는 방법도 있겠지만, 번거로운 작업이므로 이미 변환이 완료된 파일을 다운로드 받겠습니다.

모델을 다운받고 적당한 폴더(Model_Name)를 만들어 다음과 같은 구조로 위치합니다.

4. Inference Faster R-CNN ONNX

모델을 다운받았다면 실행시켰을 때의 성능을 확인해봐야겠죠. ONNX Runtime에서는 onnxruntime_perf_test으로 성능 테스트가 가능합니다. 아래와 같이 실행하여, 일반적인 cuda 환경에서의 Faster R-CNN ONNX Runtime 성능을 확인해봅시다.

-e 옵션은 Execution Provider의 plug-in hardware Accelerator 입니다. 아래와 같은 옵션들이 있는데, 저희는 일단 지금은 GPU 환경에서 돌려보는 것이 목적이므로 cuda로 지정해 줍니다.

[cpu|cuda|mkldnn|tensorrt|ngraph|openvino|nuphar|acl]

-r 옵션은 테스트에서 수행할 inference의 반복 수 입니다. default 는 1000으로 되어있어서 오래 걸리니 100으로 고쳐주고 코드를 실행시켜보겠습니다.

ONNX Runtime (only)

실행 결과 저는 위와 같이 나왔는데요, 제 경우에는 전체 inference가 약 7.5초 정도 걸렸네요! 13.43 fps 정도입니다. 참고로 Pytorch 는 Detectron2를 사용하면 제 환경에서 9.5 fps 정도가 나옵니다! ONNX 가 기본적으로 Pytorch 보다 빠르네요.

Inference Faster R-CNN ONNX with TensorRT

이번에는 TensorRT와 ONNX Runtime을 섞어서 추론을 해 보겠습니다. 먼저 위에서 이용했던 onnx 파일을 다음 스크립트로 실행시켜 TensorRT에 대한 sub-graph를 만들어주어야 합니다.

GitHub - microsoft/onnxruntime: ONNX Runtime: cross-platform, high performance ML inferencing and training accelerator
ONNX Runtime: cross-platform, high performance ML inferencing and training accelerator - GitHub - microsoft/onnxruntime: ONNX Runtime: cross-platform, high performance ML inferencing and training a...

위의 스크립트를 수행 하기 전에 sympy 를 설치해야 합니다. pip를 사용하여 sympy를 설치해줍시다.

sympy의 설치가 완료되었다면 다음과 같이 실행합니다. input으로 위에서 사용했던 ONNX 모델을 지정해주시고, output에 sub-graph로 분리된 모델의 output 경로를 지정해주시면 됩니다.

이제 새로운 모델을 아까 받은 모델과 바꿔치기! 해주시고, -e 옵션을 cuda에서 tensorrt 로 바꿔서 onnxruntime 실행을 해봅시다!

ONNX Runtime + TensorRT

와우! 물론 모델 전체를 최적화 한 것은 아니지만 ONNX 로만 돌렸을 때 보다 Total inference run time (100 iterations)은 약 1초 정도 줄어서, 실행 시간이 12.36% 절감되었습니다. FPS 관점에서 살펴보면, ONNX Runtime만 사용했을 때의 속도는 13.43 fps이고, 여기서 TensorRT도 동시에 사용할 경우 15.32 fps로 증가합니다.

Session creation time이 꽤나 늘었지만 처음 실행할 때 한 번만 발생하는 작업이고, 실제 환경에서 40초라는 시간은 모델이 굉장히 많은 추론을 한다는 전제에서는 정말 아무것도 아니죠. 특히나 저희 mAy-I 처럼 길이가 긴 동영상을 처리한다면 꽤나 많은 시간을 절약할 수 있겠습니다. 단적으로, 원래는 8시간 동안 모델을 돌려야 했다면 7시간 만에 끝내고 한 시간 일찍 퇴근할 수 있습니다!

이번 글에서는 TensorRT의 Unsupported Operator를 처리하기 위해, ONNX Runtime과 함께 구동하는 방법을 살펴보았습니다. 다음 번에는 NVIDIA Jetson 보드에서 극한의 최적화를 통한 방법으로 돌아오겠습니다!

Spread the word

Keep reading