AWS SAM で画像認識パイプライン(S3 + Lambda + Rekognition)を構築しよう【コンソール版との比較付き】

AWS Basic
スポンサーリンク
スポンサーリンク

はじめに

「画像認識の仕組みをコードで管理して、いつでも同じ環境を再現できるようにしたい」という要件に、AWS SAM(Serverless Application Model) は最適な選択肢のひとつです。

この記事では、AWS SAM を使って、S3 + Lambda + Rekognition による画像認識パイプラインをゼロから構築するハンズオンを紹介します。

ユーザー
  ↓ aws s3 cp image.jpg s3://bucket/
S3 バケット(STACK-upload-ACCOUNT_ID)
  ↓ ObjectCreated イベント(自動)
Lambda(DetectFunction / Python 3.12)
  ↓ boto3 rekognition.detect_labels(S3Object={...})
Amazon Rekognition
  ↓ Labels: [{Name, Confidence}, ...]
Lambda
  ↓ print(json.dumps(result))
CloudWatch Logs

このハンズオンで体験できること:

  • AWS::S3::Bucket / AWS::Serverless::Function の SAM 定義
  • S3ReadPolicy / RekognitionDetectOnlyPolicy — SAM 組み込みポリシーによる1行での権限付与
  • Events: Type: S3(ObjectCreated)— Lambda の S3 トリガーをコードで定義する方法
  • コンソール版との権限設定の違いを体感

このハンズオンの特徴:

  • sam build + sam deploy2コマンドで全リソースをデプロイ
  • S3 バケット + Lambda + IAM ロールを template.yaml 1ファイルで管理
  • sam delete全リソースを一括削除(コンソール版では S3 / Lambda / IAM / ロググループを個別に削除)

Amazon検索[本 AWS 開発]

スポンサーリンク

SAM vs コンソール:どれだけ違うか

比較項目SAM(コード)コンソール(手動)
S3 トリガーEvents: Type: S3 で1箇所に定義Lambda → トリガーを追加(手動クリック)
Rekognition 権限RekognitionDetectOnlyPolicy: {} の1行IAM → AmazonRekognitionReadOnlyAccess を手動アタッチ
S3 GetObject 権限S3ReadPolicy で特定バケットに自動付与IAM → インラインポリシーを手動作成
削除sam delete 1コマンドS3 / Lambda / IAM / ロググループを個別に削除
再現性チームで同じ環境を即座に再現できる手順書が必要

スポンサーリンク

キーワード解説

用語意味
DetectLabelsRekognition API。画像内の物体・シーンを検出してラベル名と信頼度を返す
S3Object 参照画像データを Lambda に転送せず、S3 の場所を Rekognition に渡す方式
RekognitionDetectOnlyPolicySAM 組み込みポリシー。DetectLabels / DetectFaces / DetectText などを付与
S3ReadPolicySAM 組み込みポリシー。特定バケットへの s3:GetObject を付与。コンソール版より スコープが狭くセキュア
無料枠最初の12ヶ月 / 月5,000枚まで無料。超過後は $0.001/枚

前提条件

ツール確認コマンド最低バージョン目安
AWS CLI v2aws --version2.x
AWS SAM CLIsam --version1.x
Python 3.12python --version3.12

AWS認証確認:

aws sts get-caller-identity

アカウントIDが表示されれば認証設定済みです。


使用するAWSサービス

サービス役割料金
S3画像のアップロード先バケット月5GBまで無料
LambdaS3 イベントを受けて Rekognition を呼び出す月100万リクエスト・400,000 GB-秒まで無料
Rekognition画像ラベル検出(DetectLabels)最初の12ヶ月 / 月5,000枚まで無料
IAMLambda の実行権限管理無料
S3(SAMデプロイ用)SAM デプロイパッケージ置き場少量のため実質無料
CloudWatch LogsLambda の実行ログ月5GBまで無料

Step 1: プロジェクトフォルダを開く

