Visual Recognition V3利用時の考慮事項～フライドチキンと犬の再評価からわかったこと～

# はじめに
前々回の投稿で書いた[フライドチキンとラブラドゥードルの比較](http://qiita.com/VegaSato/items/2cd40369ea7bd6ae26bf)はVRのV2の頃のテストだった。半年前だったもので。ということで、今ならV3でも試してみよう！と思ってやってみたら、いろいろわかったことがあるので忘れないうちにメモっておく。

# VR V3の使い方
詳しい使い方は[公式](http://www.ibm.com/watson/developercloud/doc/visual-recognition/)にお願いするとして、ここでは**「こうやったら動いた」**という要点だけまとめようと思う。

VRを使うとき、以下のような流れで進める。そしてテスト後に追加画像を集めたり再トレーニングしたりして、モデルを洗練させていく。とりあえずまぁ今回は1周しかしてないけれど。

0. 画像集め
0. トレーニング(学習)
0. テスト(評価)

## 画像集め
画像はV2と同じなので[こちら](http://qiita.com/VegaSato/items/2cd40369ea7bd6ae26bf)を参照のこと。

集めた画像をそれぞれzipファイルにする。train_chicken.zip、train_labradoodle.zipとしておく。それぞれ写真は200枚くらい、zipすると50MBくらい。これは、V2の頃の制約で、画像ファイルは合計100MBまでだったため。
V3ではどうかというと以下のとおり。
![2016-11-23 23_27_43-Visual Recognition Service Documentation _ Watson Developer Cloud.png](https://qiita-image-store.s3.amazonaws.com/0/102519/86fdd460-8a3b-7ce0-cc09-3b3855367699.png)

つまり**「zipファイル1つあたり最低10枚、最高1万枚、100MBまで。全クラス合計256MBまで」**ということだ。うれしいことに上限が増えている。(もしかしてV2の頃の条件を間違って認識していたとか？？)

V2と比較もしたかったので、データは変えないことにした。

## 学習
学習は、次のコマンドを実行した。

```bash
curl -X POST -F "FriedChiken_positive_examples=@train_chicken.zip" -F "Labradoodle_positive_examples=@train_labradoodle.zip" -F "name=Chicken_or_Dog" "https://gateway-a.watsonplatform.net/visual-recognition/api/v3/classifiers?api_key={api_key}&version=2016-05-20"
```

V3では学習に必要なパラメーターは、分類器の名前と、画像データが2種類以上。これだけ。
画像データは、分類したい画像のイメージ(ポジティブ・イメージ)の画像2種類以上か、ポジティブ・イメージを1種類以上とネガティブ・イメージ1種類が必要だ。
V2ではネガティブ・イメージが必須だったがV3では必須ではなくなく、ポジティブ・イメージが2つ以上あればネガティブ・イメージはなくても大丈夫になった。これは地味にありがたい。

api_keyは自身のBluemixで取得したVRのAPIキーを入力する。**え？どこにあるかわからない？**そんなのは自分で調べて欲しい。このあたりにあるはず。
<img src="https://qiita-image-store.s3.amazonaws.com/0/102519/65981bc0-1dcb-73f6-caba-a944804b8bc0.png" width=600></img>

待つこと約10分。こんなレスポンスが返って来て学習完了。

```json
{
    "classifier_id": "Chicken_or_Dog_1056118805",
    "name": "Chicken_or_Dog",
    "owner": "****************************************",
    "status": "training",
    "created": "2016-11-22T13:44:07.856Z",
    "classes": [
        {"class": "Labradoodle"},
        {"class": "FriedChiken"}
    ]
}
```

## テスト(評価)
テストは例のツイッター画像を、それぞれ1つずつに切り取ってテストする。
VRは画像をzipにして一気にテストが可能なので、切り取った画像をチキンと犬に分けてtest_chichen.zip、test_labradoodle.zipにする。

あとは、Classifierを指定するjsonファイルを作成する。thresholdは分類クラスのスコアの閾値だ。スコアがこれを下回る場合は結果を返さない。が、テストするときは全部返してくれた方が色々と参考になるので、thresholdは0を指定しておく。V2では0.5が閾値だったためスコアがわからないケースがあったが、それの改善なのだろうか。よい変更である。

```json
{
  "classifier_ids": [
    "Chicken_or_Dog_1056118805"
  ],
  "threshold":"0"
}
```

これで実行準備完了だ。以下のコマンドでVRをテストしてみよう。

```bash
curl -X POST -F "images_file=@test_chicken.zip" -F "parameters=@myClassifier.json" "https://gateway-a.watsonplatform.net/visual-recognition/api/v3/classify?api_key={api_key}&version=2016-05-20"
```

# 結果！！
結果、こうなった。
![2016-11-23 22_58_22-PowerPoint Slide Show - [VR_APPL.pptx].png](https://qiita-image-store.s3.amazonaws.com/0/102519/10f0f92e-5da1-e7a3-88ea-ef119a3adbe8.png)
数字は、犬またはフライドチキンの画像であると推測したスコアを表している。

ん？スコアが低い？？
結果のオリジナルはこちら。

```json:結果から抜粋
{
    "custom_classes": 2,
    "images": [
        {
            "classifiers": [
                {
                    "classes": [
                        {
                            "class": "FriedChiken",
                            "score": 0.569074
                        },
                        {
                            "class": "Labradoodle",
                            "score": 0.0463844
                        }
                    ],
                    "classifier_id": "Chicken_or_Dog_1056118805",
                    "name": "Chicken_or_Dog"
                }
            ],
            "image": "test_chicken.zip/test_chicken/c1.png"
        },
      (略)
```

表にするとこうなった。

|イメージ|犬1|犬2|犬3|犬4|犬5|犬6|犬7|犬8|
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|Labradoodle |0.5549|0.4164|0.5309|0.4468|0.5064|0.5337|0.4296|0.3918|
|FriedChicken|0.0493|0.0833|0.0536|0.0737|0.0594|0.0536|0.0783|0.0909|

|イメージ|チキン1|チキン2|チキン3|チキン4|チキン5|チキン6|チキン7|チキン8|
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|Labradoodle |0.0463|0.0410|0.0474|0.0461|0.0449|0.0443|0.0527|0.0601|
|FriedChicken|0.5690|0.6002|0.5633|0.5703|0.5775|0.5801|0.5343|0.5019|

確かに正しい方のスコアが圧倒的に高い。が、0.4～0.6くらいのスコアになっている。スコアの範囲は0.0～1.0だし前回の結果を考えると、ちょっと低いような・・・

## もしかして、こういうこと？
うーん、と思って眺めていたら、とあることに気づいた。
<font color="red">**「もしかして、V2の頃は全クラスにおける割合として結果を出しているのでは？？」**</font>
Softmaxに近いような気がしたが、*exp*してないのでSoftmaxとは呼ばなさそう。でも何て言えばいいかわからん。。。
(参考：[Softmax](http://ibisforest.org/index.php?%E3%82%BD%E3%83%95%E3%83%88%E3%83%9E%E3%83%83%E3%82%AF%E3%82%B9%E9%96%A2%E6%95%B0))

ということで、割合を算出してみると結果は次のようになった。これならV2の頃と同じような数値だ。だがV2の頃は果たしてSoftmaxが使われていたのかどうか･･･今となっては知る由もない。公式リファレンスの説明にも「スコアだよ」としか書かれていない。もうちょっと詳しく説明してよ･･･。
![2016-11-23 22_58_49-PowerPoint Slide Show - [VR_APPL.pptx].png](https://qiita-image-store.s3.amazonaws.com/0/102519/22d6a65e-09d1-2ba1-4a4c-773a4dce7e30.png)

# 考察
とりあえずわかったことは、

- V3はどんなにスコアが低くても結果を返すことができる
- V3はV2よりもスコアが低めに出る
- 割合を計算するとV2時代のスコアに近くなるっぽい

という感じ。
特に最後の項目については、常に割合を出せばよいというわけではないのに注意が必要だ。

そもそもテスト用の画像がどのクラスにも似ていない場合、そのスコアは高くはならないはず。試しに今回の分類器に人間の顔を入れてみたら、チキン=約0.2、犬=約0.2という結果となった。これの割合は50%、50%だ。確かにどっちにも分類できるし分類できないという意味では50%は正しいのかもしれないが、果たして50%といってよいのだろうか･･･？割合を使う場合の前提は全ての値を足すと1.0(=100%)になる、つまり、その中のどれかが正解である、ということだ。だが、人間は犬ではないし、ましてやフライドチキンでもない。そういう場合に割合によるスコアの比較は意味をなさないかもしれない。

## 考慮点をまとめると

**スコアは割合が重要**
今回スコアの割合を計算したが、結構よい予測値になったのではないだろうか。
割合を使う場合、クラスAとクラスBの数値がどちらも同じくらいの数値になったら、どちらかの画像であると50%、50%で予想しているということだと考えられそうだ。だが課題もある(後述)。

**スコアの絶対値が重要**
やはりスコアが低すぎてもいけないと思う。今回の結果から考察するに、スコアは0.3以上あって欲しいものだ。もし、片方のスコアが0.009、もう片方が0.001だった場合、割合を計算すると前者は90%、後者は10%になる。といっても、スコア0.009のものが正しい答えであるとは言いづらい。ある程度絶対値が高くないと、割合を比較しても意味がなさそうだ。

**合わせ技で考えよう**
つまり、絶対値と割合を併用して総合的に判断することが必要だ。

# おわりに
V3でやってみたらスコアが低くなったときはビビった。**割合**という仮定を持ち出してみたが、果たして合っているかどうか気になるところ。

V3は色々と便利になっているので、スコアを適切に評価してうまく使っていって欲しい。

それでは今回はここまで。