הפעלת מודל LLM במעבדי L4 GPU באמצעות Ray

במדריך הזה נדגים איך להשתמש ב-Ray ובתוסף Ray Operator כדי להפעיל מודלים גדולים של שפה (LLM) ב-Google Kubernetes Engine ‏ (GKE). המסגרת Ray מספקת פלטפורמת AI/ML מקצה לקצה לאימון, לאימון מדויק ולמסקנות של עומסי עבודה של למידת מכונה. ‫Ray Serve הוא framework ב-Ray שאפשר להשתמש בו כדי להפעיל מודלים פופולריים של LLM מ-Hugging Face.

לפני שקוראים את המדריך הזה, חשוב לוודא שמכירים את המודל שרוצים להפעיל במדריך הזה. אפשר להפעיל כל אחד מהמודלים הבאים:

הדף הזה מיועד למהנדסי למידת מכונה (ML) ולאדמינים ומפעילים של פלטפורמות שמנהלים עומסי עבודה של ML. מידע נוסף על תפקידים נפוצים ומשימות לדוגמה שאנחנו מתייחסים אליהם ב Google Cloud תוכן זמין במאמר תפקידים נפוצים של משתמשים ומשימות ב-GKE.

המדריך הזה כולל את השלבים הבאים:

  1. יוצרים אשכול GKE במצב Autopilot או במצב Standard עם התוסף Ray Operator מופעל.
  2. פריסת משאב RayService שמוריד ומציג מודל שפה גדול (LLM) מ-Hugging Face.
  3. פריסת ממשק צ'אט ודיאלוג עם מודלים של LLM.

לפני שמתחילים

לפני שמתחילים, חשוב לוודא שביצעתם את המשימות הבאות:

  • מפעילים את Google Kubernetes Engine API.
  • הפעלת Google Kubernetes Engine API
  • כדי להשתמש ב-Google Cloud CLI למשימה הזו, מתקינים ואז מאתחלים את ה-CLI של gcloud. אם התקנתם בעבר את ה-CLI של gcloud, מריצים את הפקודה gcloud components update כדי לקבל את הגרסה העדכנית. יכול להיות שגרסאות קודמות של ה-CLI של gcloud לא יתמכו בהרצת הפקודות שמופיעות במסמך הזה.
  • אם אין לכם חשבון ב-Hugging Face, יוצרים חשבון.
  • מוודאים שיש לכם טוקן של Hugging Face.
  • מוודאים שיש לכם גישה למודל Hugging Face שבו אתם רוצים להשתמש. בדרך כלל מקבלים את ההרשאה הזו על ידי חתימה על הסכם ושליחת בקשת גישה מבעלי המודל בדף המודל ב-Hugging Face.
  • מוודאים שיש לכם מכסת GPU באזור us-central1. מידע נוסף זמין במאמר בנושא מכסת GPU.

הכנת הסביבה

  1. במסוף Google Cloud , מפעילים מכונה של Cloud Shell:
    פתיחת Cloud Shell

  2. משכפלים את המאגר לדוגמה:

    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. מגדירים את משתני הסביבה שמוגדרים כברירת מחדל:

    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
    

    מחליפים את מה שכתוב בשדות הבאים:

    • ‫PROJECT_ID: מזהה הפרויקט ב- Google Cloud.
    • ‫CLUSTER_VERSION: גרסת GKE לשימוש. הגרסה צריכה להיות 1.30.1 ואילך.
    • ‫HUGGING_FACE_TOKEN: טוקן הגישה שלכם ל-Hugging Face.

יצירת אשכול עם מאגר צמתים של GPU

אתם יכולים להפעיל מודל שפה גדול (LLM) במעבדי GPU מסוג L4 באמצעות Ray באשכול GKE Autopilot או באשכול רגיל באמצעות התוסף Ray Operator. באופן כללי, מומלץ להשתמש באשכול Autopilot כדי ליהנות מחוויית Kubernetes מנוהלת באופן מלא. אם תרחיש השימוש שלכם דורש יכולת התאמה גבוהה או אם אתם רוצים יותר שליטה על הגדרת האשכול, כדאי לבחור באשכול Standard. כדי לבחור את מצב ההפעלה של GKE שהכי מתאים לעומסי העבודה שלכם, קראו את המאמר בחירת מצב הפעלה של GKE.

משתמשים ב-Cloud Shell כדי ליצור אשכול Autopilot או אשכול רגיל:

טייס אוטומטי

יוצרים אשכול Autopilot עם התוסף Ray Operator מופעל:

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

רגילה

