ディープラーニングを使った画像認識、やってみたらうまくいきましたという話をよく目にするようになりました。

フレームワークの整備が進み、その上で動く個々のアルゴリズムの実装が公開され、中身の詳しいところまで立ち入らなくてもその高い性能を比較的簡単に利用できるようになってきたのです。これは素晴らしいことで、成熟したテクノロジーとはこうでなくてはいけません。

一方で「うまくいきました」っていうのはちと微妙な概念で、ざっくり感満載(笑)です。動作の確認程度ならいいのですが、パラメータを変更したり、学習データ数を増やしてうまく学習が進んでいるのか説明したいときなど、そのうまくいってる度をなんらかの形で数字にしたくなりますよね。

画像認識の汎用タスク(*)のうち、Classificationに対する評価は比較的簡単です。基本は各画像ごとに正解だったか不正解だったかをだせばいいわけです。(* Classification, Object Detection, Semantic Segmentation)

もう少しきちっとやるときには以下のように結果の分類をします。動物の写真判定を例としましょう。推測結果を以下のように分類します。

TP (True Positive): 猫だと判定して実際に猫の写真だったとき
FP (False Positive): 猫だと判定したけど猫の写真じゃなかったとき
FN (False Negative): 猫の写真を猫と判定できなかったとき



左から推定が猫、猫、スフィンクス、正解は猫、犬、猫 -> TP, FP, FN

これらの測定値を使って、正解率として、PrecisionとRecallというものを定義します。

Precision(精度) = TPの数 / (TPの数+FPの数)
Recall(再現率) = TPの数 / (TPの数+FNの数)

精度は推測が正しい確率(ただし見逃しても=FNは影響しない)、再現率はどれだけ見逃せずに推測できたかの確率(ただし間違えて推測=FPしても影響しない)を意味することになります。

さらに、F値といって、この二つの値の調和平均をとったものを指標とすることもあります。

F-measure = 2*Recall*Precision / (Reall+Precision)

今回のパラメータ設定はPrecisionはいいけどRecallがイマイチとか、PrecisionとRecallのバランスが良くてF値が高いとかそういう使い方をします。

さて、実は今回の本題はClassificationではなくてSemantic Segmentationの評価法についてなので、Classificationについてはこれくらいにしときます。

Semantic SegmentationはピクセルレベルのClassificationと考えることができますので、評価としても同様に考えることができます。ただClassificationと違って、Semantic Segmentationにはひとつの画像のなかで複数のクラスがあり各ピクセルはどこかのクラスに所属します。

なのですべてのピクセルを各クラスごとに

Precision = TPの数 / (TPの数+FPの数)

とすれば、Precision が求まります。複数の画像についてこの平均をとればAP(Average Precison)が求まり、さらにAPのクラス平均をとれば mAP (mean Average Precision)が求まります。

もうひとつ別の評価指標をご紹介しましょう。Semantic Segmentationはピクセルが独立してクラスに所属できますが、実際にはある程度の固まった領域が何らかのクラスに所属します。(じゃないと意味のある自然画像にならないので)

こんな感じです。


一般画像認識のひとつ、Object Detectionは矩形でオブジェクトを判定する性質上、必然的に画像上に面積をもった推定領域があり、その評価としてはIoU (Intersection over Union)がよく用いられています。

IoUの解説についてはひとまず

https://www.pyimagesearch.com/2016/11/07/intersection-over-union-iou-for-object-detection/

が詳しいのでご参照ください。

これに倣い、Semantic SegmentationでのピクセルをIoUの定義にあわせて分類します。

また猫の例で考えれば

GT: (Ground Truth、正しい猫領域のピクセル)
PR: (Prediction、猫領域と推定したピクセル)
TP: (True Positive、正しく猫領域と推定されたピクセル)

IoU = TP / (GT+PR-TP)

これを複数枚について計算したものが average IoUとなり、さらにそのクラス平均値をとれば mIoU (mean IoU)となります。

では、実際に計算してみましょう。Semantic Segmentationのデータ表現としては、

1. indexed pngのインデックスで表現する方法 (index番号がクラス番号)
2. BMPの実値で表現する方法 (実値がクラス番号)

が考えられます。どちらでもいいのだけど、2の方は直感的で作りやすい一方で、そのまま絵を表示したときにわかりにくい(クラス数が小さいと真っ黒な画像にしかみえない)です。

RefineNetのbmpoutブランチに推測結果をbmpで出力するコードを入れたpredict.pyをおいてあります。

https://github.com/ponta256/chainer_refinenet

また以下に、mAPとmIoUを計算するスクリプトを起きました。

https://github.com/ponta256/metirics

ひとまず正当データの方がindexed png, 推測データの方がbmpを想定しています。
$ python ss_metrics.py valid.png pred.bmp 
valid.png
Class  0: correct 228194, incorrect     15, accuracy 1.0
Class  1: correct   1529, incorrect    662, accuracy 0.698
Total   : correct 229723, incorrect    677, accuracy 0.997
Mean Accuracy   : 0.849

Class  0: IoU 0.997
Class  1: IoU 0.693
Total IoU  : 0.994
Mean IoU   : 0.845
のように結果が表示されます。これはClass0がバックグラウンドで領域サイズが大きいので、実際にはClass1の結果に着目して評価するタイプの例です。

今回は以上になります。画像認識の定量評価を検討される方の一助になれば幸いです。

#いつものことですが、何か勘違いしてたらご指摘いただけるととうれしいです。^_^