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

gwaw.jp
 
◈ GWAW.JP / JAVASCRIPT × ML EXPERIMENTS / LSTM
TENSORFLOW.JS EXPERIMENT

LSTM による USD/JPY
短期予測

為替レートデータをブラウザ内で学習し、LSTMネットワークが翌ステップのレートを予測します。 データ取得・前処理・学習・予測・可視化まで、すべてクライアント完結。

TensorFlow.js LSTM 時系列予測 ブラウザ完結 USD/JPY
01

概要

このデモは、LSTM(Long Short-Term Memory)ネットワークを使って USD/JPY の為替レートの短期的な動きを予測するものです。 TensorFlow.js の CPU バックエンド(デフォルト)を使用し、外部サーバーへの通信なしに、すべての計算がブラウザ内で完結します。このモデルは行列サイズが小さいため、 WebGL(GPU)よりも CPU の方が転送オーバーヘッドなしに高速に動作します。

💡 このデモで学べること
時系列データをLSTMに入力するための「スライディングウィンドウ」手法、 正規化・逆正規化のパイプライン、予測精度の評価指標(RMSE・MAPE)、そしてモデルの限界を正直に観察することまでが、ひとつの実装で体験できます。
⚠️ モデルの限界について
為替市場は経済指標・地政学的リスク・中央銀行の政策など無数の要因で動きます。 このLSTMはあくまで過去の「数値パターン」のみを学習しており、それらの外部要因は一切考慮できません。予測が外れることも多く、それ自体が重要な学びです。
02

動作環境・注意事項

Chrome 113+✔ 推奨(CPU / WebGL 切替対応)
Safari 16.4+✔ 動作確認済み(iOS / iPadOS 含む)
Firefox 120+✔ 動作します
Edge 113+✔ 動作します
データソースデモ用合成データ(実際の為替データに近い特性を持つ生成データ)
学習時間CPUバックエンドでモバイルでも高速

03

インタラクティブ・デモ

USD/JPY LSTM PREDICTOR — TENSORFLOW.JS
```
BACKEND
● CPU — デフォルト(小モデルに最適)
「① データ生成」からスタートしてください
USD/JPY RATE — HISTORICAL + PREDICTION
NEXT STEP PREDICTION
JPY
BACKEND
CPU
TRAIN TIME
DATA POINTS
TRAIN / TEST
FINAL LOSS
TEST RMSE
TEST MAPE
TRAINING LOSS CURVE
PREDICTION ERROR DISTRIBUTION (TEST SET)
```
04

動作原理と内部の仕組み

LSTMは時間の流れを記憶できるニューラルネットワークです。 通常の全結合層(Dense層)はひとつの入力を見て出力するだけですが、 LSTMは過去の入力を「記憶」として保持しながら処理できるため、 時系列データの予測に適しています。

STEP 01

スライディングウィンドウ

時系列データを固定長の窓で切り出します。例えばウィンドウサイズ20なら「直近20ステップのデータから翌ステップを予測」する訓練データを作ります。

STEP 02

正規化

生の為替レート(例:150円台)を[0, 1]の範囲に変換します。LSTMはこのスケールで学習し、予測後に逆変換して実際のレートに戻します。

STEP 03

LSTM の記憶機構

セル状態(長期記憶)とゲート機構(忘却・入力・出力)によって、関連する過去情報を保持し、不要な情報を忘れます。これが長い依存関係の学習を可能にします。

STEP 04

多ステップ予測

1ステップ先の予測値を新たな入力として追加し、ウィンドウをスライドさせながら繰り返し予測します。ステップ数が増えるほど誤差が累積します。

モデルのアーキテクチャは以下の通りです:

INPUT [ windowSize × 1 ]
LSTM ( units, return_sequences )
Dropout ( rate )
↓ ※2層・3層の場合は繰り返し
LSTM ( units )
Dropout ( rate )
Dense ( 16, relu )
OUTPUT Dense ( 1, linear )
項目 株価LSTM(前回記事) 為替LSTM(本記事)
データ取得 CSV アップロード 合成データ自動生成(API不要)
モデル層 固定1〜2層 1〜3層をUI で切替
予測 翌日終値1点 最大30ステップ先まで
評価指標 損失のみ RMSE・MAPE・誤差分布
Dropout なし スライダーで調整可
05

コードのポイント解説

TensorFlow.js で LSTM を実装するとき、初心者がつまずきやすいポイントを中心に解説します。

スライディングウィンドウでデータを準備する
// 時系列データを [入力ウィンドウ, 正解ラベル] の組に変換する
function createWindows(data, windowSize) {
  const X = [], Y = [];

for (let i = 0; i < data.length - windowSize; i++) {
X.push(data.slice(i, i + windowSize));  // 過去 N ステップ
Y.push(data[i + windowSize]);           // 翌ステップの値(正解)
}
return { X, Y };
}

// LSTM に渡すには 3D テンソル [samples, timesteps, features] が必要
const xTensor = tf.tensor3d(X, [X.length, windowSize, 1]);
const yTensor = tf.tensor2d(Y, [Y.length, 1]);

Dense 層は 2D テンソル(バッチ × 特徴量)を受け取りますが、 LSTM は 3D テンソル [samples, timesteps, features] を必要とします。 tf.tensor3d で形状を明示的に指定するのが重要なポイントです。

