Offene Modelle mit einem benutzerdefinierten vLLM-Container bereitstellen

Obwohl die verschiedenen Optionen für die Modellbereitstellung in Vertex AI für viele Anwendungsfälle ausreichen, müssen Sie möglicherweise Ihre eigenen Container-Images verwenden, um Modelle in Vertex AI bereitzustellen. In diesem Dokument wird beschrieben, wie Sie ein benutzerdefiniertes vLLM-Container-Image verwenden, um Modelle in Vertex AI auf CPUs, GPUs oder TPUs bereitzustellen. Weitere Informationen zu von vLLM unterstützten Modellen finden Sie in der vLLM-Dokumentation.

Der vLLM API-Server implementiert das OpenAI API-Protokoll, unterstützt aber nicht die Anforderungen an Anfragen und Antworten von Vertex AI. Daher müssen Sie eine Rohinferenzanfrage von Vertex AI verwenden, um Inferenzen von Modellen abzurufen, die mit einem Vorhersageendpunkt in Vertex AI bereitgestellt werden. Weitere Informationen zur Methode „Raw Prediction“ im Vertex AI Python SDK finden Sie in der Python SDK-Dokumentation.

Sie können Modelle sowohl von Hugging Face als auch von Cloud Storage beziehen. Dieser Ansatz bietet Flexibilität, sodass Sie den von der Community betriebenen Modell-Hub (Hugging Face) und die optimierten Datenübertragungs- und Sicherheitsfunktionen von Cloud Storage für die interne Modellverwaltung oder feinabgestimmte Versionen nutzen können.

vLLM lädt die Modelle von Hugging Face herunter, wenn ein Hugging Face-Zugriffstoken angegeben wird. Andernfalls geht vLLM davon aus, dass das Modell auf der lokalen Festplatte verfügbar ist. Mit dem benutzerdefinierten Container-Image kann Vertex AI das Modell zusätzlich zu Hugging Face auch vonGoogle Cloud herunterladen.

Hinweise

  1. Aktivieren Sie in Ihrem Google Cloud -Projekt die Vertex AI- und Artifact Registry-APIs.

    gcloud services enable aiplatform.googleapis.com \
        artifactregistry.googleapis.com
    
  2. Konfigurieren Sie das Google Cloud CLI mit Ihrer Projekt-ID und initialisieren Sie das Vertex AI SDK.

    PROJECT_ID = "PROJECT_ID"
    LOCATION = "LOCATION"
    import vertexai
    vertexai.init(project=PROJECT_ID, location=LOCATION)
    
    gcloud config set project {PROJECT_ID}
    
  3. ein Docker-Repository in Artifact Registry erstellen

    gcloud artifacts repositories create DOCKER_REPOSITORY \
        --repository-format=docker \
        --location=LOCATION \
        --description="Vertex AI Docker repository"
    
  4. Optional: Wenn Sie Modelle von Hugging Face herunterladen, besorgen Sie sich ein Hugging Face-Token.

    1. Erstellen Sie ein Hugging Face-Konto, falls Sie noch keines haben.
    2. Für Modelle mit eingeschränktem Zugriff wie Llama 3.2 müssen Sie den Zugriff auf Hugging Face beantragen und erhalten, bevor Sie fortfahren.
    3. Zugriffstoken generieren: Rufen Sie Mein Profil > Einstellungen > Zugriffstokens auf.
    4. Wählen Sie Neues Token aus.
    5. Geben Sie einen Namen und eine Rolle mit mindestens Leseberechtigung an.
    6. Wählen Sie Token generieren aus.
    7. Speichern Sie dieses Token für die Bereitstellungsschritte.

Container-Build-Dateien vorbereiten

Mit dem folgenden Dockerfile wird das benutzerdefinierte vLLM-Container-Image für GPUs, TPUs und CPUs erstellt. In diesem benutzerdefinierten Container werden Modelle von Hugging Face oder Cloud Storage heruntergeladen.

ARG BASE_IMAGE
FROM ${BASE_IMAGE}

