Servir un LLM en GPUs L4 con Ray

En esta guía se muestra cómo usar modelos de lenguaje extensos (LLMs) con Ray y el complemento Ray Operator en Google Kubernetes Engine (GKE). El framework Ray proporciona una plataforma integral de IA y aprendizaje automático para entrenar, ajustar y realizar inferencias de cargas de trabajo de aprendizaje automático. Ray Serve es un framework de Ray que puedes usar para servir LLMs populares de Hugging Face.

Antes de leer esta guía, asegúrate de que conoces el modelo que quieres usar en este tutorial. Puedes publicar cualquiera de los siguientes modelos:

Esta página está dirigida a ingenieros de aprendizaje automático (ML), administradores y operadores de plataformas que facilitan las cargas de trabajo de ML. Para obtener más información sobre los roles habituales y las tareas de ejemplo a las que hacemos referencia en el contenido de Google Cloud , consulta Roles y tareas de usuario habituales de GKE.

En esta guía se explican los siguientes pasos:

  1. Crea un clúster de Autopilot o Estándar de GKE con el complemento Ray Operator habilitado.
  2. Despliega un recurso RayService que descarga y sirve un modelo de lenguaje extenso (LLM) de Hugging Face.
  3. Despliega una interfaz de chat y un diálogo con LLMs.

Antes de empezar

Antes de empezar, asegúrate de que has realizado las siguientes tareas:

  • Habilita la API de Google Kubernetes Engine.
  • Habilitar la API de Google Kubernetes Engine
  • Si quieres usar Google Cloud CLI para esta tarea, instálala y, a continuación, inicialízala. Si ya has instalado la gcloud CLI, obtén la versión más reciente ejecutando gcloud components update.
  • Crea una cuenta de Hugging Face si aún no tienes una.
  • Asegúrate de tener un token de Hugging Face.
  • Asegúrate de que tienes acceso al modelo de Hugging Face que quieras usar. Normalmente, se concede firmando un contrato y solicitando acceso al propietario del modelo en la página del modelo de Hugging Face.
  • Asegúrate de tener cuota de GPU en la región us-central1. Para obtener más información, consulta Cuota de GPU.

Prepara tu entorno

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

  2. Clona el repositorio de muestra:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git
    cd kubernetes-engine-samples/ai-ml/gke-ray/rayserve/llm
    export TUTORIAL_HOME=`pwd`
    
  3. Define las variables de entorno predeterminadas:

    gcloud config set project PROJECT_ID
    export PROJECT_ID=$(gcloud config get project)
    export COMPUTE_REGION=us-central1
    export CLUSTER_VERSION=CLUSTER_VERSION
    export HF_TOKEN=HUGGING_FACE_TOKEN
    

    Haz los cambios siguientes:

    • PROJECT_ID: tu Google Cloud ID de proyecto.
    • CLUSTER_VERSION: la versión de GKE que se va a usar. Debe ser 1.30.1 o posterior.
    • HUGGING_FACE_TOKEN: tu token de acceso de Hugging Face.

Crear un clúster con un grupo de nodos de GPU

Puedes servir un LLM en GPUs L4 con Ray en un clúster de GKE Autopilot o Estándar mediante el complemento Ray Operator. Por lo general, recomendamos que uses un clúster de Autopilot para disfrutar de una experiencia de Kubernetes totalmente gestionada. Elige un clúster estándar si tu caso práctico requiere una alta escalabilidad o si quieres tener más control sobre la configuración del clúster. Para elegir el modo de funcionamiento de GKE que mejor se adapte a tus cargas de trabajo, consulta Elegir un modo de funcionamiento de GKE.

Usa Cloud Shell para crear un clúster de Autopilot o Estándar:

Autopilot

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

gcloud container clusters create-auto rayserve-cluster \
    --enable-ray-operator \
    --cluster-version=${CLUSTER_VERSION} \
    --location=${COMPUTE_REGION}

Estándar

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

