הפעלת מודל 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
  • כדי להשתמש ב-CLI של Google Cloud למשימה הזו, צריך להתקין ואז להפעיל את gcloud CLI. אם התקנתם בעבר את ה-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 מנוהלת באופן מלא. אם תרחיש השימוש שלכם דורש יכולת הרחבה גבוהה או אם אתם רוצים יותר שליטה בהגדרת האשכול, כדאי לבחור באשכול רגיל. כדי לבחור את מצב הפעולה של 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
  }
}

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

אתם יכולים להשתמש ב-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 בדפדפן כדי לשוחח עם המודל.

הצגת כמה מודלים באמצעות מודל מולטיפלקס

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

בדוגמה הזו, יוצרים אפליקציית 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, לאפליקציה אחת. המודל הראשון הוא מודל העוזר הדיגיטלי שמשיב על שאלות שמופיעות בהנחיה. המודל השני הוא מודל הסיכום. הפלט של מודל ה-Assistant משורשר לקלט של מודל המסכם. התוצאה הסופית היא גרסה מסוכמת של התשובה מהמודל של העוזר הדיגיטלי.

  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
    

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