יוצרים אשכול רגיל עם תוסף Ray Operator מופעל:

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

יצירת סוד של Kubernetes לפרטי הכניסה של Hugging Face

ב-Cloud Shell, יוצרים סוד של Kubernetes:

  1. מגדירים את kubectl כדי לתקשר עם האשכול:

    gcloud container clusters get-credentials ${CLUSTER_NAME} --location=${COMPUTE_REGION}
    
  2. יוצרים סוד של Kubernetes שמכיל את הטוקן של Hugging Face:

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

פריסת מודל LLM

מאגר GitHub ששיבטתם כולל ספריה לכל מודל, שכוללת הגדרה של RayService. ההגדרה של כל מודל כוללת את הרכיבים הבאים:

  • פריסת Ray Serve: פריסת Ray Serve, שכוללת הגדרת משאבים ויחסי תלות בזמן ריצה.
  • מודל: מזהה המודל של Hugging Face.
  • אשכול Ray: אשכול Ray הבסיסי והמשאבים שנדרשים לכל רכיב, כולל Pods של ראש ושל עובד.

Gemma 2B IT

  1. פורסים את המודל:

    kubectl apply -f gemma-2b-it/
    
  2. מחכים שהמשאב של RayService יהיה מוכן:

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

    הפלט אמור להיראות כך:

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

    בפלט הזה, status: RUNNING מציין שהמשאב RayService מוכן.

  3. מוודאים ש-GKE יצר את השירות לאפליקציית Ray Serve:

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

    הפלט אמור להיראות כך:

    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. פורסים את המודל:

    kubectl apply -f gemma-7b-it/
    
  2. מחכים שהמשאב של RayService יהיה מוכן:

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

    הפלט אמור להיראות כך:

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

    בפלט הזה, status: RUNNING מציין שהמשאב RayService מוכן.

  3. מוודאים ש-GKE יצר את השירות לאפליקציית Ray Serve:

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

    הפלט אמור להיראות כך:

    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. פורסים את המודל:

    kubectl apply -f llama-2-7b/
    
  2. מחכים שהמשאב של RayService יהיה מוכן:

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

    הפלט אמור להיראות כך:

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

    בפלט הזה, status: RUNNING מציין שהמשאב RayService מוכן.

  3. מוודאים ש-GKE יצר את השירות לאפליקציית Ray Serve:

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

    הפלט אמור להיראות כך:

    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. פורסים את המודל:

    kubectl apply -f llama-3-8b/
    
  2. מחכים שהמשאב של RayService יהיה מוכן:

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

    הפלט אמור להיראות כך:

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

    בפלט הזה, status: RUNNING מציין שהמשאב RayService מוכן.

  3. מוודאים ש-GKE יצר את השירות לאפליקציית Ray Serve:

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

    הפלט אמור להיראות כך:

    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. פורסים את המודל:

    kubectl apply -f mistral-7b/
    
  2. מחכים שהמשאב של RayService יהיה מוכן:

    kubectl get rayservice mistral-7b -o yaml
    

    הפלט אמור להיראות כך:

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

    בפלט הזה, status: RUNNING מציין שהמשאב RayService מוכן.

  3. מוודאים ש-GKE יצר את השירות לאפליקציית Ray Serve:

    kubectl get service mistral-7b-serve-svc
    

    הפלט אמור להיראות כך:

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

פרסום המודל

המודלים Llama2 7B ו-Llama3 8B משתמשים במפרט הצ'אט של OpenAI API. המודלים האחרים תומכים רק ביצירת טקסט, שהיא טכניקה ליצירת טקסט על סמך הנחיה.

הגדרת העברה ליציאה אחרת

מגדירים העברה ליציאה אחרת לשרת ההסקה:

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

אינטראקציה עם המודל באמצעות curl

משתמשים ב-curl כדי לשוחח עם המודל:

Gemma 2B IT

בסשן חדש של מסוף:

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

בסשן חדש של הטרמינל:

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

בסשן חדש של מסוף:

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

בסשן חדש של מסוף:

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

בסשן חדש של מסוף:

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 3 8B:

יוצרים דיאלוג עם המודל באמצעות 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
}'

הפלט אמור להיראות כך:

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

(אופציונלי) התחברות לממשק הצ'אט

