Amazon Web Services ブログ

Amazon Elastic Inference を使用して Amazon SageMaker で PyTorch モデルの ML 推論コストを削減する

本日、Amazon Elastic Inference を使用して、Amazon SageMaker と Amazon EC2 の両方で PyTorch モデルの推論を加速し、推論コストを削減できるようになったことを発表します。

PyTorch は、動的なコンピューティンググラフを使用する一般的なディープラーニングフレームワークです。これにより、命令的で慣用的な Python コードを使用してディープラーニングモデルを簡単に開発できます。推論は、トレーニングされたモデルを使用して予測を行うプロセスです。PyTorch などのフレームワークを使用するディープラーニングアプリケーションの場合、推論は計算コストの最大 90% を占めます。ディープラーニングモデルはさまざまな量の GPU、CPU、およびメモリリソースを必要とするため、推論に適切なインスタンスを選択することは困難です。通常、スタンドアロン GPU インスタンスでこれらのリソースの 1 つを最適化すると、他のリソースが十分に活用されなくなります。したがって、未使用のリソースに対して料金を支払うことになる可能性があります。

Amazon Elastic Inference は、Amazon SageMakerEC2 インスタンス、または Amazon ECS タスクに適切な量の GPU による推論アクセラレーションをアタッチできるようにすることで、この問題を解決します。アプリケーションの全体的なコンピューティングとメモリのニーズに最適な AWS の CPU インスタンスを選択し、アプリケーションのレイテンシー要件を満たすために必要な適切な量の GPU による推論アクセラレーションを個別にアタッチできます。これにより、リソースをより効率的に使用し、推論コストを削減できます。今日、PyTorch が、Elastic Inference でサポートされるディープラーニングフレームワークとして TensorFlow と Apache MXNet に加わります。この記事の執筆時点でリリースされているバージョンは 1.3.1 です。

Amazon SageMaker は、すべての開発者およびデータサイエンティストが TensorFlow、Apache MXNet、PyTorch などのディープラーニングフレームワークで機械学習 (ML) モデルを迅速に構築、トレーニング、デプロイできるようにする完全マネージド型のサービスです。Amazon SageMaker は、本番環境で機械学習モデルをデプロイし、モデルの品質をモニタリングするために必要なものすべてを提供することにより、予測の生成を容易にします。

この記事では、Elastic Inference を使用して、Amazon SageMaker 上の PyTorch モデルのコストを削減し、レイテンシーを改善する方法を示します。

TorchScript: 研究と生産のギャップを埋める

次に、PyTorch コードからシリアル化および最適化可能なモデルを作成する方法である TorchScript について説明します。PyTorch で Elastic Inference を使用するには、モデルを TorchScript に変換する必要があります。

PyTorch の動的コンピューティンググラフを使用することで、モデル開発プロセスが大幅に簡素化されます。ただし、このパラダイムは、本番モデルのデプロイに固有の課題を突き付けます。本番環境では、モデルの静的なグラフ表現が有益です。これにより、Python のない環境でモデルを使用できるだけでなく、パフォーマンスの向上とメモリの最適化も可能になります。

TorchScript は、モデルをコンパイルして Python フリーのグラフベースの表現にエクスポートする機能を提供することにより、このギャップを埋めます。PyTorch モデルを TorchScript に変換することにより、あらゆる本番環境でモデルを実行できます。TorchScript は、ジャストインタイムのグラフレベルの最適化も行い、標準的な PyTorch よりもパフォーマンスを向上させます。

Elastic Inference を PyTorch で使用するには、モデルを TorchScript 形式に変換し、Elastic Inference 用の推論 API を使用する必要があります。この記事では、モデルを TorchScript にコンパイルし、Elastic Inference 対応の PyTorch を使用してエンドツーエンドの推論レイテンシーをベンチマークする方法を例示します。記事の後半では、さまざまなインスタンスとアクセラレータの組み合わせのパフォーマンスとコストメトリクスをスタンドアロンの CPU および GPU インスタンスと比較します。

TorchScript を使用したモデルのコンパイルとシリアル化

tracing または scripting を使用して、PyTorch モデルを TorchScript にコンパイルできます。どちらもコンピューティンググラフを作成しますが、作成方法が異なります。

