はじめに
こんにちは。MLエンジニアの福成毅です。
私は、ある自社プロダクトの要素技術として時系列異常検知モデルの開発に携わってきました。(2019/10 〜 2020/03) 異常検知には今まで取り組んだことがなかったですが、時間をかけて様々なアプローチがあることを学びました。 異常検知は、機械の故障やシステム障害などにおいて発生する異常データを見つけ出すということですが、様々な産業での応用が期待されています。
一方で教師データ(特に異常データ)の不足や時系列特有の制約など、どうしても難易度が高くなりがちなタスクでもあります。
この連載では、業務を通して得た学びとして、自分なりに時系列異常検知を再解釈し、経験を基にいくつかの切り口で手法を紹介していきます。 また、上記モデル開発の初期PoCを通しての気づきや実際ハマったところについても共有していきます。
何回かに分けて投稿しますので、少し長くなりますが、おつきあい頂ければ幸いです。
基本的な考え方
ここでは異常検知の基本的な考え方について述べていきます。
教師なし学習
異常検知は教師あり学習・教師なし学習どちらでも解くことができますが、 どちらかというと教師なし学習の方がスタンダードなやり方になります。
イメージとしては、まず「正常モデル」のみを作り上げ、 この正常モデルでは「理解」できなかったデータは異常と考えるということです。
ちなみに正常と異常が選り分けられなくていなくとも、異常データが正常データに比べてごくわずかであれば、異常データがノイズとなるだけで正常モデルを作ることができます。(とはいえ正常データのみで正常モデルを作ることがベストではありますが・・・)
教師あり学習の難しさ
なぜ教師なし学習が異常検知においてスタンダードなのか。 異常検知は教師あり学習・教師なし学習どちらでも解くことができます。 ただその中で「異常検知は教師なし学習で行うのがよい」ということを皆さんはよく耳にするかと思います。 もちろんラベルさえあれば教師あり学習でも行うことは可能ですが、いくつかハードルを乗り越える必要があると思います。
具体的には、以下のようなケースがあると考えられます。
異常データが少なすぎる
そもそも異常は滅多に起こらず(だからこそ「異常」なのですが)、 正常データは十分あるが異常データがほとんど得られないということが考えられます。 このような不均衡データでモデルを作るとどうしても予測が正常に偏りがちになります。
またモデルが作れたとしてもかなり不均衡なデータになり、教師あり学習その問題にも対処する必要が出てきます。
未知の異常に遭遇する可能性が高い
いままで運良く故障しなかった箇所の故障、新手の詐欺・ハッキングetc... 大方我々を待ち受けているのは未知の異常です。これまでの既知の異常でモデルを作ったとしても、未知の異常が得られるたびに、再学習や時には問題設定の変更を強いられることになります。
そもそもラベルがない
よくある話です。まだ異常に遭遇していなかったり、異常のパターンが網羅できてなかったりすることが理由として考えられます。 また後に述べますが、正常の定義が変わっていくことでラベルをつけることができないケースも考えられます。
確率分布による正常モデル
ではその「正常モデル」をどうやって作っていくか。色々方法はあるかと思いますが、まず思いつくものとして確率分布を考えることかと思います。 ざっくりとですが、正常データでヒストグラムを作り、それを滑らかにするイメージです。 ここでの正常データは、異常が含まれていないか、含まれていたとしてもごくわずかであることを前提とします。 ごくわずかであれば含まれていてもよいというのは、わずかであればモデル化の際に無視されるためです。
そして異常かどうか調べたいデータが上記の分布において確率が低いところで観測された場合、 正常とされる中でめったに起こらないことが起こった = 別の分布から発生したのではないか?と疑うことができます。つまり正常ではないということです。どれぐらいの低確率だったら異常とするか = 閾値をどれくらいにするかは調整次第ですが、様々な手法は概ねこの考え方に帰着しそうです。
また、分布そのものを考えなくとも、統計量で考えることも可能です。例えば、正常データの平均値からの距離が標準偏差×定数倍を超えたら異常とする、といったものです。データが少なすぎてどうしても分布を推定できそうにない時に役立ちそうです。 (他にも距離で考えるアプローチなど色々ありますが、後ほど追って紹介していきます。)
時系列データにおける考え方
以降では、時系列データにおける異常検知の考え方について述べていきます。
時系列データにおける異常検知は、同じ時系列に正常だといえる期間と比べて異常かどうかを吟味することになります。
まず、時系列データの中で二つの区間を決めます。 正常と定義したベースラインの区間をここでは「参照区間」とします。 対して、その参照区間と比べて異常かどうか調べたい区間を「評価区間」とします。
そして参照区間でモデルを作り、評価区間でのデータをそのモデルで「理解できない」とした時に 「参照区間に対して評価区間が異常である」と言えます。
大抵のタスクでは、直近の時系列に対して異常かどうかを判定したい場合が多いので、 参照区間と評価区間を隣り合わせにすることがポイントです。 そして下図のようにスライドさせることで、すべての区間で異常かどうかを調べていく、という流れになります。
また私自身で経験はしていませんが、もし正常な区間が明確にわかっているようなタスクの場合は、参照区間を正常な区間に固定し、 評価区間のみをスライドさせることも考えられます。(機械の故障検知などでみられるのでしょうか?)
時系列異常検知のタスク
時系列における異常検知のタスクとして みなさんがよく耳にするのは「外れ値検知」「変化点検知」この2つかと思います。 なんとなく違いをイメージできるかと思いますが、 ここでは、先ほど紹介した参照区間と評価区間の枠組みで改めて振り返ってみたいと思います。
評価区間を1点にする → 外れ値検知
評価区間を1点とることで、「1点」が異常かどうかを調べることになります。 これが「外れ値検知」とよばれるタスクになってきます。
そしてざっくりとですが、外れ値検知はさらに2種類に分けられます。
1つが時間依存しない外れ値です。 つまり時系列をシャッフルさせても外れ値としてわかるものです。 値そのものがイレギュラーな値になるので、先ほどの確率分布による正常モデルで考えることができます。 また、閾値を持たせることでルールベースでも解けそうだというのがわかります。
もう1つが時間依存する外れ値です。 値そのものとしてはおかしな値でもないのですが、文脈的にみるとおかしく見えるものです。 このような外れ値の場合はChangeFinderのような時系列予測系のモデルを用いた方がうまく解けそうです。
評価区間を2点以上とる → 変化点検知
逆に評価区間をある程度の長さをとることで、「変化点検知」とよばれるようになります。
参照区間を正常と仮定することで、評価区間では「カタマリ」として異常が出てくることになります。
参照区間と評価区間を隣り合わせにしていることが前提ですが、 上記が起こった場合、参照区間と評価区間で何かしらの「変化」が生じたということが言え、 区間の境目が「変化点」ということになります。
これに対するアプローチも様々かと思いますが、 代表的なものとしては、下図のように部分時系列ベクトルにデータを変換してから外れ値検知的なアプローチに持ち込む、というのがシンプルな方法かと思います。
また、これまでは正常区間のみでモデルを作ることをお話ししてきましたが、 評価区間にも十分データが揃うので、評価区間でもモデルを作ることが可能になってきます。 分布のイメージだと、参照区間と評価区間でそれぞれ分布ができるようなものです。 あとは分布そのものを比較したり、また後述する分布の比を求める方法で異常かどうか調べていくことができます。
今回はここまでです。次回以降は、様々なアプローチの紹介や、PoCを行なって行く上でのハマりどころ などについて述べていく予定です。
参考文献
おわりに
エクサウィザーズは優秀なエンジニア、社会課題を一緒に解決してくれる魔法使い”ウィザーズ”を募集していますので、ご興味を持たれた方はぜひご応募ください。
採用情報|株式会社エクサウィザーズ
ExaWizards Engineer Blogでは、AIなどの技術情報を発信していきます。ぜひフォローをよろしくお願いします!
Linkedinもどしどしフォローお待ちしています!