このチュートリアルでは、TensorFlow Serving コンポーネントを使用して、トレーニングされた TensorFlow モデルの新しいバージョンを動的に検出して提供する標準の TensorFlow ModelServer を構築する方法を示します。標準サーバーを使用してモデルを提供したい場合は、 TensorFlow Serving の基本チュートリアルを参照してください。
このチュートリアルでは、TensorFlow チュートリアルで導入された単純な Softmax 回帰モデルを手書き画像 (MNIST データ) 分類に使用します。 TensorFlow または MNIST が何なのかわからない場合は、 ML 初心者のための MNISTチュートリアルを参照してください。
このチュートリアルのコードは 2 つの部分で構成されます。
モデルの複数のバージョンをトレーニングおよびエクスポートする Python ファイルmnist_saved_model.py 。
C++ ファイルmain.cc。これは、新しいエクスポートされたモデルを検出し、それらを提供するためのgRPCサービスを実行する標準 TensorFlow ModelServer です。
このチュートリアルでは、次のタスクを段階的に実行します。
- TensorFlow モデルをトレーニングしてエクスポートします。
- TensorFlow Serving
ServerCore
を使用してモデルのバージョン管理を管理します。 -
SavedModelBundleSourceAdapterConfig
を使用してバッチ処理を構成します。 - TensorFlow Serving
ServerCore
を使用してリクエストを処理します。 - サービスを実行してテストします。
始める前に、まずDocker をインストールします
TensorFlow モデルのトレーニングとエクスポート
まず、まだ行っていない場合は、このリポジトリのクローンをローカル マシンに作成します。
git clone https://github.com/tensorflow/serving.git
cd serving
エクスポート ディレクトリが既に存在する場合はクリアします。
rm -rf /tmp/models
モデルの最初のバージョンをトレーニング (100 回の反復) してエクスポートします。
tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
--training_iteration=100 --model_version=1 /tmp/mnist
トレーニング (2000 回の反復) を実行し、モデルの 2 番目のバージョンをエクスポートします。
tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
--training_iteration=2000 --model_version=2 /tmp/mnist
mnist_saved_model.py
でわかるように、トレーニングとエクスポートはTensorFlow Serving の基本チュートリアルと同じ方法で行われます。デモンストレーションの目的で、最初の実行ではトレーニングの反復を意図的にダイヤルダウンして v1 としてエクスポートし、2 回目の実行では通常どおりトレーニングして同じ親ディレクトリに v2 としてエクスポートします。これは後者で達成されると予想されます。より集中的なトレーニングにより分類精度が向上します。 /tmp/mnist
ディレクトリに各トレーニング実行のトレーニング データが表示されるはずです。
$ ls /tmp/mnist
1 2
サーバーコア
ここで、新しいアルゴリズムが実験されるとき、またはモデルが新しいデータセットでトレーニングされるときに、モデルの v1 と v2 が実行時に動的に生成されると想像してください。運用環境では、v1 を提供しながら v2 を検出、ロード、実験、監視、または元に戻すことができる、段階的なロールアウトをサポートできるサーバーを構築することができます。あるいは、v2 を起動する前に v1 を破棄することもできます。 TensorFlow Serving は両方のオプションをサポートしています。1 つは移行中の可用性を維持するのに適しており、もう 1 つはリソースの使用量 (RAM など) を最小限に抑えるのに適しています。
TensorFlow Serving Manager
まさにそれを行います。 TensorFlow モデルのロード、提供、アンロードやバージョンの移行など、TensorFlow モデルのライフサイクル全体を処理します。このチュートリアルでは、 AspiredVersionsManager
を内部的にラップする TensorFlow Serving ServerCore
の上にサーバーを構築します。
int main(int argc, char** argv) {
...
ServerCore::Options options;
options.model_server_config = model_server_config;
options.servable_state_monitor_creator = &CreateServableStateMonitor;
options.custom_model_config_loader = &LoadCustomModelConfig;
::google::protobuf::Any source_adapter_config;
SavedModelBundleSourceAdapterConfig
saved_model_bundle_source_adapter_config;
source_adapter_config.PackFrom(saved_model_bundle_source_adapter_config);
(*(*options.platform_config_map.mutable_platform_configs())
[kTensorFlowModelPlatform].mutable_source_adapter_config()) =
source_adapter_config;
std::unique_ptr<ServerCore> core;
TF_CHECK_OK(ServerCore::Create(options, &core));
RunServer(port, std::move(core));
return 0;
}
ServerCore::Create()
ServerCore::Options パラメーターを受け取ります。よく使用されるオプションをいくつか示します。
- ロードするモデルを指定する
ModelServerConfig
。モデルは、モデルの静的リストを宣言するmodel_config_list
を通じて、または実行時に更新される可能性のあるモデルのリストを宣言するカスタム方法を定義するcustom_model_config
を通じて宣言されます。 -
PlatformConfigMap
、プラットフォームの名前 (tensorflow
など) からPlatformConfig
にマッピングされ、SourceAdapter
作成に使用されます。SourceAdapter
、StoragePath
(モデル バージョンが検出されるパス) をモデルLoader
(ストレージ パスからモデル バージョンをロードし、Manager
に状態遷移インターフェイスを提供します) に適合させます。PlatformConfig
にSavedModelBundleSourceAdapterConfig
が含まれている場合、SavedModelBundleSourceAdapter
作成されます。これについては後で説明します。
SavedModelBundle
は TensorFlow Serving の重要なコンポーネントです。これは、特定のパスからロードされた TensorFlow モデルを表し、推論を実行するための TensorFlow と同じSession::Run
インターフェイスを提供します。 SavedModelBundleSourceAdapter
、モデルの有効期間をManager
で管理できるように、ストレージ パスをLoader<SavedModelBundle>
に適合させます。 SavedModelBundle
非推奨のSessionBundle
の後継であることに注意してください。 SessionBundle
のサポートは間もなく削除されるため、ユーザーはSavedModelBundle
を使用することをお勧めします。
これらすべてにより、 ServerCore
内部で次のことを行います。
-
model_config_list
で宣言されたモデルのエクスポート パスを監視するFileSystemStoragePathSource
をインスタンス化します。 -
model_config_list
で宣言されたモデル プラットフォームでPlatformConfigMap
を使用してSourceAdapter
インスタンス化し、それにFileSystemStoragePathSource
を接続します。このようにして、新しいモデル バージョンがエクスポート パスで検出されるたびに、SavedModelBundleSourceAdapter
はそれをLoader<SavedModelBundle>
に適応させます。 -
SavedModelBundleSourceAdapter
によって作成されたこのようなすべてのLoader
インスタンスを管理するAspiredVersionsManager
と呼ばれるManager
の特定の実装をインスタンス化します。ServerCore
呼び出しをAspiredVersionsManager
に委任することでManager
インターフェイスをエクスポートします。
新しいバージョンが利用可能になると、このAspiredVersionsManager
は新しいバージョンをロードし、デフォルトの動作では古いバージョンをアンロードします。カスタマイズを開始する場合は、内部で作成されるコンポーネントとその構成方法を理解することをお勧めします。
TensorFlow Serving は非常に柔軟で拡張可能になるようにゼロから設計されていることは言及する価値があります。 ServerCore
やAspiredVersionsManager
などの汎用コア コンポーネントを活用しながら、さまざまなプラグインを構築してシステムの動作をカスタマイズできます。たとえば、ローカル ストレージではなくクラウド ストレージを監視するデータ ソース プラグインを構築したり、別の方法でバージョン移行を行うバージョン ポリシー プラグインを構築したりできます。実際、サービスを提供するカスタム モデル プラグインを構築することもできます。非 TensorFlow モデル。これらのトピックは、このチュートリアルの範囲外です。ただし、詳細については、カスタム ソースとカスタム サーバブルのチュートリアルを参照してください。
バッチ処理
実稼働環境に必要なもう 1 つの典型的なサーバー機能はバッチ処理です。機械学習の推論に使用される最新のハードウェア アクセラレータ (GPU など) は、通常、推論リクエストが大規模なバッチで実行されるときに最高の計算効率を達成します。
SavedModelBundleSourceAdapter
の作成時に適切なSessionBundleConfig
を指定することで、バッチ処理をオンにできます。この場合、 BatchingParameters
をほぼデフォルト値で設定します。バッチ処理は、カスタム タイムアウト、batch_size などの値を設定することで微調整できます。詳細については、 BatchingParameters
を参照してください。
SessionBundleConfig session_bundle_config;
// Batching config
if (enable_batching) {
BatchingParameters* batching_parameters =
session_bundle_config.mutable_batching_parameters();
batching_parameters->mutable_thread_pool_name()->set_value(
"model_server_batch_threads");
}
*saved_model_bundle_source_adapter_config.mutable_legacy_config() =
session_bundle_config;
フルバッチに達すると、推論リクエストは内部で単一の大きなリクエスト (tensor) にマージされ、 tensorflow::Session::Run()
が呼び出されます (GPU での実際の効率の向上はここから来ます)。
マネージャーと一緒に奉仕する
前述したように、TensorFlow Serving Manager
、任意の機械学習システムによって生成されたモデルのロード、サービング、アンロード、およびバージョン移行を処理できる汎用コンポーネントとして設計されています。その API は、次の主要な概念に基づいて構築されています。
Serable : Servable は、クライアントのリクエストに対応するために使用できる任意の不透明なオブジェクトです。サーブブルのサイズと粒度は柔軟で、単一のサーブブルにはルックアップ テーブルの単一のシャードから単一の機械学習モデル、モデルのタプルまであらゆるものが含まれる可能性があります。サーバブルは任意のタイプおよびインターフェイスにすることができます。
サーバブル バージョン: サーバブルはバージョン管理されており、TensorFlow Serving
Manager
サーバブルの 1 つ以上のバージョンを管理できます。バージョニングにより、サーブブルの複数のバージョンを同時にロードできるようになり、段階的なロールアウトと実験がサポートされます。サーバブル ストリーム: サーバブル ストリームは、バージョン番号が増加するサーバブルのバージョンのシーケンスです。
モデル: 機械学習モデルは、1 つ以上のサーバブルによって表されます。サーバブルの例は次のとおりです。
- TensorFlow セッションまたはその周囲のラッパー (
SavedModelBundle
など)。 - 他の種類の機械学習モデル。
- 語彙検索テーブル。
- ルックアップテーブルの埋め込み。
複合モデルは、複数の独立したサーバブルとして、または単一の複合サーブルとして表すことができます。サーバブルは、たとえば、多くの
Manager
インスタンスにわたってシャード化された大規模なルックアップ テーブルなど、モデルの一部に対応する場合もあります。- TensorFlow セッションまたはその周囲のラッパー (
これらすべてをこのチュートリアルのコンテキストに組み込むには、次のようにします。
TensorFlow モデルは、1 種類のサーバブル (
SavedModelBundle
によって表されます。SavedModelBundle
内部的に、どのグラフがセッションにロードされるか、および推論のためにそれを実行する方法に関するいくつかのメタデータとペアになったtensorflow:Session
で構成されます。TensorFlow エクスポートのストリームを含むファイル システム ディレクトリがあり、それぞれの名前がバージョン番号である独自のサブディレクトリにあります。外側のディレクトリは、提供される TensorFlow モデルの提供可能なストリームのシリアル化された表現と考えることができます。各エクスポートは、ロードできるサーバブルに対応します。
AspiredVersionsManager
エクスポート ストリームを監視し、すべてのSavedModelBundle
サーバブルのライフサイクルを動的に管理します。
TensorflowPredictImpl::Predict
から、次のようにします。
- マネージャーから (ServerCore 経由で)
SavedModelBundle
リクエストします。 -
generic signatures
を使用して、PredictRequest
の論理テンソル名を実際のテンソル名にマップし、値をテンソルにバインドします。 - 推論を実行します。
サーバーをテストして実行する
エクスポートの最初のバージョンを監視対象フォルダーにコピーします。
mkdir /tmp/monitored
cp -r /tmp/mnist/1 /tmp/monitored
次にサーバーを起動します。
docker run -p 8500:8500 \
--mount type=bind,source=/tmp/monitored,target=/models/mnist \
-t --entrypoint=tensorflow_model_server tensorflow/serving --enable_batching \
--port=8500 --model_name=mnist --model_base_path=/models/mnist &
サーバーは、「Aspiring version for servable ...」というログ メッセージを 1 秒ごとに出力します。これは、エクスポートが見つかり、その存続を追跡していることを意味します。
--concurrency=10
を指定してクライアントを実行してみましょう。これにより、同時リクエストがサーバーに送信され、バッチ処理ロジックがトリガーされます。
tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
--num_tests=1000 --server=127.0.0.1:8500 --concurrency=10
その結果、次のような出力が得られます。
...
Inference error rate: 13.1%
次に、エクスポートの 2 番目のバージョンを監視対象フォルダーにコピーし、テストを再実行します。
cp -r /tmp/mnist/2 /tmp/monitored
tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
--num_tests=1000 --server=127.0.0.1:8500 --concurrency=10
その結果、次のような出力が得られます。
...
Inference error rate: 9.5%
これにより、サーバーが新しいバージョンを自動的に検出し、それを提供に使用することが確認されます。