【コード検証中】【精度対決】リアルな画像で異常検知

[前回の記事](https://qiita.com/shinmura0/items/ee074172ec3c818b614e)では、SSIMオートエンコーダによる異常検知を紹介しました。

是非とも「metric learningによる異常検知」と比較したいと思い、調べていたところ、
SSIMの精度が出ている論文を見つけました。

そこで、本稿では以下のことを行います。

+ まずは、論文の中身を紹介します。
+ 論文中のSSIMの精度と「metric learningによる異常検知」の精度を比較します。

※こちらは[Pythonデータ分析勉強会#11](https://pythondata.connpass.com/event/142084/)の発表資料です。
※全体のコードは[こちら](https://github.com/shinmura0/AutoEncoder_vs_MetricLearning/blob/master/L2_vs_Autoencoder.ipynb)に置いています。

#結論から
論文のデータセットを使って実験したところ、「論文に出てくる全ての異常検知手法
（SSIMオートエンコーダを含む）に対し、**metric learningによる異常検知の方が
良いスコアを出しました。**」

#論文の中身
※本稿の図は、基本的に論文（[MVTec AD — A Comprehensive Real-World Dataset for Unsupervised Anomaly Detection](http://openaccess.thecvf.com/content_CVPR_2019/papers/Bergmann_MVTec_AD_--_A_Comprehensive_Real-World_Dataset_for_Unsupervised_Anomaly_CVPR_2019_paper.pdf)）より引用しています。

まずは、論文の中身をざっとご紹介します。

+ 異常検知のデータセットを提供する論文です。CVPR2019で公開されました。
+ データセットは実際のテクスチャーや物体を写したもので、正常な写真と異常な写真が添付されています。
+ 各種異常検知手法のベンチマークも同時に行い、精度と可視化について定量的に評価しています。
+ データは[こちら](https://www.mvtec.com/company/research/datasets/mvtec-ad/)よりダウンロードできます。（何故かPythonのAPIを叩かないとダウンロードできませんでした。）
+ データセットの数は以下のとおりです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/e5838313-6f86-eb65-61bf-1742cd9a4b8d.png)
1クラスの学習データは大体200個を超えています。
テストデータの数は異常＞正常となっており、かなり不均衡です。

ちなみに、Cable,Capsule,Leather,Carpetのテストデータは以下のとおりです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/3a2d4af8-2520-58ae-c669-8d04834a4e7d.png)

ケーブルが無かったり、銅線が無かったり、欠け、印字ミス、傷、打痕、染みなど
多種多様な欠陥があります。

解像度は700 x 700 ～ 1024 x 1024と幅があるようです。

#論文に登場する異常検知手法たち
一応、論文中に出てくる異常検知手法たちを紹介します。
結論からいって、論文ではオートエンコーダ($l2$、SSIM)が良いスコアを示しました。

+ オートエンコーダ($l2$)、オートエンコーダ(SSIM)
この手法は[前回の記事](https://qiita.com/shinmura0/items/ee074172ec3c818b614e)を参考にしてください。

+ AnoGAN
この手法は[こちら](https://qiita.com/NakaokaRei/items/231ec4efe42dfe79d1ff)に詳しく載っています。

+ CNN Feature Dictionary
ImageNetで学習させたモデルを使って、GlobalAgeragePoolingの出力をPCAで次元圧縮する
手法のようです。最終的にはk-means法を使うようです。metric learningに似ていますが、
スコアはイマイチです。

+ GMM-Based Texture Inspection Model
+ Variation Model

一応、精度を載せておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/5669ce25-9cc9-d1e6-46b7-d6f068c6b8ea.png)

上段はTrue positive rate（再現率）、下段はTrue negative rate（特異度）を示しています。
論文では、AUCではなく、この二つの和が一番大きいものを良い異常検知手法としています。

#実験条件
SSIMとmetric learningによる異常検知の性能を比較するために
実験を行います。

※全体のコードは[こちら](https://github.com/shinmura0/AutoEncoder_vs_MetricLearning/blob/master/L2_vs_Autoencoder.ipynb)に置いています。Colabで動くはずです。

+ MVTEC-ADから難しそうなデータを4つ選定しました。
+ 今回は精度のみを比較します。可視化の比較は行いません。
+ 選んだデータの数は以下のとおりです。

|画像の種類|学習データの数|テストデータ（正常）の数|テストデータ（異常）の数|
|---|---|---|---|
|Cable|224|58|92|
|Leather|245|32|92|
|Carpet|280|28|89|
|Capsule|219|23|109|

##SSIMオートエンコーダ（論文より引用）
+ SSIMを適用する窓のサイズは11 x 11
+ オートエンコーダの入力画像サイズは256 x 256
+ 潜在変数は100
+ 学習データはDataAugmentationにより10,000個に増幅

##metric learning
+ 学習データは上記4種類のデータ全てを渡しました。つまり、968個のデータです。
+ 入力画像サイズは224 x 224
+ 今回使うmetric learningはL2 SoftmaxLoss
+ epochは50、最適化手法はSGD
+ バッチサイズは128
+ ベースモデルはMobileNet V2($\alpha=0.5$)（学習済モデルを使用、つまり転移学習）
+ 異常スコアはLOFで算出
+ 10回試行して、それぞれの試行で再現率と特異度の和が高いものを採用

###アンサンブル異常検知
metric learningについて、更なる高精度を目指してアンサンブル学習を行います。

アンサンブル学習といっても、やることは単純で、複数のモデルを用意して異常スコアの
平均値をとるだけです。今回は同一構造のモデルを3つ用意し、全く同じデータで学習
させました。

異常検知のアンサンブルは、必ずしも精度向上につながるわけではありません。
ここが教師あり学習と違うところです。精度が上がったら、めっけもんです。

#実験結果
##Cable
論文では、ケーブルで一番スコアが出たのはSSIMでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/1bc5ca36-ba50-554c-e696-66e6e52174f1.png)

下の図（自作）は「再現率と特異度の和」と「AUC」を示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/7b4eeb75-4071-c1a0-d918-0ed2191159fa.png)

左図のように、metric learningのスコアがSSIMを大きく上回っています。
また、右図からも分かるとおり、単一のモデルよりアンサンブル学習の方が
スコアが上がります。

異常スコアと画像の特徴を見てみます。

異常スコアが大きいと、**正常からかけ離れたもの**を意味します。
まずは、異常スコアが大きい異常サンプルです。

![high__.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/01fb0c8a-0bf3-4f98-3f3a-bf215618fe75.png)

ご覧のようにケーブルがないものやリード線が折れ曲がっているものがあり、
とても分かりやすい異常サンプルです。

続いて、異常スコアが小さい異常サンプルです。

![low__.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/88f6ce21-6fe3-280b-759b-8d3c1329e214.png)

リード線がないものや外のケーブルが割れているものがあります。
直観的にケーブルの割れは分かりやすい気がしますが、異常度が小さいと
判断されています。

##Leather
論文では、革で一番スコアが出たのはCNN Feature Dictionaryでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/b919fc4f-c310-12c5-2bb9-be3a8bcb0d7e.png)

下の図（自作）は「再現率と特異度の和」と「AUC」を示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/585372db-159a-b0a6-1eaa-ffc715b0ea60.png)

ケーブルと同じような結果になっています。
metric learningの方が、そして、アンサンブル学習の方がより良いスコアが出ています。

異常スコアと画像の特徴を見てみます。
まずは、異常スコアが大きい異常サンプルです。

![high___.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/1a8e4da0-df13-db11-63ff-22c4adefd4cd.png)

打痕が大きいものが多く、とても分かりやすい異常サンプルです。
異常スコアが大きいのも頷けます。

続いて、異常スコアが小さい異常サンプルです。

![low___.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/472f6643-4041-6595-7a2b-2a0d38ffeab6.png)

小さな傷があるものが多い印象で、分かりにくい異常サンプルです。

##Carpet
論文では、カーペットで一番スコアが出たのはSSIMでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/52a9506f-188b-4a02-41fe-b5dc811129ff.png)