gcloud container clusters create rayserve-cluster \
    --addons=RayOperator \
    --cluster-version=${CLUSTER_VERSION} \
    --machine-type=g2-standard-24 \
    --location=${COMPUTE_ZONE} \
    --num-nodes=2 \
    --accelerator type=nvidia-l4,count=2,gpu-driver-version=latest

Crear un secreto de Kubernetes para las credenciales de Hugging Face

En Cloud Shell, crea un secreto de Kubernetes haciendo lo siguiente:

  1. Configura kubectl para que se comunique con tu clúster:

    gcloud container clusters get-credentials ${CLUSTER_NAME} --location=${COMPUTE_REGION}
    
  2. Crea un secreto de Kubernetes que contenga el token de Hugging Face:

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

Desplegar el modelo LLM

El repositorio de GitHub que has clonado tiene un directorio para cada modelo que incluye una configuración de RayService. La configuración de cada modelo incluye los siguientes componentes:

  • Despliegue de Ray Serve: el despliegue de Ray Serve, que incluye la configuración de recursos y las dependencias del tiempo de ejecución.
  • Modelo: el ID del modelo de Hugging Face.
  • Clúster de Ray: el clúster de Ray subyacente y los recursos necesarios para cada componente, incluidos los pods de head y de trabajador.

Gemma 2B IT

  1. Despliega el modelo:

    kubectl apply -f gemma-2b-it/
    
  2. Espera a que el recurso RayService esté listo:

    kubectl get rayservice gemma-2b-it -o yaml
    

    El resultado debería ser similar al siguiente:

    status:
      activeServiceStatus:
        applicationStatuses:
          llm:
            healthLastUpdateTime: "2024-06-22T02:51:52Z"
            serveDeploymentStatuses:
              VLLMDeployment:
                healthLastUpdateTime: "2024-06-22T02:51:52Z"
                status: HEALTHY
            status: RUNNING
    

    En este resultado, status: RUNNING indica que el recurso RayService está listo.

  3. Confirma que GKE ha creado el servicio para la aplicación Ray Serve:

    kubectl get service gemma-2b-it-serve-svc
    

    El resultado debería ser similar al siguiente:

    NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    gemma-2b-it-serve-svc   ClusterIP   34.118.226.104   <none>        8000/TCP   45m
    

Gemma 7B IT

  1. Despliega el modelo:

    kubectl apply -f gemma-7b-it/
    
  2. Espera a que el recurso RayService esté listo:

    kubectl get rayservice gemma-7b-it -o yaml
    

    El resultado debería ser similar al siguiente:

    status:
      activeServiceStatus:
        applicationStatuses:
          llm:
            healthLastUpdateTime: "2024-06-22T02:51:52Z"
            serveDeploymentStatuses:
              VLLMDeployment:
                healthLastUpdateTime: "2024-06-22T02:51:52Z"
                status: HEALTHY
            status: RUNNING
    

    En este resultado, status: RUNNING indica que el recurso RayService está listo.

  3. Confirma que GKE ha creado el servicio para la aplicación Ray Serve:

    kubectl get service gemma-7b-it-serve-svc
    

    El resultado debería ser similar al siguiente:

    NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    gemma-7b-it-serve-svc   ClusterIP   34.118.226.104   <none>        8000/TCP   45m
    

Llama 2 7B

  1. Despliega el modelo:

    kubectl apply -f llama-2-7b/
    
  2. Espera a que el recurso RayService esté listo:

    kubectl get rayservice llama-2-7b -o yaml
    

    El resultado debería ser similar al siguiente:

    status:
      activeServiceStatus:
        applicationStatuses:
          llm:
            healthLastUpdateTime: "2024-06-22T02:51:52Z"
            serveDeploymentStatuses:
              VLLMDeployment:
                healthLastUpdateTime: "2024-06-22T02:51:52Z"
                status: HEALTHY
            status: RUNNING
    

    En este resultado, status: RUNNING indica que el recurso RayService está listo.

  3. Confirma que GKE ha creado el servicio para la aplicación Ray Serve:

    kubectl get service llama-2-7b-serve-svc
    

    El resultado debería ser similar al siguiente:

    NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    llama-2-7b-serve-svc    ClusterIP   34.118.226.104   <none>        8000/TCP   45m
    

