AWS Lambdaで画像を使った異常検知の推論を行う

2022年11月、AIカメラお手軽導入パックは教師なしで実現できる異常検知に対応しました。この異常検知について、お客様にイメージしていただきやすいようデモの実装を行いました。
今回のデモの推論では現在AWS Lambdaを使用しています。
推論コード自体はPythonを使用しているのですがAWS LambdaのpythonランタイムではなくカスタムDockerランタイムを使用しました。

カスタムDockerランタイムとは

AWS Lambdaでは基本的に以下の言語をサポートしています(バージョンは省略, 2022年12月28日現在)

  • Node.js
  • Python
  • Java
  • .NET
  • Go
  • Ruby

カスタムDockerランタイムは上記言語以外の言語を使った実装も可能になります。

なぜPythonランタイムを使わずにカスタムDockerランタイムを使ったのか

PythonなどのカスタムDockerランタイム以外のランタイムはデプロイパッケージのサイズ上限が250MBとなっています。推論をするために今回Pytorchを使っています。また、その他にもscipyやpillowなど様々な外部ライブラリを使用しています。それ以外にもなんと言っても推論するためのモデルファイルも存在しています。これらのファイルサイズは大きく、サイズ上限を上回ってしまいます。しかし、カスタムDockerランタイムのイメージサイズの上限は10GBと大きく、今回使用するライブラリやモデルはサイズに収まることができました。そのため、今回はカスタムDockerランタイムを使用することにしました。

AWS Lambda内で実施していること

実施していること自体はシンプルです。API gateway経由でAIカメラから画像を送信しています。そこからAWS Lambdaに渡ってきた画像データを推論して異常があるかどうかを判断し、推論結果をAmazon DynamoDB、結果画像をAmazon S3に保存しています。

実装内容

今回使用したベースイメージはamazon/aws-lambda-python:3.8というAWSが用意しているベースイメージです。ただし、AWSベースイメージを必ず使用する必要はなく、awslambdaricのインストール等必要な処理をすれば他のベースイメージも使用可能です。(参考記事:代替ベースイメージからのイメージの作成)
Dockerfileさえ用意してしまえばあとは普段pythonでAWS Lambdaを実装するのと同じようにコーディングするだけです。

AWS Lambdaのデプロイ

今回はAWS CDK(TypeScript)を使用してデプロイをしています。
以下のコードで簡単にデプロイすることができます。
ECRに用意したリポジトリでコードを管理すればデプロイ時間の短縮をすることができます。

const repository = Repository.fromRepositoryName(this, "getECRRepository", "test-repo");
new DockerImageFunction(this, "createDockerLambda", {
     code: DockerImageCode.fromEcr(repository),
     memorySize: 2048
   });

fromEcrとなっている部分をfromAssetとすれば都度ビルドしてデプロイしてくれるので、リポジトリを用意して管理する必要はなくなります。(ただし、毎度ゼロベースでビルドするのでデプロイに時間がかかります。)

new DockerImageFunction(this, "createDockerLambda", {
     code: DockerImageCode.fromAsset("path/to/lambda/file"),
     memorySize: 2048
   });

実際にAWS Lambdaで推論してみた際の速度検証

今回はAWS Lambdaのメモリを1GB / 1.5GB / 2GBに設定して推論速度の比較検証も実施しました。
それぞれのメモリで同時実行数を1~100にして検証したところ推論にかかった時間は以下のようになりました。

メモリ(GB)平均(ms)最小(ms)最大(ms)
12313.3331672.66614020.333
1.51816.3331195.33314461.666
21598926.33315141.666

最大でかかった時間についてはAWS Lambdaのコールドスタート部分で時間がかかっているためです。具体的にはモデルファイルの読み込みに大きな時間を費やしています。
ただ、それ以降では約1~2秒で推論が可能となっています。
ユースケースによりますがそこまで大きなメモリを用意しなくてもある程度の推論はできそうです。今回のデモでは1秒インターバルで画像を送信しており、レスポンスも速度をそこまで求められていないため十分な速度が出ています。

まとめ

チームの開発ではAmazon API Gateway -> AWS Lambdaが鉄板構成となっており構成の理解もしやすく、費用も比較的安価に済ませることができるため速度を求められない際には便利だなと感じました。同時実行数が急激に増えてコールドスタートが発生してしまうと、一部レスポンスが悪くなってしまうのでユースケースによっては構成を見直す必要があるかなと思います。
(今後はエッジでの異常検知推論対応できたらいいなぁ…)