ホーム » 変分オートエンコーダ
「変分オートエンコーダ」カテゴリーアーカイブ
Alibi Detect 0.7 : Examples : VAE 外れ値検知 on CIFAR10
Alibi Detect 0.7 : Examples : VAE 外れ値検知 on CIFAR10 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 07/04/2021 (0.7.0)
* 本ページは、Alibi Detect の以下のドキュメントを翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
スケジュールは弊社 公式 Web サイト でご確認頂けます。
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- ウェビナー運用には弊社製品「ClassCat® Webinar」を利用しています。
人工知能研究開発支援 | 人工知能研修サービス | テレワーク & オンライン授業を支援 |
PoC(概念実証)を失敗させないための支援 (本支援はセミナーに参加しアンケートに回答した方を対象としています。) |
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション |
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ ; Facebook |
Alibi Detect 0.7 : Examples : VAE 外れ値検知 on CIFAR10
VAE – 概要
変分オートエンコーダ (VAE, Variational Auto-Encoder) 外れ値検知器は最初にラベル付けされていない、しかし通常 (inlier) データのバッチで訓練されます。教師なしか半教師あり訓練が望ましいです、何故ならばラベル付けされたデータはしばしば十分でないからです。VAE 検知器はそれが受け取る入力を再構築しようとします。入力データが上手く再構築されない場合、再構築エラーは高くそしてデータは外れ値としてフラグ立てできます。再構築エラーは、入力と再構築されたインスタンスの間の平均二乗誤差 (MSE, mean squared error) か、入力と再構築されたインスタンスの両者が同じプロセスで生成される確率として測定されます。アルゴリズムは表形式か画像データのために適合します。
データセット
CIFAR10 は 10 クラスに渡り均等に分配された 60,000 の 32 x 32 RGB 画像から成ります。
import logging
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
tf.keras.backend.clear_session()
from tensorflow.keras.layers import Conv2D, Conv2DTranspose, Dense, Layer, Reshape, InputLayer
from tqdm import tqdm
from alibi_detect.models.tensorflow.losses import elbo
from alibi_detect.od import OutlierVAE
from alibi_detect.utils.fetching import fetch_detector
from alibi_detect.utils.perturbation import apply_mask
from alibi_detect.utils.saving import save_detector, load_detector
from alibi_detect.utils.visualize import plot_instance_score, plot_feature_outlier_image
logger = tf.get_logger()
logger.setLevel(logging.ERROR)
CIFAR10 データをロードする
train, test = tf.keras.datasets.cifar10.load_data()
X_train, y_train = train
X_test, y_test = test
X_train = X_train.astype('float32') / 255
X_test = X_test.astype('float32') / 255
print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)
(50000, 32, 32, 3) (50000, 1) (10000, 32, 32, 3) (10000, 1)
外れ値検知器をロードまたは定義する
examples ノートブックで使用される事前訓練済みの外れ値と敵対的検知器は ここ で見つかります。組込みの fetch_detector 関数を利用できます、これは事前訓練モデルをローカルディレクトリ filepath にセーブして検知器をロードします。代わりに、スクラッチから検知器を訓練することができます :
load_outlier_detector = False
filepath = 'model_vae_cifar10' # change to directory where model is downloaded
if load_outlier_detector: # load pretrained outlier detector
detector_type = 'outlier'
dataset = 'cifar10'
detector_name = 'OutlierVAE'
od = fetch_detector(filepath, detector_type, dataset, detector_name)
filepath = os.path.join(filepath, detector_name)
else: # define model, initialize, train and save outlier detector
latent_dim = 1024
encoder_net = tf.keras.Sequential(
[
InputLayer(input_shape=(32, 32, 3)),
Conv2D(64, 4, strides=2, padding='same', activation=tf.nn.relu),
Conv2D(128, 4, strides=2, padding='same', activation=tf.nn.relu),
Conv2D(512, 4, strides=2, padding='same', activation=tf.nn.relu)
])
decoder_net = tf.keras.Sequential(
[
InputLayer(input_shape=(latent_dim,)),
Dense(4*4*128),
Reshape(target_shape=(4, 4, 128)),
Conv2DTranspose(256, 4, strides=2, padding='same', activation=tf.nn.relu),
Conv2DTranspose(64, 4, strides=2, padding='same', activation=tf.nn.relu),
Conv2DTranspose(3, 4, strides=2, padding='same', activation='sigmoid')
])
# initialize outlier detector
od = OutlierVAE(threshold=.015, # threshold for outlier score
score_type='mse', # use MSE of reconstruction error for outlier detection
encoder_net=encoder_net, # can also pass VAE model instead
decoder_net=decoder_net, # of separate encoder and decoder
latent_dim=latent_dim,
samples=2)
# train
od.fit(X_train,
loss_fn=elbo,
cov_elbo=dict(sim=.05),
epochs=50,
verbose=True)
# save the trained outlier detector
save_detector(od, filepath)
(訳注 : TF 2.5.0, 8 vCPUs)
782/782 [=] - 200s 254ms/step - loss: 3261.4951 782/782 [=] - 199s 254ms/step - loss: -2490.5888 782/782 [=] - 199s 254ms/step - loss: -3502.6840 782/782 [=] - 203s 259ms/step - loss: -3973.3844 782/782 [=] - 203s 259ms/step - loss: -4287.5373 782/782 [=] - 202s 258ms/step - loss: -4530.9941 782/782 [=] - 202s 257ms/step - loss: -4697.7253 782/782 [=] - 202s 257ms/step - loss: -4847.7671 782/782 [=] - 203s 260ms/step - loss: -4976.0743 782/782 [=] - 198s 253ms/step - loss: -5082.4453 782/782 [=] - 200s 254ms/step - loss: -5159.3614 782/782 [=] - 203s 259ms/step - loss: -5219.0779 782/782 [=] - 200s 255ms/step - loss: -5276.2153 782/782 [=] - 201s 256ms/step - loss: -5351.2658 782/782 [=] - 201s 257ms/step - loss: -5400.3945 782/782 [=] - 203s 258ms/step - loss: -5440.3792 (打ち切り)
(訳注 : TF 2.4.1, NVIDIA T4 GPU)
782/782 [=] - 39s 36ms/step - loss: 2861.8008 782/782 [=] - 29s 36ms/step - loss: -2660.4216 782/782 [=] - 29s 36ms/step - loss: -3656.3224 782/782 [=] - 29s 36ms/step - loss: -4132.3934 782/782 [=] - 29s 36ms/step - loss: -4442.0791 782/782 [=] - 29s 36ms/step - loss: -4647.3034 782/782 [=] - 29s 36ms/step - loss: -4835.5262 782/782 [=] - 29s 36ms/step - loss: -4972.2206 782/782 [=] - 29s 36ms/step - loss: -5072.7729 782/782 [=] - 29s 37ms/step - loss: -5150.4993 782/782 [=] - 29s 36ms/step - loss: -5216.9460 782/782 [=] - 29s 37ms/step - loss: -5288.1443 782/782 [=] - 29s 36ms/step - loss: -5347.1787 782/782 [=] - 29s 36ms/step - loss: -5415.1764 782/782 [=] - 29s 36ms/step - loss: -5458.5443 782/782 [=] - 29s 36ms/step - loss: -5507.7469 782/782 [=] - 29s 36ms/step - loss: -5530.3080 782/782 [=] - 29s 36ms/step - loss: -5575.4234 782/782 [=] - 29s 36ms/step - loss: -5614.9955 782/782 [=] - 29s 36ms/step - loss: -5635.2912 782/782 [=] - 29s 36ms/step - loss: -5672.6891 782/782 [=] - 29s 36ms/step - loss: -5689.9361 782/782 [=] - 29s 36ms/step - loss: -5719.1222 782/782 [=] - 29s 37ms/step - loss: -5734.5167 782/782 [=] - 29s 37ms/step - loss: -5761.0373 782/782 [=] - 29s 36ms/step - loss: -5770.7223 782/782 [=] - 29s 36ms/step - loss: -5797.3944 782/782 [=] - 29s 36ms/step - loss: -5813.8093 782/782 [=] - 29s 36ms/step - loss: -5825.7507 782/782 [=] - 29s 36ms/step - loss: -5842.4082 782/782 [=] - 29s 36ms/step - loss: -5852.7256 782/782 [=] - 29s 36ms/step - loss: -5870.8946 782/782 [=] - 29s 36ms/step - loss: -5877.0400 782/782 [=] - 29s 36ms/step - loss: -5887.7013 782/782 [=] - 29s 36ms/step - loss: -5898.9985 782/782 [=] - 29s 36ms/step - loss: -5910.3501 782/782 [=] - 29s 36ms/step - loss: -5918.1856 782/782 [=] - 29s 36ms/step - loss: -5930.0882 782/782 [=] - 29s 36ms/step - loss: -5940.8020 782/782 [=] - 29s 36ms/step - loss: -5944.5714 782/782 [=] - 29s 36ms/step - loss: -5952.0312 782/782 [=] - 29s 36ms/step - loss: -5963.3228 782/782 [=] - 29s 36ms/step - loss: -5966.7727 782/782 [=] - 29s 36ms/step - loss: -5970.3328 782/782 [=] - 29s 36ms/step - loss: -5976.2218 782/782 [=] - 29s 36ms/step - loss: -5977.2582 782/782 [=] - 29s 36ms/step - loss: -5990.5260 782/782 [=] - 29s 36ms/step - loss: -5997.9227 782/782 [=] - 29s 36ms/step - loss: -6001.5070 782/782 [=] - 29s 36ms/step - loss: -6005.6862
VAE モデルの品質を確認する
idx = 8
X = X_train[idx].reshape(1, 32, 32, 3)
X_recon = od.vae(X)
plt.imshow(X.reshape(32, 32, 3))
plt.axis('off')
plt.show()
plt.imshow(X_recon.numpy().reshape(32, 32, 3))
plt.axis('off')
plt.show()
元の CIFAR 画像で外れ値を確認する
X = X_train[:500]
print(X.shape)
(500, 32, 32, 3)
od_preds = od.predict(X,
outlier_type='instance', # use 'feature' or 'instance' level
return_feature_score=True, # scores used to determine outliers
return_instance_score=True)
print(list(od_preds['data'].keys()))
['instance_score', 'feature_score', 'is_outlier']
インスタンスレベルの外れ値スコアをプロットする
target = np.zeros(X.shape[0],).astype(int) # all normal CIFAR10 training instances
labels = ['normal', 'outlier']
plot_instance_score(od_preds, target, labels, od.threshold)
予測を可視化する
X_recon = od.vae(X).numpy()
plot_feature_outlier_image(od_preds,
X,
X_recon=X_recon,
instance_ids=[8, 60, 100, 330], # pass a list with indices of instances to display
max_instances=5, # max nb of instances to display
outliers_only=False) # only show outlier predictions
(訳注 : 下は実験結果)
摂動された CIFAR 画像で外れ値を予測する
CIFAR 画像を画像のパッチ (マスク) にランダムノイズを追加することにより摂動させます。n_mask_sizes の各マスクサイズについて、n_masks をサンプリングしてそれらを n_imgs 画像の各々に適用します。そしてマスクされたインスタンスで外れ値を予測します :
# nb of predictions per image: n_masks * n_mask_sizes
n_mask_sizes = 10
n_masks = 20
n_imgs = 50
マスクを定義して画像を得る :
mask_sizes = [(2*n,2*n) for n in range(1,n_mask_sizes+1)]
print(mask_sizes)
img_ids = np.arange(n_imgs)
X_orig = X[img_ids].reshape(img_ids.shape[0], 32, 32, 3)
print(X_orig.shape)
[(2, 2), (4, 4), (6, 6), (8, 8), (10, 10), (12, 12), (14, 14), (16, 16), (18, 18), (20, 20)] (50, 32, 32, 3)
インスタンスレベルの外れ値スコアを計算します :
all_img_scores = []
for i in tqdm(range(X_orig.shape[0])):
img_scores = np.zeros((len(mask_sizes),))
for j, mask_size in enumerate(mask_sizes):
# create masked instances
X_mask, mask = apply_mask(X_orig[i].reshape(1, 32, 32, 3),
mask_size=mask_size,
n_masks=n_masks,
channels=[0,1,2],
mask_type='normal',
noise_distr=(0,1),
clip_rng=(0,1))
# predict outliers
od_preds_mask = od.predict(X_mask)
score = od_preds_mask['data']['instance_score']
# store average score over `n_masks` for a given mask size
img_scores[j] = np.mean(score)
all_img_scores.append(img_scores)
外れ値スコア vs. マスクサイズ
x_plt = [mask[0] for mask in mask_sizes]
for ais in all_img_scores:
plt.plot(x_plt, ais)
plt.xticks(x_plt)
plt.title('Outlier Score All Images for Increasing Mask Size')
plt.xlabel('Mask size')
plt.ylabel('Outlier Score')
plt.show()
ais_np = np.zeros((len(all_img_scores), all_img_scores[0].shape[0]))
for i, ais in enumerate(all_img_scores):
ais_np[i, :] = ais
ais_mean = np.mean(ais_np, axis=0)
plt.title('Mean Outlier Score All Images for Increasing Mask Size')
plt.xlabel('Mask size')
plt.ylabel('Outlier score')
plt.plot(x_plt, ais_mean)
plt.xticks(x_plt)
plt.show()
インスタンスレベルの外れ値を調査する
i = 8 # index of instance to look at
plt.plot(x_plt, all_img_scores[i])
plt.xticks(x_plt)
plt.title('Outlier Scores Image {} for Increasing Mask Size'.format(i))
plt.xlabel('Mask size')
plt.ylabel('Outlier score')
plt.show()
マスクされた画像の再構築とチャネル毎の外れ値スコア :
all_X_mask = []
X_i = X_orig[i].reshape(1, 32, 32, 3)
all_X_mask.append(X_i)
# apply masks
for j, mask_size in enumerate(mask_sizes):
# create masked instances
X_mask, mask = apply_mask(X_i,
mask_size=mask_size,
n_masks=1, # just 1 for visualization purposes
channels=[0,1,2],
mask_type='normal',
noise_distr=(0,1),
clip_rng=(0,1))
all_X_mask.append(X_mask)
all_X_mask = np.concatenate(all_X_mask, axis=0)
all_X_recon = od.vae(all_X_mask).numpy()
od_preds = od.predict(all_X_mask)
可視化します :
plot_feature_outlier_image(od_preds,
all_X_mask,
X_recon=all_X_recon,
max_instances=all_X_mask.shape[0],
n_channels=3)
(訳注 : 下は実験結果)
特徴のサブセットで外れ値を予測する
外れ値検知器の sensitivity (感度) は閾値を通してだけでなくインスタンスレベルの外れ値スコア計算のために使用される特徴のパーセンテージを選択することによっても制御できます。例えば、特徴の 40% が閾値を越える平均外れ値スコアを持つ場合外れ値であるとフラグ立てすることを望むかもしれません。これは predict 関数の outlier_perc 引数を通して可能です。それは降順の外れ値スコア順序でソートされた、外れ値検知のために使用される特徴のパーセンテージを指定します。
perc_list = [20, 40, 60, 80, 100]
all_perc_scores = []
for perc in perc_list:
od_preds_perc = od.predict(all_X_mask, outlier_perc=perc)
iscore = od_preds_perc['data']['instance_score']
all_perc_scores.append(iscore)
外れ値スコア vs. マスクサイズと使用された特徴サイズのパーセンテージを可視化します :
x_plt = [0] + x_plt
for aps in all_perc_scores:
plt.plot(x_plt, aps)
plt.xticks(x_plt)
plt.legend(perc_list)
plt.title('Outlier Score for Increasing Mask Size and Different Feature Subsets')
plt.xlabel('Mask Size')
plt.ylabel('Outlier Score')
plt.show()
外れ値の閾値を推論する
良い閾値を見つけることは技巧的であり得ます、何故ならばそれらは典型的には解釈することが容易でないからです。infer_threshold メソッドは sensible な値を見つけるのに役立ちます。インスタンスのバッチ X を渡してそれらの何パーセントを正常であると考えるかを threshold_perc を通して指定する必要があります。
print('Current threshold: {}'.format(od.threshold))
od.infer_threshold(X, threshold_perc=99) # assume 1% of the training data are outliers
print('New threshold: {}'.format(od.threshold))
Current threshold: 0.015 New threshold: 0.010383214280009267
(訳注 : 実験結果)
Current threshold: 0.015 New threshold: 0.0018019021837972088
以上
Alibi Detect 0.7 : Examples : AEGMM と VAEGMM 外れ値検知 on TCP dump
Alibi Detect 0.7 : Examples : AEGMM と VAEGMM 外れ値検知 on KDD Cup ‘99 データセット (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 07/03/2021 (0.7.0)
* 本ページは、Alibi Detect の以下のドキュメントを翻訳した上で適宜、補足説明したものです:
- AEGMM and VAEGMM outlier detection on KDD Cup ‘99 dataset
- Auto-Encoding Gaussian Mixture Model
- Variational Auto-Encoding Gaussian Mixture Model
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
スケジュールは弊社 公式 Web サイト でご確認頂けます。
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- ウェビナー運用には弊社製品「ClassCat® Webinar」を利用しています。
人工知能研究開発支援 | 人工知能研修サービス | テレワーク & オンライン授業を支援 |
PoC(概念実証)を失敗させないための支援 (本支援はセミナーに参加しアンケートに回答した方を対象としています。) |
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション |
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ ; Facebook |
Alibi Detect 0.7 : Examples :AEGMM と VAEGMM 外れ値検知 on KDD Cup ‘99 データセット
AEGMM (オートエンコーディング・ガウス混合モデル) – 概要
オートエンコーディング・ガウス混合モデル (AEGMM) 外れ値検知器は 教師なし異常検知のための深層オートエンコーディング・ガウス混合モデル (Deep Autoencoding Gaussian Mixture Model for Unsupervised Anomaly Detection) 論文に従っています。エンコーダがデータを圧縮する一方で、デコーダにより生成された再構築されたインスタンスは入力と再構築の間の再構築誤差に基づいた追加の特徴を作成するために使用されます。これらの特徴はエンコーディングと結合されてガウス混合モデル (GMM) に供給されます。AEGMM 外れ値検知器はラベル付けされていない、しかし通常 (inlier) データのバッチ上で最初に訓練されます。教師なしか半教師あり訓練が望ましいです、何故ならばラベル付けされたデータはしばしば十分ではないからです。そして GMM のサンプルのエネルギーはインスタンスが外れ値 (高サンプル・エネルギー) か否か (低サンプル・エネルギー) を決定するために使用できます。このアルゴリズムは表形式か画像データのために適合します。
VAEGMM (変分オートエンコーディング・ガウス混合モデル) – 概要
変分オートエンコーディング・ガウス混合モデル (VAEGMM) 外れ値検知器は 教師なし異常検知のための深層オートエンコーディング・ガウス混合モデル (Deep Autoencoding Gaussian Mixture Model for Unsupervised Anomaly Detection) 論文に従っていますが、通常のオートエンコーダの代わりに VAE を使用します。エンコーダがデータを圧縮する一方で、デコーダにより生成された再構築されたインスタンスは入力と再構築の間の再構築誤差に基づいた追加の特徴を作成するために使用されます。これらの特徴はエンコーディングと結合されてガウス混合モデル (GMM) に供給されます。VAEGMM 外れ値検知器はラベル付けされていない、しかし通常 (inlier) データのバッチ上で最初に訓練されます。教師なしか半教師あり訓練が望ましいです、何故ならばラベル付けされたデータはしばしば十分ではないからです。そして GMM のサンプルのエネルギーはインスタンスが外れ値 (高サンプル・エネルギー) か否か (低サンプル・エネルギー) を決定するために使用できます。このアルゴリズムは表形式か画像データのために適合します。
データセット
典型的な U.S. 空軍 LAN をシミュレートした LAN の TCP dump データを使用して、外れ値検知器はコンピュータ・ネットワーク侵入を検知する必要があります。コネクションは明確に定義された時間で開始して終了する TCP パケットのシークエンスで、その間にデータは明確に定義されたプロトコルのもとにソース IP とターゲット IP アドレス間で流れます。各コネクションは正常、また攻撃としてラベル付けされます。
データセットには 4 タイプの攻撃があります :
- DOS: denial-of-service, e.g. syn flood;
- R2L: 遠隔マシンからの権限のないアクセス、e.g. パスワードの推測 ;
- U2R: ローカルのスーパーユーザ (root) 特権への権限のないアクセス ;
- probing : 偵察と他の厳密な調査、e.g., ポートスキャン。
データセットは約 500 万のコネクション・レコードを含みます。
3 つのタイプの特徴があります :
- 個々のコネクションの基本的な特徴, e.g. 接続時間 (duration of connection)
- コネクション内のコンテンツ特徴, e.g. 失敗したログイン試行の数
- 2 秒 window 内の traffic 特徴, e.g. 現在の接続と同じホストへのコネクションの数
import logging
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import pandas as pd
import seaborn as sns
from sklearn.metrics import confusion_matrix, f1_score
import tensorflow as tf
tf.keras.backend.clear_session()
from tensorflow.keras.layers import Dense, InputLayer
from alibi_detect.datasets import fetch_kdd
from alibi_detect.models.tensorflow.autoencoder import eucl_cosim_features
from alibi_detect.od import OutlierAEGMM, OutlierVAEGMM
from alibi_detect.utils.data import create_outlier_batch
from alibi_detect.utils.fetching import fetch_detector
from alibi_detect.utils.saving import save_detector, load_detector
from alibi_detect.utils.visualize import plot_instance_score, plot_feature_outlier_tabular, plot_roc
logger = tf.get_logger()
logger.setLevel(logging.ERROR)
データセットをロードする
幾つかの continuous (連続) な特徴 (41 の内から 18) だけを保持します。
kddcup = fetch_kdd(percent10=True) # only load 10% of the dataset
print(kddcup.data.shape, kddcup.target.shape)
Downloading https://ndownloader.figshare.com/files/5976042 (494021, 18) (494021,)
kddcup.data[0]
array([8, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 9, 9, 1.0, 0.0, 0.11, 0.0, 0.0, 0.0, 0.0, 0.0], dtype=object)
モデルはデータセットの (外れ値ではなく) 正常インスタンス上で訓練されて標準化 (= standardization) が適用されていると仮定します :
np.random.seed(0)
normal_batch = create_outlier_batch(kddcup.data, kddcup.target, n_samples=400000, perc_outlier=0)
X_train, y_train = normal_batch.data.astype('float32'), normal_batch.target
print(X_train.shape, y_train.shape)
print('{}% outliers'.format(100 * y_train.mean()))
(400000, 18) (400000,) 0.0% outliers
mean, stdev = X_train.mean(axis=0), X_train.std(axis=0)
print(mean)
print(stdev)
[1.09550075e+01 1.55620000e-03 1.74745000e-03 5.54626500e-02 5.57733250e-02 9.85440925e-01 1.82663500e-02 1.33057100e-01 1.48641492e+02 2.02133175e+02 8.44858050e-01 5.64032750e-02 1.33479675e-01 2.40508250e-02 2.11637500e-03 1.05915000e-03 5.73124750e-02 5.52324500e-02] [2.17181039e+01 2.78305002e-02 2.61481724e-02 2.28073133e-01 2.26952689e-01 9.25608777e-02 1.16637691e-01 2.77172101e-01 1.03333220e+02 8.68577798e+01 3.05254458e-01 1.79868747e-01 2.80221411e-01 4.92476707e-02 2.95181081e-02 1.59275611e-02 2.24229381e-01 2.17798555e-01]
標準化を適用します :
X_train = (X_train - mean) / stdev
AEGMM 外れ値検知器をロードまたは定義する
examples ノートブックで使用される事前訓練済みの外れ値と敵対的検知器は ここ で見つかります。組込みの fetch_detector 関数を利用できます、これは事前訓練モデルをローカルディレクトリ filepath にセーブして検知器をロードします。代わりに、スクラッチから検知器を訓練することができます :
load_outlier_detector = False
filepath = 'model_aegmm' # 'my_path' # change to directory (absolute path) where model is downloaded
if load_outlier_detector: # load pretrained outlier detector
detector_type = 'outlier'
dataset = 'kddcup'
detector_name = 'OutlierAEGMM'
od = fetch_detector(filepath, detector_type, dataset, detector_name)
filepath = os.path.join(filepath, detector_name)
else: # define model, initialize, train and save outlier detector
# the model defined here is similar to the one defined in the original paper
n_features = X_train.shape[1]
latent_dim = 1
n_gmm = 2 # nb of components in GMM
encoder_net = tf.keras.Sequential(
[
InputLayer(input_shape=(n_features,)),
Dense(60, activation=tf.nn.tanh),
Dense(30, activation=tf.nn.tanh),
Dense(10, activation=tf.nn.tanh),
Dense(latent_dim, activation=None)
])
decoder_net = tf.keras.Sequential(
[
InputLayer(input_shape=(latent_dim,)),
Dense(10, activation=tf.nn.tanh),
Dense(30, activation=tf.nn.tanh),
Dense(60, activation=tf.nn.tanh),
Dense(n_features, activation=None)
])
gmm_density_net = tf.keras.Sequential(
[
InputLayer(input_shape=(latent_dim + 2,)),
Dense(10, activation=tf.nn.tanh),
Dense(n_gmm, activation=tf.nn.softmax)
])
# initialize outlier detector
od = OutlierAEGMM(threshold=None, # threshold for outlier score
encoder_net=encoder_net, # can also pass AEGMM model instead
decoder_net=decoder_net, # of separate encoder, decoder
gmm_density_net=gmm_density_net, # and gmm density net
n_gmm=n_gmm,
recon_features=eucl_cosim_features) # fn used to derive features
# from the reconstructed
# instances based on cosine
# similarity and Eucl distance
# train
od.fit(X_train,
epochs=50,
batch_size=1024,
#save_path=filepath,
verbose=True)
# save the trained outlier detector
save_detector(od, filepath)
391/391 [=] - 10s 25ms/step - loss: 1.7450 391/391 [=] - 10s 26ms/step - loss: 1.6758 391/391 [=] - 10s 26ms/step - loss: 1.5309 391/391 [=] - 10s 25ms/step - loss: 1.4671 391/391 [=] - 10s 25ms/step - loss: 1.4172 391/391 [=] - 10s 25ms/step - loss: 1.3793 391/391 [=] - 10s 25ms/step - loss: 1.3396 391/391 [=] - 10s 26ms/step - loss: 1.2962 391/391 [=] - 10s 26ms/step - loss: 1.2483 391/391 [=] - 10s 25ms/step - loss: 1.2015 391/391 [=] - 10s 25ms/step - loss: 1.1678 391/391 [=] - 10s 25ms/step - loss: 1.1356 391/391 [=] - 10s 25ms/step - loss: 1.0989 391/391 [=] - 10s 26ms/step - loss: 1.0617 391/391 [=] - 10s 26ms/step - loss: 1.0288 391/391 [=] - 10s 25ms/step - loss: 0.9975 391/391 [=] - 10s 25ms/step - loss: 0.9630 391/391 [=] - 10s 25ms/step - loss: 0.9298 391/391 [=] - 10s 25ms/step - loss: 0.9013 391/391 [=] - 10s 26ms/step - loss: 0.8748 391/391 [=] - 11s 27ms/step - loss: 0.8481 391/391 [=] - 10s 25ms/step - loss: 0.8259 391/391 [=] - 10s 25ms/step - loss: 0.8081 391/391 [=] - 10s 25ms/step - loss: 0.7944 391/391 [=] - 10s 25ms/step - loss: 0.7825 391/391 [=] - 10s 26ms/step - loss: 0.7726 391/391 [=] - 10s 26ms/step - loss: 0.7628 391/391 [=] - 10s 25ms/step - loss: 0.7543 391/391 [=] - 10s 25ms/step - loss: 0.7460 391/391 [=] - 10s 25ms/step - loss: 0.7385 391/391 [=] - 10s 26ms/step - loss: 0.7314 391/391 [=] - 10s 26ms/step - loss: 0.7242 391/391 [=] - 10s 25ms/step - loss: 0.7185 391/391 [=] - 10s 25ms/step - loss: 0.7120 391/391 [=] - 10s 25ms/step - loss: 0.7064 391/391 [=] - 10s 25ms/step - loss: 0.7005 391/391 [=] - 10s 25ms/step - loss: 0.6947 391/391 [=] - 10s 26ms/step - loss: 0.6891 391/391 [=] - 11s 27ms/step - loss: 0.6844 391/391 [=] - 10s 25ms/step - loss: 0.6787 391/391 [=] - 10s 25ms/step - loss: 0.6738 391/391 [=] - 10s 25ms/step - loss: 0.6693 391/391 [=] - 10s 25ms/step - loss: 0.6648 391/391 [=] - 10s 26ms/step - loss: 0.6604 391/391 [=] - 10s 26ms/step - loss: 0.6561 391/391 [=] - 10s 25ms/step - loss: 0.6521 391/391 [=] - 10s 25ms/step - loss: 0.6476 391/391 [=] - 10s 25ms/step - loss: 0.6446 391/391 [=] - 10s 25ms/step - loss: 0.6409 391/391 [=] - 10s 26ms/step - loss: 0.6378
!ls model_aegmm -l
!ls model_aegmm/model -l
total 12 -rw-rw-r-- 1 ubuntu ubuntu 760 7月 3 07:33 OutlierAEGMM.pickle -rw-rw-r-- 1 ubuntu ubuntu 89 7月 3 07:33 meta.pickle drwxrwxr-x 2 ubuntu ubuntu 4096 7月 3 07:33 model total 120 -rw-rw-r-- 1 ubuntu ubuntu 29329 7月 3 07:33 aegmm.ckpt.data-00000-of-00001 -rw-rw-r-- 1 ubuntu ubuntu 1398 7月 3 07:33 aegmm.ckpt.index -rw-rw-r-- 1 ubuntu ubuntu 77 7月 3 07:33 checkpoint -rw-rw-r-- 1 ubuntu ubuntu 31576 7月 3 07:33 decoder_net.h5 -rw-rw-r-- 1 ubuntu ubuntu 31608 7月 3 07:33 encoder_net.h5 -rw-rw-r-- 1 ubuntu ubuntu 14488 7月 3 07:33 gmm_density_net.h5
警告は outlier threshold (外れ値閾値) を依然として設定する必要があることを教えます。これは infer_threshold メソッドで成されます。インスタンスのバッチを渡してそれらの何パーセントを正常であると考えるかを threshold_perc を通して指定する必要があります。およそ 5% の外れ値を含むことを知るあるデータを持つと仮定しましょう。外れ値のパーセンテージは create_outlier_batch 関数で perc_outlier で設定できます。
np.random.seed(0)
perc_outlier = 5
threshold_batch = create_outlier_batch(kddcup.data, kddcup.target, n_samples=1000, perc_outlier=perc_outlier)
X_threshold, y_threshold = threshold_batch.data.astype('float32'), threshold_batch.target
X_threshold = (X_threshold - mean) / stdev
print('{}% outliers'.format(100 * y_threshold.mean()))
5.0% outliers
od.infer_threshold(X_threshold, threshold_perc=100-perc_outlier)
print('New threshold: {}'.format(od.threshold))
New threshold: 5.188828468322754
更新された閾値で外れ値検知器をセーブしましょう :
save_detector(od, filepath)
外れ値を検出する
今は 10% の外れ値を持つデータのバッチを生成しそしてバッチ内の外れ値を検出します。
np.random.seed(1)
outlier_batch = create_outlier_batch(kddcup.data, kddcup.target, n_samples=1000, perc_outlier=10)
X_outlier, y_outlier = outlier_batch.data.astype('float32'), outlier_batch.target
X_outlier = (X_outlier - mean) / stdev
print(X_outlier.shape, y_outlier.shape)
print('{}% outliers'.format(100 * y_outlier.mean()))
(1000, 18) (1000,) 10.0% outliers
外れ値を予測します :
od_preds = od.predict(X_outlier, return_instance_score=True)
結果を表示する
F1 スコアと混同行列 :
labels = outlier_batch.target_names
y_pred = od_preds['data']['is_outlier']
f1 = f1_score(y_outlier, y_pred)
print('F1 score: {:.4f}'.format(f1))
cm = confusion_matrix(y_outlier, y_pred)
df_cm = pd.DataFrame(cm, index=labels, columns=labels)
sns.heatmap(df_cm, annot=True, cbar=True, linewidths=.5)
plt.show()
F1 score: 0.3352
インスタンスレベルの外れ値スコア vs 外れ値閾値をプロットします :
plot_instance_score(od_preds, y_outlier, labels, od.threshold, ylim=(None, None))
検出器の外れ値スコアのための ROC カーブをプロットすることもできます :
roc_data = {'AEGMM': {'scores': od_preds['data']['instance_score'], 'labels': y_outlier}}
plot_roc(roc_data)
インスタンスレベル外れ値を調査する
潜在空間のインスタンスのエンコーディングとデコーダにより再構築されたインスタンスに由来する特徴を可視化できます。そしてエンコーディングと特徴は GMM 密度ネットワークに供給されます。
enc = od.aegmm.encoder(X_outlier) # encoding
X_recon = od.aegmm.decoder(enc) # reconstructed instances
recon_features = od.aegmm.recon_features(X_outlier, X_recon) # reconstructed features
df = pd.DataFrame(dict(enc=enc[:, 0].numpy(),
cos=recon_features[:, 0].numpy(),
eucl=recon_features[:, 1].numpy(),
label=y_outlier))
groups = df.groupby('label')
fig, ax = plt.subplots()
for name, group in groups:
ax.plot(group.enc, group.cos, marker='o',
linestyle='', ms=6, label=labels[name])
plt.title('Encoding vs. Cosine Similarity')
plt.xlabel('Encoding')
plt.ylabel('Cosine Similarity')
ax.legend()
plt.show()
fig, ax = plt.subplots()
for name, group in groups:
ax.plot(group.enc, group.eucl, marker='o',
linestyle='', ms=6, label=labels[name])
plt.title('Encoding vs. Relative Euclidean Distance')
plt.xlabel('Encoding')
plt.ylabel('Relative Euclidean Distance')
ax.legend()
plt.show()
多くの外れ値が潜在空間で既に上手く分離されています。
VAEGMM 外れ値検知器を使用する
Google Cloud Bucket から 事前訓練済みの VAEGMM 検出器を再度インスタンス化できます。組込みの fetch_detector 関数を利用できます、これは事前訓練モデルをローカルディレクトリ filepath にセーブして検知器をロードします。代わりに、スクラッチから検知器を訓練することができます :
load_outlier_detector = False
filepath = 'model_vaegmm' # change to directory (absolute path) where model is downloaded
if load_outlier_detector: # load pretrained outlier detector
detector_type = 'outlier'
dataset = 'kddcup'
detector_name = 'OutlierVAEGMM'
od = fetch_detector(filepath, detector_type, dataset, detector_name)
filepath = os.path.join(filepath, detector_name)
else: # define model, initialize, train and save outlier detector
# the model defined here is similar to the one defined in
# the OutlierVAE notebook
n_features = X_train.shape[1]
latent_dim = 2
n_gmm = 2
encoder_net = tf.keras.Sequential(
[
InputLayer(input_shape=(n_features,)),
Dense(20, activation=tf.nn.relu),
Dense(15, activation=tf.nn.relu),
Dense(7, activation=tf.nn.relu)
])
decoder_net = tf.keras.Sequential(
[
InputLayer(input_shape=(latent_dim,)),
Dense(7, activation=tf.nn.relu),
Dense(15, activation=tf.nn.relu),
Dense(20, activation=tf.nn.relu),
Dense(n_features, activation=None)
])
gmm_density_net = tf.keras.Sequential(
[
InputLayer(input_shape=(latent_dim + 2,)),
Dense(10, activation=tf.nn.relu),
Dense(n_gmm, activation=tf.nn.softmax)
])
# initialize outlier detector
od = OutlierVAEGMM(threshold=None,
encoder_net=encoder_net,
decoder_net=decoder_net,
gmm_density_net=gmm_density_net,
n_gmm=n_gmm,
latent_dim=latent_dim,
samples=10,
recon_features=eucl_cosim_features)
# train
od.fit(X_train,
epochs=50,
batch_size=1024,
cov_elbo=dict(sim=.0025), # standard deviation assumption
verbose=True) # for elbo training
# save the trained outlier detector
save_detector(od, filepath)
391/391 [=] - 16s 40ms/step - loss: 0.7435 391/391 [=] - 15s 39ms/step - loss: 0.6727 391/391 [=] - 15s 38ms/step - loss: 0.6538 391/391 [=] - 15s 38ms/step - loss: 0.6449 391/391 [=] - 16s 40ms/step - loss: 0.6384 391/391 [=] - 15s 38ms/step - loss: 0.6383 391/391 [=] - 15s 38ms/step - loss: 0.6410 391/391 [=] - 16s 40ms/step - loss: 0.6557 391/391 [=] - 15s 39ms/step - loss: 0.7462 391/391 [=] - 15s 38ms/step - loss: 0.9006 391/391 [=] - 15s 38ms/step - loss: 0.8419 391/391 [=] - 15s 39ms/step - loss: 0.8301 391/391 [=] - 16s 41ms/step - loss: 0.8225 391/391 [=] - 15s 38ms/step - loss: 0.8158 391/391 [=] - 15s 39ms/step - loss: 0.8086 391/391 [=] - 15s 39ms/step - loss: 0.8014 391/391 [=] - 16s 40ms/step - loss: 0.7956 391/391 [=] - 15s 39ms/step - loss: 0.7901 391/391 [=] - 15s 39ms/step - loss: 0.7835 391/391 [=] - 15s 39ms/step - loss: 0.7772 391/391 [=] - 15s 39ms/step - loss: 0.7687 391/391 [=] - 15s 39ms/step - loss: 0.7593 391/391 [=] - 15s 39ms/step - loss: 0.7490 391/391 [=] - 15s 39ms/step - loss: 0.7400 391/391 [=] - 16s 41ms/step - loss: 0.7326 391/391 [=] - 15s 39ms/step - loss: 0.7261 391/391 [=] - 15s 39ms/step - loss: 0.7212 391/391 [=] - 16s 40ms/step - loss: 0.7167 391/391 [=] - 16s 40ms/step - loss: 0.7125 391/391 [=] - 15s 39ms/step - loss: 0.7068 391/391 [=] - 15s 39ms/step - loss: 0.7023 391/391 [=] - 16s 40ms/step - loss: 0.6979 391/391 [=] - 15s 39ms/step - loss: 0.6941 391/391 [=] - 15s 39ms/step - loss: 0.6903 391/391 [=] - 15s 39ms/step - loss: 0.6883 391/391 [=] - 16s 40ms/step - loss: 0.6861 391/391 [=] - 16s 40ms/step - loss: 0.6843 391/391 [=] - 15s 39ms/step - loss: 0.6829 391/391 [=] - 15s 39ms/step - loss: 0.6814 391/391 [=] - 16s 41ms/step - loss: 0.6802 391/391 [=] - 15s 39ms/step - loss: 0.6791 391/391 [=] - 15s 39ms/step - loss: 0.6786 391/391 [=] - 15s 39ms/step - loss: 0.6774 391/391 [=] - 16s 40ms/step - loss: 0.6767 391/391 [=] - 15s 39ms/step - loss: 0.6759 391/391 [=] - 15s 39ms/step - loss: 0.6756 391/391 [=] - 15s 40ms/step - loss: 0.6753 391/391 [=] - 16s 41ms/step - loss: 0.6741 391/391 [=] - 15s 39ms/step - loss: 0.6729 391/391 [=] - 15s 39ms/step - loss: 0.6733
!ls model_vaegmm -l
!ls model_vaegmm/model -l
total 12 -rw-rw-r-- 1 ubuntu ubuntu 935 7月 3 07:56 OutlierVAEGMM.pickle -rw-rw-r-- 1 ubuntu ubuntu 90 7月 3 07:56 meta.pickle drwxrwxr-x 2 ubuntu ubuntu 4096 7月 3 07:56 model total 80 -rw-rw-r-- 1 ubuntu ubuntu 79 7月 3 07:56 checkpoint -rw-rw-r-- 1 ubuntu ubuntu 22104 7月 3 07:56 decoder_net.h5 -rw-rw-r-- 1 ubuntu ubuntu 19304 7月 3 07:56 encoder_net.h5 -rw-rw-r-- 1 ubuntu ubuntu 14488 7月 3 07:56 gmm_density_net.h5 -rw-rw-r-- 1 ubuntu ubuntu 10033 7月 3 07:56 vaegmm.ckpt.data-00000-of-00001 -rw-rw-r-- 1 ubuntu ubuntu 1503 7月 3 07:56 vaegmm.ckpt.index
再度閾値を推論する必要があります :
od.infer_threshold(X_threshold, threshold_perc=100-perc_outlier)
print('New threshold: {}'.format(od.threshold))
New threshold: 9.472237873077368
更新された閾値で外れ値検知器をセーブします :
save_detector(od, filepath)
外れ値を検出して結果を表示する
予測します :
od_preds = od.predict(X_outlier, return_instance_score=True)
F1 スコアと混同行列 :
labels = outlier_batch.target_names
y_pred = od_preds['data']['is_outlier']
f1 = f1_score(y_outlier, y_pred)
print('F1 score: {:.4f}'.format(f1))
cm = confusion_matrix(y_outlier, y_pred)
df_cm = pd.DataFrame(cm, index=labels, columns=labels)
sns.heatmap(df_cm, annot=True, cbar=True, linewidths=.5)
plt.show()
F1 score: 0.9515
インスタンスレベルの外れ値スコア vs 外れ値閾値をプロットします :
plot_instance_score(od_preds, y_outlier, labels, od.threshold, ylim=(None, None))
ylim の min と max 値を調整することによりズームインできます。VAEGMM ROC カーブを AEGMM と比較することもできます :
roc_data['VAEGMM'] = {'scores': od_preds['data']['instance_score'], 'labels': y_outlier}
plot_roc(roc_data)
以上
Alibi Detect 0.7 : Examples : VAE 外れ値検知 on TCP dump
Alibi Detect 0.7 : Examples : VAE 外れ値検知 on KDD Cup ‘99 データセット (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 07/02/2021 (0.7.0)
* 本ページは、Alibi Detect の以下のドキュメントを翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
スケジュールは弊社 公式 Web サイト でご確認頂けます。
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- ウェビナー運用には弊社製品「ClassCat® Webinar」を利用しています。
人工知能研究開発支援 | 人工知能研修サービス | テレワーク & オンライン授業を支援 |
PoC(概念実証)を失敗させないための支援 (本支援はセミナーに参加しアンケートに回答した方を対象としています。) |
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション |
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ ; Facebook |
Alibi Detect 0.7 : Examples : VAE 外れ値検知 on KDD Cup ‘99 データセット
VAE – 概要
変分オートエンコーダ (VAE, Variational Auto-Encoder) 外れ値検知器は最初にラベル付けされていない、しかし通常 (inlier) データのバッチで訓練されます。教師なしか半教師あり訓練が望ましいです、何故ならばラベル付けされたデータはしばしば十分でないからです。VAE 検知器はそれが受け取る入力を再構築しようとします。入力データが上手く再構築されない場合、再構築エラーは高くそしてデータは外れ値としてフラグ立てできます。再構築エラーは、入力と再構築されたインスタンスの間の平均二乗誤差 (MSE, mean squared error) か、入力と再構築されたインスタンスの両者が同じプロセスで生成される確率として測定されます。アルゴリズムは表形式か画像データのために適合します。
データセット
典型的な U.S. 空軍 LAN をシミュレートした LAN の TCP dump データを使用して、外れ値検知器はコンピュータ・ネットワーク侵入を検知する必要があります。コネクションは明確に定義された時間で開始して終了する TCP パケットのシークエンスで、その間にデータは明確に定義されたプロトコルのもとにソース IP とターゲット IP アドレス間で流れます。各コネクションは正常、また攻撃としてラベル付けされます。
データセットには 4 タイプの攻撃があります :
- DOS: denial-of-service, e.g. syn flood;
- R2L: 遠隔マシンからの権限のないアクセス、e.g. パスワードの推測 ;
- U2R: ローカルのスーパーユーザ (root) 特権への権限のないアクセス ;
- probing : 偵察と他の厳密な調査、e.g., ポートスキャン。
データセットは約 500 万のコネクション・レコードを含みます。
3 つのタイプの特徴があります :
- 個々のコネクションの基本的な特徴, e.g. 接続時間 (duration of connection)
- コネクション内のコンテンツ特徴, e.g. 失敗したログイン試行の数
- 2 秒 window 内の traffic 特徴, e.g. 現在の接続と同じホストへのコネクションの数
import logging
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import pandas as pd
import seaborn as sns
from sklearn.metrics import confusion_matrix, f1_score
import tensorflow as tf
tf.keras.backend.clear_session()
from tensorflow.keras.layers import Dense, InputLayer
from alibi_detect.datasets import fetch_kdd
from alibi_detect.models.tensorflow.losses import elbo
from alibi_detect.od import OutlierVAE
from alibi_detect.utils.data import create_outlier_batch
from alibi_detect.utils.fetching import fetch_detector
from alibi_detect.utils.saving import save_detector, load_detector
from alibi_detect.utils.visualize import plot_instance_score, plot_feature_outlier_tabular, plot_roc
logger = tf.get_logger()
logger.setLevel(logging.ERROR)
データセットをロードする
幾つかの continuous (連続) な特徴 (41 の内から 18) だけを保持します。
kddcup = fetch_kdd(percent10=True) # only load 10% of the dataset
print(kddcup.data.shape, kddcup.target.shape)
Downloading https://ndownloader.figshare.com/files/5976042 (494021, 18) (494021,)
kddcup.data[0]
array([8, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 9, 9, 1.0, 0.0, 0.11, 0.0, 0.0, 0.0, 0.0, 0.0], dtype=object)
機械学習モデルはデータセットの (外れ値ではなく) 正常インスタンス上で訓練されて標準化 (= standardization) が適用されていると仮定します :
np.random.seed(0)
normal_batch = create_outlier_batch(kddcup.data, kddcup.target, n_samples=400000, perc_outlier=0)
X_train, y_train = normal_batch.data.astype('float'), normal_batch.target
print(X_train.shape, y_train.shape)
print('{}% outliers'.format(100 * y_train.mean()))
(400000, 18) (400000,) 0.0% outliers
mean, stdev = X_train.mean(axis=0), X_train.std(axis=0)
print(mean)
print(stdev)
[1.09550075e+01 1.55620000e-03 1.74745000e-03 5.54626500e-02 5.57733250e-02 9.85440925e-01 1.82663500e-02 1.33057100e-01 1.48641492e+02 2.02133175e+02 8.44858050e-01 5.64032750e-02 1.33479675e-01 2.40508250e-02 2.11637500e-03 1.05915000e-03 5.73124750e-02 5.52324500e-02] [2.17181039e+01 2.78305002e-02 2.61481724e-02 2.28073133e-01 2.26952689e-01 9.25608777e-02 1.16637691e-01 2.77172101e-01 1.03333220e+02 8.68577798e+01 3.05254458e-01 1.79868747e-01 2.80221411e-01 4.92476707e-02 2.95181081e-02 1.59275611e-02 2.24229381e-01 2.17798555e-01]
標準化を適用します :
X_train = (X_train - mean) / stdev
外れ値検知器をロードまたは定義する
examples ノートブックで使用される事前訓練済みの外れ値と敵対的検知器は ここ で見つかります。組込みの fetch_detector 関数を利用できます、これは事前訓練モデルをローカルディレクトリ filepath にセーブして検知器をロードします。代わりに、スクラッチから検知器を訓練することができます。
load_outlier_detector = False
filepath = 'my_dir' # change to directory (absolute path) where model is downloaded
if load_outlier_detector: # load pretrained outlier detector
detector_type = 'outlier'
dataset = 'kddcup'
detector_name = 'OutlierVAE'
od = fetch_detector(filepath, detector_type, dataset, detector_name)
filepath = os.path.join(filepath, detector_name)
else: # define model, initialize, train and save outlier detector
n_features = X_train.shape[1]
latent_dim = 2
encoder_net = tf.keras.Sequential(
[
InputLayer(input_shape=(n_features,)),
Dense(20, activation=tf.nn.relu),
Dense(15, activation=tf.nn.relu),
Dense(7, activation=tf.nn.relu)
])
decoder_net = tf.keras.Sequential(
[
InputLayer(input_shape=(latent_dim,)),
Dense(7, activation=tf.nn.relu),
Dense(15, activation=tf.nn.relu),
Dense(20, activation=tf.nn.relu),
Dense(n_features, activation=None)
])
# initialize outlier detector
od = OutlierVAE(threshold=None, # threshold for outlier score
score_type='mse', # use MSE of reconstruction error for outlier detection
encoder_net=encoder_net, # can also pass VAE model instead
decoder_net=decoder_net, # of separate encoder and decoder
latent_dim=latent_dim,
samples=5)
# train
od.fit(X_train,
loss_fn=elbo,
cov_elbo=dict(sim=.01),
epochs=30,
verbose=True)
# save the trained outlier detector
save_detector(od, filepath)
6250/6250 [=] - 148s 24ms/step - loss: 28695.7242 6250/6250 [=] - 148s 24ms/step - loss: 12437.6854 6250/6250 [=] - 146s 23ms/step - loss: 10256.9219 6250/6250 [=] - 155s 25ms/step - loss: 9557.9839 6250/6250 [=] - 147s 23ms/step - loss: 8414.8731 6250/6250 [=] - 148s 24ms/step - loss: 7847.7130 6250/6250 [=] - 151s 24ms/step - loss: 7549.5546 6250/6250 [=] - 150s 24ms/step - loss: 7412.6179 6250/6250 [=] - 147s 23ms/step - loss: 7358.9181 6250/6250 [=] - 148s 24ms/step - loss: 7064.3351 6250/6250 [=] - 145s 23ms/step - loss: 7047.5733 6250/6250 [=] - 150s 24ms/step - loss: 6862.8724 6250/6250 [=] - 146s 23ms/step - loss: 6859.6950 6250/6250 [=] - 149s 24ms/step - loss: 6733.0950 6250/6250 [=] - 146s 23ms/step - loss: 6395.8519 6250/6250 [=] - 152s 24ms/step - loss: 6239.8235 6250/6250 [=] - 147s 23ms/step - loss: 6141.0218 6250/6250 [=] - 149s 24ms/step - loss: 6080.4994 6250/6250 [=] - 150s 24ms/step - loss: 6030.9626 6250/6250 [=] - 152s 24ms/step - loss: 5986.5710 6250/6250 [=] - 152s 24ms/step - loss: 5968.1871 6250/6250 [=] - 150s 24ms/step - loss: 6026.3471 6250/6250 [=] - 152s 24ms/step - loss: 5828.1424 6250/6250 [=] - 149s 24ms/step - loss: 5841.5844 6250/6250 [=] - 147s 24ms/step - loss: 5794.9508 6250/6250 [=] - 154s 25ms/step - loss: 5792.5575 6250/6250 [=] - 147s 24ms/step - loss: 5767.5592 6250/6250 [=] - 150s 24ms/step - loss: 5643.3078 6250/6250 [=] - 147s 23ms/step - loss: 5571.4557 6250/6250 [=] - 148s 24ms/step - loss: 5541.4037
!ls model_vae -l
!ls model_vae/model -l
total 12 -rw-rw-r-- 1 ubuntu ubuntu 107 7月 2 13:26 OutlierVAE.pickle -rw-rw-r-- 1 ubuntu ubuntu 87 7月 2 13:26 meta.pickle drwxrwxr-x 2 ubuntu ubuntu 4096 7月 2 13:26 model total 64 -rw-rw-r-- 1 ubuntu ubuntu 73 7月 2 13:26 checkpoint -rw-rw-r-- 1 ubuntu ubuntu 22104 7月 2 13:26 decoder_net.h5 -rw-rw-r-- 1 ubuntu ubuntu 19304 7月 2 13:26 encoder_net.h5 -rw-rw-r-- 1 ubuntu ubuntu 9269 7月 2 13:26 vae.ckpt.data-00000-of-00001 -rw-rw-r-- 1 ubuntu ubuntu 1259 7月 2 13:26 vae.ckpt.index
警告は outlier threshold (外れ値閾値) を依然として設定する必要があることを教えます。これは infer_threshold メソッドで成されます。インスタンスのバッチを渡してそれらの何パーセントを正常であると考えるかを threshold_perc を通して指定する必要があります。およそ 5% の外れ値を含むことを知るあるデータを持つと仮定しましょう。外れ値のパーセンテージは create_outlier_batch 関数で perc_outlier で設定できます。
np.random.seed(0)
perc_outlier = 5
threshold_batch = create_outlier_batch(kddcup.data, kddcup.target, n_samples=1000, perc_outlier=perc_outlier)
X_threshold, y_threshold = threshold_batch.data.astype('float'), threshold_batch.target
X_threshold = (X_threshold - mean) / stdev
print('{}% outliers'.format(100 * y_threshold.mean()))
5.0% outliers
od.infer_threshold(X_threshold, threshold_perc=100-perc_outlier)
print('New threshold: {}'.format(od.threshold))
New threshold: 1.5222603200798008
threshold_perc を例えば 99 に設定して推論された閾値に少しのマージンを加えることにより通常の訓練データから閾値をすいろんすることもできました。更新された閾値で外れ値検知器をセーブしましょう :
save_detector(od, filepath)
!ls model_vae -l
!ls model_vae/model -l
total 12 -rw-rw-r-- 1 ubuntu ubuntu 218 7月 2 13:35 OutlierVAE.pickle -rw-rw-r-- 1 ubuntu ubuntu 87 7月 2 13:35 meta.pickle drwxrwxr-x 2 ubuntu ubuntu 4096 7月 2 13:35 model total 64 -rw-rw-r-- 1 ubuntu ubuntu 73 7月 2 13:35 checkpoint -rw-rw-r-- 1 ubuntu ubuntu 22104 7月 2 13:35 decoder_net.h5 -rw-rw-r-- 1 ubuntu ubuntu 19304 7月 2 13:35 encoder_net.h5 -rw-rw-r-- 1 ubuntu ubuntu 9269 7月 2 13:35 vae.ckpt.data-00000-of-00001 -rw-rw-r-- 1 ubuntu ubuntu 1259 7月 2 13:35 vae.ckpt.index
外れ値を検出する
今は 10% の外れ値を持つデータのバッチを生成しそしてバッチ内の外れ値を検出します。
np.random.seed(1)
outlier_batch = create_outlier_batch(kddcup.data, kddcup.target, n_samples=1000, perc_outlier=10)
X_outlier, y_outlier = outlier_batch.data.astype('float'), outlier_batch.target
X_outlier = (X_outlier - mean) / stdev
print(X_outlier.shape, y_outlier.shape)
print('{}% outliers'.format(100 * y_outlier.mean()))
(1000, 18) (1000,) 10.0% outliers
外れ値を予測します :
od_preds = od.predict(X_outlier,
outlier_type='instance', # use 'feature' or 'instance' level
return_feature_score=True, # scores used to determine outliers
return_instance_score=True)
print(list(od_preds['data'].keys()))
['instance_score', 'feature_score', 'is_outlier']
od_preds['data']['is_outlier'][:10]
array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0])
od_preds['data']['instance_score'][:10]
array([5.74442137e-04, 6.24835379e-04, 6.83877481e-04, 1.52228703e+00, 2.47923307e-02, 4.29582862e+01, 1.52229905e+00, 4.45219175e-03, 8.09561496e-02, 2.37765956e-02])
od_preds['data']['feature_score']
array([[4.77347707e-05, 6.23364775e-05, 4.80892692e-05, ..., 3.21192958e-04, 6.79559419e-05, 5.60611257e-05], [1.67435697e-04, 7.68863402e-05, 1.12371712e-04, ..., 3.19287128e-04, 9.01695907e-05, 8.10840695e-05], [9.42410698e-04, 1.08231414e-06, 3.40019366e-05, ..., 5.65485925e-04, 1.88107799e-05, 1.04572967e-05], ..., [2.08158688e-03, 4.93670543e-06, 3.57241685e-05, ..., 6.89739720e-04, 9.91289453e-05, 3.80882650e-06], [2.27466705e-03, 4.25181944e-03, 6.06307292e-05, ..., 3.40673684e-05, 9.27018184e-06, 6.57232246e-03], [1.50122506e-03, 4.51257037e-03, 1.09080541e-05, ..., 4.76422446e-04, 4.67411636e-03, 4.86378648e-02]])
結果を表示する
F1 スコアと混同行列 :
labels = outlier_batch.target_names
y_pred = od_preds['data']['is_outlier']
f1 = f1_score(y_outlier, y_pred)
print('F1 score: {:.4f}'.format(f1))
cm = confusion_matrix(y_outlier, y_pred)
df_cm = pd.DataFrame(cm, index=labels, columns=labels)
sns.heatmap(df_cm, annot=True, cbar=True, linewidths=.5)
plt.show()
F1 score: 0.9754
インスタンスレベルの外れ値スコア vs 外れ値閾値をプロットします :
plot_instance_score(od_preds, y_outlier, labels, od.threshold)
幾つかの外れ値が検出するのに非常に簡単である一方で、他は通常データに近い外れ値スコアを持つことが明瞭に分かります。検出器の外れ値スコアのための ROC カーブをプロットすることもできます :
roc_data = {'VAE': {'scores': od_preds['data']['instance_score'], 'labels': y_outlier}}
plot_roc(roc_data)
インスタンスレベル外れ値を調査する
今は X_outlier 上の個々の予測の幾つかを詳しく見ることができます。
X_recon = od.vae(X_outlier).numpy() # reconstructed instances by the VAE
plot_feature_outlier_tabular(od_preds,
X_outlier,
X_recon=X_recon,
threshold=od.threshold,
instance_ids=None, # pass a list with indices of instances to display
max_instances=5, # max nb of instances to display
top_n=5, # only show top_n features ordered by outlier score
outliers_only=False, # only show outlier predictions
feature_names=kddcup.feature_names, # add feature names
figsize=(20, 30))
(訳注 : 下は実験結果)
srv_count 特徴は多くの表示される外れ値の責任を負います。
以上