Entrega un LLM con TPU en GKE con KubeRay


En este instructivo, se muestra cómo entregar un modelo de lenguaje grande (LLM) con unidades de procesamiento tensorial (TPU) en Google Kubernetes Engine (GKE) con el complemento Ray Operator y el framework de entrega vLLM.

En este instructivo, puedes entregar modelos de LLM en TPU v5e o TPU Trillium (v6e) de la siguiente manera:

Esta guía está dirigida a clientes de IA generativa, usuarios nuevos y existentes de GKE, ingenieros de AA, ingenieros de MLOps (DevOps) o administradores de plataformas interesados en usar las capacidades de organización de contenedores de Kubernetes para entregar modelos con Ray en TPU con vLLM.

Fondo

En esta sección, se describen las tecnologías clave que se usan en este instructivo.

Servicio de Kubernetes administrado por GKE

Google Cloud ofrece una amplia gama de servicios, incluido GKE, que es adecuado para implementar y administrar cargas de trabajo de IA/AA. GKE es un servicio administrado de Kubernetes que simplifica la implementación, el escalamiento y la administración de aplicaciones alojadas en contenedores. GKE proporciona la infraestructura necesaria, incluidos recursos escalables, computación distribuida y redes eficientes, para controlar las demandas computacionales de los LLMs.

Para obtener más información sobre los conceptos clave de Kubernetes, consulta Comienza a aprender sobre Kubernetes. Para obtener más información sobre GKE y cómo te ayuda a escalar, automatizar y administrar Kubernetes, consulta la Descripción general de GKE.

Operador de Ray

El complemento de Ray Operator en GKE proporciona una plataforma de IA/AA de extremo a extremo para la entrega, el entrenamiento y el ajuste de cargas de trabajo de aprendizaje automático. En este instructivo, usarás Ray Serve, un framework en Ray, para entregar LLM populares de Hugging Face.

TPU

Las TPU son circuitos integrados personalizados específicos de aplicaciones (ASIC) de Google que se usan para acelerar el aprendizaje automático y los modelos de IA compilados con frameworks como el siguiente:TensorFlow, PyTorch yJAX.

En este instructivo, se explica cómo publicar modelos de LLM en nodos de TPU v5e o TPU Trillium (v6e) con topologías de TPU configuradas según los requisitos de cada modelo para publicar mensajes con baja latencia.

vLLM

vLLM es un framework de entrega de LLM de código abierto altamente optimizado que puede aumentar la capacidad de procesamiento de entrega en TPU, con funciones como las siguientes:

  • Implementación optimizada de transformadores con PagedAttention
  • Agrupación en lotes continua para mejorar la capacidad de procesamiento general de la entrega
  • Paralelismo de tensor y entrega distribuida en varias GPUs

Para obtener más información, consulta la documentación de vLLM.

Objetivos

En este instructivo, se abarcan los siguientes pasos:

  1. Crear un clúster de GKE con un grupo de nodos TPU
  2. Implementa un recurso personalizado de RayCluster con una porción de TPU de host único. GKE implementa el recurso personalizado RayCluster como Pods de Kubernetes.
  3. Entrega un LLM.
  4. Interactuar con los modelos

De forma opcional, puedes configurar los siguientes recursos y técnicas de entrega de modelos que admite el framework de Ray Serve:

  • Implementa un recurso personalizado de RayService.
  • Crea varios modelos con la composición de modelos.

Antes de comenzar

Antes de comenzar, asegúrate de haber realizado las siguientes tareas:

  • Habilita la API de Google Kubernetes Engine.
  • Habilitar la API de Google Kubernetes Engine
  • Si deseas usar Google Cloud CLI para esta tarea, instala y, luego, inicializa gcloud CLI. Si ya instalaste gcloud CLI, ejecuta gcloud components update para obtener la versión más reciente.
  • Crea una cuenta de Hugging Face, si todavía no la tienes.
  • Asegúrate de tener un token de Hugging Face.
  • Asegúrate de tener acceso al modelo de Hugging Face que deseas usar. Por lo general, se otorga mediante la firma de un acuerdo y la solicitud de acceso al propietario del modelo en la página del modelo de Hugging Face.
  • Asegúrate de tener las siguientes funciones de IAM:
    • roles/container.admin
    • roles/iam.serviceAccountAdmin
    • roles/container.clusterAdmin
    • roles/artifactregistry.writer

