DNN accelerator

Efficient Processing of Deep Neural Networks - HW for DNN Processing: Systolic array

전공생 2021. 8. 12. 03:48

CNN model의 inception module, shortcut module등과 같은 다양한 방법을 사용하여 더 높은 정확성과 연산량을 줄이려고 하였다. 그러나, ResNet의 MAC의 개수를 보면 필요로 하는 연산량이 매-우 많다. 이런 연산을 처리하기 위해서는 많은 자원이 필요하고, 좋은 자원이 있어도 에너지 소모량도 방대하며 실행되는데 걸리는 시간도 오래걸린다. 이런 문제들을 줄이기 위한 노력이 하드웨어적으로 이루어지고 있는데, 이번 부분에서는 이에 대해 이야기 해보려고 한다. 

data reuse

데이터를 읽어올때 반드시 DRAM을 거쳐서 오게 되는데, DRAM에 접근하는 것은 오랜 시간과 많은 에너지를 사용하므로 최대한 DRAM에서 데이터를 읽어오거나 쓰는 일을 줄여야한다. 즉, DRAM에서 가져온 data를 칩 안에서 최대한 재사용하여야 한다. data를 재사용하는 것도 어떤 data를 재사용 하느냐에따라 세 종류로 나눌 수 있다.

  • convolutional reuse: ifmap(input feature map)과 weight 값을 모두 재사용한다. filter는 ofmap(output feature map )의 개수만큼 재사용되고 ifmap은 filter 개수만큼 재사용 된다. 
  • ifmap reuse: 각 ifmap pixel을 filter의 channel의 개수만큼 재사용한다.
  • filter reuse: 각 filter weight을 ifmap의 batch 개수만큼 재사용한다.

 

dataflow - systolic array

이러한 data reuse를 최대한 사용하기 위해 PE(processing element)를 사용하여 연산하는 부분을 구성한다. 

PE는 MAC연산을 수행하는 연산자(ALU) + 재사용할 data를 저장해두는 local memory로 구성되어있다.

그림에서 왼쪽이 CPU와 GPU의 연산부분의 구조이고, 오른쪽이 TPU, NPU와 같은 DNN accelerator의 연산부분의 구조이다.

오른쪽 부분에서 ALU와 파란색, 빨간색이 합쳐진 작은 네모 하나가 PE이다. CPU, GPU에서 data를 가지고 있는 register file(파란색)과 control unit(빨간색)이 ALU와 멀리 있어서 data를 가져올때 매번 register file까지 값을 read, write하는 data 이동이 많다. 반면에 NPU의 경우 매번 data를 register file에서 가져올 필요 없이 PE에서 사용한 data를 위 혹은 아래 PE로 넘겨줘서 다음 PE에서 data를 바로 사용할 수 있도록 연산한다. 또한 해당 PE를 거치는 여러 data가 local memory에 저장된 같은 값을 매번 사용하여 연산할 수 있다. 1*5+2*5+3*5를 (1+2+3)*5로 계산한다고 생각하면 좋을 것 같다. 앞의 식은 5를 매번 RF(register file)에서 가져와야 하고, 뒤의 식은 5를 한번만 가져와서 local memory에 저장해서 메모리 접근을 줄인다는 것이다. 오른쪽 구조처럼 data를 재사용하여 병렬적으로 연산하는 구조를 systolic array라고 한다. local memory에 어떤 값을 저장하느냐에 따라 여러 종류로 나눌 수 있다.

(a) weight stationary (b) output stationary (c) no local reuse

Weight Stationary(WS)

register file에서 weight를 가져오는 것을 최소화함으로써 weight를 읽을 때의 에너지 소모를 최소화하도록 설계된 구조이다. 위의 (a)번 그림처럼 local memory에 weight값을 미리 DRAM에서 가져와서 저장해놓고 global buffer로부터 input값과 부분합을 받아서 해당 input값과 고정된 weight값이 계산되어 global buffer로 계산한 부분합을 저장한다. convolutional과 filter reuse를 최대화 하는 구조이다. 구글 사에서 만든 DNN accelerator인 TPU의 계산부분이 WS로 구성되어있다.

