Amazon SageMakerで「IP Insights」ビルトインアルゴリズムが使えるようになりました

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

概要

こんにちは、yoshimです。
「Amazon SageMaker」で「IP Insights」というビルトインアルゴリズムが使えるようになっていたので、早速調べてみました。

今まで「Amazon SageMaker」で提供されてきた機械学習モデルと比較すると、「利用用途が明確,かつデータも既に揃っていることが多そうなので使いやすそう」で面白そうです。

目次

1.「IP Insights」の概要

さて、「IP Insights」では何ができるのでしょうか?
「IP Insights」の紹介ページには下記のように書いてあります。
(2018年11月21日9時時点で、日本語ページに記述がなかったので英語の記述をgoogle翻訳で日本語にしたものです)

Amazon SageMaker IP Insightsは、IPv4アドレスの使用パターンを学習する教師なし学習アルゴリズムです。IPv4アドレスとユーザーIDやアカウント番号などのさまざまなエンティティ間の関連付けを取得するように設計されています。たとえば、異常なIPアドレスからWebサービスにログインしようとしているユーザーを識別するために使用することができます。または、これを使用して、異常なIPアドレスからコンピューティングリソースを作成しようとしているアカウントを特定できます。

どうやら「IPアドレス,エンティティの情報をベクトル化し、そのベクトルからIPアドレス-エンティティの関連性を計算し、異常な挙動を見つける」ことができるアルゴリズムのようです。
また、「IP Insights」の紹介ページには実用イメージについてもう少し記述してあります。

Amazon SageMaker IP Insightsは、「エンティティ、IPv4アドレス」をペアとして履歴データを取り込み、各エンティティのIPアドレスの使用パターンを学習します。「Amazon SageMaker IP Insights」モデルは、(エンティティ、IPv4アドレス)イベントで照会すると、イベントのパターンが異常であることを推測するスコアを返します。たとえば、ユーザーがIPアドレスからログインしようとすると、IP Insightスコアが十分に高い場合、Webログインサーバーはマルチファクタ認証システムをトリガーすることになります。より高度なソリューションでは、IP Insightsスコアを別の機会学習モデルに追加することができます。例えば、Amazon GuardDuty。

「IP Insightスコアが高い場合」のイメージについて、今回ご紹介するチュートリアルの結果を紹介するのが一番わかりやすいかと思います。

これは「正常なデータ」と意図的に作成した「異常データ」で「IP Insightスコア」を計測したものです。
(横軸が「IP Insightスコア」、縦軸が割合です。)
「異常データ」の計測結果をオレンジ色で描画しているのですが、「正常なデータ」と比較して「IP Insightスコア」が高い傾向にあることがわかります。
このように、「エンティティ-IPアドレス」のイベントに「IP Insightスコア」を計測し、値が高いデータについては「異常」と見なすことができる、というものです。

*「IP Insightスコア」は「dot_product」にマイナスをかけた数値で計算しています。

また、上記までの「異常検出」のような使い方以外にも「クラスタリング」に利用することもできます。

Amazon SageMaker IP Insightsアルゴリズムは、埋め込み(embeddings)と呼ばれるIPアドレスのベクトル表現を学習することもできます。このベクトル表現は、IPアドレスで観測される情報を使用する機械学習タスクの特徴量として使用できます。たとえば、似ているIPアドレスでクラスタリングし、可視化することもできます。

アルゴリズムの概要については以上です。続いて、チュートリアルで提供されているノートブックを実際に実行して、より理解を深めていこうと思います。

2.「IP Insights」の詳解

続いて、「IP Insights」のもう少し細かい部分について記述しようと思います。

2-1.利用するデータについて