Prepara el entorno

  1. Verifica que tengas suficiente cuota en tu proyecto Google Cloud para una TPU v5e de host único o una TPU Trillium (v6e) de host único. Para administrar tu cuota, consulta Cuotas de TPU.

  2. En la Google Cloud consola, inicia una instancia de Cloud Shell:
    Abrir Cloud Shell

  3. Clona el repositorio de ejemplo:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git cd kubernetes-engine-samples 
  4. Navega hasta el directorio de trabajo:

    cd ai-ml/gke-ray/rayserve/llm 
  5. Establece las variables de entorno predeterminadas para la creación del clúster de GKE:

    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 

    Reemplaza lo siguiente:

    • HUGGING_FACE_TOKEN: Tu token de acceso de Hugging Face.
    • REGION: Es la región en la que tienes cuota de TPU. Asegúrate de que la versión de TPU que quieres usar esté disponible en esta región. Para obtener más información, consulta la disponibilidad de TPU en GKE.
    • ZONE: Es la zona con la cuota de TPU disponible.
    • VLLM_IMAGE: Es la imagen de TPU de vLLM. Puedes usar la imagen pública docker.io/vllm/vllm-tpu:866fa4550d572f4ff3521ccf503e0df2e76591a1 o compilar tu propia imagen de TPU.

    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 

    Reemplaza lo siguiente:

    • HUGGING_FACE_TOKEN: Tu token de acceso de Hugging Face.
    • REGION: Es la región en la que tienes cuota de TPU. Asegúrate de que la versión de TPU que quieres usar esté disponible en esta región. Para obtener más información, consulta la disponibilidad de TPU en GKE.
    • ZONE: Es la zona con la cuota de TPU disponible.
    • VLLM_IMAGE: Es la imagen de TPU de vLLM. Puedes usar la imagen pública docker.io/vllm/vllm-tpu:866fa4550d572f4ff3521ccf503e0df2e76591a1 o compilar tu propia imagen de TPU.

    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 

    Reemplaza lo siguiente:

    • HUGGING_FACE_TOKEN: Tu token de acceso de Hugging Face.
    • REGION: Es la región en la que tienes cuota de TPU. Asegúrate de que la versión de TPU que quieres usar esté disponible en esta región. Para obtener más información, consulta la disponibilidad de TPU en GKE.
    • ZONE: Es la zona con la cuota de TPU disponible.
    • VLLM_IMAGE: Es la imagen de TPU de vLLM. Puedes usar la imagen pública docker.io/vllm/vllm-tpu:866fa4550d572f4ff3521ccf503e0df2e76591a1 o compilar tu propia imagen de TPU.
  6. Extrae la imagen del contenedor de vLLM:

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

Crea un clúster

Puedes entregar un LLM en TPU con Ray en un clúster de GKE Autopilot o Standard con el complemento Ray Operator.

Prácticas recomendadas:

Usa un clúster de Autopilot para una experiencia de Kubernetes completamente administrada. Para elegir el modo de operación de GKE que se adapte mejor a tus cargas de trabajo, consulta Elige un modo de operación de GKE.

Usa Cloud Shell para crear un clúster de Autopilot o Standard:

Autopilot

  1. Crea un clúster de GKE Autopilot con el complemento Ray Operator habilitado:

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

Estándar

  1. Crea un clúster estándar con el complemento Ray Operator habilitado:

    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. Crea un grupo de nodos de porción de TPU de host único:

    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 crea un grupo de nodos TPU v5e con un tipo de máquina 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 crea un grupo de nodos TPU v5e con un tipo de máquina 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 crea un grupo de nodos TPU v6e con un tipo de máquina ct6e-standard-8t.

Configura kubectl para comunicarse con tu clúster

Para configurar kubectl para que se comunique con tu clúster, ejecuta el siguiente comando:

Autopilot

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

Estándar

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

Crea un secreto de Kubernetes para las credenciales de Hugging Face

Para crear un Secret de Kubernetes que contenga el token de Hugging Face, ejecuta el siguiente comando:

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

Cree un bucket de Cloud Storage

Para acelerar el tiempo de inicio de la implementación de vLLM y minimizar el espacio en disco requerido por nodo, usa el controlador CSI de Cloud Storage FUSE para activar el modelo descargado y la caché de compilación en los nodos de Ray.