ENV DEBIAN_FRONTEND=noninteractive
# Install gcloud SDK
RUN apt-get update && \
    apt-get install -y apt-utils git apt-transport-https gnupg ca-certificates curl \
    && echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list \
    && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg \
    && apt-get update -y && apt-get install google-cloud-cli -y \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /workspace/vllm

# Copy entrypoint.sh to the container
COPY ./entrypoint.sh /workspace/vllm/vertexai/entrypoint.sh
RUN chmod +x /workspace/vllm/vertexai/entrypoint.sh

ENTRYPOINT ["/workspace/vllm/vertexai/entrypoint.sh"]

Erstellen Sie das benutzerdefinierte Container-Image mit Cloud Build. Die folgende cloudbuild.yaml-Konfigurationsdatei zeigt, wie das Image für mehrere Plattformen mit demselben Dockerfile erstellt wird.

steps:
-   name: 'gcr.io/cloud-builders/docker'
  automapSubstitutions: true
  script: |
      #!/usr/bin/env bash
      set -euo pipefail
      device_type_param=${_DEVICE_TYPE}
      device_type=${device_type_param,,}
      base_image=${_BASE_IMAGE}
      image_name="vllm-${_DEVICE_TYPE}"
      if [[ $device_type == "cpu" ]]; then
        echo "Quietly building open source vLLM CPU container image"
        git clone https://github.com/vllm-project/vllm.git
        cd vllm && DOCKER_BUILDKIT=1 docker build -t $base_image -f docker/Dockerfile.cpu . -q
        cd ..
      fi
      echo "Quietly building container image for: $device_type"
      docker build -t $LOCATION-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/$image_name --build-arg BASE_IMAGE=$base_image . -q
      docker push $LOCATION-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/$image_name
substitutions:
    _DEVICE_TYPE: gpu
    _BASE_IMAGE: vllm/vllm-openai
    _REPOSITORY: my-docker-repo

Die Dateien sind im GitHub-Repository googlecloudplatform/vertex-ai-samples verfügbar. Klonen Sie das Repository, um sie zu verwenden:

git clone https://github.com/GoogleCloudPlatform/vertex-ai-samples.git

Container-Image erstellen und per Push übertragen

Erstellen Sie das benutzerdefinierte Container-Image mit Cloud Build, indem Sie die Datei cloudbuild.yaml einreichen. Verwenden Sie Ersetzungen, um den Zielgerätetyp (GPU, TPU oder CPU) und das entsprechende Basis-Image anzugeben.

GPU

DEVICE_TYPE="gpu"
BASE_IMAGE="vllm/vllm-openai"
cd vertex-ai-samples/notebooks/official/prediction/vertexai_serving_vllm/cloud-build && \
gcloud builds submit \
    --config=cloudbuild.yaml \
    --region=LOCATION \
    --timeout="2h" \
    --machine-type=e2-highcpu-32 \
    --substitutions=_REPOSITORY=DOCKER_REPOSITORY,_DEVICE_TYPE=$DEVICE_TYPE,_BASE_IMAGE=$BASE_IMAGE

TPU

DEVICE_TYPE="tpu"
BASE_IMAGE="vllm/vllm-tpu:nightly"
cd vertex-ai-samples/notebooks/official/prediction/vertexai_serving_vllm/cloud-build && \
gcloud builds submit \
    --config=cloudbuild.yaml \
    --region=LOCATION \
    --timeout="2h" \
    --machine-type=e2-highcpu-32 \
    --substitutions=_REPOSITORY=DOCKER_REPOSITORY,_DEVICE_TYPE=$DEVICE_TYPE,_BASE_IMAGE=$BASE_IMAGE

CPU

DEVICE_TYPE="cpu"
BASE_IMAGE="vllm-cpu-base"
cd vertex-ai-samples/notebooks/official/prediction/vertexai_serving_vllm/cloud-build && \
gcloud builds submit \
    --config=cloudbuild.yaml \
    --region=LOCATION \
    --timeout="2h" \
    --machine-type=e2-highcpu-32 \
    --substitutions=_REPOSITORY=DOCKER_REPOSITORY,_DEVICE_TYPE=$DEVICE_TYPE,_BASE_IMAGE=$BASE_IMAGE

