[vLLM] Multimodal: Vision, Audio, Video 처리 파이프라인
들어가며
최근 LLM은 텍스트뿐만 아니라 이미지, 오디오, 비디오를 함께 처리하는 멀티모달 모델로 진화하고 있다. vLLM은 vllm/multimodal/ 모듈에서 이러한 다양한 모달리티를 통합적으로 처리하는 프레임워크를 제공한다.
공식 문서
vLLM 공식 문서: Multimodal Inputs
핵심 구조/코드 분석
MultiModalRegistry
class MultiModalRegistry:
def supports_multimodal_inputs(self, model_config: "ModelConfig") -> bool:
if not model_config.is_multimodal_model:
return False
mm_config = model_config.get_multimodal_config()
info = self._create_processing_info(model_config, tokenizer=None)
if all(mm_config.get_limit_per_prompt(modality) == 0
for modality in info.supported_mm_limits):
if mm_config.enable_mm_embeds:
return True # 사전 계산된 임베딩은 여전히 처리 필요
return False
return True
레지스트리는 모델이 멀티모달을 지원하는지 판단한다. 모든 모달리티의 제한이 0이면 텍스트 전용 모드로 실행하되, enable_mm_embeds가 켜져 있으면 사전 계산된 임베딩 처리를 위해 멀티모달 인프라를 유지한다.
프로세서 팩토리 패턴
@dataclass(frozen=True)
class _ProcessorFactories(Generic[_I]):
info: ProcessingInfoFactory[_I]
processor: MultiModalProcessorFactory[_I]
dummy_inputs: DummyInputsBuilderFactory[_I]
def build_processor(self, ctx, *, cache=None):
info = self.info(ctx)
dummy_inputs_builder = self.dummy_inputs(info)
return self.processor(info, dummy_inputs_builder, cache=cache)
세 가지 팩토리(정보, 프로세서, 더미 입력)를 조합하여 프로세서를 구성한다. 모델 클래스에 _processor_factory로 등록된다:
def register_processor(self, processor, *, info, dummy_inputs):
def wrapper(model_cls):
model_cls._processor_factory = _ProcessorFactories(
info=info, dummy_inputs=dummy_inputs, processor=processor,
)
return model_cls
return wrapper
캐싱 시스템
def _get_cache_type(self, vllm_config) -> Literal[None, "processor_only", "lru", "shm"]:
mm_config = model_config.get_multimodal_config()
if mm_config.mm_processor_cache_gb <= 0:
return None
is_ipc_supported = parallel_config._api_process_count == 1 and (
parallel_config.data_parallel_size == 1
or parallel_config.data_parallel_external_lb
)
if not is_ipc_supported:
return "processor_only"
return mm_config.mm_processor_cache_type
멀티모달 캐시는 네 가지 모드를 지원한다:
None: 캐시 비활성화processor_only: 프로세서 결과만 캐시 (IPC 불가 환경)lru: LRU 기반 프로세서+수신자 캐시shm: 공유 메모리 기반 캐시 (ShmObjectStore)
모달리티별 미디어 처리
vllm/multimodal/media/
├── base.py # 기본 미디어 인터페이스
├── image.py # 이미지 처리
├── audio.py # 오디오 처리
├── video.py # 비디오 처리
└── connector.py # 미디어 커넥터
각 모달리티의 원시 데이터를 모델이 이해하는 형식으로 변환한다. 이미지의 경우 리사이징, 정규화, 패치 분할 등을 수행한다.
더미 입력과 메모리 프로파일링
def get_dummy_mm_inputs(self, model_config, mm_counts, *, cache=None, processor=None):
seq_len = model_config.max_model_len
processor_inputs = processor.dummy_inputs.get_dummy_processor_inputs(
seq_len=seq_len, mm_counts=mm_counts, mm_options=mm_config.limit_per_prompt,
)
mm_inputs = processor.apply(processor_inputs, timing_ctx=TimingContext(enabled=False))
prompt_token_ids = mm_inputs["prompt_token_ids"]
if len(prompt_token_ids) < seq_len:
prompt_token_ids.extend([0] * (seq_len - len(prompt_token_ids)))
return mm_inputs
메모리 프로파일링을 위해 최대 크기의 더미 멀티모달 입력을 생성한다. 이를 통해 GPU 메모리 예산을 정확하게 계산할 수 있다.
왜 이 설계인가
-
데코레이터 기반 모델 등록:
@register_processor데코레이터로 모델 클래스에 직접 프로세서를 바인딩한다. 이렇게 하면 모델 정의와 멀티모달 처리 로직이 함께 관리되어, 새 모델 추가 시 한 곳만 수정하면 된다. -
IPC 기반 캐시 분기: 데이터 병렬 환경에서는 여러 프로세스가 같은 이미지를 처리할 수 있다. SHM 캐시를 사용하면 한 번 처리한 결과를 공유 메모리로 다른 프로세스에 전달하여 중복 연산을 피한다. IPC가 불가능한 환경에서는 프로세서 전용 캐시로 폴백한다.
-
타이밍 컨텍스트:
TimingContext로 멀티모달 처리 각 단계의 소요 시간을 측정할 수 있다. 이미지 전처리, 토큰화, 인코더 실행 등 어디서 병목이 발생하는지 관측 가능하다.
참고 자료
관련 포스트
vLLM 의 다른글
- 이전글 [vLLM] Reasoning & Tool Calling: 추론 파서와 도구 호출 파서
- 현재글 : [vLLM] Multimodal: Vision, Audio, Video 처리 파이프라인
- 다음글 [vLLM] Sleep Mode: GPU 메모리 동적 관리
댓글