En Cloud Shell, ejecute el siguiente comando:

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

Este comando crea un bucket de Cloud Storage para almacenar los archivos del modelo que descargas de Hugging Face.

Configura una ServiceAccount de Kubernetes para acceder al bucket

  1. Crea la ServiceAccount de Kubernetes:

    kubectl create serviceaccount ${KSA_NAME} \     --namespace ${NAMESPACE} 
  2. Otorga acceso de lectura y escritura a la ServiceAccount de Kubernetes en el bucket de Cloud Storage:

    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 crea los siguientes recursos para el LLM:

    1. Un bucket de Cloud Storage para almacenar el modelo descargado y la caché de compilación Un controlador CSI de Cloud Storage FUSE lee el contenido del bucket.
    2. Volúmenes con el almacenamiento en caché de archivos habilitado y la función de descarga paralela de Cloud Storage FUSE
    Práctica recomendada:

    Usa una caché de archivos respaldada por tmpfs o Hyperdisk / Persistent Disk, según el tamaño esperado del contenido del modelo, por ejemplo, los archivos de pesos. En este instructivo, usarás la caché de archivos de Cloud Storage FUSE respaldada por RAM.

Implementa un recurso personalizado de RayCluster

Implementa un recurso personalizado de RayCluster, que suele constar de un Pod del sistema y varios Pods de trabajo.

Llama-3-8B-Instruct

Para crear el recurso personalizado RayCluster y, así, implementar el modelo Llama 3 8B ajustado para instrucciones, completa los siguientes pasos:

  1. Inspecciona el manifiesto ray-cluster.tpu-v5e-singlehost.yaml:

    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. Aplica el manifiesto

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

    El comando envsubst reemplaza las variables de entorno en el manifiesto.

GKE crea un recurso personalizado RayCluster con un workergroup que contiene un host único de TPU v5e en una topología 2x4.

Mistral-7B

Para crear el recurso personalizado RayCluster y, así, implementar el modelo Mistral-7B, completa los siguientes pasos:

  1. Inspecciona el manifiesto ray-cluster.tpu-v5e-singlehost.yaml:

    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. Aplica el manifiesto

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

    El comando envsubst reemplaza las variables de entorno en el manifiesto.

GKE crea un recurso personalizado RayCluster con un workergroup que contiene un host único de TPU v5e en una topología 2x4.

Llama 3.1 70B

Para crear el recurso personalizado RayCluster y, así, implementar el modelo Llama 3.1 70B, completa los siguientes pasos:

  1. Inspecciona el manifiesto ray-cluster.tpu-v6e-singlehost.yaml:

    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. Aplica el manifiesto

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

    El comando envsubst reemplaza las variables de entorno en el manifiesto.

GKE crea un recurso personalizado de RayCluster con un workergroup que contiene una TPU v6e de host único en una topología 2x4.

Conéctate al recurso personalizado de RayCluster

Después de crear el recurso personalizado de RayCluster, puedes conectarte a él y comenzar a entregar el modelo.

  1. Verifica que GKE haya creado el Service de RayCluster:

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

    El resultado es similar a este:

    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    ###   ###.###.###.###  ###.###.###.### 

    Espera hasta que el STATUS sea ready y las columnas HEAD POD IP y HEAD SERVICE IP tengan una dirección IP.

  2. Establece sesiones de port-forwarding en el encabezado de Ray:

    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. Verifica que el cliente de Ray pueda conectarse al recurso personalizado de RayCluster remoto:

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

    El resultado es similar a este:

    ======== 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 

Implementa el modelo con vLLM

Implementa el modelo con vLLM:

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"}}' 

Visualiza el panel de Ray

Puedes ver tu implementación de Ray Serve y los registros pertinentes desde el panel de Ray.

  1. Haz clic en el botón Ícono de vista previa en la Web Vista previa en la Web, que se encuentra en la parte superior derecha de la barra de tareas de Cloud Shell.
  2. Haz clic en Cambiar puerto y establece el número de puerto en 8265.
  3. Haz clic en Cambiar y obtener vista previa (Change and Preview).
  4. En el panel de Ray, haz clic en la pestaña Serve.

Una vez que la implementación de Serve tenga el estado HEALTHY, el modelo estará listo para comenzar a procesar entradas.

Entrega el modelo

En esta guía, se destacan los modelos que admiten la generación de texto, una técnica que permite crear contenido de texto a partir de una instrucción.

