Hikaru's notes

A collection of notes and resources

View the Project on GitHub HikaruMizoe/notes

3.2 既存のアーキテクチャと要件に基づいてインフラストラクチャを作成し、スクリプト化する

タスクステートメント

既存のアーキテクチャと要件に基づいてインフラストラクチャを作成し、スクリプト化する

対象知識

オンデマンドリソースとプロビジョンドリソースの違い

オンデマンドリソース

プロビジョンドリソース

SageMaker プロビジョンド同時実行

スケーリングポリシーを比較する方法

ターゲット追跡スケーリング

ステップスケーリング

スケジュールベーススケーリング

Infrastructure as Code (IaC) のオプション

AWS CloudFormation

AWS CDK (Cloud Development Kit)

from aws_cdk import Stack
from aws_cdk import aws_sagemaker as sagemaker

class MLStack(Stack):
    def __init__(self, scope, id, **kwargs):
        super().__init__(scope, id, **kwargs)
        
        # SageMaker エンドポイント定義
        endpoint = sagemaker.CfnEndpoint(
            self, "MLEndpoint",
            endpoint_config_name="my-endpoint-config"
        )

Terraform

コンテナ化の概念と AWS のコンテナサービス

Docker の基礎

Amazon ECR (Elastic Container Registry)

Amazon ECS (Elastic Container Service)

Amazon EKS (Elastic Kubernetes Service)

SageMaker エンドポイントのオートスケーリングポリシーを使用してスケーラビリティの要件を満たす方法

スケーリングメトリクス

スケーリング設定

対象スキル

1. 保守可能かつスケーラブルで費用対効果の高い ML ソリューションを有効にするためのベストプラクティスを適用する

SageMaker エンドポイントのオートスケーリング

import boto3

client = boto3.client('application-autoscaling')

# スケーラブルターゲットの登録
response = client.register_scalable_target(
    ServiceNamespace='sagemaker',
    ResourceId=f'endpoint/{endpoint_name}/variant/{variant_name}',
    ScalableDimension='sagemaker:variant:DesiredInstanceCount',
    MinCapacity=1,
    MaxCapacity=10
)

# ターゲット追跡スケーリングポリシー
client.put_scaling_policy(
    PolicyName='target-tracking-policy',
    ServiceNamespace='sagemaker',
    ResourceId=f'endpoint/{endpoint_name}/variant/{variant_name}',
    ScalableDimension='sagemaker:variant:DesiredInstanceCount',
    PolicyType='TargetTrackingScaling',
    TargetTrackingScalingPolicyConfiguration={
        'TargetValue': 750.0,  # 目標値
        'PredefinedMetricSpecification': {
            'PredefinedMetricType': 'SageMakerVariantInvocationsPerInstance'
        },
        'ScaleInCooldown': 300,
        'ScaleOutCooldown': 60
    }
)

スポットインスタンスの動的な追加

from sagemaker.estimator import Estimator

# トレーニングでスポットインスタンス使用
estimator = Estimator(
    image_uri=container,
    role=role,
    instance_count=2,
    instance_type='ml.p3.2xlarge',
    use_spot_instances=True,
    max_run=3600,
    max_wait=7200  # スポット中断時の待機時間
)

エンドポイントの後ろでの Lambda の使用

import json
import boto3

sagemaker_runtime = boto3.client('sagemaker-runtime')

def lambda_handler(event, context):
    # 前処理
    payload = preprocess(event['body'])
    
    # SageMaker 推論
    response = sagemaker_runtime.invoke_endpoint(
        EndpointName='my-endpoint',
        ContentType='application/json',
        Body=json.dumps(payload)
    )
    
    # 後処理
    result = postprocess(response['Body'].read())
    
    return {
        'statusCode': 200,
        'body': json.dumps(result)
    }

2. スタック間の通信を含むコンピューティングリソースのプロビジョニングを自動化する

CloudFormation でのクロススタック参照

# Stack 1: ネットワーク
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16

Outputs:
  VPCId:
    Value: !Ref VPC
    Export:
      Name: MLVPCId

# Stack 2: SageMaker
Resources:
  SageMakerEndpoint:
    Type: AWS::SageMaker::Endpoint
    Properties:
      EndpointConfigName: !Ref EndpointConfig
      Tags:
        - Key: VPC
          Value: !ImportValue MLVPCId

AWS CDK でのクロススタック参照

from aws_cdk import Stack, CfnOutput
from aws_cdk import aws_ec2 as ec2
from aws_cdk import aws_sagemaker as sagemaker

class NetworkStack(Stack):
    def __init__(self, scope, id, **kwargs):
        super().__init__(scope, id, **kwargs)
        
        self.vpc = ec2.Vpc(self, "MLVPC")
        
        # 他のスタックで使用できるように出力
        CfnOutput(self, "VPCId", value=self.vpc.vpc_id)

class MLStack(Stack):
    def __init__(self, scope, id, vpc, **kwargs):
        super().__init__(scope, id, **kwargs)
        
        # ネットワークスタックのVPCを使用
        endpoint = sagemaker.CfnEndpoint(
            self, "Endpoint",
            endpoint_config_name="config"
        )

3. コンテナを構築および保守する

Dockerfile の作成

