すべてのプロダクト
Search
ドキュメントセンター

Alibaba Cloud Service Mesh:LLM を推論サービスとして使用する

最終更新日:Jan 13, 2025

大規模言語モデル(LLM)とは、Generative Pre-Trained Transformer 3(GPT-3)、GPT-4、Pathways Language Model(PaLM)、PaLM 2 など、数億のパラメーターを持つニューラルネットワーク言語モデルを指します。大量の自然言語データを処理する必要がある場合、または複雑な言語理解システムを構築する場合、LLM を推論サービスとして使用し、API を呼び出すことで、テキスト分類、感情分析、機械翻訳などの高度な自然言語処理(NLP)機能をアプリケーションに簡単に統合できます。 LLM-as-a-service モードでは、高額なインフラストラクチャコストを支払う必要がなく、市場の変化に迅速に対応できます。さらに、LLM はクラウド上で実行されるため、ユーザーリクエストの急増に対応するためにいつでもサービスを拡張し、運用効率を向上させることができます。

前提条件

ステップ 1:カスタムランタイムを構築する

プロンプトチューニング構成で Hugging Face LLM を提供するカスタムランタイムを構築します。この例では、デフォルト値は、事前に構築されたカスタムランタイムイメージと事前に構築されたプロンプトチューニング構成に設定されています。

  1. MLServer の MLModel クラスを継承するクラスを実装します。

    peft_model_server.py ファイルには、プロンプトチューニング構成の Hugging Face LLM がどのように提供されるかについてのすべてのコードが含まれています。ファイル内の _load_model 関数は、トレーニングされた PEFT プロンプトチューニング構成で事前トレーニング済み LLM モデルを選択するために使用されます。 _load_model 関数は、ユーザーに推論リクエストからの生の文字列入力をテンソルバイトに前処理するように要求することなく、エンコードおよびデコードできるトークナイザーも定義します。

    peft_model_server.py ファイルを表示する

    from typing import List
    
    from mlserver import MLModel, types
    from mlserver.codecs import decode_args
    
    from peft import PeftModel, PeftConfig
    from transformers import AutoModelForCausalLM, AutoTokenizer
    import torch
    import os
    
    class PeftModelServer(MLModel):
        async def load(self) -> bool:
            # モデルをロードします
            self._load_model()
            self.ready = True
            return self.ready
    
        @decode_args
        async def predict(self, content: List[str]) -> List[str]:
            return self._predict_outputs(content)
    
        def _load_model(self):
            # 事前トレーニング済みモデルのパスを取得します。デフォルトは "bigscience/bloomz-560m" です。
            model_name_or_path = os.environ.get("PRETRAINED_MODEL_PATH", "bigscience/bloomz-560m")
            # PEFT モデル ID を取得します。デフォルトは "aipipeline/bloomz-560m_PROMPT_TUNING_CAUSAL_LM" です。
            peft_model_id = os.environ.get("PEFT_MODEL_ID", "aipipeline/bloomz-560m_PROMPT_TUNING_CAUSAL_LM")
            # トークナイザーを初期化します
            self.tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, local_files_only=True)
            # PEFT 構成をロードします
            config = PeftConfig.from_pretrained(peft_model_id)
            # 事前トレーニング済みモデルをロードします
            self.model = AutoModelForCausalLM.from_pretrained(config.base_model_name_or_path)
            # PEFT モデルをロードします
            self.model = PeftModel.from_pretrained(self.model, peft_model_id)
            # データセットのテキスト列名を取得します。デフォルトは "Tweet text" です。
            self.text_column = os.environ.get("DATASET_TEXT_COLUMN_NAME", "Tweet text")
            return
    
        def _predict_outputs(self, content: List[str]) -> List[str]:
            output_list = []
            for input in content:
                # 入力テキストをトークン化します
                inputs = self.tokenizer(
                    f'{self.text_column} : {input} Label : ',
                    return_tensors="pt",
                )
                with torch.no_grad():
                    inputs = {k: v for k, v in inputs.items()}
                    # モデルを使用してテキストを生成します
                    outputs = self.model.generate(
                        input_ids=inputs["input_ids"], attention_mask=inputs["attention_mask"], max_new_tokens=10, eos_token_id=3
                    )
                    # 生成されたテキストをデコードします
                    outputs = self.tokenizer.batch_decode(outputs.detach().cpu().numpy(), skip_special_tokens=True)
                output_list.append(outputs[0])
            return output_list
    
  2. Docker イメージをビルドします。

    モデルクラスを実装した後、MLServer を含むその依存関係を、ServingRuntime リソースとしてサポートされているイメージにパッケージ化する必要があります。次の Dockerfile を参照してイメージをビルドできます。

    Dockerfile を表示する

    # TODO: 適切なベースイメージを選択し、Python、MLServer、および
    # MLModel 実装の依存関係をインストールします
    FROM python:3.8-slim-buster
    RUN pip install mlserver peft transformers datasets
    # ...
    
    # カスタム `MLModel` 実装は、イメージの作業ディレクトリに依存するのではなく、Python 検索パス上にある必要があります。
    # 単一ファイルモジュールを使用する場合、これは次のように実現できます。
    COPY --chown=${USER} ./peft_model_server.py /opt/peft_model_server.py
    ENV PYTHONPATH=/opt/
    
    # ModelMesh Serving と互換性のある環境変数
    # これらは ServingRuntime でも設定できますが、ビルド時とテスト時の一貫性のためにこれが推奨されます
    ENV MLSERVER_MODELS_DIR=/models/_mlserver_models \
        MLSERVER_GRPC_PORT=8001 \
        MLSERVER_HTTP_PORT=8002 \
        MLSERVER_LOAD_MODELS_AT_STARTUP=false \
        MLSERVER_MODEL_NAME=peft-model
    
    # この設定では、実装フィールドはモデル設定で必須ではなくなり、組み込みアダプターが基本的なモデル設定ファイルを生成できるようにすることで統合が容易になります
    ENV MLSERVER_MODEL_IMPLEMENTATION=peft_model_server.PeftModelServer
    
    CMD mlserver start ${MLSERVER_MODELS_DIR}
    
  3. 新しい ServingRuntime リソースを作成します。

    1. 次のコンテンツを使用して新しい ServingRuntime リソースを作成し、作成したイメージを指します。

      YAML ファイルを表示する

      apiVersion: serving.kserve.io/v1alpha1
      kind: ServingRuntime
      metadata:
        name: peft-model-server
        namespace: modelmesh-serving
      spec:
        supportedModelFormats:
          - name: peft-model
            version: "1"
            autoSelect: true
        multiModel: true
        grpcDataEndpoint: port:8001
        grpcEndpoint: port:8085
        containers:
          - name: mlserver
            image:  registry.cn-beijing.aliyuncs.com/test/peft-model-server:latest
            env:
              - name: MLSERVER_MODELS_DIR
                value: "/models/_mlserver_models/"
              - name: MLSERVER_GRPC_PORT
                value: "8001"
              - name: MLSERVER_HTTP_PORT
                value: "8002"
              - name: MLSERVER_LOAD_MODELS_AT_STARTUP
                value: "true"
              - name: MLSERVER_MODEL_NAME
                value: peft-model
              - name: MLSERVER_HOST
                value: "127.0.0.1"
              - name: MLSERVER_GRPC_MAX_MESSAGE_LENGTH
                value: "-1"
              - name: PRETRAINED_MODEL_PATH
                value: "bigscience/bloomz-560m"
              - name: PEFT_MODEL_ID
                value: "aipipeline/bloomz-560m_PROMPT_TUNING_CAUSAL_LM"
              # - name: "TRANSFORMERS_OFFLINE"
              #   value: "1"  
              # - name: "HF_DATASETS_OFFLINE"
              #   value: "1"    
            resources:
              requests:
                cpu: 500m
                memory: 4Gi
              limits:
                cpu: "5"
                memory: 5Gi
        builtInAdapter:
          serverType: mlserver
          runtimeManagementPort: 8001
          memBufferBytes: 134217728
          modelLoadingTimeoutMillis: 90000
      
    2. 次のコマンドを実行して、ServingRuntime リソースをデプロイします。

      kubectl apply -f sample-runtime.yaml

      ServingRuntime リソースを作成した後、ModelMesh デプロイメントで新しいカスタムランタイムを確認できます。

