Exibir um LLM em GPUs L4 com Ray


Este guia mostra como disponibilizar modelos de linguagem grandes (LLMs) usando o Ray e o complemento Ray Operator com o Google Kubernetes Engine (GKE).

Neste guia, qualquer um destes modelos pode ser exibido:

Este guia também aborda técnicas de disponibilização de modelos, como multiplexação e composição, que são compatíveis com o framework Ray Serve.

Contexto

O framework do Ray fornece uma plataforma completa de IA/ML para treinamento, treinamento detalhado e inferência de cargas de trabalho de ML. O Ray Serve é um framework no Ray que pode ser usado para disponibilizar LLMs conhecidos do Hugging Face.

O número de GPUs varia de acordo com o formato de dados do modelo. Neste guia, o modelo pode usar uma ou duas GPUs L4.

Abordamos as etapas a seguir:

  1. Crie um cluster do GKE Autopilot ou do Standard com o complemento do operador do Ray ativado.
  2. Implante um recurso do RayService que faz o download e disponibiliza um modelo de linguagem grande (LLM) do Hugging Face.
  3. Implante uma interface de chat e converse com LLMs.

Antes de começar

Antes de começar, verifique se você realizou as tarefas a seguir:

  • Ativar a API Google Kubernetes Engine.
  • Ativar a API Google Kubernetes Engine
  • Se você quiser usar a Google Cloud CLI para essa tarefa, instale e, em seguida, inicialize a CLI gcloud. Se você instalou a CLI gcloud anteriormente, instale a versão mais recente executando gcloud components update.
  • Crie uma conta do Hugging Face caso ainda não tenha uma.
  • Verifique se você tem um token do Hugging Face.
  • Verifique se você tem acesso ao modelo do Hugging Face que quer usar. Isso geralmente é concedido ao assinar um contrato e solicitar acesso ao proprietário do modelo na página do modelo do Hugging Face.
  • Verifique se você tem uma cota de GPU na região us-central1. Para saber mais, consulte Cota de GPU.

Prepare o ambiente

  1. No console do Google Cloud, inicie uma instância do Cloud Shell:
    Abrir o Cloud Shell

  2. Clone o repositório de amostra:

    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. Defina as variáveis de ambiente padrão:

    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
    

    Substitua:

    • PROJECT_ID: seuID de projeto no Google Cloud.
    • CLUSTER_VERSION: a versão do GKE a ser usada. Precisa ser 1.30.1 ou mais recente.
    • HUGGING_FACE_TOKEN: seu token de acesso do Hugging Face.

Criar um cluster com um pool de nós de GPU

É possível disponibilizar um LLM em GPUs L4 com Ray em um cluster do GKE Autopilot ou Standard usando o complemento do Operador do Ray. Recomendamos que você use um cluster do Autopilot para ter uma experiência totalmente gerenciada do Kubernetes. Escolha um cluster Standard se o caso de uso exigir alta escalonabilidade ou se você quiser mais controle sobre a configuração do cluster. Para escolher o modo de operação do GKE mais adequado para suas cargas de trabalho, consulte Escolher um modo de operação do GKE.

Use o Cloud Shell para criar um cluster Autopilot ou Standard:

Autopilot

Crie um cluster Autopilot com o complemento do operador do Ray ativado:

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

Standard

Crie um cluster Standard com o complemento do Operador do Ray ativado:

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

Criar um Secret do Kubernetes para as credenciais do Hugging Face

No Cloud Shell, crie um Secret do Kubernetes assim:

  1. Configure kubectl para se comunicar com o cluster:

    gcloud container clusters get-credentials ${CLUSTER_NAME} --location=${COMPUTE_REGION}
    
  2. Crie um Secret do Kubernetes que contenha o token do Hugging Face:

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

Implantar o modelo LLM

O repositório do GitHub que você clonou tem um diretório para cada modelo que inclui uma configuração do RayService. A configuração de cada modelo inclui os seguintes componentes:

  • Implantação do Ray Serve: a implantação do Ray Serve, que inclui a configuração de recursos e as dependências do ambiente de execução.
  • Modelo: o ID do modelo do Hugging Face.
  • Cluster do Ray: o cluster do Ray e os recursos necessários para cada componente, incluindo pods principais e de worker.

Gemma 2B IT

  1. Implante o modelo:

    kubectl apply -f gemma-2b-it/
    
  2. Aguarde até que o recurso do RayService esteja pronto:

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

    O resultado será assim:

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

    Nesta saída, status: RUNNING indica que o recurso do RayService está pronto.

  3. Confirme se o GKE criou o Serviço para o aplicativo Ray Serve:

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

    O resultado será assim:

    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. Implante o modelo:

    kubectl apply -f gemma-7b-it/
    
  2. Aguarde até que o recurso do RayService esteja pronto:

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

    O resultado será assim:

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

    Nesta saída, status: RUNNING indica que o recurso do RayService está pronto.

  3. Confirme se o GKE criou o Serviço para o aplicativo Ray Serve:

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

    O resultado será assim:

    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. Implante o modelo:

    kubectl apply -f llama-2-7b/
    
  2. Aguarde até que o recurso do RayService esteja pronto:

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

    O resultado será assim:

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

    Nesta saída, status: RUNNING indica que o recurso do RayService está pronto.

  3. Confirme se o GKE criou o Serviço para o aplicativo Ray Serve:

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

    O resultado será assim:

    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. Implante o modelo:

    kubectl apply -f llama-3-8b/
    
  2. Aguarde até que o recurso do RayService esteja pronto:

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

    O resultado será assim:

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

    Nesta saída, status: RUNNING indica que o recurso do RayService está pronto.

  3. Confirme se o GKE criou o Serviço para o aplicativo Ray Serve:

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

    O resultado será assim:

    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. Implante o modelo:

    kubectl apply -f mistral-7b/
    
  2. Aguarde até que o recurso do RayService esteja pronto:

    kubectl get rayservice mistral-7b -o yaml
    

    O resultado será assim:

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

    Nesta saída, status: RUNNING indica que o recurso do RayService está pronto.

  3. Confirme se o GKE criou o Serviço para o aplicativo Ray Serve:

    kubectl get service mistral-7b-serve-svc
    

    O resultado será assim:

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

