Computing

cuDNN Graph API (1) (Feat, Operator Fusion & TVM) 본문

Deep Learning/jhDNN

cuDNN Graph API (1) (Feat, Operator Fusion & TVM)

jhson989 2022. 5. 3. 23:43

Operation (Operator, Kernel, Layer) Fusion

Operation (or operator, kernel, layer) fusion은 딥러닝 학습 및 추론 속도 향상을 위한 최적화 기법 중 하나로, 여러 operations(예를 들어, convolution, bias addition, ReLU activation)을 하나의 operation으로 만들어 실행시키는 기법이다.

 

대표적인 딥러닝 최적화 컴파일러인 TVM[4] 또한 operator fusion 기법을 적용한다. Operator fusion 기법은 여러 operator들을 하나의 operator로 만듦으로서, 데이터 재활용 비율을 높여 성능 향상을 꾀한다. 즉 한 operator 결과(=중간 결과)를 다른 operator가 쓸 때, 중간 결과를 off-chip 메모리에 저장할 필요 없이 다른 operator가 사용할 수 있게 한다. 이 결과 두 딥러닝 operators 사이의 메모리 operation이 제거 되어, 엄청난 계산 성능 향상[4]은 물론이며 에너지 사용량도 줄일 수 있다.

 

Fig 1. fusion이 적용된 경우와 적용되지 않은 경우의 메모리 operation 차이를 간단히 나타낸 그림으로, off-chip memory는 DRAM, on-chip memory는 register(or cache)를 의미한다. Fig 1.에서 operator fusion 시 두 operator(초록 박스) 사이에 off-chip 메모리 접근이 제거됨을 확인할 수 있다. Fusion을 적용 시 register에 있는 데이터를 곧바로 다음 operator가 사용할 수 있다.

 

Fig 1. Operator fusion이 적용된 경우와 적용되지 않은 경우 비교

 

Fig 2.은 Operator fusion 적용 시 실제 얼마나 빨라지는 지 나타낸 결과[4]이다. NVIDIA Titan X에서 실험한 결과로 각 operator들을 fusion 하지 않았을 경우와 fusion 했을 경우를 비교한 결과이다. 큰 성능 향상을 볼 수 있다.

 

Fig 2. Operator fusion을 적용했을 경우와 안했을 경우의 계산 성능 비교 [4]

 

TVM은 딥러닝 operator들을 4가지 카테고리로 분류하였는데, 다음과 같다.

  • Injective : element-wise 연산 (addition, subtraction, scale, ReLU)
  • Reduction : 여러 element 들간의 연산 (e.g., sum)
  • Complexout-fusable : 복잡한 연산 (e.g., Conv2D)
  • Opaque : fuse 될 수 없는 연산 (e.g., sort)

Injective operation끼리는 서로 쉽게 fuse될 수 있으며, reduction operator는 injective operators의 마지막에 fuse될 수 있다. Complexout-fusable operator는 그 뒤에 injective operator가 fuse 될 수 있다. (이 밖의 자세한 fuse rule은 다음에 제대로 정리해 봐야겠다.)

 

 

 

cuDNN Graph API

Operator fusion은 딥러닝에 어떤 operator들이 포함되어 있는 지를 알아야 실행이 가능하다. (Conv2D 다음에 어떤 operator가 오는 지도 모르는데 어떻게 fusion을 하겠냐?) 여기서 딥러닝 최적화 컴파일러(deep learning optimization compiler)의 필요성이 나타난다. 딥러닝 최적화 컴파일러는 딥러닝 네트워크를 입력으로 받아 최적화된 딥러닝 네트워크를 출력한다. 출력 형태는 컴파일러에 따라 다른데, machine code가 될 수도 있고, CUDA code generation 역할을 할 수도 있다. 

 

기존 cuDNN 7은 딥 러닝의 개별 operation의 최적 구현에 집중하였다. Convolution layer나 RNN layer, ReLU layer 등을 최적으로 구현하여 라이브러리로 제공하였다. cuDNN 8부터는 cuDNN Graph API를 도입하였는데, 개발자들이 이러한 operator들을 이용하여 딥러닝 네트워크 graph를 생성할 수 있도록 한다. cuDNN graph는 Fig 3.과 같이 tensors가 흐르는 dataflow graph의 형태로 표현되는데, graph의 node는 딥러닝 operator이다.

 

Fig 3. cuDNN Graph API를 이용한 graph 생성 [1]

 

개발자에 의해 graph가 생성되고 실제 딥러닝 추론이 실행되기까지 총 4단계를 거친다.

  1. Create the operation graph : 딥러닝 네트워크의 구조 및 각 operation의 tensor input/output(edge들)를 cuDNN Graph API를 통해서 명시함
  2. Finalize the operation graph : 딥러닝 네트워크 구조 분석을 시작하며, 각 operation들간의 dependency 분석 및 그래프가 올바르게 생성되었는 지 확인함
  3. Configuring an engine that will execute the operation graph : Finalized graph를 실행시킨 engine을 선택함. 그 결과 execution plan이 생성됨. Engine 선택은 cuDNN이 추천하거나 개발자가 직접 선택할 수 있음
  4. Executing the engine : 생성된 execution plan을 실행 시킴. GPU는 variant pack (입력 tensor들을 가리키는 실제 device pointer. tensor와 차이는 tensor는 가상의 개념이라면, variant pack은 실제 물리적인 데이터를 가리킴. 네트워크는 동일하지만 데이터들은 변수(variant)이기에 이러한 이름이 붙음)들을 입력으로 받아 execution plan에 따라 딥러닝 계산을 실행함

 

 

 

Reference

[1] https://docs.nvidia.com/deeplearning/cudnn/developer-guide/index.html#op-fusion

[2] https://docs.nvidia.com/deeplearning/cudnn/api/index.html#cudnn-backend-api

[3] https://github.com/NVIDIA/cudnn-frontend

[4] Tianqi Chen, Thierry Moreau, Ziheng Jiang, Lianmin Zheng, Eddie Yan, Haichen Shen, Meghan Cowan, Leyuan Wang, Yuwei Hu, Luis Ceze, et al. 2018. {TVM}: An automated end-to-end optimizing compiler for deep learning. In 13th {USENIX} Symposium on Operating Systems Design and Implementation ({OSDI} 18), pages 578–594.