LSTMからハイブリッドへ:降雨流出解析プロトタイプ作成 Step 1 LSTM単独モデルを実装する
はじめに
前回の記事では、降雨流出解析について、まずLSTM単独モデルを試し、その後に物理モデルとのハイブリッドへ拡張する流れを整理しました。
今回はその Step 1 として、Docker環境で動作する LSTM単独モデル を作成します。
今回作成するプロトタイプ名は以下です。
RainfallRunoffLSTM_Prototype_r001
この段階では、タンクモデルや貯留関数法などの物理・概念モデルはまだ使いません。
まずは、雨量・気温・蒸発散量から流量を直接予測するLSTMモデルを実装します。
今回の目的
今回の目的は、以下を確認することです。
1. Docker環境でLSTM降雨流出モデルを動かす
2. サンプルの降雨・流量データを作成する
3. 前処理で学習用データを作る
4. LSTM単独モデルを学習する
5. 観測流量と予測流量を比較する
6. NSE, KGE, RMSEなどで評価する
今回はあくまでも 第1段階のプロトタイプ です。
精度を追い込むことよりも、まずは一連の処理が動くことを重視します。
モデル構成
今回のLSTM単独モデルは、以下の構成です。
入力:
日雨量 precip_mm
日平均気温 temp_c
可能蒸発散量 pet_mm
モデル:
LSTM
出力:
流出高 q_mm_day
フォルダー構成
今回のフォルダー構成は以下です。
RainfallRunoffLSTM_Prototype_r001/
├─ docker/
│ ├─ Dockerfile
│ └─ requirements.txt
├─ docker-compose.yml
├─ .env
├─ configs/
│ ├─ lstm_config.yaml
│ └─ lstm_config_quick.yaml
├─ data/
│ ├─ raw/
│ │ └─ rainfall_runoff_sample.csv
│ └─ processed/
│ └─ rainfall_runoff_daily.csv
├─ src/
│ ├─ generate_sample_data.py
│ ├─ preprocess.py
│ ├─ datasets.py
│ ├─ model_lstm.py
│ ├─ train_lstm.py
│ ├─ evaluate.py
│ ├─ predict.py
│ ├─ metrics.py
│ └─ utils.py
├─ notebooks/
│ └─ 01_check_data.ipynb
├─ outputs/
│ ├─ models/
│ ├─ figures/
│ ├─ metrics/
│ └─ predictions/
├─ scripts/
│ ├─ run_generate_sample.sh
│ ├─ run_preprocess.sh
│ ├─ run_train_lstm.sh
│ ├─ run_evaluate.sh
│ └─ run_quick_test.sh
├─ docs/
│ └─ qiita_step1_lstm.md
├─ run_docker_start.bat
└─ run_docker_quick_test.bat
各フォルダーの役割
| フォルダー | 内容 |
|---|---|
docker/ |
DockerfileとPythonライブラリ定義 |
configs/ |
学習条件・評価条件の設定ファイル |
data/raw/ |
元データ |
data/processed/ |
前処理後のデータ |
src/ |
Pythonソースコード |
notebooks/ |
データ確認用Notebook |
outputs/models/ |
学習済みモデル |
outputs/figures/ |
ハイドログラフ、散布図、loss曲線 |
outputs/metrics/ |
評価指標CSV |
outputs/predictions/ |
予測結果CSV |
scripts/ |
Dockerコンテナ内で実行する補助スクリプト |
docs/ |
Qiita記事用Markdown |
Docker環境
Docker環境では、JupyterLabと学習実行を同じコンテナで行います。
docker-compose.yml
services:
rainfall-runoff-lstm:
build:
context: .
dockerfile: docker/Dockerfile
container_name: rainfall_runoff_lstm_r001
working_dir: /workspace
volumes:
- .:/workspace
- ./data:/workspace/data
- ./outputs:/workspace/outputs
- ./notebooks:/workspace/notebooks
ports:
- "8888:8888"
env_file:
- .env
command: >
jupyter lab
--ip=0.0.0.0
--port=8888
--no-browser
--allow-root
--NotebookApp.token=${JUPYTER_TOKEN}
設定ファイル
通常実行用の設定例です。
seq_length: 180
hidden_size: 64
num_layers: 1
dropout: 0.0
batch_size: 64
epochs: 50
learning_rate: 0.001
loss: mse
target: q_mm_day
各パラメータの意味は以下です。
| パラメータ | 意味 |
|---|---|
seq_length |
LSTMに入力する過去時系列の長さ |
hidden_size |
LSTM内部の隠れ状態の次元数 |
num_layers |
LSTM層の数 |
dropout |
過学習を抑えるためのdropout率 |
batch_size |
1回の学習更新に使うサンプル数 |
epochs |
学習データ全体を繰り返す回数 |
learning_rate |
重み更新の学習率 |
loss |
学習時に最小化する損失関数 |
target |
予測対象の目的変数 |
実行方法
1. Dockerコンテナを起動
ZIPファイルをダウンロードして、解凍してください。
docker compose up --build
JupyterLabは以下で開きます。
http://localhost:8888
.env の設定例です。
JUPYTER_TOKEN=rainfall
TZ=Asia/Tokyo
簡易テスト
最初は通常設定ではなく、簡易設定で動作確認します。
docker compose run --rm rainfall-runoff-lstm bash scripts/run_quick_test.sh
このスクリプトでは、以下をまとめて実行します。
サンプルデータ作成
↓
前処理
↓
LSTM学習
↓
評価
個別に実行する場合
サンプルデータ作成
docker compose run --rm rainfall-runoff-lstm python src/generate_sample_data.py
前処理
docker compose run --rm rainfall-runoff-lstm python src/preprocess.py --config configs/lstm_config.yaml
LSTM学習
docker compose run --rm rainfall-runoff-lstm python src/train_lstm.py --config configs/lstm_config.yaml
評価
docker compose run --rm rainfall-runoff-lstm python src/evaluate.py --config configs/lstm_config.yaml
評価指標
今回のプロトタイプでは、以下の評価指標を出力します。
| 指標 | 内容 |
|---|---|
| NSE | 観測流量と予測流量の一致度を評価する指標 |
| KGE | 相関・ばらつき・バイアスを含む指標 |
| RMSE | 平均二乗誤差の平方根 |
| MAE | 平均絶対誤差 |
| Bias | 全体的な過大・過小評価 |
| Peak Error | ピーク流量の誤差 |
NSEは、流出解析でよく使われる再現性指標です。
NSE = 1.0 に近いほど再現性が高い
NSE = 0.0 は観測平均を使うモデルと同程度
NSE < 0.0 は観測平均より悪い
出力されるファイル
実行後、以下のようなファイルが出力されます。
outputs/
├─ models/
│ └─ lstm_best.pth
├─ figures/
│ ├─ hydrograph_test.png
│ ├─ scatter_obs_pred.png
│ └─ loss_curve.png
├─ metrics/
│ └─ test_metrics.csv
└─ predictions/
└─ test_predictions.csv
図の内容
| 図 | 内容 |
|---|---|
hydrograph_test.png |
観測流量とLSTM予測流量の比較 |
scatter_obs_pred.png |
観測値と予測値の散布図 |
loss_curve.png |
学習lossと検証lossの推移 |
今回の位置づけ
今回の RainfallRunoffLSTM_Prototype_r001 は、LSTM単独モデルの第1段階です。
Step 1:
LSTM単独モデルを作る
Step 2:
実効雨量・先行降雨指数を特徴量に追加する
Step 3:
タンクモデルなどの概念モデルを追加する
Step 4:
タンクモデル + LSTM補正のハイブリッドモデルへ拡張する
Step 5:
微分可能水文モデルへ発展させる
今回は、Step 1として以下を確認しました。
1. Docker環境で動く
2. サンプルデータを作成できる
3. 前処理できる
4. LSTMを学習できる
5. 評価指標と図を出力できる
注意点
今回のモデルは、あくまでもプロトタイプです。
実務利用するには、以下の検討が必要です。
- 実流域の観測雨量・観測流量を使った検証
- 欠測値・異常値処理
- 学習期間・検証期間・テスト期間の適切な分割
- 洪水イベントごとの評価
- ピーク流量とピーク時刻の評価
- 低水時の評価
- 水収支の確認
- 外挿性の確認
特に、LSTM単独モデルは水収支を保証しません。
そのため、次の段階では、実効雨量や先行降雨指数を追加し、さらにタンクモデルなどの物理・概念モデルとのハイブリッド化を検討します。
まとめ
今回は、降雨流出解析プロトタイプのStep 1として、Docker環境で動作するLSTM単独モデルを作成しました。
RainfallRunoffLSTM_Prototype_r001
この段階では、雨量・気温・蒸発散量を入力し、LSTMで流出高を予測します。
まずはLSTM単独モデルで、データ作成、前処理、学習、評価までの一連の流れを確認しました。
次回は、以下のような水文特徴量を追加します。
- 実効雨量
- 先行降雨指数
- 累積雨量
- 前日流量
これにより、LSTMに水文学的な特徴量を与え、再現性の改善を確認します。
参考リンク
-
前回記事:LSTM単独からハイブリッドへ:物理モデル×深層学習で考える降雨流出解析プロトタイプ
https://qiita.com/rino_yume/items/11238afbfc8c488488dc -
Rainfall–Runoff Modelling Using Long Short-Term Memory Networks
https://hess.copernicus.org/articles/22/6005/2018/ -
NeuralHydrology
https://neuralhydrology.readthedocs.io/ -
PyTorch LSTM
https://pytorch.org/docs/stable/generated/torch.nn.LSTM.html