「IP Insights」を「IPアドレス-エンティティ間の関連性から、異常な挙動を見つける」ことを目的として利用する場合、「異常な挙動のデータがないと、学習できないのでは」と思う方もいるかもしれません。
しかし、結論から言うと「正常なデータのみで学習が可能」です。というより、学習に利用するデータに異常なデータは入れないほうがいいです。
というのも、「IP Insights」の学習の仕組みとしては、「オリジナルデータと、ランダムに生成した異常データを識別するモデル」を学習するものだからです。

The algorithm trains a discriminator model , which learns to separate observed data points (positive samples) from randomly generated data points (negative samples).

引用:Tuning an IP Insights Modelより

では、この「ランダムに生成した異常データ」とはどのように生成するのでしょうか?
これは、「学習時に指定するハイパーパラメータ」で指定することになります。
具体的には、下記の2つを検討する必要があります。
いずれのハイパーパラメータも「1件の正常なデータに対して生成される異常なデータの件数」を指定するのですが、「異常データの生成方法」が異なります。

・random_negative_sampling_rate

ランダムに生成したIPアドレスを利用することで、異常データを生成する。
今回紹介するチュートリアルでは、「最初は1を指定するのが良い」と記述してありました。

・shuffled_negtiave_sampling_rate

学習に利用するデータから、「エンティティ-IPアドレスをシャッフル」して異常データを生成する。 今回紹介するチュートリアルでは、「最初は1を指定するのが良い」と記述してありました。

長くなりましたが、とりあえず「正常なデータ」から「random_negative_sampling_rate」、「shuffled_negtiave_sampling_rate」を1に設定して始めるのが良さそう、といったところのようです。 ただ、もし「異常データ」があるようなら、「異常とみなす閾値を決定」する際に利用できます。

2-2.閾値の決定

「IP Insights」でモデルを生成した後は、「IP Insightスコア(dot_productにマイナスをかけた値)がいくつ以上だったら異常データとみなすか」という閾値を決定する必要があります。
これは「最終的な利用目的」、「データの内容」に合わせて設定する必要があるため、ちょっと大変です。

例えば、「異常データの検出が漏れた場合、業務上大きな悪影響がある」場合はこの閾値を小さめの値に設定した方がよく、逆に「正常なデータを異常データだと誤検知したくない」場合は大きな値にする必要があります。
また、「具体的に閾値にどんな値を設定するか」については、「異常データ」と「正常データ」を使って分布を確認するやり方が良いでしょう。
こちらの例ですと、閾値が0付近のところで「正常・異常データ」の比率が逆転していることも確認できます。

2-3.GPU、CPUのいずれを使うか

「IP Insights」の学習・推論にはGPU、CPUのいずれも利用可能です。
GPUの方が処理が早いので基本的にはGPUで処理するのが良さそうなのですが、データ量が増えるようならCPUで分散処理した方がコスト的に良い、とのことです。

ipinsights-tutorial.ipynb

Then, we need to determine the training cluster to use. The IP Insights algorithm supports both CPU and GPU training. We recommend using GPU machines as they will train faster. However, when the size of your dataset increases, it can become more economical to use multiple CPU machines running with distributed training. See Recommended Instance Types for more details.

3.チュートリアル

前置きが長くなりましたが、チュートリアルを触ってみようと思います。
とはいえ、実行コードはこちらにある通りなので、「要点のみ」を記述します。

3-1.チュートリアルの流れ

チュートリアルは大まかに下記のような構成になっています。

  • データの取得、前処理、S3への保存
  • モデルの学習
  • エンドポイントにデプロイし、推論

この流れはどの機械学習アルゴリズムでもほぼほぼ同じものになりますが、「推論時に閾値を指定」する点には気をつけましょう。

3-2.学習に利用するデータのフォーマット

学習に利用するデータの準備について、いくつか確認するべきことがあります。

まず、学習に投入するデータは、下記のように「エンティティID,IPv4アドレス」の2列で、「ヘッダーのないcsv」である必要があります。
また「IPv4アドレス」は「.」で区切られている必要があります。

詳細についてはIP Insights Training Data Formatsをご参照ください。