LSTM モデルの構築(層数を動的に変える)
function buildModel(windowSize, lstmUnits, numLayers, dropoutRate) {
  const model = tf.sequential();

for (let i = 0; i < numLayers; i++) {
const isFirst = i === 0;
const isLast  = i === numLayers - 1;

```
model.add(tf.layers.lstm({
  units: lstmUnits,
```

      returnSequences: !isLast,  // 最終層だけ false — 重要!
inputShape: isFirst ? [windowSize, 1] : undefined,
}));
model.add(tf.layers.dropout({ rate: dropoutRate }));
}

model.add(tf.layers.dense({ units: 16, activation: ‘relu’ }));
model.add(tf.layers.dense({ units: 1  }));  // 出力は1値(次のレート)

model.compile({
optimizer: tf.train.adam(0.001),
loss: ‘meanSquaredError’
});
return model;
}

returnSequences: true は「次のLSTM層にシーケンス全体を渡す」設定です。 LSTM を積み重ねる場合、最後の層だけ false(= 最終ステップの出力だけ返す)にする必要があります。 ここを間違えると形状エラーが発生します。

バックエンドの選択(なぜ CPU がデフォルトか)
// ページ読み込み時に CPU バックエンドで初期化する
await tf.setBackend('cpu');
await tf.ready();

// WebGPU は navigator.gpu で事前チェックしてから切替
if (!navigator.gpu) {
showUnsupported(); // バッジを赤く表示してフォールバック
} else {
await tf.setBackend(‘webgpu’);
await tf.ready();
// 実際に切り替わったか確認(未対応時はフォールバックが起きる)
const actual = tf.getBackend();
if (actual !== ‘webgpu’) throw new Error(`フォールバック: ${actual}`);
}

WebGL(GPU)バックエンドは大きな行列演算では有利ですが、CPU↔GPU のデータ転送コストが発生します。 このモデルの入力は最大 40×1、LSTM Units は最大 128 と非常に小さいため、 転送オーバーヘッドが演算時間を上回り CPU の方が高速になります。
WebGPU バックエンドは Chrome 113+ / HTTPS 環境が必要で、navigator.gpu の存在で事前チェックできます。 対応環境であれば WebGL より低オーバーヘッドで動作しますが、このモデルサイズでは CPU が依然として優位です。 デモのトグルで3つを切り替えて TRAIN TIME を比較してみてください。

学習ループ(進捗表示 + UI フリーズ防止)
await model.fit(xTrain, yTrain, {
  epochs,
  batchSize: 32,
  validationSplit: 0.1,
  callbacks: {
    onEpochEnd: async (epoch, logs) => {
      lossHistory.push(logs.loss);
      valLossHistory.push(logs.val_loss);

```
  // プログレスバーとステータスを更新
  const pct = ((epoch + 1) / epochs * 100).toFixed(0);
  setProgress(pct);
  setStatus(`学習中 ${pct}% — loss: ${logs.loss.toFixed(6)}`, 'run');
```

      await tf.nextFrame();  // ← UIスレッドに制御を返す(必須)
}
}
});

await tf.nextFrame() がないと、学習中はページ全体がフリーズします。 各エポック終了後にブラウザのレンダリングサイクルに制御を返すことで、 プログレスバーやステータスのリアルタイム更新が可能になります。

多ステップ予測(再帰的な予測)
function multiStepPredict(model, seedWindow, steps, minVal, maxVal) {
  let window = [...seedWindow];  // 直近 N ステップのコピー
  const predictions = [];

for (let s = 0; s < steps; s++) {
// [1, windowSize, 1] の形状で入力テンソルを作成
const input = tf.tensor3d([window.map(v => [v])], [1, window.length, 1]);
const normPred = model.predict(input).dataSync()[0];
input.dispose();

```
// 逆正規化して実際のレートに変換
const realPred = normPred * (maxVal - minVal) + minVal;
predictions.push(realPred);
```

    // 予測値をウィンドウに追加して次のステップへ(自己回帰)
window = […window.slice(1), normPred];
}
return predictions;
}

ハイライト行が「自己回帰(autoregressive)」の核心です。 予測した値を次の入力ウィンドウの末尾に追加することで、連続的に先の未来を予測できます。 ただしステップが増えるほど誤差が積み重なるため、遠い未来の予測精度は下がります。

評価指標(RMSE・MAPE)の計算
// RMSE: 予測誤差の大きさを実際のレートの単位(円)で表す
function calcRMSE(actual, predicted) {
  const mse = actual.reduce((s, v, i) =>
    s + (v - predicted[i]) ** 2, 0
  ) / actual.length;
  return Math.sqrt(mse);
}

// MAPE: 誤差をパーセントで表す(スケールに依存しない比較ができる)
function calcMAPE(actual, predicted) {
const sum = actual.reduce((s, v, i) =>
s + Math.abs((v - predicted[i]) / v), 0
);
return (sum / actual.length) * 100;
}

RMSE が「1.5」なら、平均的に±1.5円の誤差があるということです。 MAPE は「1%」なら実際の値の1%程度の誤差、という意味で、 為替レートのスケールが変わっても比較しやすい指標です。

⚠️ 免責事項
本デモはTensorFlow.jsの学習・実験を目的としたものです。 デモの予測結果は実際の為替市場の動向を予測するものではなく、 投資判断や取引の根拠として使用しないでください。 為替取引はリスクを伴い、元本割れの可能性があります。 投資判断はご自身の責任で行い、必要に応じて専門家にご相談ください。

『LSTM による USD/JPY 短期予測 — TensorFlow.js』を公開しました。