cd C:\my-aws\aws-learning-projects\rekognition-image-pipeline

フォルダ構造

rekognition-image-pipeline/
├── template.yaml       # SAMテンプレート(S3 + Lambda + Rekognition 定義)
├── samconfig.toml      # デプロイ設定(gitignore 対象・毎回手動作成が必要)
├── docs/
│   ├── 1_console.md    # AWSコンソール版手順
│   └── 2_sam.md        # SAM版手順
└── src/
    └── app.py          # Lambda 関数(detect_labels + ログ出力)

Step 2: SAMテンプレートの確認(template.yaml)

template.yaml は全 AWSリソースの設計図です。コンソール版との違いに注目しながらポイントを確認します。

Resources:
  UploadBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${AWS::StackName}-upload-${AWS::AccountId}"

  # Lambda 関数
  DetectFunction:
    Type: AWS::Serverless::Function
    Properties:
      Policies:
        # SAM 組み込みポリシー: 特定バケットへの s3:GetObject を付与
        - S3ReadPolicy:
            BucketName: !Sub "${AWS::StackName}-upload-${AWS::AccountId}"
        # SAM 組み込みポリシー: DetectLabels / DetectFaces / DetectText などを付与
        - RekognitionDetectOnlyPolicy: {}
      Events:
        S3UploadEvent:
          Type: S3
          Properties:
            Bucket: !Ref UploadBucket
            Events: s3:ObjectCreated:*

template.yaml のポイント:

ポイント説明
RekognitionDetectOnlyPolicy: {}SAM 組み込みポリシー。コンソール版では AmazonRekognitionReadOnlyAccess を手動アタッチ
S3ReadPolicy特定バケットのみに s3:GetObject を付与。コンソール版よりスコープが狭くセキュア
BucketName: !Sub "${AWS::StackName}-upload-${AWS::AccountId}"アカウントIDを含めることでグローバルユニークを保証
Events: Type: S3(ObjectCreated)Lambda に S3 トリガーをコードで定義。コンソール版では手動でトリガーを追加

Step 3: Lambda コードの確認(src/app.py)

コードはすでに作成済みです。構造を把握しておきます。

import json
import urllib.parse
import boto3

rekognition = boto3.client("rekognition")   # Lambda 起動時に1回だけ初期化


def lambda_handler(event, context):
    for record in event["Records"]:
        bucket = record["s3"]["bucket"]["name"]
        key = urllib.parse.unquote_plus(record["s3"]["object"]["key"])  # 日本語対応

        response = rekognition.detect_labels(
            Image={"S3Object": {"Bucket": bucket, "Name": key}},
            MaxLabels=10,      # 最大10ラベル
            MinConfidence=70,  # 70%以上のラベルのみ返す
        )

        labels = [{"name": l["Name"], "confidence": round(l["Confidence"], 1)}
                  for l in response["Labels"]]

        print(json.dumps({"key": key, "label_count": len(labels), "labels": labels},
                         ensure_ascii=False))

    return {"processedCount": len(event["Records"])}

app.py のポイント:

  • S3Object 参照: 画像データを Lambda のメモリに転送せず S3 の場所を Rekognition に渡す。メモリ効率が良い
  • urllib.parse.unquote_plus(key): 日本語や空白を含むファイル名は S3 イベントで URL エンコードされる
  • boto3.client("rekognition") をグローバルスコープに置く: Lambda のコールドスタート時に1回だけ初期化され、ウォームスタート時は再利用される(パフォーマンス向上)

Step 4: samconfig.toml を作成する

samconfig.toml.gitignore で管理外のため、毎回手動で作成する必要があります。

rekognition-image-pipeline/samconfig.toml を新規作成して以下を貼り付けます。

version = 0.1

[default.deploy.parameters]
stack_name = "rekognition-image-pipeline-stack"
resolve_s3 = true
s3_prefix = "rekognition-image-pipeline-stack"
region = "ap-northeast-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
disable_rollback = true
image_repositories = []

