Azure Anomaly Detector Docker containerを使ってみる

# はじめに

[Azure Anomaly Detectorを使ってみる](https://qiita.com/bathtimefish/items/e97f29c21af13a697783) のつづき

[Azure Anomary Detector](https://azure.microsoft.com/ja-jp/services/cognitive-services/anomaly-detector/)ではDocker containerが提供されていてエッジデバイスでの異常検知が可能になっています。

公式ドキュメントの[Install and run Anomaly Detector containers](https://docs.microsoft.com/en-us/azure/cognitive-services/anomaly-detector/anomaly-detector-container-howto)にしたがってコンテナを起動してみることにします。

# コンテナレジストリからイメージを取得する

現時点ではコンテナイメージはプライベートなレポジトリで提供されています。レポジトリにアクセスするためには[Anomaly Detector Container Request form](https://aka.ms/adcontainer)にアクセスして必要事項を記入しリクエストを送ります。数日中にAnomaly Detector Termからアクセスに必要なUsernameとPasswordが送られてきます。[^1]

送られてきた UsernameとPasswordでログインします。

```shell
docker login containerpreview.azurecr.io -u [Username] -p [Password]
```

イメージをpullします

```shell
docker pull containerpreview.azurecr.io/microsoft/cognitive-services-anomaly-detector:latest
```

# コンテナを起動する

`[API KEY]`はportalで立ち上げたAnomaly Detectorサービスのキーを指定します

```shell
docker run --rm -it -p 5000:5000 --memory 4g --cpus 1 \
containerpreview.azurecr.io/microsoft/cognitive-services-anomaly-detector:latest \
Eula=accept \
Billing=https://westus2.api.cognitive.microsoft.com/ \
ApiKey=[API KEY]
```

実行すると以下のようにAPIサーバーが起動します。現時点でプレビューのため注意書きが出ています

```shell
Notice: This Preview is made available to you on the condition that you agree to the Supplemental Terms of Use for Microsoft Azure Previews [https://go.microsoft.com/fwlink/?linkid=2018815], which supplement your agreement [https://go.microsoft.com/fwlink/?linkid=2018657] governing your use of Azure. If you do not have an existing agreement governing your use of Azure, you agree that your agreement governing use of Azure is the Microsoft Online Subscription Agreement [https://go.microsoft.com/fwlink/?linkid=2018755] (which incorporates the Online Services Terms [https://go.microsoft.com/fwlink/?linkid=2018760]). By using the Preview you agree to these terms.


Logging to console.
Submitting metering to 'https://westus2.api.cognitive.microsoft.com/'.
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
      No XML encryptor configured. Key {6f2918c5-bb2f-4d64-ab9c-53761574071b} may be persisted to storage in unencrypted form.
WARNING: No access control enabled!
warn: Microsoft.AspNetCore.Server.Kestrel[0]
      Overriding address(es) 'http://+:80'. Binding to endpoints defined in UseKestrel() instead.
Hosting environment: Production
Content root path: /app
Now listening on: http://0.0.0.0:5000
Application started. Press Ctrl+C to shut down.
```

[localhost:5000](http://localhost:5000/)にアクセスするとAnomaly Detector APIのホームにアクセスすることができます

![スクリーンショット 2019-07-06 14.53.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/c4763b8a-64f2-43d6-6f71-0eada0178f43.png)

# APIを使ってみる

サーバーのステータスチェック用APIは[Validate that a container is running](https://docs.microsoft.com/en-us/azure/cognitive-services/anomaly-detector/anomaly-detector-container-howto#validate-that-a-container-is-running)に記載があります

```shell
curl -X GET http://localhost:5000/status

{"service":"anomalydetector","apiStatus":"Valid","apiStatusMessage":"Api Key is valid."}
```

[localhost:5000/swagger](http://localhost:5000/swagger/index.html)にアクセスするとSwagger UIのAPIドキュメントを参照できます

![スクリーンショット 2019-07-06 15.05.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/93fcc215-2073-7c8a-c80d-c7934111ef9b.png)

時系列データの異常検知をしてみます。サンプルデータは[Azure-Samplesのもの](https://github.com/Azure-Samples/AnomalyDetector/blob/master/example-data/request-data.json)を使いました

まず末尾のデータの異常検知をリクエストします

```shell
curl -X POST "http://localhost:5000/anomalydetector/v1.0/timeseries/last/detect" -H "Content-Type: application/json" -d @request-data.json | jq .
```

レスポンスは以下のようになりました。さすがlocalhostだけに速い

```shell
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  4202    0   204  100  3998   3016  59114 --:--:-- --:--:-- --:--:-- 59671
{
  "period": 7,
  "suggestedWindow": 29,
  "expectedValue": 35344244.421857625,
  "upperMargin": 353442.44421857625,
  "lowerMargin": 353442.44421857625,
  "isAnomaly": false,
  "isNegativeAnomaly": false,
  "isPositiveAnomaly": false
}
```

次に全データの異常検知をリクエストします

```shell
curl -X POST "http://localhost:5000/anomalydetector/v1.0/timeseries/entire/detect" -H "Content-Type: application/json" -d @request-data.json | jq .
```

```shell
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  7555    0  3557  100  3998  42467  47732 --:--:-- --:--:-- --:--:-- 48168
{
  "period": 7,
  "expectedValues": [
    32894418.9615615,
    29707932.24471988,
    22651867.032410353,
    24943247.98913801,
    34098022.11082705,
    33893733.15343374,
    33668289.17375017,
    32807561.144138098,
    29618567.705954053,
    22584659.813523095,
    24383099.07,
    34092130.34860708,
    33930369.33544473,
    33771835.54784974,
    32979718.237272907,
    29873907.686442,
    22898518.640143186,
    25266675.592631694,
    34507880.72026111,
    34392110.769727185,
    34264840.807082534,
    33381054.952848945,
    30169003.69004338,
    23087373.931769907,
    25351908.53601038,
    34479836.30521223,
    34250788.99625075,
    33423011.962283727,
    32615075.76349892,
    29478874.156142138,
    22473094.05331745,
    24813478.313006707,
    34017255.73765734,
    33864058.08414464,
    33577519.658487104,
    32851940.511712912,
    29199901.5,
    22918033.675673913,
    25384135.75749503,
    34746812.760001436,
    34752514.68434451,
    34634850.418293975,
    33883602.629261605,
    30764952.72634012,
    23773788.078124832,
    26128787.792423487,
    35344244.421857625
  ],
  "upperMargins": [
    328944.189615615,
    297079.3224471988,
    226518.67032410353,
    249432.47989138012,
    340980.2211082705,
    338937.3315343374,
    336682.8917375017,
    328075.611441381,
    296185.6770595405,
    225846.59813523095,
    243830.9907,
    340921.30348607077,
    339303.6933544473,
    337718.3554784974,
    329797.18237272906,
    298739.07686441997,
    228985.18640143186,
    252666.75592631695,
    345078.8072026111,
    343921.10769727186,
    342648.40807082533,
    333810.5495284895,
    301690.03690043377,
    230873.73931769907,
    253519.0853601038,
    344798.3630521223,
    342507.88996250747,
    334230.1196228373,
    326150.7576349892,
    294788.74156142137,
    224730.9405331745,
    248134.78313006705,
    340172.5573765734,
    338640.58084144635,
    335775.19658487104,
    328519.40511712915,
    291999.015,
    229180.33675673913,
    253841.35757495032,
    347468.1276000144,
    347525.1468434451,
    346348.50418293977,
    338836.02629261604,
    307649.5272634012,
    237737.88078124833,
    261287.87792423487,
    353442.44421857625
  ],
  "lowerMargins": [
    328944.189615615,
    297079.3224471988,
    226518.67032410353,
    249432.47989138012,
    340980.2211082705,
    338937.3315343374,
    336682.8917375017,
    328075.611441381,
    296185.6770595405,
    225846.59813523095,
    243830.9907,
    340921.30348607077,
    339303.6933544473,
    337718.3554784974,
    329797.18237272906,
    298739.07686441997,
    228985.18640143186,
    252666.75592631695,
    345078.8072026111,
    343921.10769727186,
    342648.40807082533,
    333810.5495284895,
    301690.03690043377,
    230873.73931769907,
    253519.0853601038,
    344798.3630521223,
    342507.88996250747,
    334230.1196228373,
    326150.7576349892,
    294788.74156142137,
    224730.9405331745,
    248134.78313006705,
    340172.5573765734,
    338640.58084144635,
    335775.19658487104,
    328519.40511712915,
    291999.015,
    229180.33675673913,
    253841.35757495032,
    347468.1276000144,
    347525.1468434451,
    346348.50418293977,
    338836.02629261604,
    307649.5272634012,
    237737.88078124833,
    261287.87792423487,
    353442.44421857625
  ],
  "isAnomaly": [
    false,
    false,
    false,
    true,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    true,
    false,
    false,
    true,
    true,
    true,
    true,
    true,
    false,
    false,
    true,
    true,
    true,
    true,
    true,
    false,
    false,
    true,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    true,
    false,
    false
  ],
  "isNegativeAnomaly": [
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    true,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    true,
    true,
    true,
    true,
    true,
    false,
    false,
    true,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    true,
    false,
    false
  ],
  "isPositiveAnomaly": [
    false,
    false,
    false,
    true,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    true,
    true,
    true,
    true,
    true,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false
  ]
}
```

# おわりに

クラウドのほうにリクエストするより圧倒的に速いので即応性を求められるシーンにはいいかもしれません。Pythonとかで異常検知アルゴリズムを実装するヒマがない場合とか、精度の追い込みよりも手軽さが優先される場合にAnomaly Detectorでいいや。という場合もあるかもしれません。[Custom Vision Service](https://docs.microsoft.com/ja-jp/azure/iot-edge/tutorial-deploy-custom-vision)をはじめAzure Cognitive ServiceはとにかくDockerコンテナを提供してエッジでも同様に動作させる方針のようでいいですね。


[^1]: https://docs.microsoft.com/en-us/azure/cognitive-services/anomaly-detector/anomaly-detector-container-howto#request-access-to-the-container-registry