ホーム » オートエンコーダ

オートエンコーダ」カテゴリーアーカイブ

Alibi Detect 0.7 : Examples : AE 外れ値検知 on CIFAR10

Alibi Detect 0.7 : Examples : AE 外れ値検知 on CIFAR10 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 07/04/2021 (0.7.0)

* 本ページは、Alibi Detect の以下のドキュメントを翻訳した上で適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

無料 Web セミナー開催中 クラスキャット主催 人工知能 & ビジネス Web セミナー

人工知能とビジネスをテーマに WEB セミナーを定期的に開催しています。
スケジュールは弊社 公式 Web サイト でご確認頂けます。
  • お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
  • ウェビナー運用には弊社製品「ClassCat® Webinar」を利用しています。
クラスキャットは人工知能・テレワークに関する各種サービスを提供しております :

人工知能研究開発支援 人工知能研修サービス テレワーク & オンライン授業を支援
PoC(概念実証)を失敗させないための支援 (本支援はセミナーに参加しアンケートに回答した方を対象としています。)

お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。

株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
E-Mail:sales-info@classcat.com  ;  WebSite: https://www.classcat.com/  ;  Facebook

 

Alibi Detect 0.7 : Examples : AE 外れ値検知 on CIFAR10

オートエンコーダ – 概要

オートエンコーダ (AE, Auto-Encoder) 外れ値検知器はラベル付けされていない、しかし通常 (inlier) データのバッチで最初に訓練されます。教師なし訓練が望ましいです、何故ならばラベル付けされたデータはしばしば十分でないからです。AE 検知器はそれが受け取る入力を再構築しようとします。入力データが上手く再構築されない場合、再構築エラーは高くそしてデータは外れ値としてフラグ立てできます。再構築エラーは入力と再構築されたインスタンスの間の平均二乗誤差 (MSE, mean squared error) として測定されます。

 

データセット

CIFAR10 は 10 クラスに渡り均等に分配された 60,000 の 32 x 32 RGB 画像から成ります。

import logging
import matplotlib.pyplot as plt
import numpy as np
import os
import tensorflow as tf
tf.keras.backend.clear_session()
from tensorflow.keras.layers import Conv2D, Conv2DTranspose, \
    Dense, Layer, Reshape, InputLayer, Flatten
from tqdm import tqdm