weight stationary를 대표로 2-D systolic array의 작동을 좀 더 자세히 보면, 다음 연속된 그림과 같다.

systolic array의 local memory에 weight값이 저장되기 때문에 array의 주황색과 초록색 부분은 각각 주황색 filter, 초록색 filter의 weight값을 저장한 것을 나타낸다. array의 왼쪽의 stream들은 input fmap에서 filter와 convolution연산이 일어날 부분을 stream으로 만든 것이고, 매 clock cycle당 input fmap의 stream을 array의 맨 왼쪽으로 넘겨준다. 동시에, array에서 오른쪽으로는 input fmap값을 넘겨주고, 아래쪽으로는 계산한 부분합을 누적해서 넘겨준다. 이를 반복하다보면 계산된 ∑weight*input의 값을 얻게 된다.

 

 

Output Stationary(OS)

부분합을 읽고 쓸때의 에너지 소모를 최소화하도록 설계된 구조이다. register file에 저장된 같은 output activation에 대한 값을 합치게 해준다. 

이는 weight stationary, input stationary와 다르게 array에 부분합을 저장한다. 

Input Stationary(IS)

이는 weight stationary와 반대로 array에 input fmap값이 저장되어있고, weight값을 array로 넘겨줘 convolution연산을 수행하는 구조이다. 

No Local Reuse(NLR)

모든 PE에 local memory와 control unit을 포함시켰을때 발생하는 비용때문에, 아예 reuse를 하지 않는 구조이다. PE에서 local memory를 두지 않는다. 당연히 data 재사용을 하지 않으므로 에너지 소모율은 가장 높다.

위에 있는 그림, (a) weight stationary (b) output stationary (c) no local reuse

Row Stationary(RS)

WS와 OS의 경우 각각 weight와 partial sum만 최적화하는데에 비해, RS는 weight, pixel, partial sum과 같은 여러 data에 대해 재사용을 최대화하는 구조이다.

row stationary의 작동을 보여준다. 순서는 (a) -> (b) -> (c)

 

그림은 RS의 구조에서 convolution연산이 이루어지는 과정을 설명한 그림이다. 빨간 네모에 속해있는 부분이 각각 local memory에 저장되는 값들이다. local memory의 파란색부분에 연산에 사용할 만큼의 input fmap 값을 넣고 output fmap 위치에 해당하는 부분합을 계산한다. (a), (b), (c) 과정 모두 같은 weight 값을 사용(weight값 재사용)을 하고 있고 매번 local memory(RF의 빨간 부분)에 하나의 값만을 저장하는 것을 볼 수 있다. 덕분에 적은 local memory와 높은 data 재사용으로 연산을 진행할 수 있고 가장 에너지 효율성이 좋은 구조이다.

systolic array의 종류별 에너지 효율성을 나타내는 그래프

연산당 소모하는 에너지의 양을 측정해보면 data 재사용을 안하는 NLR(No Local Reuse)의 에너지 효율이 가장 안 좋고, data 재사용을 많이 하며 적은 local memory 사용하는 RS(Row Stationary)의 에너지 효율이 가장 좋은 것을 알 수 있다...여기까지 보면 RS가 가장 좋은 구조로 보이지만, 이론적으로만 그렇고 실제로 구현해보면 그만큼의 효율이 안 나온다고 한다. 실제로는 부분합을 재사용하는 OS가 가장 흔하게 사용된다.

 

 

 

이 논문에서는 systolic array 뿐만 아니라 quantization, HMC 등과 같은 더 다양한 방법의 하드웨어적으로 DNN의 연산을 가속하는 방법에 대해 소개하고 있다. 그러나 그 부분들은 많은 하드웨어 지식을 요구해서, systolic array에 대해서만 글을 쓰게 되었다. 하드웨어에 대해 많이 알고 있으면, 이런 부분에 대해서 더 읽어봐도 좋을 것 같다.

 

 

 

※ 공부하고 있는 단계라 내용에 부족한 부분이 많습니다. 조언이나 지적은 감사히 받아들이고 수정하겠습니다.