Llama 3 8B

  1. Despliega el modelo:

    kubectl apply -f llama-3-8b/
    
  2. Espera a que el recurso RayService esté listo:

    kubectl get rayservice llama-3-8b -o yaml
    

    El resultado debería ser similar al siguiente:

    status:
      activeServiceStatus:
        applicationStatuses:
          llm:
            healthLastUpdateTime: "2024-06-22T02:51:52Z"
            serveDeploymentStatuses:
              VLLMDeployment:
                healthLastUpdateTime: "2024-06-22T02:51:52Z"
                status: HEALTHY
            status: RUNNING
    

    En este resultado, status: RUNNING indica que el recurso RayService está listo.

  3. Confirma que GKE ha creado el servicio para la aplicación Ray Serve:

    kubectl get service llama-3-8b-serve-svc
    

    El resultado debería ser similar al siguiente:

    NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    llama-3-8b-serve-svc    ClusterIP   34.118.226.104   <none>        8000/TCP   45m
    

Mistral 7B

  1. Despliega el modelo:

    kubectl apply -f mistral-7b/
    
  2. Espera a que el recurso RayService esté listo:

    kubectl get rayservice mistral-7b -o yaml
    

    El resultado debería ser similar al siguiente:

    status:
      activeServiceStatus:
        applicationStatuses:
          llm:
            healthLastUpdateTime: "2024-06-22T02:51:52Z"
            serveDeploymentStatuses:
              VLLMDeployment:
                healthLastUpdateTime: "2024-06-22T02:51:52Z"
                status: HEALTHY
            status: RUNNING
    

    En este resultado, status: RUNNING indica que el recurso RayService está listo.

  3. Confirma que GKE ha creado el servicio para la aplicación Ray Serve:

    kubectl get service mistral-7b-serve-svc
    

    El resultado debería ser similar al siguiente:

    NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    mistral-7b-serve-svc    ClusterIP   34.118.226.104   <none>        8000/TCP   45m
    

Aplicar el modelo

Los modelos Llama 2 7B y Llama 3 8B usan la especificación de chat de la API de OpenAI. Los demás modelos solo admiten la generación de texto, que es una técnica que genera texto a partir de una petición.

Configurar la redirección de puertos

Configura la redirección de puertos al servidor de inferencias:

Gemma 2B IT

kubectl port-forward svc/gemma-2b-it-serve-svc 8000:8000

Gemma 7B IT

kubectl port-forward svc/gemma-7b-it-serve-svc 8000:8000

Llama2 7B

kubectl port-forward svc/llama-7b-serve-svc 8000:8000

Llama 3 8B

kubectl port-forward svc/llama-3-8b-serve-svc 8000:8000

Mistral 7B

kubectl port-forward svc/mistral-7b-serve-svc 8000:8000

Interactuar con el modelo mediante curl

Usa curl para chatear con tu modelo:

Gemma 2B IT

En una nueva sesión de terminal:

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

Gemma 7B IT

En una nueva sesión de terminal:

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

Llama2 7B

En una nueva sesión de terminal:

curl http://localhost:8000/v1/chat/completions     -H "Content-Type: application/json"     -d '{
      "model": "meta-llama/Llama-2-7b-chat-hf",
      "messages": [
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "What are the top 5 most popular programming languages? Please be brief."}
      ],
      "temperature": 0.7
    }'

Llama 3 8B

En una nueva sesión de terminal:

curl http://localhost:8000/v1/chat/completions     -H "Content-Type: application/json"     -d '{
      "model": "meta-llama/Meta-Llama-3-8B-Instruct",
      "messages": [
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "What are the top 5 most popular programming languages? Please be brief."}
      ],
      "temperature": 0.7
    }'

Mistral 7B

En una nueva sesión de terminal:

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

Como los modelos que has publicado no conservan ningún historial, cada mensaje y respuesta deben enviarse de nuevo al modelo para crear una experiencia de diálogo interactiva. En el siguiente ejemplo se muestra cómo puedes crear un diálogo interactivo con el modelo Llama 3 8B:

Crea un diálogo con el modelo mediante curl:

curl http://localhost:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
      "model": "meta-llama/Meta-Llama-3-8B-Instruct",
      "messages": [
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "What are the top 5 most popular programming languages? Please be brief."},
        {"role": "assistant", "content": " \n1. Java\n2. Python\n3. C++\n4. C#\n5. JavaScript"},
        {"role": "user", "content": "Can you give me a brief description?"}
      ],
      "temperature": 0.7
}'

El resultado debería ser similar al siguiente:

{
  "id": "cmpl-3cb18c16406644d291e93fff65d16e41",
  "object": "chat.completion",
  "created": 1719035491,
  "model": "meta-llama/Meta-Llama-3-8B-Instruct",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Here's a brief description of each:\n\n1. **Java**: A versatile language for building enterprise-level applications, Android apps, and web applications.\n2. **Python**: A popular language for data science, machine learning, web development, and scripting, known for its simplicity and ease of use.\n3. **C++**: A high-performance language for building operating systems, games, and other high-performance applications, with a focus on efficiency and control.\n4. **C#**: A modern, object-oriented language for building Windows desktop and mobile applications, as well as web applications using .NET.\n5. **JavaScript**: A versatile language for client-side scripting on the web, commonly used for creating interactive web pages, web applications, and mobile apps.\n\nNote: These descriptions are brief and don't do justice to the full capabilities and uses of each language."
      },
      "logprobs": null,
      "finish_reason": "stop",
      "stop_reason": null
    }
  ],
  "usage": {
    "prompt_tokens": 73,
    "total_tokens": 245,
    "completion_tokens": 172
  }
}

(Opcional) Conectarse a la interfaz de chat

Puedes usar Gradio para crear aplicaciones web que te permitan interactuar con tu modelo. Gradio es una biblioteca de Python que tiene un wrapper ChatInterface que crea interfaces de usuario para chatbots. En el caso de Llama 2 7B y Llama 3 7B, instalaste Gradio al desplegar el modelo LLM.

  1. Configura la redirección de puertos al servicio gradio:

    kubectl port-forward service/gradio 8080:8080 &
    
  2. Abre http://localhost:8080 en tu navegador para chatear con el modelo.

Servir varios modelos con multiplexación de modelos

Multiplexación de modelos es una técnica que se usa para servir varios modelos en el mismo clúster de Ray. Puedes dirigir el tráfico a modelos específicos mediante encabezados de solicitud o balanceo de carga.