通常、モデルのスクリプトは、すべてのモデルロジックを保持するため、TorchScript にコンパイルする好ましい方法です。ただし、この記事の執筆時点では、PyTorch 1.3.1 を使用したスクリプト可能なモデルのセットは、トレース可能なモデルのセットよりも小さくなっています。モデルはトレースできるけれどもスクリプト化できないか、まったくトレース不可能である可能性があります。モデルコードを修正して TorchScript との互換性を確保する必要があることもあります。

Elastic Inference が現在 PyTorch 1.3.1 の制御フロー操作を処理する方法のため、多くの条件分岐を含むスクリプトモデルにとって推論のレイテンシーが最適化されていない可能性があります。モデルが Elastic Inference でどのようなパフォーマンスを発揮するかを確認するには、トレースとスクリプトの両方を試してください。1.3.1 のリリースでは、トレースモデルの方がスクリプトバージョンよりもパフォーマンスが高い可能性があります。

詳細については、PyTorch ウェブサイトの「TorchScript のご紹介」のチュートリアルをご覧ください。

スクリプト

スクリプトはソースコードの直接分析を実行して、コンピューティンググラフを構築し、制御フローを保持します。次の例では、スクリプトを使用してモデルをコンパイルする方法を示しています。ResNet-18 には TorchVision の事前トレーニング済みの重みを使用します。結果のスクリプトモデルをファイルに保存してから、Elastic Inference 対応の PyTorch を使用して torch.jit.load で読み込むことができます。次のコードを参照してください。

import torchvision, torch

# Call eval() to set model to inference mode
model = torchvision.models.resnet18(pretrained=True).eval()
scripted_model = torch.jit.script(model)

トレース

トレースでは、サンプル入力を使用して、その入力でモデルを実行したときの操作のパフォーマンスを記録します。つまり、単一の入力でコードをトレースしてグラフをコンパイルしているため、制御フローが消去される可能性があります。たとえば、モデル定義には、特定のサイズ x の画像をパディングするコードが含まれる場合があります 異なるサイズ y のイメージでモデルをトレースする場合、トレースされるモデルに供給されるサイズ x の入力は将来パディングされません。これは、特定の入力でトレース中にすべてのコードパスが実行されたわけではないために発生します。

次の例は、ランダム化されたテンソル入力でトレースすることでモデルをコンパイルする方法を示しています。また、ResNet-18 向けに TorchVision の事前トレーニング済みの重みを使用します。Elastic Inference でトレースされたモデルを使用するには、デバイス順序の 2 番目のパラメータで torch.jit.optimized_execution コンテキストブロックを使用する必要があります。この変更された関数定義は 2 つのパラメータを受け入れ、Elastic Inference 対応の PyTorch フレームワークを介してのみ使用できます。

標準の PyTorch フレームワークを使用してモデルをトレースする場合、torch.jit.optimized_execution ブロックを省略します。それでも結果のトレースされたモデルをファイルに保存し、Elastic Inference 対応の PyTorch を使用して torch.jit.load で読み込むことができます。次のコードを参照してください。

# ImageNet pre-trained models take inputs of this size.
x = torch.rand(1,3,224,224)
# Call eval() to set model to inference mode
model = torchvision.models.resnet18(pretrained=True).eval()

# Required when using Elastic Inference
with torch.jit.optimized_execution(True, {‘target_device’: ‘eia:0’}):
    traced_model = torch.jit.trace(model, x)

コンパイル済みモデルの保存と読み込み

トレースとスクリプトの出力は ScriptModule です。これは、標準の PyTorch の nn.Module の TorchScript の類似物です。TorchScript モジュールのシリアル化と逆シリアル化は、それぞれ torch.jit.save()torch.jit.load() を呼び出すのと同じくらい簡単です。これは、torch.save()torch.load() を使用して標準の PyTorch モデルを保存およびロードする JIT の類似物です。次のコードを参照してください。

torch.jit.save(traced_model, 'resnet18_traced.pt')
torch.jit.save(scripted_model, 'resnet18_scripted.pt')

traced_model = torch.jit.load('resnet18_traced.pt')
scripted_model = torch.jit.load('resnet18_scripted.pt')

保存された標準の PyTorch モデルとは異なり、保存された TorchScript モデルは特定のクラスおよびコードディレクトリにバインドされていません。最初にモデルクラスをインスタンス化せずに、保存された TorchScript モデルを直接読み込むことができます。これにより、Python のない環境で TorchScript モデルを使用できます。