Konfigurieren Sie nach Abschluss des Builds Docker für die Authentifizierung bei Artifact Registry:

gcloud auth configure-docker LOCATION-docker.pkg.dev --quiet

Modell in Model Registry hochladen und bereitstellen

Laden Sie Ihr Modell in die Vertex AI Model Registry hoch, erstellen Sie einen Endpunkt und stellen Sie das Modell bereit. In diesem Beispiel wird Llama 3.2 3B verwendet. Sie können es aber auch für andere Modelle anpassen.

  1. Modell- und Deployment-Variablen definieren Legen Sie die Variable DOCKER_URI auf das Image fest, das Sie im vorherigen Schritt erstellt haben (z. B. für GPU):

    DOCKER_URI = f"LOCATION-docker.pkg.dev/PROJECT_ID/DOCKER_REPOSITORY/vllm-gpu"
    

    Definieren Sie Variablen für das Hugging Face-Token und die Modelleigenschaften. Beispiel für die GPU-Bereitstellung:

    hf_token = "your-hugging-face-auth-token"
    model_name = "gpu-llama3_2_3B-serve-vllm"
    model_id = "meta-llama/Llama-3.2-3B"
    machine_type = "g2-standard-8"
    accelerator_type = "NVIDIA_L4"
    accelerator_count = 1
    
  2. Laden Sie das Modell in Model Registry hoch. Die upload_model-Funktion variiert je nach Gerätetyp leicht, da unterschiedliche vLLM-Argumente und Umgebungsvariablen verwendet werden.

    from google.cloud import aiplatform
    
    def upload_model_gpu(model_name, model_id, hf_token, accelerator_count, docker_uri):
        vllm_args = [
            "python3", "-m", "vllm.entrypoints.openai.api_server",
            "--host=0.0.0.0", "--port=8080", f"--model={model_id}",
            "--max-model-len=2048", "--gpu-memory-utilization=0.9",
            "--enable-prefix-caching", f"--tensor-parallel-size={accelerator_count}",
        ]
        env_vars = {
            "HF_TOKEN": hf_token,
            "LD_LIBRARY_PATH": "$LD_LIBRARY_PATH:/usr/local/nvidia/lib64",
        }
        model = aiplatform.Model.upload(
            display_name=model_name,
            serving_container_image_uri=docker_uri,
            serving_container_args=vllm_args,
            serving_container_ports=[8080],
            serving_container_predict_route="/v1/completions",
            serving_container_health_route="/health",
            serving_container_environment_variables=env_vars,
            serving_container_shared_memory_size_mb=(16 * 1024),  # 16 GB
            serving_container_deployment_timeout=1800,
        )
        return model
    
    def upload_model_tpu(model_name, model_id, hf_token, tpu_count, docker_uri):
        vllm_args = [
            "python3", "-m", "vllm.entrypoints.openai.api_server",
            "--host=0.0.0.0", "--port=8080", f"--model={model_id}",
            "--max-model-len=2048", "--enable-prefix-caching",
            f"--tensor-parallel-size={tpu_count}",
        ]
        env_vars = {"HF_TOKEN": hf_token}
        model = aiplatform.Model.upload(
            display_name=model_name,
            serving_container_image_uri=docker_uri,
            serving_container_args=vllm_args,
            serving_container_ports=[8080],
            serving_container_predict_route="/v1/completions",
            serving_container_health_route="/health",
            serving_container_environment_variables=env_vars,
            serving_container_shared_memory_size_mb=(16 * 1024),  # 16 GB
            serving_container_deployment_timeout=1800,
        )
        return model
    
    def upload_model_cpu(model_name, model_id, hf_token, docker_uri):
        vllm_args = [
            "python3", "-m", "vllm.entrypoints.openai.api_server",
            "--host=0.0.0.0", "--port=8080", f"--model={model_id}",
            "--max-model-len=2048",
        ]
        env_vars = {"HF_TOKEN": hf_token}
        model = aiplatform.Model.upload(
            display_name=model_name,
            serving_container_image_uri=docker_uri,
            serving_container_args=vllm_args,
            serving_container_ports=[8080],
            serving_container_predict_route="/v1/completions",
            serving_container_health_route="/health",
            serving_container_environment_variables=env_vars,
            serving_container_shared_memory_size_mb=(16 * 1024),  # 16 GB
            serving_container_deployment_timeout=1800,
        )
        return model
    
    # Example for GPU:
    vertexai_model = upload_model_gpu(model_name, model_id, hf_token, accelerator_count, DOCKER_URI)
    
  3. Erstellen Sie einen Endpunkt.

    endpoint = aiplatform.Endpoint.create(display_name=f"model_name-endpoint")
    
  4. Stellen Sie das Modell auf dem Endpunkt bereit. Die Bereitstellung des Modells kann 20 bis 30 Minuten dauern.

    # Example for GPU:
    vertexai_model.deploy(
        endpoint=endpoint,
        deployed_model_display_name=model_name,
        machine_type=machine_type,
        accelerator_type=accelerator_type,
        accelerator_count=accelerator_count,
        traffic_percentage=100,
        deploy_request_timeout=1800,
        min_replica_count=1,
        max_replica_count=4,
        autoscaling_target_accelerator_duty_cycle=60,
    )
    

    Lassen Sie bei TPUs die Parameter accelerator_type und accelerator_count weg und verwenden Sie autoscaling_target_request_count_per_minute=60. Lassen Sie bei CPUs die Parameter accelerator_type und accelerator_count weg und verwenden Sie autoscaling_target_cpu_utilization=60.

