LLM mithilfe von TPUs in GKE mit KubeRay bereitstellen


In dieser Anleitung wird beschrieben, wie Sie ein Large Language Model (LLM) mit Tensor Processing Units (TPUs) in Google Kubernetes Engine (GKE) mit dem Ray Operator-Add-on und dem vLLM-Bereitstellungs-Framework bereitstellen.

In dieser Anleitung können Sie LLM-Modelle auf TPU v5e oder TPU Trillium (v6e) bereitstellen:

Dieser Leitfaden richtet sich an Kunden von generativer KI, neue und bestehende GKE-Nutzer, ML-Entwickler, MLOps-Entwickler (DevOps) oder Plattformadministratoren, die daran interessiert sind, Funktionen zur Kubernetes-Containerorchestrierung für die Bereitstellung von Modellen mit Ray auf TPUs mit vLLM zu nutzen.

Hintergrund

In diesem Abschnitt werden die in diesem Leitfaden verwendeten Schlüsseltechnologien beschrieben.

Verwalteter Kubernetes-Dienst von GKE

Google Cloud bietet eine Vielzahl von Diensten, darunter GKE, der sich gut für die Bereitstellung und Verwaltung von KI-/ML-Arbeitslasten eignet. GKE ist ein verwalteter Kubernetes-Dienst, der die Bereitstellung, Skalierung und Verwaltung von Containeranwendungen vereinfacht. GKE bietet die erforderliche Infrastruktur, einschließlich skalierbarer Ressourcen, verteiltes Computing und effiziente Netzwerke, um die Rechenanforderungen von LLMs zu bewältigen.

Weitere Informationen zu wichtigen Kubernetes-Konzepten finden Sie unter Informationen zu Kubernetes. Weitere Informationen zu GKE und dazu, wie Sie damit Kubernetes skalieren, automatisieren und verwalten können, finden Sie in der GKE-Übersicht.

Ray Operator

Das Ray Operator-Add-on in GKE bietet eine End-to-End-KI-/ML-Plattform für die Bereitstellung, das Training und die Optimierung von ML-Arbeitslasten. In dieser Anleitung verwenden Sie Ray Serve, ein Framework in Ray, um beliebte LLMs von Hugging Face bereitzustellen.

TPUs

TPUs sind von Google speziell entwickelte anwendungsspezifische integrierte Schaltungen (Application-Specific Integrated Circuits, ASICs), die verwendet werden, um das maschinelle Lernen und die KI-Modelle zu beschleunigen, die mit Frameworks wie folgenden erstellt wurden:TensorFlow, PyTorch und JAX.

In diesem Tutorial wird beschrieben, wie Sie LLM-Modelle auf TPU v5e- oder TPU Trillium-Knoten (v6e) bereitstellen. Dabei werden TPU-Topologien basierend auf den Anforderungen der einzelnen Modelle für die Bereitstellung von Prompts mit niedriger Latenz konfiguriert.

vLLM

vLLM ist ein hoch optimiertes Open-Source-LLM-Bereitstellungs-Framework, das den Bereitstellungsdurchsatz auf TPUs über Funktionen wie die Folgenden beschleunigen kann:

  • Optimierte Transformer-Implementierung mit PagedAttention
  • Kontinuierliche Batchverarbeitung zur Verbesserung des allgemeinen Bereitstellungsdurchsatzes
  • Tensor-Parallelität und verteilte Bereitstellung auf mehreren GPUs

Weitere Informationen finden Sie in der vLLM-Dokumentation.

Lernziele

Diese Anleitung umfasst die folgenden Schritte:

  1. Erstellen Sie einen GKE-Cluster mit einem TPU-Knotenpool.
  2. Stellen Sie eine benutzerdefinierte RayCluster-Ressource mit einem TPU-Slice mit einem einzelnen Host bereit. In GKE wird die benutzerdefinierte RayCluster-Ressource als Kubernetes-Pods bereitgestellt.
  3. LLM bereitstellen
  4. Mit den Modellen interagieren

Optional können Sie die folgenden Ressourcen und Techniken für die Modellbereitstellung konfigurieren, die vom Ray Serve-Framework unterstützt werden:

  • Stellen Sie eine benutzerdefinierte RayService-Ressource bereit.
  • Mehrere Modelle mit der Modellkomposition zusammenführen.

Hinweise

Führen Sie die folgenden Aufgaben aus, bevor Sie beginnen:

  • Aktivieren Sie die Google Kubernetes Engine API.
  • Google Kubernetes Engine API aktivieren
  • Wenn Sie die Google Cloud CLI für diese Aufgabe verwenden möchten, müssen Sie die gcloud CLI installieren und dann initialisieren. Wenn Sie die gcloud CLI bereits installiert haben, rufen Sie die neueste Version mit gcloud components update ab.
  • Erstellen Sie ein Hugging Face-Konto, falls Sie noch keines haben.
  • Sie benötigen ein Hugging Face-Token.
  • Prüfen Sie, ob Sie Zugriff auf das Hugging Face-Modell haben, das Sie verwenden möchten. Diesen Zugriff erhalten Sie in der Regel, indem Sie eine Vereinbarung unterzeichnen und auf der Modellseite von Hugging Face Zugriff vom Modelleigentümer anfordern.
  • Prüfen Sie, ob Sie die folgenden IAM-Rollen haben:
    • roles/container.admin
    • roles/iam.serviceAccountAdmin
    • roles/container.clusterAdmin
    • roles/artifactregistry.writer

Umgebung vorbereiten

  1. Prüfen Sie, ob Sie in Ihrem Google Cloud -Projekt ein ausreichendes Kontingent für eine Single-Host-TPU v5e oder eine Single-Host-TPU Trillium (v6e) haben. Informationen zum Verwalten Ihres Kontingents finden Sie unter TPU-Kontingente.

  2. Starten Sie in der Google Cloud Console eine Cloud Shell-Instanz:
    Cloud Shell öffnen

  3. Klonen Sie das Beispiel-Repository:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git
    cd kubernetes-engine-samples
    
  4. Wechseln Sie zum Arbeitsverzeichnis:

    cd ai-ml/gke-ray/rayserve/llm
    
  5. Legen Sie die Standardumgebungsvariablen für die Erstellung des GKE-Cluster fest:

    Llama-3-8B-Instruct

    export PROJECT_ID=$(gcloud config get project)
    export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")
    export CLUSTER_NAME=vllm-tpu
    export COMPUTE_REGION=REGION
    export COMPUTE_ZONE=ZONE
    export HF_TOKEN=HUGGING_FACE_TOKEN
    export GSBUCKET=vllm-tpu-bucket
    export KSA_NAME=vllm-sa
    export NAMESPACE=default
    export MODEL_ID="meta-llama/Meta-Llama-3-8B-Instruct"
    export VLLM_IMAGE=docker.io/vllm/vllm-tpu:866fa4550d572f4ff3521ccf503e0df2e76591a1
    export SERVICE_NAME=vllm-tpu-head-svc
    

    Ersetzen Sie Folgendes:

    • HUGGING_FACE_TOKEN: Ihr Hugging Face-Zugriffstoken.
    • REGION: Die Region, in der Sie ein TPU-Kontingent haben. Prüfen Sie, ob die TPU-Version, die Sie verwenden möchten, in dieser Region verfügbar ist. Weitere Informationen finden Sie unter TPU-Verfügbarkeit in GKE.
    • ZONE: Die Zone mit verfügbarem TPU-Kontingent.
    • VLLM_IMAGE: Das vLLM-TPU-Image. Sie können das öffentliche docker.io/vllm/vllm-tpu:866fa4550d572f4ff3521ccf503e0df2e76591a1-Image verwenden oder ein eigenes TPU-Image erstellen.

    Mistral-7B

    export PROJECT_ID=$(gcloud config get project)
    export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")
    export CLUSTER_NAME=vllm-tpu
    export COMPUTE_REGION=REGION
    export COMPUTE_ZONE=ZONE
    export HF_TOKEN=HUGGING_FACE_TOKEN
    export GSBUCKET=vllm-tpu-bucket
    export KSA_NAME=vllm-sa
    export NAMESPACE=default
    export MODEL_ID="mistralai/Mistral-7B-Instruct-v0.3"
    export TOKENIZER_MODE=mistral
    export VLLM_IMAGE=docker.io/vllm/vllm-tpu:866fa4550d572f4ff3521ccf503e0df2e76591a1
    export SERVICE_NAME=vllm-tpu-head-svc
    

    Ersetzen Sie Folgendes:

    • HUGGING_FACE_TOKEN: Ihr Hugging Face-Zugriffstoken.
    • REGION: Die Region, in der Sie ein TPU-Kontingent haben. Prüfen Sie, ob die TPU-Version, die Sie verwenden möchten, in dieser Region verfügbar ist. Weitere Informationen finden Sie unter TPU-Verfügbarkeit in GKE.
    • ZONE: Die Zone mit verfügbarem TPU-Kontingent.
    • VLLM_IMAGE: Das vLLM-TPU-Image. Sie können das öffentliche docker.io/vllm/vllm-tpu:866fa4550d572f4ff3521ccf503e0df2e76591a1-Image verwenden oder ein eigenes TPU-Image erstellen.

    Llama 3.1 70B

    export PROJECT_ID=$(gcloud config get project)
    export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")
    export CLUSTER_NAME=vllm-tpu
    export COMPUTE_REGION=REGION
    export COMPUTE_ZONE=ZONE
    export HF_TOKEN=HUGGING_FACE_TOKEN
    export GSBUCKET=vllm-tpu-bucket
    export KSA_NAME=vllm-sa
    export NAMESPACE=default
    export MODEL_ID="meta-llama/Llama-3.1-70B"
    export MAX_MODEL_LEN=8192
    export VLLM_IMAGE=docker.io/vllm/vllm-tpu:866fa4550d572f4ff3521ccf503e0df2e76591a1
    export SERVICE_NAME=vllm-tpu-head-svc
    

    Ersetzen Sie Folgendes:

    • HUGGING_FACE_TOKEN: Ihr Hugging Face-Zugriffstoken.
    • REGION: Die Region, in der Sie ein TPU-Kontingent haben. Prüfen Sie, ob die TPU-Version, die Sie verwenden möchten, in dieser Region verfügbar ist. Weitere Informationen finden Sie unter TPU-Verfügbarkeit in GKE.
    • ZONE: Die Zone mit verfügbarem TPU-Kontingent.
    • VLLM_IMAGE: Das vLLM-TPU-Image. Sie können das öffentliche docker.io/vllm/vllm-tpu:866fa4550d572f4ff3521ccf503e0df2e76591a1-Image verwenden oder ein eigenes TPU-Image erstellen.
  6. Rufen Sie das vLLM-Container-Image ab:

    sudo usermod -aG docker ${USER}
    newgrp docker
    docker pull ${VLLM_IMAGE}
    

