2つのAIが、同じ点を指さすとき
1本目で「予測の外れ=異常の兆候かもしれない」と予告し、 2本目で実データを取れるようにしました。いよいよ、その予告を確かめる回です。
LSTM(予測)と AutoEncoder(異常検知)は、別々のツールに見えます。 ところが同じ為替データに重ねると、片方が「予測を外した」点と、もう片方が「異常だ」と言う点が、 同じ場所に立つ。この一致こそ、この記事の主役です。
LSTM で「過去の窓」を束ねる
1本目の構造図——過去N日 → 翌日1点——を、実装に落とします。ウィンドウをスライドさせて、 「過去N日」を入力、「翌日」を正解とする教師データを大量に作ります。
const model = tf.sequential(); model.add(tf.layers.lstm({ units: 32, inputShape: [WINDOW, 1] })); model.add(tf.layers.dense({ units: 1 })); model.compile({ optimizer: 'adam', loss: 'meanSquaredError' }); await model.fit(xs, ys, { epochs: 50, batchSize: 32 });
評価は RMSE(二乗誤差の平方根)と MAPE(平均絶対誤差率)。 「どれだけ外れたか」を数値で持っておきます——これが、後で異常検知と繋がる伏線です。
normalize と地続きの処理です。
スケールを揃えないと、LSTM はうまく学べません。
AutoEncoder で「再構成できなさ」を測る
AutoEncoder は、入力を一度小さく圧縮して、また元に戻すネットワークです。 正常なパターンばかりで学習すると、正常な入力は上手に戻せるようになります。
const ae = tf.sequential(); ae.add(tf.layers.dense({ units: 8, activation: 'relu', inputShape: [WINDOW] })); ae.add(tf.layers.dense({ units: 2, activation: 'relu' })); // ボトルネック(圧縮) ae.add(tf.layers.dense({ units: 8, activation: 'relu' })); ae.add(tf.layers.dense({ units: WINDOW })); // 復元 ae.compile({ optimizer: 'adam', loss: 'meanSquaredError' });
肝は再構成誤差——「入力」と「復元されたもの」の差です。正常なら小さく、 いつもと違うパターン(異常)はうまく戻せず、誤差が大きくなる。戻せなさが、異常の大きさです。
どこからを異常とするかは閾値で決めます。誤差の分布から自動で決める方法と、 感度スライダーで手動調整する方法。閾値を動かすと、検出される点が増減します。
異常には「これが異常」というラベルが普通ありません。AutoEncoder は正常だけを学べば異常が浮かぶ。ラベル不要で異常検知ができる、これが時系列と相性の良い理由です。
予測の「外れ」と異常は一致するか
ここで2つの誤差を並べます。LSTMの予測誤差(外れ具合)と、 AEの再構成誤差(戻せなさ)。 どちらも「いつもと違う」を、別の角度から測った量です。
これを同一グラフに重ねると——予測が大きく外れた点と、AEが異常とした点が、同じ場所に立ちます。 なぜか。市場の急変(ショック)は、過去から予測できないし、同時に正常パターンから外れる。 同じ現象を、予測モデルは「外れ」として、異常検知モデルは「再構成できなさ」として捉えているからです。
もちろん常に一致するわけではありません。緩やかな変化は AE が拾い、瞬間的なスパイクは LSTM が強く反応する、 といった片方だけが立つ点もあります。そこにも意味があります。
2つのAIは、同じ異常を指すか
為替風のデータに、いくつか異常(急なスパイク・段差)を仕込んであります。 感度(閾値)スライダーを動かして、LSTMの予測誤差と AEの再構成誤差が、同じ点で立つのを確かめてください。
感度を上げすぎると、正常な揺らぎまで拾って誤検出が増える。下げすぎると、本物の異常を見逃す。 その中間で、仕込んだ異常だけを両者が同時に指さす——一致率が跳ね上がる帯があります。
なぜ CPU バックエンド固定か
TensorFlow.js は同じコードで CPU / WebGL / WebGPU を切り替えられます。 「GPUの方が速い」——ところがこのツールは、あえて CPU 固定です。直感に反しますが、理由があります。
await tf.setBackend('cpu'); // WebGL/WebGPU を使わない
小さいモデルは、CPUが速い
gwaw.jp の TensorFlow.js バックエンド速度比較で実測したとおり、 小さいモデルでは CPU が WebGL/WebGPU より速い。GPUはデータのアップロードやカーネル起動に 固定コストがかかり、小さな演算ではそれを取り返せないからです。GPUが逆転するのは行列が十分大きくなってから。
LSTM は、特に CPU 向き
時系列モデルはさらに CPU 有利です。LSTM は各ステップが前のステップに依存する逐次計算で、 GPUの並列性が活きにくい。gwaw.jp の 「LSTMはCPU、モンテカルロはGPU」 という結論とも一致します。
点と点が、繋がった
3本かけて、教科書デモと実用ツールを隔てる3つの壁を越えました。 壁①データ(yf-proxy.php と3段フォールバック)、壁②時系列(LSTMで過去の窓を束ねる)、 壁③不確実性(AutoEncoderで再構成できなさを測る)。
そして最後に見たのは、予測と異常検知が裏表だったという事実。 「うまく予測できない」がそのまま「異常」になる。別々のAIが、同じ点を指さしていました。
- MNISTから先へ、何が要ったか
実データ・時系列・不確実性という3つの壁 - 実データを、どう取るか
yf-proxy.php と3段フォールバック - 2つのAIを、同じグラフに(この記事)
LSTM×AutoEncoder、予測と異常検知は裏表
MNIST(教科書)から、実データを扱う金融ツールへ。この道のりの到達点が、 為替 LSTM 予測 & アノマリー検出デモです。
この記事のまとめ
- LSTM は過去N日の窓 → 翌日を予測。RMSE / MAPE で「外れ」を数値化する。
- AutoEncoder は入力を圧縮して復元。再構成できなさ=異常の大きさ。閾値で検出。
- 予測誤差と再構成誤差を同一グラフに重ねると、同じ点で立つ。予測と異常検知は裏表。
- 小さいモデル・逐次計算のLSTMは CPUが速い。だからCPUバックエンド固定。
- gwaw版がベンチ、iseeit版が実用。同じ TensorFlow.js を役割で住み分ける。