0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

NeuralHydrologyに渡す前のデータ作成:DuckDBで管理してGenericDataset形式に出力する

0
Posted at

NeuralHydrologyに渡す前のデータ作成:DuckDBで管理してGenericDataset形式に出力する

はじめに

前回の記事では、NeuralHydrologyを使って水文LSTMを進める全体像を整理しました。次はいよいよStep 1のCudaLSTMに入りたいところですが、その前にやることがあります。

それは、NeuralHydrologyに渡せる形でデータを作ること です。

NeuralHydrologyは便利なライブラリですが、独自データを使う場合は、データの作成方法をそろえる必要があります。この記事では、まず小さなサンプルデータを作り、DuckDBで管理し、最後にNeuralHydrologyのGenericDataset形式へ出力するところまでを扱います。

この記事で作るものは次の2つです。

NeuralHydrologyに渡す前のデータ作成

  1. サンプルデータを作る

    • basin_001.nc
    • basin_002.nc
    • basin_003.nc
  2. GenericDataset形式で読み込める形にする

    • time_seriesフォルダ
    • attributesフォルダ

後続のStep 1では、このデータをそのまま使ってCudaLSTM + 日単位 + GenericDatasetを動かします。

参考にしているNeuralHydrologyのURLです。


今回の方針

この記事では、次の構成で進めます。

Python 3.13
Docker Compose
Jupyter Lab
GPU対応
DuckDB
NetCDF
NeuralHydrology GenericDataset形式

データ作成だけならGPUは必須ではありません。ただ、Step 1以降でCudaLSTMを動かすことを考えると、最初からGPUが見えるDocker環境にしておくと楽です。

参考のためソースコードと開発環境一式をZIPファイルにしていますので、参考にしてください。


GenericDatasetで必要な形

NeuralHydrologyのGenericDatasetでは、data_dirの下にtime_seriesフォルダを置きます。このフォルダには、流域ごとに1つのNetCDFファイルを置きます。

data/neuralhydrology/
├─ time_series/
│  ├─ basin_001.nc
│  ├─ basin_002.nc
│  └─ basin_003.nc
│
└─ attributes/
   └─ attributes.csv

NetCDFファイルには、dateという日時データが必要です。流域属性を使う場合は、attributesフォルダにCSVを置き、流域IDをキーにして属性を管理します。

今回のNetCDFには、次の変数を入れます。

変数名 内容 単位
precipitation 日雨量 mm/day
temperature 日平均気温 degree_C
pet 可能蒸発散量 mm/day
discharge 流出高 mm/day
discharge_m3s 流量換算値 m3/s

Step 1では、precipitationtemperaturepetを入力、dischargeを教師データとして使う想定です。


なぜDuckDBで管理するのか

NetCDFだけを直接作っても、Step 1は動かせます。ですが、後から流域を増やしたり、時間雨量や水位を追加したり、品質フラグを持たせたりすると、ファイルだけで管理するのは少しつらくなります。

そこで、この記事ではDuckDBをデータの元帳として使います。

考え方はこうです。

DuckDB
  ↓ export