3-3.学習に利用するデータをシャッフルする

また、もしデータが「時系列」等でソートされているようなら、「ランダムにシャッフル」した方が最終的な推論の精度がよくなります。

Shuffling improves the model's performance since SageMaker IP Insights uses stochastic gradient descent. This ensures that login events for the same user are less likely to occur in the same mini batch. This allows the model to improve its performance in between predictions of the same user, which will improve training convergence.

引用:チュートリアル

3-4.推論結果のフォーマット

デフォルトだと、下記のようなjson形式で返ってきます。
この「dot_product」は「IPアドレスをユーザーが利用しているっぽさ」を意味しており、「値が高ければ高いほど正常なデータ」と見做すことができます。

{'predictions': [{'dot_product': 3.8872947692871094},
  {'dot_product': 3.2846269607543945},
  {'dot_product': 4.157506465911865},
  {'dot_product': 4.2245306968688965},
  {'dot_product': 4.985958576202393}]}

一般的には、この値を使うだけでも十分だと思いますが、もしもより高度なことをやる必要がある場合は、下記のような設定をしてから推論しましょう。

predictor.accept = 'application/json; verbose=True'
predictor.predict(inference_data)

すると先ほどまで取得できていた「dot_product」以外に「ip_embedding」、「entity_embedding」という値が取得できます。
この2つの値は「dot_product」を計算するために利用している値です。これらの値を使って、自前で分析したい方はこの値を使いましょう。

{'predictions': [{'ip_embedding': [0.13874202966690063,
    0.17863915860652924,
    .
    .
    'entity_embedding': [-0.20224013924598694,
    -0.36146488785743713,
    .
    .  
    0.3696984052658081],
   'dot_product': 3.8872947692871094},

3-5.閾値の決定

「dot_product」にマイナスをかけた値が○○以上だったらそのデータを異常と見做す、という閾値を決定します。
今回のチュートリアルでは、用意していた正常データに「異常データ」をスクリプトで生成して、分布を確認しています。

分布で確認した後は基本的な評価指標で定量的な確認もした方がいいでしょう。
参考までに、私がチュートリアルをもとに少し修正したものを記述しておきます。

・スクリプト

threshold = 0.0

flagged_cases = test_case[np.array(test_case_scores) > threshold]

num_flagged_cases = len(flagged_cases)
num_true_positives = len(flagged_cases[flagged_cases['label'] == 1])
num_false_positives = len(flagged_cases[flagged_cases['label'] == 0])
num_all_positives = len(test_case.loc[test_case['label'] == 1])
precision = num_true_positives/float(num_flagged_cases)
recall = num_true_positives/float(num_all_positives)
f_value = (2 * precision * recall) / float(precision + recall)

print("a.閾値: {}".format(threshold))
print("b.全ケース:{}".format(len(test_case_scores)))
print("c.テストに使ったデータのうち、異常であるケース数:{}".format(num_all_positives))
print("d.異常と予測したケース数:{}".format(num_flagged_cases))
print("e.異常と予測して、本当に異常だったケース数;{}".format(num_true_positives))
print("f.精度(e/d): {:.4f}".format(precision))
print("g.再現率(e/c): {:.4f}".format(recall))
print("h.F値(2*f*g/(f+g)): {:.4f}".format(f_value))

・結果

a.閾値: 0.0
b.全ケース:200000
c.テストに使ったデータのうち、異常であるケース数:100000
d.異常と予測したケース数:103289
e.異常と予測して、本当に異常だったケース数;98539
f.精度(e/d): 0.9540
g.再現率(e/c): 0.9854
h.F値(2*f*g/(f+g)): 0.9694

4.まとめ

「IP insights」は今まで提供されてきたアルゴリズムと比較すると、「利用用途が明確」で使いやすいアルゴリズムだと感じました。
機械学習に興味のあるエンジニアの方は、自社データ等で試してみると面白いのではないでしょうか。