En este ejemplo, crearás una aplicación multiplexada de Ray Serve que consta de dos modelos: Gemma 7B IT y Llama 3 8B.

  1. Despliega el recurso RayService:

    kubectl apply -f model-multiplexing/
    
  2. Espera a que el recurso RayService esté listo:

    kubectl get rayservice model-multiplexing -o yaml
    

    La salida es similar a la siguiente:

    status:
      activeServiceStatus:
        applicationStatuses:
          llm:
            healthLastUpdateTime: "2024-06-22T14:00:41Z"
            serveDeploymentStatuses:
              MutliModelDeployment:
                healthLastUpdateTime: "2024-06-22T14:00:41Z"
                status: HEALTHY
              VLLMDeployment:
                healthLastUpdateTime: "2024-06-22T14:00:41Z"
                status: HEALTHY
              VLLMDeployment_1:
                healthLastUpdateTime: "2024-06-22T14:00:41Z"
                status: HEALTHY
            status: RUNNING
    

    En este resultado, status: RUNNING indica que el recurso RayService está listo.

  3. Confirma que GKE ha creado el servicio de Kubernetes para la aplicación Ray Serve:

    kubectl get service model-multiplexing-serve-svc
    

    El resultado debería ser similar al siguiente:

    NAME                           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    model-multiplexing-serve-svc   ClusterIP   34.118.226.104   <none>        8000/TCP   45m
    
  4. Configura la redirección de puertos a la aplicación Ray Serve:

    kubectl port-forward svc/model-multiplexing-serve-svc 8000:8000
    
  5. Envía una solicitud al modelo de TI de Gemma 7B:

    curl -X POST http://localhost:8000/ -H "Content-Type: application/json" --header "serve_multiplexed_model_id: google/gemma-7b-it" -d '{"prompt": "What are the top 5 most popular programming languages? Please be brief.", "max_tokens": 200}'
    

    El resultado debería ser similar al siguiente:

    {"text": ["What are the top 5 most popular programming languages? Please be brief.\n\n1. JavaScript\n2. Java\n3. C++\n4. Python\n5. C#"]}
    
  6. Envía una solicitud al modelo Llama 3 8B:

    curl -X POST http://localhost:8000/ -H "Content-Type: application/json" --header "serve_multiplexed_model_id: meta-llama/Meta-Llama-3-8B-Instruct" -d '{"prompt": "What are the top 5 most popular programming languages? Please be brief.", "max_tokens": 200}'
    

    El resultado debería ser similar al siguiente:

    {"text": ["What are the top 5 most popular programming languages? Please be brief. Here are your top 5 most popular programming languages, based on the TIOBE Index, a widely used measure of the popularity of programming languages.\r\n\r\n1. **Java**: Used in Android app development, web development, and enterprise software development.\r\n2. **Python**: A versatile language used in data science, machine learning, web development, and automation.\r\n3. **C++**: A high-performance language used in game development, system programming, and high-performance computing.\r\n4. **C#**: Used in Windows and web application development, game development, and enterprise software development.\r\n5. **JavaScript**: Used in web development, mobile app development, and server-side programming with technologies like Node.js.\r\n\r\nSource: TIOBE Index (2022).\r\n\r\nThese rankings can vary depending on the source and methodology used, but this gives you a general idea of the most popular programming languages."]}
    
  7. Envía una solicitud a un modelo aleatorio excluyendo el encabezado serve_multiplexed_model_id:

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

    El resultado es uno de los resultados de los pasos anteriores.

Crear varios modelos con la composición de modelos

La composición de modelos es una técnica que se usa para combinar varios modelos en una sola aplicación. La composición de modelos te permite encadenar entradas y salidas en varios LLMs y escalar tus modelos como una sola aplicación.

En este ejemplo, vas a combinar dos modelos, Gemma 7B IT y Llama 3 8B, en una sola aplicación. El primer modelo es el modelo de asistente que responde a las preguntas proporcionadas en la petición. El segundo modelo es el modelo de resumen. La salida del modelo del 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. Despliega el recurso RayService:

    kubectl apply -f model-composition/
    
  2. Espera a que el recurso RayService esté listo:

    kubectl get rayservice model-composition -o yaml
    

    La salida es similar a la siguiente:

    status:
      activeServiceStatus:
        applicationStatuses:
          llm:
            healthLastUpdateTime: "2024-06-22T14:00:41Z"
            serveDeploymentStatuses:
              MutliModelDeployment:
                healthLastUpdateTime: "2024-06-22T14:00:41Z"
                status: HEALTHY
              VLLMDeployment:
                healthLastUpdateTime: "2024-06-22T14:00:41Z"
                status: HEALTHY
              VLLMDeployment_1:
                healthLastUpdateTime: "2024-06-22T14:00:41Z"
                status: HEALTHY
            status: RUNNING
    

    En este resultado, status: RUNNING indica que el recurso RayService está listo.

  3. Confirma que GKE ha creado el servicio para la aplicación Ray Serve:

    kubectl get service model-composition-serve-svc
    

    El resultado debería ser similar al siguiente:

    NAME                           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    model-composition-serve-svc    ClusterIP   34.118.226.104   <none>        8000/TCP   45m
    
  4. 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}'
    
  5. El resultado debería ser similar al siguiente:

    {"text": ["\n\n**Sure, here is a summary in a single sentence:**\n\nThe most popular programming language for machine learning is Python due to its ease of use, extensive libraries, and growing community."]}
    

Eliminar el proyecto

  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.

Eliminar los recursos concretos

Si has usado un proyecto que ya existía y no quieres eliminarlo, puedes eliminar los recursos concretos.

  1. Elimina el clúster:

    gcloud container clusters delete rayserve-cluster
    

Siguientes pasos