Elastic Inference PyTorch を使用した Amazon SageMaker のエンドツーエンドの推論ベンチマーク

この記事では、Amazon SageMaker がホストするエンドポイントを使用して、DenseNet-121 の Elastic Inference 対応 PyTorch 推論レイテンシーをベンチマークするプロセスについて説明します。DenseNet-121 は、さまざまなデータセットの画像分類で最先端の結果を達成した畳み込みニューラルネットワーク (CNN) です。そのアーキテクチャは、画像分類用の別の一般的な CNN である ResNet に大まかに基づいています。

Amazon SageMaker ホスティングにより、モデルを HTTPS エンドポイントにデプロイできるようになり、モデルが HTTP リクエストを介して推論を実行できるようになります。

前提条件

このチュートリアルでは、Amazon SageMaker がホストするエンドポイントを起動および操作するためのクライアントとして EC2 インスタンスを使用します。このクライアントインスタンスには、アクセラレータがアタッチされていません。そのため、アクセラレータがアタッチされたホスティングインスタンスをプロビジョニングするエンドポイントを起動します。チュートリアルを完了するには、最初に次の前提条件を満たす必要があります。

  • IAM ロールを作成し、AmazonSageMakerFullAccess を追加します。このポリシーは、Amazon Elastic Inference と Amazon SageMaker を使用するアクセス許可を付与します。
  • m5.large CPU EC2 インスタンスを起動します。
    • Linux または Ubuntu Deep Learning AMI (DLAMI) v27 を使用します。

この記事では、Amazon SageMaker SDK にアクセスし、PyTorch 1.3.1 を使用して DenseNet-121 の重みを保存するためにのみ、DLAMI の組み込みの Elastic Inference 対応 PyTorch Conda 環境を使用します。Amazon SageMaker Notebook のサポートが開始されたら、代わりに Notebook カーネルを使用できます。

ホストされたインスタンスとアクセラレータは、AWS DL Container を介して Elastic Inference 対応の PyTorch を使用します。クライアントインスタンスの環境の選択により、Amazon SageMaker SDK 使用を簡易化し、PyTorch 1.3.1 を使用してモデルの重みを保存できます。

チュートリアル