Cluster erstellen

Sie können eine LLM auf TPUs mit Ray in einem GKE Autopilot- oder Standardcluster mit dem Ray Operator-Add-on bereitstellen.

Best practices:

Verwenden Sie einen Autopilot-Cluster für eine vollständig verwaltete Kubernetes-Umgebung. Informationen zum Auswählen des GKE-Betriebsmodus, der für Ihre Arbeitslasten am besten geeignet ist, finden Sie unter GKE-Betriebsmodus auswählen.

Autopilot- oder Standardcluster mit Cloud Shell erstellen:

Autopilot

  1. GKE Autopilot-Cluster mit aktiviertem Ray-Operator-Add-on erstellen:

    gcloud container clusters create-auto ${CLUSTER_NAME}  \
        --enable-ray-operator \
        --release-channel=rapid \
        --location=${COMPUTE_REGION}
    

Standard

  1. Standardcluster mit aktiviertem Ray-Operator-Add-on erstellen:

    gcloud container clusters create ${CLUSTER_NAME} \
        --release-channel=rapid \
        --location=${COMPUTE_ZONE} \
        --workload-pool=${PROJECT_ID}.svc.id.goog \
        --machine-type="n1-standard-4" \
        --addons=RayOperator,GcsFuseCsiDriver
    
  2. So erstellen Sie einen TPU-Slice-Knotenpool mit einem Host:

    Llama-3-8B-Instruct

    gcloud container node-pools create tpu-1 \
        --location=${COMPUTE_ZONE} \
        --cluster=${CLUSTER_NAME} \
        --machine-type=ct5lp-hightpu-8t \
        --num-nodes=1
    

    GKE erstellt einen TPU v5e-Knotenpool mit dem Maschinentyp ct5lp-hightpu-8t.

    Mistral-7B

    gcloud container node-pools create tpu-1 \
        --location=${COMPUTE_ZONE} \
        --cluster=${CLUSTER_NAME} \
        --machine-type=ct5lp-hightpu-8t \
        --num-nodes=1
    

    GKE erstellt einen TPU v5e-Knotenpool mit dem Maschinentyp ct5lp-hightpu-8t.

    Llama 3.1 70B

    gcloud container node-pools create tpu-1 \
        --location=${COMPUTE_ZONE} \
        --cluster=${CLUSTER_NAME} \
        --machine-type=ct6e-standard-8t \
        --num-nodes=1
    

    GKE erstellt einen TPU v6e-Knotenpool mit dem Maschinentyp ct6e-standard-8t.

kubectl für die Kommunikation mit Ihrem Cluster konfigurieren

Führen Sie den folgenden Befehl aus, um kubectl für die Kommunikation mit Ihrem Cluster zu konfigurieren:

Autopilot

gcloud container clusters get-credentials ${CLUSTER_NAME} \
    --location=${COMPUTE_REGION}

Standard

gcloud container clusters get-credentials ${CLUSTER_NAME} \
    --location=${COMPUTE_ZONE}

Kubernetes-Secret für Hugging Face-Anmeldedaten erstellen

Führen Sie den folgenden Befehl aus, um ein Kubernetes-Secret zu erstellen, das das Hugging Face-Token enthält:

kubectl create secret generic hf-secret \
    --from-literal=hf_api_token=${HF_TOKEN} \
    --dry-run=client -o yaml | kubectl --namespace ${NAMESPACE} apply -f -

Cloud Storage-Bucket erstellen

Um die Startzeit der vLLM-Bereitstellung zu verkürzen und den erforderlichen Speicherplatz pro Knoten zu minimieren, verwenden Sie den Cloud Storage FUSE-CSI-Treiber, um das heruntergeladene Modell und den Kompilierungscache auf den Ray-Knoten bereitzustellen.

Führen Sie in Cloud Shell den folgenden Befehl aus:

gcloud storage buckets create gs://${GSBUCKET} \
    --uniform-bucket-level-access

Mit diesem Befehl wird ein Cloud Storage-Bucket zum Speichern der Modelldateien erstellt, die Sie von Hugging Face herunterladen.

Kubernetes-ServiceAccount für den Zugriff auf den Bucket einrichten

  1. Erstellen Sie das Kubernetes-Dienstkonto:

    kubectl create serviceaccount ${KSA_NAME} \
        --namespace ${NAMESPACE}
    
  2. Gewähren Sie dem Kubernetes-Dienstkonto Lese-/Schreibzugriff auf den Cloud Storage-Bucket:

    gcloud storage buckets add-iam-policy-binding gs://${GSBUCKET} \
        --member "principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/${NAMESPACE}/sa/${KSA_NAME}" \
        --role "roles/storage.objectUser"
    

    GKE erstellt die folgenden Ressourcen für das LLM:

    1. Ein Cloud Storage-Bucket zum Speichern des heruntergeladenen Modells und des Kompilierungscache. Ein Cloud Storage FUSE-CSI-Treiber liest den Inhalt des Buckets.
    2. Volumes mit aktiviertem Datei-Caching und die Funktion Paralleler Download von Cloud Storage FUSE.
    Best Practice:

    Verwenden Sie einen Dateicache, der von tmpfs oder Hyperdisk / Persistent Disk unterstützt wird, je nach erwarteter Größe der Modellinhalte, z. B. Gewichtsdateien. In dieser Anleitung verwenden Sie einen durch RAM unterstützten Cloud Storage FUSE-Dateicache.

Benutzerdefinierte RayCluster-Ressource bereitstellen

Stellen Sie eine benutzerdefinierte RayCluster-Ressource bereit, die in der Regel aus einem System-Pod und mehreren Worker-Pods besteht.

Llama-3-8B-Instruct

