モデルサービスが最初のリクエストを受信した際、ランタイムは初期化を遅延させることがあります。これには、モデルファイルの読み込み、グラフ操作の JIT コンパイル、Java 仮想マシン (JVM) のコールドスタートなどが含まれます。この初期化の遅延により、最初のリクエストでレイテンシーが増加したり、408 タイムアウトや 450 エラーが発生したりする可能性があります。
Platform for AI (PAI) の Elastic Algorithm Service (EAS) が提供するモデルウォームアップ機能は、このコールドスタートによるレイテンシーを解消します。EAS は、モデルサービスが公開される前に、サービスエンジンにウォームアップリクエストを送信します。モデルサービスは、これらのウォームアップリクエストが正常に送信された後にのみ、完全に起動したと見なされます。
仕組み
ウォームアップのフローは以下の通りです:
-
EAS SDK を使用してウォームアップリクエストファイルを生成します。
-
ファイルを Object Storage Service (OSS) にアップロードします。
-
モデルサービスの JSON 構成でこのファイルを参照します。
-
サービスをデプロイまたは更新します。EAS は起動時にウォームアップリクエストを自動的に送信します。
前提条件
開始する前に、以下のものが揃っていることを確認してください:
-
ウォームアップリクエストファイルを保存するための OSS バケット
-
インストール済みの Python SDK または Java SDK
-
デプロイ済みまたはデプロイ準備が整った EAS モデルサービス
ウォームアップリクエストファイルの生成
ウォームアップリクエストファイルには、実際の本番トラフィックを代表する 1 つ以上のサンプルリクエストが含まれます。EAS は起動時にこれらのリクエストを再生して、モデルを初期化します。
2 つのファイル形式がサポートされています:
-
バイナリ (`.bin`): TensorFlow やその他の構造化入力モデル用です。EAS SDK を使用して作成します。
-
テキスト (`.txt`): 文字列入力モデル用です。各行が 1 つのリクエストになります。EAS は形式を自動的に検出します。
ウォームアップリクエストの入力と出力は、本番環境で使用されるものと完全に一致する必要があります。入力または出力に違いがあると、TensorFlow はモデルファイルを再読み込みするため、ウォームアップの目的が損なわれます。
以下の例は、TensorFlow モデル用の .bin 形式のウォームアップリクエストファイルの作成方法を示しています。
Python SDK の使用
#!/usr/bin/env python
from eas_prediction import TFRequest
# 本番リクエストと完全に一致するウォームアップリクエストを作成します。
# 入力と出力は、サービス公開後に使用されるものと同一でなければなりません。
req = TFRequest('serving_default')
req.add_feed('sentence1', [200, 15], TFRequest.DT_INT32, [1] * 200 * 15)
req.add_feed('sentence2', [200, 15], TFRequest.DT_INT32, [1] * 200 * 15)
req.add_feed('y', [200, 2], TFRequest.DT_INT32, [2] * 200 * 2)
req.add_feed('keep_rate', [], TFRequest.DT_FLOAT, [0.2])
req.add_feed('images', [1, 784], TFRequest.DT_FLOAT, [1] * 784)
req.add_fetch('sorted_labels')
req.add_fetch('sorted_probs')
# ウォームアップリクエストをバイナリファイルに保存します。
with open("warm_up.bin", "wb") as fw:
fw.write(req.to_string())
Java SDK の使用
eas-sdk 依存関係を pom.xml に追加します:
<dependency>
<groupId>com.aliyun.openservices.eas</groupId>
<artifactId>eas-sdk</artifactId>
<version>2.0.13</version>
</dependency>
最新バージョンについては、Maven リポジトリで確認してください。
import java.io.File;
import com.aliyun.openservices.eas.predict.request.TFDataType;
import com.aliyun.openservices.eas.predict.request.TFRequest;
import org.apache.commons.io.FileUtils;
public class TestTf {
public static void main(String[] args) throws Exception {
// 本番リクエストと完全に一致するウォームアップリクエストを作成します。
TFRequest request = new TFRequest();
request.setSignatureName("predict_images");
float[] content = new float[784];
for (int i = 0; i < content.length; i++) {
content[i] = (float) 0.0;
}
request.addFeed("images", TFDataType.DT_FLOAT, new long[]{1, 784}, content);
request.addFetch("scores");
// リクエストをバイナリファイルに書き込みます。
File writename = new File("/path/to/warm_up1.bin");
FileUtils.writeByteArrayToFile(writename, request.getRequest().toByteArray());
}
}
/path/to/warm_up1.bin を、ファイルを保存したい実際のパスに置き換えてください。
リクエストファイルの検証
ファイルを OSS にアップロードする前に、有効な応答が生成されることを検証します。
curl を使用したテストリクエストの送信
curl --data-binary @"</path/to/warmup.bin>" \
-H 'Authorization: <your-token>' \
<service-address>
| プレースホルダー | 説明 |
|---|---|
</path/to/warmup.bin> |
ウォームアップリクエストファイルへのパス |
<your-token> |
モデルサービスへのアクセスに使用するトークン |
<service-address> |
モデルサービスのエンドポイント |
応答が大きすぎてターミナルに表示できない場合は、--output <file-path> を追加してファイルに保存します。
ファイルの直接解析
このメソッドを使用して、実行中のサービスなしでリクエストの内容を検査します。
Python
from eas_prediction import TFRequest
req = TFRequest()
with open('/path/to/warm_up1.bin', 'rb') as wm:
req.request_data.ParseFromString(wm.read())
print(req.request_data)
Java
import com.aliyun.openservices.eas.predict.proto.PredictProtos;
import org.apache.commons.io.FileUtils;
import java.io.File;
public class Test {
public static void main(String[] args) throws Exception {
File refile = new File("/path/to/warm_up1.bin");
byte[] data = FileUtils.readFileToByteArray(refile);
PredictProtos.PredictRequest pb = PredictProtos.PredictRequest.parseFrom(data);
System.out.println(pb);
}
}
モデルサービスの構成とデプロイ
-
ウォームアップリクエストファイルを OSS にアップロードします。
-
ウォームアップパラメーターをモデルサービスの JSON 構成に追加します:
{ "name": "warm_up_demo", "model_path": "oss://path/to/model", "warm_up_data_path": "oss://path/to/warm_up_test.bin", "processor": "tensorflow_cpu_1.15", "metadata": { "cpu": 2, "instance": 1, "rpc": { "warm_up_count": 5 } } }パラメーター 説明 デフォルト warm_up_data_pathウォームアップリクエストファイルの OSS パス。EAS は起動時にこのファイルを自動的に特定して使用します。 — warm_up_count各ウォームアップリクエストが送信される回数。 5他のすべての構成パラメーターについては、「モデルサービスのパラメーター」をご参照ください。
EAS は起動時にウォームアップリクエストを送信します。モデルサービスは、すべてのウォームアップリクエストが成功した後にのみ、完全に起動したと見なされます。
よくある質問
ウォームアップ後も TensorFlow モデルがファイルを再読み込みするのはなぜですか?
問題
実際のビジネスシナリオでは、TensorFlow モデルを更新すると、サービスが不安定になる可能性があります。プロセッサにウォームアップ機能を追加しても、この問題が解決しないことがあります。これは、個別の入出力シグネチャごとに、モデルがウォームアップのためにファイルを再読み込みする可能性があるためです。
原因
この問題は、TensorFlow の関数 session->Run(inputs, output_tensor_names, {}, &outputs) が、入力と output_tensor_names に対してハッシュ検証を実行するために発生します。入力または出力に変更があると、再読み込みがトリガーされます。
例えば、以下の入出力を持つ TensorFlow モデルを考えます:
Inputs:
threshold: []; DT_FLOAT
model_id: []; DT_STRING
input_holder: [-1]; DT_STRING
Outputs:
model_version_id: []; DT_STRING
sorted_labels: [-1, 3]; DT_STRING
sorted_probs: [-1, 3]; DT_FLOAT
ウォームアップリクエストが sorted_labels と sorted_probs のみをフェッチする場合:
request.addFeed("input_holder", TFDataType.DT_STRING, new long[]{1}, input);
request.addFeed("threshold", TFDataType.DT_FLOAT, new long[] {}, th);
request.addFeed("model_id", TFDataType.DT_STRING, new long[]{}, model_name);
request.addFetch("sorted_labels");
request.addFetch("sorted_probs");
しかし、本番リクエストでは model_version_id もフェッチする場合:
request.addFeed("input_holder", TFDataType.DT_STRING, new long[]{1}, input);
request.addFeed("threshold", TFDataType.DT_FLOAT, new long[] {}, th);
request.addFeed("model_id", TFDataType.DT_STRING, new long[]{}, model_name);
request.addFetch("sorted_labels");
request.addFetch("sorted_probs");
request.addFetch("model_version_id"); // An additional output is fetched.
この追加の出力がハッシュ値を変更するため、ウォームアップ後でも再読み込みが発生します。
解決策
各サービスは、ウォームアップに実際のビジネスリクエストを使用する必要があります。実際の本番リクエストから作成され、入力と出力が完全に一致するウォームアップファイルをアップロードしてください。session->Run が一致するリクエストで一度正常に実行されれば十分です。つまり、ウォームアップファイルは 1 つだけで済みます。
次のステップ
-
SDK:EAS SDK を使用してリクエストを作成し、送信する方法について説明します。
-
モデルサービスのパラメーター:JSON デプロイメントパラメーターの全セットについて説明します。