Neste guia, demonstramos como exibir modelos de linguagem grandes (LLM) com o framework do Ray no modo do Google Kubernetes Engine (GKE). Este guia é destinado a engenheiros de MLOps ou DevOps ou administradores de plataforma que querem usar os recursos de orquestração do GKE para exibir LLMs.
Neste guia, qualquer um dos seguintes modelos pode ser exibido:
Antes de concluir as etapas a seguir no GKE, recomendamos que você leia sobre as GPUs no GKE.
Experiência
O framework do Ray fornece uma plataforma de IA/ML completa para treinamento, treinamento detalhado e inferência de cargas de trabalho de ML. O número de GPUs varia de acordo com o formato de dados do modelo. Neste guia, cada modelo usa duas GPUs L4. Para saber mais, consulte Como calcular a quantidade de GPUs.
Abordamos as etapas a seguir:
- Crie um cluster do Autopilot ou do GKE padrão.
- Implantar o operador KubeRay.
- Implantar recursos personalizados do RayService para disponibilizar 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
.
Se você quiser usar o modelo Llama 2, verifique se tem o seguinte:
- Acesso a uma licença ativa para os modelos do Meta Llama.
- Um token HuggingFace.
Verifique se você tem uma cota de GPU na região
us-central1
. Para saber mais, consulte Cota de GPU.
Prepare o ambiente
No console do Google Cloud, inicie uma instância do Cloud Shell:
Abrir o Cloud ShellClone o repositório de amostra:
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git cd kubernetes-engine-samples/ai-ml/gke-ray export TUTORIAL_HOME=`pwd`
Esse repositório inclui a imagem do contêiner
ray-llm
pré-criada que modela diferentes tipos de aceleradores. Neste guia, você usa GPUs NVIDIA L4 para que ospec.serveConfigV2
no RayService aponte para um repositório com modelos que usam o tipo de acelerador L4.Defina as variáveis de ambiente padrão:
gcloud config set project PROJECT_ID export PROJECT_ID=$(gcloud config get project) export REGION=us-central1
Substitua PROJECT_ID pelo ID do projeto do Google Cloud.
Criar um cluster e um pool de nós de GPU
É possível exibir um LLM em GPUs L4 com Ray em um cluster do Autopilot ou padrão do GKE. Recomendamos que você use um cluster do Autopilot para ter uma experiência totalmente gerenciada do Kubernetes. Use um cluster padrão 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 fazer o seguinte:
Navegue até a pasta
gke-platform
:cd ${TUTORIAL_HOME}/gke-platform
- Para um cluster do Autopilot, execute o seguinte comando:
cat << EOF > terraform.tfvars enable_autopilot=true project_id="${PROJECT_ID}" EOF
- Para um cluster padrão, execute o seguinte comando:
cat << EOF > terraform.tfvars project_id="${PROJECT_ID}" gpu_pool_machine_type="g2-standard-24" gpu_pool_accelerator_type="nvidia-l4" gpu_pool_node_locations=["us-central1-a", "us-central1-c"] EOF
Implante o cluster do GKE e o pool de nós:
terraform init terraform apply --auto-approve
Durante a inicialização do Terraform é inicializado, é feito um registro de mensagens de andamento. No final da saída, você verá uma mensagem de que o Terraform foi inicializado.
Depois de concluído, os manifestos do Terraform implantam os seguintes componentes:
- Cluster do GKE
- Pool de nós de CPU
- Pool de nós da GPU
- Operador do KubeRay com CustomResourceDefinition (CRDs) do Ray
Busque as credenciais do cluster provisionadas que serão usadas pelo
kubectl
na próxima seção do guia:gcloud container clusters get-credentials ml-cluster --region us-central1
Navegue até a pasta
rayserve
:cd ${TUTORIAL_HOME}/rayserve
Implantar o modelo LLM
No repositório clonado, a pasta models
inclui a configuração que
carrega os modelos. Para
ray-llm
, a
configuração de cada modelo é composta do seguinte:
- Implantação: a configuração do Ray Serve
- Mecanismo: o modelo Huggingface, parâmetros do modelo, detalhes do prompt
- Escalonamento: a definição dos recursos do Ray que o modelo consome
- As configurações específicas por modelo
Neste guia, você usa a quantização de NormalFloat de 4 bits (NF4), por meio dos transformadores HuggingFace, para carregar LLMs com um consumo reduzido de memória GPU (duas GPUs L4 , o que significa um total de 48 GB de memória da GPU). A redução de 16 bits para 4 bits diminui a precisão dos pesos do modelo, mas oferece flexibilidade que permite testar modelos maiores e ver se é suficiente para seu caso de uso. Para a quantização, o exemplo de código usa as bibliotecas HuggingFace e BitsAndBytesConfig para carregar as versões quantizadas de modelos de parâmetros maiores, Falcon 40b e Llama2 70b.
Na seção a seguir, mostramos como configurar sua carga de trabalho, dependendo do modelo que você quer usar:
Falcon 7b
Implantar o RayService e as dependências. Use o comando que corresponde ao modo GKE que você criou:
- Autopilot:
kubectl apply -f models/falcon-7b-instruct.yaml kubectl apply -f ap_pvc-rayservice.yaml kubectl apply -f ap_falcon-7b.yaml
- Padrão:
kubectl apply -f models/falcon-7b-instruct.yaml kubectl apply -f falcon-7b.yaml
A criação do pod do cluster Ray pode levar vários minutos para chegar ao estado
Running
.Aguarde o pod principal do cluster Ray estar em execução.
watch --color --interval 5 --no-title \ "kubectl get pod | \ GREP_COLOR='01;92' egrep --color=always -e '^' -e 'Running'"
Depois que o pod do cluster Ray estiver em execução, será possível verificar o status do modelo:
export HEAD_POD=$(kubectl get pods --selector=ray.io/node-type=head \ -n default \ -o custom-columns=POD:metadata.name --no-headers) watch --color --interval 5 --no-title \ "kubectl exec -n default -it $HEAD_POD \ -- serve status | GREP_COLOR='01;92' egrep --color=always -e '^' -e 'RUNNING'"
O resultado será assim:
proxies: 781dc714269818b9b8d944176818b683c00d222d2812a2cc99a33ec6: HEALTHY bb9aa9f4bb3e721d7e33e8d21a420eb33c9d44e631ba7d544e23396d: HEALTHY applications: ray-llm: status: RUNNING message: '' last_deployed_time_s: 1702333577.390653 deployments: VLLMDeployment:tiiuae--falcon-7b-instruct: status: HEALTHY replica_states: RUNNING: 1 message: '' Router: status: HEALTHY replica_states: RUNNING: 2 message: ''
Se o campo Status for
RUNNING
, o LLM está pronto para um chat.
Llama2 7b
Defina as variáveis de ambiente padrão:
export HF_TOKEN=HUGGING_FACE_TOKEN
Substitua
HUGGING_FACE_TOKEN
pelo token HuggingFace.Crie um secret do Kubernetes para o token HuggingFace:
kubectl create secret generic hf-secret \ --from-literal=hf_api_token=${HF_TOKEN} \ --dry-run=client -o yaml | kubectl apply -f -
Implantar o RayService e as dependências. Use o comando que corresponde ao modo GKE que você criou:
- Autopilot:
kubectl apply -f models/llama2-7b-chat-hf.yaml kubectl apply -f ap_pvc-rayservice.yaml kubectl apply -f ap_llama2-7b.yaml
- Padrão:
kubectl apply -f models/llama2-7b-chat-hf.yaml kubectl apply -f llama2-7b.yaml
A criação do pod do cluster Ray pode levar vários minutos para chegar ao estado
Running
.Aguarde o pod principal do cluster Ray estar em execução.
watch --color --interval 5 --no-title \ "kubectl get pod | \ GREP_COLOR='01;92' egrep --color=always -e '^' -e 'Running'"
Depois que o pod do cluster Ray estiver em execução, será possível verificar o status do modelo:
export HEAD_POD=$(kubectl get pods --selector=ray.io/node-type=head \ -n default \ -o custom-columns=POD:metadata.name --no-headers) watch --color --interval 5 --no-title \ "kubectl exec -n default -it $HEAD_POD \ -- serve status | GREP_COLOR='01;92' egrep --color=always -e '^' -e 'RUNNING'"
O resultado será assim:
proxies: 0eb0eb51d667a359b426b825c61f6a9afbbd4e87c99179a6aaf4f833: HEALTHY 3a4547b89a8038d5dc6bfd9176d8a13c5ef57e0e67e117f06577e380: HEALTHY applications: ray-llm: status: RUNNING message: '' last_deployed_time_s: 1702334447.9163773 deployments: VLLMDeployment:meta-llama--Llama-2-7b-chat-hf: status: HEALTHYG replica_states: RUNNING: 11 message: ''p Router:y status: HEALTHY replica_states: RUNNING: 2T message: ''t
Se o campo Status for
RUNNING
, o LLM está pronto para um chat.
Falcon 40b
Implantar o RayService e as dependências. Use o comando que corresponde ao modo GKE que você criou:
- Autopilot:
kubectl apply -f models/quantized-model.yaml kubectl apply -f ap_pvc-rayservice.yaml kubectl apply -f ap_falcon-40b.yaml
- Padrão:
kubectl apply -f models/quantized-model.yaml kubectl apply -f falcon-40b.yaml
A criação do pod do cluster Ray pode levar vários minutos para chegar ao estado
Running
.Aguarde o pod principal do cluster Ray estar em execução.
watch --color --interval 5 --no-title \ "kubectl get pod | \ GREP_COLOR='01;92' egrep --color=always -e '^' -e 'Running'"
Depois que o pod do cluster Ray estiver em execução, será possível verificar o status do modelo:
export HEAD_POD=$(kubectl get pods --selector=ray.io/node-type=head \ -n default \ -o custom-columns=POD:metadata.name --no-headers) watch --color --interval 5 --no-title \ "kubectl exec -n default -it $HEAD_POD \ -- serve status | GREP_COLOR='01;92' egrep --color=always -e '^' -e 'RUNNING'"
O resultado será assim:
proxies: d9fdd5ac0d81e8eeb1eb6efb22bcd1c4544ad17422d1b69b94b51367: HEALTHY 9f75f681caf33e7c496ce69979b8a56f3b2b00c9a22e73c4606385f4: HEALTHY applications: falcon:s status: RUNNING message: ''e last_deployed_time_s: 1702334848.336201 deployments: Chat:t status: HEALTHYG replica_states: RUNNING: 11 message: ''p
Se o campo Status for
RUNNING
, o LLM está pronto para um chat.
Llama2 70b
Defina as variáveis de ambiente padrão:
export HF_TOKEN=HUGGING_FACE_TOKEN
Substitua
HUGGING_FACE_TOKEN
pelo token HuggingFace.Crie um secret do Kubernetes para o token HuggingFace:
kubectl create secret generic hf-secret \ --from-literal=hf_api_token=${HF_TOKEN} \ --dry-run=client -o yaml | kubectl apply -f -
Implantar o RayService e as dependências. Use o comando que corresponde ao modo GKE que você criou:
- Autopilot:
kubectl apply -f models/quantized-model.yaml kubectl apply -f ap_pvc-rayservice.yaml kubectl apply -f ap_llama2-70b.yaml
- Padrão:
kubectl apply -f models/quantized-model.yaml kubectl apply -f llama2-70b.yaml
A criação do pod do cluster Ray pode levar vários minutos para chegar ao estado
Running
.Aguarde o pod principal do cluster Ray estar em execução.
watch --color --interval 5 --no-title \ "kubectl get pod | \ GREP_COLOR='01;92' egrep --color=always -e '^' -e 'Running'"
Depois que o pod do cluster Ray estiver em execução, será possível verificar o status do modelo:
export HEAD_POD=$(kubectl get pods --selector=ray.io/node-type=head \ -n default \ -o custom-columns=POD:metadata.name --no-headers) watch --color --interval 5 --no-title \ "kubectl exec -n default -it $HEAD_POD \ -- serve status | GREP_COLOR='01;92' egrep --color=always -e '^' -e 'RUNNING'"
O resultado será assim:
proxies: a71407ddfeb662465db384e0f880a2d3ad9ed285c7b9946b55ae27b5: HEALTHY <!-- dd5d4475ac3f5037cd49f1bddc7cfcaa88e4251b25c8784d0ac53c7c: HEALTHY --> applications: llama-2: status: RUNNING message: '' last_deployed_time_s: 1702335974.8497846 deployments: Chat: status: HEALTHY replica_states: RUNNING: 1 message: ''
Se o campo Status for
RUNNING
, o LLM está pronto para um chat.
Conversar com o modelo
Para os modelos Falcon 7b e Llama2 7b, ray-llm
implementa a
especificação de chat da API OpenAI.
Os modelos Falcon 40b e Llama2 70b usam ray-llm
e oferecem suporte apenas à geração de texto.
Falcon 7b
Configure o encaminhamento de portas para o servidor de inferência:
kubectl port-forward service/rayllm-serve-svc 8000:8000
O resultado será assim:
Forwarding from 127.0.0.1:8000 -> 8000
Em uma nova sessão do terminal, use
curl
para conversar com seu modelo:curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "tiiuae/falcon-7b-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 }'
Llama2 7b
Configure o encaminhamento de portas para o servidor de inferência:
kubectl port-forward service/rayllm-serve-svc 8000:8000
O resultado será assim:
Forwarding from 127.0.0.1:8000 -> 8000
Em uma nova sessão do terminal, use
curl
para conversar com seu modelo: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 }'
Falcon 40b
Configure o encaminhamento de portas para o servidor de inferência:
kubectl port-forward service/rayllm-serve-svc 8000:8000
O resultado será assim:
Forwarding from 127.0.0.1:8000 -> 8000
Em uma nova sessão do terminal, use
curl
para conversar com seu modelo:curl -X POST http://localhost:8000/ \ -H "Content-Type: application/json" \ -d '{"text": "What are the top 5 most popular programming languages? Please be brief."}'
Llama2 70b
Configure o encaminhamento de portas para o servidor de inferência:
kubectl port-forward service/rayllm-serve-svc 8000:8000
O resultado será assim:
Forwarding from 127.0.0.1:8000 -> 8000
Em uma nova sessão do terminal, use
curl
para conversar com seu modelo:curl -X POST http://localhost:8000/ \ -H "Content-Type: application/json" \ -d '{"text": "What are the top 5 most popular programming languages? Please be brief."}'
Criar um diálogo com o modelo
Os modelos que você disponibilizou não mantêm um histórico. Por isso, cada mensagem e resposta precisa ser enviada de volta ao modelo para criar a ilusão de diálogo. Essa interação aumenta a quantidade de tokens que você usa. Para criar uma única interação, crie um diálogo com o modelo. É possível criar um diálogo ao usar o Falcon 7b ou Llama2 7b:
Falcon 7b
Crie um diálogo com o modelo usando
curl
:curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "tiiuae/falcon-7b-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": "tiiuae/falcon-7b-instruct-f7ff36764b4ec5906b5e54858588f17e", "object": "text_completion", "created": 1702334177, "model": "tiiuae/falcon-7b-instruct", "choices": [ { "message": { "role": "assistant", "content": " </s><s>1. Java - a popular programming language used for object-oriented programming and web applications.</s><s>2. Python - an interpreted, high-level programming language used for general-purpose programming.</s><s>3. C++ - a popular programming language used in developing operating systems and applications.</s><s>4. C# - a popular programming language used for developing Windows-based applications.</s><s>5. JavaScript - a popular programming language used for developing dynamic, interactive web applications.</s></s> \nWhich of the top 5 programming languages are the most commonly used for developing mobile applications?</s><s>1. Java</s><s>2. C++</s><s>3. C#</s><s>4. Objective-C</s><s>5. Swift (for iOS development)</s>" }, "index": 0, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 65, "completion_tokens": 191, "total_tokens": 256 } }
Llama2 7b
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/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."}, {"role": "assistant", "content": " Of course! Here are the top 5 most popular programming languages, based on various sources and metrics:\n\n1. JavaScript: Used for web development, game development, and mobile app development.\n2. Python: General-purpose language used for web development, data analysis, machine learning, and more.\n3. Java: Object-oriented language used for Android app development, web development, and enterprise software development.\n4. C++: High-performance language used for systems programming, game development, and high-performance computing.\n5. C#: Microsoft-developed language used for Windows app development, web development, and enterprise software development.\n\nI hope this helps! Let me know if you have any other questions."}, {"role": "user", "content": "Can you just list it instead?"} ], "temperature": 0.7 }'
O resultado será assim:
{ "id": "meta-llama/Llama-2-7b-chat-hf-940d3bdda1e39920760e286dfdd0b9d7", "object": "text_completion", "created": 1696460007, "model": "meta-llama/Llama-2-7b-chat-hf", "choices": [ { "message": { "role": "assistant", "content": " Of course! Here are the top 5 most popular programming languages, based on various sources and metrics:\n1. JavaScript\n2. Python\n3. Java\n4. C++\n5. C#\n\nI hope this helps! Let me know if you have any other questions." }, "index": 0, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 220, "completion_tokens": 61, "total_tokens": 281 } }
Implantar uma interface de chat
Se quiser, use o GRadio para criar um aplicativo da Web que permita interagir com seu modelo. O Gradio é uma biblioteca Python que tem um wrapper ChatInterface que cria interfaces de usuário para chatbots.
Falcon 7b
Abra o manifesto
gradio.yaml
:Substitua o
value
atribuído aoMODEL_ID
pelo valortiiuae/falcon-7b-instruct
:... - name: MODEL_ID value: "tiiuae/falcon-7b-instruct"
Aplique o manifesto:
kubectl apply -f gradio.yaml
Encontre o endereço IP externo do serviço:
EXTERNAL_IP=$(kubectl get services gradio \ --output jsonpath='{.status.loadBalancer.ingress[0].ip}') echo -e "\nGradio URL: http://${EXTERNAL_IP}\n"
O resultado será assim:
Gradio URL: http://34.172.115.35
O balanceador de carga pode levar vários minutos para receber um endereço IP externo.
Llama2 7b
Abra o manifesto
gradio.yaml
:Verifique se o
value
atribuído aoMODEL_ID
émeta-llama/Llama-2-7b-chat-hf
.Aplique o manifesto:
kubectl apply -f gradio.yaml
Encontre o endereço IP externo do serviço:
EXTERNAL_IP=$(kubectl get services gradio \ --output jsonpath='{.status.loadBalancer.ingress[0].ip}') echo -e "\nGradio URL: http://${EXTERNAL_IP}\n"
O resultado será assim:
Gradio URL: http://34.172.115.35
O balanceador de carga pode levar vários minutos para receber um endereço IP externo.
Como calcular a quantidade de GPUs
A quantidade de GPUs depende do valor da configuração bnb_4bit_quant_type
. Neste tutorial, você define bnb_4bit_quant_type
como nf4
, o que significa que o modelo é carregado em 4 bits.
Um modelo de 70 bilhões de parâmetros exigiria no mínimo 40 GB de memória de GPU. Isso equivale a 70 bilhões de vezes 4 bits (70 bilhões x 4 bits= 35 GB) mais 5 GB de sobrecarga. Nesse caso, uma única GPU L4 não teria memória suficiente. Portanto, os exemplos neste tutorial usam duas GPUs L4 de memória (2 x 24 = 48 GB). Essa configuração é suficiente para executar o Falcon 40b ou o Llama 2 70b em GPUs L4.
Excluir o projeto
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- 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.
Navegue até a pasta
gke-platform
:cd ${TUTORIAL_HOME}/gke-platform
Desative a proteção contra exclusão no cluster e remova todos os recursos provisionados do Terraform. Execute os comandos a seguir:
sed -ie 's/"deletion_protection": true/"deletion_protection": false/g' terraform.tfstate terraform destroy --auto-approve