Erstellen Sie die benutzerdefinierte RayCluster-Ressource, um das auf Anweisungen abgestimmte Llama 3-Modell mit 8 Milliarden Parametern bereitzustellen. Führen Sie dazu die folgenden Schritte aus:

  1. Prüfen Sie das ray-cluster.tpu-v5e-singlehost.yaml-Manifest:

    apiVersion: ray.io/v1
    kind: RayCluster
    metadata:
      name: vllm-tpu
    spec:
      headGroupSpec:
        rayStartParams: {}
        template:
          metadata:
            annotations:
              gke-gcsfuse/volumes: "true"
              gke-gcsfuse/cpu-limit: "0"
              gke-gcsfuse/memory-limit: "0"
              gke-gcsfuse/ephemeral-storage-limit: "0"
          spec:
            serviceAccountName: $KSA_NAME
            containers:
              - name: ray-head
                image: $VLLM_IMAGE
                imagePullPolicy: IfNotPresent
                resources:
                  limits:
                    cpu: "2"
                    memory: 8G
                  requests:
                    cpu: "2"
                    memory: 8G
                env:
                  - name: HUGGING_FACE_HUB_TOKEN
                    valueFrom:
                      secretKeyRef:
                        name: hf-secret
                        key: hf_api_token
                  - name: VLLM_XLA_CACHE_PATH
                    value: "/data"
                ports:
                  - containerPort: 6379
                    name: gcs
                  - containerPort: 8265
                    name: dashboard
                  - containerPort: 10001
                    name: client
                  - containerPort: 8000
                    name: serve
                  - containerPort: 8471
                    name: slicebuilder
                  - containerPort: 8081
                    name: mxla
                volumeMounts:
                - name: gcs-fuse-csi-ephemeral
                  mountPath: /data
                - name: dshm
                  mountPath: /dev/shm
            volumes:
            - name: gke-gcsfuse-cache
              emptyDir:
                medium: Memory
            - name: dshm
              emptyDir:
                medium: Memory
            - name: gcs-fuse-csi-ephemeral
              csi:
                driver: gcsfuse.csi.storage.gke.io
                volumeAttributes:
                  bucketName: $GSBUCKET
                  mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
      workerGroupSpecs:
      - groupName: tpu-group
        replicas: 1
        minReplicas: 1
        maxReplicas: 1
        numOfHosts: 1
        rayStartParams: {}
        template:
          metadata:
            annotations:
              gke-gcsfuse/volumes: "true"
              gke-gcsfuse/cpu-limit: "0"
              gke-gcsfuse/memory-limit: "0"
              gke-gcsfuse/ephemeral-storage-limit: "0"
          spec:
            serviceAccountName: $KSA_NAME
            containers:
              - name: ray-worker
                image: $VLLM_IMAGE
                imagePullPolicy: IfNotPresent
                resources:
                  limits:
                    cpu: "100"
                    google.com/tpu: "8"
                    ephemeral-storage: 40G
                    memory: 200G
                  requests:
                    cpu: "100"
                    google.com/tpu: "8"
                    ephemeral-storage: 40G
                    memory: 200G
                env:
                  - name: VLLM_XLA_CACHE_PATH
                    value: "/data"
                  - name: HUGGING_FACE_HUB_TOKEN
                    valueFrom:
                      secretKeyRef:
                        name: hf-secret
                        key: hf_api_token
                volumeMounts:
                - name: gcs-fuse-csi-ephemeral
                  mountPath: /data
                - name: dshm
                  mountPath: /dev/shm
            volumes:
            - name: gke-gcsfuse-cache
              emptyDir:
                medium: Memory
            - name: dshm
              emptyDir:
                medium: Memory
            - name: gcs-fuse-csi-ephemeral
              csi:
                driver: gcsfuse.csi.storage.gke.io
                volumeAttributes:
                  bucketName: $GSBUCKET
                  mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
            nodeSelector:
              cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
              cloud.google.com/gke-tpu-topology: 2x4
  2. Wenden Sie das Manifest an:

    envsubst < tpu/ray-cluster.tpu-v5e-singlehost.yaml | kubectl --namespace ${NAMESPACE} apply -f -
    

    Mit dem Befehl envsubst werden die Umgebungsvariablen im Manifest ersetzt.

GKE erstellt eine benutzerdefinierte RayCluster-Ressource mit einem workergroup, das einen TPU v5e-Einzelhost in einer 2x4-Topologie enthält.

Mistral-7B

Erstellen Sie die benutzerdefinierte RayCluster-Ressource, um das Mistral-7B-Modell bereitzustellen. Gehen Sie dazu so vor:

  1. Prüfen Sie das ray-cluster.tpu-v5e-singlehost.yaml-Manifest:

    apiVersion: ray.io/v1
    kind: RayCluster
    metadata:
      name: vllm-tpu
    spec:
      headGroupSpec:
        rayStartParams: {}
        template:
          metadata:
            annotations:
              gke-gcsfuse/volumes: "true"
              gke-gcsfuse/cpu-limit: "0"
              gke-gcsfuse/memory-limit: "0"
              gke-gcsfuse/ephemeral-storage-limit: "0"
          spec:
            serviceAccountName: $KSA_NAME
            containers:
              - name: ray-head
                image: $VLLM_IMAGE
                imagePullPolicy: IfNotPresent
                resources:
                  limits:
                    cpu: "2"
                    memory: 8G
                  requests:
                    cpu: "2"
                    memory: 8G
                env:
                  - name: HUGGING_FACE_HUB_TOKEN
                    valueFrom:
                      secretKeyRef:
                        name: hf-secret
                        key: hf_api_token
                  - name: VLLM_XLA_CACHE_PATH
                    value: "/data"
                ports:
                  - containerPort: 6379
                    name: gcs
                  - containerPort: 8265
                    name: dashboard
                  - containerPort: 10001
                    name: client
                  - containerPort: 8000
                    name: serve
                  - containerPort: 8471
                    name: slicebuilder
                  - containerPort: 8081
                    name: mxla
                volumeMounts:
                - name: gcs-fuse-csi-ephemeral
                  mountPath: /data
                - name: dshm
                  mountPath: /dev/shm
            volumes:
            - name: gke-gcsfuse-cache
              emptyDir:
                medium: Memory
            - name: dshm
              emptyDir:
                medium: Memory
            - name: gcs-fuse-csi-ephemeral
              csi:
                driver: gcsfuse.csi.storage.gke.io
                volumeAttributes:
                  bucketName: $GSBUCKET
                  mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
      workerGroupSpecs:
      - groupName: tpu-group
        replicas: 1
        minReplicas: 1
        maxReplicas: 1
        numOfHosts: 1
        rayStartParams: {}
        template:
          metadata:
            annotations:
              gke-gcsfuse/volumes: "true"
              gke-gcsfuse/cpu-limit: "0"
              gke-gcsfuse/memory-limit: "0"
              gke-gcsfuse/ephemeral-storage-limit: "0"
          spec:
            serviceAccountName: $KSA_NAME
            containers:
              - name: ray-worker
                image: $VLLM_IMAGE
                imagePullPolicy: IfNotPresent
                resources:
                  limits:
                    cpu: "100"
                    google.com/tpu: "8"
                    ephemeral-storage: 40G
                    memory: 200G
                  requests:
                    cpu: "100"
                    google.com/tpu: "8"
                    ephemeral-storage: 40G
                    memory: 200G
                env:
                  - name: VLLM_XLA_CACHE_PATH
                    value: "/data"
                  - name: HUGGING_FACE_HUB_TOKEN
                    valueFrom:
                      secretKeyRef:
                        name: hf-secret
                        key: hf_api_token
                volumeMounts:
                - name: gcs-fuse-csi-ephemeral
                  mountPath: /data
                - name: dshm
                  mountPath: /dev/shm
            volumes:
            - name: gke-gcsfuse-cache
              emptyDir:
                medium: Memory
            - name: dshm
              emptyDir:
                medium: Memory
            - name: gcs-fuse-csi-ephemeral
              csi:
                driver: gcsfuse.csi.storage.gke.io
                volumeAttributes:
                  bucketName: $GSBUCKET
                  mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
            nodeSelector:
              cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
              cloud.google.com/gke-tpu-topology: 2x4
  2. Wenden Sie das Manifest an:

    envsubst < tpu/ray-cluster.tpu-v5e-singlehost.yaml | kubectl --namespace ${NAMESPACE} apply -f -
    

    Mit dem Befehl envsubst werden die Umgebungsvariablen im Manifest ersetzt.

GKE erstellt eine benutzerdefinierte RayCluster-Ressource mit einem workergroup, das einen TPU v5e-Einzelhost in einer 2x4-Topologie enthält.

Llama 3.1 70B