Modelle aus Cloud Storage laden

Der benutzerdefinierte Container lädt das Modell von einem Cloud Storage-Speicherort herunter, anstatt es von Hugging Face herunterzuladen. Wenn Sie Cloud Storage verwenden, gilt Folgendes:

  • Legen Sie den Parameter model_id in der Funktion upload_model auf einen Cloud Storage-URI fest, z. B. gs://<var>my-bucket</var>/<var>my-models</var>/<var>llama_3_2_3B</var>.
  • Lassen Sie die Variable HF_TOKEN in env_vars weg, wenn Sie upload_model aufrufen.
  • Wenn Sie model.deploy aufrufen, geben Sie ein service_account an, das die Berechtigungen zum Lesen aus dem Cloud Storage-Bucket hat.

IAM-Dienstkonto für den Cloud Storage-Zugriff erstellen

Wenn sich Ihr Modell in Cloud Storage befindet, erstellen Sie ein Dienstkonto, mit dem Vertex Prediction-Endpunkte auf die Modellartefakte zugreifen können.

SERVICE_ACCOUNT_NAME = "vertexai-endpoint-sa"
SERVICE_ACCOUNT_EMAIL = f"SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com"
gcloud iam service-accounts create SERVICE_ACCOUNT_NAME \
    --display-name="Vertex AI Endpoint Service Account"

# Grant storage read permission
gcloud projects add-iam-policy-binding PROJECT_ID \
    --member="serviceAccount:SERVICE_ACCOUNT_EMAIL" \
    --role="roles/storage.objectViewer"

Übergeben Sie beim Bereitstellen die E-Mail-Adresse des Dienstkontos an die Methode deploy: service_account=<var>SERVICE_ACCOUNT_EMAIL</var>.

Vorhersagen über Endpunkt abrufen

Nachdem Sie das Modell erfolgreich auf dem Endpunkt bereitgestellt haben, können Sie die Modellantwort mit raw_predict überprüfen.

import json

PROMPT = "Distance of moon from earth is "
request_body = json.dumps(
    {
        "prompt": PROMPT,
        "temperature": 0.0,
    },
)

raw_response = endpoint.raw_predict(
    body=request_body, headers={"Content-Type": "application/json"}
)
assert raw_response.status_code == 200
result = json.loads(raw_response.text)

for choice in result["choices"]:
    print(choice)

Beispielausgabe:

{
  "index": 0,
  "text": "384,400 km. The moon is 1/4 of the earth's",
  "logprobs": null,
  "finish_reason": "length",
  "stop_reason": null,
  "prompt_logprobs": null
}

Nächste Schritte