次の手順を実行します。

  1. 作成したインスタンスにログインします。
  2. 次のコマンドを使用して、Elastic Inference 対応の PyTorch Conda 環境をアクティブ化します。
    source activate amazonei_pytorch_p36
  3. script.py という空のファイルを作成します。このファイルは、ホストされているコンテナのエントリポイントとして機能します。デフォルトの model_fnpredict_fn をトリガーするために、ファイルは空です。デフォルトの predict_fn は、標準的な PyTorch と Elastic Inference 対応の PyTorch の両方で利用できます。ただし、デフォルトの model_fn は、Elastic Inference 対応の PyTorch にのみ実装されます。標準的な PyTorch のベンチマークを行う場合、以前のように独自の model_fn を実装する必要があります。
  4. 同じディレクトリ内で、create_sm_tarball.py というスクリプトを次のコードで作成します。
    import torch, torchvision
    import subprocess
    
    # Toggle inference mode
    model = torchvision.models.densenet121(pretrained=True).eval()
    cv_input = torch.rand(1,3,224,224)
    model = torch.jit.trace(model,cv_input)
    torch.jit.save(model, 'model.pt')
    subprocess.call(['tar', '-czvf', 'densenet121_traced.tar.gz', 'model.pt'])
    

    このスクリプトは、Amazon SageMaker が使用する命名規則 (デフォルトでは model.pt) に従って tarball を作成します。DenseNet-121 のモデルの重みは ImageNet で事前にトレーニングされており、TorchVision から取得しています。詳細については、「SageMaker Python SDK で PyTorch を使用する」を参照してください。

  5. 次のコマンドを使用して、スクリプトを実行して tarball を作成します。
    python create_sm_tarball.py
  6. 次のコードを使用して create_sm_endpoint.py というスクリプトを作成します。
    import sagemaker
    from sagemaker.pytorch import PyTorchModel
    
    sagemaker_session = sagemaker.Session()
    region = YOUR_DESIRED_REGION
    role = YOUR_IAM_ROLE_ARN
    
    instance_type = 'c5.large'
    accelerator_type = 'eia2.medium'
    
    ecr_image = '763104351884.dkr.ecr.{}.amazonaws.com/pytorch-inference-eia:1.3.1-cpu-py3'.format(region)
    
    # Satisfy regex
    endpoint_name = 'pt-ei-densenet121-traced-{}-{}'.format(instance_type, accelerator_type).replace('.', '').replace('_', '')
    tar_filename = 'densenet121_traced.tar.gz'
    
    # script.py should be blank to use default EI model_fn and predict_fn
    # For non-EI PyTorch usage, must implement own model_fn
    entry_point = 'script.py'
    
    # Returns S3 bucket URL
    print('Upload tarball to S3')
    model_data = sagemaker_session.upload_data(path=tar_filename)
    
    pytorch = PyTorchModel(model_data=model_data, role=role, image=ecr_image, entry_point=entry_point, sagemaker_session=sagemaker_session)
    
    # Function will exit before endpoint is finished creating
    predictor = pytorch.deploy(initial_instance_count=1, instance_type='ml.' + instance_type, accelerator_type='ml.' + accelerator_type, endpoint_name=endpoint_name, wait=False)

    AWS アカウント ID、リージョン、IAM ARN ロールを含めるようにスクリプトを変更する必要があります。このスクリプトは、以前に作成した tarball と空のエントリポイントスクリプトを使用して、Amazon SageMaker がホストするエンドポイントをプロビジョニングします。このサンプルコードは、ml.eia2.medium アクセラレータがアタッチされた ml.c5.large ホスティングインスタンスのベンチマーキングを行います。

    エンドポイントを作成するために画像を直接提供する必要はありませんが、この記事ではわかりやすくするために提供しています。他のフレームワークで使用できる Docker コンテナの詳細については、「ディープラーニングコンテナイメージ」を参照してください。

  7. 次のコマンドを使用して、スクリプトを実行し、ml.c5.large と ml.eia2.medium がアタッチされたホスト型エンドポイントを作成します。
    python create_sm_endpoint.py
  8. SageMaker コンソールに移動し、エンドポイントのデプロイが完了するまで待ちます。これには約 10 分かかります。これで、エンドポイントを呼び出して推論を行う準備ができました。
  9. 次のコードを使用して、benchmark_sm_endpoint.py というスクリプトを作成します。
    import sagemaker
    from sagemaker.pytorch import PyTorchPredictor
    import torch
    import boto3
    import datetime
    import math
    import numpy as np
    import time
    
    instance_type = 'c5.large'
    accelerator_type = 'eia2.medium'
    
    endpoint_name = 'pt-ei-densenet121-traced-{}-{}'.format(instance_type, accelerator_type).replace('.', '').replace('_', '')
    predictor = PyTorchPredictor(endpoint_name)
    data = torch.rand(1,3,224,224)
    
    # Do warmup round of 100 inferences to warm up routers
    print('Doing warmup round of 100 inferences (not counted)')
    for i in range(100):
      output = predictor.predict(data)
    time.sleep(15)
    
    client_times = []
    print('Running 1000 inferences for {}:'.format(endpoint_name))
    cw_start = datetime.datetime.utcnow()
    for i in range(1000):
      client_start = time.time()
      output = predictor.predict(data)
      client_end = time.time()
      client_times.append((client_end - client_start)*1000)
    cw_end = datetime.datetime.utcnow()
    
    print('Client end-to-end latency percentiles:')
    client_avg = np.mean(client_times)
    client_p50 = np.percentile(client_times, 50)
    client_p90 = np.percentile(client_times, 90)
    client_p95 = np.percentile(client_times, 95)
    client_p100 = np.percentile(client_times, 100)
    print('Avg | P50 | P90 | P95 | P100')
    print('{:.4f} | {:.4f} | {:.4f} | {:.4f}\n'.format(client_avg, client_p50, client_p90, client_p95, client_p100))
    
    print('Getting Cloudwatch:')
    cloudwatch = boto3.client('cloudwatch')
    statistics=['SampleCount', 'Average', 'Minimum', 'Maximum']
    extended=['p50', 'p90', 'p95', 'p100']
    
    # Give 5 minute buffer to end
    cw_end += datetime.timedelta(minutes=5)
    
    # Period must be 1, 5, 10, 30, or multiple of 60
    # Calculate closest multiple of 60 to the total elapsed time
    factor = math.ceil((cw_end - cw_start).total_seconds() / 60)
    period = factor * 60
    print('Time elapsed: {} seconds'.format((cw_end - cw_start).total_seconds()))
    print('Using period of {} seconds\n'.format(period))
    
    cloudwatch_ready = False
    # Keep polling CloudWatch metrics until datapoints are available
    while not cloudwatch_ready:
      time.sleep(30)
      print('Waiting 30 seconds ...')
      # Must use default units of microseconds
      model_latency_metrics = cloudwatch.get_metric_statistics(MetricName='ModelLatency',
                                                 Dimensions=[{'Name': 'EndpointName',
                                                              'Value': endpoint_name},
                                                             {'Name': 'VariantName',
                                                              'Value': "AllTraffic"}],
                                                 Namespace="AWS/SageMaker",
                                                 StartTime=cw_start,
                                                 EndTime=cw_end,
                                                 Period=period,
                                                 Statistics=statistics,
                                                 ExtendedStatistics=extended
                                                 )
    
      # Should be 1000
      if len(model_latency_metrics['Datapoints']) > 0:
        print('{} latency datapoints ready'.format(model_latency_metrics['Datapoints'][0]['SampleCount']))
        print('Side-car latency percentiles:')
        side_avg = model_latency_metrics['Datapoints'][0]['Average'] / 1000
        side_p50 = model_latency_metrics['Datapoints'][0]['ExtendedStatistics']['p50'] / 1000
        side_p90 = model_latency_metrics['Datapoints'][0]['ExtendedStatistics']['p90'] / 1000
        side_p95 = model_latency_metrics['Datapoints'][0]['ExtendedStatistics']['p95'] / 1000
        side_p100 = model_latency_metrics['Datapoints'][0]['ExtendedStatistics']['p100'] / 1000
        print('Avg | P50 | P90 | P95 | P100')
        print('{:.4f} | {:.4f} | {:.4f} | {:.4f}\n'.format(side_avg, side_p50, side_p90, side_p95, side_p100))
    
        cloudwatch_ready = True

    このスクリプトは、サイズ 1 x 3 x 224 x 224 (画像分類の標準) のテンソルを使用しています。最初に一連の 100 のウォームアップ推論を実行し、次に 1000 の推論を実行します。レイテンシーパーセンタイルは、これらの 1000 の推論からのみ報告されます。

    この記事では、レイテンシーメトリクス ModelLatency を使用します。このメトリクスは Amazon CloudWatch に送信され、Amazon SageMaker システム内の推論レイテンシーをキャプチャします。詳細については、「Amazon CloudWatch を使用した Amazon SageMaker のモニタリング」を参照してください。

    TorchScript を使用してモデルをコンパイルし、tarball に model.pt として保存する必要があります。

    ホスティングインスタンスにアタッチされたアクセラレータでエンドポイントを呼び出すと、Amazon SageMaker はデフォルトで model_fnpredict_fn を呼び出します。アクセラレータなしで Amazon SageMaker で PyTorch を使用している場合、エントリポイントスクリプトを介して model_fn を独自に実装する必要があります。

    デフォルトの model_fn は、以前に TorchScript でモデルをシリアル化し、ファイルの命名規則に準拠していることを前提としているため、torch.jit.load('model.pt') を使用してモデルの重みを読み込みます。アクセラレータがアタッチされている場合、デフォルトの predict_fntorch.jit.optimized_execution ブロックを使用します。これは、モデルを最適化して、アタッチされた Elastic Inference アクセラレータで実行できるようにする必要があることを指しています。それ以外の場合、predict_fn は標準的な PyTorch の方法で推論を行います。この記事の執筆時点では、Amazon SageMaker ではマルチアタッチはサポートされていません。したがって、デバイスの序数は常に 0 に設定されます。

    Elastic Inference の使用中に独自の predict_fn を実装することにした場合は、torch.jit.optimized_execution コンテキストを使用することを忘れないでください。そうしないと、推論が全体的にホストインスタンスで実行され、アタッチされたアクセラレータを使用しません。詳細については、「SageMaker Python SDK で PyTorch を使用する」を参照してください。

    デフォルトのハンドラーが GitHub で利用できます。

  10. 次のコマンドを使用してベンチマークスクリプトを実行します。
    python benchmark_sm_endpoint.py