FROM python:3.9-slim

# 依存関係のインストール
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# アプリケーションコードのコピー
COPY app/ /opt/ml/code/
WORKDIR /opt/ml/code

# SageMaker の推論スクリプト
ENV SAGEMAKER_PROGRAM inference.py

# エントリーポイント
ENTRYPOINT ["python", "inference.py"]

ECR へのプッシュ

# ECR リポジトリの作成
aws ecr create-repository --repository-name ml-inference

# Docker イメージのビルド
docker build -t ml-inference .

# ECR にログイン
aws ecr get-login-password --region us-east-1 | \
  docker login --username AWS --password-stdin \
  123456789012.dkr.ecr.us-east-1.amazonaws.com

# タグ付け
docker tag ml-inference:latest \
  123456789012.dkr.ecr.us-east-1.amazonaws.com/ml-inference:latest

# プッシュ
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/ml-inference:latest

SageMaker での BYOC (Bring Your Own Container)

from sagemaker.model import Model

model = Model(
    image_uri='123456789012.dkr.ecr.us-east-1.amazonaws.com/ml-inference:latest',
    model_data=f's3://{bucket}/model.tar.gz',
    role=role
)

predictor = model.deploy(
    initial_instance_count=1,
    instance_type='ml.m5.xlarge'
)

4. VPC ネットワーク内に SageMaker エンドポイントを設定する

from sagemaker.tensorflow import TensorFlowModel

model = TensorFlowModel(
    model_data=f's3://{bucket}/model.tar.gz',
    role=role,
    framework_version='2.12'
)

# VPC 設定でデプロイ
predictor = model.deploy(
    initial_instance_count=1,
    instance_type='ml.m5.xlarge',
    endpoint_name='private-endpoint',
    vpc_config={
        'SecurityGroupIds': ['sg-xxxxx'],
        'Subnets': ['subnet-yyyyy', 'subnet-zzzzz']
    }
)

VPC Endpoint の設定

import boto3

ec2 = boto3.client('ec2')

# SageMaker Runtime VPC Endpoint
response = ec2.create_vpc_endpoint(
    VpcId='vpc-xxxxx',
    ServiceName='com.amazonaws.us-east-1.sagemaker.runtime',
    VpcEndpointType='Interface',
    SubnetIds=['subnet-yyyyy'],
    SecurityGroupIds=['sg-zzzzz']
)

5. SageMaker SDK を使用してモデルをデプロイおよびホストする

from sagemaker.pytorch import PyTorchModel

# モデルの作成
pytorch_model = PyTorchModel(
    model_data=f's3://{bucket}/model.tar.gz',
    role=role,
    framework_version='2.0',
    py_version='py310',
    entry_point='inference.py'
)

# デプロイ
predictor = pytorch_model.deploy(
    initial_instance_count=2,
    instance_type='ml.g4dn.xlarge',
    serializer=sagemaker.serializers.JSONSerializer(),
    deserializer=sagemaker.deserializers.JSONDeserializer()
)

# 推論
result = predictor.predict(data)

6. オートスケーリングのための具体的なメトリクスを選択する

メトリクス 用途 設定例
InvocationsPerInstance 一般的な負荷 目標値: 1000
ModelLatency レイテンシー重視 目標値: 100ms
CPUUtilization CPU集約的モデル 目標値: 70%
GPUUtilization GPU集約的モデル 目標値: 80%
# カスタムメトリクスベースのスケーリング
client.put_scaling_policy(
    PolicyName='latency-based-scaling',
    ServiceNamespace='sagemaker',
    ResourceId=f'endpoint/{endpoint_name}/variant/{variant_name}',
    ScalableDimension='sagemaker:variant:DesiredInstanceCount',
    PolicyType='TargetTrackingScaling',
    TargetTrackingScalingPolicyConfiguration={
        'TargetValue': 100.0,  # 100ms
        'CustomizedMetricSpecification': {
            'MetricName': 'ModelLatency',
            'Namespace': 'AWS/SageMaker',
            'Dimensions': [
                {'Name': 'EndpointName', 'Value': endpoint_name},
                {'Name': 'VariantName', 'Value': variant_name}
            ],
            'Statistic': 'Average'
        },
        'ScaleInCooldown': 600,
        'ScaleOutCooldown': 300
    }
)

CloudFormation vs CDK 比較

観点 CloudFormation CDK
言語 YAML/JSON Python, TypeScript等
学習曲線 緩やか やや急
再利用性 低い 高い(クラス、関数)
テスト 困難 容易
IDEサポート 限定的 優れている
抽象化 低レベル 高レベル

重要なポイント

IaC のベストプラクティス

  1. バージョン管理: Git でコード管理
  2. 環境分離: dev, staging, prod
  3. パラメータ化: ハードコードを避ける
  4. モジュール化: 再利用可能なコンポーネント
  5. ドキュメント: README、コメント

コンテナのベストプラクティス

  1. 軽量イメージ: Alpine Linux 等
  2. レイヤーキャッシング: 依存関係を先にコピー
  3. マルチステージビルド: ビルドサイズ削減
  4. 脆弱性スキャン: ECR イメージスキャン
  5. タグ戦略: latest を避け、バージョンタグ使用

関連リンク