Erstellen Sie die benutzerdefinierte RayCluster-Ressource, um das Modell Llama 3.1 70B bereitzustellen. Führen Sie dazu die folgenden Schritte aus:

  1. Prüfen Sie das ray-cluster.tpu-v6e-singlehost.yaml-Manifest:

    apiVersion: ray.io/v1
    kind: RayCluster
    metadata:
      name: vllm-tpu
    spec:
      headGroupSpec:
        rayStartParams: {}
        template:
          metadata:
            annotations:
              gke-gcsfuse/volumes: "true"
              gke-gcsfuse/cpu-limit: "0"
              gke-gcsfuse/memory-limit: "0"
              gke-gcsfuse/ephemeral-storage-limit: "0"
          spec:
            serviceAccountName: $KSA_NAME
            containers:
              - name: ray-head
                image: $VLLM_IMAGE
                imagePullPolicy: IfNotPresent
                resources:
                  limits:
                    cpu: "2"
                    memory: 8G
                  requests:
                    cpu: "2"
                    memory: 8G
                env:
                  - name: HUGGING_FACE_HUB_TOKEN
                    valueFrom:
                      secretKeyRef:
                        name: hf-secret
                        key: hf_api_token
                  - name: VLLM_XLA_CACHE_PATH
                    value: "/data"
                ports:
                  - containerPort: 6379
                    name: gcs
                  - containerPort: 8265
                    name: dashboard
                  - containerPort: 10001
                    name: client
                  - containerPort: 8000
                    name: serve
                  - containerPort: 8471
                    name: slicebuilder
                  - containerPort: 8081
                    name: mxla
                volumeMounts:
                - name: gcs-fuse-csi-ephemeral
                  mountPath: /data
                - name: dshm
                  mountPath: /dev/shm
            volumes:
            - name: gke-gcsfuse-cache
              emptyDir:
                medium: Memory
            - name: dshm
              emptyDir:
                medium: Memory
            - name: gcs-fuse-csi-ephemeral
              csi:
                driver: gcsfuse.csi.storage.gke.io
                volumeAttributes:
                  bucketName: $GSBUCKET
                  mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
      workerGroupSpecs:
      - groupName: tpu-group
        replicas: 1
        minReplicas: 1
        maxReplicas: 1
        numOfHosts: 1
        rayStartParams: {}
        template:
          metadata:
            annotations:
              gke-gcsfuse/volumes: "true"
              gke-gcsfuse/cpu-limit: "0"
              gke-gcsfuse/memory-limit: "0"
              gke-gcsfuse/ephemeral-storage-limit: "0"
          spec:
            serviceAccountName: $KSA_NAME
            containers:
              - name: ray-worker
                image: $VLLM_IMAGE
                imagePullPolicy: IfNotPresent
                resources:
                  limits:
                    cpu: "100"
                    google.com/tpu: "8"
                    ephemeral-storage: 40G
                    memory: 200G
                  requests:
                    cpu: "100"
                    google.com/tpu: "8"
                    ephemeral-storage: 40G
                    memory: 200G
                env:
                  - name: HUGGING_FACE_HUB_TOKEN
                    valueFrom:
                      secretKeyRef:
                        name: hf-secret
                        key: hf_api_token
                  - name: VLLM_XLA_CACHE_PATH
                    value: "/data"
                volumeMounts:
                - name: gcs-fuse-csi-ephemeral
                  mountPath: /data
                - name: dshm
                  mountPath: /dev/shm
            volumes:
            - name: gke-gcsfuse-cache
              emptyDir:
                medium: Memory
            - name: dshm
              emptyDir:
                medium: Memory
            - name: gcs-fuse-csi-ephemeral
              csi:
                driver: gcsfuse.csi.storage.gke.io
                volumeAttributes:
                  bucketName: $GSBUCKET
                  mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
            nodeSelector:
              cloud.google.com/gke-tpu-accelerator: tpu-v6e-slice
              cloud.google.com/gke-tpu-topology: 2x4
  2. Wenden Sie das Manifest an:

    envsubst < tpu/ray-cluster.tpu-v6e-singlehost.yaml | kubectl --namespace ${NAMESPACE} apply -f -
    

    Mit dem Befehl envsubst werden die Umgebungsvariablen im Manifest ersetzt.

GKE erstellt eine benutzerdefinierte RayCluster-Ressource mit einem workergroup, das einen TPU v6e-Einzelhost in einer 2x4-Topologie enthält.

Verbindung zur benutzerdefinierten RayCluster-Ressource herstellen

Nachdem die benutzerdefinierte RayCluster-Ressource erstellt wurde, können Sie eine Verbindung zur RayCluster-Ressource herstellen und mit der Bereitstellung des Modells beginnen.

  1. Prüfen Sie, ob GKE den RayCluster-Dienst erstellt hat:

    kubectl --namespace ${NAMESPACE} get raycluster/vllm-tpu \
        --output wide
    

    Die Ausgabe sieht etwa so aus:

    NAME       DESIRED WORKERS   AVAILABLE WORKERS   CPUS   MEMORY   GPUS   TPUS   STATUS   AGE   HEAD POD IP      HEAD SERVICE IP
    vllm-tpu   1                 1                   ###    ###G     0      8      ready    ###   ###.###.###.###  ###.###.###.###
    

    Warten Sie, bis STATUS den Wert ready hat und in den Spalten HEAD POD IP und HEAD SERVICE IP eine IP-Adresse angezeigt wird.

  2. Stellen Sie port-forwarding-Sitzungen zum Ray-Head her:

    pkill -f "kubectl .* port-forward .* 8265:8265"
    pkill -f "kubectl .* port-forward .* 10001:10001"
    kubectl --namespace ${NAMESPACE} port-forward service/${SERVICE_NAME} 8265:8265 2>&1 >/dev/null &
    kubectl --namespace ${NAMESPACE} port-forward service/${SERVICE_NAME} 10001:10001 2>&1 >/dev/null &
    
  3. Prüfen Sie, ob der Ray-Client eine Verbindung zur benutzerdefinierten Remote-RayCluster-Ressource herstellen kann:

    docker run --net=host -it ${VLLM_IMAGE} \
    ray list nodes --address http://localhost:8265
    

    Die Ausgabe sieht etwa so aus:

    ======== List: YYYY-MM-DD HH:MM:SS.NNNNNN ========
    Stats:
    ------------------------------
    Total: 2
    
    Table:
    ------------------------------
        NODE_ID    NODE_IP          IS_HEAD_NODE  STATE    STATE_MESSAGE    NODE_NAME          RESOURCES_TOTAL                   LABELS
    0  XXXXXXXXXX  ###.###.###.###  True          ALIVE                     ###.###.###.###    CPU: 2.0                          ray.io/node_id: XXXXXXXXXX
                                                                                               memory: #.### GiB
                                                                                               node:###.###.###.###: 1.0
                                                                                               node:__internal_head__: 1.0
                                                                                               object_store_memory: #.### GiB
    1  XXXXXXXXXX  ###.###.###.###  False         ALIVE                     ###.###.###.###    CPU: 100.0                       ray.io/node_id: XXXXXXXXXX
                                                                                               TPU: 8.0
                                                                                               TPU-v#e-8-head: 1.0
                                                                                               accelerator_type:TPU-V#E: 1.0
                                                                                               memory: ###.### GiB
                                                                                               node:###.###.###.###: 1.0
                                                                                               object_store_memory: ##.### GiB
                                                                                               tpu-group-0: 1.0
    

Modell mit vLLM bereitstellen

Modell mit vLLM bereitstellen:

Llama-3-8B-Instruct

docker run \
    --env MODEL_ID=${MODEL_ID} \
    --net=host \
    --volume=./tpu:/workspace/vllm/tpu \
    -it \
    ${VLLM_IMAGE} \
    serve run serve_tpu:model \
    --address=ray://localhost:10001 \
    --app-dir=./tpu \
    --runtime-env-json='{"env_vars": {"MODEL_ID": "meta-llama/Meta-Llama-3-8B-Instruct"}}'

Mistral-7B

docker run \
    --env MODEL_ID=${MODEL_ID} \
    --env TOKENIZER_MODE=${TOKENIZER_MODE} \
    --net=host \
    --volume=./tpu:/workspace/vllm/tpu \
    -it \
    ${VLLM_IMAGE} \
    serve run serve_tpu:model \
    --address=ray://localhost:10001 \
    --app-dir=./tpu \
    --runtime-env-json='{"env_vars": {"MODEL_ID": "mistralai/Mistral-7B-Instruct-v0.3", "TOKENIZER_MODE": "mistral"}}'

Llama 3.1 70B

docker run \
    --env MAX_MODEL_LEN=${MAX_MODEL_LEN} \
    --env MODEL_ID=${MODEL_ID} \
    --net=host \
    --volume=./tpu:/workspace/vllm/tpu \
    -it \
    ${VLLM_IMAGE} \
    serve run serve_tpu:model \
    --address=ray://localhost:10001 \
    --app-dir=./tpu \
    --runtime-env-json='{"env_vars": {"MAX_MODEL_LEN": "8192", "MODEL_ID": "meta-llama/Meta-Llama-3.1-70B"}}'

Ray-Dashboard aufrufen

Sie können Ihre Ray Serve-Bereitstellung und relevante Logs im Ray-Dashboard aufrufen.

  1. Klicken Sie oben rechts in der Cloud Shell-Taskleiste auf die Schaltfläche Symbol für Webvorschau Webvorschau.
  2. Klicken Sie auf Port ändern und legen Sie die Portnummer auf 8265 fest.
  3. Klicken Sie auf Ändern und Vorschau.
  4. Klicken Sie im Ray-Dashboard auf den Tab Bereitstellen.

