本番稼働用バリアント - Amazon SageMaker

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

本番稼働用バリアント

本番稼働用 ML ワークフローでは、データサイエンティストやエンジニアが、で自動モデルチューニングを実行する SageMaker、追加されたデータや最新のデータのトレーニング、機能選択の改善、より適切に更新されたインスタンスの使用、コンテナの提供など、さまざまな方法を使用して頻繁にパフォーマンスの改善を試みています。本番稼働用バリアントを使用して、モデル、インスタンス、コンテナを比較し、推論リクエストに応答するのに最もパフォーマンスの高い候補を選択できます。

SageMaker マルチバリアントエンドポイントでは、各バリアントのトラフィック分散を指定して複数の本番稼働用バリアントにエンドポイント呼び出しリクエストを分散することも、リクエストごとに特定のバリアントを直接呼び出すこともできます。このトピックでは、ML モデルをテストするための両方の方法について説明します。

トラフィック分散を指定してモデルをテストする

複数のモデル間でトラフィックを分散してテストするには、エンドポイント構成の各本番稼働用バリアントの重みを指定して、各モデルにルーティングされるトラフィックの割合を指定します。詳細については、「」を参照してくださいCreateEndpointConfig。次の図は、この詳しい仕組みを示しています。

特定のバリアントを呼び出してモデルをテストする

リクエストごとに特定のモデルを呼び出して複数のモデルをテストするには、 を呼び出すときに TargetVariantパラメータの値を指定して、呼び出すモデルの特定のバージョンを指定しますInvokeEndpoint。指定した本番稼働用バリアントによってリクエストが処理 SageMaker されるようにします。すでにトラフィック分散を指定し、 TargetVariant パラメータに値を指定している場合、ターゲットルーティングによってランダムなトラフィック分散が上書きされます。次の図は、この詳しい仕組みを示しています。

モデル A/B テスト例

新しいモデルと本番稼働用トラフィックのある古いモデル間で A/B テストを実行することは、新しいモデルの検証プロセスの効果的な最終ステップとなります。A/B テストでは、モデルのさまざまなバリアントをテストし、各バリアントのパフォーマンスを比較します。モデルの新しいバージョンが、既存のバージョンよりも優れたパフォーマンスを発揮する場合は、モデルの古いバージョンを本番環境の新しいバージョンに置き換えます。

次の例は、A/B モデルのテストの実行方法を示しています。この例を実装したサンプルノートブックについては、 「本番環境での A/B テスト ML モデル」を参照してください。

ステップ 1: モデルの作成とデプロイ

まず、Amazon S3 のどこにモデルが配置されるかを定義します。これらの場所は、以降のステップでモデルをデプロイするときに使用されます。

model_url = f"s3://{path_to_model_1}" model_url2 = f"s3://{path_to_model_2}"

次に、イメージとモデルデータを使用してモデルオブジェクトを作成します。これらのモデルオブジェクトは、エンドポイントに本番稼働用バリアントをデプロイするために使用されます。モデルは、異なるデータセット、異なるアルゴリズムまたは ML フレームワーク、および異なるハイパーパラメータで ML モデルをトレーニングすることによって開発されます。

from sagemaker.amazon.amazon_estimator import get_image_uri model_name = f"DEMO-xgb-churn-pred-{datetime.now():%Y-%m-%d-%H-%M-%S}" model_name2 = f"DEMO-xgb-churn-pred2-{datetime.now():%Y-%m-%d-%H-%M-%S}" image_uri = get_image_uri(boto3.Session().region_name, 'xgboost', '0.90-1') image_uri2 = get_image_uri(boto3.Session().region_name, 'xgboost', '0.90-2') sm_session.create_model( name=model_name, role=role, container_defs={ 'Image': image_uri, 'ModelDataUrl': model_url } ) sm_session.create_model( name=model_name2, role=role, container_defs={ 'Image': image_uri2, 'ModelDataUrl': model_url2 } )

ここでは、それぞれ独自のモデルとリソース要件 (インスタンスタイプと数) が異なる 2 つの本番稼働用バリアントを作成します。これにより、さまざまなインスタンスタイプでモデルをテストすることもできます。

両方のバリアントの initial_weight を 1 に設定します。これにより、リクエストの 50% が Variant1 に送信され、残りの 50% が Variant2 に送信されます。両方のバリアントの重みの合計は 2 で、各バリアントの重みの割り当ては 1 です。つまり、各バリアントは合計トラフィックの 1/2 (50%) を受信することになります。

from sagemaker.session import production_variant variant1 = production_variant( model_name=model_name, instance_type="ml.m5.xlarge", initial_instance_count=1, variant_name='Variant1', initial_weight=1, ) variant2 = production_variant( model_name=model_name2, instance_type="ml.m5.xlarge", initial_instance_count=1, variant_name='Variant2', initial_weight=1, )

最後に、これらの本番稼働用バリアントを SageMaker エンドポイントにデプロイする準備が整いました。

endpoint_name = f"DEMO-xgb-churn-pred-{datetime.now():%Y-%m-%d-%H-%M-%S}" print(f"EndpointName={endpoint_name}") sm_session.endpoint_from_production_variants( name=endpoint_name, production_variants=[variant1, variant2] )

ステップ 2: デプロイされたモデルを呼び出す

