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"

더 알아보기 (Learn more)