Source code for pyhazards.models.neuralhydrology_lstm

from __future__ import annotations

from typing import Any

import torch
import torch.nn as nn


def _streamflow_inputs(batch: Any) -> torch.Tensor:
    x = batch["x"] if isinstance(batch, dict) else batch
    if x.ndim != 4:
        raise ValueError("NeuralHydrology-style models expect inputs shaped (batch, history, nodes, features).")
    return x


[docs] class NeuralHydrologyLSTM(nn.Module): """Adapter-style LSTM streamflow baseline.""" def __init__( self, input_dim: int = 2, hidden_dim: int = 64, num_layers: int = 2, out_dim: int = 1, dropout: float = 0.1, ): super().__init__() self.out_dim = int(out_dim) self.encoder = nn.LSTM( input_size=input_dim, hidden_size=hidden_dim, num_layers=num_layers, batch_first=True, dropout=dropout if num_layers > 1 else 0.0, ) self.head = nn.Linear(hidden_dim, self.out_dim)
[docs] def forward(self, batch: Any) -> torch.Tensor: x = _streamflow_inputs(batch) bsz, history, nodes, features = x.shape series = x.permute(0, 2, 1, 3).reshape(bsz * nodes, history, features) encoded, _ = self.encoder(series) preds = self.head(encoded[:, -1]) return preds.view(bsz, nodes, self.out_dim)
[docs] def neuralhydrology_lstm_builder( task: str, input_dim: int = 2, hidden_dim: int = 64, num_layers: int = 2, out_dim: int = 1, dropout: float = 0.1, **kwargs, ) -> nn.Module: _ = kwargs if task.lower() != "regression": raise ValueError("NeuralHydrologyLSTM only supports regression for streamflow forecasting.") return NeuralHydrologyLSTM( input_dim=input_dim, hidden_dim=hidden_dim, num_layers=num_layers, out_dim=out_dim, dropout=dropout, )
__all__ = ["NeuralHydrologyLSTM", "neuralhydrology_lstm_builder"]