본문 바로가기
코드/ONNX

[ONNX] ONNX Runtime? Pytorch 모델 ONNX 변환하기 (Renset18)

by 코드퀸 2023. 8. 8.
728x90
반응형

 

들어가며..

안녕하세요, 코드퀸입니다. 

 

여러 플랫폼에서 딥러닝 모델을 실행시킬 수 있도록 변환해주는 라이브러리인 ONNX 를 자세히 파헤쳐 보고자합니다. 

작성 내용은 공식 홈페이지에 작성된 내용을 제 나름대로 해석하거나 재현한 것들입니다.

 

내용에 오류가 발견되면 댓글 부탁드립니다.  

 

오늘의 컨텐츠 -> https://onnxruntime.ai/docs/

 

ONNX Runtime

ONNX Runtime is a cross-platform machine-learning model accelerator

onnxruntime.ai


Welcom to ONNX Runtime!

ONNX Runtime 이란?

  • 플랫폼 간의 모델을 교환하여 사용할 수 있는 라이브러리 
  • 예1) PyTorch, Tensorflow/Keras, TFLite, scikit-learn 등에서 학습된 모델들을 사용할 수 있음
  • 예2) Python 에서 생성 모델을 C++ 에서도 사용할 수 있음 

 

ONNX Runtime 의 기능 - Inference (추론)

  • 최적화 : 추론 시간 단축 가능 
  • 실행 환경 변경  : 다른 하드웨어, OS 에서 실행 가능
  • 플랫폼 변경 : Python 에서 학습했지만.. C#/C++/Java 에서 사용 가능 
  • 재학습 : 다른 프레임워크에서 생성된 모델 재학습 가능 

 

어떻게 사용하지?

  1. 모델 가져 오기 : 다른 플랫폼에서 생성한 모델을 ONNX 포맷으로 변경하기  
  2. 모델 로드하고 실행하기 : 생성한 모델 불러와서 다양한 언어로 실행하기 (Python -> C++)
  3. 성능 개선하기 : 다양한 기능으로 성능 개선하기 (but.. ONNX 포맷으로 변경만 해도 추론 시간 개선 됨)

 

 


 

오늘의 예제
Resnet18 모델  ONNX 파일 생성하기 
import torch.onnx
import torchvision.models as models

batch_size = 16
device = torch.device('cuda')

def convert_to_onnx(resnet):
   resnet.eval()
   dummy_input = (torch.randn(batch_size, 3, 224, 224, device=device)).to(device=device)
   input_names = [ 'input' ]
   output_names = [ 'output' ]
   torch.onnx.export(resnet,
               dummy_input,
               "resnet18.onnx",
               verbose=True,
               opset_version=13,
               input_names=input_names,
               output_names=output_names,
               export_params=True,
               do_constant_folding=True,
               dynamic_axes={
                  'input': {0: 'batch_size'},  # variable length axes
                  'output': {0: 'batch_size'}}
               )


if __name__ == "__main__":
    # Conversion to ONNx
    resnet = (models.resnet18(pretrained=True)).to(device=device)
    convert_to_onnx(resnet)

 

Resnet18 Pytorch 모델과  ONNX 모델  성능 비교하기 
import onnxruntime
import onnx
import numpy as np
import torchvision.models as models
import torch
import os
from time import time

def to_numpy(tensor):
    return tensor.detach().cpu().numpy() if tensor.requires_grad else tensor.cpu().numpy()

device = 'cpu'

model_onnx_path = os.path.join(".", "resnet18.onnx")
so = onnxruntime.SessionOptions()
exproviders = ["CPUExecutionProvider"]

ort_session = onnxruntime.InferenceSession(model_onnx_path, so, providers=exproviders)

# ONNX 런타임에서 계산된 결과값
x = torch.randn(1, 3, 224, 224, requires_grad=True, dtype=torch.float32, device=device) #

ort_inputs = {ort_session.get_inputs()[0].name: to_numpy(x)}
pre_time = time()
ort_outs = ort_session.run(None, ort_inputs)
print("ONNX Runtime processing time : ", time()-pre_time)

resnet = (models.resnet18(pretrained=True)).to(device=device)

pre_time = time()
torch_out = resnet(x)
print("Pytorch processing time : ", time()-pre_time)

# 기존 output과 onnx output 값 차이 비교
np.testing.assert_allclose(to_numpy(torch_out), ort_outs[0], rtol=1e-02, atol=1e-02)

 

ONNX Runtime processing time : 0.006972312927246094
Pytorch processing time : 0.03097057342529297

 

728x90
반응형

댓글