Sobald die Bereitstellung des Dienstes den Status HEALTHY hat, kann das Modell mit der Verarbeitung von Eingaben beginnen.

Modell bereitstellen

In diesem Leitfaden werden Modelle vorgestellt, die die Textgenerierung unterstützen. Mit dieser Technik lassen sich Textinhalte aus einem Prompt erstellen.

Llama-3-8B-Instruct

  1. Richten Sie die Portweiterleitung an den Server ein:

    pkill -f "kubectl .* port-forward .* 8000:8000"
    kubectl --namespace ${NAMESPACE} port-forward service/${SERVICE_NAME} 8000:8000 2>&1 >/dev/null &
    
  2. Senden Sie einen Prompt an den Serve-Endpunkt:

    curl -X POST http://localhost:8000/v1/generate -H "Content-Type: application/json" -d '{"prompt": "What are the top 5 most popular programming languages? Be brief.", "max_tokens": 1024}'
    

Mistral-7B

  1. Richten Sie die Portweiterleitung an den Server ein:

    pkill -f "kubectl .* port-forward .* 8000:8000"
    kubectl --namespace ${NAMESPACE} port-forward service/${SERVICE_NAME} 8000:8000 2>&1 >/dev/null &
    
  2. Senden Sie einen Prompt an den Serve-Endpunkt:

    curl -X POST http://localhost:8000/v1/generate -H "Content-Type: application/json" -d '{"prompt": "What are the top 5 most popular programming languages? Be brief.", "max_tokens": 1024}'
    

Llama 3.1 70B

  1. Richten Sie die Portweiterleitung an den Server ein:

    pkill -f "kubectl .* port-forward .* 8000:8000"
    kubectl --namespace ${NAMESPACE} port-forward service/${SERVICE_NAME} 8000:8000 2>&1 >/dev/null &
    
  2. Senden Sie einen Prompt an den Serve-Endpunkt:

    curl -X POST http://localhost:8000/v1/generate -H "Content-Type: application/json" -d '{"prompt": "What are the top 5 most popular programming languages? Be brief.", "max_tokens": 1024}'
    

Zusätzliche Konfiguration

Optional können Sie die folgenden Ressourcen und Techniken für die Modellbereitstellung konfigurieren, die vom Ray Serve-Framework unterstützt werden:

RayService bereitstellen