今度は、このエンドポイントにリクエストを送信して、リアルタイムで推論を取得します。トラフィック分散と直接ターゲティングの両方を使用します。

まず、前のステップで構成したトラフィック分散を使用します。各推論応答には、要求を処理する本番稼働用バリアントの名前が含まれているため、2 つの本番稼働用バリアントへのトラフィックはほぼ等しいことがわかります。

# get a subset of test data for a quick test !tail -120 test_data/test-dataset-input-cols.csv > test_data/test_sample_tail_input_cols.csv print(f"Sending test traffic to the endpoint {endpoint_name}. \nPlease wait...") with open('test_data/test_sample_tail_input_cols.csv', 'r') as f: for row in f: print(".", end="", flush=True) payload = row.rstrip('\n') sm_runtime.invoke_endpoint( EndpointName=endpoint_name, ContentType="text/csv", Body=payload ) time.sleep(0.5) print("Done!")

SageMaker は、Amazon の各バリアントInvocationsに対して Latencyや などのメトリクスを発行します CloudWatch。が SageMaker 出力するメトリクスの完全なリストについては、「」を参照してくださいAmazon SageMaker で Amazon をモニタリングする CloudWatch。クエリ CloudWatch を実行して、バリアントごとの呼び出し数を取得し、デフォルトで呼び出しがバリアント間でどのように分割されるかを示します。

次に、TargetVariant の呼び出しで Variant1invoke_endpoint としてを指定することで、モデルの特定のバージョンを呼び出します。

print(f"Sending test traffic to the endpoint {endpoint_name}. \nPlease wait...") with open('test_data/test_sample_tail_input_cols.csv', 'r') as f: for row in f: print(".", end="", flush=True) payload = row.rstrip('\n') sm_runtime.invoke_endpoint( EndpointName=endpoint_name, ContentType="text/csv", Body=payload, TargetVariant="Variant1" ) time.sleep(0.5)

すべての新しい呼び出しが によって処理されたことを確認するためにVariant1、 をクエリ CloudWatch してバリアントあたりの呼び出し回数を取得できます。最新の呼び出し (最新のタイムスタンプ) では、指定されたようにすべてのリクエストが Variant1 によって処理されたことがわかります。Variant2 に対する呼び出しはありませんでした。

ステップ 3: モデルパフォーマンスの評価

どのモデルバージョンがより優れたパフォーマンスを発揮するかを確認するために、各バリアントの曲線の下にある正確性、精度、リコール、F1 スコア、レシーバー動作特性/領域を評価します。まず、Variant1 のメトリクスを見てみましょう。

次に、Variant2 のメトリクスを見てみましょう。

定義済みのメトリクスのほとんどについて、Variant2 のパフォーマンスが向上しているため、本番環境で使用するのはこれになります。

ステップ 4: 最適なモデルに対するトラフィックの増加

Variant2 のパフォーマンスが Variant1 より優れていると判断したため、より多くのトラフィックをそちらにシフトさせます。引き続き TargetVariantを使用して特定のモデルバリアントを呼び出すことができますが、より簡単な方法は、 を呼び出して各バリアントに割り当てられた重みを更新することですUpdateEndpointWeightsAndCapacities。これにより、エンドポイントを更新することなく、運用バリアントへのトラフィック分散が変更されます。セットアップセクションから、トラフィックを 50/50 に分割するようバリアントの重みを設定したことを思い出してください。以下の各バリアントの合計呼び出し回数の CloudWatch メトリクスは、各バリアントの呼び出しパターンを示しています。

次に、 を使用して各バリアントに新しい重みを割り当てるVariant2ことで、トラフィックの 75% を に移行しますUpdateEndpointWeightsAndCapacities。 SageMaker 現在、 は推論リクエストの 75% を に送信Variant2し、残りの 25% は に送信しますVariant1

sm.update_endpoint_weights_and_capacities( EndpointName=endpoint_name, DesiredWeightsAndCapacities=[ { "DesiredWeight": 25, "VariantName": variant1["VariantName"] }, { "DesiredWeight": 75, "VariantName": variant2["VariantName"] } ] )

各バリアントの合計呼び出し回数の CloudWatch メトリクスは、 Variant2よりも の呼び出し回数が多いことを示していますVariant1

引き続きメトリクスを監視し、バリアントのパフォーマンスに満足したら、トラフィックの 100% をそのバリアントにルーティングできます。UpdateEndpointWeightsAndCapacities を使用して、バリアントのトラフィック割り当てを更新します。の重みVariant1は 0 に設定され、 の重みVariant2は 1. SageMaker now はすべての推論リクエストの 100% を に送信しますVariant2

sm.update_endpoint_weights_and_capacities( EndpointName=endpoint_name, DesiredWeightsAndCapacities=[ { "DesiredWeight": 0, "VariantName": variant1["VariantName"] }, { "DesiredWeight": 1, "VariantName": variant2["VariantName"] } ] )

各バリアントの合計呼び出し回数の CloudWatch メトリクスは、すべての推論リクエストが によって処理されておりVariant2、 によって処理された推論リクエストがないことを示していますVariant1

これで、エンドポイントを安全に更新し、エンドポイントから Variant1 を削除できるようになりました。エンドポイントに新しいバリアントを追加し、ステップ 2 ~ 4 を実行することで、本番環境での新しいモデルのテストを続行することもできます。