Llama 3.1 405B를 Lambda 1-Click 클러스터에서 서빙하기

Llama 3.1 405B를 Lambda 1-Click 클러스터에서 서빙하기

Llama 3.1 405B는 단일 GPU에 담기에는 너무 큰, 수백 GB급의 거대한 모델이에요. 이 가이드에서는 Lambda의 1-Click Cluster(1CC)에서 vLLM과 Ray를 조합해, 여러 노드에 걸쳐 모델을 나눠 올리는 분산 서빙 구조를 만드는 과정을 보여줘요.

핵심은 파이프라인 병렬(pipeline parallelism)이에요. 모델을 층 단위로 잘라 여러 GPU에 분산하고, 1CC의 InfiniBand 패브릭으로 노드 간 통신을 연결하면 405B 같은 모델도 납득할 만한 속도로 서빙할 수 있어요. 이 페이지를 읽고 나면 헤드 노드 설정부터 Ray 클러스터 상태 확인, 실제 추론 테스트까지 한 흐름이 잡혀요.

출처: Serving Llama 3.1 405B on a Lambda 1-Click Cluster - Lambda Docs

준비 사항

이 튜토리얼에는 이런 것들이 필요해요.

Llama 3.1 405B 모델을 내려받으려면 먼저 모델 라이선스 계약을 읽고 동의해야 해요. 동의하면 레포지토리 접근 요청이 승인 절차를 거치는데, 대개 금방 승인돼요. 요청 상태는 Hugging Face 계정 설정에서 확인할 수 있어요.

405B 모델 내려받기와 헤드 노드 설정

먼저 1CC 접근 방법을 따라 SSH를 설정해요. 그다음 1CC의 GPU 노드 중 하나로 SSH 접속해요. 노드 이름은 Lambda Cloud 콘솔의 1-Click Clusters 페이지에서 확인할 수 있어요. 이 노드를 클러스터 관리를 위한 헤드 노드로 쓸게요.

헤드 노드에서 이 튜토리얼에 필요한 환경변수를 설정해요.

export HEAD_IP=HEAD-IP
export SHARED_DIR=/home/ubuntu/FILE-SYSTEM-NAME
export HF_TOKEN=HF-TOKEN
export HF_HOME="${SHARED_DIR}/.cache/huggingface"
export MODEL_REPO=meta-llama/Meta-Llama-3.1-405B-Instruct
  • HEAD-IP: 헤드 노드의 IP 주소 (콘솔의 1-Click Clusters 페이지에서 확인)
  • FILE-SYSTEM-NAME: 1CC의 영구 스토리지 파일시스템 이름
  • HF-TOKEN: Hugging Face User Access Token

이어서 모델을 내려받아요.

mkdir -p "${HF_HOME}"
python3 -m venv llama-3.1
source llama-3.1/bin/activate
pip install -U huggingface_hub[cli]
huggingface-cli login --token "${HF_TOKEN}"
huggingface-cli download "${MODEL_REPO}"

이 명령들은 (1) 헤드 노드에 이 튜토리얼용 파이썬 가상환경을 만들고, (2) Llama 3.1 405B 모델을 1CC의 영구 스토리지 파일시스템에 내려받아요.

Llama 3.1 405B 모델은 약 2.3TB 크기라 내려받는 데 몇 시간이 걸릴 수 있어요.

여전히 헤드 노드에서 tmux로 세션을 시작해요. 그다음 vLLM이 제공하는 도우미 스크립트를 받아 Ray 클러스터를 띄워요.

curl -o "${SHARED_DIR}/run_cluster.sh" https://raw.githubusercontent.com/vllm-project/vllm/main/examples/run_cluster.sh
sudo bash "${SHARED_DIR}/run_cluster.sh" \
    vllm/vllm-openai \
    "${HEAD_IP}" \
    --head "${HF_HOME}" \
    --privileged -e NCCL_IB_HCA=^mlx5_0

앞의 명령은 (1) 공유 영구 스토리지 파일시스템에 vLLM 다중 노드 추론·서빙용 도우미 스크립트를 내려받고, (2) 이 스크립트로 vLLM이 Llama 3.1 405B를 서빙할 Ray 클러스터를 시작해요. 이 Ray 클러스터는 1CC의 InfiniBand 패브릭을 사용해 최적 성능을 내요.

다른 GPU 노드를 헤드 노드에 연결하기

이번에는 1CC의 다른 GPU 노드를 헤드 노드에 연결할게요. 이 노드를 워커 노드라고 부를게요.

새 터미널에서 워커 노드로 SSH 접속한 뒤, 환경변수를 설정해요.

export HEAD_IP=HEAD-IP
export SHARED_DIR=/home/ubuntu/FILE-SYSTEM-NAME
export HF_HOME="${SHARED_DIR}/.cache/huggingface"

