モバイル&ワイヤレスブロードバンドでインターネットへ

gwaw.jp
 
◈ GWAW.JP — JAVASCRIPT × ML EXPERIMENTS

時系列データのアノマリー検出

TensorFlow.js AutoEncoder によるブラウザ内異常検知

2026 · TENSORFLOW.JS 4.x · WEBGL BACKEND
TensorFlow.js AutoEncoder 教師なし学習 時系列 ブラウザ完結

このデモは、AutoEncoder(自己符号化器)という深層学習モデルをブラウザ内で学習・推論し、時系列データの中から「通常パターンとは異なる点(アノマリー)」を自動的に見つけ出すものです。 外部サーバーへの通信は一切なく、すべての計算がブラウザ内の TensorFlow.js で完結します。

💡 アノマリー検出とは?
株価の急騰・急落、センサーの異常値、ネットワークへの不正アクセスなど、「普段と違うデータ」を自動的に発見する技術です。 人間が閾値をいちいち設定しなくても、AIが正常パターンを学習して異常を判断します。
Chrome 113+✔ 推奨(WebGL 2.0 フル対応)
Safari 16.4+✔ 動作確認済み(iOS / iPadOS 含む)
Firefox 120+✔ 動作します
Edge 113+✔ 動作します
Internet Explorer✘ 非対応

学習処理はすべてクライアント側GPU(WebGL)で実行されます。 低スペック端末では学習に数十秒かかる場合があります。ページを閉じるとモデルはリセットされます。

ANOMALY DETECTOR — LIVE DEMO

まず「① データ生成」を押してください
TOTAL POINTS
ANOMALIES FOUND
DETECTION RATE
TRAINING LOSS

AutoEncoder は「入力データを小さな表現に圧縮し、そこから元のデータに戻す」ことを学習するニューラルネットワークです。 正常データだけを使って学習させるのがポイントです。

入力データ
(時系列ウィンドウ)
Encoder
(圧縮)
潜在表現
(小さなベクトル)
Decoder
(復元)
再構成データ
再構成誤差(Reconstruction Error)が判断の鍵です。
正常データ → モデルがうまく復元できる → 誤差が小さい
異常データ → モデルが復元できない → 誤差が大きい
STEP 01

データ準備

時系列データをスライディングウィンドウで切り出し、[0, 1] に正規化します。正常区間だけを学習データとします。

STEP 02

Encoder(符号化)

入力ウィンドウを Dense 層で段階的に圧縮します。このデモでは 20次元 → 8次元 → 4次元に絞ります。

STEP 03

Decoder(復号化)

圧縮した表現を逆の順序で元のサイズに戻します。入力と復元の差(MSE)を最小化するよう学習します。

STEP 04

閾値で判定

学習後、各データ点の再構成誤差を計算します。誤差が閾値を超えた点を「アノマリー」とマークします。

初めて TensorFlow.js を触る方でも理解しやすいよう、重要な部分をステップ別に解説します。

データの正規化(Min-Max スケーリング)

// 時系列データを 0〜1 の範囲に変換する
function normalize(data) {
  const min = Math.min(...data);
  const max = Math.max(...data);
  return {
    normalized: data.map(v => (v - min) / (max - min)),
    min, max
  };
}

// 予測結果を元のスケールに戻す(逆正規化)
function denormalize(value, min, max) {
return value * (max - min) + min;
}

ニューラルネットワークは 0〜1 のような小さな数値を扱うのが得意です。 生の数値(例:株価 3万円台)をそのまま入れると学習が不安定になるため、まずスケーリングを行います。

AutoEncoder モデルの構築

function buildAutoEncoder(windowSize) {
  const model = tf.sequential();

// ── Encoder(圧縮側)──
model.add(tf.layers.dense({
inputShape: [windowSize],
units: 8,          // 20次元 → 8次元に圧縮
activation: ‘relu’
}));
model.add(tf.layers.dense({
units: 4,           // 8次元 → 4次元にさらに圧縮(ボトルネック)
activation: ‘relu’
}));

// ── Decoder(復元側)──
model.add(tf.layers.dense({
units: 8,           // 4次元 → 8次元に展開
activation: ‘relu’
}));
model.add(tf.layers.dense({
units: windowSize,   // 元のサイズに戻す
activation: ‘sigmoid’
}));

model.compile({
optimizer: ‘adam’,
loss: ‘meanSquaredError’  // 入力と復元の差を最小化
});

return model;
}

Encoder 部分で次元を絞ることで、データの「本質的なパターン」だけを抽出します。 この圧縮されたボトルネック(4次元)が、正常パターンの記憶として機能します。 meanSquaredError(平均二乗誤差)が学習の目標で、これが最終的にアノマリースコアにもなります。

学習の実行(非同期・進捗表示付き)

await model.fit(trainTensor, trainTensor, {
  // 入力と正解が同じ(= 自己符号化)
  epochs: epochCount,
  batchSize: 32,
  validationSplit: 0.1,
  callbacks: {
    onEpochEnd: async (epoch, logs) => {
      // エポックごとに損失を表示(学習の進み具合を確認できる)
      setStatus(`学習中... Epoch ${epoch + 1} / Loss: ${logs.loss.toFixed(6)}`);
      await tf.nextFrame(); // UIがフリーズしないよう制御を返す
    }
  }
});

tf.nextFrame()が重要です。 JavaScriptはシングルスレッドなので、重い計算中はUIが固まります。 各エポックの終わりにメインスレッドに制御を返すことで、進捗表示がリアルタイムに更新されます。

再構成誤差の計算とアノマリー判定

async function computeErrors(model, windows) {
  const inputTensor  = tf.tensor2d(windows);
  const outputTensor = model.predict(inputTensor);
  const input  = await inputTensor.array();
  const output = await outputTensor.array();

// 各ウィンドウの MSE(平均二乗誤差)を計算
return input.map((win, i) => {
const mse = win.reduce((sum, v, j) =>
sum + (v - output[i][j]) ** 2, 0
) / win.length;
return mse;
});
}

// 閾値を超えたらアノマリー
const anomalies = errors.map(e => e > threshold);

MSE(Mean Squared Error)は「入力と復元の差の二乗平均」です。 正常データは小さく、異常データは大きくなります。 スライダーで閾値を調整することで、どこからを「異常」と見なすかをリアルタイムに変えられます。

『時系列データのアノマリー検出 — TensorFlow.js AutoEncoder』を公開しました。