ステップ 2:LLM サービスをデプロイする

新しく作成したランタイムを使用してモデルをデプロイするには、モデルを提供する InferenceService リソースを作成する必要があります。このリソースは、KServe および ModelMesh がモデルを管理するために使用するメインインターフェースです。これは、推論を提供するためのモデルの論理エンドポイントを表します。

  1. 次のコンテンツを使用して、モデルを提供する InferenceService リソースを作成します。

    YAML ファイルを表示する

    apiVersion: serving.kserve.io/v1beta1
    kind: InferenceService
    metadata:
      name: peft-demo
      namespace: modelmesh-serving
      annotations:
        serving.kserve.io/deploymentMode: ModelMesh
    spec:
      predictor:
        model:
          modelFormat:
            name: peft-model
          runtime: peft-model-server
          storage:
            key: localMinIO
            path: sklearn/mnist-svm.joblib
    

    YAML ファイルでは、InferenceService リソースの名前は peft-demo で、そのモデル形式は peft-model として宣言されています。これは、前のステップで作成したカスタムランタイムの例と同じ形式です。オプションのフィールド runtime も渡され、ModelMesh に peft-model-server ランタイムを使用してこのモデルをデプロイするように明示的に指示します。

  2. 次のコマンドを実行して、InferenceService リソースをデプロイします。

    kubectl apply -f ${YAML ファイルの名前}.yaml