NeuralHydrology GenericDataset
  ├─ time_series/*.nc
  └─ attributes/*.csv

DuckDB側には、元データに近い形でテーブルを持たせます。NeuralHydrologyに渡すときだけ、NetCDFとCSVに書き出します。

今回作るDuckDBの主なテーブルは次の2つです。

テーブル 内容
basins 流域面積、標高、勾配、森林率などの静的属性
daily_timeseries 日雨量、気温、蒸発散、流量などの日単位時系列

フォルダ構成

後続の記事でも使い回せるように、最初から少し整理した構成にしておきます。

neuralhydrology_data_prep_project/
├─ docker-compose.yml
├─ Dockerfile
├─ pyproject.toml
├─ README.md
├─ Makefile
│
├─ configs/
│  └─ README.md
│
├─ data/
│  ├─ raw/
│  ├─ duckdb/
│  │  └─ hydro_sample.duckdb
│  └─ neuralhydrology/
│     ├─ time_series/
│     │  ├─ basin_001.nc
│     │  ├─ basin_002.nc
│     │  └─ basin_003.nc
│     ├─ attributes/
│     │  └─ attributes.csv
│     ├─ basins_all.txt
│     ├─ basins_train.txt
│     ├─ basins_validation.txt
│     └─ basins_test.txt
│
├─ notebooks/
│  ├─ 00_check_environment.ipynb
│  └─ 01_create_sample_data.ipynb
│
├─ scripts/
│  ├─ 01_create_sample_dataset.py
│  └─ 02_validate_generic_dataset.py
│
└─ src/
   └─ hydro_sample/
      ├─ config.py
      ├─ synthetic.py
      ├─ database.py
      ├─ export_generic.py
      ├─ validate.py
      ├─ plotting.py
      ├─ pipeline.py
      └─ cli.py

configsは、次の記事でNeuralHydrologyの学習設定ファイルを置く場所です。今回はまだ使いません。


Docker Compose環境

docker-compose.ymlでは、Jupyter Labを起動し、GPUも見えるようにしています。

deploy:
  resources:
    reservations:
      devices:
        - driver: nvidia
          count: all
          capabilities: [gpu]

Docker側でGPUを使うには、ホスト側にNVIDIA DriverとNVIDIA Container Toolkitが必要です。データ作成だけならGPUがなくても考え方は同じですが、後続の学習まで同じ環境で進めるため、ここではGPU対応の設定にしています。

起動は次です。

docker compose build
docker compose up

ブラウザで次を開きます。

http://localhost:8888/lab?token=neuralhydrology

サンプルデータを作る

データ作成は、次のコマンドで実行します。

docker compose run --rm jupyter python scripts/01_create_sample_dataset.py

内部では、次の処理を行います。

1. basin_001, basin_002, basin_003 の静的属性を作る
2. 2010-01-01 から 2023-12-31 までの日単位データを作る
3. DuckDB に basins と daily_timeseries を保存する
4. DuckDB から GenericDataset 形式へ書き出す
5. 出力されたNetCDFとCSVを検証する

このサンプルでは、降雨、気温、蒸発散、流出高を合成データとして作っています。実務用のモデルではありませんが、NeuralHydrologyのデータ形式を確認するには十分です。


DuckDBに保存する

生成したデータは、まずDuckDBに保存します。

basinsには、流域ごとの固定属性を入れます。

カラム 内容
basin_id 流域ID
area_km2 流域面積
mean_elevation_m 平均標高
mean_slope 平均勾配
forest_ratio 森林率
urban_ratio 市街地率
geology_code 地質区分
river_length_km 河道長
basin_shape 流域形状指標

daily_timeseriesには、日単位の時系列を入れます。

カラム 内容
basin_id 流域ID
date 日付
precipitation_mm_day 日雨量
temperature_c 日平均気温
pet_mm_day 可能蒸発散量
discharge_mm_day 流出高
discharge_m3s 流量換算値
quality_flag 品質フラグ

後でMTS-LSTMに進むときは、ここにhourly_timeseriesのようなテーブルを追加すればよいです。


GenericDataset形式へ出力する

DuckDBに保存した後、NeuralHydrologyが読める形へ出力します。

data/neuralhydrology/
├─ time_series/
│  ├─ basin_001.nc
│  ├─ basin_002.nc
│  └─ basin_003.nc
└─ attributes/
   └─ attributes.csv

各NetCDFファイルは、1流域分の日単位時系列を持ちます。

Pythonで中を見ると、次のように確認できます。

import xarray as xr

ds = xr.open_dataset("data/neuralhydrology/time_series/basin_001.nc")
ds

attributes.csvは、次のような形式です。

basin_id,area_km2,mean_elevation_m,mean_slope,forest_ratio,urban_ratio,geology_code,river_length_km,basin_shape
basin_001,120.5,430.2,0.18,0.72,0.05,volcanic,34.8,1.35
basin_002,85.1,250.7,0.12,0.48,0.18,sedimentary,22.4,1.1
basin_003,210.4,680.1,0.25,0.81,0.02,granitic,51.2,1.6

出力を検証する

データを作った後は、必ず検証します。

docker compose run --rm jupyter python scripts/02_validate_generic_dataset.py

検証では、主に次を確認しています。

  • time_seriesフォルダがあるか
  • attributesフォルダがあるか
  • basin_001.ncなどのNetCDFファイルがあるか
  • NetCDFにdate座標があるか
  • precipitationtemperaturepetdischargeがあるか
  • attributes.csvbasin_idがあるか
  • NetCDFと属性CSVの流域IDが対応しているか
  • 欠測値が-999のような値で埋められていないか

水文データでは、欠測を-999で持っていることがよくあります。しかし、NeuralHydrologyに渡す段階では、欠測はNaNにしておくのが安全です。


Jupyter Labで確認する

Jupyter Labでは、次のnotebookを用意しています。

notebooks/00_check_environment.ipynb
notebooks/01_create_sample_data.ipynb

00_check_environment.ipynbでは、Pythonのバージョン、DuckDB、xarray、PyTorch、GPUの見え方を確認します。

01_create_sample_data.ipynbでは、サンプルデータを作成し、DuckDBの中身を見て、NetCDFを開き、簡単なハイドログラフを描きます。

まずはnotebookで中身を確認しておくと、次のStep 1で設定ファイルを書くときに迷いにくくなります。


後続Stepへのつなぎ方

この記事で作ったデータは、Step 1のCudaLSTM + 日単位 + GenericDatasetでそのまま使う想定です。

Step 1では、NeuralHydrologyのconfigで次のように指定します。

dataset: generic
data_dir: data/neuralhydrology

dynamic_inputs:
  - precipitation
  - temperature
  - pet

target_variables:
  - discharge

Step 2でEA-LSTMに進むときは、attributes.csvの流域属性を使います。

Step 3でMTS-LSTMに進むときは、DuckDBに時間単位のテーブルを追加し、日単位と時間単位の両方を出力できるようにします。

Step 4でMC-LSTMに進むときは、雨量を水収支上の入力水量としてどう扱うかを考えます。

つまり、今回の構成は単なるサンプル作成ではなく、後続の拡張を見越した入口になります。


まとめ

この記事では、NeuralHydrologyのStep 1に入る前の準備として、サンプルデータを作成し、DuckDBで管理し、GenericDataset形式に出力する流れを作りました。

ポイントは次の通りです。

DuckDBを元帳にする
  ↓
GenericDataset形式へ出力する
  ↓
NeuralHydrologyのconfigから読む

最初から実データで複雑な処理を始めるより、まずは小さな合成データでフォルダ構成、変数名、NetCDF、属性CSVの流れを確認しておくと、その後の学習実験がかなり進めやすくなります。

次は、このデータを使ってCudaLSTM + 日単位 + GenericDatasetを動かします。


参考リンク

NeuralHydrology

Docker / GPU / Python

DuckDB / NetCDF


0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?