Llama-3-8B-Instruct

  1. Configura la redirección de puertos al servidor:

    pkill -f "kubectl .* port-forward .* 8000:8000" kubectl --namespace ${NAMESPACE} port-forward service/${SERVICE_NAME} 8000:8000 2>&1 >/dev/null & 
  2. Envía una instrucción al extremo de Serve:

    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. Configura la redirección de puertos al servidor:

    pkill -f "kubectl .* port-forward .* 8000:8000" kubectl --namespace ${NAMESPACE} port-forward service/${SERVICE_NAME} 8000:8000 2>&1 >/dev/null & 
  2. Envía una instrucción al extremo de Serve:

    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. Configura la redirección de puertos al servidor:

    pkill -f "kubectl .* port-forward .* 8000:8000" kubectl --namespace ${NAMESPACE} port-forward service/${SERVICE_NAME} 8000:8000 2>&1 >/dev/null & 
  2. Envía una instrucción al extremo de Serve:

    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}' 

Configuración adicional

De forma opcional, puedes configurar los siguientes recursos y técnicas de entrega de modelos que admite el framework de Ray Serve:

Implementa un RayService

Puedes implementar los mismos modelos de este instructivo con un recurso personalizado de RayService.

  1. Borra el recurso personalizado de RayCluster que creaste en este instructivo:

    kubectl --namespace ${NAMESPACE} delete raycluster/vllm-tpu 
  2. Crea el recurso personalizado de RayService para implementar un modelo:

    Llama-3-8B-Instruct

    1. Inspecciona el manifiesto ray-service.tpu-v5e-singlehost.yaml:

      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. Aplica el manifiesto

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

      El comando envsubst reemplaza las variables de entorno en el manifiesto.

      GKE crea un RayService con un workergroup que contiene un host único de TPU v5e en una topología 2x4.

    Mistral-7B

    1. Inspecciona el manifiesto ray-service.tpu-v5e-singlehost.yaml:

      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. Aplica el manifiesto

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

      El comando envsubst reemplaza las variables de entorno en el manifiesto.

      GKE crea un RayService con un workergroup que contiene un host único de TPU v5e en una topología 2x4.

    Llama 3.1 70B

    1. Inspecciona el manifiesto ray-service.tpu-v6e-singlehost.yaml:

      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. Aplica el manifiesto

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

      El comando envsubst reemplaza las variables de entorno en el manifiesto.

    GKE crea un recurso personalizado de RayCluster en el que se implementa la aplicación Ray Serve y se crea el recurso personalizado de RayService posterior.

  3. Verifica el estado del recurso de RayService:

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

    Espera a que el estado del servicio cambie a Running:

    NAME       SERVICE STATUS   NUM SERVE ENDPOINTS vllm-tpu   Running          1 
  4. Recupera el nombre del servicio principal de RayCluster:

    SERVICE_NAME=$(kubectl --namespace=${NAMESPACE} get rayservices/vllm-tpu \     --template={{.status.activeServiceStatus.rayClusterStatus.head.serviceName}}) 
  5. Establece sesiones de port-forwarding en el encabezado de Ray para ver el panel de Ray:

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

  7. Entrega el modelo.

  8. Limpia el recurso RayService:

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

Cómo crear varios modelos con la composición de modelos

La composición de modelos es una técnica para componer varios modelos en una sola aplicación.