次のような出力が表示されるはずです。

Doing warmup round of 100 inferences (not counted)
Running 1000 inferences for pt-ei-densenet121-traced-c5large-eia2medium:
Client end-to-end latency percentiles:
Avg | P50 | P90 | P95 | P100
64.7758 | 61.7952 | 73.7203 | 77.3841

Getting Cloudwatch:
Time elapsed: 364.777493 seconds
Using period of 420 seconds

Waiting 30 seconds ...
1000.0 latency datapoints ready
Side-car latency percentiles:
Avg | P50 | P90 | P95 | P100
47.8507 | 46.1647 | 51.7429 | 56.7705

適切なインスタンスを選択する

新しい推論ワークロードをデプロイするとき、多くのインスタンスタイプから選択できます。その際は以下の重要なパラメータを考慮に入れてください。

  • メモリ – アプリケーションに十分な CPU とアクセラレータメモリを提供するホストインスタンスとアクセラレータの組み合わせを選択する必要があります。ランタイムメモリ要件の下限を入力テンソルサイズとモデルサイズの合計値に設定できます。ただし、実行時のメモリ使用量は通常、どのモデルでもこの下限を大幅に上回り、フレームワークにも左右されます。このガイドラインは、CPU インスタンスと Elastic Inference アクセラレータを選択する際の大まかなガイダンスとしてのみご使用ください。
  • レイテンシー要件 – 十分なメモリを備えたホストインスタンスとアクセラレータのセットを作成したら、アプリケーションのレイテンシー要件を満たす選択肢にさらに絞り込むことができます。この記事では、パフォーマンスを評価するための重要な指標として、推論ごとのレイテンシーを考慮しています。単位時間あたりに処理される画像または単語の推論スループットは、一般的に使用される別のメトリクスです。
  • コスト – メモリ要件とレイテンシー要件の両方を満たす一連のハードウェアの組み合わせができたら、推論ごとに最低料金を実現する組み合わせを選択することで、コスト効率を最適化できます。このメトリクスは、(料金 / 秒 * 推論の呼び出しごとの平均レイテンシー) として計算できます。数値をより具体的にするために、この記事では 100,000 推論あたりのコストを示しています。ワークロードのコスト効率を比較し、ハードウェアの組み合わせごとに計算することで、最適なハードウェアを選択できます。この記事では、米国西部 (オレゴン) リージョンの 1 時間あたりの料金を使用しています。

