메모리 절약하기
메모리 절약하기 (Conserving Memory)
큰 모델을 실행하면 머신의 메모리가 부족해져 OOM(Out Of Memory)이 발생할 수 있습니다. 이 글에서는 그런 문제를 완화하는 데 도움이 되는 몇 가지 옵션을 소개합니다.
출처: 문서
본문
텐서 병렬화 (Tensor Parallelism, TP)
tensor_parallel_size 옵션으로 모델을 여러 GPU에 나눠 담을 수 있습니다. 아래 코드는 모델을 2개 GPU에 분할합니다.
from vllm import LLM
llm = LLM(model="ibm-granite/granite-3.1-8b-instruct", tensor_parallel_size=2)
경고: vLLM이 CUDA를 올바르게 초기화하도록, vLLM 초기화 전에
torch.cuda.set_device같은 관련 함수를 호출하지 마세요. 그렇지 않으면RuntimeError: Cannot re-initialize CUDA in forked subprocess오류가 날 수 있습니다. 사용할 디바이스는CUDA_VISIBLE_DEVICES환경 변수로 제어하세요.참고: 텐서 병렬화를 켜면 각 프로세스가 전체 모델을 읽고 조각으로 나누므로 디스크 읽기 시간이 더 길어집니다(TP 크기에 비례).
examples/offline_inference/save_sharded_state.py로 체크포인트를 샤딩된 형태로 변환하면 이후 로드를 훨씬 빠르게 할 수 있습니다. 변환은 시간이 걸리지만, 텐서 병렬 크기와 무관하게 모델 로딩 시간이 일정해집니다.
양자화 (Quantization)
양자화된 모델은 정밀도가 낮아지는 대신 메모리를 덜 차지합니다. 정적 양자화 모델은 HF Hub에서 내려받아 별도 설정 없이 바로 쓸 수 있고(Red Hat AI에 유명한 몇 가지가 있음), 동적 양자화도 quantization 옵션으로 지원됩니다.
컨텍스트 길이와 배치 크기
모델의 컨텍스트 길이(max_model_len)와 최대 배치 크기(max_num_seqs)를 제한하면 메모리 사용을 더 줄일 수 있습니다.
from vllm import LLM
llm = LLM(model="adept/fuyu-8b", max_model_len=2048, max_num_seqs=2)
CUDA 그래프 줄이기
기본적으로 vLLM은 CUDA 그래프로 추론을 최적화하며, 이는 GPU에 추가 메모리를 차지합니다. compilation_config를 조절해 추론 속도와 메모리 사이의 균형을 맞출 수 있습니다.
from vllm import LLM
from vllm.config import CompilationConfig, CompilationMode
llm = LLM(
model="meta-llama/Llama-3.1-8B-Instruct",
compilation_config=CompilationConfig(
mode=CompilationMode.VLLM_COMPILE,
# 기본적으로 max_num_seqs 까지 올라감
cudagraph_capture_sizes=[1, 2, 4, 8, 16],
),
)
그래프 캡처를 완전히 끄려면 enforce_eager 플래그를 사용합니다.
from vllm import LLM
llm = LLM(model="meta-llama/Llama-3.1-8B-Instruct", enforce_eager=True)
캐시 크기 조절
CPU RAM이 부족할 때는 다음 옵션을 시도해 보세요.
- 멀티모달 모델 전용:
mm_processor_cache_gb엔진 인자로 멀티모달 캐시 크기를 지정(기본 4 GiB). - CPU 백엔드 전용:
VLLM_CPU_KVCACHE_SPACE환경 변수로 KV 캐시 크기 지정(기본 4 GiB).
멀티모달 입력 제한
프롬프트당 멀티모달 아이템 수를 줄여 모델의 메모리 사용량을 낮출 수 있습니다.
from vllm import LLM
# 프롬프트당 이미지 최대 3장, 비디오 최대 1개 허용
llm = LLM(
model="Qwen/Qwen2.5-VL-3B-Instruct",
limit_mm_per_prompt={"image": 3, "video": 1},
)
사용하지 않는 모달리티는 그 값의 제한을 0으로 두어 할당 자체를 끌 수도 있습니다. 예를 들어 이미지만 받는 앱이라면 비디오에 메모리를 할당할 필요가 없습니다.
from vllm import LLM
# 이미지는 몇 장이든 받지만 비디오는 받지 않음
llm = LLM(
model="Qwen/Qwen2.5-VL-3B-Instruct",
limit_mm_per_prompt={"video": 0},
)
심지어 멀티모달 모델을 텍스트 전용 추론으로도 실행할 수 있습니다.
from vllm import LLM
# 이미지를 받지 않고 텍스트만
llm = LLM(
model="google/gemma-3-27b-it",
limit_mm_per_prompt={"image": 0},
)
구성 가능한 옵션
limit_mm_per_prompt는 모달리티별 구성 옵션도 받습니다. count를 지정하면서 크기 힌트(size hints)를 추가로 주면, 모델이 절대 최대치가 아니라 실제로 기대하는 미디어 크기에 맞춰 메모리를 프로파일링·예약할 수 있습니다.
image:{"count": int, "width": int, "height": int}video:{"count": int, "num_frames": int, "width": int, "height": int}audio:{"count": int, "length": int}
from vllm import LLM
# 프롬프트당 이미지 최대 5장, 512x512 크기로 프로파일링.
# 프롬프트당 비디오 최대 1개, 32프레임 640x640 크기로 프로파일링.
llm = LLM(
model="Qwen/Qwen2.5-VL-3B-Instruct",
limit_mm_per_prompt={
"image": {"count": 5, "width": 512, "height": 512},
"video": {"count": 1, "num_frames": 32, "width": 640, "height": 640},
},
)
정수값을 넘기면 기존처럼 동작하며 {"count": <int>}로 해석됩니다. 예: limit_mm_per_prompt={"image": 5}는 {"image": {"count": 5}}와 동등하고, 형식 혼합도 가능합니다.
멀티모달 프로세서 인자
일부 모델은 멀티모달 프로세서 인자로 처리되는 입력 크기를 줄여 메모리를 절약할 수 있습니다.
from vllm import LLM
# Qwen2-VL 계열 모델에서 사용 가능
llm = LLM(
model="Qwen/Qwen2.5-VL-3B-Instruct",
mm_processor_kwargs={"max_pixels": 768 * 768}, # 기본은 1280 * 28 * 28
)
# InternVL 계열 모델에서 사용 가능
llm = LLM(
model="OpenGVLab/InternVL2-2B",
mm_processor_kwargs={"max_dynamic_patch": 4}, # 기본은 12
)
더 알아보기 (Learn more)
- Optimization and Tuning — vLLM V1 성능 최적화와 튜닝
- Engine Arguments — 위 옵션들이 속한 엔진 인자 전체 목록
- Environment Variables —
VLLM_CPU_KVCACHE_SPACE등 환경 변수