Disaggregated Encoder 예제
Disaggregated Encoder 예제
인코더-디코더(멀티모달) 요청을 처리할 때, 인코더를 별도의 인스턴스로 떼어 내면 프리필·디코드 부담을 줄이고 리소스를 더 유연하게 쓸 수 있어요. 이 예제 스크립트들은 vLLM의 disaggregated encoder(EPD) 기능을 시연해요.
출처: 공식문서
EPD 기능에 대한 자세한 설명은 Disaggregated Encoder Feature Documentation을 참고하세요.
파일
-
disagg_epd_proxy.py- XeYpZd 구성(X 인코더 인스턴스, Y 프리필 인스턴스, Z 디코드 인스턴스)을 시연하는 프록시 스크립트. 현재 1e1p1d 구성에서 안정적으로 동작해요. -
disagg_1e1p1d_example.sh- 1e1p1d 구성을 세팅하고, VisionArena 벤치마크를 실행한 뒤, 로컬 이미지로 단일 요청을 처리해요. -
disagg_1e1pd_example.sh- 1e1pd 구성을 세팅하고, VisionArena 벤치마크를 실행한 뒤, 로컬 이미지로 단일 요청을 처리해요.
커스텀 구성 (Custom Configuration)
# Use specific GPUs
GPU_E=0 GPU_PD=1 GPU_P=1 GPU_D=2 bash disagg_1e1p1d_example.sh
# Use specific ports
ENDPOINT_PORT=10001 bash disagg_1e1p1d_example.sh
# Use specific model
MODEL="Qwen/Qwen2.5-VL-3B-Instruct" bash disagg_1e1p1d_example.sh
# Use specific storage path
EC_SHARED_STORAGE_PATH="/tmp/my_ec_cache" bash disagg_1e1p1d_example.sh
# Run on XPU; scripts switch from CUDA_VISIBLE_DEVICES to ZE_AFFINITY_MASK
DEVICE_PLATFORM=xpu GPU_E=0 GPU_PD=1 bash disagg_1e1pd_example.sh
DEVICE_PLATFORM의 기본값은 cuda예요. 인텔 GPU에서 이 예제를 실행할 때는 DEVICE_PLATFORM=xpu로 설정해서, 스크립트가 장치 선택에 CUDA_VISIBLE_DEVICES 대신 ZE_AFFINITY_MASK를 쓰게 하세요.
인코더 인스턴스 (Encoder Instances)
인코더 엔진은 다음 플래그로 실행해야 해요.
-
--enforce-eager(필수) – 현재 EPD 구현은 이 모드로 실행되는 인코더 인스턴스에서만 호환돼요. -
--no-enable-prefix-caching(필수) – 인코더 인스턴스는 KV 캐시를 소비하지 않아요. 다른 기능과의 충돌을 피하기 위해 프리픽스 캐싱을 끕니다. -
--max-num-batched-tokens=<큰 값>(기본값: 2048) – 이 플래그는 디코딩 스텝당 토큰 스케줄링 예산을 제어하는데, 인코더 전용 인스턴스와는 무관해요. 스케줄러 제한을 우회하려면 아주 큰 값(사실상 무제한)으로 설정하세요. 실제 토큰 예산은 인코더 캐시 매니저가 관리해요. -
--mm-encoder-only(선택) – 가능하면 초기화 중 언어 모델을 건너뛰어 장치 메모리 사용량을 줄여요.
로컬 미디어 입력
로컬 이미지 입력(MEDIA_PATH 디렉토리에서)을 지원하려면 인코더 인스턴스에 다음 플래그를 추가하세요.
--allowed-local-media-path $MEDIA_PATH
vllm 인스턴스와 disagg_encoder_proxy는 {"url": "file://'"$MEDIA_PATH_FILENAME"'"} 형태의 로컬 URI를 멀티모달 입력으로 지원해요. 각 URI는 disagg_encoder_proxy에서 인코더 인스턴스로 변경 없이 전달되어, 인코더가 미디어를 로컬에서 로드할 수 있어요.
EC 커넥터와 KV 전송
ECExampleonnector는 인코더 캐시를 로컬 디스크에 저장하고 전송을 돕는 데 쓰여요. 인코더 분리 기능을 켜려면 다음 구성을 추가하세요.
# Add to encoder instance:
--ec-transfer-config '{
"ec_connector": "ECExampleConnector",
"ec_role": "ec_producer",
"ec_connector_extra_config": {
"shared_storage_path": "'"$EC_SHARED_STORAGE_PATH"'"
}
}'
# Add to prefill/prefill+decode instance:
--ec-transfer-config '{
"ec_connector": "ECExampleConnector",
"ec_role": "ec_consumer",
"ec_connector_extra_config": {
"shared_storage_path": "'"$EC_SHARED_STORAGE_PATH"'"
}
}'
$EC_SHARED_STORAGE_PATH는 EC 커넥터가 캐시를 임시로 저장하는 경로예요.
프리필 인스턴스를 켜면(--prefill-servers-urls가 비활성화되지 않은 경우), PD 분리를 위해 --kv-transfer-config가 필요해요. 현재는 이를 위해 NixlConnector를 사용해요. Nixl로 PD 분리하는 더 많은 예제 코드는 tests/v1/kv_connector/nixl_integration을 참고하세요.
# Add to prefill instance:
--kv-transfer-config '{
"kv_connector": "NixlConnector",
"kv_role": "kv_producer"
}'
# Add to decode instance:
--kv-transfer-config '{
"kv_connector": "NixlConnector",
"kv_role": "kv_consumer"
}'
프록시 인스턴스 플래그 (disagg_epd_proxy.py)
| 플래그 | 설명 |
|---|---|
--encode-servers-urls |
쉼표로 구분된 인코더 엔드포인트 목록. 요청에서 추출된 모든 멀티모달 항목이 라운드로빈 방식으로 이 URL 중 하나에 팬아웃돼요. |
--prefill-servers-urls |
쉼표로 구분된 프리필 엔드포인트 목록. disable, none, 또는 ""로 설정하면 전용 프리필 단계를 건너뛰고 E+PD(인코더 + 프리필/디코드 결합)로 실행해요. |
--decode-servers-urls |
쉼표로 구분된 디코드 엔드포인트 목록. non-stream과 stream 경로 모두 이 목록에 대해 라운드로빈을 해요. |
--host, --port |
프록시 자신의 바인딩 주소(기본값: 0.0.0.0:8000). |
사용 예시입니다.
E + PD 구성:
$ python disagg_encoder_proxy.py \
--encode-servers-urls "http://e1:8001,http://e2:8002" \
--prefill-servers-urls "disable" \
--decode-servers-urls "http://pd1:8003,http://pd2:8004"
E + P + D 구성:
$ python disagg_encoder_proxy.py \
--encode-servers-urls "http://e1:8001,http://e2:8001" \
--prefill-servers-urls "http://p1:8003,http://p2:8004" \
--decode-servers-urls "http://d1:8005,http://d2:8006"