Ray を使用して L4 GPU で LLM を提供する


このガイドでは、Google Kubernetes Engine(GKE)で Ray と Ray Operator アドオンを使用して大規模言語モデル(LLM)を提供する方法について説明します。

このガイドでは、次のモデルを提供できます。

このガイドでは、Ray Serve フレームワークでサポートされているモデルの多重化やモデルの構成などのモデル サービング手法についても説明します。

背景

Ray フレームワークは、ML ワークロードのトレーニング、微調整、推論を行うエンドツーエンドの AI / ML プラットフォームを提供します。Ray Serve は、Hugging Face の一般的な LLM を提供するために使用できる Ray のフレームワークです。

GPU の数はモデルのデータ形式によって異なります。このガイドでは、モデルで 1 つまたは 2 つの L4 GPU を使用できます。

このガイドでは、次の手順を説明します。

  1. Ray Operator アドオンを有効にして、Autopilot または Standard GKE クラスタを作成します。
  2. Hugging Face から大規模言語モデル(LLM)をダウンロードして提供する RayService リソースをデプロイします。
  3. LLM でチャット インターフェースとダイアログをデプロイします。

始める前に

始める前に、次の作業が完了していることを確認してください。

  • Google Kubernetes Engine API を有効にする。
  • Google Kubernetes Engine API の有効化
  • このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化する。すでに gcloud CLI をインストールしている場合は、gcloud components update を実行して最新のバージョンを取得する。
  • Hugging Face アカウントを作成します(まだ作成していない場合)。
  • Hugging Face トークンがあることを確認します。
  • 使用する Hugging Face モデルにアクセスできることを確認します。通常、これは契約に署名し、Hugging Face モデルページでモデル所有者にアクセスをリクエストすることで付与されます。
  • us-central1 リージョンに GPU 割り当てがあることを確認します。詳細については、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 プロジェクト ID
    • CLUSTER_VERSION: 使用する GKE のバージョン。1.30.1 以降にする必要があります。
    • HUGGING_FACE_TOKEN: Hugging Face アクセス トークン。

クラスタと GPU ノードプールを作成する

Ray Operator アドオンを使用して、GKE Autopilot クラスタまたは Standard クラスタで Ray を使用して L4 GPU で LLM を提供できます。一般的に、フルマネージドの Kubernetes エクスペリエンスを実現するには、Autopilot クラスタを使用することをおすすめします。高い拡張性を必要とするユースケースや、クラスタ構成をより詳細に制御する必要がある場合は、Standard クラスタを選択します。ワークロードに最適な GKE の運用モードを選択するには、GKE の運用モードを選択するをご覧ください。

Cloud Shell を使用して、Autopilot クラスタまたは Standard クラスタを作成します。

Autopilot

Ray Operator アドオンを有効にして Autopilot クラスタを作成します。

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

Standard

Ray Operator アドオンを有効にして Standard クラスタを作成します。

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

Hugging Face の認証情報用の Kubernetes Secret を作成する

Cloud Shell で、次の手順で Kubernetes Secret を作成します。

  1. クラスタと通信を行うように kubectl を構成します。

    gcloud container clusters get-credentials ${CLUSTER_NAME} --location=${COMPUTE_REGION}
    
  2. Hugging Face トークンを含む Kubernetes Secret を作成します。

    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 モデル ID。
  • Ray クラスタ: 基盤となる Ray クラスタと、各コンポーネントに必要なリソース(ヘッド Pod とワーカー Pod を含む)。

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 アプリケーションの Service を作成したことを確認します。

    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 アプリケーションの Service を作成したことを確認します。

    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 アプリケーションの Service を作成したことを確認します。

    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 アプリケーションの Service を作成したことを確認します。

    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 アプリケーションの Service を作成したことを確認します。

    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/Llama-3-8b-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
    }'

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 は、chatbot のユーザー インターフェースを作成する ChatInterface ラッパーを含む Python ライブラリです。Llama 2 7B と Llama 3 7B の場合、LLM モデルをデプロイするときに Gradio をインストールしました。

  1. gradio Service へのポート転送を設定します。

    kubectl port-forward service/gradio 8080:8080 & 
    
  2. ブラウザで http://localhost:8080 を開き、モデルとチャットします。

モデルの多重化を使用して複数のモデルを提供する

モデルの多重化は、同じ Ray クラスタ内で複数のモデルを提供する手法です。リクエスト ヘッダーを使用するか、ロード バランシングを使用して、トラフィックを特定のモデルに転送できます。

この例では、Gemma 7B IT モデルと Llama 3 8B モデルの 2 つのモデルで構成される多重化された Ray Serve アプリケーションを作成します。

  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 が Ray Serve アプリケーションの Kubernetes Service を作成したことを確認します。

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

    出力は、前のステップの出力の 1 つです。

モデル構成で複数のモデルを作成する

モデル構成は、複数のモデルを 1 つのアプリケーションに作成するために使用される手法です。モデル構成を使用すると、複数の LLM にわたって入力と出力を連結し、モデルを単一のアプリケーションとしてスケーリングできます。

この例では、Gemma 7B IT モデルと Llama 3 8B モデルを 1 つのアプリケーションに作成します。最初のモデルは、プロンプトで提供された質問に回答するアシスタント モデルです。2 番目のモデルは、要約モデルです。アシスタント モデルの出力は、要約モデルの入力に連結されます。最終的な結果は、アシスタント モデルからのレスポンスの要約版です。

  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 アプリケーションの Service を作成したことを確認します。

    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. 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.

個々のリソースを削除する

使用している既存のプロジェクトを削除しない場合は、リソースを個別に削除できます。

  1. クラスタを削除します。

    gcloud container clusters delete rayserve-cluster
    

次のステップ