OC-NNに基づく教師なし異常検知をPyTorchで実装した

はじめに

教師なし異常検知の機械学習モデルの一つとして、"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志向にしたいものだ。