Sie können dieselben Modelle aus dieser Anleitung mit einer benutzerdefinierten RayService-Ressource bereitstellen.

  1. Löschen Sie die benutzerdefinierte RayCluster-Ressource, die Sie in dieser Anleitung erstellt haben:

    kubectl --namespace ${NAMESPACE} delete raycluster/vllm-tpu
    
  2. Erstellen Sie die benutzerdefinierte RayService-Ressource, um ein Modell bereitzustellen:

    Llama-3-8B-Instruct

    1. Prüfen Sie das ray-service.tpu-v5e-singlehost.yaml-Manifest:

      apiVersion: ray.io/v1
      kind: RayService
      metadata:
        name: vllm-tpu
      spec:
        serveConfigV2: |
          applications:
            - name: llm
              import_path: ai-ml.gke-ray.rayserve.llm.tpu.serve_tpu:model
              deployments:
              - name: VLLMDeployment
                num_replicas: 1
              runtime_env:
                working_dir: "https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/archive/main.zip"
                env_vars:
                  MODEL_ID: "$MODEL_ID"
                  MAX_MODEL_LEN: "$MAX_MODEL_LEN"
                  DTYPE: "$DTYPE"
                  TOKENIZER_MODE: "$TOKENIZER_MODE"
                  TPU_CHIPS: "8"
        rayClusterConfig:
          headGroupSpec:
            rayStartParams: {}
            template:
              metadata:
                annotations:
                  gke-gcsfuse/volumes: "true"
                  gke-gcsfuse/cpu-limit: "0"
                  gke-gcsfuse/memory-limit: "0"
                  gke-gcsfuse/ephemeral-storage-limit: "0"
              spec:
                serviceAccountName: $KSA_NAME
                containers:
                - name: ray-head
                  image: $VLLM_IMAGE
                  imagePullPolicy: IfNotPresent
                  ports:
                  - containerPort: 6379
                    name: gcs
                  - containerPort: 8265
                    name: dashboard
                  - containerPort: 10001
                    name: client
                  - containerPort: 8000
                    name: serve
                  env:
                  - name: HUGGING_FACE_HUB_TOKEN
                    valueFrom:
                      secretKeyRef:
                        name: hf-secret
                        key: hf_api_token
                  - name: VLLM_XLA_CACHE_PATH
                    value: "/data"
                  resources:
                    limits:
                      cpu: "2"
                      memory: 8G
                    requests:
                      cpu: "2"
                      memory: 8G
                  volumeMounts:
                  - name: gcs-fuse-csi-ephemeral
                    mountPath: /data
                  - name: dshm
                    mountPath: /dev/shm
                volumes:
                - name: gke-gcsfuse-cache
                  emptyDir:
                    medium: Memory
                - name: dshm
                  emptyDir:
                    medium: Memory
                - name: gcs-fuse-csi-ephemeral
                  csi:
                    driver: gcsfuse.csi.storage.gke.io
                    volumeAttributes:
                      bucketName: $GSBUCKET
                      mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
          workerGroupSpecs:
          - groupName: tpu-group
            replicas: 1
            minReplicas: 1
            maxReplicas: 1
            numOfHosts: 1
            rayStartParams: {}
            template:
              metadata:
                annotations:
                  gke-gcsfuse/volumes: "true"
                  gke-gcsfuse/cpu-limit: "0"
                  gke-gcsfuse/memory-limit: "0"
                  gke-gcsfuse/ephemeral-storage-limit: "0"
              spec:
                serviceAccountName: $KSA_NAME
                containers:
                  - name: ray-worker
                    image: $VLLM_IMAGE
                    imagePullPolicy: IfNotPresent
                    resources:
                      limits:
                        cpu: "100"
                        google.com/tpu: "8"
                        ephemeral-storage: 40G
                        memory: 200G
                      requests:
                        cpu: "100"
                        google.com/tpu: "8"
                        ephemeral-storage: 40G
                        memory: 200G
                    env:
                      - name: JAX_PLATFORMS
                        value: "tpu"
                      - name: HUGGING_FACE_HUB_TOKEN
                        valueFrom:
                          secretKeyRef:
                            name: hf-secret
                            key: hf_api_token
                      - name: VLLM_XLA_CACHE_PATH
                        value: "/data"
                    volumeMounts:
                    - name: gcs-fuse-csi-ephemeral
                      mountPath: /data
                    - name: dshm
                      mountPath: /dev/shm
                volumes:
                - name: gke-gcsfuse-cache
                  emptyDir:
                    medium: Memory
                - name: dshm
                  emptyDir:
                    medium: Memory
                - name: gcs-fuse-csi-ephemeral
                  csi:
                    driver: gcsfuse.csi.storage.gke.io
                    volumeAttributes:
                      bucketName: $GSBUCKET
                      mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
                nodeSelector:
                  cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
                  cloud.google.com/gke-tpu-topology: 2x4
    2. Wenden Sie das Manifest an:

      envsubst < tpu/ray-service.tpu-v5e-singlehost.yaml | kubectl --namespace ${NAMESPACE} apply -f -
      

      Mit dem Befehl envsubst werden die Umgebungsvariablen im Manifest ersetzt.

      GKE erstellt einen RayService mit einem workergroup, der einen TPU v5e-Einzelhost in einer 2x4-Topologie enthält.

    Mistral-7B

    1. Prüfen Sie das ray-service.tpu-v5e-singlehost.yaml-Manifest:

      apiVersion: ray.io/v1
      kind: RayService
      metadata:
        name: vllm-tpu
      spec:
        serveConfigV2: |
          applications:
            - name: llm
              import_path: ai-ml.gke-ray.rayserve.llm.tpu.serve_tpu:model
              deployments:
              - name: VLLMDeployment
                num_replicas: 1
              runtime_env:
                working_dir: "https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/archive/main.zip"
                env_vars:
                  MODEL_ID: "$MODEL_ID"
                  MAX_MODEL_LEN: "$MAX_MODEL_LEN"
                  DTYPE: "$DTYPE"
                  TOKENIZER_MODE: "$TOKENIZER_MODE"
                  TPU_CHIPS: "8"
        rayClusterConfig:
          headGroupSpec:
            rayStartParams: {}
            template:
              metadata:
                annotations:
                  gke-gcsfuse/volumes: "true"
                  gke-gcsfuse/cpu-limit: "0"
                  gke-gcsfuse/memory-limit: "0"
                  gke-gcsfuse/ephemeral-storage-limit: "0"
              spec:
                serviceAccountName: $KSA_NAME
                containers:
                - name: ray-head
                  image: $VLLM_IMAGE
                  imagePullPolicy: IfNotPresent
                  ports:
                  - containerPort: 6379
                    name: gcs
                  - containerPort: 8265
                    name: dashboard
                  - containerPort: 10001
                    name: client
                  - containerPort: 8000
                    name: serve
                  env:
                  - name: HUGGING_FACE_HUB_TOKEN
                    valueFrom:
                      secretKeyRef:
                        name: hf-secret
                        key: hf_api_token
                  - name: VLLM_XLA_CACHE_PATH
                    value: "/data"
                  resources:
                    limits:
                      cpu: "2"
                      memory: 8G
                    requests:
                      cpu: "2"
                      memory: 8G
                  volumeMounts:
                  - name: gcs-fuse-csi-ephemeral
                    mountPath: /data
                  - name: dshm
                    mountPath: /dev/shm
                volumes:
                - name: gke-gcsfuse-cache
                  emptyDir:
                    medium: Memory
                - name: dshm
                  emptyDir:
                    medium: Memory
                - name: gcs-fuse-csi-ephemeral
                  csi:
                    driver: gcsfuse.csi.storage.gke.io
                    volumeAttributes:
                      bucketName: $GSBUCKET
                      mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
          workerGroupSpecs:
          - groupName: tpu-group
            replicas: 1
            minReplicas: 1
            maxReplicas: 1
            numOfHosts: 1
            rayStartParams: {}
            template:
              metadata:
                annotations:
                  gke-gcsfuse/volumes: "true"
                  gke-gcsfuse/cpu-limit: "0"
                  gke-gcsfuse/memory-limit: "0"
                  gke-gcsfuse/ephemeral-storage-limit: "0"
              spec:
                serviceAccountName: $KSA_NAME
                containers:
                  - name: ray-worker
                    image: $VLLM_IMAGE
                    imagePullPolicy: IfNotPresent
                    resources:
                      limits:
                        cpu: "100"
                        google.com/tpu: "8"
                        ephemeral-storage: 40G
                        memory: 200G
                      requests:
                        cpu: "100"
                        google.com/tpu: "8"
                        ephemeral-storage: 40G
                        memory: 200G
                    env:
                      - name: JAX_PLATFORMS
                        value: "tpu"
                      - name: HUGGING_FACE_HUB_TOKEN
                        valueFrom:
                          secretKeyRef:
                            name: hf-secret
                            key: hf_api_token
                      - name: VLLM_XLA_CACHE_PATH
                        value: "/data"
                    volumeMounts:
                    - name: gcs-fuse-csi-ephemeral
                      mountPath: /data
                    - name: dshm
                      mountPath: /dev/shm
                volumes:
                - name: gke-gcsfuse-cache
                  emptyDir:
                    medium: Memory
                - name: dshm
                  emptyDir:
                    medium: Memory
                - name: gcs-fuse-csi-ephemeral
                  csi:
                    driver: gcsfuse.csi.storage.gke.io
                    volumeAttributes:
                      bucketName: $GSBUCKET
                      mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
                nodeSelector:
                  cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
                  cloud.google.com/gke-tpu-topology: 2x4
    2. Wenden Sie das Manifest an:

      envsubst < tpu/ray-service.tpu-v5e-singlehost.yaml | kubectl --namespace ${NAMESPACE} apply -f -
      

      Mit dem Befehl envsubst werden die Umgebungsvariablen im Manifest ersetzt.

      GKE erstellt einen RayService mit einem workergroup, der einen TPU v5e-Einzelhost in einer 2x4-Topologie enthält.

    Llama 3.1 70B

    1. Prüfen Sie das ray-service.tpu-v6e-singlehost.yaml-Manifest:

      apiVersion: ray.io/v1
      kind: RayService
      metadata:
        name: vllm-tpu
      spec:
        serveConfigV2: |
          applications:
            - name: llm
              import_path: ai-ml.gke-ray.rayserve.llm.tpu.serve_tpu:model
              deployments:
              - name: VLLMDeployment
                num_replicas: 1
              runtime_env:
                working_dir: "https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/archive/main.zip"
                env_vars:
                  MODEL_ID: "$MODEL_ID"
                  MAX_MODEL_LEN: "$MAX_MODEL_LEN"
                  DTYPE: "$DTYPE"
                  TOKENIZER_MODE: "$TOKENIZER_MODE"
                  TPU_CHIPS: "8"
        rayClusterConfig:
          headGroupSpec:
            rayStartParams: {}
            template:
              metadata:
                annotations:
                  gke-gcsfuse/volumes: "true"
                  gke-gcsfuse/cpu-limit: "0"
                  gke-gcsfuse/memory-limit: "0"
                  gke-gcsfuse/ephemeral-storage-limit: "0"
              spec:
                serviceAccountName: $KSA_NAME
                containers:
                - name: ray-head
                  image: $VLLM_IMAGE
                  imagePullPolicy: IfNotPresent
                  ports:
                  - containerPort: 6379
                    name: gcs
                  - containerPort: 8265
                    name: dashboard
                  - containerPort: 10001
                    name: client
                  - containerPort: 8000
                    name: serve
                  env:
                  - name: HUGGING_FACE_HUB_TOKEN
                    valueFrom:
                      secretKeyRef:
                        name: hf-secret
                        key: hf_api_token
                  - name: VLLM_XLA_CACHE_PATH
                    value: "/data"
                  resources:
                    limits:
                      cpu: "2"
                      memory: 8G
                    requests:
                      cpu: "2"
                      memory: 8G
                  volumeMounts:
                  - name: gcs-fuse-csi-ephemeral
                    mountPath: /data
                  - name: dshm
                    mountPath: /dev/shm
                volumes:
                - name: gke-gcsfuse-cache
                  emptyDir:
                    medium: Memory
                - name: dshm
                  emptyDir:
                    medium: Memory
                - name: gcs-fuse-csi-ephemeral
                  csi:
                    driver: gcsfuse.csi.storage.gke.io
                    volumeAttributes:
                      bucketName: $GSBUCKET
                      mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
          workerGroupSpecs:
          - groupName: tpu-group
            replicas: 1
            minReplicas: 1
            maxReplicas: 1
            numOfHosts: 1
            rayStartParams: {}
            template:
              metadata:
                annotations:
                  gke-gcsfuse/volumes: "true"
                  gke-gcsfuse/cpu-limit: "0"
                  gke-gcsfuse/memory-limit: "0"
                  gke-gcsfuse/ephemeral-storage-limit: "0"
              spec:
                serviceAccountName: $KSA_NAME
                containers:
                  - name: ray-worker
                    image: $VLLM_IMAGE
                    imagePullPolicy: IfNotPresent
                    resources:
                      limits:
                        cpu: "100"
                        google.com/tpu: "8"
                        ephemeral-storage: 40G
                        memory: 200G
                      requests:
                        cpu: "100"
                        google.com/tpu: "8"
                        ephemeral-storage: 40G
                        memory: 200G
                    env:
                      - name: JAX_PLATFORMS
                        value: "tpu"
                      - name: HUGGING_FACE_HUB_TOKEN
                        valueFrom:
                          secretKeyRef:
                            name: hf-secret
                            key: hf_api_token
                      - name: VLLM_XLA_CACHE_PATH
                        value: "/data"
                    volumeMounts:
                    - name: gcs-fuse-csi-ephemeral
                      mountPath: /data
                    - name: dshm
                      mountPath: /dev/shm
                volumes:
                - name: gke-gcsfuse-cache
                  emptyDir:
                    medium: Memory
                - name: dshm
                  emptyDir:
                    medium: Memory
                - name: gcs-fuse-csi-ephemeral
                  csi:
                    driver: gcsfuse.csi.storage.gke.io
                    volumeAttributes:
                      bucketName: $GSBUCKET
                      mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
                nodeSelector:
                  cloud.google.com/gke-tpu-accelerator: tpu-v6e-slice
                  cloud.google.com/gke-tpu-topology: 2x4
    2. Wenden Sie das Manifest an:

      envsubst < tpu/ray-service.tpu-v6e-singlehost.yaml | kubectl --namespace ${NAMESPACE} apply -f -
      

      Mit dem Befehl envsubst werden die Umgebungsvariablen im Manifest ersetzt.

    GKE erstellt eine benutzerdefinierte RayCluster-Ressource, in der die Ray Serve-Anwendung bereitgestellt wird, und die nachfolgende benutzerdefinierte RayService-Ressource wird erstellt.

  3. Prüfen Sie den Status der RayService-Ressource:

    kubectl --namespace ${NAMESPACE} get rayservices/vllm-tpu
    

    Warten Sie, bis sich der Dienststatus in Running ändert:

    NAME       SERVICE STATUS   NUM SERVE ENDPOINTS
    vllm-tpu   Running          1
    
  4. Rufen Sie den Namen des Head-Dienstes des RayCluster ab:

    SERVICE_NAME=$(kubectl --namespace=${NAMESPACE} get rayservices/vllm-tpu \
        --template={{.status.activeServiceStatus.rayClusterStatus.head.serviceName}})
    
  5. Stellen Sie port-forwarding-Sitzungen zum Ray-Head her, um das Ray-Dashboard aufzurufen:

    pkill -f "kubectl .* port-forward .* 8265:8265"
    kubectl --namespace ${NAMESPACE} port-forward service/${SERVICE_NAME} 8265:8265 2>&1 >/dev/null &
    
  6. Ray-Dashboard aufrufen

  7. Modell bereitstellen.

  8. Bereinigen Sie die RayService-Ressource:

    kubectl --namespace ${NAMESPACE} delete rayservice/vllm-tpu
    

