Diffuser un LLM sur des GPU L4 avec Ray


Ce guide explique comment diffuser des modèles de langage volumineux (LLM) à l'aide de Ray et du module complémentaire Ray Operator avec Google Kubernetes Engine (GKE).

Dans ce guide, vous pouvez diffuser l'un des modèles suivants :

Ce guide aborde également les techniques de diffusion de modèles telles que le multiplexage et la composition de modèles, qui sont compatibles avec le framework Ray Serve.

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 machine learning. Ray Serve est un framework de Ray que vous pouvez utiliser pour diffuser des LLM populaires à partir de Hugging Face.

Selon le format de données du modèle, le nombre de GPU varie. Dans ce guide, votre modèle peut utiliser un ou deux GPU L4.

Ce guide couvre les étapes suivantes :

  1. Créez un cluster GKE Autopilot ou Standard avec le module complémentaire Ray Operator activé.
  2. Déployez une ressource RayService qui télécharge et diffuse un grand modèle de langage (LLM) depuis Hugging Face.
  3. Déployez une interface de chat et interagissez avec des 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.
  • Créez un compte Hugging Face si vous n'en possédez pas.
  • Assurez-vous de disposer d'un jeton Hugging Face.
  • Assurez-vous d'avoir accès au modèle Hugging Face que vous souhaitez utiliser. Pour cela, vous devez généralement signer un accord et demander l'accès au propriétaire du modèle sur la page du modèle Hugging Face.
  • 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

  1. Dans la console Google Cloud, démarrez une instance Cloud Shell :
    Ouvrir Cloud Shell

  2. Clonez l'exemple de dépôt :

    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. Définissez les variables d'environnement par défaut :

    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
    

    Remplacez les éléments suivants :

    • PROJECT_ID : ID de votre projet Google Cloud.
    • CLUSTER_VERSION : version de GKE à utiliser. Doit être 1.30.1 ou une version ultérieure.
    • HUGGING_FACE_TOKEN : jeton d'accès Hugging Face.

Créer un cluster GKE avec un pool de nœuds GPU.

Vous pouvez diffuser un LLM sur des GPU L4 avec Ray dans un cluster GKE Autopilot ou Standard à l'aide du module complémentaire Ray Operator. Nous vous recommandons généralement d'utiliser un cluster Autopilot pour une expérience Kubernetes entièrement gérée. Choisissez plutôt 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 créer un cluster Autopilot ou Standard :

Autopilot

Créez un cluster Autopilot avec le module complémentaire Ray Operator activé :

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

Standard

Créez un cluster Standard avec le module complémentaire Ray Operator activé :

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

Créer un secret Kubernetes pour les identifiants Hugging Face

Dans Cloud Shell, créez un Secret Kubernetes en procédant comme suit :

  1. Configurez kubectl de manière à communiquer avec votre cluster :

    gcloud container clusters get-credentials ${CLUSTER_NAME} --location=${COMPUTE_REGION}
    
  2. Créez un secret Kubernetes contenant le jeton Hugging Face:

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

Déployer le modèle LLM

Le dépôt GitHub que vous avez cloné comporte un répertoire pour chaque modèle qui inclut une configuration RayService. La configuration de chaque modèle comprend les composants suivants :

  • Déploiement de Ray Serve : déploiement de Ray Serve, qui inclut la configuration des ressources et les dépendances d'exécution.
  • Modèle : ID du modèle Hugging Face.
  • Cluster Ray : le cluster Ray sous-jacent et les ressources requises pour chaque composant, y compris les pods principaux et de calcul.

Gemma 2B IT

  1. Déployez le modèle :

    kubectl apply -f gemma-2b-it/
    
  2. Attendez que la ressource RayService soit prête :

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

    Le résultat ressemble à ce qui suit :

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

    Dans ce résultat, status: RUNNING indique que la ressource RayService est prête.

  3. Vérifiez que GKE a créé le Service pour l'application Ray Serve :

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

    Le résultat ressemble à ce qui suit :

    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. Déployez le modèle :

    kubectl apply -f gemma-7b-it/
    
  2. Attendez que la ressource RayService soit prête :

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

    Le résultat ressemble à ce qui suit :

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

    Dans ce résultat, status: RUNNING indique que la ressource RayService est prête.

  3. Vérifiez que GKE a créé le service pour l'application Ray Serve :

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

    Le résultat ressemble à ce qui suit :

    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. Déployez le modèle :

    kubectl apply -f llama-2-7b/
    
  2. Attendez que la ressource RayService soit prête :

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

    Le résultat ressemble à ce qui suit :

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

    Dans ce résultat, status: RUNNING indique que la ressource RayService est prête.

  3. Vérifiez que GKE a créé le Service pour l'application Ray Serve :

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

    Le résultat ressemble à ce qui suit :

    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. Déployez le modèle :

    kubectl apply -f llama-3-8b/
    
  2. Attendez que la ressource RayService soit prête :

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

    Le résultat ressemble à ce qui suit :

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

    Dans ce résultat, status: RUNNING indique que la ressource RayService est prête.

  3. Vérifiez que GKE a créé le Service pour l'application Ray Serve :

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

    Le résultat ressemble à ce qui suit :

    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. Déployez le modèle :

    kubectl apply -f mistral-7b/
    
  2. Attendez que la ressource RayService soit prête :

    kubectl get rayservice mistral-7b -o yaml
    

    Le résultat ressemble à ce qui suit :

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

    Dans ce résultat, status: RUNNING indique que la ressource RayService est prête.

  3. Vérifiez que GKE a créé le Service pour l'application Ray Serve :

    kubectl get service mistral-7b-serve-svc
    

    Le résultat ressemble à ce qui suit :

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

