Ce guide explique comment diffuser des modèles de langage volumineux (LLM) avec le framework Ray en mode Google Kubernetes Engine (GKE). Ce guide est destiné aux ingénieurs MLOps ou DevOps ou aux administrateurs de plate-forme qui souhaitent utiliser les fonctionnalités d'orchestration GKE pour obtenir des inférences à partir d'un LLM.
Dans ce guide, vous pouvez diffuser l'un des modèles suivants :
Avant d'effectuer les étapes suivantes dans GKE, nous vous recommandons de vous familiariser avec la Présentation des GPU dans GKE.
Contexte
Le framework Ray fournit une plate-forme AI/ML de bout en bout pour l'entraînement, l'optimisation et l'inférence de charges de travail de ML. Selon le format de données du modèle, le nombre de GPU varie. Dans ce guide, chaque modèle utilise deux GPU L4. Pour en savoir plus, consultez la page Calculer la quantité de GPU.
Ce guide couvre les étapes suivantes :
- Créer un cluster GKE Autopilot ou standard
- Déployez l'opérateur KubeRay.
- Déployez des ressources personnalisées RayService pour diffuser les LLM.
Avant de commencer
Avant de commencer, effectuez les tâches suivantes :
- Activez l'API Google Kubernetes Engine. Activer l'API Google Kubernetes Engine
- Si vous souhaitez utiliser Google Cloud CLI pour cette tâche, installez puis initialisez gcloud CLI. Si vous avez déjà installé gcloud CLI, assurez-vous de disposer de la dernière version en exécutant la commande
gcloud components update
.
Si vous souhaitez utiliser le modèle Llama 2, vérifiez les points suivants :
- Accès à une licence active pour les modèles Meta Llama.
- Un jeton HuggingFace.
Assurez-vous de disposer d'un quota de GPU dans la région
us-central1
. Pour en savoir plus, consultez la page Quota de GPU.
Préparer votre environnement
Dans la console Google Cloud, démarrez une instance Cloud Shell :
Ouvrir Cloud ShellClonez l'exemple de dépôt :
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git cd kubernetes-engine-samples/ai-ml/gke-ray export TUTORIAL_HOME=`pwd`
Ce dépôt inclut l'image de conteneur
ray-llm
prédéfinie qui modélise et provisionne différents types d'accélérateurs. Dans ce guide, vous utilisez des GPU NVIDIA L4, de sorte quespec.serveConfigV2
dans RayService pointe vers un dépôt contenant des modèles utilisant le type d'accélérateur L4.Définissez les variables d'environnement par défaut :
gcloud config set project PROJECT_ID export PROJECT_ID=$(gcloud config get project) export REGION=us-central1
Remplacez PROJECT_ID par l'ID du projet Google Cloud.
Créer un cluster et un pool de nœuds GPU
Vous pouvez diffuser un LLM sur des GPU L4 avec Ray dans un cluster GKE Autopilot ou standard. Nous vous recommandons d'utiliser un cluster Autopilot pour une expérience Kubernetes entièrement gérée ou un cluster standard si votre cas d'utilisation nécessite une grande évolutivité ou si vous souhaitez davantage de contrôle sur la configuration du cluster. Pour choisir le mode de fonctionnement GKE le mieux adapté à vos charges de travail, consultez la section Choisir un mode de fonctionnement GKE.
Utilisez Cloud Shell pour effectuer les opérations suivantes :
Accédez au dossier
gke-platform
:cd ${TUTORIAL_HOME}/gke-platform
- Pour un cluster Autopilot, exécutez la commande suivante :
cat << EOF > terraform.tfvars enable_autopilot=true project_id="${PROJECT_ID}" EOF
- Pour un cluster Standard, exécutez la commande suivante :
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
Déployez le cluster et le pool de nœuds GKE :
terraform init terraform apply --auto-approve
Lors de l'initialisation de Terraform, les messages de progression sont consignés. À la fin du résultat, un message indique que Terraform a bien été initialisé.
Une fois l'opération terminée, les fichiers manifestes Terraform déploient les composants suivants :
- Cluster GKE
- Pool de nœuds du processeur
- Pool de nœuds du GPU
- Opérateur KubeRay avec des objets CustomResourceDefinitions (CRD) Ray
Récupérez les identifiants de cluster provisionnés que
kubectl
utilisera dans la section suivante du guide :gcloud container clusters get-credentials ml-cluster --region us-central1
Accédez au dossier
rayserve
:cd ${TUTORIAL_HOME}/rayserve
Déployer le modèle LLM
Dans le dépôt cloné, le dossier models
inclut la configuration qui charge les modèles. Pour ray-llm
, la configuration de chaque modèle est composée des éléments suivants :
- Déploiement : configuration de Ray Serve
- Moteur : modèle Huggingface, paramètres du modèle, détails de la requête
- Mise à l'échelle : définition des ressources Ray utilisées par le modèle
- Configurations spécifiques par modèle
Dans ce guide, vous utilisez la quantification de NormalFloat 4 bits (NF4), via les transformateurs Huggingface, pour charger des LLM avec une empreinte de mémoire GPU réduite (deux GPU L4), soit 48 Go de mémoire GPU au total. La réduction de 16 bits à 4 bits diminue la précision des pondérations du modèle, mais offre une certaine flexibilité qui vous permet de tester des modèles plus volumineux et de voir si cela est suffisant pour votre cas d'utilisation. Pour la quantification, l'exemple de code utilise les bibliothèques HugingFace et BitsAndBytesConfig pour charger les versions quantifiées de modèles de paramètres plus volumineux, Falcon 40b et Llama2 70b.
La section suivante montre comment configurer votre charge de travail en fonction du modèle que vous souhaitez utiliser :
Falcon 7b
Déployez RayService et les dépendances. Exécutez la commande correspondant au mode GKE que vous avez créé :
- 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 création du pod du cluster Ray peut prendre plusieurs minutes pour atteindre l'état
Running
.Attendez que le pod principal du cluster Ray soit opérationnel.
watch --color --interval 5 --no-title \ "kubectl get pod | \ GREP_COLOR='01;92' egrep --color=always -e '^' -e 'Running'"
Une fois le pod du cluster Ray en cours d'exécution, vous pouvez vérifier l'état du modèle :
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'"
Le résultat ressemble à ce qui suit :
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 le champ État indique
RUNNING
, votre LLM est prêt à discuter.
Llama2 7b
Définissez les variables d'environnement par défaut :
export HF_TOKEN=HUGGING_FACE_TOKEN
Remplacez
HUGGING_FACE_TOKEN
par votre jeton HuggingFace.Créez un secret Kubernetes pour le jeton HuggingFace :
kubectl create secret generic hf-secret \ --from-literal=hf_api_token=${HF_TOKEN} \ --dry-run=client -o yaml | kubectl apply -f -
Déployez RayService et les dépendances. Exécutez la commande correspondant au mode GKE que vous avez créé :
- Autopilot :
kubectl apply -f models/llama2-7b-chat-hf.yaml kubectl apply -f ap_pvc-rayservice.yaml kubectl apply -f ap_llama2-7b.yaml
- Standard :
kubectl apply -f models/llama2-7b-chat-hf.yaml kubectl apply -f llama2-7b.yaml
La création du pod du cluster Ray peut prendre plusieurs minutes pour atteindre l'état
Running
.Attendez que le pod principal du cluster Ray soit opérationnel.
watch --color --interval 5 --no-title \ "kubectl get pod | \ GREP_COLOR='01;92' egrep --color=always -e '^' -e 'Running'"
Une fois le pod du cluster Ray en cours d'exécution, vous pouvez vérifier l'état du modèle :
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'"
Le résultat ressemble à ce qui suit :
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 le champ État indique
RUNNING
, votre LLM est prêt à discuter.
Falcon 40b
Déployez RayService et les dépendances. Exécutez la commande correspondant au mode GKE que vous avez créé :
- 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 création du pod du cluster Ray peut prendre plusieurs minutes pour atteindre l'état
Running
.Attendez que le pod principal du cluster Ray soit opérationnel.
watch --color --interval 5 --no-title \ "kubectl get pod | \ GREP_COLOR='01;92' egrep --color=always -e '^' -e 'Running'"
Une fois le pod du cluster Ray en cours d'exécution, vous pouvez vérifier l'état du modèle :
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'"
Le résultat ressemble à ce qui suit :
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 le champ État indique
RUNNING
, votre LLM est prêt à discuter.
Llama2 70b
Définissez les variables d'environnement par défaut :
export HF_TOKEN=HUGGING_FACE_TOKEN
Remplacez
HUGGING_FACE_TOKEN
par votre jeton HuggingFace.Créez un secret Kubernetes pour le jeton HuggingFace :
kubectl create secret generic hf-secret \ --from-literal=hf_api_token=${HF_TOKEN} \ --dry-run=client -o yaml | kubectl apply -f -
Déployez RayService et les dépendances. Exécutez la commande correspondant au mode GKE que vous avez créé :
- 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 création du pod du cluster Ray peut prendre plusieurs minutes pour atteindre l'état
Running
.Attendez que le pod principal du cluster Ray soit opérationnel.
watch --color --interval 5 --no-title \ "kubectl get pod | \ GREP_COLOR='01;92' egrep --color=always -e '^' -e 'Running'"
Une fois le pod du cluster Ray en cours d'exécution, vous pouvez vérifier l'état du modèle :
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'"
Le résultat ressemble à ce qui suit :
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 le champ État indique
RUNNING
, votre LLM est prêt à discuter.
Discuter avec votre modèle
Pour les modèles Falcon 7b et Llama2 7b, ray-llm
met en œuvre la spécification de chat de l'API OpenAI. Les modèles Falcon 40b et Llama2 70b utilisent ray-llm
et ne sont compatibles qu'avec la génération de texte.
Falcon 7b
Configurez un transfert de port vers le serveur d'inférence :
kubectl port-forward service/rayllm-serve-svc 8000:8000
Le résultat ressemble à ce qui suit :
Forwarding from 127.0.0.1:8000 -> 8000
Dans une nouvelle session de terminal, utilisez
curl
pour discuter avec votre modèle :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
Configurez un transfert de port vers le serveur d'inférence :
kubectl port-forward service/rayllm-serve-svc 8000:8000
Le résultat ressemble à ce qui suit :
Forwarding from 127.0.0.1:8000 -> 8000
Dans une nouvelle session de terminal, utilisez
curl
pour discuter avec votre modèle :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
Configurez un transfert de port vers le serveur d'inférence :
kubectl port-forward service/rayllm-serve-svc 8000:8000
Le résultat ressemble à ce qui suit :
Forwarding from 127.0.0.1:8000 -> 8000
Dans une nouvelle session de terminal, utilisez
curl
pour discuter avec votre modèle :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
Configurez un transfert de port vers le serveur d'inférence :
kubectl port-forward service/rayllm-serve-svc 8000:8000
Le résultat ressemble à ce qui suit :
Forwarding from 127.0.0.1:8000 -> 8000
Dans une nouvelle session de terminal, utilisez
curl
pour discuter avec votre modèle :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."}'
Créer un dialogue avec le modèle
Les modèles que vous avez diffusés ne conservent aucun historique. Par conséquent, chaque message et chaque réponse doivent être renvoyés au modèle pour créer l'illusion d'un dialogue. Cette interaction augmente la quantité de jetons que vous utilisez. Pour créer une seule interaction, créez un dialogue avec votre modèle. Vous pouvez créer un dialogue lorsque vous utilisez Falcon 7b ou Llama2 7b :
Falcon 7b
Créez un dialogue avec le modèle à l'aide 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 }'
Le résultat ressemble à ce qui suit :
{ "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
Créez un dialogue avec le modèle à l'aide 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 }'
Le résultat ressemble à ce qui suit :
{ "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 } }
Déployer une interface de chat
Si vous le souhaitez, vous pouvez utiliser Gradio pour créer une application Web qui vous permet d'interagir avec votre modèle. Gradio est une bibliothèque Python dotée d'un wrapper ChatInterface qui crée des interfaces utilisateur pour les chatbots.
Falcon 7b
Ouvrez le fichier manifeste
gradio.yaml
:Remplacez le
value
attribué àMODEL_ID
par la valeurtiiuae/falcon-7b-instruct
:... - name: MODEL_ID value: "tiiuae/falcon-7b-instruct"
Appliquez le fichier manifeste :
kubectl apply -f gradio.yaml
Recherchez l'adresse IP externe du service :
EXTERNAL_IP=$(kubectl get services gradio \ --output jsonpath='{.status.loadBalancer.ingress[0].ip}') echo -e "\nGradio URL: http://${EXTERNAL_IP}\n"
Le résultat ressemble à ce qui suit :
Gradio URL: http://34.172.115.35
L'équilibreur de charge peut prendre plusieurs minutes pour obtenir une adresse IP externe.
Llama2 7b
Ouvrez le fichier manifeste
gradio.yaml
:Assurez-vous que la valeur
value
attribuée auMODEL_ID
estmeta-llama/Llama-2-7b-chat-hf
.Appliquez le fichier manifeste :
kubectl apply -f gradio.yaml
Recherchez l'adresse IP externe du service :
EXTERNAL_IP=$(kubectl get services gradio \ --output jsonpath='{.status.loadBalancer.ingress[0].ip}') echo -e "\nGradio URL: http://${EXTERNAL_IP}\n"
Le résultat ressemble à ce qui suit :
Gradio URL: http://34.172.115.35
L'équilibreur de charge peut prendre plusieurs minutes pour obtenir une adresse IP externe.
Calculer le nombre de GPU
Le nombre de GPU dépend de la valeur de la configuration bnb_4bit_quant_type
. Dans ce tutoriel, vous définissez bnb_4bit_quant_type
sur nf4
, ce qui signifie que le modèle est chargé en 4 bits.
Un modèle avec 70 milliards de paramètres nécessiterait au moins 40 Go de mémoire GPU. Cela équivaut à 70 milliards fois 4 bits (70 milliards x 4 bits= 35 Go) plus 5 Go de surcharge. Dans ce cas, un GPU L4 ne disposerait pas de suffisamment de mémoire. Par conséquent, les exemples de ce tutoriel utilisent la mémoire de deux GPU L4 de mémoire (2 x 24 = 48 Go). Cette configuration est suffisante pour exécuter Falcon 40b ou Llama 2 70b sur les GPU L4.
Supprimer le projet
- 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.
Supprimer les ressources individuelles
Si vous avez utilisé un projet existant et que vous ne souhaitez pas le supprimer, supprimez les ressources individuelles.
Accédez au dossier
gke-platform
:cd ${TUTORIAL_HOME}/gke-platform
Désactivez la protection contre la suppression sur le cluster et supprimez toutes les ressources Terraform provisionnées. Exécutez les commandes suivantes :
sed -ie 's/"deletion_protection": true/"deletion_protection": false/g' terraform.tfstate terraform destroy --auto-approve
Étapes suivantes
- En savoir plus sur les VM G2 avec les GPU NVIDIA L4
- Entraîner les modèles avec des GPU en mode GKE Standard