En esta sección, usarás un clúster de GKE para componer dos modelos, Llama 3 8B IT y Gemma 7B IT, en una sola aplicación:

  • El primer modelo es el modelo de asistente que responde las preguntas que se hacen en la instrucción.
  • El segundo modelo es el de resumen. El resultado del modelo de asistente se encadena a la entrada del modelo de resumen. El resultado final es la versión resumida de la respuesta del modelo del asistente.
  1. Para acceder al modelo de Gemma, completa los siguientes pasos:

    1. Accede a la plataforma de Kaggle, firma el contrato de consentimiento de licencia y obtén un token de la API de Kaggle. En este instructivo, usas un Secret de Kubernetes para las credenciales de Kaggle.
    2. Accede a la página de consentimiento del modelo en Kaggle.com.
    3. Ingresa en Kaggle si aún no lo has hecho.
    4. Haz clic en Solicitar acceso.
    5. En la sección Elegir cuenta para el consentimiento, selecciona Verificar mediante la cuenta de Kaggle para usar tu cuenta de Kaggle para obtener el consentimiento.
    6. Acepta los Términos y Condiciones del modelo.
  2. Configura tu entorno:

    export ASSIST_MODEL_ID=meta-llama/Meta-Llama-3-8B-Instruct export SUMMARIZER_MODEL_ID=google/gemma-7b-it 
  3. Para los clústeres estándar, crea un grupo de nodos de porción de TPU de host único adicional:

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

    Reemplaza MACHINE_TYPE por cualquiera de los siguientes tipos de máquinas:

    • ct5lp-hightpu-8t para aprovisionar TPU v5e.
    • ct6e-standard-8t para aprovisionar la TPU v6e.

    Los clústeres de Autopilot aprovisionan automáticamente los nodos requeridos.

  4. Implementa el recurso RayService según la versión de TPU que deseas usar:

    TPU v5e

    1. Inspecciona el manifiesto ray-service.tpu-v5e-singlehost.yaml:

      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. Aplica el manifiesto

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

    TPU v6e

    1. Inspecciona el manifiesto ray-service.tpu-v6e-singlehost.yaml:

      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. Aplica el manifiesto

      envsubst < model-composition/ray-service.tpu-v6e-singlehost.yaml | kubectl --namespace ${NAMESPACE} apply -f - 
  5. Espera a que el estado del recurso de RayService cambie a Running:

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

    El resultado es similar a este:

    NAME       SERVICE STATUS   NUM SERVE ENDPOINTS vllm-tpu   Running          2 

    En este resultado, el estado RUNNING indica que el recurso de RayService está listo.

  6. Confirma que GKE haya creado el Service para la aplicación Ray Serve:

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

    El resultado es similar a este:

    NAME                 TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)    AGE vllm-tpu-serve-svc   ClusterIP   ###.###.###.###   <none>        8000/TCP   ### 
  7. Establece sesiones de port-forwarding en el encabezado de Ray:

    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. Envía una solicitud al modelo:

    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}' 

    El resultado es similar a este:

      {"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."]} 

Compila e implementa la imagen de TPU

En este instructivo, se usan imágenes de TPU alojadas de vLLM. vLLM proporciona una imagen de Dockerfile.tpu que compila vLLM sobre la imagen de PyTorch XLA requerida que incluye dependencias de TPU. Sin embargo, también puedes compilar e implementar tu propia imagen de TPU para tener un control más detallado sobre el contenido de tu imagen de Docker.

  1. Crea un repositorio de Docker para almacenar las imágenes de contenedor de esta guía:

    gcloud artifacts repositories create vllm-tpu --repository-format=docker --location=${COMPUTE_REGION} && \ gcloud auth configure-docker ${COMPUTE_REGION}-docker.pkg.dev 
  2. Clona el repositorio de vLLM:

    git clone https://github.com/vllm-project/vllm.git cd vllm 
  3. Compila la imagen:

    docker build -f ./docker/Dockerfile.tpu . -t vllm-tpu 
  4. Etiqueta la imagen de TPU con el nombre de tu registro de Artifact Registry:

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

    Reemplaza TAG por el nombre de la etiqueta que deseas definir. Si no especificas una etiqueta, Docker aplica la etiqueta predeterminada más reciente.

  5. Envía la imagen a Artifact Registry:

    docker push ${VLLM_IMAGE} 

Borra los recursos individuales

Si usaste un proyecto existente y no quieres borrarlo, puedes borrar los recursos individuales.

  1. Borra el recurso personalizado RayCluster:

    kubectl --namespace ${NAMESPACE} delete rayclusters vllm-tpu 
  2. Borra el bucket de Cloud Storage:

    gcloud storage rm -r gs://${GSBUCKET} 
  3. Borra el repositorio de Artifact Registry:

    gcloud artifacts repositories delete vllm-tpu \     --location=${COMPUTE_REGION} 
  4. Borra el clúster:

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

    Reemplaza LOCATION con cualquiera de las siguientes variables de entorno:

    • Para los clústeres de Autopilot, usa COMPUTE_REGION.
    • Para los clústeres de Standard, usa COMPUTE_ZONE.

Borra el proyecto

Si implementaste el instructivo en un proyecto Google Cloud nuevo y ya no lo necesitas, sigue estos pasos para borrarlo:

  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.

¿Qué sigue?