これで、このプロセスを適用して、DenseNet-121 を実行するための最適なインスタンスを選択する準備ができました。まず、アプリケーションのメモリと CPU の要件を評価し、それらの要件を満たすホストインスタンスとアクセラレータのサブセットの候補リストを作成します。

次に、レイテンシーパフォーマンスを調べます。この記事では、各インスタンスで DenseNet-121 に対して同じテンソル入力と TorchVision ImageNet の事前トレーニング済みの重みを使用しました。この入力を使用してモデルで 1,000 回の推論を実行し、実行ごとのレイテンシーを収集し、平均レイテンシーと 90 パーセンタイルレイテンシー (P90 レイテンシー) を報告しました。この記事では、P90 レイテンシーが 80 ミリ秒未満である必要があります。つまり、すべての推論呼び出しの 90% のレイテンシーは、80 ミリ秒未満である必要があります。

Amazon Elastic Inference アクセラレータを 3 種類の CPU ホストインスタンスにアタッチし、それぞれに対して前述のパフォーマンステストを実行しました。次のテーブルは、1 時間あたりの料金、推論呼び出しごとの平均レイテンシー、および 100,000 推論あたりのコストを示しています。以下のすべての組み合わせは、レイテンシーしきい値を満たしています。

クライアントインスタンスタイプ Elastic Inference アクセラレータのタイプ 時間あたりのコスト 推定レイテンシー (P90) AWS Managed Services 平均推論レイテンシー AWS Managed Services (平均レイテンシーでの) 100,000 推論あたりのコスト
ml.m5.large ml.eia2.medium 0.30 USD 55.41 52.07 0.44 USD
ml.eia2.large 0.47 USD 52.01 47.88 0.63 USD
ml.eia2.xlarge 0.61 USD 47.43 44.74 0.76 USD
ml.m5.xlarge ml.eia2.medium 0.44 USD 49.27 45.23 0.55 USD
ml.eia2.large 0.60 USD 51.69 48.00 0.81 USD
ml.eia2.xlarge 0.74 USD 43.18 42.18 0.87 USD
ml.c5.large ml.eia2.medium 0.29 USD 51.74 47.85 0.38 USD
ml.eia2.large 0.46 USD 50.64 47.13 0.60 USD
ml.eia2.xlarge 0.60 USD 43.25 41.52 0.69 USD
ml.c5.xlarge ml.eia2.medium 0.41 USD 49.94 45.79 0.52 USD
ml.eia2.large 0.57 USD 46.60 43.06 0.69 USD
ml.eia2.xlarge 0.71 USD 42.91 40.11 0.80 USD

