
GPU VRAM: 그래픽 카드의 전용 메모리
딥러닝 모델 학습시키다가 'CUDA Out of Memory' 에러를 보고 좌절한 적 있나요? VRAM과 일반 RAM의 차이를 '요리 재료'에 비유합니다.

딥러닝 모델 학습시키다가 'CUDA Out of Memory' 에러를 보고 좌절한 적 있나요? VRAM과 일반 RAM의 차이를 '요리 재료'에 비유합니다.
맥북 배터리는 왜 오래 갈까? 서버 비용을 줄이려면 AWS Graviton을 써야 할까? 복잡함(CISC)과 단순함(RISC)의 철학적 차이를 정리해봤습니다.

AI 시대의 금광, 엔비디아 GPU. 도대체 게임용 그래픽카드로 왜 AI를 돌리는 걸까? 단순 노동자(CUDA)와 행렬 계산 천재(Tensor)의 차이로 파헤쳐봤습니다.

빠른 SSD를 샀는데 왜 느릴까요? 1차선 시골길(SATA)과 16차선 고속도로(NVMe). 인터페이스가 성능의 병목이 되는 이유.

LP판과 USB. 물리적으로 회전하는 판(Disc)이 왜 느릴 수밖에 없는지, 그리고 SSD가 어떻게 서버의 처리량을 100배로 만들었는지 파헤쳐봤습니다.

