Azure Cognitive ServicesのFace APIを利用して簡易的な顔認証モデルを作成する

# はじめに
この記事ではFace APIを利用して簡易的な顔認証のモデルを作成します。Cognitive Servicesといえばカスタマイズ不要のAPIという印象があるかもしれませんが、特定のシナリオにおいては独自のデータで学習させる必要があるため、カスタマイズ可能な機能も提供しています。

Face APIはCustom Visonと異なり予めモデル構築用のワークスペースが用意されているわけではないため、基本的にはAPIとのやり取りを繰り返して環境を構築していきます。

APIの扱いに慣れるまでは少しイメージしづらい部分があるかと思うので記録として残しておきます。
前提条件としてAzure上にFace APIリソースを作成しておきましょう。検索欄で「Face」と検索するとMarketplaceの方に出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205918/14a0bb47-d3aa-6f33-6ae4-5dad47448792.png)

リソースを作成後、APIとのやり取りに必要なためリソースのキーを利用できる形にコピーしておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205918/9a81c76d-8a25-b3cd-536f-20ef2b1a5422.png)


# 構築方法
まず全体のイメージは以下のようなものになります。Azure Blob Storage上に認識対象の画像を配置しておき、FaceAPIのIdentity機能を学習させます。学習後カメラ付きデバイス上で撮影した新たな写真を入力としてそれが誰なのかを返します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205918/c160a423-1d37-cc9f-68bc-92982140dece.png)

今回はアプリケーション側には触れず、FaceAPIの訓練の部分のみで説明します。構築する際にはFace APIとHTTPリクエストのやり取りをして構築する形になります。手順は以下です。
## 学習時

1. Person Groupの作成
2. Person Group内にPersonオブジェクトの作成
3. Personオブジェクトに顔写真の登録
4. Identifyの顔識別モデルの学習

[Face API v1.0](https://westus.dev.cognitive.microsoft.com/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395236)のドキュメントを見ればどんなリクエストを投げればいいかわかるのでこちらをご参照ください。適宜GETリクエストでPerson GroupやPersonオブジェクトの中にどんなデータが紐づいているのか確認しながら進めると分かりやすいです。

個々の構築が少し煩雑なので[Postman](https://www.postman.com/)を使うことをお勧めします。APIドキュメントから直接リクエストを投げることができますが、Postmanなどのコンソールを用いたほうが複数タブで管理できるため、GETリクエストの結果を常に表示しておくことが可能になり、ミスがないか適宜確認できます。

```json:GETで確認すると何が生成されているかわかる(face/v1.0/persongroups/<PersonGroup>/persons/).json
[
    {
        "personId": "12c63d80-5b09-42f7-978f-1533a1cfd817",
        "persistedFaceIds": [
            "0b65bdf0-cde8-4ccd-9300-2662c60a6421",
            "4ceca7c8-b8c2-4ab4-aef2-9f08b9cc6dda",
            "ddb448cc-43f9-4e1a-b4fa-903e7dbb5373"
        ],
        "name": "person_2"
    },
    {
        "personId": "1db21b08-bfe0-4bfc-832e-a41f0179666f",
        "persistedFaceIds": [
            "2cf5e02c-7221-4d4d-bb73-2baf22e673e2",
            "5ec78176-aafb-46d9-bcd6-27bcf7ba2fd9",
            "8f34505c-d3fb-4f6d-a5fe-75f888717b81"
        ],
        "name": "person_1"
    },
    {
        "personId": "55ad6e21-32c6-4b33-a8a5-709017361581",
        "persistedFaceIds": [
            "18a3349f-89cf-411c-a177-7bbb5c304bbe",
            "80acad29-c0fa-4591-9414-583e7769b267",
            "e289488d-d190-41b0-915b-0c897aeb16c3"
        ],
        "name": "person_4"
    },
    {
        "personId": "5618f953-e234-42d4-8368-2df0034a57a4",
        "persistedFaceIds": [
            "756c6d88-8402-4550-8215-13e0f10b2b61",
            "cfc9571a-bb90-410f-8e88-fcf9845c6c24",
            "dde56204-1d49-4a75-9a69-2717a940c7fd"
        ],
        "name": "person_3"
    },
    {
        "personId": "d3eec28c-b3e4-4adc-9378-b4379d4e43f4",
        "persistedFaceIds": [
            "64687c3d-fbad-47c4-b840-09cc5b607af2",
            "973ca744-9f3e-4ade-87eb-fa4a8799e845",
            "f2037eed-40b1-4ee8-9b94-8ba292c92d86"
        ],
        "name": "person_0"
    }
]
```

## 推論時
新しい画像を入力として利用し、結果を返す場合には
1. Face APIのDetectによってfaceIdを発行(face/v1.0/detect)

ここでDetectされた顔画像は時間がたつと自動で参照できなくなりますのでご注意ください。

```json
[
    {
        "faceId": "093aa3cb-77d3-42ab-add2-2c5466afe16b",
        "faceRectangle": {
            "top": 108,
            "left": 190,
            "width": 337,
            "height": 337
        }
    }
]
```
2. faceIdを入力としてFace APIに推論してもらう

ペイロードにpersonGroupIdとfaceId(複数可)を含めます。

```json:body.json
{
    "personGroupId": "xxxxx",
    "faceIds": [
        "797c7c71-da65-405b-86f5-909004f94d85"
    ],
    "maxNumOfCandidatesReturned": 1,
    "confidenceThreshold": 0.5
}
```
3. レスポンスとしてどのPersonオブジェクトなのか(personId)が返ってくる

personIdからPersonオブジェクトを逆順で参照すれば、正しく識別されているか確認できます。
confidenceの部分で確信度を確認できます。

```json:response.json
[
    {
        "faceId": "093aa3cb-77d3-42ab-add2-2c5466afe16b",
        "candidates": [
            {
                "personId": "d3eec28c-b3e4-4adc-9378-b4379d4e43f4",
                "confidence": 0.81538
            }
        ]
    }
]
```
4. (アプリを使う場合にはresponseをビューに反映)

今回はViewの方に触れていませんが、SDKやHTTPリクエスト用のライブラリを組み込んでレスポンスをインターフェースに反映すればアプリの完成です。時間と技術力の関係でできていませんが、、、笑。時間があればやってみようと思います。

# おわりに
Custom Vision等のカスタマイズ可能なサービスは独自のワークスペースが用意されていて学習させるのも容易ですが、こちらの機能は同様ではなく少し癖があると思いました。今回触ってみてCognitive Services群と相互にやり取りしなければならない場合の雰囲気が理解できました。

あとは時間を見つけてWebやネイティブアプリなどから呼び出せるようにしたいと思っています。Cognitive ServicesがAPIなので他のサービスになっても1度覚えてしまえば転用が効くと思うからです。頑張ります。