さまざまなホストインスタンスがレイテンシーに与える影響を確認できます。同じアクセラレータタイプに対して、より強力なホストインスタンスを使用しても、レイテンシーは大幅に改善されません。ただし、モデルがアクセラレータで実行されるため、より大きなアクセラレータをアタッチするとレイテンシーが低下し、より大きなアクセラレータには GPU コンピューティングやメモリなどのリソースが多くなります。アプリケーションに十分な CPU メモリを提供する最も安価なホストインスタンスタイプを選択する必要があります。ml.m5.large または ml.c5.large は、多くのユースケースには十分ですが、すべてのユースケースで十分というわけではありません。

前述の基準に基づいて、この記事では、レイテンシー要件を満たす最低コストオプションを 2 つ選択しました。ml.c5.large および ml.eia2.medium のオプションと、ml.m5.large および ml.eia2.medium のオプションです。このユースケースでは両方とも実行可能です。

SageMaker での推論のための異なるインスタンスの比較

この記事では、スタンドアロン CPU および GPU ホストインスタンスのレイテンシーおよびコストパフォーマンスデータも収集し、前述の Elastic Inference ベンチマークと比較しました。使用したスタンドアロン CPU インスタンスは、ml.c5.xl、ml.c5.4xl、ml.m5.xl、および ml.m5.4xl でした。使用したスタンドアロン GPU インスタンスは、ml.p3.2xl、ml.g4dn.xl、ml.g4dn.2xl、および ml.g4dn.4xl でした。

次の集計表は、Elastic Inference 対応オプションのコストパフォーマンスデータと、それに続くスタンドアロンインスタンスのオプションを示しています。

インスタンスタイプ 時間あたりのコスト 推定レイテンシー (P90) AWS Managed Services 平均推論レイテンシー AWS Managed Services (平均レイテンシーでの) 100,000 推論あたりのコスト
ml.c5.large + ml.eia2.medium 0.29 USD 51.74 47.85 0.38 USD
ml.m5.large + ml.eia2.medium 0.30 USD 55.41 52.07 0.44 USD
ml.g4dn.xlarge 0.74 USD 21.88 21.82 0.45 USD
ml.g4dn.2xlarge 1.06 USD 23.84 19.84 0.58 USD
ml.c5.xlarge 0.24 USD 134.18 125.5 0.83 USD
ml.g4dn.4xlarge 1.69 USD 22.19 19.36 0.91 USD
ml.m5.xlarge 0.27 USD 152.58 143.96 1.07 USD
ml.m5.4xlarge 0.95 USD 121.86 114.37 3.02 USD
ml.p3.2xlarge 4.28 USD 29.60 28.05 3.34 USD
ml.c5.4xlarge 1.08 USD 146.77 136.78 4.10 USD

Elastic Inference がスタンドアロン CPU および GPU インスタンスで提供する価値命題をよりよく理解するために、各ハードウェアタイプのレイテンシーとコスト効率データを並べて視覚化できます。次の棒グラフは 100,000 推論あたりのコストをプロットし、折れ線グラフはミリ秒単位で P90 推論レイテンシーをプロットしています。濃い灰色のバーは Elastic Inference アクセラレータを備えたインスタンス、緑色のバーはスタンドアロン GPU インスタンス、青色のバーはスタンドアロン CPU インスタンスです。

レイテンシーの分析

予想どおり、GPU インスタンスと比較した場合、CPU インスタンスのパフォーマンスは低下しています。ml.g4dn.xl インスタンスは、CPU インスタンスよりも約 7 倍高速です。スタンドアロン CPU インスタンスはどれも、80 ミリ秒の P90 レイテンシーしきい値を満たしていません。