Mehrere Modelle mit der Modellkomposition zusammenführen

Bei der Modellkomposition werden mehrere Modelle zu einer einzigen Anwendung zusammengefasst.

In diesem Abschnitt verwenden Sie einen GKE-Cluster, um zwei Modelle, Llama 3 8B IT und Gemma 7B IT, in einer einzigen Anwendung zusammenzufassen:

  • Das erste Modell ist das Assistant-Modell, das Fragen beantwortet, die im Prompt gestellt werden.
  • Das zweite Modell ist das Zusammenfassungsmodell. Die Ausgabe des Assistant-Modells wird an die Eingabe des Zusammenfassungsmodells angehängt. Das Endergebnis ist die zusammengefasste Version der Antwort des Assistant-Modells.
  1. So erhalten Sie Zugriff auf das Gemma-Modell:

    1. Melden Sie sich in der Kaggle-Plattform an, unterzeichnen Sie die Lizenz-Einwilligungsvereinbarung und rufen Sie ein Kaggle API-Token ab. In dieser Anleitung verwenden Sie ein Kubernetes Secret für die Kaggle-Anmeldedaten.
    2. Rufen Sie die Seite zur Modelleinwilligung auf Kaggle.com auf.
    3. Melden Sie sich bei Kaggle an, falls Sie dies noch nicht getan haben.
    4. Klicken Sie auf Zugriffsanfrage.
    5. Wählen Sie im Abschnitt Konto zur Einwilligung die Option Über Kaggle-Konto verifizieren aus, um Ihr Kaggle-Konto für das Erteilen der Einwilligung zu verwenden.
    6. Akzeptieren Sie die Nutzungsbedingungen des Modells.
  2. Umgebung einrichten:

    export ASSIST_MODEL_ID=meta-llama/Meta-Llama-3-8B-Instruct
    export SUMMARIZER_MODEL_ID=google/gemma-7b-it
    
  3. Erstellen Sie für Standardcluster einen zusätzlichen TPU-Slice-Knotenpool mit einem Host:

    gcloud container node-pools create tpu-2 \
      --location=${COMPUTE_ZONE} \
      --cluster=${CLUSTER_NAME} \
      --machine-type=MACHINE_TYPE \
      --num-nodes=1
    

    Ersetzen Sie MACHINE_TYPE durch einen der folgenden Maschinentypen:

    • ct5lp-hightpu-8t, um TPU v5e bereitzustellen.
    • ct6e-standard-8t zum Bereitstellen von TPU v6e.

    In Autopilot-Clustern werden die erforderlichen Knoten automatisch bereitgestellt.

  4. Stellen Sie die RayService-Ressource basierend auf der TPU-Version bereit, die Sie verwenden möchten:

    TPU v5e

    1. Prüfen Sie das ray-service.tpu-v5e-singlehost.yaml-Manifest:

      apiVersion: ray.io/v1
      kind: RayService
      metadata:
        name: vllm-tpu
      spec:
        serveConfigV2: |
          applications:
          - name: llm
            route_prefix: /
            import_path:  ai-ml.gke-ray.rayserve.llm.model-composition.serve_tpu:multi_model
            deployments:
            - name: MultiModelDeployment
              num_replicas: 1
            runtime_env:
              working_dir: "https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/archive/main.zip"
              env_vars:
                ASSIST_MODEL_ID: "$ASSIST_MODEL_ID"
                SUMMARIZER_MODEL_ID: "$SUMMARIZER_MODEL_ID"
                TPU_CHIPS: "16"
                TPU_HEADS: "2"
        rayClusterConfig:
          headGroupSpec:
            rayStartParams: {}
            template:
              metadata:
                annotations:
                  gke-gcsfuse/volumes: "true"
                  gke-gcsfuse/cpu-limit: "0"
                  gke-gcsfuse/memory-limit: "0"
                  gke-gcsfuse/ephemeral-storage-limit: "0"
              spec:
                serviceAccountName: $KSA_NAME
                containers:
                - name: ray-head
                  image: $VLLM_IMAGE
                  resources:
                    limits:
                      cpu: "2"
                      memory: 8G
                    requests:
                      cpu: "2"
                      memory: 8G
                  ports:
                  - containerPort: 6379
                    name: gcs-server
                  - containerPort: 8265
                    name: dashboard
                  - containerPort: 10001
                    name: client
                  - containerPort: 8000
                    name: serve
                  env:
                    - name: HUGGING_FACE_HUB_TOKEN
                      valueFrom:
                        secretKeyRef:
                          name: hf-secret
                          key: hf_api_token
                    - name: VLLM_XLA_CACHE_PATH
                      value: "/data"
                  volumeMounts:
                  - name: gcs-fuse-csi-ephemeral
                    mountPath: /data
                  - name: dshm
                    mountPath: /dev/shm
                volumes:
                - name: gke-gcsfuse-cache
                  emptyDir:
                    medium: Memory
                - name: dshm
                  emptyDir:
                    medium: Memory
                - name: gcs-fuse-csi-ephemeral
                  csi:
                    driver: gcsfuse.csi.storage.gke.io
                    volumeAttributes:
                      bucketName: $GSBUCKET
                      mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
          workerGroupSpecs:
          - replicas: 2
            minReplicas: 1
            maxReplicas: 2
            numOfHosts: 1
            groupName: tpu-group
            rayStartParams: {}
            template:
              metadata:
                annotations:
                  gke-gcsfuse/volumes: "true"
                  gke-gcsfuse/cpu-limit: "0"
                  gke-gcsfuse/memory-limit: "0"
                  gke-gcsfuse/ephemeral-storage-limit: "0"
              spec:
                serviceAccountName: $KSA_NAME
                containers:
                - name: llm
                  image: $VLLM_IMAGE
                  env:
                    - name: HUGGING_FACE_HUB_TOKEN
                      valueFrom:
                        secretKeyRef:
                          name: hf-secret
                          key: hf_api_token
                    - name: VLLM_XLA_CACHE_PATH
                      value: "/data"
                  resources:
                    limits:
                      cpu: "100"
                      google.com/tpu: "8"
                      ephemeral-storage: 40G
                      memory: 200G
                    requests:
                      cpu: "100"
                      google.com/tpu: "8"
                      ephemeral-storage: 40G
                      memory: 200G
                  volumeMounts:
                  - name: gcs-fuse-csi-ephemeral
                    mountPath: /data
                  - name: dshm
                    mountPath: /dev/shm
                volumes:
                - name: gke-gcsfuse-cache
                  emptyDir:
                    medium: Memory
                - name: dshm
                  emptyDir:
                    medium: Memory
                - name: gcs-fuse-csi-ephemeral
                  csi:
                    driver: gcsfuse.csi.storage.gke.io
                    volumeAttributes:
                      bucketName: $GSBUCKET
                      mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
                nodeSelector:
                  cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
                  cloud.google.com/gke-tpu-topology: 2x4
    2. Wenden Sie das Manifest an:

      envsubst < model-composition/ray-service.tpu-v5e-singlehost.yaml | kubectl --namespace ${NAMESPACE} apply -f -
      

    TPU v6e

    1. Prüfen Sie das ray-service.tpu-v6e-singlehost.yaml-Manifest:

      apiVersion: ray.io/v1
      kind: RayService
      metadata:
        name: vllm-tpu
      spec:
        serveConfigV2: |
          applications:
          - name: llm
            route_prefix: /
            import_path:  ai-ml.gke-ray.rayserve.llm.model-composition.serve_tpu:multi_model
            deployments:
            - name: MultiModelDeployment
              num_replicas: 1
            runtime_env:
              working_dir: "https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/archive/main.zip"
              env_vars:
                ASSIST_MODEL_ID: "$ASSIST_MODEL_ID"
                SUMMARIZER_MODEL_ID: "$SUMMARIZER_MODEL_ID"
                TPU_CHIPS: "16"
                TPU_HEADS: "2"
        rayClusterConfig:
          headGroupSpec:
            rayStartParams: {}
            template:
              metadata:
                annotations:
                  gke-gcsfuse/volumes: "true"
                  gke-gcsfuse/cpu-limit: "0"
                  gke-gcsfuse/memory-limit: "0"
                  gke-gcsfuse/ephemeral-storage-limit: "0"
              spec:
                serviceAccountName: $KSA_NAME
                containers:
                - name: ray-head
                  image: $VLLM_IMAGE
                  resources:
                    limits:
                      cpu: "2"
                      memory: 8G
                    requests:
                      cpu: "2"
                      memory: 8G
                  ports:
                  - containerPort: 6379
                    name: gcs-server
                  - containerPort: 8265
                    name: dashboard
                  - containerPort: 10001
                    name: client
                  - containerPort: 8000
                    name: serve
                  env:
                    - name: HUGGING_FACE_HUB_TOKEN
                      valueFrom:
                        secretKeyRef:
                          name: hf-secret
                          key: hf_api_token
                    - name: VLLM_XLA_CACHE_PATH
                      value: "/data"
                  volumeMounts:
                  - name: gcs-fuse-csi-ephemeral
                    mountPath: /data
                  - name: dshm
                    mountPath: /dev/shm
                volumes:
                - name: gke-gcsfuse-cache
                  emptyDir:
                    medium: Memory
                - name: dshm
                  emptyDir:
                    medium: Memory
                - name: gcs-fuse-csi-ephemeral
                  csi:
                    driver: gcsfuse.csi.storage.gke.io
                    volumeAttributes:
                      bucketName: $GSBUCKET
                      mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
          workerGroupSpecs:
          - replicas: 2
            minReplicas: 1
            maxReplicas: 2
            numOfHosts: 1
            groupName: tpu-group
            rayStartParams: {}
            template:
              metadata:
                annotations:
                  gke-gcsfuse/volumes: "true"
                  gke-gcsfuse/cpu-limit: "0"
                  gke-gcsfuse/memory-limit: "0"
                  gke-gcsfuse/ephemeral-storage-limit: "0"
              spec:
                serviceAccountName: $KSA_NAME
                containers:
                - name: llm
                  image: $VLLM_IMAGE
                  env:
                    - name: HUGGING_FACE_HUB_TOKEN
                      valueFrom:
                        secretKeyRef:
                          name: hf-secret
                          key: hf_api_token
                    - name: VLLM_XLA_CACHE_PATH
                      value: "/data"
                  resources:
                    limits:
                      cpu: "100"
                      google.com/tpu: "8"
                      ephemeral-storage: 40G
                      memory: 200G
                    requests:
                      cpu: "100"
                      google.com/tpu: "8"
                      ephemeral-storage: 40G
                      memory: 200G
                  volumeMounts:
                  - name: gcs-fuse-csi-ephemeral
                    mountPath: /data
                  - name: dshm
                    mountPath: /dev/shm
                volumes:
                - name: gke-gcsfuse-cache
                  emptyDir:
                    medium: Memory
                - name: dshm
                  emptyDir:
                    medium: Memory
                - name: gcs-fuse-csi-ephemeral
                  csi:
                    driver: gcsfuse.csi.storage.gke.io
                    volumeAttributes:
                      bucketName: $GSBUCKET
                      mountOptions: "implicit-dirs,file-cache:enable-parallel-downloads:true,file-cache:parallel-downloads-per-file:100,file-cache:max-parallel-downloads:-1,file-cache:download-chunk-size-mb:10,file-cache:max-size-mb:-1"
                nodeSelector:
                  cloud.google.com/gke-tpu-accelerator: tpu-v6e-slice
                  cloud.google.com/gke-tpu-topology: 2x4
    2. Wenden Sie das Manifest an:

      envsubst < model-composition/ray-service.tpu-v6e-singlehost.yaml | kubectl --namespace ${NAMESPACE} apply -f -
      
  5. Warten Sie, bis sich der Status der RayService-Ressource in Running ändert:

    kubectl --namespace ${NAMESPACE} get rayservice/vllm-tpu
    

    Die Ausgabe sieht etwa so aus:

    NAME       SERVICE STATUS   NUM SERVE ENDPOINTS
    vllm-tpu   Running          2
    

    In dieser Ausgabe gibt der Status RUNNING an, dass die RayService-Ressource bereit ist.

  6. Prüfen Sie, ob GKE den Dienst für die Ray Serve-Anwendung erstellt hat:

    kubectl --namespace ${NAMESPACE} get service/vllm-tpu-serve-svc
    

    Die Ausgabe sieht etwa so aus:

    NAME                 TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)    AGE
    vllm-tpu-serve-svc   ClusterIP   ###.###.###.###   <none>        8000/TCP   ###
    
  7. Stellen Sie port-forwarding-Sitzungen zum Ray-Head her:

    pkill -f "kubectl .* port-forward .* 8265:8265"
    pkill -f "kubectl .* port-forward .* 8000:8000"
    kubectl --namespace ${NAMESPACE} port-forward service/vllm-tpu-serve-svc 8265:8265 2>&1 >/dev/null &
    kubectl --namespace ${NAMESPACE} port-forward service/vllm-tpu-serve-svc 8000:8000 2>&1 >/dev/null &
    
  8. Senden Sie eine Anfrage an das Modell:

    curl -X POST http://localhost:8000/ -H "Content-Type: application/json" -d '{"prompt": "What is the most popular programming language for machine learning and why?", "max_tokens": 1000}'
    

    Die Ausgabe sieht etwa so aus:

      {"text": [" used in various data science projects, including building machine learning models, preprocessing data, and visualizing results.\n\nSure, here is a single sentence summarizing the text:\n\nPython is the most popular programming language for machine learning and is widely used in data science projects, encompassing model building, data preprocessing, and visualization."]}
    