אתם יכולים להשתמש ב-Gradio כדי ליצור אפליקציות אינטרנט שמאפשרות לכם לקיים אינטראקציה עם המודל. ‫Gradio היא ספריית Python שיש לה wrapper ‏ChatInterface שיוצר ממשקי משתמש לצ'אטבוטים. במקרה של Llama 2 7B ו-Llama 3 7B, התקנתם את Gradio כשפרסתם את מודל ה-LLM.

  1. מגדירים העברה ליציאה אחרת לשירות gradio:

    kubectl port-forward service/gradio 8080:8080 &
    
  2. פותחים את http://localhost:8080 בדפדפן כדי לשוחח עם המודל.

הצגת כמה מודלים באמצעות ריבוב מודלים

Multiplexing מודלים היא טכניקה שמשמשת להכניס לשימוש בסביבת הייצור כמה מודלים באותו אשכול Ray. אפשר להפנות תעבורת נתונים למודלים ספציפיים באמצעות request header או באמצעות איזון עומסים.

בדוגמה הזו, יוצרים אפליקציית Ray Serve מרובת ערוצים שמורכבת משני מודלים: Gemma 7B IT ו-Llama 3 8B.

  1. פורסים את המשאב של RayService:

    kubectl apply -f model-multiplexing/
    
  2. מחכים עד שהמשאב RayService יהיה מוכן:

    kubectl get rayservice model-multiplexing -o yaml
    

    הפלט אמור להיראות כך:

    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
    

    בפלט הזה, הערך status: RUNNING מציין שהמשאב של RayService מוכן.

  3. מאשרים ש-GKE יצר את שירות Kubernetes לאפליקציית Ray Serve:

    kubectl get service model-multiplexing-serve-svc
    

    הפלט אמור להיראות כך:

    NAME                           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    model-multiplexing-serve-svc   ClusterIP   34.118.226.104   <none>        8000/TCP   45m
    
  4. מגדירים העברה ליציאה אחרת לאפליקציית Ray Serve:

    kubectl port-forward svc/model-multiplexing-serve-svc 8000:8000
    
  5. שליחת בקשה למודל 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}'
    

    הפלט אמור להיראות כך:

    {"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. שליחת בקשה למודל 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}'
    

    הפלט אמור להיראות כך:

    {"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. שליחת בקשה למודל אקראי על ידי החרגת הכותרת 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}'
    

    הפלט הוא אחד מהפלטים מהשלבים הקודמים.

שילוב של כמה מודלים באמצעות הרכבת מודלים

הרכבת מודלים היא טכניקה שמשמשת להרכבת כמה מודלים לאפליקציה אחת. הרכבת מודלים מאפשרת לכם לשרשר קלט ופלט בין כמה מודלים גדולים של שפה (LLM) ולהרחיב את המודלים שלכם כאפליקציה אחת.

בדוגמה הזו, אתם יוצרים קומפוזיציה של שני מודלים, Gemma 7B IT ו-Llama 3 8B, לאפליקציה אחת. המודל הראשון הוא מודל העוזר הדיגיטלי שמשיב על שאלות שמופיעות בהנחיה. המודל השני הוא מודל הסיכום. הפלט של מודל העוזר הדיגיטלי משורשר לקלט של מודל הסיכום. התוצאה הסופית היא גרסה מסוכמת של התשובה מהמודל של העוזר הדיגיטלי.

  1. פורסים את המשאב של RayService:

    kubectl apply -f model-composition/
    
  2. מחכים עד שהמשאב RayService יהיה מוכן:

    kubectl get rayservice model-composition -o yaml
    

    הפלט אמור להיראות כך:

    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
    

    בפלט הזה, status: RUNNING מציין שהמשאב RayService מוכן.

  3. מאשרים ש-GKE יצר את השירות לאפליקציית Ray Serve:

    kubectl get service model-composition-serve-svc
    

    הפלט אמור להיראות כך:

    NAME                           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    model-composition-serve-svc    ClusterIP   34.118.226.104   <none>        8000/TCP   45m
    
  4. שליחת בקשה למודל:

    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. הפלט אמור להיראות כך:

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

מחיקת הפרויקט

  1. במסוף Google Cloud , נכנסים לדף Manage resources.

    כניסה לדף Manage resources

  2. ברשימת הפרויקטים, בוחרים את הפרויקט שרוצים למחוק ולוחצים על Delete.
  3. כדי למחוק את הפרויקט, כותבים את מזהה הפרויקט בתיבת הדו-שיח ולוחצים על Shut down.

מחיקת המשאבים הנפרדים

אם השתמשתם בפרויקט קיים ואתם לא רוצים למחוק אותו, אתם יכולים למחוק את המשאבים הבודדים.

  1. מחיקת האשכול:

    gcloud container clusters delete rayserve-cluster
    

המאמרים הבאים