[default.global.parameters]
region = "ap-northeast-1"

samconfig.toml の置き場所:
rekognition-image-pipeline/ フォルダの直下に置く必要があります。


Step 5: sam build(ビルド)

cd C:\my-aws\aws-learning-projects\rekognition-image-pipeline
sam build

成功すると以下のように表示されます。

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

sam build が行っていること:
src/ フォルダを ZIP パッケージ化して .aws-sam/build/ に配置し、Lambda デプロイの準備を整えます。


Step 6: sam deploy(デプロイ)

sam deploy

変更内容が表示されて確認を求められます。

Deploy this changeset? [y/N]: y

y を入力して進めます。数分でデプロイが完了します。

デプロイ完了の確認

ターミナルに Outputs が表示されます。

Outputs
----------------------------------------------------------------------
Key    BucketName
Value  rekognition-image-pipeline-stack-upload-123456789012

Key    DetectFunctionArn
Value  arn:aws:lambda:ap-northeast-1:123456789012:function:rekognition-image-pipeline-stack-DetectFunction-XXXX
----------------------------------------------------------------------

BucketName を控えておきます。

デプロイされるリソース一覧

S3 バケット × 1        : rekognition-image-pipeline-stack-upload-ACCOUNT_ID
Lambda 関数 × 1        : rekognition-image-pipeline-stack-DetectFunction-XXXX
IAM ロール × 1         : Lambda 用(S3 GetObject + Rekognition DetectLabels 権限付き)
S3(SAM用)            : デプロイパッケージ
CloudWatch Logs        : Lambda 自動生成ログ

Step 7: 動作テスト

事前準備: バケット名を変数に設定する

set BUCKET=rekognition-image-pipeline-stack-upload-123456789012

123456789012 を自分のアカウントIDに置き換える(Outputs の値をそのままコピー)。


テスト1: 画像をアップロードしてラベルを確認する

任意の JPEG または PNG 画像(15MB 以下)を用意してアップロードする。

aws s3 cp "C:\Users\yourname\Pictures\dog.jpg" s3://%BUCKET%/ --region ap-northeast-1

アップロード直後(数秒以内)に Lambda が自動起動する。

CloudWatch Logs でラベル検出結果を確認:

aws logs tail /aws/lambda/rekognition-image-pipeline-stack-DetectFunction-XXXX --follow

期待するログ出力:

{"status": "start", "bucket": "rekognition-image-pipeline-stack-upload-...", "key": "dog.jpg"}
{
  "key": "dog.jpg",
  "label_count": 8,
  "labels": [
    {"name": "Dog", "confidence": 98.5},
    {"name": "Pet", "confidence": 98.5},
    {"name": "Animal", "confidence": 98.5},
    {"name": "Canine", "confidence": 98.5},
    {"name": "Mammal", "confidence": 97.2},
    {"name": "Golden Retriever", "confidence": 85.3},
    {"name": "Grass", "confidence": 76.1},
    {"name": "Outdoors", "confidence": 71.4}
  ]
}
{"processedCount": 1}


テスト2: 複数枚アップロードして無料枠を確認する

aws s3 cp "C:\Users\yourname\Pictures\cat.jpg"  s3://%BUCKET%/ --region ap-northeast-1
aws s3 cp "C:\Users\yourname\Pictures\city.jpg" s3://%BUCKET%/ --region ap-northeast-1

各ファイルのアップロードごとに Lambda が起動し、それぞれのラベル検出結果がログに記録される。

無料枠の管理:
AWS コンソール → Billing → 無料利用枠 → 「Amazon Rekognition」で当月の使用枚数を確認できます。


Step 8: AWSコンソールで確認(任意)