下の図（自作）は「再現率と特異度の和」と「AUC」を示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/6de98db3-1dc7-f22a-2499-dac50c0fbbc0.png)

左図より、L2-SoftmaxLossの中央値はSSIMを上回ることが分かりました。
単一のモデルとアンサンブル学習の比較では、ほぼ同じスコアが出ています。

異常スコアと画像の特徴を見てみます。
まずは、異常スコアが大きい異常サンプルです。

![high_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/8f01afad-c641-acc8-33c3-1ab2dc7ba943.png)

変色や大きな傷、糸のほつれなどが目立ちます。
かなり分かりやすいサンプルと言えそうです。

続いて、異常スコアが小さい異常サンプルです。

![low_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/c3349dcc-ed0a-b84b-9b09-a0d25d5f20ba.png)

変色しているものや染みがあるのは分かりますが、異常部分がどこなのか
見つけられないものもあります。これはかなり難しいサンプルと言えそうです。

##Capsule
論文では、カプセルで一番スコアが出たのはL2でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/d59031e7-2611-4468-b339-4253f68c2afa.png)

下の図（自作）は「再現率と特異度の和」と「AUC」を示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/a9c1e84f-5396-3c3e-1dd5-4c3350ddc10c.png)

左図より、L2-SoftmaxLossの中央値はSSIMを上回っていることが分かります。
一方、このサンプルだけは、**単一モデルの方が**アンサンブル学習よりも優れていました。

