はじめに
教師なし異常検知の機械学習モデルの一つとして、"One-Class Neural Network" (以降OC-NN)が知られている。 今回はこれを、異常検知/外れ値検知のためのPythonパッケージPyODの仕様に沿った形で、PyTorchにより実装したということである。
異常検知について
以下の記事を読むのが良いだろう。 qiita.com
深層学習を用いた異常検知技術について
以下の解説論文を読むのが良い。OC-NNについての解説もある。 www.jstage.jst.go.jp
One-Class Neural Network(OC-NN)について
OC-NNはDeep SVDDと同時期に提案された教師なし異常検知モデルであり、OC-SVMを深層学習を用いて拡張したものとして位置づけられる。 OC-SVMの損失関数のカーネル計算および重みとの内積計算をニューラルネットワークで置き換えている。
論文は以下から読むことができる。ver 1 (KDD2018)とver 2で掲載されている実験が異なっていたりするので、両方に目を通すのがよい。特に後者にはDeep SVDDとの比較実験が載っている。 arxiv.org
先述の解説論文に加えて、解説スライドおよび解説記事へのリンクを以下に置く。
www.slideshare.net www.smartbowwow.com作成したクラス:OneClassNN
OC-NNの実装は探すとTensorflowやPyTorchのものが見つかるが、自分には少々使いづらいものだったので、改めて実装を試みた。 オートエンコーダによる重みの事前学習も可能にしてあるが、あまり使う機会はないかもしれない。 ほか実装にはまだ怪しい箇所があるかもしれない。
【コードを表示する】
gist.github.com
注意点
前回記事のDeep SVDDと同様に、ニューラルネット部分は全結合層のみからなっている。 画像データを対象にする場合には畳み込み層やプーリング層へと実装を修正する必要がある。
デモンストレーション
PyODから提供されている各種アルゴリズムのexample用スクリプトを参考に、簡単なデモンストレーションのnotebookを作成した。 今回作成したOneClassNNクラスをocnn.pyとして保存した場合のnotebookである。 データの生成および評価にはPyODから提供されている関数generate_dataおよびevaluate_printをそれぞれ用いた。
300次元の疑似データ量をいくつか変えて試してみた。疑似データが簡単すぎるせいか、今回は検出精度がかなり高く出た。 gist.github.com
おわりに
前回記事のDeep SVDDの実装ができたので、それを参考にすれば今回のOC-NNの実装は比較的容易だった。
とはいえ実際に実装すると理解が進む(それはそう)。例えば損失関数の計算について、データで平均を計算している箇所はtorch.mean()
として「ミニバッチ内の平均」として翻訳できる。またmax(0, 某)の箇所はtorch.max(torch.zeros_like(某), 某)
として明示的に計算するか、もしくはミニバッチのsample-wiseにrelu関数(torch.nn.functional.relu
)を通す、という翻訳ができるなど。
先に述べたとおり、OC-NNの上記論文にはDeep SVDDとの比較実験も載っている。 Deep SVDDを上回る性能を示すケースも見られたが、下回ることもあり、「匹敵する」モデルと言えるだろう。
OC-NNはDeep SVDD同様に特徴量空間に写像した圧縮表現に基づいており、元のデータの「構造」に関する情報は多少なり落ちている。 それゆえ、圧縮表現を得るためのencoderの相対的な重要性が増しているが、OC-NNは外付けネットワークからのencoder出力を使っている。 論文の図(ver1はFigure 2, ver2はFigure 1)ではencoder部分はfreezeと書いてある。そして本文を読むと、ver1では"frozen (not trained)"と書いてあり、ver2では"not frozen (but trained)"と書いてあったりする(どっちやねん!)。前者は事前学習したオートエンコーダのencoder重みを与えて固定しており、後者はOC-NNのfeed-forward部分の重み更新時に、encoder部分の重みまで一緒に更新するということを意味する。
たとえdeep系を使うにせよ良質な特徴抽出(と潜在表現獲得) is all you needな感はあるが、いずれにせよもう少しend-to-end志向にしたいものだ。