アミフィアブル株式会社AI研究部、エンジニアの吉村です。
はじめに
SageMaker AI を利用することで、モデルの訓練や訓練済みモデルを手軽に利用できます。しかし、モデルの訓練や利用にはそれなりの料金が発生します。本記事では主に SageMaker を利用した推論モデルのデプロイ・利用に焦点を当て、効果的なコスト削減方法について解説します。
対象読者は、AWS の基本知識があり、SageMaker を既に使用している、または使用検討中の方です。
SageMaker の料金は主にインスタンスタイプと利用時間によって決まります。モデルの性能要件に適したインスタンスを必要な時間だけ使用することが、コスト最適化の基本となります
SageMaker インスタンス
インスタンスの料金は、CPU/GPU の数、メモリ容量、およびリージョンによって決定されます。 詳細な料金情報は公式料金ページ で確認できます。
SageMaker 推論タイプ
SageMaker には主に以下の推論方式があります:
- リアルタイム推論:常時インスタンスが稼働し、リクエストをリアルタイムに処理
- 非同期推論:バッチ処理に適した非同期型の推論
- サーバーレス推論:リクエストに応じてインスタンスを自動的に起動・停止
リアルタイム推論と非同期推論は、あらかじめインスタンスを起動しておくため応答が速い一方、常時料金が発生します。サーバーレス推論はアクセス後にインスタンスを起動するため、アクセス頻度が低く、起動時間の遅延が許容できる場合に最もコスト効率が高くなります。
ただし、サーバーレス推論は現時点では GPU インスタンスに対応していない点に注意が必要です。GPU を必要とするモデルの場合は、リアルタイム推論か非同期推論を選択する必要があります。
Autoscaling
リアルタイム推論と非同期推論でコスト最適化を図る上で重要なのが、Autoscaling(自動スケーリング)機能です。これにより、需要に応じてインスタンス数を動的に調整できます。
Autoscaling には主に以下の 2 種類があります:
- スケジュールベース:時間帯によってインスタンス数を調整
- メトリクスベース:CPU/GPU 使用率やリクエスト数などの指標に基づいてスケーリング
※リアルタイム推論は最小インスタンス数が 1 であるのに対し、非同期推論は最小値を 0 に設定できます。そのため、夜間などの低使用時間帯には、非同期推論を使うことで完全にコストをゼロにできる可能性があります。
スケジュールベース実装例
SageMakerScalableTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
Properties:
MaxCapacity: 3
MinCapacity: 0
ResourceId: !Sub "endpoint/${SageMakerEndpoint.EndpointName}/variant/${variantName}"
RoleARN: !GetAtt SageMakerScalableTargetRole.Arn
ScalableDimension: "sagemaker:variant:DesiredInstanceCount"
ServiceNamespace: "sagemaker"
ScheduledActions:
- ScalableTargetAction:
MaxCapacity: 3
MinCapacity: 1
Schedule: "cron(00 9 ? * MON-FRI *)"
ScheduledActionName: ScaleOutSchedule
Timezone: Asia/Tokyo
- ScalableTargetAction:
MaxCapacity: 0
MinCapacity: 0
Schedule: "cron(00 17 ? * MON-FRI *)"
ScheduledActionName: ScaleInSchedule
Timezone: Asia/Tokyo
この設定では、平日の9時に最小1、最大3インスタンスとなり、17時に0インスタンスになります。
メトリクスベース実装例
SageMakerScalableTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
Properties:
MaxCapacity: 3
MinCapacity: 0
ResourceId: !Sub "endpoint/${SageMakerEndpoint.EndpointName}/variant/${variantName}"
RoleARN: !GetAtt SageMakerScalableTargetRole.Arn
ScalableDimension: "sagemaker:variant:DesiredInstanceCount"
ServiceNamespace: "sagemaker"
SageMakerScalingPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
Properties:
PolicyName: SageMakerAutoScalingPolicy
PolicyType: TargetTrackingScaling
ScalingTargetId: !Ref SageMakerScalableTarget
ServiceNamespace: sagemaker
ScalableDimension: sagemaker:variant:DesiredInstanceCount
TargetTrackingScalingPolicyConfiguration:
TargetValue: 1
ScaleInCooldown: 300
ScaleOutCooldown: 300
CustomizedMetricSpecification:
MetricName: ApproximateBacklogSizePerInstance
Namespace: 'AWS/SageMaker'
Dimensions:
- Name: EndpointName
Value: !GetAtt SageMakerEndpoint.EndpointName
Statistic: Average
この設定では、インスタンスあたりのバックログサイズの平均値が1を超えると自動的にスケールアウトし、1を下回るとスケールインします。クールダウン期間(300秒)を設けることで、頻繁なスケーリングを防ぎます。
スケジュールベースとメトリクスベースのミスマッチ
通常、スケジュールベースの設定(ScheduledActions)とメトリクスベースの設定(ScalingPolicy)を単純に組み合わせようとすると、意図した動作を得られないことがあります。例えば:
SageMakerScalableTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
Properties:
MaxCapacity: 3
MinCapacity: 0
ResourceId: !Sub "endpoint/${SageMakerEndpoint.EndpointName}/variant/${variantName}"
RoleARN: !GetAtt SageMakerScalableTargetRole.Arn
ScalableDimension: "sagemaker:variant:DesiredInstanceCount"
ServiceNamespace: "sagemaker"
ScheduledActions:
- ScalableTargetAction:
MaxCapacity: 3
MinCapacity: 1
Schedule: "cron(00 9 ? * MON-FRI *)"
ScheduledActionName: ScaleOutSchedule
Timezone: Asia/Tokyo
- ScalableTargetAction:
MaxCapacity: 0
MinCapacity: 0
Schedule: "cron(00 17 ? * MON-FRI *)"
ScheduledActionName: ScaleInSchedule
Timezone: Asia/Tokyo
SageMakerScalingPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
Properties:
PolicyName: SageMakerAutoScalingPolicy
PolicyType: TargetTrackingScaling
ScalingTargetId: !Ref SageMakerScalableTarget
ServiceNamespace: sagemaker
ScalableDimension: sagemaker:variant:DesiredInstanceCount
TargetTrackingScalingPolicyConfiguration:
TargetValue: 1
ScaleInCooldown: 300
ScaleOutCooldown: 300
CustomizedMetricSpecification:
MetricName: ApproximateBacklogSizePerInstance
Namespace: 'AWS/SageMaker'
Dimensions:
- Name: EndpointName
Value: !GetAtt SageMakerEndpoint.EndpointName
Statistic: Average
この方法では、メトリクスベースのスケーリングポリシーが常に ScalableTarget の MinCapacity と MaxCapacity の範囲内でしか動作しません。そのため、17時以降に完全にインスタンスをゼロにするスケジュールアクションが設定されたとしても、ScalableTargetの基本設定が異なると期待通りに動作しない場合があります。
EventBridge による解決
この問題を解決するために、スケジュールベースのアクションとして ScheduledActions を使用する代わりに、EventBridge Scheduler を使用して、時間帯に応じて ScalableTarget 自体の MinCapacity と MaxCapacity を動的に変更する方法が効果的です。
基本的なScalableTargetの設定、メトリクスベースのスケーリングポリシーに以下の実装例を加えることで
EventBridge Schedulerを使って時間帯によって ScalableTarget の範囲自体を変更します
SageMakerScheduleRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: scheduler.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonEventBridgeSchedulerFullAccess
- !Ref SageMakerSchedulePolicy
SageMakerSchedulePolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
Description: "Permission for EventBridge to manage SageMaker autoscaling"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- application-autoscaling:RegisterScalableTarget
- application-autoscaling:DescribeScalableTargets
- application-autoscaling:TagResource
- cloudwatch:PutMetricAlarm
- cloudwatch:DeleteAlarms
- cloudwatch:DescribeAlarms
- sagemaker:DescribeEndpointConfig
- sagemaker:DescribeEndpoint
- sagemaker:UpdateEndpointWeightsAndCapacities
Resource: '*'
SageMakerScaleOutSchedule:
Type: AWS::Scheduler::Schedule
Properties:
ScheduleExpression: "cron(00 9 ? * MON-FRI *)"
FlexibleTimeWindow:
Mode: "OFF"
ScheduleExpressionTimezone: Asia/Tokyo
Target:
Arn: arn:aws:scheduler:::aws-sdk:applicationautoscaling:registerScalableTarget
Input: !Sub |
{
"ServiceNamespace": "sagemaker",
"ResourceId": "endpoint/${SageMakerEndpoint.EndpointName}/variant/${variantName}",
"ScalableDimension": "sagemaker:variant:DesiredInstanceCount",
"MaxCapacity": 3,
"MinCapacity": 1
}
RoleArn: !GetAtt SageMakerScheduleRole.Arn
SageMakerScaleInSchedule:
Type: AWS::Scheduler::Schedule
Properties:
ScheduleExpression: "cron(00 17 ? * MON-FRI *)"
FlexibleTimeWindow:
Mode: "OFF"
ScheduleExpressionTimezone: Asia/Tokyo
Target:
Arn: arn:aws:scheduler:::aws-sdk:applicationautoscaling:registerScalableTarget
Input: !Sub |
{
"ServiceNamespace": "sagemaker",
"ResourceId": "endpoint/${SageMakerEndpoint.EndpointName}/variant/${variantName}",
"ScalableDimension": "sagemaker:variant:DesiredInstanceCount",
"MaxCapacity": 0,
"MinCapacity": 0
}
RoleArn: !GetAtt SageMakerScheduleRole.Arn
この実装では、EventBridge Schedulerを使用して以下のようなスケーリング制御を行います:
- 平日9時:業務時間開始にインスタンス数の最小値を1、最大値を3に設定
- 平日17時:業務時間終了後にインスタンス数の最小値と最大値を0に設定し、完全に停止
これにより、ScheduledActions を使用する代わりに、EventBridge Scheduler を使ってより柔軟なスケーリング制御が可能になります。EventBridge Scheduler を使用する大きな利点は、ScalableTarget の MinCapacity と MaxCapacity をAPI経由で直接変更できることです。これにより、メトリクスベースのスケーリングが機能する範囲を時間帯によって動的に変更でき、業務時間中はメトリクスに応じたスケーリング、業務時間外は完全停止という最適な運用が実現できます。
まとめ
SageMakerは強力なML基盤を提供しますが、適切に設計・運用しなければコストが高くなりがちです。しかし、本記事で紹介した手法を取り入れることで、大幅なコスト削減が可能になります。特に:
- 適切な推論タイプの選択(リアルタイム、非同期、サーバーレス)
- Autoscalingの効果的な活用(メトリクスベース)
- EventBridge Schedulerを使用したAutoscalingの設定変更
これらの手法を組み合わせることで、コストを最適化したSageMaker環境を構築できます。また、非同期推論と組み合わせることで、業務時間外のコストを完全にゼロにすることが可能です。