AWS Lambda 関数による異常の検出 - Amazon Lookout for Vision

サポート終了通知: 2025 年 10 月 31 日、 AWS は Amazon Lookout for Vision のサポートを終了します。2025 年 10 月 31 日以降、Lookout for Vision コンソールまたは Lookout for Vision リソースにアクセスできなくなります。詳細については、このブログ記事 を参照してください。

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

AWS Lambda 関数による異常の検出

AWS Lambda は、サーバーをプロビジョニングまたは管理せずにコードを実行できるようにするコンピューティングサービスです。たとえば、アプリケーションコードをホストするサーバーを作成しなくても、モバイルアプリケーションから送信された画像を分析できます。以下の手引きは、DetectAnomalies を呼び出すLambda 関数を Python で作成する方法を示しています。この関数は提供された画像を分析し、その画像での異常の存在に対する分類を返します。手引きには、Amazon S3 バケット内の画像またはローカルコンピュータから提供された画像を使用して Lambda 関数を呼び出す方法を示す Python コードの例が含まれています。

ステップ 1: AWS Lambda 関数を作成する (コンソール)

このステップでは、空の AWS 関数と、お使いの関数に DetectAnomalies オペレーションを呼び出させる IAM 実行ロールを作成します。分析用の画像を保存する Amazon S3 バケットへのアクセス権も付与します。また、以下の環境変数も指定します:

  • Lambda 関数に使用させたい Amazon Lookout for Vision プロジェクトとモデルバージョン。

  • モデルに使用させたい信頼限度。

後で、ソースコードとレイヤー (オプション) を Lambda 関数に追加します。

