OpenShift AIのモデルサービング機能について

はじめに

こんにちはサイオステクノロジーの小野です。前回はOpenShift AIのワークベンチを設定して、実際に機械学習を行いました。今回はOpenShift AIの主要な機能の一つであるモデルサービング機能を利用して、学習したモデルをAPIとして提供する方法を解説します。

モデルサービングとは

モデルサービングとは学習したモデルをモデルサーバーにデプロイすることで、推論APIとしてモデルを提供する機能です。

サービングの種類

OpenShiftAIではマルチモデルサービングとシングルモデルサービングという2つのモデルサービングプラットフォームを提供しています。

シングルモデルサービング

LLMなどの大規模モデル用のプラットフォームです。KServeコンポーネントをベースとしているため、OpenShift AIのほかにRed Hat OpenShift ServerlessとRed Hat OpenShift Service Meshのインストールをする必要があります。各モデルが独自のモデルサーバーからデプロイされるため、多くのリソースを必要とする大規模なモデルに適しています。

マルチモデルサービング

小規模および中規模モデル用のプラットフォームです。ModelMeshコンポーネントをベースとしています。同じモデルサーバーに複数のモデルをデプロイできます。

マルチモデルサービング実例

今回はマルチモデルサービングの設定をして、APIのリクエストを送るところまで解説します。マルチモデルサービングの一般的な構成図は以下のようになります:

マルチモデルサービングの構成図

モデルデプロイ

OpenShiftAIの設定

前提条件
  • OpenShift AI:2.13
  • データサイエンスプロジェクト作成済み
  • データ接続設定済み
  • 前回の機械学習サンプルプログラム実行済み
    • 以前の記事を参考にしてください(OpenShift AIで機械学習をやってみた
    • 実行済みだとS3内にtest-demo/models/mnist_model_latest.onnxというファイルが作成されます。このONNXファイルをデプロイします。

      今回デプロイするモデルデータ

モデルのデプロイ方法

モデルのデプロイ方法を説明します。データサイエンスプロジェクト内のModelsの項目に移動します。

最初にモデルサーバーの設定を行います。Add model serverを押下して以下の項目を入力してください:

  • Model server name:test-serving
  • Serving runtime:OpenVINO Model Server
  • Number of model server replicas to deploy:1
  • Model server size:small
  • Accelerator:NVIDIA GPU(GPUがない場合None)
  • Number of accelerators:1(GPUがある場合設定する)
  • Make deployed models available through an external route:✅(APIを外部公開するかどうかの設定)
  • Require token authentication:✅(認証トークンを利用するかどうかの設定。外部公開する場合必須。)
    • Service account name:トークン名

モデルサーバー設定

以上を設定することでモデルサーバーを立ち上げることができます。また、Tokensの項目から認証トークンの値が確認できます。

モデルサーバー設定後画面

Tokensを押下すると、認証トークンのシークレットが確認できる

deploy modelを押下することでモデルのデプロイ設定を行います:

  • Model name:test-onnx
  • Model framework(name – version):onnx-1
  • Existing data connection:✅
    • Name:test-connection(設定したデータ接続名を選択)
    • Path:test-demo/models/mnist_model_latest.onnx

モデルデプロイ設定

設定後、statusが✅になればデプロイ完了です。エンドポイントが表示されるので、以降のAPIリクエストする手順で用いるためメモしておいてください。

モデルデプロイ設定後画面。ここからAPIエンドポイントを確認できる。

APIインターフェース情報

インターフェース情報は以下のようになります:

  • 内部公開用エンドポイント
    • gRPC用エンドポイント:grpc://modelmesh-serving.<プロジェクト名>:8033
    • rest用エンドポイント:http://modelmesh-serving.<プロジェクト名>:8008
  • 外部公開エンドポイント:https://<モデル名>-<プロジェクト名>.apps.<クラスタードメイン>/v2/models/<モデル名>/infer
  • リクエストヘッダー
    • {
          "Content-Type": "application/json",
          "Authorization": "Bearer {トークンのシークレット}"
      }
  • リクエストボディ
    • {
          "model_name": {モデル名},
          "inputs": [
              {
                  "name": {入力名},
                  "shape": {入力するデータの形},
                  "datatype": {入力するデータの型},
                  "data": {リクエストを送るデータの値}
              }
          ]
      }
      
  • レスポンス
    • {
          "model_name": {モデル名},
          "model_version": {モデルのバージョン},
          "outputs": [
              {
                  "name": {出力名},
                  "datatype": {出力するデータの型},
                  "shape": {出力するデータの形},
                  "data": {レスポンスとして返ってきた推論の値}
              }
          ]
      }
      

APIリクエスト手順

前回のMNISTの画像を識別するモデルを例にAPIリクエストを行います。

curlでAPI情報確認

APIリクエストを送る手順を説明します。以降に説明するコマンドやコードはOpenShift AIワークベンチのJupyterNotebookで実行することを想定します。

リクエストを送る前にcurlでAPI情報を確認します。エンドポイントの末尾/inferを削除したURLに対してcurlコマンドを実施します。<token>の部分には実際の認証トークンの値を入れてください。

curl -ks https://test-onnx-test-ai.apps.<クラスタードメイン>/v2/models/test-onnx -H 'Authorization: Bearer <token>' | jq

curlの結果が以下のようになります。結果からモデルAPIの情報を確認することができます。

{
  "name": "test-onnx__isvc-045f6c46c3",
  "versions": [
    "1"
  ],
  "platform": "OpenVINO",
  "inputs": [
    {
      "name": "input",
      "datatype": "FP32",
      "shape": [
        "-1",
        "1",
        "28",
        "28"
      ]
    }
  ],
  "outputs": [
    {
      "name": "output",
      "datatype": "FP32",
      "shape": [
        "-1",
        "10"
      ]
    }
  ]
}

PythonコードでAPIリクエスト実行

実際にリクエストを送るPythonコードを以下に示します。<クラスタードメイン>の部分にはクラスタードメインを入力してください。またはinfer_url変数にモデルAPI設定後に表示されてメモしたエンドポイントを入力してください。<token>の部分には実際の認証トークンの値を入れてください。

また、APIリクエストに対する構成図は以下のようになります:

PythonコードによるAPIリクエスト実行の構成図

import numpy as np
import torchvision.transforms as transforms
from torchvision.datasets import MNIST
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import requests

def load_mnist_image():
    transform = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.5,), (0.5,))
    ])

    mnist_dataset = MNIST(root='./data', train=False, download=True, transform=transform)
    dataloader = DataLoader(mnist_dataset, batch_size=5, shuffle=True)

    images, labels = next(iter(dataloader))
    return images.numpy(), labels.numpy()

