21장. AI 거버넌스와 보안, 온프레미스 인프라
GPU 클러스터와 온프레미스 아키텍처
은행 전산실을 지으려면 먼저 하루 거래량을 셈해 서버 수를 정합니다. 모자라면 창구가 멈추고, 넘치면 돈이 샙니다. 온프레미스 LLM 도 모델 크기와 동시 사용자 수로 GPU 메모리를 먼저 셈합니다.
그림은 사내에 두는 LLM 서비스의 층입니다. 1번 사내 인증(SSO)으로 사용자를 확인하고, 2번 API 게이트웨이가 요청 수와 권한을 지키고(13, 17장), 3번 서빙 엔진(vLLM, Ollama)이 모델을 돌리고(16장), 4번 GPU 서버가 계산하고, 5번 저장소에 문서, 색인, 모델, 기록을 둡니다(11, 19장). 은행 전산실의 서버 수가 4번의 GPU 셈입니다.
GPU 메모리를 차지하는 것
| 것 | 셈 | 3B 모델의 예 |
|---|---|---|
| 가중치 | 파라미터 수 × 한 개의 바이트 | 3.09B × 2바이트(fp16) ≈ 6.2GB, 4비트면 약 1.9GB |
| KV 캐시 | 2 × 층 수 × KV 헤드 수 × 헤드 크기 × 바이트 × 토큰 수 | 토큰 하나에 36KB, 4,096 토큰이면 약 0.15GB |
| 계산 여유 | 실행 중의 임시 메모리 | 엔진마다 다르다. 10~20% 를 남긴다 |
메모리 셈
def weights_gb(params_b, bits):
"""가중치가 차지하는 GPU 메모리(GB)"""
return params_b * 1e9 * bits / 8 / 1e9
def kv_gb(layers, kv_heads, head_dim, tokens, users, bytes_=2):
"""KV 캐시(GB): 토큰마다 층마다 K 와 V 를 하나씩 담는다"""
return 2 * layers * kv_heads * head_dim * bytes_ * tokens * users / 1e9
# Qwen2.5-7B: 76.1억 파라미터, 28층, KV 헤드 4개, 헤드 크기 128 (공개된 config.json 값)
for bits in [16, 8, 4]:
w = weights_gb(7.61, bits)
kv = kv_gb(28, 4, 128, tokens=4096, users=8)
print(f"{bits:2d}비트 · 가중치 {w:5.1f}GB + KV(4,096토큰 × 8명) {kv:4.1f}GB = {w + kv:5.1f}GB")코드에 나오는 함수
| 코드 | 쉬운 뜻 |
|---|---|
params_b * 1e9 | 파라미터 수를 억 단위에서 개수로 바꾼다. 1e9 는 1 × 10의 9제곱, 곧 10억이다. params_b 의 b 는 billion(10억)이다 |
bits / 8 | 비트를 바이트로 바꾼다. 8비트가 1바이트다 |
/ 1e9 | 바이트를 GB(기가바이트)로 바꾼다. 여기서는 10억 바이트를 1GB 로 셈한다 |
2 * layers * kv_heads * head_dim * bytes_ | 토큰 하나가 KV 캐시에 차지하는 바이트다. 앞의 2 는 K 와 V 두 벌이라는 뜻이다 |
bytes_=2 | 인자를 주지 않으면 2바이트(fp16)로 셈한다. 파이썬의 bytes 와 이름이 겹치지 않게 밑줄을 붙였다 |
tokens=4096, users=8 | 이름을 붙여 넘긴 인자다. 사람마다 4,096 토큰, 동시에 8명이다 |
f"{bits:2d}", f"{w:5.1f}" | 2칸 폭의 정수, 5칸 폭에 소수 첫째 자리까지로 찍는다 |
이 코드가 뜻하는 것
도서관 열람실과 같습니다. 서가에 꽂힌 책(가중치)은 이용자가 몇 명이든 자리를 똑같이 차지합니다. 이용자마다 책상에 펼쳐 둔 메모지(KV 캐시)는 사람 수와 읽은 쪽수만큼 늘어납니다. 여기서 책이 가중치, 메모지가 KV 캐시, 이용자 수가 users, 읽은 쪽수가 tokens 입니다. 비유와 다른 점도 있습니다. 실제 메모지는 사람마다 쓰는 양이 다르지만, KV 캐시는 토큰 수만 정해지면 크기가 딱 정해집니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
weights_gb(params_b, bits) | 가중치 메모리를 셈한다 | 서가의 책이 차지하는 자리 |
kv_gb(...) | KV 캐시 메모리를 셈한다 | 책상 위 메모지 |
for bits in [16, 8, 4] | 세 가지 정밀도로 셈한다 | 책을 큰 글씨판, 보통판, 축쇄판으로 |
w + kv | 둘을 더한다 | 열람실에 필요한 자리 |
결과에서 가중치는 16비트 15.2GB 에서 4비트 3.8GB 로 줄지만, KV 캐시 1.9GB 는 그대로입니다. 이 코드는 KV 캐시를 늘 2바이트로 셈하기 때문입니다. 비트를 줄여 가중치를 줄일수록 KV 캐시가 차지하는 몫이 커집니다.
작게 줄여서 눈으로 보기
본문 표의 "토큰 하나에 몇 KB" 를 Qwen2.5-7B 의 값으로 직접 셈해 봅니다. 숫자는 본문 코드의 주석에 적힌 설정값입니다.
# Qwen2.5-7B 의 토큰 하나가 KV 캐시에 차지하는 바이트
layers, kv_heads, head_dim, bytes_ = 28, 4, 128, 2
per_token = 2 * layers * kv_heads * head_dim * bytes_ # K 와 V 두 벌
print(f"토큰 하나 {per_token:,} 바이트 = {per_token / 1024:.0f}KB")
print(f"4,096 토큰 × 8명 = {per_token * 4096 * 8 / 1e9:.2f}GB")토큰 하나 57,344 바이트 = 56KB
4,096 토큰 × 8명 = 1.88GB| 결과 | 읽는 법 |
|---|---|
토큰 하나 57,344 바이트 = 56KB | 2 × 28 × 4 × 128 × 2 = 57,344 바이트다. KB 는 1,024 바이트로 나눴다 |
4,096 토큰 × 8명 = 1.88GB | 토큰 하나의 크기에 토큰 수와 사람 수를 곱했다. 본문 결과의 1.9GB 를 반올림하기 전 값이다 |
본문 표의 3B 모델은 토큰 하나에 36KB 였습니다. 모델마다 층 수와 KV 헤드 수가 달라 토큰 하나의 크기도 다릅니다. 사람 수나 문맥 길이를 두 배로 늘리면 KV 캐시도 정확히 두 배가 됩니다.
주의할 점
- KV 캐시는 동시 사용자 수와 문맥 길이에 비례합니다. RAG 는 문맥이 길어 KV 캐시가 빨리 늘어납니다(16장).
- 온프레미스는 GPU 값뿐 아니라 전력, 냉각, 운영 인력, 교체 주기가 듭니다. 데이터를 밖에 낼 수 없는지, 사용량이 꾸준한지를 함께 보고 클라우드와 견줍니다.