Diffuser le modèle

Les modèles Llama2 7B et Llama3 8B utilisent la spécification de chat de l'API OpenAI. Les autres modèles ne sont compatibles qu'avec la génération de texte, une technique qui génère du texte en fonction d'une requête.

Configurer le transfert de port

Configurez un transfert de port vers le serveur d'inférence :

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

Llama 2 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 avec le modèle à l'aide de curl

Utilisez curl pour discuter avec votre modèle :

Gemma 2B IT

Dans une nouvelle session 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

Dans une nouvelle session 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}'

Llama 2 7B

Dans une nouvelle session 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

Dans une nouvelle session 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

Dans une nouvelle session 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}'

Étant donné que les modèles que vous avez diffusés ne conservent aucun historique, chaque message et chaque réponse doivent être renvoyés au modèle pour créer une expérience de dialogue interactive. L'exemple suivant montre comment créer un dialogue interactif à l'aide du modèle Llama 3 8B :

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/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
}'

Le résultat ressemble à ce qui suit :

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

(Facultatif) Se connecter à l'interface de chat

Vous pouvez utiliser Gradio pour créer des applications Web qui vous permettent 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. Pour Llama 2 7B et Llama 3 7B, vous avez installé Gradio lorsque vous avez déployé le modèle LLM.

  1. Configurez le transfert de port vers le Service gradio :

    kubectl port-forward service/gradio 8080:8080 &
    
  2. Ouvrez http://localhost:8080 dans votre navigateur pour discuter avec le modèle.

Diffuser plusieurs modèles avec le multiplexage de modèles

Le multiplexage de modèles est une technique utilisée pour diffuser plusieurs modèles au sein du même cluster Ray. Vous pouvez acheminer le trafic vers des modèles spécifiques à l'aide d'en-têtes de requête ou en équilibrant la charge.

Dans cet exemple, vous allez créer une application Ray Serve multiplexée composée de deux modèles : Gemma 7B IT et Llama 3 8B.

  1. Déployez la ressource RayService :

    kubectl apply -f model-multiplexing/
    
  2. Attendez que la ressource RayService soit prête :

    kubectl get rayservice model-multiplexing -o yaml
    

    Le résultat ressemble à ce qui suit :

    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
    

    Dans ce résultat, status: RUNNING indique que la ressource RayService est prête.

  3. Vérifiez que GKE a créé le service Kubernetes pour l'application Ray Serve :

    kubectl get service model-multiplexing-serve-svc
    

    Le résultat ressemble à ce qui suit :

    NAME                           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    model-multiplexing-serve-svc   ClusterIP   34.118.226.104   <none>        8000/TCP   45m
    
  4. Configurez le transfert de port vers l'application Ray Serve :

    kubectl port-forward svc/model-multiplexing-serve-svc 8000:8000
    
  5. Envoyez une requête au modèle Gemma 7B IT :

    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}'
    

    Le résultat ressemble à ce qui suit :

    {"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. Envoyez une requête au modèle 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}'
    

    Le résultat ressemble à ce qui suit :

    {"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. Envoyez une requête à un modèle aléatoire en excluant l'en-tête 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}'
    

    La sortie est l'une des sorties des étapes précédentes.

Composez plusieurs modèles avec la composition de modèles

La composition de modèles est une technique qui permet de composer plusieurs modèles dans une seule application. La composition de modèles vous permet d'enchaîner des entrées et des sorties sur plusieurs LLM et d'adapter vos modèles en une seule application.

Dans cet exemple, vous allez composer deux modèles, Gemma 7B IT et Llama 3 8B, dans une seule application. Le premier modèle est le modèle d'assistant qui répond aux questions fournies dans l'invite. Le deuxième modèle est le modèle de résumé. La sortie du modèle d'assistant est associée à l'entrée du modèle de résumé. Le résultat final est la version résumée de la réponse du modèle d'assistant.

  1. Déployez la ressource RayService :

    kubectl apply -f model-composition/
    
  2. Attendez que la ressource RayService soit prête :

    kubectl get rayservice model-composition -o yaml
    

    Le résultat ressemble à ce qui suit :

    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
    

    Dans ce résultat, status: RUNNING indique que la ressource RayService est prête.

  3. Vérifiez que GKE a créé le service pour l'application Ray Serve :

    kubectl get service model-composition-serve-svc
    

    Le résultat ressemble à ce qui suit :

    NAME                           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    model-composition-serve-svc    ClusterIP   34.118.226.104   <none>        8000/TCP   45m
    
  4. Envoyez une requête au modèle :

    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. Le résultat ressemble à ce qui suit :

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

Supprimer le projet

  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.

Supprimer les ressources individuelles

Si vous avez utilisé un projet existant et que vous ne souhaitez pas le supprimer, vous pouvez supprimer les ressources individuelles.

  1. Supprimez le cluster à l'aide de la commande suivante :

    gcloud container clusters delete rayserve-cluster
    

Étape suivante