from alibi_detect.od import OutlierAE
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_ae_cifar10'  # change to (absolute) directory where model is downloaded
if load_outlier_detector:  # load pretrained outlier detector
    detector_type = 'outlier'
    dataset = 'cifar10'
    detector_name = 'OutlierAE'
    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
    encoding_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),
          Flatten(),
          Dense(encoding_dim,)
      ])

    decoder_net = tf.keras.Sequential(
      [
          InputLayer(input_shape=(encoding_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 = OutlierAE(threshold=.015,  # threshold for outlier score
                    encoder_net=encoder_net,  # can also pass AE model instead
                    decoder_net=decoder_net,  # of separate encoder and decoder
                    )
    # train
    od.fit(X_train,
           epochs=50,
           verbose=True)

    # save the trained outlier detector
    save_detector(od, filepath)

 

AE モデルの品質を確認する

idx = 8
X = X_train[idx].reshape(1, 32, 32, 3)
X_recon = od.ae(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()

 

元の CIFAR10 画像の外れ値を確認する

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.ae(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.ae(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.0017021061840932791
 

以上



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 の以下のドキュメントを翻訳した上で適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

無料 Web セミナー開催中 クラスキャット主催 人工知能 & ビジネス Web セミナー

人工知能とビジネスをテーマに WEB セミナーを定期的に開催しています。
スケジュールは弊社 公式 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)

 

以上



PyOD 0.8 : Examples : AutoEncoder

PyOD 0.8 : Examples : AutoEncoder (解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 06/28/2021 (0.8.9)

* 本ページは、PyOD の以下のドキュメントとサンプルを参考にして作成しています:


* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

PyOD 0.8 : Examples : AutoEncoder

完全なサンプル : examples/auto_encoder_example.py

 

合成データの生成

pyod.utils.data.generate_data() でサンプルデータを生成します :

from pyod.utils.data import generate_data

contamination = 0.1  # percentage of outliers
n_train = 20000  # number of training points
n_test = 2000  # number of testing points
n_features = 300  # number of features

# Generate sample data
X_train, y_train, X_test, y_test = generate_data(
    n_train=n_train,
    n_test=n_test,
    n_features=n_features,
    contamination=contamination,
    random_state=42)

X_train, y_train の shape と値を確認します :

print(X_train.shape)
print(y_train.shape)
(20000, 300)
(20000,)
X_train[:10]
array([[6.43365854, 5.5091683 , 5.04469788, ..., 4.98920813, 6.08796866,
        5.65703627],
       [6.98114644, 4.97019307, 7.24011768, ..., 4.13407401, 4.17437525,
        7.14246591],
       [6.96879306, 5.29747338, 5.29666367, ..., 5.97531553, 6.40414268,
        5.8399228 ],
       ...,
       [5.13676552, 6.62890142, 6.14075622, ..., 5.42330645, 5.68013833,
        7.49193446],
       [6.09141558, 5.30143243, 7.09624952, ..., 6.32592813, 7.31717914,
        7.4945297 ],
       [5.74924769, 6.76427622, 7.10854915, ..., 6.38070765, 6.23367069,
        6.3011638 ]])
y_train[:10]
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])

 

モデル訓練

pyod.models.auto_encoder.AutoEncoder 検出器をインポートして初期化し、そしてモデルを適合させます。

オートエンコーダ (AE) は有用なデータ表現を教師なしで学習するためのニューラルネットワークの一種です。PCA と同様に、再構築エラーを計算することによりデータの外れ値オブジェクトを検出するために使用できるでしょう。

参照 :

  • Charu C Aggarwal. Outlier analysis. In Data mining, 75–79. Springer, 2015.
from pyod.models.auto_encoder import AutoEncoder

# train AutoEncoder detector
clf_name = 'AutoEncoder'
clf = AutoEncoder(epochs=30, contamination=contamination)
clf.fit(X_train)
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 300)               90300     
_________________________________________________________________
dropout (Dropout)            (None, 300)               0         
_________________________________________________________________
dense_1 (Dense)              (None, 300)               90300     
_________________________________________________________________
dropout_1 (Dropout)          (None, 300)               0         
_________________________________________________________________
dense_2 (Dense)              (None, 64)                19264     
_________________________________________________________________
dropout_2 (Dropout)          (None, 64)                0         
_________________________________________________________________
dense_3 (Dense)              (None, 32)                2080      
_________________________________________________________________
dropout_3 (Dropout)          (None, 32)                0         
_________________________________________________________________
dense_4 (Dense)              (None, 32)                1056      
_________________________________________________________________
dropout_4 (Dropout)          (None, 32)                0         
_________________________________________________________________
dense_5 (Dense)              (None, 64)                2112      
_________________________________________________________________
dropout_5 (Dropout)          (None, 64)                0         
_________________________________________________________________
dense_6 (Dense)              (None, 300)               19500     
=================================================================
Total params: 224,612
Trainable params: 224,612
Non-trainable params: 0
_________________________________________________________________
None
Epoch 1/30
563/563 [==============================] - 2s 3ms/step - loss: 3.9799 - val_loss: 1.6536
Epoch 2/30
563/563 [==============================] - 1s 2ms/step - loss: 1.3378 - val_loss: 1.2611
Epoch 3/30
563/563 [==============================] - 1s 2ms/step - loss: 1.1653 - val_loss: 1.1830
Epoch 4/30
563/563 [==============================] - 1s 2ms/step - loss: 1.1163 - val_loss: 1.1421
Epoch 5/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0902 - val_loss: 1.1188
Epoch 6/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0745 - val_loss: 1.1108
Epoch 7/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0609 - val_loss: 1.0937
Epoch 8/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0519 - val_loss: 1.0851
Epoch 9/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0439 - val_loss: 1.0823
Epoch 10/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0372 - val_loss: 1.0715
Epoch 11/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0309 - val_loss: 1.0658
Epoch 12/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0247 - val_loss: 1.0612
Epoch 13/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0193 - val_loss: 1.0576
Epoch 14/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0158 - val_loss: 1.0543
Epoch 15/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0129 - val_loss: 1.0523
Epoch 16/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0103 - val_loss: 1.0495
Epoch 17/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0081 - val_loss: 1.0476
Epoch 18/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0062 - val_loss: 1.0460
Epoch 19/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0045 - val_loss: 1.0445
Epoch 20/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0031 - val_loss: 1.0433
Epoch 21/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0019 - val_loss: 1.0422
Epoch 22/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0008 - val_loss: 1.0413
Epoch 23/30
563/563 [==============================] - 1s 2ms/step - loss: 1.0001 - val_loss: 1.0405
Epoch 24/30
563/563 [==============================] - 1s 2ms/step - loss: 0.9993 - val_loss: 1.0399
Epoch 25/30
563/563 [==============================] - 1s 2ms/step - loss: 0.9987 - val_loss: 1.0394
Epoch 26/30
563/563 [==============================] - 1s 2ms/step - loss: 0.9982 - val_loss: 1.0389
Epoch 27/30
563/563 [==============================] - 1s 2ms/step - loss: 0.9978 - val_loss: 1.0386
Epoch 28/30
563/563 [==============================] - 1s 2ms/step - loss: 0.9975 - val_loss: 1.0383
Epoch 29/30
563/563 [==============================] - 1s 2ms/step - loss: 0.9972 - val_loss: 1.0380
Epoch 30/30
563/563 [==============================] - 1s 2ms/step - loss: 0.9969 - val_loss: 1.0378
AutoEncoder(batch_size=32, contamination=0.1, dropout_rate=0.2, epochs=30,
      hidden_activation='relu', hidden_neurons=[64, 32, 32, 64],
      l2_regularizer=0.1,
      loss=,
      optimizer='adam', output_activation='sigmoid', preprocessing=True,
      random_state=None, validation_size=0.1, verbose=1)

訓練データの予測ラベルと外れ値スコアを取得します :

y_train_pred = clf.labels_  # binary labels (0: inliers, 1: outliers)
y_train_scores = clf.decision_scores_  # raw outlier scores
y_train_pred
array([0, 0, 0, ..., 1, 1, 1])
y_train_scores[:10]
array([7.71661709, 8.3933272 , 8.03062351, 8.3012123 , 7.29930043,
       7.8202035 , 8.25040261, 7.89435037, 8.68701496, 7.54829144])

 

予測と評価

先に正解ラベルを確認しておきます :

y_test
array([0., array([0., 0., 0., ..., 1., 1., 1.])

テストデータ上で予測を行ないます :

y_test_pred = clf.predict(X_test)  # outlier labels (0 or 1)
y_test_scores = clf.decision_function(X_test)  # outlier scores
y_test_pred
array([0, 0, 0, ..., 1, 1, 1])
y_test_scores[:10]
array([7.88748478, 7.4678574 , 7.68665623, 7.7947202 , 7.81147175,
       7.44892412, 7.35455911, 7.74632114, 7.46644309, 8.08000442])

ROC と Precision @ Rank n pyod.utils.data.evaluate_print() を使用して予測を評価します。

from pyod.utils.data import evaluate_print
# evaluate and print the results
print("\nOn Training Data:")
evaluate_print(clf_name, y_train, y_train_scores)
print("\nOn Test Data:")
evaluate_print(clf_name, y_test, y_test_scores)
On Training Data:
AutoEncoder ROC:1.0, precision @ rank n:1.0

On Test Data:
AutoEncoder ROC:1.0, precision @ rank n:1.0
 

以上



ClassCat® Chatbot

人工知能開発支援
クラスキャットは 人工知能研究開発支援 サービスを提供しています :
  • テクニカルコンサルティングサービス
  • 実証実験 (プロトタイプ構築)
  • アプリケーションへの実装
  • 人工知能研修サービス
◆ お問合せ先 ◆
クラスキャット
セールス・インフォメーション
E-Mail:sales-info@classcat.com