Corgi Dog Bark

ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TENSOR RT 란??
    뜯고 또 뜯어보는 컴퓨터/TENSORRT 2021. 10. 7. 15:13
    반응형

    Welcome to TENSOR RT!

    안녕하세요 Tensor RT 에 대해 처음 쓰는 글인데, 모델을 Tensor RT 로 변환 하려다 보니, 어려움이 많아 직접 글을 적게 되었습니다. 혹시 오탈자나 틀린 부분이 있으면 알려주세요! 언제나 환영입니다. 본 글은 엔비디아 TensorRT 도큐먼테이션을 참고하였습니다. https://docs.nvidia.com/deeplearning/tensorrt/developer-guide/index.html

    1. Introduction
    NVIDIA® TensorRT™ is an SDK that facilitates high performance machine learning inference. It is designed to work in a complementary fashion with training frameworks such as TensorFlow, PyTorch, and MXNet. It focuses specifically on running an already-trained network quickly and efficiently on NVIDIA hardware.

     

     

     

    TENSOR RT 란?

    TENSOR RT 란 양자화 및 컬리브레이션, 그래프 최적화, 커널 자동 튜닝 등등의 기법으로 모델을 GPU 상에서 추론속도를 증가시켜주는 역활을 합니다. 밑은 가장 간단한 예시인데, 밑의 예시는 구글의 LENET 모델의 Inception module 을 virtical optimization을 시켜줌으로써, 최적화 시켜주는 가장 간단한 예시입니다. Tensor RT 로 된 수많은 자료가 있지만, 본 포스팅은 TENSOR RT 를 통한 최적화 방법에 대해 집중적으로 다룰 수 있도록 하겠습니다.

    TENSOR RT 최적화 구조

    - TENSOR RT 의 설치 방법은 DOCKER 설치로 진행하였으며, https://eehoeskrap.tistory.com/414?category=705774꾸준희 님의 블로그에 굉장히 자세히 설명이 되어있으니 참고하길 바랍니다.

     

    TENSOR RT 기본

    1. Introduction
    NVIDIA® TensorRT™ is an SDK that facilitates high performance machine learning inference. It is designed to work in a complementary fashion with training frameworks such as TensorFlow, PyTorch, and MXNet. It focuses specifically on running an already-trained network quickly and efficiently on NVIDIA hardware.

    공식 문서에 나와있는 Tensor RT 에 대한 설명은 다음과 같습니다. Tensor RT란, 공식문서에서는  Machine Learning Inference(추론) 속도를 증가시켜주는 SDK 로 정의가 되어있고, 현재 수많은 머신러닝 프레임 워크 TensorFlow, PyTorch, MXNet 등과 호환이 된다고 합니다. 

     

     

     

    TENSOR RT CAPABILITY

    2.1. C++ and Python APIs
    TensorRT’s API has language bindings for both C++ and Python, with nearly identical capabilities. The Python API facilitates interoperability with Python data processing toolkits and libraries like NumPy and SciPy. The C++ API can be more efficient, and may better meet some compliance requirements, for example in automotive applications.

    - TENSOR RT 의 경우 현재 파이썬 과 C++ 에 대한 API 를 지원해주고 있으며, 파이썬의 경우 NumPy 와 SciPy 등의 라이브러리와 호환이 가능하고, C++ API 의 경우, cuda control 이나 호환성 부분에서 더욱 안정적인 적용이 가능합니다.추가로 필자가 Tensor RT를 사용해본 결과, Tensor RT 와 관련한 github 자료 및 내가 원하는 모델을 Tensor RT로 바꿔주고 싶을 때에는 C++이 훨씬 유리하고 유연하다는 것을 말해주고 싶다..

     

     

     

    TENSOR RT PHASE DESCRIPTION

    TENSOR RT의 사용방법을 알기전, 기본 사항부터 말씀드리겠습니다. TENSOR RT 의 경우 크게 두가지 PHASE 로 구분이 되어 있는데, 첫번째 단계는 TENSOR RT 로 모델을 구성하는 단계입니다. 이 경우, TENSOR RT 가 타켓 GPU 즉, 현재 내가 쓰고 있는 GPU에 모델을 최적화를 시켜주게 되고(Build Phase), 두번째 단계에서는 최적화된 모델을 추론(Run  INFERENCE PHASE)하는데 쓰이게 됩니다. 두번째 PHASE 는 Run Inference 단계로 최적화 된 모델을 가지고 추론을 실시하게 되는 단계입니다.

    1. BUILDER PHASE - 첫번째 단계
      TENSOR RT 는 BUILDER 라는 객체를 가지고 있는데, Network 객체와, 추론 ENGINE 이라는 객체를 만들어 냅니다. 이때 TENSOR RT NETWORK 객체는 TENSOR layer 와 TENSOR 를 가지고 네트워크를 직접 만들 수도 있고, 이미 뽑아낸 모델(Pytorch 와 텐서플로로 미리 build 된 모델)로 TENSORRT Network 엔진을 빌드 할 수도 있는데, 필자는 후자를 강력히 추천합니다. 힘들게 Pytorch 나 Tensor Flow로 모델을 만들어 놨는데, Tensor RT 로 다시 쌓는건 모델이 커질 경우, 굉장히 노동력이 드는 일이기 때문입니다..
      하지만 직접 LAYER 를 쌓아줘야 하는일이 있을때도 있는데,  이는 내가 만든 네트워크 Layer 나 특정 tensor를 Tensor RT 가 지원을 하지 않는 경우입니다. 하지만 Tensor RT도 발전을 거듭하는 만큼, 이런일이 발생하는 것은 많이 보지 못하였습니다. ( 참고, 이렇게 생산된 ENGINE 의 경우, Tensor RT 의 버전과 자신이 쓰는 장비에서만 최적화가 된 것이니, 다른 장비에서 돌릴려면, 그 장비에서 또한 마찬가지로 세팅을 해서 ENGINE을 빌드 해줘야합니다.)

    처음에는 이해가 잘 안가지만, 예를 한번 봐보면 좀 더 직관적으로 되실 겁니다. (c++ 로도 가능하지만, 빠른 이해를 위해 Python 으로 설하겠습니다 C++ 를 Wrapper 형태로 파이썬 모듈을 작성한 것이라, 파이썬 스럽진 않지만, 빠른 이해와 C++ API 또한 같은 방식으로 이용됩니다.) 

     

    다음은 Pytorch 로 작성된 간단한 모델 예시 입니다.

    Class net(nn.Module):
    	
        def __init(self):
        	super(Net,self).__init__()
           	self.conv1  = nn.Conv2d(1, 20, kernel_size = 5)
            self.conv2 = nn.Conv2d(20,50, kernel_size = 5)
    		self.fc1 = nn.Linear(800,500)
    		self.fc2 = nn.Linear(500,10)
    		
            def forward(self, x):
            	x = F.max_pool2d(self.conv1(x), kernel_size=2, stride=2)
                x = F.max_pool2d(self.conv2(x), kernel_size=2, stride=2)
                x = x.view(-1, 800)
                x = F.relu(self.fc1(x))
                x = self.fc2(x)
                
            return F.log_softmax(x, dim=1)

     

    모델은 훈련시키고 난 다음, Weight 파일을 저장하고,  다음과 같이 Builder 를 통해 Network 모델을 정의해 줍니다.
    밑에 주석으로 달아 놨지만, Builder 를 선언하기전, TRT LOGGER 를 미리 설정하여, 해당 Logger 를 통해 Builder 를 작성하여 줍니다.

    # builder 를 선언하기 전 LOGGER 를 먼저 정의 trt.Logger.Warning 말고도 많은 Logger 및 커스텀 Logger가 작성 가능하니 참고.
    TRT_LOGGER  =  trt.Logger(trt.Logger.WARNING)
    
    
    '''
    	여기서는 TRT_LOGGER 를 설정해주어 Builder 를 만들어주었는데, 방금 만든 Logger를 인자로 넘겨주어 
    	Builder 를 설정해줍니다. 그 다음 builder를 통해 create_network() 를 불러오고 network() 객체를 만들어 주게 됩니다. 
    '''
    
    builder = trt.Builder(TRT_LOGGER)
    network = builder.create_network()
    config = builder.create_builder_config()

     

    Builder Config 작성
    Builder 의 Config 를 작성해주어야 하는데, Builder 의 Config 는 어떠한 방식으로 모델을 최적화 할것인지에 대한 config(Batch size, input name, output name 등등)입니다. 따라서 Config 를 작성해주면 Tensor RT 는 config에 따라 input 과 output 그리고 runtime 속도등을 최적화 시켜줍니다.

    # builder 의 config 객체를 생산해준다. -> default config 를 생성
    config  =  builder.create_builder_config()
    # config 의 max_workspace 를 생성. 
    config.max_workspace_size  =  common.GiB(1)
    
    config.set_flag(trt.BuilderFlag.REFIT)

     

    그 다음 Builder 를 통해 생성된 Network 객체 와 Config 객체 를 가지고, 최종적으로 모델 엔진을 빌드하러 가면 됩니다.

    class ModelData(object):
    	INPUT_NAME = "data"
    	INPUT_SHAPE = (1, 28, 28)
    	OUTPUT_NAME = "prob"
    	OUTPUT_SIZE = 10
    	DTYPE = trt.float32
    
    # 네트워크에 내가 직접 layer 와 weight를 넣어주는 함수
    def  populate_network_with_some_dummy_weights(network, weights):
    	# 예시로 더미 weight를 생성해서 넣어줌. 나중에 weights를 통해 넣어줄 수 있다.
    	conv1_w  =  np.zeros((20,5,5), dtype=np.float32)
    	conv1_b = np.zeros(20, dtype=np.float32)
    	
    	# network 모델에 Tensor RT layer 를 쌓아주는 모습
    	input_tensor  =  network.add_input(name=ModelData.INPUT_NAME, dtype=ModelData.DTYPE, shape=ModelData.INPUT_SHAPE)
    	conv1 = network.add_convolution(input=input_tensor, num_output_maps=20, kernel_shape=(5,5), kernel=conv1_w, bias=conv1_b)
    	conv1.name = "conv_1" # 이렇게 이름을 적어줘야 나중에, weight 를 통한 Match가 가능(지금은 dummy weight)
    	conv1.stride = (1, 1)	
    	network.set_weights_name(conv1_w, 'conv1.weight')
    	
    	conv2_w  =  weights['conv2.weight'].numpy()
    	conv2_b  =  weights['conv2.bias'].numpy()
    	conv2  =  network.add_convolution(pool1.get_output(0), 50, (5, 5), conv2_w, conv2_b)
    	conv2.stride  = (1, 1)
    	
    	최종적으로 network.mark_output 을 생성.
    	fc2.get_output(0).name = ModelData.OUTPUT_NAME
    	network.mark_output(tensor=fc2.get_output(0))

    이제 builder 를 통한 모델 Build 가 마무리 되었는데, 여기서 주의할 점은 builder 가 완료되기 전에 weight 메모리를 release 해주지 말라는 것입니다. Tensor RT 변환을 하기위한 첫번째 단계가 끝났는데, 다음 포스팅에서는 Runtime API 를 돌리는 법에 대해 설명드리겠습니다.

     

     

    반응형

    '뜯고 또 뜯어보는 컴퓨터 > TENSORRT' 카테고리의 다른 글

    TENSOR RT _ SIMPLE MNIST 예제  (0) 2021.10.12
    TENSOR RT - (2)  (0) 2021.10.07

    댓글

Designed by Tistory.