최신글

AI모델 로딩과 서빙에 필요한 VRAM은 다릅니다

반응형

vLLM에서 GPU를 사용할 때 GPU 계산하는 과정을 정리했습니다.

이전 글에 정리한 그래픽카드 하드웨어 글과 같이 보면 좋습니다.
- https://malwareanalysis.tistory.com/957

 

요약

서빙엔진에서는 GPU VRAM에 AI모델을 로드한 이후, 추가로 VRAM이 더 필요합니다.

 

AI 모델 로드에 필요한 GPU 메모리를 계산하고 실제로 로드하기

이론

Qwen/Qwen2.5-7B-Instruct AI 모델을 bfloat16으로 GPU에 올릴 수 있는지 계산해 보면, 약 14GB의 GPU 메모리가 필요합니다. 파라미터 수 7B에 bfloat16의 2byte를 곱하여 VRAM을 계산합니다.

  • 계산식: 70억 parameters x bytes -> 7GB x 2bytes = 14GB
7,000,000,000 parameters × 2 bytes = 14,000,000,000 bytes ≈ 14 GB

 

실험

실제로 GeForce RTX 5060 Ti 16GB GPU에서 Transformers로 Qwen/Qwen2.5-7B-Instruct AI 모델로드를 성공했습니다.
- 실습 코드: https://github.com/choisungwook/portfolio/blob/master/computer_science/ai/study-llmserving/ch5-6/model_loader/load_7b_expect_oom.py

from transformers import AutoModelForCausalLM

model_id = "Qwen/Qwen2.5-7B-Instruct"

model = AutoModelForCausalLM.from_pretrained(
  model_id,
  dtype=torch.bfloat16,
  low_cpu_mem_usage=True,
)
model.to("cuda")

 

OOM이 발생하지 않으면 오류 메시지를 표시하도록 했는데, AI 모델 로드에 성공해 OOM이 발생하지 않았다는 메시지가 출력되었습니다.

MODEL_ID = "Qwen/Qwen2.5-7B-Instruct"

result = load_model(MODEL_ID)
save_result(result, Path("results/ch5-7b-bf16-oom.json"))

if result.loaded:
    raise RuntimeError("7B BF16 unexpectedly loaded; the expected OOM was not")

 

 

서빙을 위해 AI모델이외에 GPU 메모리가 더 필요합니다.

이론

Qwen2.5-7B-Instruct BF16 모델은 16GB GPU에 로드하는 데 성공했지만, vLLM 같은 서빙 엔진에서는 초기화에 실패합니다. 모델 weight가 대부분의 VRAM을 사용했으므로, 요청 처리 준비에 필요한 임시 GPU 메모리가 부족했기 때문입니다.

 

vLLM은 초기화할 때 더미 forward 연산을 실행해 모델의 최대 메모리 사용량을 측정합니다. AI모델로드 후 남은 GPU가 측정한 GPU보다 작으면 초기화를 실패합니다.
- 모델 실행에 필요한 activation 메모리(모델이 입력을 계산하면서 만드는 중간 결과를 VRAM에 저장)
- 실행 가능한 연산과 kernel
- KV cache에 사용할 수 있는 남은 VRAM

 

실험

저는 AI모델이후 남은 GPU가 부족하면, vLLM초기화 실패하는지 테스트를 진행했습니다.

모델 weight 적재 완료: 14.29GiB
→ dummy request 실행
→ activation 생성 및 GPU 연산 컴파일
→ 임시 작업 공간 1.02GiB 추가 요청
→ VRAM 부족으로 OOM
→ KV cache 실제 할당 전에 서버 초기화 실패

 

GTX 5060 ti 16GB GPU 환경에서 docker compose로 실행하면 OOM 오류가 발생합니다.
- 예제 코드: https://github.com/choisungwook/portfolio/blob/master/computer_science/ai/study-llmserving/ch5-6/docker-compose.yml

$ docker compose --profile oom run --rm vllm-7b-bf16-expect-failure

command:
    - vllm
    - serve
    - Qwen/Qwen2.5-7B-Instruct
    - --served-model-name
    - qwen
    - --dtype
    - bfloat16
    - --max-model-len
    - "4096"
    - --max-num-seqs
    - "1"
    - --max-num-batched-tokens
    - "4096"
    - --gpu-memory-utilization
    - "0.85"

 

 

stack trace를 확인하면 determine_available_memory의 profile_run이 호출한 dummy_run 함수에서 OOM이 발생했습니다.

_initialize_kv_caches()
└─ determine_available_memory()
   └─ profile_run()
      └─ _dummy_run()
         └─ TorchInductor autotuning
            └─ CUDA out of memory

 

dummy_run 함수는 vLLM이 초기화 과정에서 실행하는 더미 workload입니다. vLLM은 파라미터를 바탕으로 더미 workload를 생성합니다. 현재 실습에 사용한 vLLM 파라미터는 다음과 같습니다.

max-num-batched-tokens = 4096
max-num-seqs = 1

 

max-num-seqs가 1개이므로 더미 workload는 요청이 1개입니다.

_dummy_req_0: 4096 tokens

 

vLLM은 더미 workload를 통해 GPU VRAM을 계산합니다.

  • activation 등 forward 실행 중 발생하는 임시 메모리
  • TorchInductor 컴파일·autotuning에 필요한 임시 메모리
  • sampler와 출력 계산에 필요한 메모리
  • 향후 CUDA graph 실행에 필요한 메모리

 

이 예제의 vLLM은 GPU VRAM을 다음과 같이 계산했습니다. 추가 할당량이 남은 VRAM보다 커서 OOM이 발생했습니다.

1. 모델로드를 위해 GPU VRAM 사용: 14.29 GiB
2. 더미 Reqeuset 실행
→ 더미 forward 연산 실행
→ 모델 forward 및 TorchInductor autotuning
→ PyTorch가 1.02 GiB 추가 할당 시도
→ 남은 공간 730.56 MiB, CUDA OOM
→ profile_run() 중단
→ KV cache 계산과 할당에는 도달하지 못함
반응형