혼자서 AI 모델(Stable Diffusion)을 돌려보려고 신나게 코드를 짰습니다.
실행 버튼을 누르자마자 에러 메시지가 떴습니다.
RuntimeError: CUDA out of memory.
제 컴퓨터 램(RAM)은 32GB나 되는데, 왜 메모리가 부족하다는 걸까요? 알고 보니 GPU는 지 밥그릇(VRAM)만 쓴다는 걸 그때 처음 알았습니다.
처음엔 당황했습니다. "GPU가 뭐가 특별하다고 메모리를 따로 쓰는 거야?" 하지만 차근차근 파고들다 보니, 이게 단순히 GPU의 고집이 아니라 물리적으로 어쩔 수 없는 선택이었다는 걸 받아들였습니다.
이 상황을 이해하는 데는 '주방 비유'가 또 등장합니다.
RAM이 아무리 32GB, 64GB로 넓어도 소용없었습니다. GPU라는 셰프는 고집이 세서, "내 도마(VRAM) 위에 올라온 재료만 요리하겠다"고 버티는 겁니다. 제 그래픽 카드는 RTX 3060이었고, VRAM은 12GB였습니다. RAM에 아무리 재료가 많아도, 12GB짜리 좁은 도마에 다 못 올리면 요리를 거부하는 것이죠.
처음엔 "융통성 없는 설계"라고 생각했습니다. 하지만 왜 이렇게 만들었는지 알고 나서, 오히려 "이렇게 안 만들면 GPU가 작동 자체를 못 하겠구나"라는 생각이 들었습니다.
"아니 좀 같이 쓰면 안 되나? 융통성 없게?" 라고 불평했습니다. 하지만 '속도(Bandwidth)' 차이를 보고 납득했습니다.
RAM에서 데이터를 가져오는 속도는 수도꼭지에서 물 나오는 수준이라면, VRAM에서 GPU로 데이터를 퍼 나르는 속도는 소방차 호스에서 물이 뿜어져 나오는 수준입니다.
GPU는 초당 수천억 번 계산을 때려야 하는데, 느려 터진 RAM에서 데이터를 가져오느라 기다릴 시간이 없습니다. 그래서 "엄청나게 빠르고 비싼 전용 메모리(GDDR)"를 칩 바로 옆에 딱 붙여놓은 것입니다.
대역폭(Bandwidth)을 이해하는 데는 고속도로 비유가 확 와닿았습니다.
GPU는 "동시에 처리할 수 있는 데이터 양"으로 승부를 보는 칩입니다. 좁은 도로로는 애초에 경쟁이 안 되니까, "넓은 도로를 내 바로 옆에 깔아놓은 것"이 VRAM의 정체였던 거죠.
VRAM이라고 다 똑같은 줄 알았습니다. 그런데 그래픽 카드를 비교하다 보니 "GDDR6", "HBM2" 같은 용어가 자꾸 나오더군요. 이게 뭐가 다를까요?
대부분의 게이밍 그래픽 카드(RTX 3060, 4090 등)에 들어가는 메모리입니다.
RTX 3060의 VRAM이 "12GB GDDR6"라는 건, "GDDR6라는 메모리를 12GB 용량으로 달았다"는 뜻입니다. 처음엔 숫자만 봤는데, 이제는 "어떤 종류의 메모리인지"도 같이 봐야 한다는 걸 이해했습니다.
데이터센터용 GPU(A100, H100)나 AMD의 일부 그래픽 카드에 쓰입니다.
HBM은 게임용으로는 과한 스펙이라 잘 안 쓰이는데, AI 학습처럼 "데이터를 대량으로 퍼 나르는 작업"에서는 필수라고 합니다. 엔비디아 A100 같은 카드가 몇천만 원 하는 이유도 바로 이 HBM 때문이었습니다.
이걸 알고 나니, "왜 서버용 GPU는 게임용 GPU보다 훨씬 비싼지" 납득이 갔습니다. 단순히 코어 개수 문제가 아니라, 메모리 자체가 다른 급이었던 거죠.
게임할 때 "옵션 타협"을 하라는 말이 결국 VRAM 때문이었습니다. 4K 해상도의 고화질 텍스처(Texture)는 덩치가 엄청 큽니다. 이걸 VRAM 도마 위에 다 못 올리면, GPU는 요리를 멈추거나 퀄리티를 강제로 낮춰야 합니다.
AI도 마찬가지였습니다. 거대 언어 모델(LLM)이나 이미지 생성 모델은 그 자체로 몇 기가바이트입니다. 이걸 VRAM에 로딩(Loading)해야 추론(Inference)을 할 수 있습니다.
처음 Stable Diffusion을 돌려봤을 때, 모델 파일 자체는 4GB 정도였습니다. 그런데 실행하니까 VRAM을 8GB 넘게 잡아먹더군요. "뭐야, 파일은 4GB인데 왜 8GB를 쓰는 거야?"
알고 보니 모델을 VRAM에 올릴 때, 추가로 중간 계산 결과(Activation)들도 같이 올라가기 때문이었습니다. 요리 비유로 치면, 재료(모델 파일)만 올리는 게 아니라 도마 위에서 썰린 재료들(중간 결과)까지 차지하는 공간이 있는 거죠.
그래서 "모델 파일이 4GB면 VRAM 4GB면 되겠지?"라고 생각하면 큰 코 다칩니다. 실제로는 모델 크기의 2~3배 정도 VRAM이 필요하다는 걸 받아들였습니다.
"모델 다이어트(Quantization)"라는 기술이 왜 유행하는지도 알게 되었습니다. 어떻게든 덩치를 줄여서 VRAM이라는 비싼 도마 위에 올리려는 눈물나는 노력이었던 겁니다.
딥러닝 모델의 숫자(가중치, Weight)는 기본적으로 FP32 (32비트 부동소수점)로 저장됩니다. 하나의 숫자를 표현하는 데 32비트(4바이트)를 씁니다.
예를 들어 10억 개의 파라미터를 가진 모델이 있다면:
이 차이가 "내 GPU에서 돌릴 수 있느냐 없느냐"를 결정합니다. RTX 3060(12GB VRAM)으로는 FP32 모델은 못 돌리지만, INT8로 압축하면 돌릴 수 있는 거죠.
이걸 이해하는 데는 "사진 해상도 낮추기" 비유가 확 와닿았습니다.
AI 모델도 마찬가지입니다. FP16이나 INT8로 줄여도 실제 성능(Accuracy)은 거의 차이가 없는 경우가 많습니다. 그래서 요즘 배포되는 모델들은 대부분 FP16이나 INT8 버전을 같이 제공합니다.
이걸 알고 나서, "VRAM이 부족하면 무조건 비싼 GPU를 사야 하나?"라는 생각에서 벗어났습니다. "모델을 압축해서 쓰면 되는구나"라는 선택지가 생긴 거죠.
CUDA Out of Memory 에러를 몇 번 겪고 나니, "내가 지금 VRAM을 얼마나 쓰고 있는지" 확인하는 게 중요하다는 걸 깨달았습니다.
리눅스나 윈도우에서 터미널을 열고 nvidia-smi를 치면, 현재 GPU 상태를 볼 수 있습니다.
nvidia-smi
출력 예시:
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 525.105.17 Driver Version: 525.105.17 CUDA Version: 12.0 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 NVIDIA GeForce ... Off | 00000000:01:00.0 On | N/A |
| 30% 45C P8 15W / 170W | 8234MiB / 12288MiB | 2% Default |
+-------------------------------+----------------------+----------------------+
여기서 중요한 건 Memory-Usage 부분입니다.
8234MiB / 12288MiB는 "12GB 중에 8GB를 쓰고 있다"는 뜻입니다.
이걸 보고 나서, "아, 내가 4GB 여유가 있구나. 배치 크기(Batch Size)를 조금 더 늘릴 수 있겠네"라는 판단을 할 수 있게 되었습니다.
코드 안에서도 VRAM 사용량을 확인할 수 있습니다.
import torch
# 현재 할당된 VRAM 확인 (바이트 단위)
allocated = torch.cuda.memory_allocated()
print(f"할당된 메모리: {allocated / 1024**3:.2f} GB")
# CUDA에서 예약한 총 VRAM
reserved = torch.cuda.memory_reserved()
print(f"예약된 메모리: {reserved / 1024**3:.2f} GB")
# VRAM 캐시 정리
torch.cuda.empty_cache()
처음엔 "그냥 에러 나면 배치 크기 줄이면 되지"라고 생각했는데, 실시간으로 메모리 사용량을 보면서 조절하니까 훨씬 효율적으로 학습할 수 있었습니다.
특히 torch.cuda.empty_cache()는 "쓰지 않는 메모리를 정리"해주는 함수인데, 이걸 중간중간 호출해주니까 Out of Memory 에러가 확 줄었습니다.
GPU VRAM을 공부하다 보니, 완전히 다른 접근을 한 제품도 있더군요. 바로 Apple M 시리즈와 AMD APU입니다.
일반 PC는 CPU용 RAM과 GPU용 VRAM이 완전히 분리되어 있습니다. CPU에서 GPU로 데이터를 보낼 때마다 "복사(Copy)"를 해야 합니다.
그런데 Apple M1/M2는 CPU와 GPU가 하나의 메모리를 공유합니다.
처음엔 "이게 왜 좋은 거야? 어차피 느린 거 아닌가?"라고 생각했습니다. 하지만 "복사 시간이 사라진다"는 게 생각보다 큰 이득이었습니다.
특히 영상 편집이나 3D 렌더링 같은 작업에서는 CPU와 GPU가 번갈아가며 데이터를 주고받는 경우가 많은데, 이때 통합 메모리가 빛을 발합니다.
기존 아키텍처는 "양동이 릴레이"입니다.
통합 메모리는 "하나의 큰 통"입니다.
이 비유를 듣고 나서, "Apple M 시리즈가 왜 메모리 용량을 강조하는지" 이해했습니다. 통합 메모리니까, 16GB를 선택하면 CPU와 GPU가 나눠 쓰는 거거든요. GPU만 12GB를 쓰면 CPU는 4GB밖에 못 쓰는 겁니다.
그래서 M 시리즈 맥을 살 때는 "VRAM만 생각하면 안 되고, 총 메모리를 넉넉하게 사야 한다"는 교훈을 얻었습니다.
CUDA Out of Memory 에러를 수도 없이 보면서, 몇 가지 대처법을 정리해봤습니다.
가장 즉각적인 효과가 있는 방법입니다.
# 원래
train_loader = DataLoader(dataset, batch_size=32)
# VRAM 부족하면
train_loader = DataLoader(dataset, batch_size=16) # 절반으로
배치 크기를 줄이면 한 번에 처리하는 데이터 양이 줄어들어 VRAM 사용량이 확 줄어듭니다. 대신 학습 속도는 조금 느려집니다.
배치 크기를 줄이면 학습이 불안정해질 수 있습니다. 이때는 "그레디언트를 여러 번 누적해서 업데이트"하는 기법을 씁니다.
accumulation_steps = 4
for i, (images, labels) in enumerate(train_loader):
loss = model(images, labels)
loss = loss / accumulation_steps
loss.backward()
if (i + 1) % accumulation_steps == 0:
optimizer.step()
optimizer.zero_grad()
배치 크기는 8인데, 4번 누적하면 "실질적으로는 배치 크기 32처럼" 작동합니다. VRAM은 아끼면서 학습 안정성은 유지하는 꼼수입니다.
FP32 대신 FP16을 쓰면 VRAM을 절반으로 줄일 수 있습니다.
from torch.cuda.amp import autocast, GradScaler
scaler = GradScaler()
for images, labels in train_loader:
with autocast(): # FP16으로 자동 변환
loss = model(images, labels)
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
PyTorch의 autocast를 쓰면 알아서 FP16으로 변환해줍니다.
정확도는 거의 그대로면서 VRAM은 확 줄어드는 마법입니다.
어쩔 수 없이 모델 자체를 줄여야 할 때도 있습니다.
이건 "마지막 수단"이긴 한데, 배포(Deployment) 단계에서는 거의 필수입니다.
| 구분 | System RAM | GPU VRAM |
|---|---|---|
| 위치 | 마더보드 슬롯 | 그래픽 카드 기판 위 (교체 불가) |
| 속도 (대역폭) | 빠름 (수십 GB/s) | 압도적으로 빠름 (수백 GB/s ~ 1TB/s) |
| 종류 | DDR4/DDR5 | GDDR6 (게임용) / HBM3 (서버용) |
| 비유 | 공용 테이블 | 셰프 전용 도마 |
VRAM 용량은 "한 번에 처리할 수 있는 작업의 크기"를 결정합니다. 그래서 딥러닝 하는 사람들이 왜 비싼 엔비디아 GPU, 그것도 VRAM 깡패인 3090, 4090을 찾는지 이제야 완벽하게 이해했습니다.
결국 이것도 "도마가 커야 큰 생선을 올린다"는 단순한 진리였습니다.
그리고 "무조건 비싼 GPU를 사야 한다"는 생각에서 벗어났습니다. Quantization으로 모델을 압축하거나, Mixed Precision으로 학습하거나, 통합 메모리 아키텍처를 활용하면 "한정된 VRAM으로도 충분히 할 수 있는 게 많다"는 걸 받아들였습니다.
VRAM은 단순한 숫자가 아니라, "내가 어떤 작업을 할 수 있는지"를 결정하는 핵심 스펙이었습니다. 이제는 GPU를 고를 때 코어 개수만 보는 게 아니라, VRAM 용량과 종류(GDDR vs HBM)도 같이 본다는 걸 정리해봅니다.