def show_image(image):
    # 画像を表示
    plt.imshow(image.squeeze(), cmap='gray')
    plt.title("MNIST Image")
    plt.show()

deployed_model_name = "test-onnx"
# クラスタードメインの値を入れる
infer_endpoint = "https://test-onnx-test-ai.apps.<クラスタードメイン>"
infer_url = f"{infer_endpoint}/v2/models/{deployed_model_name}/infer"
# トークンの値を入れる
token = ""


def rest_request(data):
    # NumPy配列をリストに変換
    data_list = data.flatten().tolist()
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {token}"
            }
    json_data = {
        "model_name": deployed_model_name,
        "inputs": [
            {
                "name": "input",
                "shape": [1, 1, 28, 28],
                "datatype": "FP32",
                "data": data_list
            }
        ]
    }

    response = requests.post(infer_url, headers=headers, json=json_data, verify=True)
    response.raise_for_status()  # HTTPエラーが発生した場合に例外をスロー
    response_dict = response.json()
    return response_dict['outputs'][0]['data']

# MNISTデータセットから画像を読み込む
data, label = load_mnist_image()

for i in range(5):
    # 画像を表示
    show_image(data[i])

    # RESTAPIリクエストの送信
    result = rest_request(data[i])
    predicted_label = np.argmax(result)

    print("Inference result:", result)
    print("Predicted label:", predicted_label)
    print("Actual label:", label[i])

実行した結果が以下になります。MNIST Imageという画像はAPIにリクエストとして送った画像になります。Inference resultが実際にAPIからレスポンスとして返ってきた結果です。10個の値は画像が0~9のどの数字に該当するかスコアを示しています。例えば0番目の値が最も高い値になっていれば、モデルAPIはリクエストとして受け取った画像を0の可能性が一番高いと推論を行ったことを示しています。Predicted labelはInference resultの中で最も高いスコアの数字です。すなわちモデルAPIがリクエストとして受け取った画像がどの数字であるかを推論したか示しています。Actual labelはリクエストとして送った画像が実際にはどの数字なのかを示しています。Predicted labelとActual labelが一致していればモデルAPIが正しい推論ができていることを示しています。

モデルAPIの推論結果

最後に

以上の手順によりOpenShift AIのモデルサービング設定を行い、推論APIを利用することができました。このようにモデルサービング機能を活用することで、簡単にモデルAPIを提供することが可能になります。このモデルサービング機能をぜひAIアプリケーション開発に役立ててください。

次回はパイプライン機能の解説を行う予定なので、そちらもよろしくお願いします。

参考

 

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です