結果的に、metric learningでは、カプセルのスコアが伸び悩みました。
ただ、次回紹介する黒魔術を使えば劇的にスコアを上げることができます。
具体的には**AUCで0.9を超える結果が出ています。**

異常スコアと画像の特徴を見てみます。
まずは、異常スコアが大きい異常サンプルです。

![high.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/dbed19fc-99ac-f2c0-0f26-28d95cb99532.png)

変形したものや印字ミス、欠損などが目立ちます。
とても分かりやすい異常サンプルです。

続いて、異常スコアが小さい異常サンプルです。

![low.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/62b370ef-8030-d1f9-6127-797605c1acb1.png)

パッ見て分かるのは印字ミスくらいで、それも僅かな異常と言えそうです。
その他のサンプルは、異常部分を見つけることが難しそうです。

#考察
なぜ、「SSIMオートエンコーダ」より「metric learning」の方が良いスコアを出したのか
考察してみます。

+ ハイパーパラメータの調整
正直、論文ではハイパーパラメータの調整は行われていないと思います。従って、SSIMではもっと精度が出るはずです。ただ、「metric learningのLeatherのスコア」に迫れるかといわれると疑問が残るところです。

+ カラー対応
SSIMは基本的に**グレースケールの画像にしか対応できません。**従って、この論文でもカラー画像をグレースケール画像に変換してベンチマークを行っています。そのためカラーの情報が欠如しており、精度が上がりにくいと思われます。metric learningはカラー画像に対応しています。

+ 教師無し学習
SSIMは純粋な教師無し学習です。しかし、metric learningは半教師あり学習に分類されるらしいです。つまり、SSIMは約200枚の正常画像を見て正常な範囲を決めていますが、metric learningは正常画像とは関係ない画像（本稿では、700枚）を見て正常な範囲を決めることができます。これは大きな差になると思われます。

+ 転移学習
SSIMでは転移学習は使えませんが、metric learningでは転移学習が使えます。転移学習はディープラーニングを適用する上で、かなり有利に働きます。精度アップはもちろんのこと、学習時間も速くなるので、運用上のメリットも生まれます。

#metric learning 精度アップのコツ
+ エポックはあまり大きくしない方が良いです。大きくすると、学習済の重みが壊れてしまうので精度が下がります。
+ 最適化手法はAdamよりSGDの方が良いようです。Adamにすると、やはり学習済の重みが壊れてしまうと思われます。
+ 参照データは多過ぎると良くないようです。最初、cifar-10のデータ2000個を混ぜて学習させましたが、精度が下がりました。
+ ベースモデルをInceptionResNetV2へ変えたところ、精度が下がりました。
+ DataAugmentationは精度アップにつながりませんでした。元々、metric learningは過学習しにくいと言われており学習データが1クラス当たり200個あれば十分なのでしょう。
+ 学習データ数が少数の場合、**ArcFaceが良い**という[報告](https://qiita.com/daisukelab/items/5f9ec189959eaf1ef211#a2-%E5%B0%91%E3%81%AA%E3%81%84%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%81%AE%E5%A0%B4%E5%90%88%E3%81%AE%E6%AF%94%E8%BC%83)もあり、L2SoftmaxLossよりArcFaceの方が良いスコアが出るのかもしれません。
+ 黒魔術を使う（[次回記事](https://qiita.com/shinmura0/items/6c805498c390d5b35714)参照）

#まとめ
+ MVTEC-ADはかなり難しいデータセット。異常検知分野の「ImageNet」になり得るかもしれない。
+ metric learningは、論文中のどの異常検知手法よりも良いスコアを出した。アンサンブル学習もやってみる価値はある。
+ しかも、ベースモデルをMobileNetにできる上、デコーダー部がないので、オートエンコーダよりも高速化することが可能。
+ metric learningは異常部分の可視化が弱いのが難点。誰か画期的なアイデアを出してください。

[次回](https://qiita.com/shinmura0/items/6c805498c390d5b35714)は、異常検知性能を劇的に向上させる黒魔術を紹介します。