현대 컴퓨팅의 시초인 폰 노이만 구조는 연산 장치(CPU)와 저장 장치(Memory)가 분리되어 있습니다. 이 구조의 치명적인 단점은 연산을 할 때마다 데이터를 메모리에서 가져오고 다시 저장해야 한다는 점입니다. 앞서 13번 글(Roofline Model)과 14번 글(Dataflow)에서 지적했듯, 이 데이터 이동 비용이 딥러닝 가속기의 성능을 제한하는 가장 큰 장벽입니다.
1978년, H.T. Kung과 C.E. Leiserson은 이 문제를 해결하기 위해 ‘Systolic Array’라는 개념을 제안했습니다. ‘Systolic’은 심장이 혈액을 펌프질하여 온몸으로 순환시키는 수축기(Systole)에서 유래한 용어로, 데이터가 메모리에서 한 번 퍼올려지면(Pumped), 수많은 연산기(PE)들의 배열 사이를 규칙적인 리듬에 맞춰 통과하며 재사용되는 구조를 의미합니다.
이 기술은 2017년 구글이 자사의 AI 전용 프로세서인 TPU(Tensor Processing Unit)의 핵심 아키텍처로 채택하면서, 딥러닝 하드웨어의 표준으로 자리 잡았습니다. 이번 글에서는 Systolic Array의 작동 원리와 구글 TPU가 이를 통해 어떻게 행렬 연산(GEMM) 효율을 극대화했는지 분석합니다.
1. 구조적 특징: PE의 2차원 격자 배열 (Mesh Topology)
일반적인 CPU나 GPU가 수천 개의 스레드를 관리하며 캐시(Cache)와 레지스터를 복잡하게 오가는 것과 달리, Systolic Array는 매우 단순하고 규칙적인 2차원 격자(Mesh) 구조를 가집니다.
- Processing Element (PE): 배열의 각 칸을 차지하는 연산 단위입니다. 각 PE는 매우 단순한 구조로, 곱셈-누적 연산기(MAC Unit)와 적은 용량의 레지스터만을 포함합니다.
- Local Interconnect (국소 연결): 각 PE는 오직 자신의 상하좌우 이웃한 PE와만 연결되어 있습니다. 전역 데이터 버스(Global Bus)에 연결되지 않으므로, 데이터를 멀리 보낼 필요가 없어 배선 복잡도와 전력 소모가 획기적으로 줄어듭니다.
- No Global Control: 개별 PE는 복잡한 명령어를 해석하지 않습니다. 중앙 컨트롤러가 보내는 단일 클럭 신호에 맞춰, 들어온 데이터를 처리하고 옆으로 넘기는 단순 반복 작업만 수행합니다.
2. 작동 메커니즘: Weight Stationary 기반의 데이터 흐름
구글 TPU v1은 Weight Stationary (WS) 데이터플로우를 Systolic Array로 구현했습니다. N * N 행렬 곱셈(C = A * B)을 예로 들어 작동 원리를 단계별로 분석해 봅시다.
- Weight Pre-loading (가중치 적재):연산을 시작하기 전, 행렬 B(가중치)의 값들이 각 PE에 미리 Load됩니다. 이 값들은 연산이 끝날 때까지 해당 PE의 레지스터에 고정(Stationary)됩니다.
- Input Streaming (입력 데이터 주입):행렬 A(입력 데이터)의 값들이 배열의 왼쪽에서 오른쪽으로 흐릅니다. 이때 중요한 것은 Skewing입니다. 모든 행의 데이터가 동시에 들어가는 것이 아니라, 첫 번째 행이 T=0에, 두 번째 행이 T=1에 들어가는 식으로 한 사이클씩 지연되어 들어갑니다. 이는 대각선 파동(Wavefront) 형태의 데이터 흐름을 만들어냅니다.
- Systolic Flow & Accumulation:
- 각 PE는 왼쪽에서 받은 입력값(Arow)과 자신이 가지고 있는 가중치(Bfixed)를 곱합니다.
- 그 결과(부분합)를 위쪽에서 내려온 값과 더합니다.
- 입력값(A)은 오른쪽 PE로 전달하고, 갱신된 부분합(C)은 아래쪽 PE로 전달합니다.
- 이 과정이 매 클럭 사이클마다 심장 박동처럼 규칙적으로 일어납니다.
- Output Draining (결과 배출):배열의 가장 아래쪽으로 완성된 결과값(C)들이 순차적으로 밀려 나옵니다.
3. Systolic Array의 핵심 장점
왜 구글은 수많은 아키텍처 중 Systolic Array를 선택했을까요? 그 이유는 연산 밀도(Density)와 대역폭 효율(Bandwidth Efficiency)에 있습니다.
A. O(N2)의 연산을 O(N)의 대역폭으로 처리
Systolic Array의 가장 강력한 특징입니다. N * N 크기의 PE 배열에는 N2개의 연산기가 있습니다. 하지만 외부 메모리와 연결된 입출력 포트는 배열의 테두리에 있는 N개뿐입니다.
즉, 한 번 데이터를 메모리에서 읽어오면(N), 내부적으로 N번의 재사용이 일어나 총 N2번의 연산을 수행합니다. 이는 메모리 대역폭 병목을 해결하고 Roofline 모델의 Compute-bound 영역으로 시스템을 밀어 넣는 가장 효과적인 방법입니다.
B. 높은 면적 효율성 (High Area Efficiency)
각 PE는 제어 유닛(Control Unit)이나 복잡한 캐시 계층 없이 순수하게 MAC 연산기 위주로 구성됩니다. 따라서 동일한 실리콘 면적 대비 훨씬 더 많은 수의 연산기를 집적할 수 있습니다. TPU v1의 경우, 700MHz의 낮은 클럭으로도 거대한 256 * 256 배열을 통해 막대한 TOPS(Tera Operations Per Second)를 달성했습니다.
4. 단점 및 한계: 유연성(Flexibility)의 부재
모든 설계에는 트레이드오프(Trade-off)가 존재합니다. Systolic Array는 행렬 연산(Matrix Multiplication)에는 극강의 효율을 보이지만, 그 외의 작업에는 취약합니다.
A. 레이턴시와 파이프라인 채우기 (Fill & Drain Overhead)
배열이 꽉 차서 모든 PE가 가동되기까지(Fill), 그리고 마지막 데이터가 빠져나오기까지(Drain) 시간이 걸립니다. 이를 Pipeline Priming 시간이라고 합니다. 따라서 처리해야 할 데이터(Batch Size)가 작으면, 파이프라인을 채우기도 전에 연산이 끝나버려 PE 가동률(Utilization)이 급격히 떨어집니다. 이는 TPU가 ‘Large Batch’ 추론이나 학습에 유리하고, 실시간 ‘Batch 1’ 추론에는 불리한 이유입니다.
B. 희소성(Sparsity) 처리의 어려움
Systolic Array는 데이터가 꽉 차 있는 밀집 행렬(Dense Matrix)을 가정합니다. 만약 데이터에 0이 많은 희소 행렬(Sparse Matrix)이라도, 규칙적인 흐름(Rhythm)을 깨뜨릴 수 없기 때문에 0을 곱하는 무의미한 연산을 수행해야 합니다. 이를 해결하기 위해 최근에는 구조적 희소성(Structured Sparsity)을 지원하는 하드웨어 연구가 진행되고 있습니다.
[Conclusion]
Systolic Array는 데이터 이동 비용 최소화라는 NPU 설계의 대원칙을 하드웨어 레벨에서 가장 우아하게 구현한 구조입니다. 국소적인 연결(Local Connection)만으로 거대한 병렬 연산을 수행하는 이 방식은 구글 TPU의 성공 이후 현대 AI 반도체의 표준 교과서가 되었습니다.
하지만 수만 개의 PE가 쉴 새 없이 돌아가려면, 그만큼 데이터를 끊김 없이 공급해 줄 강력한 메모리 시스템이 뒷받침되어야 합니다. 다음 글에서는 이 Systolic Array에 데이터를 먹여 살리기 위한 “메모리 계층 구조(Memory Hierarchy): DRAM – Global Buffer – PE Register”의 데이터 이동 전략에 대해 알아보겠습니다.
참고: In-Datacenter Performance Analysis of a Tensor Processing Unit