[vLLM] InputProcessor: 입력 전처리 파이프라인
들어가며
LLM 서빙에서 입력 전처리는 단순한 토크나이징 이상의 작업이다. 파라미터 검증, 멀티모달 데이터 처리, LoRA 검증, 시퀀스 길이 제한 등을 모두 수행해야 한다. vLLM v1 엔진의 InputProcessor(vllm/v1/engine/input_processor.py)가 이 모든 과정을 담당한다.
핵심 구조/코드 분석
InputProcessor 초기화
class InputProcessor:
def __init__(
self,
vllm_config: VllmConfig,
renderer: BaseRenderer | None = None,
*,
mm_registry: MultiModalRegistry = MULTIMODAL_REGISTRY,
) -> None:
self.vllm_config = vllm_config
self.generation_config_fields = model_config.try_get_generation_config()
self.renderer = renderer or renderer_from_config(vllm_config)
self.supports_mm_inputs = mm_registry.supports_multimodal_inputs(model_config)
if self.supports_mm_inputs:
mm_budget = MultiModalBudget(vllm_config, mm_registry)
self.mm_encoder_cache_size = mm_budget.encoder_cache_size
self.input_preprocessor = InputPreprocessor(
vllm_config, renderer=renderer, mm_registry=mm_registry,
)
멀티모달 지원 여부를 레지스트리에서 확인하고, 지원하는 경우 멀티모달 인코더 캐시 크기를 사전 계산한다. InputPreprocessor는 레거시 프롬프트 형식을 처리하기 위한 하위 프로세서이다.
process_inputs: 핵심 메서드
process_inputs는 사용자 프롬프트를 EngineCoreRequest로 변환하는 핵심 파이프라인이다.
def process_inputs(
self,
request_id: str,
prompt: PromptType | EngineInput,
params: SamplingParams | PoolingParams,
supported_tasks: tuple[SupportedTask, ...],
arrival_time: float | None = None,
lora_request: LoRARequest | None = None,
...
) -> EngineCoreRequest:
self._validate_params(params, supported_tasks)
self._validate_lora(lora_request)
encoder_inputs, decoder_inputs = split_enc_dec_input(processed_inputs)
self._validate_model_inputs(encoder_inputs, decoder_inputs)
if isinstance(params, SamplingParams):
sampling_params = params.clone()
if sampling_params.max_tokens is None:
seq_len = length_from_prompt_token_ids_or_embeds(...)
sampling_params.max_tokens = self.model_config.max_model_len - seq_len
sampling_params.update_from_generation_config(
self.generation_config_fields,
self.renderer.get_eos_token_id(),
)
처리 순서는 다음과 같다:
- 파라미터 검증: SamplingParams 또는 PoolingParams의 유효성 확인
- LoRA 검증: LoRA 요청이 있으면 LoRA 설정 활성화 여부 확인
- 입력 분리: encoder-decoder 모델을 위한 입력 분리
- max_tokens 자동 설정: 미지정 시
max_model_len - prompt_len으로 설정 - generation_config 반영: HuggingFace generation_config의 값 적용
요청 ID 유니크성 보장
@staticmethod
def assign_request_id(request: EngineCoreRequest):
request.external_req_id = request.request_id
if envs.VLLM_DISABLE_REQUEST_ID_RANDOMIZATION:
logger.warning_once(
"VLLM_DISABLE_REQUEST_ID_RANDOMIZATION is set..."
)
else:
request.request_id = f"{request.external_req_id}-{random_uuid():.8}"
외부 요청 ID에 8자리 랜덤 UUID를 추가하여 내부 요청 ID를 생성한다. 동일한 외부 ID로 재시도가 올 때 이전 요청과 충돌하지 않도록 보장한다.
멀티모달 입력 처리
멀티모달 데이터는 별도의 파이프라인을 거친다.
if decoder_inputs["type"] == "multimodal":
decoder_mm_inputs = decoder_inputs["mm_kwargs"]
decoder_mm_positions = decoder_inputs["mm_placeholders"]
decoder_mm_hashes = decoder_inputs["mm_hashes"]
sorted_mm_idxs = argsort_mm_positions(decoder_mm_positions)
mm_features = []
for modality, idx in sorted_mm_idxs:
base_mm_hash = decoder_mm_hashes[modality][idx]
mm_features.append(
MultiModalFeatureSpec(
data=decoder_mm_inputs[modality][idx],
modality=modality,
identifier=self._get_mm_identifier(base_mm_hash, lora_request),
mm_position=decoder_mm_positions[modality][idx],
mm_hash=base_mm_hash,
)
)
멀티모달 데이터는 시퀀스 내 위치순으로 정렬되고, 해시 기반 식별자를 부여받는다. LoRA가 활성화된 경우, 동일 이미지라도 LoRA별로 다른 임베딩이 생성될 수 있으므로 LoRA 이름을 식별자에 포함시킨다.
파라미터 검증 로직
def _validate_params(self, params, supported_tasks):
if isinstance(params, SamplingParams):
supported_generation_tasks = [
task for task in supported_tasks if task in GENERATION_TASKS
]
if not supported_generation_tasks:
raise ValueError("This model does not support generation")
params.verify(self.model_config, self.speculative_config, ...)
elif isinstance(params, PoolingParams):
if params.task is None:
if "token_embed" in supported_pooling_tasks:
params.task = "token_embed"
모델이 지원하지 않는 태스크로 요청이 오면 즉시 에러를 발생시킨다. PoolingParams의 태스크가 미지정이면 모델이 지원하는 태스크 중 우선순위에 따라 자동 할당한다.
왜 이 설계인가
-
Fail-fast 검증: 실제 GPU 연산 전에 모든 입력 유효성을 검사한다. GPU 리소스 낭비를 방지하고, 사용자에게 즉각적인 피드백을 제공한다.
-
Renderer와의 분리: 토크나이징은 Renderer가, 전처리 검증과 요청 구성은 InputProcessor가 담당한다. 관심사 분리를 통해 각 컴포넌트를 독립적으로 테스트하고 교체할 수 있다.
-
멀티모달 해시 캐싱: 동일 이미지가 반복 요청되면 해시 기반으로 인코더 캐시를 재사용한다. 이미지 인코딩이 비용이 높으므로 이 최적화의 효과가 크다.
-
generation_config 자동 반영: 모델 제작자가 설정한 기본 생성 파라미터를 자동으로 적용한다. 사용자가 명시적으로 오버라이드하지 않으면 모델의 권장 설정을 따른다.
정리
InputProcessor는 vLLM 엔진의 관문이다. 사용자의 다양한 입력 형식(텍스트, 토큰, 임베딩, 멀티모달)을 통일된 EngineCoreRequest로 정규화하고, 엔진이 안전하게 처리할 수 있도록 보장한다. 프레임워크의 안정성과 사용자 경험을 좌우하는 핵심 컴포넌트이다.
관련 포스트
vLLM 의 다른글
- 이전글 [vLLM] Pooling Tasks: 임베딩, 분류, 스코어링
- 현재글 : [vLLM] InputProcessor: 입력 전처리 파이프라인
- 다음글 [vLLM] OutputProcessor: 출력 후처리 및 디토크나이징
댓글