기준일을 100으로 놓고 그린 선입니다. 통화가 서로 달라 지수로 겹쳤습니다.
아래 손잡이를 움직이면 도달 성능과 활용률이 그 자리에서 계산됩니다. 핵심은 나눗셈 하나입니다 — 임계 연산강도 = 연산 성능 ÷ 대역폭. 이 값보다 연산강도가 낮으면 칩은 계산할 게 없어서가 아니라 읽어 올 게 안 와서 놉니다.
위 단면은 제가 블렌더로 지은 모식도입니다. 아래는 사람들이 실제로 뚜껑을 까고 잘라서 찍은 사진입니다 — 위키미디어 커먼즈에서 라이선스가 확인되는 것만 가져왔습니다.
가운데 크고 매끈한 회색이 GPU 다이입니다. 그 주위에 작고 어두운 네모 네 개가 보이는데 그게 HBM 스택입니다. 밑에 무지개색으로 번들거리는 판이 실리콘 인터포저고요.
이 사진이 말하는 건 하나입니다 — 메모리가 GPU 바로 옆에 있습니다. 보통 그래픽카드는 메모리 칩이 기판 위에 흩어져 있는데, 여기는 손톱만 한 판 하나 위에 다 올라와 있습니다. 선을 짧게 만들려고 이렇게 합니다. 짧아야 많이 뽑을 수 있고, 많이 뽑아야 대역폭이 나옵니다.
Tesla P100(GP100)을 잘라서 찍은 것입니다. 촬영자가 층마다 두께를 재서 적어 놓았습니다.
DRAM 한 장이 50μm입니다. 사람 머리카락이 70~100μm이니 그보다 얇습니다. 그 얇은 판을 여러 장 겹쳐 놓고 위아래로 구멍을 뚫어 이은 게 HBM입니다.
그래서 위 모식도는 두께를 일부러 부풀렸습니다. 실제 비율대로 그리면 선 몇 개로만 보여 아무것도 설명이 안 됩니다. 진짜 비율은 이 사진 쪽입니다. 왼쪽 아래 하얀 실뭉치는 먼지가 아니라 붓털입니다 — 이런 걸 찍으려면 그만큼 후벼파야 합니다.
Radeon RX Vega 64에서 뜯어낸 HBM DRAM 다이 한 장입니다. 세로 줄무늬가 메모리 뱅크고, 가운데 가로로 지나가는 노란 띠가 채널 회로부입니다.
자세히 보면 표면에 점이 규칙적으로 박혀 있습니다. 그게 관통전극(TSV) 자리입니다 — 점 하나하나가 위층 다이로 신호를 올려보내는 구멍입니다. 위 모식도에서 구리 기둥으로 그린 게 이것이고, 이 점의 개수가 곧 배선 1,024개로 이어집니다.
검게 뭉개진 자국은 뜯어낼 때 남은 접착제입니다.
★관통전극을 나노미터 배율로 찍은 SEM 사진은 커먼즈에 없습니다. 그건 사실상 전부 기업이 들고 있어서, 공개 라이선스로 구할 수 있는 실사진은 여기까지입니다. 없는 것을 있는 것처럼 채우지 않았습니다.
가중치가 N개인 모델이 토큰 하나를 낼 때 곱셈과 덧셈을 2N번 합니다. 배치가 B면 계산은 2NB번으로 늘지만, 읽어 오는 가중치는 그대로 N개입니다 — 한 번 읽어서 배치 전체가 나눠 씁니다. 그래서 연산강도는 2NB ÷ (N × 2바이트) = B. fp16에서는 배치 숫자가 곧 연산강도입니다.
여기서 이 판의 결론이 나옵니다. 한 사람이 혼자 쓰면 배치는 1이고, 연산강도도 1입니다. 그런데 굶지 않으려면 수백이 필요합니다. 혼자 쓰는 순간 가속기는 사 놓은 성능의 1%도 못 씁니다. 챗봇 서비스가 요청을 모아서 한꺼번에 돌리는 이유가 이것이고, 그 대가로 내 요청이 남을 기다립니다.
글자 하나를 내려면 모델 전체를 한 번 읽어야 합니다. 그래서 속도의 바닥은 연산이 아니라 가중치 바이트 ÷ 대역폭입니다. 그 훑기를 세워 놓고 보겠습니다.
★위 손잡이로 배치를 키워 보세요. 한 번 훑을 때 나오는 토큰 수가 배치만큼 늘어납니다 — 오른쪽에 초록 토큰이 그만큼 쌓입니다. 그런데 훑는 시간은 꿈쩍도 안 합니다. 그래서 전체 처리량은 배로 오르는데 한 사람이 받는 속도는 제자리입니다. ‘서버를 키웠는데 내 화면은 왜 그대로냐’가 이것입니다.
★배치를 올려 보면 이렇게 됩니다(70B 모델 · 3.4 TB/s · 1,000 TFLOPS 에서 실측). 훑는 시간은 41.2 ms 로 다섯 번 다 똑같습니다.
★296에서 선이 하나 그어집니다. 거기서 연산기가 처음으로 100% 찹니다. 그 전까지는 배치를 키워도 아무도 손해를 안 봅니다 — 한 사람이 받는 속도가 24.3 그대로인데 전체는 24에서 7,143으로 약 300배가 됩니다. 놀고 있던 연산기를 채운 것뿐입니다.
★그런데 512에서는 이야기가 바뀝니다. 전체 처리량은 7,143에서 더 안 늘고, 한 사람이 받는 속도만 24.3 → 14.0으로 떨어집니다. 선을 넘으면 손님을 더 받아 봐야 모두가 느려질 뿐입니다. ‘굶는 쪽’이 메모리에서 연산으로 넘어가는 자리가 여기입니다.
★시간은 눌러 그렸습니다. 한 번 훑기가 실제로는 수십 밀리초라 그대로 돌리면 초당 스무 번 넘게 깜빡여 아무것도 안 보입니다. 화면에서는 한 번 훑기를 늘 2.2초로 고정했고, 진짜 밀리초는 계기가 말합니다. 바꿔 말하면 이 화면에서 빨라져 보이는 일은 없습니다 — 그게 요지이기도 합니다. 빨라지려면 훑는 시간, 즉 대역폭을 건드려야 합니다.
★계산은 위 계기 것을 그대로 씁니다. 여기 숫자는 전부 __hbm.read() 가 내놓는 값이고, 이 층은 그리기만 합니다.
토큰 하나를 내려면 가중치를 전부 한 번 읽어야 합니다. 그러니 한 사람이 받을 수 있는 속도에는 바닥이 있습니다 — 가중치 바이트 ÷ 대역폭. 70B 모델을 fp16으로 올리면 가중치가 140GB이고, 3.4 TB/s로 읽으면 41밀리초가 걸립니다. 그 역수인 초당 24토큰이 한 사람이 볼 수 있는 최대치입니다.
여기서 배치의 정체가 드러납니다. 배치를 32로 키우면 전체 처리량은 32배가 되지만, 한 사람이 받는 속도는 그대로 24토큰/초입니다. 배치는 같은 시간에 더 많은 사람을 받는 장치이지 한 사람을 더 빨리 만드는 장치가 아닙니다. 위 두 번째 판에서 모델 크기를 키워 보면 그 바닥이 어떻게 무너지는지 보입니다 — 405B에서는 초당 4토큰입니다.
위 그림의 비스듬한 지붕 아래에 있는 동안은 성능이 대역폭에만 비례합니다. 그 구간에서 연산 성능을 두 배로 올리면 지붕의 평평한 부분만 높아지고, 내가 서 있는 자리는 그대로입니다. 반대로 대역폭을 두 배로 올리면 비스듬한 지붕 자체가 올라가 성능이 정확히 두 배가 됩니다. 손잡이로 직접 확인해 보세요 — 연산 성능만 끝까지 올려도 배치 1에서는 숫자가 꿈쩍도 하지 않습니다.
메모리를 만드는 회사와 가속기를 파는 회사가 같은 병목의 양쪽에 서 있는 이유입니다. 누가 얼마를 가져가는지는 공개 원가가 없어 이 페이지에서는 수치로 주장하지 않습니다.