AWS Lambda 関数を作成するには (コンソール)
  1. AWS Management Console にサインインして AWS Lambda コンソール (https://console.aws.amazon.com/lambda/) を開きます。

  2. [関数を作成] を選択します。詳細については、「コンソールで Lambda 関数を作成する」を参照してください。

  3. 次のオプションを選択します。

    • [最初から作成] を選択します。

    • [関数名] の値を入力します。

    • [ランタイム] では、[Python 3.10] を選択します。

  4. [関数を作成] を選択し AWS Lambda 関数を作成します。

  5. 「関数」ページで、[構成] タブを選択します。

  6. [環境変数] ペインで、[編集] を選択します。

  7. 次の環境変数を追加します。変数ごとに [環境変数を追加] を選択し、変数のキーと値を入力します。

    キー

    PROJECT_NAME

    使用したいモデルが含まれている Lookout for Vision プロジェクト。

    MODEL_VERSION

    使用したいモデルのバージョン。

    信頼度

    予測が異常であるというモデルの信頼度の最小値 (0 ~ 100)。信頼度が低い場合、分類は正常とみなされます。

  8. [保存] を選択して環境変数を保存します。

  9. [権限] ペインの [ロール名] で、実行ロールを選択して IAM コンソールで開きます。

  10. [権限] タブで、[権限を追加][インラインポリシーを作成] をクリックします。

  11. [JSON] を選択し、既存の JSON を次のポリシーに置き換えます。

    { "Version": "2012-10-17", "Statement": [ { "Action": "lookoutvision:DetectAnomalies", "Resource": "*", "Effect": "Allow", "Sid": "DetectAnomaliesAccess" } ] }
  12. [次へ] をクリックします。

  13. ポリシー詳細」に、「DetectAnomalies-access」などのポリシーの名前を入力します。

  14. [ポリシーを作成] を選択します。

  15. 分析用の画像を Amazon S3 バケットに保存する場合は、ステップ 10 ~ 14 を繰り返します。

    1. ステップ 11 では、次のポリシーを使用します。バケット/フォルダパス を Amazon S3 バケット、分析する画像へのフォルダパスに置き換えます。

      { "Version": "2012-10-17", "Statement": [ { "Sid": "S3Access", "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::bucket/folder path/*" } ] }
    2. ステップ 13 では、S3bucket-access などの別のポリシー名を選択します。

ステップ 2: (オプション) レイヤーを作成する (コンソール)

この例を実行するには、このステップを行う必要はありません。DetectAnomalies オペレーションは、AWS SDK for Python (Boto3) の一部としてデフォルトの Lambda Python 環境に含まれています。Lambda 関数の他の部分で、デフォルトの Lambda Python AWS 環境にはない最新のサービス更新が必要な場合は、このステップを実行して、最新の Boto3 SDK リリースを関数のレイヤーとして追加してください。

まず、Boto3 SDK を含む.zip ファイルアーカイブを作成します。次に、レイヤーを作成し、.zip ファイルアーカイブをそのレイヤーに追加します。詳細については、「Lambda 関数でのレイヤーの使用」を参照してください。

レイヤーを作成して追加するには (コンソール)
  1. コマンドプロンプトを開き、次のコマンドを入力します。

    pip install boto3 --target python/. zip boto3-layer.zip -r python/
  2. zip ファイル (boto3-layer.zip) の名前をメモします。それは、この手順のステップ 6 で必要になります。

  3. AWS Lambda コンソールを https://console.aws.amazon.com/lambda/ で開きます。

  4. ナビゲーションペインで [レイヤー] を選択します。

  5. [レイヤーを作成] を選択します。

  6. [名前][説明] の値を入力します。

  7. [.zip ファイルをアップロード][アップロード] の順に選択します。

  8. ダイアログボックスで、この手順のステップ 1 で作成した.zip ファイルアーカイブ (boto3-layer.zip) を選択します。

  9. 互換性のあるランタイムについては、Python 3.9 を選択してください。

  10. [作成] を選択してレイヤーを作成します。

  11. ナビゲーションペインのメニューアイコンを選択します。

  12. ナビゲーションペインで、[関数] を選択します。

  13. リソースリストで、ステップ 1: AWS Lambda 関数を作成する (コンソール) で作成した関数を選択します。

  14. [コード] タブを選択します。

  15. [レイヤー] セクションで、[レイヤーを追加] を選択します。

  16. [カスタムレイヤー] を選択します。

  17. [カスタムレイヤー] で、ステップ 6 で入力したレイヤー名を選択します。

  18. [バージョン] で、レイヤーのバージョン「1」を選択します。

  19. [追加] を選択します。

ステップ 3: Python コードを追加する (コンソール)

このステップでは、Lambda コンソールコードエディタを使用して Lambda 関数に Python コードを追加します。コードは提供された画像を DetectAnomalies により分析して分類を返します (画像に異常がある場合は true、画像が正常であれば false)。提供される画像は、Amazon S3 バケットに配置したり、byte64 でエンコードされた画像バイトとすることもできます。

Python コードを追加するには (コンソール)
  1. Lambda コンソールを使用していない場合は、次の操作を行います:

    1. AWS Lambda コンソールを https://console.aws.amazon.com/lambda/ で開きます。

    2. ステップ 1: AWS Lambda 関数を作成する (コンソール) で作成した Lambda 関数を開きます。

  2. [コード] タブを選択します。

  3. [コードソース] で、lambda_function.py のコードを次のコードに置き換えます。

    # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 """ Purpose An AWS lambda function that analyzes images with an Amazon Lookout for Vision model. """ import base64 import imghdr from os import environ from io import BytesIO import logging import boto3 from botocore.exceptions import ClientError logger = logging.getLogger(__name__) # Get the model and confidence. project_name = environ['PROJECT_NAME'] model_version = environ['MODEL_VERSION'] min_confidence = int(environ.get('CONFIDENCE', 50)) lookoutvision_client = boto3.client('lookoutvision') def lambda_handler(event, context): """ Lambda handler function param: event: The event object for the Lambda function. param: context: The context object for the lambda function. return: The labels found in the image passed in the event object. """ try: file_name = "" # Determine image source. if 'image' in event: # Decode the encoded image image_bytes = event['image'].encode('utf-8') img_b64decoded = base64.b64decode(image_bytes) image_type = get_image_type(img_b64decoded) image = BytesIO(img_b64decoded) file_name = event['filename'] elif 'S3Object' in event: bucket = boto3.resource('s3').Bucket(event['S3Object']['Bucket']) image_object = bucket.Object(event['S3Object']['Name']) image = image_object.get().get('Body').read() image_type = get_image_type(image) file_name = f"s3://{event['S3Object']['Bucket']}/{event['S3Object']['Name']}" else: raise ValueError( 'Invalid image source. Only base 64 encoded image bytes or images in S3 buckets are supported.') # Analyze the image. response = lookoutvision_client.detect_anomalies( ProjectName=project_name, ContentType=image_type, Body=image, ModelVersion=model_version) reject = reject_on_classification( response['DetectAnomalyResult'], confidence_limit=float(environ['CONFIDENCE'])/100) status = "anomalous" if reject else "normal" lambda_response = { "statusCode": 200, "body": { "Reject": reject, "RejectMessage": f"Image {file_name} is {status}." } } except ClientError as err: error_message = f"Couldn't analyze {file_name}. " + \ err.response['Error']['Message'] lambda_response = { 'statusCode': 400, 'body': { "Error": err.response['Error']['Code'], "ErrorMessage": error_message, "Image": file_name } } logger.error("Error function %s: %s", context.invoked_function_arn, error_message) except ValueError as val_error: lambda_response = { 'statusCode': 400, 'body': { "Error": "ValueError", "ErrorMessage": format(val_error), "Image": event['filename'] } } logger.error("Error function %s: %s", context.invoked_function_arn, format(val_error)) return lambda_response def get_image_type(image): """ Gets the format of the image. Raises an error if the type is not PNG or JPEG. :param image: The image that you want to check. :return The type of the image. """ image_type = imghdr.what(None, image) if image_type == "jpeg": content_type = "image/jpeg" elif image_type == "png": content_type = "image/png" else: logger.info("Invalid image type") raise ValueError( "Invalid file format. Supply a jpeg or png format file.") return content_type def reject_on_classification(prediction, confidence_limit): """ Returns True if the anomaly confidence is greater than or equal to the supplied confidence limit. :param image: The name of the image file that was analyzed. :param prediction: The DetectAnomalyResult object returned from DetectAnomalies :param confidence_limit: The minimum acceptable confidence. Float value between 0 and 1. :return: True if the error condition indicates an anomaly, otherwise False. """ reject = False if prediction['IsAnomalous'] and prediction['Confidence'] >= confidence_limit: reject = True reject_info = (f"Rejected: Anomaly confidence ({prediction['Confidence']:.2%}) is greater" f" than limit ({confidence_limit:.2%})") logger.info("%s", reject_info) if not reject: logger.info("No anomalies found.") return reject
  4. Lambda 関数をデプロイするには、[デプロイ] を選択します。

ステップ 4: Lambda 関数を試す

このステップでは、コンピューター上の Python コードを使用して、ローカル画像または Amazon S3 バケット内の画像を Lambda 関数に渡します。ローカルコンピュータから渡される画像は 6291456 バイト未満でなければなりません。画像が大きい場合は、画像を Amazon S3 バケットにアップロードし、画像への Amazon S3 パスを使用してスクリプトを呼び出します。Amazon S3 バケットへの画像ファイルのアップロードに関しては、「オブジェクトのアップロード」を参照してください。

必ず Lambda 関数を作成したのと同じ AWS リージョンでコードを実行するようにします。Lambda 関数の AWS リージョンは、Lambda コンソールの関数詳細ページのナビゲーションバーで確認できます。

AWS Lambda 関数がタイムアウトエラーを返す場合は、Lambda 関数のタイムアウト期間を延長します。詳細については、「関数タイムアウトの構成 (コンソール)」を参照してください。

コードから Lambda 関数を呼び出す場合の詳細については、「AWS Lambda 関数の呼び出し」を参照してください。

Lambda 関数を試すには
  1. まだの場合は、 以下を実行してください:

    1. クライアントコードを使用するユーザーに lambda:InvokeFunction 権限があることを確かめてください。以下の権限を使用できます。

      { "Version": "2012-10-17", "Statement": [ { "Sid": "LambdaPermission", "Effect": "Allow", "Action": "lambda:InvokeFunction", "Resource": "ARN for lambda function" } ] }

      Lambda 関数の ARN は、Lambda コンソールの関数概要から取得できます。

      アクセスを提供するには、ユーザー、グループ、またはロールにアクセス許可を追加します。

    2. Python 用 AWS SDK をインストールして構成します。詳細については、「ステップ 4: をセットアップする AWS CLI また、 AWS SDKs」を参照してください。

    3. ステップ 1: AWS Lambda 関数を作成する (コンソール) のステップ 7 で指定したモデルを開始します。

  2. 次のコードを client.py という名前のファイルに保存します。

    # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 """ Purpose: Shows how to call the anomaly detection AWS Lambda function. """ from botocore.exceptions import ClientError import argparse import logging import base64 import json import boto3 from os import environ logger = logging.getLogger(__name__) def analyze_image(function_name, image): """ Analyzes an image with an AWS Lambda function. :param image: The image that you want to analyze. :return The status and classification result for the image analysis. """ lambda_client = boto3.client('lambda') lambda_payload = {} if image.startswith('s3://'): logger.info("Analyzing image from S3 bucket: %s", image) bucket, key = image.replace("s3://", "").split("/", 1) s3_object = { 'Bucket': bucket, 'Name': key } lambda_payload = {"S3Object": s3_object} # Call the lambda function with the image. else: with open(image, 'rb') as image_file: logger.info("Analyzing local image image: %s ", image) image_bytes = image_file.read() data = base64.b64encode(image_bytes).decode("utf8") lambda_payload = {"image": data, "filename": image} response = lambda_client.invoke(FunctionName=function_name, Payload=json.dumps(lambda_payload)) return json.loads(response['Payload'].read().decode()) def add_arguments(parser): """ Adds command line arguments to the parser. :param parser: The command line parser. """ parser.add_argument( "function", help="The name of the AWS Lambda function " "that you want to use to analyze the image.") parser.add_argument( "image", help="The local image that you want to analyze.") def main(): """ Entrypoint for script. """ try: logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") # Get command line arguments. parser = argparse.ArgumentParser(usage=argparse.SUPPRESS) add_arguments(parser) args = parser.parse_args() # Analyze image and display results. result = analyze_image(args.function, args.image) status = result['statusCode'] if status == 200: classification = result['body'] print(f"classification: {classification['Reject']}") print(f"Message: {classification['RejectMessage']}") else: print(f"Error: {result['statusCode']}") print(f"Message: {result['body']}") except ClientError as error: logging.error(error) print(error) if __name__ == "__main__": main()
  3. コードを実行します。コマンドライン引数には、Lambda 関数名と分析するローカル画像へのパスを指定します。例:

    python client.py function_name /bucket/path/image.jpg

    完了すると、出力は画像で見つかった異常の分類になります。分類が返されない場合は、ステップ 1: AWS Lambda 関数を作成する (コンソール) のステップ 7 で設定した信頼値を下げることを検討してください。

  4. Lambda 関数を使い終わっても、そのモデルが他のアプリケーションで使用されていない場合は、モデルを停止します。次回 Lambda 関数を使用するときには、モデルを開始することを忘れないでください。