ステップ 3:推論を実行する

curl コマンドを実行して、前のステップでデプロイされた LLM サービスに推論リクエストを送信します。

MODEL_NAME="peft-demo"
ASM_GW_IP="イングレスゲートウェイの IP アドレス"
curl -X POST -k http://${ASM_GW_IP}:8008/v2/models/${MODEL_NAME}/infer -d @./input.json

curl コマンドの input.json はリクエストデータを示します。

{
    "inputs": [
        {
          "name": "content",
          "shape": [1],
          "datatype": "BYTES",
          "contents": {"bytes_contents": ["RXZlcnkgZGF5IGlzIGEgbmV3IGJpbm5pbmcsIGZpbGxlZCB3aXRoIG9wdGlvbnBpZW5pbmcgYW5kIGhvcGU="]}
        }
    ]
}

bytes_contents の値は、文字列 "Every day is a new beginning, filled with opportunities and hope" の Base64 エンコードされたコンテンツです。

次のコードブロックは JSON レスポンスを示しています。

{
 "modelName": "peft-demo__isvc-5c5315c302",
 "outputs": [
  {
   "name": "output-0",
   "datatype": "BYTES",
   "shape": [
    "1",
    "1"
   ],
   "parameters": {
    "content_type": {
     "stringParam": "str"
    }
   },
   "contents": {
    "bytesContents": [
     "VHdlZXQgdGV4dCA6IEV2ZXJ5IGRheSBpcyBhIG5ldyBiaW5uaW5nLCBmaWxsZWQgd2l0aCBvcHRpb25waWVuaW5nIGFuZCBob3BlIExhYmVsIDogbm8gY29tcGxhaW50"
    ]
   }
  }
 ]
}

次のコードブロックは、bytesContents の Base64 デコードされたコンテンツを示しています。これは、推論リクエストが期待どおりに LLM サービスで実行されたことを示しています。

Tweet text : Every day is a new binning, filled with optionpiening and hope Label : no complaint