SAMでデプロイしたリソースはコンソールでも確認できます。

  • S3: S3 → rekognition-image-pipeline-stack-upload-... → アップロードしたファイルを確認
  • Lambda: Lambda → 関数 → DetectFunction-XXXX → 「設定」→「トリガー」で S3 トリガーを確認
  • IAM: IAM → ロール → Lambda のロールに S3ReadPolicy / RekognitionDetectOnlyPolicy が適用されていることを確認
  • CloudWatch Logs: Lambda → 「モニタリング」→「CloudWatch Logs を表示」でログ詳細を確認

Step 9: リソースの削除

課金を止めるために、ハンズオン完了後は必ず削除してください。

【注意】 S3 バケットにオブジェクトが残っていると sam delete が失敗します。
先にバケットを空にしてから実行してください。

rem Step 1: バケットを空にする
aws s3 rm s3://%BUCKET% --recursive --region ap-northeast-1

rem Step 2: スタック削除
sam delete --stack-name rekognition-image-pipeline-stack --region ap-northeast-1
Are you sure you want to delete the stack rekognition-image-pipeline-stack? [y/N]: y
Are you sure you want to delete the folder rekognition-image-pipeline-stack in S3? [y/N]: y

削除完了の確認:

aws cloudformation describe-stacks --stack-name rekognition-image-pipeline-stack --region ap-northeast-1

Stack with id rekognition-image-pipeline-stack does not exist が表示されれば削除完了。

削除されるリソース一覧:

  • S3 バケット(事前に空にした場合)
  • Lambda 関数
  • IAM ロール
  • CloudWatch Logs ロググループ

Rekognition はサービス自体(バケット・コレクション等)を作成しないため、削除作業は不要です。


トラブルシューティング

症状原因対処
sam deployBucketAlreadyOwnedByYouバケット名が既存と重複stack_name を変更して samconfig.toml を更新する
画像アップロード後 Lambda が動作しないS3 トリガーが未設定(デプロイエラー)sam deploy が正常完了しているか確認。CloudFormation スタックイベントを確認
AccessDeniedException (Rekognition)RekognitionDetectOnlyPolicy が適用されていないsam deploy を再実行
AccessDenied (S3)S3ReadPolicy が適用されていないLambda と S3 が同一リージョンかを確認。sam deploy を再実行
InvalidImageFormatExceptionJPEG/PNG 以外のファイルをアップロードしたJPEG または PNG 形式の画像を使用する
ImageTooLargeException15MB を超える画像をアップロードした15MB 以下の画像を使用する
sam deleteBucketNotEmpty エラーS3 バケットにオブジェクトが残っているaws s3 rm s3://%BUCKET% --recursive で先に空にする
ラベルが 0 件または少ないMinConfidence が高い、または被写体が不明瞭MinConfidence=70 を下げて再デプロイ。または別の画像を試す

まとめ

今回のハンズオンで実現したこと:

確認項目内容
S3 + Lambda の連携画像アップロードを契機に Lambda が自動起動する仕組みをコードで定義
Rekognition DetectLabels画像に写った物体・動物・シーンが自動でラベル付けされる様子を確認
SAM 組み込みポリシーS3ReadPolicy / RekognitionDetectOnlyPolicy で権限設定が1行で完結
一括削除sam delete でS3 / Lambda / IAM を一括クリーンアップ

SAMのメリットを実感できたポイント

  • RekognitionDetectOnlyPolicy: {}S3ReadPolicy により IAM 権限設定がワンライナーで完結
  • S3 バケット名に !Sub "${AWS::StackName}-upload-${AWS::AccountId}" を使うことでグローバルユニークを自動保証
  • sam delete で S3 / Lambda / IAM を一括削除。コンソール版のような個別削除が不要

コンソール版と比較してみる

SAMが裏で何をやっているか、同じ構成をAWSコンソールのみで構築する手順をまとめました。コンソール版では IAM の権限追加を S3 用・Rekognition 用と2回行う必要があるなど、SAMの組み込みポリシーがどれだけ手間を削減しているかが明確に分かります。


関連記事

Amazon検索[本 AWS 開発]

コメント