코어-메모리 병렬화, 데이터 이동 최적화, 자원 재활용과 최적운송이론
AI 컴퓨팅의 병목이 코어-메모리의 폰노이만 격차, 그리고 코어의 동작 속도와 메모리의 대응 속도 사이의 격차인 메모리 장벽에 있음은 잘 알려져 있습니다. 이를 근본적으로 해결하는 일은 여전히 요원하며, 따라서 이를 우회하기 위해 반도체 업계에서는 다양한 기술적 시도가 진행되고 있습니다. 이 중에서 가장 가능성이 높아 보이는 병렬화 방법론은 어떤 장점이 있으며 또 어떤 한계가 있는지 살펴볼 필요가 있습니다. 그러한 한계를 다시 극복하기 위한 전략도 알아볼 필요가 있습니다.
일단 이 메모리 장벽이 비단 latency만 있는 것은 아니기에, 조금 더 세밀하게 데이터의 이동에 걸리는 시간을 나눠서 생각해 보겠습니다. 일단 첫 번째 단계는 DRAM의 셀 액세스(DRAM array access)에 걸리는 시간입니다. 여기에 시간이 걸리는 까닭은 DRAM 모듈 내부에서 특정 데이터를 찾기 위해 행(row)을 활성화한 후, 다시 열(column) 접근을 하여 위치를 특정한 다음, 그 위치에 있는 데이터를 읽는 방식의 순차 처리가 필요하기 때문입니다. 보통 DDR5 DIMM의 경우 대략 90-100 ns 정도 걸리고, HBM은 50 ns 내외 정도 걸립니다. HBM의 경우 이 시간을 더 낮출 수는 있는데, 이는 DRAM 셀 근처 로직의 속도를 개선함으로써 가능합니다. 최근 언급되는 SOCAMM의 경우, LPDDR5 기반이므로, 보통 DDR5와 설계 구조를 상당 부분 공유하기 때문에, 50-60 ns 정도로 시간을 낮출 수 있습니다.
두 번째 단계는 메모리 모듈 내 PHY와 버스 전송에 걸리는 시간입니다. 이는 DRAM i/o과 BUS/PHYS 이동 시간의 합으로 계산됩니다. 일단 DRAM 다이에서 특정 위치에 있는 데이터를 찾아 읽는다고 끝나는 것이 아니라, 그 데이터를 이제 이동시켜야 하는데, 이동의 관제는 메모리 컨트롤러가 합니다. 따라서 다이에서 컨트롤러로 가는 시간이 걸립니다. 그리고 컨트롤러를 통과한 데이터는 패키지 핀(PHYS)으로 옮겨지고, 이를 통해 CPU 등과 연결된 외부 버스에 메모리가 올라탑니다. DDR5 DIMM의 경우 10-20 ns 정도 걸리는데, 대부분의 시간은 버스 타이밍 맞추고, i/o signaling 하기 위한 오버헤드로 소요됩니다. HBM은 이 시간을 5 ns까지 낮출 수 있습니다. 이는 tsv 방식으로 위에 언급한 각 단계의 물리적 거리를 최단거리로 낮출 수 있기 때문입니다. SOCAMM의 경우, LPDDRX 기반을 가정하면 역시 10 ns 정도 걸립니다. CXL을 장착한 DRAM도 대략 10 ns 정도 걸립니다.
세 번째 단계는 메모리 컨트롤러와 GPU 혹은 노드 내의 GPU-to-GPU 데이터 전송이고 여기에는 GPU-to-CPU 메모리 연결에 100-150 ns 정도 소요됩니다. NVLINK를 쓰면 이 시간을 100 ns 이하로 줄일 수 있습니다. 인텔 등이 추진하는 UALINK를 이보다 더 짧은 시간을 목표로 하는데, 50 ns 이하를 목표로 합니다. CXL이나 SOCAMM은 30-40 ns 사이에서 통제가 가능하며, 이는 온-모듈 기반으로 레이아웃을 최적화할 여지가 있기 때문입니다. HBM의 경우, 온-인터포저 방식이므로 2-5 ns까지 줄일 수 있습니다.
네 번째 단계는 GPU on-die cache (L2 cache) 로서, HBM은 대략 10-20 ns, SOCAMM은 20-30 ns, CXL은 100 ns, NVLINK는 20 ns, UALINK도 대략 20 ns로서, 대동소이합니다.
마지막 단계는 GPU SM 내 로드/저장 (L1/shared memory-to-register) 단계로서, 한 사이클에 대략 1-2 ns 정도로 매우 빠르게 진행됩니다.
어쨌든 이러한 단계를 모두 거치면 범용 DDR PCIe 활용 시, 300 ns 정도, HBM (on-interposer) 활용 시 70 ns 정도, CXL (DDR5 CXL-A) 활용 시 270 ns, SOCAMM (LPDDR5X) 활용 시 130 ns 정도, NVLINK 활용 시, 200 ns 정도, UALINK 활용 시 170 ns 정도 됩니다. 한 가지 유념할 부분은 애초에 HBM, CXL, NVLINK는 같은 층위에서 동등하게 비교되기에는 좀 무리가 있는 기술들이라는 것입니다. 그렇지만 이러한 기술들을 활용하여 메모리-to-코어의 과정만 본다면 대략적으로 이렇게 추정될 수 있다는 것 정도입니다.
어쨌든 각 접근법에 대해 기술적 혁신은 앞으로 계속되겠지만, HBM은 50 ns 정도가 한계로 보이고, SOCAMM은 100 ns, CXL은 250 ns 정도, NVLINK는 70 ns, UALINK는 50 ns 정도가 한계로 보입니다. 그래서 앞으로 고속 메모리 설계 방향은 풀스택 통합이 추진되어야 할 것으로 보이고, 온-다이 광인터커넥트는 옵션이 아니라 필수가 될 것으로 보입니다. 특히 STCO (system-technology co-optimization)이 정말 중요할 것으로 보이는데, 이는 각 층위의 기술을 패키징 하는 단계에서 설계한 지연 특성들이 제대로 구현되지 못할 수도 있을 것이기 때문입니다. (이는 HBM에서 하이닉스를 제외한 다른 메이커들이 고생하는 것만 봐도 알 수 있습니다.)
따라서 메모리 내부의 데이터 i/o 시간 단축과 더불어, 보다 근본적인 질문을 해야 합니다. 예를 들어 많은 사람들은 이제 수백, 수천 장의 GPU를 연결하여 클러스터화 시키면 좋을 것이라는 점에 대해서는 다들 쉽게 받아들이고, 또 목놓아 AI 데이터 서버를 더 크게 만들어야 한다고들 주장하지만, 정작 병렬 컴퓨팅 관점에서는 이를 깊게 고민하는 목소리들은 잘 나오지 않고 있습니다.
제가 박사과정일 때, 저는 매우 거대한 규모의 MC simulation을 KMC 기반으로 돌린 적이 있습니다. 고분자 콜로이드 입자의 자기조립을 모델링하기 위해 단 10만 개 정도의 입자만 고려해도, 컴퓨팅 파워가 너무 많이 들어간다는 것이 문제였고, 그래서 48 코어짜리 클러스터에서 이러한 시뮬레이션을 돌리기 위해 병렬화를 조금 공부했던 적이 있습니다. 그때 나이브했던 저는 24 코어짜리 클러스터에서 돌릴 때보다, 당연히 48 코어짜리에서 돌리면 계산 시간이 절반으로 단축될 것이라 믿었지만, 실제로 두 클러스터를 직접 돌려보니, 시간은 생각만큼 많이 단축되지 않았다는 것을 발견했던 기억이 납니다. 코어의 개수에 비례하여 병렬 컴퓨팅 계산 시간이 무조건 단축되지 못하는 이유는 여러 개 있습니다. 그중에서도 고려해야 할 것은 병렬 컴퓨팅 자체의 계산 자원 분배에도 또 다른 계산이 필요하다는 것입니다.
대략 두 세대 전, 처음으로 병렬 컴퓨팅 개념이 나오기 시작했을 때는 데이터 자체의 병렬성에 초점을 맞췄습니다. 그때는 클러스터 개념도 없었고, CPU를 연결한다는 개념도 없었죠. 콘솔에서 제한된 자원을 최대한 활용하기 위해, 중앙 메모리 개념을 이용하여, 벡터 프로세서를 이용하는 것이 주요 전략이었습니다. 그러다가 CPU의 대량 생산이 시작된 80년대 이후, MIMD (multi-instruction, multi-data) 기반의 현대적인 클러스터 컴퓨팅 개념이 나오기 시작했고, 기기간 통신이 정립되면서 코어뿐만 아니라, PC-to-PC 연계 클러스터 시스템이 구현되기도 했습니다. 2000년대 이후에는 인텔이 선보이기 시작한 멀티코어 기술, GPU, 클라우드 개념들이 차례로 등장하면서, 범용 병렬 가속기 개념이 나왔습니다. 병렬 컴퓨팅의 발전은 하드웨어 발전도 한몫했지만, 사실 더 중요한 병목 지점은 데이터를 어떻게 나눠서 동시성을 유지할 수 있느냐, 그리고 지역성이 최적화된 알고리즘을 어떻게 구현하느냐에 있었다고 볼 수 있습니다.
특히 지역성이 최적화된 알고리즘은 수천 개의 코어를 가지고 있는 GPU를 병렬 컴퓨팅 가속기로 쓰기 위해 매우 중요한 기술이었는데, 예를 들어 커다란 행렬 데이터를 블록으로 나누거나 타일링하는 작업 등은 이러한 지역성을 보장하기 위한 일종의 전처리 기술이라고도 볼 수 있습니다. 예를 들어, 훈련 데이터 전체를 N개의 GPU에 샘플 단위로 분할한 후, 각 GPU가 로컬 gradient를 계산하고, 다시 NCCL 기반 all-reduce로 '평균' gradient를 계산하면서 가중치를 갱신하는 학습 과정을 생각해 봅시다. 이는 기존의 CPU cluster에서 활용되던 분산 SGD (stochastic gradient decent) 개념과 유사하지만, GPU cluster에서는 GPU-to-GPU link 혹은 GPU-NIC-GPU (infiniband 등)의 경로를 최우선적으로 활용하여 통신 자체에 의한 오버헤드를 최소화하는 것이 더 중요하다는 차이점이 있습니다. 따라서 데이터 전처리는 단순히 패치워크나 분할만 다루는 것이 아니라, 샘플들의 gradient 압축(quantization), dynamic gradient scaling 기법이 더해져야 하는 작업이기 때문에 최적화 여지가 아직 꽤 남아 있습니다. 예를 들어 데이터 병렬화는 이제 모델 병렬화까지 아우르게 되는데, 구체적 사례로서 대형 transformer 계열의 모델 (GPT4 등)에서, 데이터를 분할할 때 단순히 행렬 크기만 생각하는 것이 아니라, 이제는 레이어 단위나 어텐션 헤드 단위로 GPU에 분할하는 것이 이러한 사례입니다. 특히 파이프라인 병렬화는 수천 개의 GPU 코어에 가해지는 동기화 오버헤드를 분산시키기 위해 활용될 수 있는 기술입니다.
여기에 더해 전처리된 거대한 데이터가 잘게 나뉘어 수천 개의 코어에서 동시에 작동하게 만들기 위해서는 코어 간 통신-동기화의 오버헤드를 최소화할 필요가 있습니다. 이는 쉽게 이해하자면 이런 것입니다. 100명의 요리사가 100인분의 요리를 최대한 빨리 만들기 위해, 1명이 1인분의 요리를 만드는 것이 아니라, 각자 철저하게 분업하여 (누구는 재료 손질, 누구는 플레이팅, 누구는 열처리 등) 일을 진행하면 좋을 것이라는 점은 누구나 잘 이해합니다. 문제는 분업한 일들이 동일한 시간에 끝나야 한다는 것입니다. 예를 들어 100인분의 당근을 다듬는 일을 하는 한 명의 요리사는 그 작업을 10분 내로 끝낼 수 있는데, 고기 요리를 담당한 다른 한 명의 요리사가 1시간이 걸린다면, 분업을 한 보람은 없을 것입니다. 왜냐하면 결국 요리 완성은 10분이 아니라 1시간이 걸릴 것이기 때문입니다. 그러면 이러한 생각을 할 수 있을 것입니다. 당근 다듬는 것에는 최소한의 인원만 배치하고, 고기 요리에 더 많은 요리사를 배치하는 것이 중요하겠다는 것 말이죠. 그리고 각 인원이 동시에 거대한 체육관 같은 곳에서 조리한다고 하더라도, 조리대 사이의 간격이 너무 멀면 요리 결과물을 서로 주고받는 데에도 꽤나 긴 시간이 걸릴 수 있을 것이니, 그 간격도 최소화해야 할 것이라는 생각을 할 수 있습니다. 또한 중간에 요리 결과물이 상하면 요리 전체가 망할 수 있으므로, 중간중간 그것을 점검하는 단계가 필요할 것입니다. 이러한 단계들은 통신 오버헤드로 볼 수 있습니다. 이제 관건은 어떻게 하면 계산 자원을 동기화시키고, 최대한 동시성 관점에서 일을 진행시키면서, 계산 자원을 최소한만 이용하여 오버헤드에 할당할 것이냐는 점입니다.
한 세대 전쯤에는 Bulk synchronous paralle (BSP) 모델이 이러한 목적으로 쓰였습니다. GPU 커널을 계산 단계-동기화 단계로 분리하여, 전역에서의 계산 효율을 극대화하는 것이 목표였습니다. BSP는 이후 GPU 간 통신 패턴을 추상화해 통신-계산을 동시에 최적화하는 단계까지 진화했습니다. 여기에 엔비디아 같은 회사는 CUDA dynamics parallelism을 구현했는데, 이는 CUDA graphs로 GPU 내 스레드 블록 관리를 최적화하는 SW였고, 이는 나중에 더 복잡한 데이터 형태인 텐서 연산 라이브러리고 발전하여, 단순히 행렬 같은 데이터뿐만 아니라 보다 추상화된 데이터인 큰 규모의 그래프 데이터를 더 작은 단위로 분할하여 수천 개의 GPU에서 동기화될 수 있게 만들어주었습니다. 이는 과거 행렬의 LU 분해, QR 분해 등에서 자주 쓰이던 패널 분할, 타일 분할 전략을 GPU에서는 2^N 크기를 갖는 블록 행렬로 쪼개고, 각 블록 내에서 다수의 FMAs(벡터 MAC)를 수행하고, 다음 블록의 데이터가 필요해지기 전에 미리 교환(pre-fetch)하는 방식으로 확장-발전한 look-ahead 전략으로 구현될 수 있습니다. 또한 한 번에 모든 GPU가 글로벌 reduce를 수행하는 대신, NVlink 내부 레벨에서 (group reduce) 진행한 후, node 레벨에서 (shared memory), 다음으로 rack 레벨에서 (infiniband), 마지막으로 dc 레벨 순서로 hierarchical reduce를 구현할 수 있습니다. 여기에 워크그룹 단위로 스케쥴링을 최적화할 수 있는 동적 스케쥴링이 가미되면 오버헤드를 더 줄일 수 있을 것입니다. 특히 tensorflow나 pytorch 같은 딥러닝 프레임워크는 기본적으로 연산 그래프를 기반으로 동작하므로, 연산 노드 간 연결을 비동기 데이터 스트림으로 표현하여 일종의 데이터플로우 머신으로 보는 것이 가능하고, 각 모델의 연산-GPU 커널 태스크 대기 시간을 줄일 수 있습니다.
이렇게 갖은 노력을 기울여도 앞서 언급한 오버헤드를 완전히 죽이는 것은 어렵습니다. 이러한 한계는 주로 암달의 법칙(Amdahl's law)으로 잘 표현됩니다. 암달의 법칙에서는 코어를 N배 할 때, 실제 병렬화 효율이 몇 배나 될지 측정하는 방식을 제시합니다. 앞서 제 경험에서 언급한 24 core vs 48 core 경우에서도, 그냥 단순하게 생각하면 2배의 효과가 나와야 할 것 같지만, 실제로는 1.4배 정도에 그치는 원인을 설명하는 셈이죠. 이론적으로 이를 살펴보면
S(N) = 1/( (1-p) + (p/N)) 로 쓸 수 있습니다. 여기서 p는 전체 작업 중 병렬화 가능한 비율을 의미하며 (따라서 1-p는 직렬화해야만 하는 비율을 의미), N은 코어나 스레드, 노드 혹은 SM 개수를 의미합니다.
GPU의 경우에 빗대본다면, p는 순수 행렬 연산 혹은 벡터 MAC 등 완전 병렬 계산에 할당할 수 있는 커널의 비중으로 볼 수 있고, 1-p는 그 외의 작업, 즉, 데이터 로드/저장 (memory(PCIe)-to-GPU), 스레드 내부 동기화 관리/점검용 (warp/CTA barrier), GPU-CPU 제어 연산 등에 할당되는 연산 비중으로 볼 수 있습니다.
예를 들어 p = 0.95, N = 1000이라고 본다면, S = 18.5 정도에 그칩니다. 즉, 이상적으로는 1000배 더 빨라졌어야 할 것 같은 연산이 '겨우' 18배 정도 향상된 것입니다. 물론 18배 향상도 어마어마한 것입니다. 예를 들어 2주 이상 걸릴 계산이 하루 이내에 끝날 수 있다는 뜻이니까요. 그렇지만 1000개를 투자한 입장에서는 다소 아쉬운 숫자일 수 있습니다. 당연히 그 체감 효용을 높이기 위해서는 p값을 1에 가깝게 만들어야 합니다. 문제 자체를 병렬화 가능한 영역 쪽으로 확장할 수 있다면 암달의 법칙이 아니라, 구스타프손 법칙(Gustafson's law)을 적용할 수 있는데, 이 경우 스피드업 되는 체감은 (1-p) + pN으로 볼 수 있습니다. 위의 사례를 보면 950배나 빨라지니까 거의 이상적인 수준에 근접한다고 볼 수 있습니다. 물론 이 역시 쉬운 기술은 아닙니다. 그나마 이 정도 수준에 조금이라도 더 가깝게 가려면 파이프라인-스테이지 분할이 이루어져야 하는데, 모델-파이프라인 병렬성이 보장되어야 합니다. 특히 GPU 코어 내 SM에서의 스트리밍 텐서 처리가 연속 데이터 흐름 중에 연산과 통신이 동시에 이뤄질 수 있도록 설계되어야 합니다. 계층적 병렬성도 강화되어야 합니다. 예를 들어 디바이스 내 SIMD-to-SIMT, 디바이스 간 노드-클러스터 병렬화가 더 강화되어야 하는 것이죠. 사실 더 급한 것은 알고리즘 강화일 수 있습니다. 오버헤드를 줄이기 위해 코어 간 혹은 코어-메모리 간 통신 부담 최소화 (혹은 속도 최적화)가 이루어져야 하고, tiled- multiply, block-sparse 모델이 구현되어야 합니다.
사실 병렬화에 있어 어찌 보면 더 유용한 자원 절약 지점 중 하나는 애초에 데이터 자체를 압축할 수 있는 여지가 있다는 것입니다. 압축이라고 하니까 좀 이상하긴 한데, 사실 데이터의 크기를 줄인다는 측면에서는 이상한 표현은 아닐 것입니다. 예를 들어 실수를 디지털로 표현하기 위한 정밀도 조절이 그렇습니다. 딥시크 사건에서 이제는 많이 알려진 것처럼, FP16/FP8 등으로 정밀도를 낮추면 GPU의 각 코어, 각 SM에서 진행되는 데이터 처리 속도는 물론, 메모리 allocation과 전송 속도도 훨씬 빨라집니다. 이는 병렬화와 큰 상관은 없는데, 각 코어에서의 진행이 동시에 빨라진다는 관점에서는 병렬화의 실질적인 체감을 강화시켜 주는 방법론이라 최근 더 중요해집니다. 물론 무턱대고 정밀도를 희생할 수는 없습니다. 그랬다가는 애써 병렬 처리한 계산 결과가 쓰레기가 될 수도 있으니까요. 결국 여기에서도 주기적으로 정밀도를 희생한 결과가 계속 누적될 때 미리 정해놓은 오차 한계를 넘어가지 않는가를 모니터링하기 위한 오버헤드가 또 들어갑니다. 이는 병렬 계산하여 얻고자 하는 결과물의 성격에 따라 조절될 수 있습니다.
사실 위에서 언급한 메모리-to-core의 병목현상 줄이기 기술도 그렇고, 병렬화의 방법론 개선도 그렇고, AI 학습 및 추론 계산에 있어 궁극적인 병렬 컴퓨팅의 목표는 latency를 0으로 만드는 compute fabric을 구현하는 것일 것입니다. core와 메모리 사이의 물리적 거리를 그야말로 극한으로 줄이고, 여기에 더해 논리적 거리도 줄여야 이러한 목표가 달성될 수 있을 것입니다. 에너지 효율 관점에서도 latency를 0으로 수렴시킬 수 있는 전역 병렬화는 매우 중요합니다. 대기 시간이 길어질수록 에너지 효율은 낮아지기 때문입니다. HW 관점에서는 지난 글들에서 언급한 것처럼, SOC, GPU, memory, interconnect 등을 따로 설계할 것이 아니라, 하나의 풀스택으로 STCO 해야 하고, 풀스택된 시스템이 무리 없이 동기화되어 돌아갈 수 있도록 컴파일러, 런타임, 프레임워크 같은 SW 영역도 최적화되어야 합니다. 예를 들어 CUDA graphs + NVSwitch backplane + PIM-DRAM 풀스택 최적화는 제가 알기로는 아직 최적화된 SW가 없는 것으로 알고 있습니다.
더 근본적인 관점은 애초에 이러한 기술적 난제가 되고 있는 폰노이만 구조를 탈피하고 기술의 중심을 동기화가 아닌, event-driven, data-driven으로 shift 하는 것일 것입니다. 많이들 이야기하는 뉴로모픽이나 멤리스터는 좋은 후보가 될 수 있으나, 여전히 궁극적인 해결책은 아니므로, 완전히 다른 개념의 구조가 등장해야 하는 기술적 압력은 점점 높아지고 있습니다.
이중에서도 data-driven shift의 방향은 무엇이 되어야 할지를 한번 보겠습니다. 예를 들어, core-memory data의 end-to-end 데이터 플로우를 살펴보면 여러 지점에서 병목 지점이 생김을 우리는 잘 알고 있습니다. 이러한 병목 지점을 계층별로 매핑하여 전체 경로의 대역폭과 레이턴시를 계층별로 정밀 측정하고 시각화하는 것이 우선 필요합니다. 여기서 말하는 대역폭이란 스펙 상의 대역폭이 아니라, 실제 활성화된 대역폭을 의미하며, 이를 모니터링하기 위해서는 대역폭을 런타임에 올려서 직접 측정해야 합니다. 이렇게 매핑-측정이 끝나고 나면, 이제 어떤 부분에서 조절이 가능해질지 보입니다. 지금까지 상식적으로 생각하던 고정된 정적 위상구조 대신, 지연이 짧은 경로를 우선 사용하고, 동적으로 워크로드를 재배치하는 작업이 가능해지는 것입니다. 이는 비유하자면 서울-부산을 일직선으로 잇는 고속도로가 있다고 할 때, 당연히 서울-부산 이동은 그 속도를 제한속도까지 풀액셀을 밟아서 가는 것이겠지만, 만약 대전-대구 구간이 막힌다면 우회로를 찾아가는 것과 마찬가지입니다. 이때 흥미로운 점은 대전-대구 구간에 몰린 교통량 일부를 차량의 운전자에게 스스로 맡기는 것이 아니라, 일종의 통합 관제센터에서 실시간으로 교통량을 관측하면서 각 차량의 이동 방향과 교통량을 이리저리 우회시킨다는 것입니다. 여기서 중요한 것은 물리적, 지리적 거리의 길고 짧음이 아니라, 시간 상 거리가 더 중요하다는 개념입니다. 회로 자체가 물리적 거리를 아무리 짧게 구현했다고 하더라도, 그것이 늘 최적운송구조를 보장하는 것은 아니라는 점이죠. 이 지점에서 매우 흥미로운 수학적 방법론이 등장합니다. 그것은 바로 그래프 상의 최적 신호 전달 구조를 찾는 최적운송이론(optimal transport)입니다.
AI 연산에 있어, 이 연산이 까다로운 까닭 중 하나는 다뤄야 하는 데이터 크기가 크다는 점도 있습니다만, 워크로드가 constant 하지 않다는 점도 있습니다. 동일한 랙에서도 스파이크가 생길 경우, 네트워크에서 배정해야 하는 대역폭이 갑자기 커지면 금방 포화될 수 있습니다. 이러면 레이턴시는 순간 급증하여 전체적인 연산 속도가 halt 될 수도 있습니다. 또한 파이프라인 단계 간 동기화 체크 주기가 짧아지면서 물리적으로 최근접 노드와 실제 네트워크 혼잡도를 낮출 수 있는 위상적 최근접 노드가 일치하지 않는 경우도 늘어나고 있다는 점도 어려운 지점입니다. 결국 인접한 노드 사이의 최단 경로가 몇 개의 p-switch를 거치는지의 위상적 개념, 연계된 이웃 간 노드에 얼마의 대역폭을 배정할 것인지의 개념, 시간적으로 예측 가능한 워크로드와 예측이 어려운 워크로드에 대해 계산자원을 얼마나 예측하며 배정하여 혼잡도를 최소화할 것인지의 개념이 모두 정리되어야 합니다.
이러한 문제들은 생각보다 굉장히 복잡하고, 이를 해결하기 위해 귀중한 계산 자원을 배분하다 보면 배꼽이 배보다 더 커진다는 문제가 생깁니다. 암달의 법칙 저주에 또 빠지는 것이죠. 그래서 최적운송이론 같은 수학적 문제 해결 관점에서 이 문제를 들여다보는 것도 중요합니다. 예를 들어 최적운송에서 다루는 거리 개념은 Wassertein distance로 환원될 수 있는데, 이 거리는 물리적, 지리적 거리와는 별 상관이 없고, 두 노드 사이를 잇는 물리적 이벤트의 성능에 대한 함수로 결정됩니다. 예를 들어 두 노드 사이의 대역폭 활용률, 데이터 전송률, 전송 시간 등은 꼭 물리적 거리로만 결정되지는 않는 것을 생각하면 됩니다. 조금 더 구체적으로 이야기해 보자면, GPU-cluster 환경에서는 텐서 블록 같은 데이터 덩어리를 GPU 코어의 SM 같은 연산 자원에 매핑할 때, 비용함수를 전역적으로 최소화하는 것이 필요한데, 이때 비용함수는 레이턴시, 전력소비, QoS 제약 등을 고려한 복합 가중치 함수로 볼 수 있고, Wassertein distance는 이러한 복합 가중치 비용으로 볼 수 있을 것입니다. 여기서 고려해야 할 부분은 데이터 블록이 분포하는 함수(예: 메모리 계층 또는 캐시 상에 저장된 텐서 블록들의 위치 분포)와 연산자원 등이 분포하는 함수(예: 가용한 GPU SM/노드의 여유 혹은 처리 능력 분포)의 매칭/매핑입니다. 예를 들어 데이터 블록과 GPU 노드 간 연관성 모델링은 Latencycost를 네트워크 상의 위상적 거리 (즉, 스위칭 호핑 횟수) * 현재 혼잡도로, Computecost를 해당 GPU의 여유 정도 (스케줄 대기 시간), Datalocalitycost를 같은 랙/인터포저/TSV 레벨 등 온-칩 연결성 여부 등으로 정의할 수 있고, 이들의 가중치 합을 이용하여 Wasserstein distance를 정의하는 것입니다.
최적운송이론에서 구현된 방법론으로 이 distance를 실시간으로 최소화하면, 어떤 텐서 블록을 어떤 GPU 노드에 할당함으로써 전역 지연을 최소화할 수 있는지를 평가할 수 있습니다. 특히 전형적인 최적운송이론과는 달리, 네트워크의 구성 요소 혹은 각 노드 간 연결 특성이 실시간으로 변하기 때문에, 데이터 블록 분포함수와 연산자원 분포함수 자체도 시간에 따른 함수라는 점을 고려해야 하는 점은 더더욱 요구 계산량을 늘어나게 만들 수 있는데, 이때 중요한 힌트 중 하나는 베이지안 방법론이나 학습 기반 Sinkhorn 등의 알고리즘을 활용하여 네트워크 상 혼잡도 변화를 예지보전하면서 대응 시간을 줄이고 대응 자원의 효율성을 높일 수 있다는 것입니다 (실제로 Sinkhorn 알고리즘은 딥러닝 기반 이미지 처리에서 Wasserstein GAN (WGAN) 등에 쓰이기도 하고 graph neural network(GNN)에서 그래프 유사도 등을 계산할 때 사용되기도 합니다.). 이는 결과적으로는 확률론적 최적운송이론의 적극적인 도입이 앞으로 더 중요해질 것이고, 이를 통해 실제로 오버헤드를 얼마나 낮출 수 있느냐가 중요해질 것임을 의미합니다. 특히 Wassertein distance의 조금 더 특수한 형태인 Sinkhorn distance는 엔트로피 정규화(즉, entropy scaling)를 반영하여 수천 개의 GPU 코어가 분포하는 연산자원 분포 함수를 보다 정밀하게 모사(특히 Sinkhorn-Knopp algorithm은 계산자원이나 데이터 블록 분포 함수를 볼츠만 분포 형태의 해로 환원할 수 있다고 알려져 있습니다.) 할 수 있기 때문에, 앞으로는 GPU-adaptive Sinkhorn distance control 알고리즘이 중요해질 것으로 예상됩니다. 이를 위해 실시간으로 업데이트되는 최적운송이론 계산을 위한 분포 함수 정보 및 이전 단계에서 계산된 최적거리 정보값을 GPU 내 shared memory/register에 상시 올려 두고, 메모리 왕복을 최소화하면서 이를 업데이트하는 알고리즘이 구현되어야 합니다. 이는 결과적으로는 메모리 장벽도 낮추면서 병렬화 효과도 높여주는데 기여할 것입니다.
최적운송이론이나 위상수학적 방법론을 적극 활용하는 것은 또한 AI 모델 자체의 위상구조를 분석하면 한 번 더 부스터를 달 수 있습니다. 예를 들어 모델의 파라미터 dependence network 구조를 감안하여 텐서 블록을 어떻게 나누고 어떻게 올리고, 다음번 텐서에 맞게 연산 자원 배치를 어떻게 조정하는지의 정보는 처음부터 AI 모델의 위상구조를 제대로 분석하면 더 효과적으로 할 수 있습니다. 즉, predictive data pre-fetch가 더 효율적으로 개선될 수 있다는 것입니다. 물론 최적운송이론 기반 최적화는 결코 가벼운 계산이 아닙니다. 분포 함수를 이루는 노드나 블록의 개수 (n)에 대해, 계산 난도는 O(n^3)이 되기 때문입니다. 또한 Sinkhorn 방법론 역시 메모리 요구량이 분포 함수 크기의 곱에 비례하여 늘어난다는 한계가 있으므로, 메모리 자원 관리에서 늘 유리한 것도 아닙니다.
따라서 한국에서 향후 더 다양한 방향으로 진화될 AI 하드웨어의 다음 단계 비전을 확보하기 위해서는 원천 기술의 관점에서 보았을 때, 수학적 추상화부터 시작하여 풀스택 STCO, 그리고 메모리 계층 전략과 오버헤드 절감의 전략을 모든 주기에서 테스트하고 실용화할 수 있는 기술적 전략들이 구체화되어야 합니다. 병렬화는 피할 수 없는 기술적 솔루션이고, 현재의 메모리 장벽은 당분간 크게 줄일 수 없겠지만, 결국 데이터의 로딩-언로딩-연산-왕복의 모든 단계에서 여전히 최적화할 여유가 있음을 인지하고 각각의 기술에 대해 기존의 방식을 연장한 방식 외에도, 근본적인 변신도 계속 시도해야 할 것입니다. 한국 메모리 메이커들에게 여전히 많은 기회가 남아 있고, AI 연산의 최적화 관점에서는 더 많은 시도를 해야 하는 이유이기도 합니다.