Disponibilizar o modelo

Os modelos Llama2 7B e Llama3 8B usam a especificação de chat da API OpenAI. Os outros modelos oferecem suporte apenas à geração de texto, que é uma técnica que gera texto com base em comandos.

Configurar o encaminhamento de portas

Configure o encaminhamento de portas para o servidor de inferência:

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

Interagir com o modelo usando curl

Use o curl para conversar com o modelo:

Gemma 2B IT

Em uma nova sessão 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

Em uma nova sessão 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

Em uma nova sessão 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

Em uma nova sessão 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

Em uma nova sessão 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 os modelos que você disponibilizou não retêm nenhum histórico, cada mensagem e resposta precisa ser enviada de volta ao modelo para criar uma experiência de conversa interativa. O exemplo a seguir mostra como criar uma conversa interativa usando o modelo Llama 3 8B:

Crie um diálogo com o modelo usando 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
}'

O resultado será assim:

{
  "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) Conectar-se à interface de chat

É possível usar o Gradio para criar aplicativos da Web que permitam interagir com seu modelo. O Gradio é uma biblioteca Python que tem um wrapper ChatInterface que cria interfaces de usuário para chatbots. Para o Llama 2 7B e o Llama 3 7B, você instalou o Gradio ao implantar o modelo LLM.

  1. Configure o encaminhamento de portas para o Serviço gradio:

    kubectl port-forward service/gradio 8080:8080 &
    
  2. Abra http://localhost:8080 no seu navegador para conversar com o modelo.

Disponibilizar vários modelos com multiplexação de modelos

A multiplexação de modelos é uma técnica usada para disponibilizar vários modelos no mesmo cluster do Ray. É possível rotear o tráfego para modelos específicos usando cabeçalhos de solicitação ou pelo balanceamento de carga.

Neste exemplo, você cria um aplicativo multiplexado do Ray Serve composto por dois modelos: Gemma 7B IT e Llama 3 8B.

  1. Implante o recurso do RayService:

    kubectl apply -f model-multiplexing/
    
  2. Aguarde até que o recurso do RayService esteja pronto:

    kubectl get rayservice model-multiplexing -o yaml
    

    O resultado será assim:

    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
    

    Nesta saída, status: RUNNING indica que o recurso do RayService está pronto.

  3. Confirme se o GKE criou o Serviço do Kubernetes para o aplicativo do Ray Serve:

    kubectl get service model-multiplexing-serve-svc
    

    O resultado será assim:

    NAME                           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    model-multiplexing-serve-svc   ClusterIP   34.118.226.104   <none>        8000/TCP   45m
    
  4. Configure o encaminhamento de portas para o aplicativo do Ray Serve:

    kubectl port-forward svc/model-multiplexing-serve-svc 8000:8000
    
  5. Envie uma solicitação para o modelo de TI do 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}'
    

    O resultado será assim:

    {"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. Envie uma solicitação para o 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}'
    

    O resultado será assim:

    {"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. Envie uma solicitação para um modelo aleatório excluindo o cabeçalho 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}'
    

    A saída é uma das saídas das etapas anteriores.

Criar vários modelos com a composição de modelos

A composição de modelos é uma técnica usada para compor vários modelos em um único aplicativo. A composição de modelos permite encadear entradas e saídas em vários LLMs e dimensionar seus modelos como um único aplicativo.

Neste exemplo, você compõe dois modelos, Gemma 7B IT e Llama 3 8B, em um único aplicativo. O primeiro modelo é o do assistente, que responde às perguntas fornecidas no comando. O segundo modelo é o de resumo. A saída do modelo do assistente é encadeada na entrada do modelo de resumo. O resultado final é a versão resumida da resposta do modelo do assistente.

  1. Implante o recurso do RayService:

    kubectl apply -f model-composition/
    
  2. Aguarde até que o recurso do RayService esteja pronto:

    kubectl get rayservice model-composition -o yaml
    

    O resultado será assim:

    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
    

    Nesta saída, status: RUNNING indica que o recurso do RayService está pronto.

  3. Confirme se o GKE criou o Serviço para o aplicativo do Ray Serve:

    kubectl get service model-composition-serve-svc
    

    O resultado será assim:

    NAME                           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    model-composition-serve-svc    ClusterIP   34.118.226.104   <none>        8000/TCP   45m
    
  4. Envie uma solicitação para o 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. O resultado será assim:

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

Excluir o projeto

  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.

Excluir recursos individuais

Se você usou um projeto existente e não quer excluí-lo, exclua os recursos individuais.

  1. Exclua o cluster:

    gcloud container clusters delete rayserve-cluster
    

A seguir