TPU-Image erstellen und bereitstellen

In dieser Anleitung werden gehostete TPU-Images von vLLM verwendet. vLLM bietet ein Dockerfile.tpu-Image, das vLLM auf dem erforderlichen PyTorch XLA-Image mit TPU-Abhängigkeiten aufbaut. Sie können aber auch Ihr eigenes TPU-Image erstellen und bereitstellen, um mehr Kontrolle über den Inhalt Ihres Docker-Images zu haben.

  1. Erstellen Sie ein Docker-Repository zum Speichern der Container-Images für diese Anleitung:

    gcloud artifacts repositories create vllm-tpu --repository-format=docker --location=${COMPUTE_REGION} && \
    gcloud auth configure-docker ${COMPUTE_REGION}-docker.pkg.dev
    
  2. Klonen Sie das vLLM-Repository:

    git clone https://github.com/vllm-project/vllm.git
    cd vllm
    
  3. Erstellen Sie das Image:

    docker build -f ./docker/Dockerfile.tpu . -t vllm-tpu
    
  4. Taggen Sie das TPU-Image mit Ihrem Artifact Registry-Namen:

    export VLLM_IMAGE=${COMPUTE_REGION}-docker.pkg.dev/${PROJECT_ID}/vllm-tpu/vllm-tpu:TAG
    docker tag vllm-tpu ${VLLM_IMAGE}
    

    Ersetzen Sie TAG durch den Namen des Tags, das Sie definieren möchten. Wenn Sie kein Tag angeben, wendet Docker das Standard-Tag „latest“ an.

  5. Übertragen Sie das Image per Push an Artifact Registry.

    docker push ${VLLM_IMAGE}
    

Einzelne Ressourcen löschen

Wenn Sie ein vorhandenes Projekt verwendet haben und es nicht löschen möchten, können Sie die einzelnen Ressourcen löschen.

  1. Löschen Sie die benutzerdefinierte RayCluster-Ressource:

    kubectl --namespace ${NAMESPACE} delete rayclusters vllm-tpu
    
  2. Löschen Sie den Cloud Storage-Bucket:

    gcloud storage rm -r gs://${GSBUCKET}
    
  3. Löschen Sie das Artifact Registry-Repository:

    gcloud artifacts repositories delete vllm-tpu \
        --location=${COMPUTE_REGION}
    
  4. Löschen Sie den Cluster:

    gcloud container clusters delete ${CLUSTER_NAME} \
        --location=LOCATION
    

    Ersetzen Sie LOCATION durch eine der folgenden Umgebungsvariablen:

    • Verwenden Sie für Autopilot-Cluster COMPUTE_REGION.
    • Verwenden Sie für Standardcluster COMPUTE_ZONE.

Projekt löschen

Wenn Sie die Anleitung in einem neuen Google Cloud -Projekt bereitgestellt haben und das Projekt nicht mehr benötigen, löschen Sie es mit den folgenden Schritten:

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Nächste Schritte