はじめに
こんにちはサイオステクノロジーの小野です。前回は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を導入してみた)
- データ接続設定済み
- 以前の記事を参考にしてください(OpenShift AIで機械学習をやってみた)
- 前回の機械学習サンプルプログラム実行済み
- 以前の記事を参考にしてください(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の項目から認証トークンの値が確認できます。
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インターフェース情報
インターフェース情報は以下のようになります:
- 内部公開用エンドポイント
- 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リクエストに対する構成図は以下のようになります:
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が正しい推論ができていることを示しています。
最後に
以上の手順によりOpenShift AIのモデルサービング設定を行い、推論APIを利用することができました。このようにモデルサービング機能を活用することで、簡単にモデルAPIを提供することが可能になります。このモデルサービング機能をぜひAIアプリケーション開発に役立ててください。
次回はパイプライン機能の解説を行う予定なので、そちらもよろしくお願いします。
参考
- モデルサービング設定:https://docs.redhat.com/ja/documentation/red_hat_openshift_ai_self-managed/2.13/html/serving_models/index
- OpenShift AIチュートリアル不正検出の例:https://docs.redhat.com/ja/documentation/red_hat_openshift_ai_self-managed/2.13/html/openshift_ai_tutorial_-_fraud_detection_example/deploying-and-testing-a-model
- 前回:OpenShift AIで機械学習をやってみた