Amazon Rekognitionを使って静止画・動画の節度判定を省力化する

この記事は [スタンバイ Advent Calendar 2021](https://qiita.com/advent-calendar/2021/stanby) の12日目の記事です。
昨日の記事は @hanishi さんの [イ〇ゲーム「そのURLに〇〇はあるか？」](https://qiita.com/hanishi/items/c892aca8d30fdffc1719) でした。

# はじめに
- ユーザーが静止画・動画をアップロードできるサービスは多いですが、わいせつ画像や暴力画像のようにサービスに不適切な画像がアップロードされてしまうと見た人が気分を害してしまいサービスの品質低下に繋がる恐れがあります。
- しかし、大量の画像を人力でチェックするとコストがかかり、スケールも難しいです。
- そこで、Amazon Rekognitionを使うことで節度判定を大きく省力化することができます。
    - ※投稿時点において自社プロダクトで使用はしていません。

# Amazon Rekognitionとは
- https://aws.amazon.com/jp/rekognition
- 機械学習モデル・インフラの構築不要で使えるフルマネージドAI機能を利用して、静止画・動画の強力な分析をスケール可能に行えるAWSのサービス。

# Amazon Rekognitionの処理能力
- 何百万もの静止画・動画を数分で分析可能。

# Amazon Rekognitionによる節度判定の注意
- 不適切・不快なコンテンツを完全に除去できるものではないので、Amazon Rekognitionをどうサービスに組み込むかは設計次第になりそうです。
- ただし、AWSカスタマーサポートにフィードバックを送ることで不適切なコンテンツの種類は今後も拡大されるとのこと。

# Amazon Rekognitionで検出できる不適切パターン
- https://docs.aws.amazon.com/rekognition/latest/dg/moderation.html
- 下記の検出が可能で、それぞれの項目の対してさらに細かい区分も検出可能なので詳細は上記ドキュメントに書かれています。
    - Explicit Nudity
    - Suggestive
    - Violence
    - Visually Disturbing
    - Rude Gestures
    - Drugs
    - Tobacco
    - Alcohol
    - Gambling
    - Hate Symbols

# この記事で使用する静止画・動画
- 全て[Pixtabay](https://pixabay.com/ja/)の静止画・動画を使用していて、[Pixabay License](https://pixabay.com/ja/service/license/)に従って商用・非商用問わず使用でき改変可能でクレジット表記不要の画像のみ使用しています。

# 静止画の判定
- まずはより多くのサービスで使用され扱いやすい静止画から試してみます。

## 静止画の判定料金
- https://aws.amazon.com/jp/rekognition/pricing/
- 処理量が増えるほど安くなりますが、1ヶ月100万枚までは画像1,000枚あたり1.30USDと余程大量の画像を扱うサービスでなければ料金で心配する程ではなさそうです。

## 静止画の判定をする

### 節度判定OKのパターン
- こちらの画像を使用
  - https://pixabay.com/ja/photos/犬-コーギー-ペット-可愛い-4415649/
![dog.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264912/c382e3d0-12a8-1851-af42-0cff9207e435.jpeg)

- 事前に対象画像をS3にアップロードしておきます。
- 静止画の判定にはdetect-moderation-labelsを使用します。
    - https://awscli.amazonaws.com/v2/documentation/api/latest/reference/rekognition/detect-moderation-labels.html
- 特定の言語に依存せずに試したいのでawscliを使用しますが、もちろん各言語のSDKからも使用可能です。

```
$ aws rekognition detect-moderation-labels --image '{"S3Object":{"Bucket":"rekognition_test","Name":"dog.jpg"}}'
{
    "ModerationLabels": [],
    "ModerationModelVersion": "5.0"
}
```

- 判定NGになるとModerationLabels内にNG内容が含まれるので、この画像は空であるため問題ないことがわかります。
- Amazon Rekognitionはモデルの定期的な改良を行っていて、使用されたモデルのバージョンがModerationModelVersionで確認できます。


### 節度判定NGの対象になるパターン
- こちらの画像を使用。
  - https://pixabay.com/ja/photos/ビール-エール-麦芽-飲料-3444480/
![beer.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264912/1cfbd60a-d81f-3482-6448-62f179a2f131.jpeg)

```
$ aws rekognition detect-moderation-labels --image '{"S3Object":{"Bucket":"rekognition_test","Name":"beer.jpg"}}'
{
    "ModerationLabels": [
        {
            "Confidence": 99.43159484863281,
            "Name": "Alcoholic Beverages",
            "ParentName": "Alcohol"
        },
        {
            "Confidence": 99.43159484863281,
            "Name": "Alcohol",
            "ParentName": ""
        }
    ],
    "ModerationModelVersion": "5.0"
}
```

- 不適切パターン10種類のうち大カテゴリとしてはAlcohol判定で引っかかっていて、さらにその中の小カテゴリとしてはAlcoholic Beverages判定で引っかかっていて、判定精度が99以上であることがわかります。
- この場合、アルコール画像がNGなサイトではこの画像を表示するべきではないですが、アルコール画像が問題ないサイトであれば無視するのが良いと思います。

## 判定精度をカスタマイズする
- Confidenceはデフォルトでは55%以上の場合に返ってくるようになっていて、閾値は--min-confidenceから増減可能です。
- Confidenceはコンテンツの検出数（再現率）と検出精度（適合率）のトレードオフとなっていて、減らすと不適切コンテンツのほとんどが検出されるようになりますが不適切でないコンテンツも検出されるようになり、増やすとその逆になるためサービスレベルに応じた設定が必要です。

# 動画の判定

## 動画の料金
- https://aws.amazon.com/jp/rekognition/pricing/
- 0.13USD/1分となっているので、大量動画を扱う際は静止画以上に料金にも気を使う必要がありそうです。

## 動画の節度判定をする

### 節度判定OKのパターン
- こちらの動画を使用。
  - https://pixabay.com/ja/videos/犬-ペット-動物-小さな-14869/
  - ![dog.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264912/8b705629-125d-2d9a-627c-8669aa66608d.gif)

- 静止画と異なり、動画の場合は判定に時間がかかるため非同期処理となります。
- まずはstart-content-moderationで動画判定を開始します。
    - https://awscli.amazonaws.com/v2/documentation/api/latest/reference/rekognition/start-content-moderation.html

```
$ aws rekognition start-content-moderation --video "S3Object={Bucket=rekognition_test,Name=dog.mp4}"
{
    "JobId": "5ce7b114031387527d65c2f1ea4a1f235cf08460e1a0b5302236e64c176113cc"
}
```

- 今回の判定に対応したJobIdが返ってくるので、それを利用してget-content-moderationで結果を取得します。
    - https://awscli.amazonaws.com/v2/documentation/api/latest/reference/rekognition/get-content-moderation.html

```
$ aws rekognition get-content-moderation --job-id 5ce7b114031387527d65c2f1ea4a1f235cf08460e1a0b5302236e64c176113cc
{
    "JobStatus": "IN_PROGRESS",
    "ModerationLabels": [],
    "ModerationModelVersion": "4.0"
}
```

- JobStatusがIN_PROGRESSの場合はまだ判定中なのでしばらく経ってからまた実行してみます。


```
$ aws rekognition get-content-moderation --job-id 5ce7b114031387527d65c2f1ea4a1f235cf08460e1a0b5302236e64c176113cc
{
    "JobStatus": "SUCCEEDED",
    "VideoMetadata": {
        "Codec": "h264",
        "DurationMillis": 19120,
        "Format": "QuickTime / MOV",
        "FrameRate": 25.0,
        "FrameHeight": 540,
        "FrameWidth": 960,
        "ColorRange": "LIMITED"
    },
    "ModerationLabels": [],
    "ModerationModelVersion": "4.0"
}
```

- 処理が完了しているとJobStatusがSUCCEEDEDで返ってきます。
- VideoMetadataで動画のメタデータもわかります。
- ModerationLabelsが空なので判定OKの動画であることがわかりました。

### 節度判定NGのパターン
- 下記動画を使用
  - https://pixabay.com/ja/videos/ワイン-ガラスの蔓-飲む-34770/
  - ![wine.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264912/8a4858e0-5eb8-1914-bdf1-6a47e0b82e36.gif)

```
$ aws rekognition start-content-moderation --video "S3Object={Bucket=rekognition_test,Name=wine.mp4}"
{
    "JobId": "e38a98add23f10d03dda1abc21c220a1fef2506487015ec99b6a0e6f39605d43"
}
```

```
$ aws rekognition get-content-moderation --job-id e38a98add23f10d03dda1abc21c220a1fef2506487015ec99b6a0e6f39605d43
{
    "JobStatus": "SUCCEEDED",
    "VideoMetadata": {
        "Codec": "h264",
        "DurationMillis": 14000,
        "Format": "QuickTime / MOV",
        "FrameRate": 25.0,
        "FrameHeight": 720,
        "FrameWidth": 1280,
        "ColorRange": "LIMITED"
    },
    "ModerationLabels": [
        {
            "Timestamp": 0,
            "ModerationLabel": {
                "Confidence": 86.58413696289062,
                "Name": "Alcohol",
                "ParentName": ""
            }
        },
        {
            "Timestamp": 0,
            "ModerationLabel": {
                "Confidence": 86.58413696289062,
                "Name": "Alcoholic Beverages",
                "ParentName": "Alcohol"
            }
        },

        ... 長いので省略 ...

        {
            "Timestamp": 13480,
            "ModerationLabel": {
                "Confidence": 99.56449890136719,
                "Name": "Alcohol",
                "ParentName": ""
            }
        },
        {
            "Timestamp": 13480,
            "ModerationLabel": {
                "Confidence": 99.56449890136719,
                "Name": "Alcoholic Beverages",
                "ParentName": "Alcohol"
            }
        }
    ],
    "ModerationModelVersion": "4.0"
}
```

- 動画の場合は静止画として分割されてフレームごとに判定されているようです。
- ModerationLabelsでAlcoholを検知していることがわかります。
- 面白いのは、動画の最初にボトルと空ワイングラスだけだと精度約86%と判定していますが、最後にワインが注がれた後だと精度99%以上の判定となっています。

# まとめ
- 実際にAmazon Rekognitionを触ってみましたが、インフラ構築不要・機械学習モデル作成不要のAPIとして提供されていて思った以上に簡単に使えました。
- 静止画・動画を扱うサービスではサービスの節度を守るために積極的に使っていこうと思いました。