ただし、これらの CPU インスタンスは、Elastic Inference をアタッチすると、GPU アクセラレーションの恩恵を受けるため、はるかに優れたパフォーマンスを発揮します。ml.c5.large および ml.eia2.medium のインスタンスは、スタンドアロン CPU インスタンスよりも推論を 3 倍近く高速化します。けれども、スタンドアロン GPU インスタンスは、Elastic Inference がアタッチされた CPU インスタンスよりも優れています。 ml.g4dn.xl は、ml.c5.large および ml.eia2.medium のオプションの 2 倍強の速度です。ml.g4dn.xl、ml.g4dn.2xl、および ml.g4dn.4xl インスタンスのレイテンシーはほぼ等しく、違いはほとんどありません。3 つの ml.g4dn インスタンスにはすべて同じ GPU がありますが、より大きな ml.g4dn インスタンスには、より多くの vCPU とメモリリソースがあります。DenseNet-121 では、vCPU とメモリリソースを増やしても推論レイテンシーは改善されません。

Elastic Inference とスタンドアロン GPU インスタンスの両方がレイテンシー要件を満たしています。

コスト分析

コストに関しては、ml.c5.large および ml.eia2.medium のオプションが際立っています。ml.c5.large および ml.eia2.medium のオプションは 1 時間あたりの料金が最低ではありませんが、100,000 推論あたりのコストが最低です。1 時間あたりの料金設定の詳細については、Amazon SageMaker 料金表を参照してください。

1 時間あたりのコストが低いインスタンスは、推論あたりのコストが必ずしも低いとは限らないと結論付けることができます。これは、推論ごとのレイテンシーが高くなる可能性があるためです。同様に、推論あたりのレイテンシーを低くするインスタンスは、推論あたりのコストが低くはならない場合があります。ml.m5.xlarge および ml.c5.xlarge CPU インスタンスは 1 時間あたりの料金は最低ですが、ほとんどの Elastic Inference およびスタンドアロン GPU オプションよりも推論あたりのコストが高くなります。より大きな ml.m5.4xlarge および ml.c5.4xlarge インスタンスは、レイテンシーが高く、1 時間あたりのコストが高いため、すべての Elastic Inference オプションよりも推論あたりのコストが高くなります。スタンドアロンの GPU インスタンスは、CUDA 演算子が活用する高度な計算並列化により、全体的に最高のレイテンシーを実現します。けれども、推論あたりのコストが最も低いのは Elastic Inference です。

Amazon Elastic Inference では、両方の長所を活かせます。GPU が提供する並列化と推論の高速化のほとんどを実現し、さらに CPU と GPU の両方のスタンドアロンインスタンスよりも優れた費用対効果を実現します。さらに、ホストインスタンスと推論アクセラレーションハードウェアを分離する柔軟性も備えているため、アプリケーションが必要とする vCPU、メモリ、およびその他すべてのリソースに対してハードウェアを柔軟に最適化できます。

上記のテストは、ml.c5.large および ml.eia2.medium のオプションが、DenseNet-121 を実行するためのレイテンシー基準とメモリ使用要件を満たした最も低コストのオプションであることを示しています。

この記事で使用するレイテンシーメトリクス (CloudWatch メトリクスで出力される ModelLatency) は、Amazon SageMaker 内のレイテンシーを測定しています。このレイテンシーメトリクスは、お使いのアプリケーションが Amazon SageMaker に及ぼすレイテンシーは考慮していません。アプリケーションのベンチマークを行うときは、このレイテンシーを考慮に入れてください。

まとめ

Amazon Elastic Inference は、Amazon SageMaker の PyTorch 推論ワークロード向けの低コストで柔軟なソリューションです。Elastic Inference アクセラレータを Amazon SageMaker インスタンスにアタッチすることで、GPU のような推論アクセラレーションを得て、スタンドアロンの Amazon SageMaker GPU および CPU インスタンスよりも良いコスト効率を保つことができます。詳細については、「Amazon Elastic Inference とは」を参照してください。


著者について

David Fan は AWS AI のソフトウェアエンジニアです。彼は、コンピュータービジョンとディープラーニングの最先端の研究を推進し、AI 研究の大規模な本番環境における使用を妨げるコンピューティングおよびドメイン知識の障壁を下げることに情熱を傾けています。余暇には、Kaggle のコンペティションに参加し、arXiv の最新の論文を読んで過ごしています。

 

 

 

Srinivas Hanabe は、AWS AI で Elastic Inference 担当の主席プロダクトマネージャです。現在の職に就く前は、Amazon VPC の PM リーダーでした。Srinivas は、長距離を走ること、さまざまなトピックについて本を読むこと、家族と過ごすことが大好きで、キャリアの指導者でもあります。