HEAD-IP는 헤드 노드 IP, FILE-SYSTEM-NAME은 1CC의 영구 스토리지 파일시스템 이름으로 바꿔주세요. tmux로 새 세션을 연 뒤 워커 모드로 스크립트를 실행해요.

sudo bash "${SHARED_DIR}/run_cluster.sh" \
    vllm/vllm-openai \
    "${HEAD_IP}" \
    --worker \
    "${HF_HOME}" \
    --privileged -e NCCL_IB_HCA=^mlx5_0

이 명령이 워커 노드를 헤드 노드에 연결해요.

Ray 클러스터 상태 확인

워커 노드에서 새 tmux 창을 열고(Ctrl + B, 이어서 C), 컨테이너 안으로 들어가요.

sudo docker exec -it node /bin/bash

Ray 클러스터 상태를 확인해요.

ray status

이 명령은 다음과 비슷한 출력을 보여줘요.

======== Autoscaler status: 2024-07-25 00:20:50.831620 ========
Node status
---------------------------------------------------------------
Active:
 1 node_d86d9f0f1894c2e463d8168530f6745e32beb08ddf3b908d229d8527
 1 node_37af7f860c4bab2e035b5a55ba06e2e49dba9fa891d65f8264648804
Pending:
 (no pending nodes)
Recent failures:
 (no failures)

Resources
---------------------------------------------------------------
Usage:
 0.0/416.0 CPU
 16.0/16.0 GPU (16.0 used of 16.0 reserved in placement groups)
 0B/3.43TiB memory
 0B/19.46GiB object_store_memory

Demands:
 (no resource demands)

이 출력은 헤드 노드와 워커 노드 두 개가 활성 상태이고, Ray 클러스터에 GPU 16개가 잡혀 있음을 보여줘요.

Llama 3.1 405B 서빙

서버 상태를 확인했으니 이제 모델을 서빙할 차례예요. 먼저 내려받은 모델 스냅샷 이름을 확인해요.

ls /root/.cache/huggingface/hub/models--meta-llama--Meta-Llama-3.1-405B-Instruct/snapshots

이 명령은 아래와 같은 이름의 스냅샷을 반환해요.

e04e3022cdc89bfed0db69f5ac1d249e21ee2d30

이제 아래 명령으로 Llama 3.1 405B 서빙을 시작해요. 텐서 병렬 크기 8과 파이프라인 병렬 크기 2를 함께 지정했어요.

vllm serve "/root/.cache/huggingface/hub/models--meta-llama--Meta-Llama-3.1-405B-Instruct/snapshots/SNAPSHOT" --tensor-parallel-size 8 --pipeline-parallel-size 2

SNAPSHOT은 방금 확인한 모델 스냅샷 이름으로 바꿔주세요.

모델이 GPU에 로드되어 서빙 준비를 마치기까지 15분 이상 걸릴 수 있어요.

서버가 뜨면 아래처럼 Uvicorn이 8000 포트에서 실행 중이라는 로그가 보여요. 이 로그가 나오면 모델이 서빙 준비를 마친 거예요.

INFO:     Started server process [24469]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

Llama 3.1 405B 테스트

여전히 워커 노드에서 새 tmux 창을 열고(Ctrl + B, 이어서 C) 테스트 클라이언트를 준비해요.

python3 -m venv llama-3.1
source llama-3.1/bin/activate
pip install -U openai
curl -o ${SHARED_DIR}/inference_test.py 'https://raw.githubusercontent.com/vllm-project/vllm/main/examples/openai_chat_completion_client.py'

위 명령은 (1) 워커 노드에 파이썬 가상환경을 만들고, (2) vLLM의 예제 OpenAI 채팅 컴플리션 클라이언트를 내려받아요.

마지막으로 테스트 스크립트를 실행해요.

python3 ${SHARED_DIR}/inference_test.py

다음과 비슷한 출력이 나와요. 모델이 "2020 월드시리즈는 어디서 열렸나?" 같은 질문에 답하는 것을 확인할 수 있어요. 첫 토큰까지는 시간이 걸리지만 전체 추론이 끝나는 구조 자체는 일반적인 채팅 컴플리션과 같아요.

Chat completion results:
ChatCompletion(id='chat-8eba7fa7e2f7442aafa82a1683bfc77f', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='The 2020 World Series was played at Globe Life Field in Arlington, Texas. This was a neutral site due to COVID-19 restrictions and was also referred to as a "bubble" environment.', role='assistant', function_call=None, tool_calls=[]), stop_reason=None)], created=1721884178, model='/root/.cache/huggingface/hub/models--meta-llama--Meta-Llama-3.1-405B-Instruct/snapshots/e04e3022cdc89bfed0db69f5ac1d249e21ee2d30', object='chat.completion', service_tier=None, system_fingerprint=None, usage=CompletionUsage(completion_tokens=41, prompt_tokens=59, total_tokens=100))

더 알아보기