En esta guía, se muestra cómo entregar modelos de lenguaje grande (LLM) con el framework de Ray en modo de Google Kubernetes Engine (GKE). Esta guía está dirigida a administradores de plataforma o ingenieros de MLOps o DevOps que deseen usar las funciones de organización de GKE para entregar LLM.
En esta guía, puedes entregar cualquiera de los siguientes modelos:
Antes de completar los siguientes pasos en GKE, te recomendamos que conozcas la Información sobre las GPU en GKE.
Antecedentes
El framework de Ray proporciona una plataforma de IA/AA de extremo a extremo para el entrenamiento, el entrenamiento detallado y la inferencia de cargas de trabajo de AA. Según el formato de datos del modelo, la cantidad de GPU varía. En esta guía, cada modelo usa dos GPU L4. Para obtener más información, consulta Calcula la cantidad de GPU.
En esta guía se abarcan los siguientes pasos:
- Crear un Autopilot o Standard clúster de GKE.
- Implementa el operador KubeRay.
- Implementa recursos personalizados de RayService para entregar LLM.
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.
Si quieres usar el modelo Llama 2, asegúrate de tener lo siguiente:
- Acceso a una licencia activa para los modelos de Meta Llama.
- Un token de HuggingFace.
Asegúrate de tener cuota de GPU en la región
us-central1
. Para obtener más información, consulta Cuota de GPU.
Prepara el entorno
En la consola de Google Cloud, inicia una instancia de Cloud Shell:
Abrir Cloud ShellClona el repositorio de ejemplo:
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git cd kubernetes-engine-samples/ai-ml/gke-ray export TUTORIAL_HOME=`pwd`
Este repositorio incluye la imagen de contenedor
ray-llm
compilada previamente que modela diferentes tipos de aceleradores. Para esta guía, debes usar GPU L4 de NVIDIA, por lo quespec.serveConfigV2
en RayService apunta a un repositorio que contiene modelos que usan el tipo de acelerador L4.Configura las variables de entorno predeterminadas:
gcloud config set project PROJECT_ID export PROJECT_ID=$(gcloud config get project) export REGION=us-central1
Reemplaza PROJECT_ID por el ID del proyecto de Google Cloud.
Crea un clúster y un grupo de nodos de GPU
Puedes entregar un LLM en GPU L4 con Ray en un clúster de GKE Autopilot o Standard. Te recomendamos que uses un clúster de Autopilot para una experiencia de Kubernetes administrada por completo en un clúster estándar si tu caso de uso requiere alta escalabilidad o si deseas más control sobre la configuración del clúster. 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 realizar las siguientes acciones:
Navega a la carpeta
gke-platform
:cd ${TUTORIAL_HOME}/gke-platform
- Para un clúster de Autopilot, ejecuta el siguiente comando:
cat << EOF > terraform.tfvars enable_autopilot=true project_id="${PROJECT_ID}" EOF
- Para un clúster de Standard, ejecuta el siguiente 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
Implementa el clúster de GKE y el grupo de nodos:
terraform init terraform apply --auto-approve
A medida que Terraform se inicializa, registra mensajes de progreso. Al final de la salida del mensaje, deberías ver un mensaje que indica que Terraform se inicializó de forma correcta.
Una vez completados, los manifiestos de Terraform implementan los siguientes componentes:
- Clúster de GKE
- Grupo de nodos de CPU
- Grupo de nodos de GPU
- Operador KubeRay con Ray CustomResourceDefinitions (CRD)
Recupera las credenciales de clúster aprovisionadas que usará
kubectl
en la siguiente sección de la guía:gcloud container clusters get-credentials ml-cluster --region us-central1
Navega a la carpeta
rayserve
:cd ${TUTORIAL_HOME}/rayserve
Implementa el modelo de LLM
En el repositorio clonado, la carpeta models
incluye la configuración que
carga los modelos. Para
ray-llm
, la
configuración de cada modelo se compone de lo siguiente:
- Implementación: la configuración de Ray Serve
- Motor: el modelo de Huggingface, los parámetros del modelo y los detalles del mensaje
- Escalamiento: la definición de los recursos de Ray que consume el modelo.
- Las configuraciones específicas por modelo
En esta guía, usarás la cuantización de NormalFloat de 4 bits (NF4), a través de los transformadores de HuggingFace, para cargar LLM con un espacio en memoria de GPU reducida (dos GPU L4, lo que significa un total de memoria de GPU de 48 GB). La reducción de 16 bits a 4 bits disminuye la precisión de los pesos del modelo, pero proporciona flexibilidad que te permite probar modelos más grandes y ver si es suficiente para tu caso de uso. Para la cuantización, el código de muestra usa las bibliotecas HuggingFace y BitsAndBytesConfig a fin de cargar las versiones cuantizadas de los modelos de parámetros más grandes, Falcon 40b y Llama2 70b.
En la siguiente sección, se muestra cómo configurar la carga de trabajo según el modelo que deseas usar:
Falcon 7b
Implementa RayService y las dependencias. Usa el comando que corresponde al modo de GKE que creaste:
- Autopilot:
kubectl apply -f models/falcon-7b-instruct.yaml kubectl apply -f ap_pvc-rayservice.yaml kubectl apply -f ap_falcon-7b.yaml
- Standard:
kubectl apply -f models/falcon-7b-instruct.yaml kubectl apply -f falcon-7b.yaml
La creación del Pod del clúster de Ray puede tardar varios minutos en alcanzar el estado
Running
.Espera a que el Pod principal del clúster de Ray esté en funcionamiento.
watch --color --interval 5 --no-title \ "kubectl get pod | \ GREP_COLOR='01;92' egrep --color=always -e '^' -e 'Running'"
Una vez que el Pod del clúster de Ray esté en ejecución, puedes verificar el estado del 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'"
El resultado es similar al siguiente:
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: ''
Si el campo Estado es
RUNNING
, tu LLM está listo para chatear.
Llama2 7b
Configura las variables de entorno predeterminadas:
export HF_TOKEN=HUGGING_FACE_TOKEN
Reemplaza
HUGGING_FACE_TOKEN
por tu token de HuggingFace.Crea un Secret de Kubernetes para el token de HuggingFace:
kubectl create secret generic hf-secret \ --from-literal=hf_api_token=${HF_TOKEN} \ --dry-run=client -o yaml | kubectl apply -f -
Implementa RayService y las dependencias. Usa el comando que corresponde al modo de GKE que creaste:
- Autopilot:
kubectl apply -f models/llama2-7b-chat-hf.yaml kubectl apply -f ap_pvc-rayservice.yaml kubectl apply -f ap_llama2-7b.yaml
- Estándar:
kubectl apply -f models/llama2-7b-chat-hf.yaml kubectl apply -f llama2-7b.yaml
La creación del Pod del clúster de Ray puede tardar varios minutos en alcanzar el estado
Running
.Espera a que el Pod principal del clúster de Ray esté en funcionamiento.
watch --color --interval 5 --no-title \ "kubectl get pod | \ GREP_COLOR='01;92' egrep --color=always -e '^' -e 'Running'"
Una vez que el Pod del clúster de Ray esté en ejecución, puedes verificar el estado del 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'"
El resultado es similar al siguiente:
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
Si el campo Estado es
RUNNING
, tu LLM está listo para chatear.
Falcon 40b
Implementa RayService y las dependencias. Usa el comando que corresponde al modo de GKE que creaste:
- Autopilot:
kubectl apply -f models/quantized-model.yaml kubectl apply -f ap_pvc-rayservice.yaml kubectl apply -f ap_falcon-40b.yaml
- Standard:
kubectl apply -f models/quantized-model.yaml kubectl apply -f falcon-40b.yaml
La creación del Pod del clúster de Ray puede tardar varios minutos en alcanzar el estado
Running
.Espera a que el Pod principal del clúster de Ray esté en funcionamiento.
watch --color --interval 5 --no-title \ "kubectl get pod | \ GREP_COLOR='01;92' egrep --color=always -e '^' -e 'Running'"
Una vez que el Pod del clúster de Ray esté en ejecución, puedes verificar el estado del 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'"
El resultado es similar al siguiente:
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
Si el campo Estado es
RUNNING
, tu LLM está listo para chatear.
Llama2 70b
Configura las variables de entorno predeterminadas:
export HF_TOKEN=HUGGING_FACE_TOKEN
Reemplaza
HUGGING_FACE_TOKEN
por tu token de HuggingFace.Crea un Secret de Kubernetes para el token de HuggingFace:
kubectl create secret generic hf-secret \ --from-literal=hf_api_token=${HF_TOKEN} \ --dry-run=client -o yaml | kubectl apply -f -
Implementa RayService y las dependencias. Usa el comando que corresponde al modo de GKE que creaste:
- Autopilot:
kubectl apply -f models/quantized-model.yaml kubectl apply -f ap_pvc-rayservice.yaml kubectl apply -f ap_llama2-70b.yaml
- Standard:
kubectl apply -f models/quantized-model.yaml kubectl apply -f llama2-70b.yaml
La creación del Pod del clúster de Ray puede tardar varios minutos en alcanzar el estado
Running
.Espera a que el Pod principal del clúster de Ray esté en funcionamiento.
watch --color --interval 5 --no-title \ "kubectl get pod | \ GREP_COLOR='01;92' egrep --color=always -e '^' -e 'Running'"
Una vez que el Pod del clúster de Ray esté en ejecución, puedes verificar el estado del 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'"
El resultado es similar al siguiente:
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: ''
Si el campo Estado es
RUNNING
, tu LLM está listo para chatear.
Chatea con tu modelo
Para los modelos Falcon 7b y Llama2 7b, ray-llm
implementa la
especificación de chat de la API de OpenAI.
Los modelos Falcon 40b y Llama2 70b usan ray-llm
y solo admiten la generación de texto.
Falcon 7b
Configura la redirección de puertos al servidor de inferencia:
kubectl port-forward service/rayllm-serve-svc 8000:8000
El resultado es similar al siguiente:
Forwarding from 127.0.0.1:8000 -> 8000
En una sesión de terminal nueva, usa
curl
para chatear con tu 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
Configura la redirección de puertos al servidor de inferencia:
kubectl port-forward service/rayllm-serve-svc 8000:8000
El resultado es similar al siguiente:
Forwarding from 127.0.0.1:8000 -> 8000
En una sesión de terminal nueva, usa
curl
para chatear con tu 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
Configura la redirección de puertos al servidor de inferencia:
kubectl port-forward service/rayllm-serve-svc 8000:8000
El resultado es similar al siguiente:
Forwarding from 127.0.0.1:8000 -> 8000
En una sesión de terminal nueva, usa
curl
para chatear con tu 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
Configura la redirección de puertos al servidor de inferencia:
kubectl port-forward service/rayllm-serve-svc 8000:8000
El resultado es similar al siguiente:
Forwarding from 127.0.0.1:8000 -> 8000
En una sesión de terminal nueva, usa
curl
para chatear con tu 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."}'
Crea un diálogo con el modelo
Los modelos que entregaste no conservan ningún historial, por lo que cada mensaje y respuesta debe enviarse de vuelta al modelo para crear la ilusión de diálogo. Esta interacción aumenta la cantidad de tokens que usas. Para crear una interacción única, crea un diálogo con tu modelo. Puedes crear un diálogo cuando usas Falcon 7b o Llama2 7b:
Falcon 7b
Crea un diálogo con el modelo a través de
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 }'
El resultado es similar al siguiente:
{ "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
Crea un diálogo con el modelo a través de
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 }'
El resultado es similar al siguiente:
{ "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 } }
Implementa una interfaz de chat
De manera opcional, puedes usar Gradio para compilar una aplicación web que te permita interactuar con tu modelo. Gradio es una biblioteca de Python que tiene un wrapper de ChatInterface que crea interfaces de usuario para chatbots.
Falcon 7b
Abre el manifiesto
gradio.yaml
:Reemplaza el
value
asignado aMODEL_ID
por el valortiiuae/falcon-7b-instruct
:... - name: MODEL_ID value: "tiiuae/falcon-7b-instruct"
Aplica el manifiesto
kubectl apply -f gradio.yaml
Busca la dirección IP externa del Service:
EXTERNAL_IP=$(kubectl get services gradio \ --output jsonpath='{.status.loadBalancer.ingress[0].ip}') echo -e "\nGradio URL: http://${EXTERNAL_IP}\n"
El resultado es similar al siguiente:
Gradio URL: http://34.172.115.35
El balanceador de cargas puede tardar varios minutos en obtener una dirección IP externa.
Llama2 7b
Abre el manifiesto
gradio.yaml
:Asegúrate de que el
value
asignado aMODEL_ID
seameta-llama/Llama-2-7b-chat-hf
.Aplica el manifiesto
kubectl apply -f gradio.yaml
Busca la dirección IP externa del Service:
EXTERNAL_IP=$(kubectl get services gradio \ --output jsonpath='{.status.loadBalancer.ingress[0].ip}') echo -e "\nGradio URL: http://${EXTERNAL_IP}\n"
El resultado es similar al siguiente:
Gradio URL: http://34.172.115.35
El balanceador de cargas puede tardar varios minutos en obtener una dirección IP externa.
Calcula la cantidad de GPU
La cantidad de GPU depende del valor de la configuración
bnb_4bit_quant_type
. En este instructivo, configurarás bnb_4bit_quant_type
como nf4
, lo que
significa que el modelo se carga en 4 bits.
Un modelo de 70,000 millones de parámetros requeriría un mínimo de 40 GB de memoria de GPU. Esto equivale a 70,000 millones de veces 4 bits (70,000 millones x 4 bits= 35 GB) más 5 GB de sobrecarga. En este caso, una sola GPU L4 no tendría suficiente memoria. Por lo tanto, en los ejemplos de este instructivo, se usan dos GPU L4 de memoria (2 x 24 = 48 GB). Esta configuración es suficiente para ejecutar Falcon 40b o Llama 2 70b en las GPU L4.
Borra el proyecto
- 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.
Borra los recursos individuales
Si usaste un proyecto existente y no quieres borrarlo, borra los recursos individuales.
Navega a la carpeta
gke-platform
:cd ${TUTORIAL_HOME}/gke-platform
Inhabilita la protección contra la eliminación en el clúster y quita todos los recursos aprovisionados de Terraform. Ejecuta los siguientes comandos:
sed -ie 's/"deletion_protection": true/"deletion_protection": false/g' terraform.tfstate terraform destroy --auto-approve
¿Qué sigue?
- Más información sobre las VMs G2 con las GPU L4 de NVIDIA
- Entrena un modelo con GPU en el modo GKE Standard