cat > doc/source/api/modules.rst << ‘EOF’ API Reference =============
This page provides the complete API reference for PhenoNN.
Main Package
PhenoNN - Deep learning for phenology prediction using climate data.
This package provides LSTM, GRU, and Transformer models to predict Green Chromatic Coordinate (GCC) or Leaf Area Index (LAI) from climate data.
- class phenonn.PhenoCamDataset(*args: Any, **kwargs: Any)[source]
Bases:
DatasetPyTorch dataset for LAI prediction.
Each sample is a 365-day sliding window of meteorological and site features, with the target being LAI on the final day of the window.
The feature tensor has shape (feature_channels, 365) where feature_channels = len(DYNAMIC_FEATURES) + len(CYCLIC_FEATURES) + len(STATIC_FEATURES) + n_pfts.
- Parameters:
site_files (list of str) – Paths to site CSV files (e.g. [‘DB_asuhighlands.csv’, …]).
norm_stats (dict) – Normalization statistics from compute_norm_stats().
seq_length (int) – Window length in days. Default 365.
target_col (str) – Target column name. Default ‘LAI’.
normalize_target (bool) – Whether to z-score the target. Default False.
pft_list (list of str, optional) – Ordered list of all PFT codes for one-hot encoding. If None, auto-discovered from site_files.
stride (int) – Step between consecutive windows. Default 1 (every day).
years (list of int, optional) – If provided, only use windows whose target day falls in these years. Use this to split “predict year by year”.
Examples
> stats = compute_norm_stats(train_files) > train_ds = PhenoCamDataset(train_files, stats, pft_list=[‘DB’, ‘EN’, ‘GR’]) > features, target = train_ds[0] > features.shape torch.Size([14, 365]) # 7 meteo + 2 cyclic + 2 static + 3 PFT > target.shape torch.Size([1])
- __init__(site_files: List[str], norm_stats: Dict[str, Dict[str, float]], seq_length: int = 365, target_col: str = 'LAI', normalize_target: bool = True, pft_list: List[str] | None = None, stride: int = 1, lai_norms=None, years: List[int] | None = None, n_target_days: int = 1, residual_csv: str | None = None, random_stride: int = 0, feature_mode: str = 'all', full_year: bool = False) None[source]
- class phenonn.LAIDataset(*args: Any, **kwargs: Any)[source]
Bases:
DatasetPyTorch dataset for LAI prediction using flat feature and target CSVs.
Each sample is one (site_id, target_year) pair. The feature window covers seq_length consecutive days ending on the last day of the target year. The target is the 36 LAI observations for that year (days 5, 15, 25 of every month).
Feature tensor shape : (n_features, seq_length) — 31 channels by default Target tensor shape : (1, 36)
- Parameters:
features_csv (str) – Path to flat daily features CSV.
target_csv (str) – Path to sparse LAI targets CSV.
norm_stats (dict) – Normalization stats from compute_norm_stats().
site_ids (list of str, optional) – Restrict to these site IDs. Default: all sites in features_csv.
seq_length (int) – Feature window length in days. Default 720 (≈ 2 years).
years (list of int, optional) – If provided, only include samples where the target year is in this list.
normalize_target (bool) – Z-score the LAI target. Default True.
lai_norms (dict, optional) – Per-site {site_id: {“lai_min”: float, “lai_max”: float}} for min-max normalization. Overrides normalize_target when site_id is present.
Examples
>>> stats = compute_norm_stats("features.csv", "targets.csv", train_ids) >>> ds = LAIDataset("features.csv", "targets.csv", stats, site_ids=train_ids) >>> feats, targets = ds[0] >>> feats.shape torch.Size([31, 720]) >>> targets.shape torch.Size([1, 36])
- phenonn.add_derived_features(df: pandas.DataFrame) pandas.DataFrame[source]
Add GDD, CDD, and Botta onset features to a site dataframe.
Must be called AFTER sorting by (year, doy) and BEFORE normalization. All features reset to zero on January 1st of each year.
- Parameters:
df (pd.DataFrame) – Site data with columns: year, doy, tmin, tmax (at minimum).
- Returns:
Same dataframe with added columns:
gdd_0, gdd_5, gdd_10 : Growing Degree Days at 0/5/10°C thresholds
cdd : Chilling Degree Days (cold accumulation below 5°C)
ncd : Number of Chilling Days (count of days where Tmean < 5°C)
- botta_thresholdGDD threshold from Botta et al. (2000)
G_thres = 964 * exp(-0.0058 * NCD) - 12.8
- botta_forcingGDD_0 / G_thres (onset proximity indicator)
~0 in winter, approaches 1 at onset, >1 during growing season
- Return type:
pd.DataFrame
- phenonn.split_sites_by_fraction(site_files: List[str], val_fraction: float = 0.2, seed: int = 42) Tuple[List[str], List[str]][source]
Split site files into train and validation sets (leave-site-out).
- phenonn.split_sites_flat(site_ids: List[str], val_fraction: float = 0.2, seed: int = 42) Tuple[List[str], List[str]]
Split site_ids into (train, val) sets (leave-site-out).
- Return type:
(train_ids, val_ids)
- phenonn.get_site_ids(csv_path: str) List[str][source]
Return sorted list of unique site_ids from a features or targets CSV.
- phenonn.extract_pft_and_site(filepath: str) Tuple[str, str][source]
Extract PFT code and site name from a filename like ‘DB_asuhighlands.csv’.
- class phenonn.RNN_LSTM(*args: Any, **kwargs: Any)[source]
Bases:
BaseRNNLSTM-based bidirectional RNN model.
This class inherits from BaseRNN and configures it to use LSTM cells.
- Parameters:
Examples
>>> model = RNN_LSTM( ... feature_channel=6, ... output_channel=4, ... hidden_size=128, ... num_layers=3 ... ) >>> x = torch.randn(16, 6, 10) >>> y = model(x) >>> print(y.shape) torch.Size([16, 4, 10])
- class phenonn.RNN_GRU(*args: Any, **kwargs: Any)[source]
Bases:
BaseRNNGRU-based bidirectional RNN model.
This class inherits from BaseRNN and configures it to use GRU cells.
- Parameters:
Examples
>>> model = RNN_GRU( ... feature_channel=6, ... output_channel=4, ... hidden_size=128, ... num_layers=3 ... ) >>> x = torch.randn(16, 6, 10) >>> y = model(x) >>> print(y.shape) torch.Size([16, 4, 10])
- class phenonn.EncoderTorch(*args: Any, **kwargs: Any)[source]
Bases:
Module
- class phenonn.CombinedModel(*args: Any, **kwargs: Any)[source]
Bases:
ModuleHybrid Transformer-based model for sequence prediction with auxiliary features.
This model combines: - A linear projection of input features into model space - A Transformer module for sequence-to-sequence processing - Additional concatenated features (PFT inputs) - A stack of Transformer encoder layers with causal masking - Final linear projection to output space
- Parameters:
input_dim (int, default=26) – Number of input features per timestep.
hidden_dim (int, default=1024) – Feedforward dimension inside Transformer encoder layers.
hidden_dim_trans (int, default=1024) – Feedforward dimension inside the built-in Transformer module.
output_dim (int, default=2) – Number of output features per timestep.
d_model (int, default=32) – Internal embedding dimension used throughout the model.
nr_blocks (int, default=3) – Number of stacked TransformerEncoderLayer blocks.
- lin1
Projects input features into model dimension (d_model).
- Type:
torch.nn.Linear
- trans
Transformer module applied to the projected input.
- Type:
torch.nn.Transformer
- lin2
Reduces Transformer output to a single feature.
- Type:
torch.nn.Linear
- lin3
Projects concatenated features into model dimension.
- Type:
torch.nn.Linear
- encoder
Stack of TransformerEncoderLayer blocks.
- Type:
torch.nn.ModuleList
- lin4
Final projection from model dimension to output space (2).
- Type:
torch.nn.Linear
- positional_encoder
Sinusoidal positional encoding module.
- Type:
Notes
The model uses a causal (lower-triangular) attention mask to prevent attending to future timesteps.
Input tensors are expected in shape: (batch_size, sequence_length, input_dim)
Internally, tensors are permuted to: (sequence_length, batch_size, d_model) for Transformer processing.
- __init__(input_dim=26, hidden_dim=1024, hidden_dim_trans=1024, output_dim=2, d_model=32, nr_blocks=3)[source]
- forward(x, return_stress=False)[source]
Forward pass of the model using full input sequence.
- Parameters:
x (torch.Tensor) – Input tensor of shape (batch_size, sequence_length, input_dim).
return_stress (bool, default=False) – If True, also returns intermediate representation after lin2.
- Returns:
- If return_stress=False:
Output tensor of shape (batch_size, sequence_length, 2)
- If return_stress=True:
Tuple (output, stress_tensor) where: - output: final predictions (B, T, 2) - stress_tensor: intermediate representation (B, T, 1)
- Return type:
torch.Tensor or tuple of torch.Tensor
- forward_from_stress(x, pft)[source]
Forward pass starting from intermediate stress representation.
This bypasses the initial Transformer and lin1/lin2 layers, and instead continues processing from a reduced representation combined with auxiliary PFT features.
- Parameters:
x (torch.Tensor) – Stress-like representation of shape (batch_size, sequence_length, 1).
pft (torch.Tensor) – Auxiliary features of shape (batch_size, sequence_length, 10).
- Returns:
Output tensor of shape (batch_size, sequence_length, 2).
- Return type:
torch.Tensor
- class phenonn.BiTransformer(*args: Any, **kwargs: Any)[source]
Bases:
ModuleBidirectional Transformer-style sequence model with auxiliary features (PFT).
This model combines: - A linear embedding layer for input features - A Transformer encoder-decoder block for global sequence mixing - A causal (autoregressive) TransformerEncoder stack - Concatenation of auxiliary PFT features - Final projection to output space
The architecture is designed for sequence-to-sequence prediction where past context is enforced via a causal attention mask.
- Parameters:
input_dim (int, default=26) – Number of input features per timestep.
feed_forward_trans (int, default=4) – Multiplier for Transformer feedforward dimension.
feed_forward_encoder (int, default=4) – Multiplier for encoder feedforward dimension.
output_dim (int, default=2) – Number of output features per timestep.
d_model (int, default=256) – Hidden representation size used throughout the model.
nr_blocks (int, default=3) – Number of TransformerEncoderLayer blocks.
dropout_trans (float, default=0.1) – Dropout rate used inside the Transformer module.
dropout_encoder (float, default=0.1) – Dropout rate used in encoder layers.
n_pft (int, default=1) – Number of trailing auxiliary features (PFT) appended to input.
- lin1
Projects input features into d_model space.
- Type:
torch.nn.Linear
- trans
Transformer encoder-decoder module for global sequence mixing.
- Type:
torch.nn.Transformer
- lin2
Reduces Transformer output to a single-channel representation.
- Type:
torch.nn.Linear
- lin3
Projects concatenated [stress, PFT] features into d_model space.
- Type:
torch.nn.Linear
- encoder
Stack of TransformerEncoderLayer blocks with causal masking.
- Type:
torch.nn.ModuleList
- lin4
Final projection to output_dim.
- Type:
torch.nn.Linear
- positional_encoder
Sinusoidal positional encoding module (defined but not used in forward).
- Type:
Notes
Input tensors are expected in shape: (batch_size, sequence_length, input_dim)
The last n_pft features are treated as auxiliary inputs and split off.
A causal (upper-triangular) mask is applied to prevent future information leakage in the encoder stack.
Internally, tensors are permuted to: (sequence_length, batch_size, d_model) for TransformerEncoder processing.
- __init__(input_dim=26, feed_forward_trans=4, feed_forward_encoder=4, output_dim=2, d_model=256, nr_blocks=3, dropout_trans=0.1, dropout_encoder=0.1, n_pft=1)[source]
- forward(x, return_stress=False)[source]
Forward pass of the BiTransformer model.
- Parameters:
x (torch.Tensor) – Input tensor of shape (batch_size, sequence_length, input_dim), where the last n_pft channels are auxiliary PFT features.
return_stress (bool, default=False) – If True, also returns intermediate representation after lin2.
- Returns:
- If return_stress=False:
Output tensor of shape (batch_size, sequence_length, output_dim)
- If return_stress=True:
Tuple (output, stress_tensor) where: - output: final predictions (B, T, output_dim) - stress_tensor: intermediate scalar representation (B, T, 1)
- Return type:
torch.Tensor or tuple of torch.Tensor
Data Module
PhenoNN Data Module
Provides dataset classes and data processing utilities for phenology prediction: - PhenoCamDataset: Per-site CSV format (original) - LAIDataset: Flat CSV format (features + targets) - Feature engineering: GDD, CDD, Botta onset features
- class phenonn.data.PhenoCamDataset(*args: Any, **kwargs: Any)[source]
Bases:
DatasetPyTorch dataset for LAI prediction.
Each sample is a 365-day sliding window of meteorological and site features, with the target being LAI on the final day of the window.
The feature tensor has shape (feature_channels, 365) where feature_channels = len(DYNAMIC_FEATURES) + len(CYCLIC_FEATURES) + len(STATIC_FEATURES) + n_pfts.
- Parameters:
site_files (list of str) – Paths to site CSV files (e.g. [‘DB_asuhighlands.csv’, …]).
norm_stats (dict) – Normalization statistics from compute_norm_stats().
seq_length (int) – Window length in days. Default 365.
target_col (str) – Target column name. Default ‘LAI’.
normalize_target (bool) – Whether to z-score the target. Default False.
pft_list (list of str, optional) – Ordered list of all PFT codes for one-hot encoding. If None, auto-discovered from site_files.
stride (int) – Step between consecutive windows. Default 1 (every day).
years (list of int, optional) – If provided, only use windows whose target day falls in these years. Use this to split “predict year by year”.
Examples
> stats = compute_norm_stats(train_files) > train_ds = PhenoCamDataset(train_files, stats, pft_list=[‘DB’, ‘EN’, ‘GR’]) > features, target = train_ds[0] > features.shape torch.Size([14, 365]) # 7 meteo + 2 cyclic + 2 static + 3 PFT > target.shape torch.Size([1])
- __init__(site_files: List[str], norm_stats: Dict[str, Dict[str, float]], seq_length: int = 365, target_col: str = 'LAI', normalize_target: bool = True, pft_list: List[str] | None = None, stride: int = 1, lai_norms=None, years: List[int] | None = None, n_target_days: int = 1, residual_csv: str | None = None, random_stride: int = 0, feature_mode: str = 'all', full_year: bool = False) None[source]
- class phenonn.data.LAIDataset(*args: Any, **kwargs: Any)[source]
Bases:
DatasetPyTorch dataset for LAI prediction using flat feature and target CSVs.
Each sample is one (site_id, target_year) pair. The feature window covers seq_length consecutive days ending on the last day of the target year. The target is the 36 LAI observations for that year (days 5, 15, 25 of every month).
Feature tensor shape : (n_features, seq_length) — 31 channels by default Target tensor shape : (1, 36)
- Parameters:
features_csv (str) – Path to flat daily features CSV.
target_csv (str) – Path to sparse LAI targets CSV.
norm_stats (dict) – Normalization stats from compute_norm_stats().
site_ids (list of str, optional) – Restrict to these site IDs. Default: all sites in features_csv.
seq_length (int) – Feature window length in days. Default 720 (≈ 2 years).
years (list of int, optional) – If provided, only include samples where the target year is in this list.
normalize_target (bool) – Z-score the LAI target. Default True.
lai_norms (dict, optional) – Per-site {site_id: {“lai_min”: float, “lai_max”: float}} for min-max normalization. Overrides normalize_target when site_id is present.
Examples
>>> stats = compute_norm_stats("features.csv", "targets.csv", train_ids) >>> ds = LAIDataset("features.csv", "targets.csv", stats, site_ids=train_ids) >>> feats, targets = ds[0] >>> feats.shape torch.Size([31, 720]) >>> targets.shape torch.Size([1, 36])
- phenonn.data.load_site(filepath: str) pandas.DataFrame[source]
Load and clean a single site CSV.
Sorts by (year, doy), adds cyclic day-of-year features, and forward-fills small meteo gaps.
- Parameters:
filepath (str) – Path to the CSV file.
- Returns:
Cleaned dataframe with all feature and target columns.
- Return type:
pd.DataFrame
- phenonn.data.extract_pft_and_site(filepath: str) Tuple[str, str][source]
Extract PFT code and site name from a filename like ‘DB_asuhighlands.csv’.
- phenonn.data.get_site_ids(csv_path: str) List[str][source]
Return sorted list of unique site_ids from a features or targets CSV.
- phenonn.data.load_lai_norms(norms_csv: str, site_files: List[str] | None = None) Dict[str, Dict[str, float]][source]
Load per-site LAI min, max (from external file). Enables inter-site normalization: lai_norm = (lai - min) / (max - min).
- phenonn.data.split_sites_by_fraction(site_files: List[str], val_fraction: float = 0.2, seed: int = 42) Tuple[List[str], List[str]][source]
Split site files into train and validation sets (leave-site-out).
- phenonn.data.split_sites_flat(site_ids: List[str], val_fraction: float = 0.2, seed: int = 42) Tuple[List[str], List[str]]
Split site_ids into (train, val) sets (leave-site-out).
- Return type:
(train_ids, val_ids)
- phenonn.data.add_derived_features(df: pandas.DataFrame) pandas.DataFrame[source]
Add GDD, CDD, and Botta onset features to a site dataframe.
Must be called AFTER sorting by (year, doy) and BEFORE normalization. All features reset to zero on January 1st of each year.
- Parameters:
df (pd.DataFrame) – Site data with columns: year, doy, tmin, tmax (at minimum).
- Returns:
Same dataframe with added columns:
gdd_0, gdd_5, gdd_10 : Growing Degree Days at 0/5/10°C thresholds
cdd : Chilling Degree Days (cold accumulation below 5°C)
ncd : Number of Chilling Days (count of days where Tmean < 5°C)
- botta_thresholdGDD threshold from Botta et al. (2000)
G_thres = 964 * exp(-0.0058 * NCD) - 12.8
- botta_forcingGDD_0 / G_thres (onset proximity indicator)
~0 in winter, approaches 1 at onset, >1 during growing season
- Return type:
pd.DataFrame
- class phenonn.data.BigLAIDataset(*args: Any, **kwargs: Any)[source]
Bases:
DatasetStreaming, per-epoch dataset for LAI prediction.
- Parameters:
features_dir (str) – Folder containing features_{year}.csv files.
target_dir (str) – Folder containing target_{year}.csv files.
years (list of int) – Target years for which (site, year) samples will be produced. For each Y in this list, the dataset also loads the previous year’s feature file (features_{Y-1}.csv) so the seq_length-day window is complete.
site_ids (list of str) – Sites to keep. Ids that do not appear in the relevant year CSVs are silently dropped — pass the full candidate list and let the loader filter.
seq_length (int) – Feature window length in days (default 720 ≈ 2 years).
normalize (bool) – Must be False for now. Reserved for a future opt-in normalization.
Notes
All required data is loaded into memory at construction time. With ~500 sites and ~3 years per epoch this stays in the few-hundred-MB range. The expectation is that main_big.py creates a fresh dataset every epoch.
- phenonn.data.generate_site_ids_from_range(row_range: Tuple[int, int], col_range: Tuple[int, int]) List[str][source]
Build every pix_{row:04d}_{col:05d} id in the given inclusive grid range.
The caller can pass this list directly to BigLAIDataset; ids that do not appear in the CSV files are silently dropped at load time, so the range can be a superset of the actually-extracted sites.
- phenonn.data.get_pixel_index(csv_path: str, verbose: bool = True) Tuple[numpy.ndarray, numpy.ndarray, bytes][source]
Return (site_ids, offsets, header), building & caching the index on first call. Subsequent calls hit the on-disk cache instantly.
LAI Prediction Dataset.
PyTorch dataset utilities for predicting Leaf Area Index (LAI) from daily meteorological, site, and vegetation characteristics derived from PhenoCam observations.
The module provides functionality to:
Load and preprocess site-level time series data.
Engineer derived phenological predictors such as growing degree days (GDD), chilling degree days (CDD), forcing metrics, and related indices.
Compute and apply feature normalization statistics.
Optionally normalize LAI targets globally or using site-specific minimum/maximum values.
Construct sliding-window datasets for supervised learning.
Support multiple feature configurations, including meteorological-only, site-only, or combined models.
Generate datasets for single-day prediction, multi-day sequence prediction, full-year forecasting, or residual learning workflows.
Create train/validation splits by site and/or year.
Dataset Structure
Input samples consist of a fixed-length sequence of daily observations ending on a target day.
Typical configuration:
- Input:
(n_features, seq_length)whereseq_lengthis typically 365 days.
- Output:
(1,)LAI value on the final day of the sequence.
Alternative modes support:
- Multi-day targets:
(1, n_target_days)
- Full-year prediction:
(1, 365)
Feature Groups
- Dynamic features
Daily meteorological variables and derived phenological metrics, including temperature, precipitation, radiation, snow water equivalent, vapor pressure deficit, and growing degree day indices.
- Static features
Site-level attributes such as climatology, geographic coordinates, soil properties, elevation, and terrain characteristics.
- Cyclic features
Sine/cosine encodings of day-of-year.
- PFT features
One-hot encoding of plant functional type (PFT).
Normalization
Feature normalization statistics are computed from the training sites. Dynamic variables can optionally be log-transformed prior to computing means and standard deviations. Static variables are normalized using cross-site statistics.
Targets may be normalized either:
Globally using dataset-wide LAI mean and standard deviation.
Per site using externally supplied LAI minimum and maximum values.
Main Components
- compute_norm_stats
Compute feature normalization statistics from training sites.
- load_norm_stats
Load previously computed normalization statistics.
- load_site
Load and preprocess a site-level CSV file.
- PhenoCamDataset
PyTorch
Datasetimplementation providing sliding-window LAI prediction samples.- split_sites_by_fraction
Create leave-site-out train/validation splits.
- split_by_year
Create train/validation datasets using year-based target splits.
Notes
This implementation is adapted from the RTnn data preprocessing workflow for daily PhenoCam time series and is designed for ecological forecasting and vegetation phenology modeling.
- phenonn.data.dataset.extract_pft_and_site(filepath: str) Tuple[str, str][source]
Extract PFT code and site name from a filename like ‘DB_asuhighlands.csv’.
- phenonn.data.dataset.load_site(filepath: str) pandas.DataFrame[source]
Load and clean a single site CSV.
Sorts by (year, doy), adds cyclic day-of-year features, and forward-fills small meteo gaps.
- Parameters:
filepath (str) – Path to the CSV file.
- Returns:
Cleaned dataframe with all feature and target columns.
- Return type:
pd.DataFrame
- phenonn.data.dataset.load_lai_norms(norms_csv: str, site_files: List[str] | None = None) Dict[str, Dict[str, float]][source]
Load per-site LAI min, max (from external file). Enables inter-site normalization: lai_norm = (lai - min) / (max - min).
- phenonn.data.dataset.compute_norm_stats(site_files: List[str], save_path: str | None = None) Dict[str, Dict[str, float]][source]
Compute per-feature mean and std across all training sites.
For features in LOG_TRANSFORM_FEATURES, stats are computed on log1p(x). For static features (mat, map), stats are computed per-site (one value per site) to avoid inflating variance with repeated rows.
- phenonn.data.dataset.load_norm_stats(path: str) Dict[str, Dict[str, float]][source]
Load normalization stats from a JSON file.
- class phenonn.data.dataset.PhenoCamDataset(*args: Any, **kwargs: Any)[source]
Bases:
DatasetPyTorch dataset for LAI prediction.
Each sample is a 365-day sliding window of meteorological and site features, with the target being LAI on the final day of the window.
The feature tensor has shape (feature_channels, 365) where feature_channels = len(DYNAMIC_FEATURES) + len(CYCLIC_FEATURES) + len(STATIC_FEATURES) + n_pfts.
- Parameters:
site_files (list of str) – Paths to site CSV files (e.g. [‘DB_asuhighlands.csv’, …]).
norm_stats (dict) – Normalization statistics from compute_norm_stats().
seq_length (int) – Window length in days. Default 365.
target_col (str) – Target column name. Default ‘LAI’.
normalize_target (bool) – Whether to z-score the target. Default False.
pft_list (list of str, optional) – Ordered list of all PFT codes for one-hot encoding. If None, auto-discovered from site_files.
stride (int) – Step between consecutive windows. Default 1 (every day).
years (list of int, optional) – If provided, only use windows whose target day falls in these years. Use this to split “predict year by year”.
Examples
> stats = compute_norm_stats(train_files) > train_ds = PhenoCamDataset(train_files, stats, pft_list=[‘DB’, ‘EN’, ‘GR’]) > features, target = train_ds[0] > features.shape torch.Size([14, 365]) # 7 meteo + 2 cyclic + 2 static + 3 PFT > target.shape torch.Size([1])
- __getitem__(index: int) Tuple[torch.Tensor, torch.Tensor][source]
Get a single sample.
- Parameters:
index (int) – Sample index.
- Returns:
features (torch.Tensor) – Feature tensor of shape (feature_channels, seq_length)
target (torch.Tensor) – Target tensor. Shape is (1,) if n_target_days=1, or (1, n_target_days) if n_target_days>1
- phenonn.data.dataset.split_sites_by_fraction(site_files: List[str], val_fraction: float = 0.2, seed: int = 42) Tuple[List[str], List[str]][source]
Split site files into train and validation sets (leave-site-out).
- phenonn.data.dataset.split_by_year(site_files: List[str], norm_stats: Dict, train_years: List[int], val_years: List[int], pft_list: List[str], **kwargs) Tuple[PhenoCamDataset, PhenoCamDataset][source]
Create train and validation datasets split by target year.
All sites are used for both sets, but training windows target train_years and validation windows target val_years.
- phenonn.data.dataset.split_by_sites_years(site_files: List[str], norm_stats: Dict, train_years: List[int], val_years: List[int], pft_list: List[str], val_fraction: float = 0.1, seed: int = 42, **kwargs) Tuple[PhenoCamDataset, PhenoCamDataset][source]
Create train and validation datasets split by both sites and years.
Validation set is composed of all years for val_fraction of sites (randomly selected) and of the years in val_years for the remaining sites. The training set is composed of the remaining years for the remaining sites.
- Parameters:
LAI Prediction Dataset.
This dataset reads from two flat CSV files that replace the per-site CSVs
used in dataset.py.
Files
- features.csv
One row per
(site_id, date)with 365 records per site-year.Columns:
site_id date (YYYYMMDD) year month day pft1_frac ... pft15_frac tmin tmax daylength prcp srad vpd swe
- targets.csv
One row per
(site_id, date)with 36 observations per site-year.Observation days are the 5th, 15th, and 25th of each month.
Columns:
site_id date year month day LAI_raw LAI
Notes
Each sample corresponds to a single (site_id, year) pair.
The returned tensors have the following shapes:
features:(n_features, seq_length)Sequence of trailing daily feature values.
targets:(1, 36)LAI observations for the corresponding year.
- phenonn.data.dataset_flat.get_site_ids(csv_path: str) List[str][source]
Return sorted list of unique site_ids from a features or targets CSV.
- phenonn.data.dataset_flat.split_sites_by_fraction(site_ids: List[str], val_fraction: float = 0.2, seed: int = 42) Tuple[List[str], List[str]][source]
Split site_ids into (train, val) sets (leave-site-out).
- Return type:
(train_ids, val_ids)
- phenonn.data.dataset_flat.compute_norm_stats(features_csv: str, target_csv: str, train_site_ids: List[str], save_path: str | None = None) Dict[str, Dict[str, float]][source]
Compute per-feature mean and std from training sites only.
Features in LOG_TRANSFORM_FEATURES are log1p-transformed before computing stats. PFT fraction columns are included.
- Parameters:
- Returns:
{feature_name: {“mean”: float, “std”: float}} for all 31 features + “LAI”.
- Return type:
- phenonn.data.dataset_flat.load_norm_stats(path: str) Dict[str, Dict[str, float]][source]
Load normalization stats from a JSON file.
- class phenonn.data.dataset_flat.LAIDataset(*args: Any, **kwargs: Any)[source]
Bases:
DatasetPyTorch dataset for LAI prediction using flat feature and target CSVs.
Each sample is one (site_id, target_year) pair. The feature window covers seq_length consecutive days ending on the last day of the target year. The target is the 36 LAI observations for that year (days 5, 15, 25 of every month).
Feature tensor shape : (n_features, seq_length) — 31 channels by default Target tensor shape : (1, 36)
- Parameters:
features_csv (str) – Path to flat daily features CSV.
target_csv (str) – Path to sparse LAI targets CSV.
norm_stats (dict) – Normalization stats from compute_norm_stats().
site_ids (list of str, optional) – Restrict to these site IDs. Default: all sites in features_csv.
seq_length (int) – Feature window length in days. Default 720 (≈ 2 years).
years (list of int, optional) – If provided, only include samples where the target year is in this list.
normalize_target (bool) – Z-score the LAI target. Default True.
lai_norms (dict, optional) – Per-site {site_id: {“lai_min”: float, “lai_max”: float}} for min-max normalization. Overrides normalize_target when site_id is present.
Examples
>>> stats = compute_norm_stats("features.csv", "targets.csv", train_ids) >>> ds = LAIDataset("features.csv", "targets.csv", stats, site_ids=train_ids) >>> feats, targets = ds[0] >>> feats.shape torch.Size([31, 720]) >>> targets.shape torch.Size([1, 36])
Feature engineering utilities for phenological modeling.
This module computes ecologically meaningful predictors derived from daily meteorological observations. The generated features are designed to capture temperature-driven vegetation dynamics, including heat accumulation, winter chilling, and spring onset forcing.
Derived variables are computed independently for each calendar year and are intended to be added to site-level meteorological records after temporal sorting and before any normalization or scaling.
Implemented Features
- Growing Degree Days (GDD)
Cumulative heat accumulation above one or more base temperature thresholds. Multiple thresholds are provided (0, 5, and 10 °C) to allow downstream models to learn the most informative representation of thermal forcing.
- Chilling Degree Days (CDD)
Cumulative cold exposure below a chilling threshold of 5 °C. This metric approximates winter dormancy release processes in temperate ecosystems.
- Number of Chilling Days (NCD)
Running count of days with mean temperature below 5 °C. Unlike CDD, this measure captures the frequency rather than the magnitude of cold exposure.
- Botta Onset Features
Phenological forcing metrics derived from the formulation proposed by Botta et al. (2000). The model assumes that accumulated chilling lowers the growing degree day requirement for spring onset.
- Threshold:
G_thres = C1 * exp(C2 * NCD) + C3
- Forcing Ratio:
GDD / G_thres
Values approaching 1 indicate proximity to the predicted onset of vegetation activity.
Notes
Input data must be sorted by
(year, doy)before feature computation.All cumulative variables reset on January 1 of each year.
Missing temperatures are forward/backward filled before accumulation to ensure stable cumulative calculations.
Feature generation is deterministic and does not modify the input dataframe in place.
References
Botta, A., Viovy, N., Ciais, P., Friedlingstein, P., & Monfray, P. (2000). A global prognostic scheme of leaf onset using satellite data. Global Change Biology, 6(7), 709–725.
- phenonn.data.feature_engineering.add_derived_features(df: pandas.DataFrame) pandas.DataFrame[source]
Add GDD, CDD, and Botta onset features to a site dataframe.
Must be called AFTER sorting by (year, doy) and BEFORE normalization. All features reset to zero on January 1st of each year.
- Parameters:
df (pd.DataFrame) – Site data with columns: year, doy, tmin, tmax (at minimum).
- Returns:
Same dataframe with added columns:
gdd_0, gdd_5, gdd_10 : Growing Degree Days at 0/5/10°C thresholds
cdd : Chilling Degree Days (cold accumulation below 5°C)
ncd : Number of Chilling Days (count of days where Tmean < 5°C)
- botta_thresholdGDD threshold from Botta et al. (2000)
G_thres = 964 * exp(-0.0058 * NCD) - 12.8
- botta_forcingGDD_0 / G_thres (onset proximity indicator)
~0 in winter, approaches 1 at onset, >1 during growing season
- Return type:
pd.DataFrame
Models Module
Model architectures for RTnn.
- class phenonn.models.RNN_LSTM(*args: Any, **kwargs: Any)[source]
Bases:
BaseRNNLSTM-based bidirectional RNN model.
This class inherits from BaseRNN and configures it to use LSTM cells.
- Parameters:
Examples
>>> model = RNN_LSTM( ... feature_channel=6, ... output_channel=4, ... hidden_size=128, ... num_layers=3 ... ) >>> x = torch.randn(16, 6, 10) >>> y = model(x) >>> print(y.shape) torch.Size([16, 4, 10])
- class phenonn.models.RNN_GRU(*args: Any, **kwargs: Any)[source]
Bases:
BaseRNNGRU-based bidirectional RNN model.
This class inherits from BaseRNN and configures it to use GRU cells.
- Parameters:
Examples
>>> model = RNN_GRU( ... feature_channel=6, ... output_channel=4, ... hidden_size=128, ... num_layers=3 ... ) >>> x = torch.randn(16, 6, 10) >>> y = model(x) >>> print(y.shape) torch.Size([16, 4, 10])
- class phenonn.models.FCN(*args: Any, **kwargs: Any)[source]
Bases:
ModuleFully Connected Network with configurable depth and width.
This model flattens the input sequence and processes it through a series of fully connected layers. It can optionally expand the sequence length using a linear transformation.
- Parameters:
feature_channel (int) – Number of input features per time step.
output_channel (int) – Number of output channels.
num_layers (int) – Number of hidden layers.
hidden_size (int) – Size of hidden layers.
seq_length (int, optional) – Length of the input sequence. Default is 55.
dim_expand (int, optional) – Number of time steps to expand the output sequence by. Default is 0 (no expansion).
Stack of hidden layers.
- Type:
nn.Sequential
- output_layer
Final output layer.
- Type:
nn.Linear
- dim_change
Optional layer for sequence length expansion.
- Type:
nn.Linear or None
Examples
>>> model = FCN( ... feature_channel=6, ... output_channel=4, ... num_layers=3, ... hidden_size=196, ... seq_length=10 ... ) >>> x = torch.randn(32, 6, 10) >>> y = model(x) >>> y.shape torch.Size([32, 4, 10])
- __init__(feature_channel: int, output_channel: int, num_layers: int, hidden_size: int, seq_length: int = 55, dim_expand: int = 0) None[source]
Initialize the FCN model.
- Parameters:
feature_channel (int) – Number of input features.
output_channel (int) – Number of output channels.
num_layers (int) – Number of hidden layers.
hidden_size (int) – Size of hidden layers.
seq_length (int, optional) – Length of the input sequence. Default is 55.
dim_expand (int, optional) – Number of time steps to expand the output sequence by. Default is 0 (no expansion).
- Raises:
ValueError – If num_layers is less than 1.
- forward(x: torch.Tensor) torch.Tensor[source]
Forward pass through the FCN.
- Parameters:
x (torch.Tensor) – Input tensor of shape (batch_size, feature_channel, seq_length).
- Returns:
Output tensor of shape (batch_size, output_channel, seq_length + dim_expand) if dim_expand > 0, otherwise (batch_size, output_channel, seq_length).
- Return type:
torch.Tensor
Notes
The forward pass: 1. Flattens the input to (batch_size, feature_channel * seq_length) 2. Passes through FCBlocks 3. Projects to output dimensions 4. Reshapes to (batch_size, output_channel, seq_length) 5. Optionally expands sequence length
- class phenonn.models.EncoderTorch(*args: Any, **kwargs: Any)[source]
Bases:
Module
- class phenonn.models.CombinedModel(*args: Any, **kwargs: Any)[source]
Bases:
ModuleHybrid Transformer-based model for sequence prediction with auxiliary features.
This model combines: - A linear projection of input features into model space - A Transformer module for sequence-to-sequence processing - Additional concatenated features (PFT inputs) - A stack of Transformer encoder layers with causal masking - Final linear projection to output space
- Parameters:
input_dim (int, default=26) – Number of input features per timestep.
hidden_dim (int, default=1024) – Feedforward dimension inside Transformer encoder layers.
hidden_dim_trans (int, default=1024) – Feedforward dimension inside the built-in Transformer module.
output_dim (int, default=2) – Number of output features per timestep.
d_model (int, default=32) – Internal embedding dimension used throughout the model.
nr_blocks (int, default=3) – Number of stacked TransformerEncoderLayer blocks.
- lin1
Projects input features into model dimension (d_model).
- Type:
torch.nn.Linear
- trans
Transformer module applied to the projected input.
- Type:
torch.nn.Transformer
- lin2
Reduces Transformer output to a single feature.
- Type:
torch.nn.Linear
- lin3
Projects concatenated features into model dimension.
- Type:
torch.nn.Linear
- encoder
Stack of TransformerEncoderLayer blocks.
- Type:
torch.nn.ModuleList
- lin4
Final projection from model dimension to output space (2).
- Type:
torch.nn.Linear
- positional_encoder
Sinusoidal positional encoding module.
- Type:
Notes
The model uses a causal (lower-triangular) attention mask to prevent attending to future timesteps.
Input tensors are expected in shape: (batch_size, sequence_length, input_dim)
Internally, tensors are permuted to: (sequence_length, batch_size, d_model) for Transformer processing.
- __init__(input_dim=26, hidden_dim=1024, hidden_dim_trans=1024, output_dim=2, d_model=32, nr_blocks=3)[source]
- forward(x, return_stress=False)[source]
Forward pass of the model using full input sequence.
- Parameters:
x (torch.Tensor) – Input tensor of shape (batch_size, sequence_length, input_dim).
return_stress (bool, default=False) – If True, also returns intermediate representation after lin2.
- Returns:
- If return_stress=False:
Output tensor of shape (batch_size, sequence_length, 2)
- If return_stress=True:
Tuple (output, stress_tensor) where: - output: final predictions (B, T, 2) - stress_tensor: intermediate representation (B, T, 1)
- Return type:
torch.Tensor or tuple of torch.Tensor
- forward_from_stress(x, pft)[source]
Forward pass starting from intermediate stress representation.
This bypasses the initial Transformer and lin1/lin2 layers, and instead continues processing from a reduced representation combined with auxiliary PFT features.
- Parameters:
x (torch.Tensor) – Stress-like representation of shape (batch_size, sequence_length, 1).
pft (torch.Tensor) – Auxiliary features of shape (batch_size, sequence_length, 10).
- Returns:
Output tensor of shape (batch_size, sequence_length, 2).
- Return type:
torch.Tensor
- class phenonn.models.BiTransformer(*args: Any, **kwargs: Any)[source]
Bases:
ModuleBidirectional Transformer-style sequence model with auxiliary features (PFT).
This model combines: - A linear embedding layer for input features - A Transformer encoder-decoder block for global sequence mixing - A causal (autoregressive) TransformerEncoder stack - Concatenation of auxiliary PFT features - Final projection to output space
The architecture is designed for sequence-to-sequence prediction where past context is enforced via a causal attention mask.
- Parameters:
input_dim (int, default=26) – Number of input features per timestep.
feed_forward_trans (int, default=4) – Multiplier for Transformer feedforward dimension.
feed_forward_encoder (int, default=4) – Multiplier for encoder feedforward dimension.
output_dim (int, default=2) – Number of output features per timestep.
d_model (int, default=256) – Hidden representation size used throughout the model.
nr_blocks (int, default=3) – Number of TransformerEncoderLayer blocks.
dropout_trans (float, default=0.1) – Dropout rate used inside the Transformer module.
dropout_encoder (float, default=0.1) – Dropout rate used in encoder layers.
n_pft (int, default=1) – Number of trailing auxiliary features (PFT) appended to input.
- lin1
Projects input features into d_model space.
- Type:
torch.nn.Linear
- trans
Transformer encoder-decoder module for global sequence mixing.
- Type:
torch.nn.Transformer
- lin2
Reduces Transformer output to a single-channel representation.
- Type:
torch.nn.Linear
- lin3
Projects concatenated [stress, PFT] features into d_model space.
- Type:
torch.nn.Linear
- encoder
Stack of TransformerEncoderLayer blocks with causal masking.
- Type:
torch.nn.ModuleList
- lin4
Final projection to output_dim.
- Type:
torch.nn.Linear
- positional_encoder
Sinusoidal positional encoding module (defined but not used in forward).
- Type:
Notes
Input tensors are expected in shape: (batch_size, sequence_length, input_dim)
The last n_pft features are treated as auxiliary inputs and split off.
A causal (upper-triangular) mask is applied to prevent future information leakage in the encoder stack.
Internally, tensors are permuted to: (sequence_length, batch_size, d_model) for TransformerEncoder processing.
- __init__(input_dim=26, feed_forward_trans=4, feed_forward_encoder=4, output_dim=2, d_model=256, nr_blocks=3, dropout_trans=0.1, dropout_encoder=0.1, n_pft=1)[source]
- forward(x, return_stress=False)[source]
Forward pass of the BiTransformer model.
- Parameters:
x (torch.Tensor) – Input tensor of shape (batch_size, sequence_length, input_dim), where the last n_pft channels are auxiliary PFT features.
return_stress (bool, default=False) – If True, also returns intermediate representation after lin2.
- Returns:
- If return_stress=False:
Output tensor of shape (batch_size, sequence_length, output_dim)
- If return_stress=True:
Tuple (output, stress_tensor) where: - output: final predictions (B, T, output_dim) - stress_tensor: intermediate scalar representation (B, T, 1)
- Return type:
torch.Tensor or tuple of torch.Tensor
- class phenonn.models.LinearBaseline(*args: Any, **kwargs: Any)[source]
Bases:
ModuleFull-window linear regression baseline.
Flattens the entire (feature_channel × seq_length) input into one vector, applies a single Linear layer to produce a scalar prediction.
- This is mathematically equivalent to:
gcc_pred = w @ flatten(input) + b
where w has C×L weights. It can learn things like “temperature on day 300 matters more than temperature on day 50” because each (channel, timestep) pair gets its own weight.
- Parameters:
Examples
>>> model = LinearBaseline(feature_channel=16, seq_length=365) >>> x = torch.randn(32, 16, 365) >>> y = model(x) >>> y.shape torch.Size([32, 1])
- forward(x: torch.Tensor) torch.Tensor[source]
- Parameters:
x ((batch, feature_channel, seq_length))
- Return type:
(batch, 1)
- class phenonn.models.PerDayLinearBaseline(*args: Any, **kwargs: Any)[source]
Bases:
ModulePer-day linear regression baseline (no temporal context).
Applies the same Linear(C, 1) to every timestep independently, then returns the prediction for the last day. This tests whether today’s feature values alone (without any history) can predict today’s LAI.
If this baseline scores well, it means the temporal context from the 365-day window isn’t adding much — the model is mostly using the current day’s meteorology.
- Parameters:
feature_channel (int) – Number of input feature channels.
Examples
>>> model = PerDayLinearBaseline(feature_channel=16) >>> x = torch.randn(32, 16, 365) >>> y = model(x) >>> y.shape torch.Size([32, 1])
- forward(x: torch.Tensor) torch.Tensor[source]
- Parameters:
x ((batch, feature_channel, seq_length))
- Return type:
(batch, 1)
Bidirectional recurrent neural network models for sequence modeling.
This module provides implementations of bidirectional recurrent neural networks (RNNs) using Long Short-Term Memory (LSTM) and Gated Recurrent Unit (GRU) cells. These models are designed for sequence-based data, such as time series or vertically structured physical profiles.
The module includes:
BaseRNN: A flexible base class supporting both LSTM and GRU architectures with bidirectional processing.
RNN_LSTM: A specialized LSTM-based model built on BaseRNN.
RNN_GRU: A specialized GRU-based model built on BaseRNN.
Features
Bidirectional sequence processing for improved context awareness
Support for stacked recurrent layers
Unified interface for LSTM and GRU architectures
Automatic hidden state initialization
Final 1D convolution layer for channel-wise output projection
Compatible with batched inputs and GPU acceleration
Notes
Inputs are expected in the shape (batch_size, feature_channel, seq_length).
Internally, inputs are permuted to (batch_size, seq_length, feature_channel) to match PyTorch RNN requirements.
Bidirectional RNNs double the hidden state size, which is handled automatically in the final projection layer.
Hidden states are initialized to zeros at each forward pass.
The final Conv1d layer maps hidden representations to the desired output channels while preserving sequence length.
Dependencies
torch
torch.nn
typing
Examples
Using LSTM-based model:
>>> model = RNN_LSTM(
... feature_channel=6,
... output_channel=4,
... hidden_size=128,
... num_layers=3
... )
>>> x = torch.randn(16, 6, 10)
>>> y = model(x)
Using GRU-based model:
>>> model = RNN_GRU(
... feature_channel=6,
... output_channel=4,
... hidden_size=128,
... num_layers=3
... )
>>> x = torch.randn(16, 6, 10)
>>> y = model(x)
Using BaseRNN directly:
>>> model = BaseRNN(
... feature_channel=6,
... output_channel=4,
... hidden_size=64,
... num_layers=2,
... rnn_type="lstm"
... )
- class phenonn.models.rnn.BaseRNN(*args: Any, **kwargs: Any)[source]
Bases:
ModuleBase class for bidirectional RNN modules (LSTM/GRU).
This class provides a common interface for both LSTM and GRU models with bidirectional processing and a final 1D convolutional layer to map the hidden states to the desired output channels.
- Parameters:
feature_channel (int) – Number of input features per time step.
output_channel (int) – Number of output channels (target variables).
hidden_size (int) – Number of hidden units in the RNN layers.
num_layers (int) – Number of stacked RNN layers.
rnn_type (str) – Type of RNN cell, either ‘lstm’ or ‘gru’.
- rnn
The bidirectional RNN layer.
- Type:
nn.LSTM or nn.GRU
- final
Final 1D convolution to project hidden states to output channels.
- Type:
nn.Conv1d
Number of hidden units.
- Type:
Examples
>>> model = BaseRNN( ... feature_channel=6, ... output_channel=4, ... hidden_size=64, ... num_layers=2, ... rnn_type='lstm' ... ) >>> x = torch.randn(32, 6, 10) # (batch, features, sequence) >>> y = model(x) >>> y.shape torch.Size([32, 4, 10])
- __init__(feature_channel: int, output_channel: int, hidden_size: int, num_layers: int, rnn_type: str) None[source]
Initialize the BaseRNN module.
Initialize the hidden state for the RNN.
- Parameters:
batch_size (int) – Batch size for the input.
device (torch.device) – Device to create the hidden state on.
- Returns:
For GRU: returns hidden state tensor of shape (2 * num_layers, batch_size, hidden_size) For LSTM: returns tuple (hidden, cell) both of same shape.
- Return type:
torch.Tensor or tuple of torch.Tensor
- forward(x: torch.Tensor) torch.Tensor[source]
Forward pass through the bidirectional RNN.
- Parameters:
x (torch.Tensor) – Input tensor of shape (batch_size, feature_channel, seq_length).
- Returns:
Output tensor of shape (batch_size, output_channel, seq_length).
- Return type:
torch.Tensor
Notes
The input is permuted to (batch_size, seq_length, feature_channel) for the RNN, then the output is permuted back for the convolution.
- class phenonn.models.rnn.RNN_LSTM(*args: Any, **kwargs: Any)[source]
Bases:
BaseRNNLSTM-based bidirectional RNN model.
This class inherits from BaseRNN and configures it to use LSTM cells.
- Parameters:
Examples
>>> model = RNN_LSTM( ... feature_channel=6, ... output_channel=4, ... hidden_size=128, ... num_layers=3 ... ) >>> x = torch.randn(16, 6, 10) >>> y = model(x) >>> print(y.shape) torch.Size([16, 4, 10])
- class phenonn.models.rnn.RNN_GRU(*args: Any, **kwargs: Any)[source]
Bases:
BaseRNNGRU-based bidirectional RNN model.
This class inherits from BaseRNN and configures it to use GRU cells.
- Parameters:
Examples
>>> model = RNN_GRU( ... feature_channel=6, ... output_channel=4, ... hidden_size=128, ... num_layers=3 ... ) >>> x = torch.randn(16, 6, 10) >>> y = model(x) >>> print(y.shape) torch.Size([16, 4, 10])
Transformer-based encoder model for sequence modeling.
This module implements a Transformer encoder architecture using PyTorch’s
native nn.TransformerEncoder components. It is designed for processing
structured sequence data, such as time series or vertical profiles, where
contextual relationships across positions are important.
The model projects input features into an embedding space, adds learnable positional encodings, and processes the sequence through stacked self-attention layers before projecting to the desired output channels.
Features
Learnable input projection to embedding space
Learnable positional embeddings for sequence order awareness
Multi-head self-attention via Transformer encoder layers
Configurable depth, attention heads, and feedforward expansion
Dropout for regularization
Final 1D convolution for channel-wise output projection
Support for attention masks and padding masks
Notes
Inputs are expected in the shape (batch_size, feature_channel, seq_length).
Internally, inputs are permuted to (batch_size, seq_length, feature_channel) to match Transformer expectations.
Positional embeddings are added to the projected input features.
The
maskargument is used for attention masking (e.g., causal masking).The
src_key_padding_maskis used to ignore padded positions in sequences.The final output preserves the sequence length and maps embeddings to
output_channeldimensions.
Dependencies
torch
torch.nn
typing
Examples
Basic usage:
>>> model = EncoderTorch(
... feature_channel=6,
... output_channel=4,
... embed_size=128,
... num_layers=3,
... heads=4,
... forward_expansion=4,
... seq_length=10,
... dropout=0.1
... )
>>> x = torch.randn(32, 6, 10)
>>> y = model(x)
>>> y.shape
torch.Size([32, 4, 10])
Using attention masks:
>>> mask = torch.triu(torch.ones(10, 10), diagonal=1).bool()
>>> y = model(x, mask=mask)
- class phenonn.models.transformer.EncoderTorch(*args: Any, **kwargs: Any)[source]
Bases:
Module
Neural network architectures for phenological and vegetation dynamics modeling.
This module contains a collection of recurrent, transformer-based, and feed-forward neural network models originally developed for vegetation greenness prediction from meteorological and environmental forcing data. The architectures range from simple baselines to multi-stage transformer models that explicitly separate environmental stress estimation from phenological state prediction.
The implementations are adapted from work by Christian Reimers and collaborators at the Max Planck Institute for Biogeochemistry and are used within the PhenoCam LAI modeling framework.
Implemented Models
- CombinedModel
Two-stage architecture that first estimates an intermediate environmental stress signal using a transformer module and then combines this signal with plant functional type (PFT) information before phenological prediction.
- BiTransformer
Improved bidirectional transformer architecture that combines environmental stress estimation with causal temporal encoding and configurable plant functional type inputs. This model serves as the primary transformer implementation for vegetation prediction tasks.
Supporting Components
- PositionalEncoding
Sinusoidal positional encoding module following the formulation introduced in “Attention Is All You Need” (Vaswani et al., 2017). Provides temporal position information to transformer-based models.
Model Inputs
Most models expect input tensors of shape:
(batch_size, sequence_length, n_features)
where each timestep contains meteorological, environmental, and optionally plant functional type (PFT) information.
Model Outputs
Models generally return predictions of shape:
(batch_size, sequence_length, output_dim)
where output_dim typically represents one or more vegetation
state variables such as greenness, LAI, or intermediate stress
indicators.
Notes
Several architectures support a
return_stressmode that exposes intermediate latent stress representations used internally by the model.Transformer-based models employ causal attention masks to prevent future information leakage during sequence prediction.
Plant Functional Type (PFT) variables are assumed to occupy the final feature channels of the input tensor when required.
Within the PhenoCam LAI workflow, wrapper modules may permute tensor dimensions to match the project’s standard convention:
(batch_size, feature_channels, sequence_length)
while the original models operate on:
(batch_size, sequence_length, feature_channels)
References
Original vegetation prediction architectures developed at the Max Planck Institute for Biogeochemistry.
- class phenonn.models.transformerbis.PositionalEncoding(*args: Any, **kwargs: Any)[source]
Bases:
ModuleSinusoidal positional encoding module.
Adds fixed positional encodings to token embeddings as described in the Transformer architecture. The positional encodings are computed using sine and cosine functions of different frequencies and stored as a non-trainable buffer.
- Parameters:
- dropout
Dropout layer applied to the sum of token embeddings and positional encodings.
- Type:
torch.nn.Dropout
- pos_encoding
Tensor of shape (max_len, 1, dim_model) containing the precomputed positional encodings.
- Type:
torch.Tensor
Notes
For position
posand embedding dimensioni:Even dimensions:
PE(pos, 2i) = sin(pos * scale_i)Odd dimensions:
PE(pos, 2i + 1) = cos(pos * scale_i)
where
scale_i = 10000^(2i / dim_model)Examples
>>> pe = PositionalEncoding(dim_model=512, dropout_p=0.1, max_len=5000) >>> x = torch.randn(20, 32, 512) >>> y = pe(x) >>> y.shape torch.Size([20, 32, 512])
- forward(token_embeding: torch.tensor) torch.tensor[source]
Add positional encodings to token embeddings.
- Parameters:
token_embeding (torch.Tensor) – Input embeddings of shape (sequence_length, batch_size, dim_model).
- Returns:
Embeddings with positional encodings added and dropout applied. Shape is identical to the input: (sequence_length, batch_size, dim_model).
- Return type:
torch.Tensor
- class phenonn.models.transformerbis.CombinedModel(*args: Any, **kwargs: Any)[source]
Bases:
ModuleHybrid Transformer-based model for sequence prediction with auxiliary features.
This model combines: - A linear projection of input features into model space - A Transformer module for sequence-to-sequence processing - Additional concatenated features (PFT inputs) - A stack of Transformer encoder layers with causal masking - Final linear projection to output space
- Parameters:
input_dim (int, default=26) – Number of input features per timestep.
hidden_dim (int, default=1024) – Feedforward dimension inside Transformer encoder layers.
hidden_dim_trans (int, default=1024) – Feedforward dimension inside the built-in Transformer module.
output_dim (int, default=2) – Number of output features per timestep.
d_model (int, default=32) – Internal embedding dimension used throughout the model.
nr_blocks (int, default=3) – Number of stacked TransformerEncoderLayer blocks.
- lin1
Projects input features into model dimension (d_model).
- Type:
torch.nn.Linear
- trans
Transformer module applied to the projected input.
- Type:
torch.nn.Transformer
- lin2
Reduces Transformer output to a single feature.
- Type:
torch.nn.Linear
- lin3
Projects concatenated features into model dimension.
- Type:
torch.nn.Linear
- encoder
Stack of TransformerEncoderLayer blocks.
- Type:
torch.nn.ModuleList
- lin4
Final projection from model dimension to output space (2).
- Type:
torch.nn.Linear
- positional_encoder
Sinusoidal positional encoding module.
- Type:
Notes
The model uses a causal (lower-triangular) attention mask to prevent attending to future timesteps.
Input tensors are expected in shape: (batch_size, sequence_length, input_dim)
Internally, tensors are permuted to: (sequence_length, batch_size, d_model) for Transformer processing.
- __init__(input_dim=26, hidden_dim=1024, hidden_dim_trans=1024, output_dim=2, d_model=32, nr_blocks=3)[source]
- forward(x, return_stress=False)[source]
Forward pass of the model using full input sequence.
- Parameters:
x (torch.Tensor) – Input tensor of shape (batch_size, sequence_length, input_dim).
return_stress (bool, default=False) – If True, also returns intermediate representation after lin2.
- Returns:
- If return_stress=False:
Output tensor of shape (batch_size, sequence_length, 2)
- If return_stress=True:
Tuple (output, stress_tensor) where: - output: final predictions (B, T, 2) - stress_tensor: intermediate representation (B, T, 1)
- Return type:
torch.Tensor or tuple of torch.Tensor
- forward_from_stress(x, pft)[source]
Forward pass starting from intermediate stress representation.
This bypasses the initial Transformer and lin1/lin2 layers, and instead continues processing from a reduced representation combined with auxiliary PFT features.
- Parameters:
x (torch.Tensor) – Stress-like representation of shape (batch_size, sequence_length, 1).
pft (torch.Tensor) – Auxiliary features of shape (batch_size, sequence_length, 10).
- Returns:
Output tensor of shape (batch_size, sequence_length, 2).
- Return type:
torch.Tensor
- class phenonn.models.transformerbis.BiTransformer(*args: Any, **kwargs: Any)[source]
Bases:
ModuleBidirectional Transformer-style sequence model with auxiliary features (PFT).
This model combines: - A linear embedding layer for input features - A Transformer encoder-decoder block for global sequence mixing - A causal (autoregressive) TransformerEncoder stack - Concatenation of auxiliary PFT features - Final projection to output space
The architecture is designed for sequence-to-sequence prediction where past context is enforced via a causal attention mask.
- Parameters:
input_dim (int, default=26) – Number of input features per timestep.
feed_forward_trans (int, default=4) – Multiplier for Transformer feedforward dimension.
feed_forward_encoder (int, default=4) – Multiplier for encoder feedforward dimension.
output_dim (int, default=2) – Number of output features per timestep.
d_model (int, default=256) – Hidden representation size used throughout the model.
nr_blocks (int, default=3) – Number of TransformerEncoderLayer blocks.
dropout_trans (float, default=0.1) – Dropout rate used inside the Transformer module.
dropout_encoder (float, default=0.1) – Dropout rate used in encoder layers.
n_pft (int, default=1) – Number of trailing auxiliary features (PFT) appended to input.
- lin1
Projects input features into d_model space.
- Type:
torch.nn.Linear
- trans
Transformer encoder-decoder module for global sequence mixing.
- Type:
torch.nn.Transformer
- lin2
Reduces Transformer output to a single-channel representation.
- Type:
torch.nn.Linear
- lin3
Projects concatenated [stress, PFT] features into d_model space.
- Type:
torch.nn.Linear
- encoder
Stack of TransformerEncoderLayer blocks with causal masking.
- Type:
torch.nn.ModuleList
- lin4
Final projection to output_dim.
- Type:
torch.nn.Linear
- positional_encoder
Sinusoidal positional encoding module (defined but not used in forward).
- Type:
Notes
Input tensors are expected in shape: (batch_size, sequence_length, input_dim)
The last n_pft features are treated as auxiliary inputs and split off.
A causal (upper-triangular) mask is applied to prevent future information leakage in the encoder stack.
Internally, tensors are permuted to: (sequence_length, batch_size, d_model) for TransformerEncoder processing.
- __init__(input_dim=26, feed_forward_trans=4, feed_forward_encoder=4, output_dim=2, d_model=256, nr_blocks=3, dropout_trans=0.1, dropout_encoder=0.1, n_pft=1)[source]
- forward(x, return_stress=False)[source]
Forward pass of the BiTransformer model.
- Parameters:
x (torch.Tensor) – Input tensor of shape (batch_size, sequence_length, input_dim), where the last n_pft channels are auxiliary PFT features.
return_stress (bool, default=False) – If True, also returns intermediate representation after lin2.
- Returns:
- If return_stress=False:
Output tensor of shape (batch_size, sequence_length, output_dim)
- If return_stress=True:
Tuple (output, stress_tensor) where: - output: final predictions (B, T, output_dim) - stress_tensor: intermediate scalar representation (B, T, 1)
- Return type:
torch.Tensor or tuple of torch.Tensor
Neural network building blocks and radiative transfer-inspired models.
This module represents a PyTorch modules for fully connected networks designed for structured data, particularly vertical profile modeling such as atmospheric or canopy radiative transfer.
The module includes:
FCBlock: A reusable fully connected block with normalization and activation.FCN: A configurable fully connected network for sequence-like inputs.
Features
Modular fully connected components with batch normalization
Flexible depth and width configuration for dense networks
Support for sequence reshaping and optional dimension expansion
Notes
FCNexpects inputs shaped as (batch_size, feature_channel, seq_length) and internally flattens them before processing.
Examples
Using FCBlock:
>>> block = FCBlock(128, 64)
>>> x = torch.randn(32, 128)
>>> y = block(x)
Using FCN:
>>> model = FCN(
... feature_channel=6,
... output_channel=4,
... num_layers=3,
... hidden_size=196,
... seq_length=10
... )
>>> x = torch.randn(32, 6, 10)
>>> y = model(x)
- class phenonn.models.fcn.FCBlock(*args: Any, **kwargs: Any)[source]
Bases:
ModuleA fully connected block with linear layer, batch normalization, and ReLU activation.
This module applies a linear transformation, followed by batch normalization, and then a ReLU activation function.
- Parameters:
- linear
Linear transformation layer.
- Type:
nn.Linear
- bn
Batch normalization layer.
- Type:
nn.BatchNorm1d
- relu
ReLU activation function.
- Type:
nn.ReLU
Examples
>>> block = FCBlock(128, 64) >>> x = torch.randn(32, 128) >>> y = block(x) >>> y.shape torch.Size([32, 64])
- forward(x: torch.Tensor) torch.Tensor[source]
Forward pass through the FCBlock.
- Parameters:
x (torch.Tensor) – Input tensor of shape (batch_size, in_features).
- Returns:
Output tensor of shape (batch_size, out_features).
- Return type:
torch.Tensor
Notes
The forward pass applies: ReLU(BatchNorm(Linear(x)))
- class phenonn.models.fcn.FCN(*args: Any, **kwargs: Any)[source]
Bases:
ModuleFully Connected Network with configurable depth and width.
This model flattens the input sequence and processes it through a series of fully connected layers. It can optionally expand the sequence length using a linear transformation.
- Parameters:
feature_channel (int) – Number of input features per time step.
output_channel (int) – Number of output channels.
num_layers (int) – Number of hidden layers.
hidden_size (int) – Size of hidden layers.
seq_length (int, optional) – Length of the input sequence. Default is 55.
dim_expand (int, optional) – Number of time steps to expand the output sequence by. Default is 0 (no expansion).
Stack of hidden layers.
- Type:
nn.Sequential
- output_layer
Final output layer.
- Type:
nn.Linear
- dim_change
Optional layer for sequence length expansion.
- Type:
nn.Linear or None
Examples
>>> model = FCN( ... feature_channel=6, ... output_channel=4, ... num_layers=3, ... hidden_size=196, ... seq_length=10 ... ) >>> x = torch.randn(32, 6, 10) >>> y = model(x) >>> y.shape torch.Size([32, 4, 10])
- __init__(feature_channel: int, output_channel: int, num_layers: int, hidden_size: int, seq_length: int = 55, dim_expand: int = 0) None[source]
Initialize the FCN model.
- Parameters:
feature_channel (int) – Number of input features.
output_channel (int) – Number of output channels.
num_layers (int) – Number of hidden layers.
hidden_size (int) – Size of hidden layers.
seq_length (int, optional) – Length of the input sequence. Default is 55.
dim_expand (int, optional) – Number of time steps to expand the output sequence by. Default is 0 (no expansion).
- Raises:
ValueError – If num_layers is less than 1.
- forward(x: torch.Tensor) torch.Tensor[source]
Forward pass through the FCN.
- Parameters:
x (torch.Tensor) – Input tensor of shape (batch_size, feature_channel, seq_length).
- Returns:
Output tensor of shape (batch_size, output_channel, seq_length + dim_expand) if dim_expand > 0, otherwise (batch_size, output_channel, seq_length).
- Return type:
torch.Tensor
Notes
The forward pass: 1. Flattens the input to (batch_size, feature_channel * seq_length) 2. Passes through FCBlocks 3. Projects to output dimensions 4. Reshapes to (batch_size, output_channel, seq_length) 5. Optionally expands sequence length
Linear regression baselines for LAI prediction.
This module provides simple linear models that serve as reference baselines for evaluating more complex neural network architectures. Both models map meteorological feature sequences to a single LAI prediction while maintaining the same input/output interface as the project’s single-day prediction models.
Implemented Models
- LinearBaseline
A full-window linear regression model that flattens the entire input sequence and applies a single fully connected layer. Each feature at each timestep receives an independent weight, allowing the model to learn temporally specific linear relationships.
Mathematically:
y = w^T x + b
where
xis the flattened(C × L)feature window.This model is equivalent to ordinary least squares regression over all feature–time combinations and provides a strong linear benchmark.
- PerDayLinearBaseline
A per-timestep linear model that ignores temporal history. The model applies a shared linear mapping from features to LAI and returns the prediction associated with the final timestep of the input sequence.
This baseline evaluates how much predictive information is contained in the current day’s meteorological conditions alone. Strong performance indicates that temporal context contributes little beyond instantaneous feature values.
Input and Output Conventions
Both models follow the project’s single-day prediction interface:
- Input:
Tensor of shape
(batch_size, feature_channels, sequence_length).- Output:
Tensor of shape
(batch_size, 1).
Notes
Neither model contains hidden layers, nonlinear activations, recurrence, attention mechanisms, or convolutional operations.
The models are intentionally simple and interpretable, making them useful as lower-bound performance baselines.
Performance gains achieved by more sophisticated architectures can be interpreted relative to these linear reference models.
- class phenonn.models.linear_baseline.LinearBaseline(*args: Any, **kwargs: Any)[source]
Bases:
ModuleFull-window linear regression baseline.
Flattens the entire (feature_channel × seq_length) input into one vector, applies a single Linear layer to produce a scalar prediction.
- This is mathematically equivalent to:
gcc_pred = w @ flatten(input) + b
where w has C×L weights. It can learn things like “temperature on day 300 matters more than temperature on day 50” because each (channel, timestep) pair gets its own weight.
- Parameters:
Examples
>>> model = LinearBaseline(feature_channel=16, seq_length=365) >>> x = torch.randn(32, 16, 365) >>> y = model(x) >>> y.shape torch.Size([32, 1])
- forward(x: torch.Tensor) torch.Tensor[source]
- Parameters:
x ((batch, feature_channel, seq_length))
- Return type:
(batch, 1)
- class phenonn.models.linear_baseline.PerDayLinearBaseline(*args: Any, **kwargs: Any)[source]
Bases:
ModulePer-day linear regression baseline (no temporal context).
Applies the same Linear(C, 1) to every timestep independently, then returns the prediction for the last day. This tests whether today’s feature values alone (without any history) can predict today’s LAI.
If this baseline scores well, it means the temporal context from the 365-day window isn’t adding much — the model is mostly using the current day’s meteorology.
- Parameters:
feature_channel (int) – Number of input feature channels.
Examples
>>> model = PerDayLinearBaseline(feature_channel=16) >>> x = torch.randn(32, 16, 365) >>> y = model(x) >>> y.shape torch.Size([32, 1])
- forward(x: torch.Tensor) torch.Tensor[source]
- Parameters:
x ((batch, feature_channel, seq_length))
- Return type:
(batch, 1)
Training Module
PhenoNN Training Module
Provides training functions for both per-site CSV and flat CSV formats.
LAI Prediction — Training Pipeline
This module implements a full training pipeline for Leaf Area Index (LAI) prediction from meteorological time series using deep learning models.
The model predicts LAI at day x using a sliding window of the previous seq_length days (default: 365 days) of meteorological and auxiliary features. It supports multiple architectures including LSTM, GRU, Transformer, FCN, and linear baselines.
The pipeline includes: - Site- or year-based dataset splitting - Feature engineering (meteorological, cyclic, static, PFT) - Optional per-site LAI normalization - Optional residual learning (predicting obs - pred) - Flexible sequence sampling (stride or random sampling) - Gradient-aware temporal loss (optional) - Early stopping and learning-rate scheduling - Diagnostic logging and training curves - Checkpointing of best model
Supported models
LSTM
GRU
Transformer
FCN / FullyConnected
Linear
Linear-per-day
Bi-directional Transformer variants
1-year sequence models (LSTM / BiTransformer)
Typical usage
Train an LSTM on all sites:
python -m phenocam.run_training –data_dir ./data/DB/ –type lstm –hidden_size 128 –num_layers 2 –num_epochs 50 –batch_size 64
Train with year-based split:
python -m phenocam.run_training –data_dir ./data/DB/ –type transformer –split_mode year –train_years 2018,2019,2020 –val_years 2021 –embed_size 64 –nhead 4
Notes
Normalization statistics are computed on training data only.
Validation can be performed on held-out sites or held-out years.
Loss functions include MSE, MAE, Huber, NMSE, and gradient-based losses.
The model can optionally predict full yearly sequences (365-day outputs).
Residual learning mode uses external predictions as input targets.
- phenonn.training.train.parse_year_list(s: str)[source]
Parse ‘2018,2019,2020’ or ‘2018-2020’ into [2018, 2019, 2020].
- phenonn.training.train.train_one_epoch(model, loader, criterion, optimizer, device, max_grad_norm=1.0)[source]
- phenonn.training.train.validate(model, loader, criterion, device, dataset=None, n_target_days=1, full_year=False)
Training pipeline for LAI prediction from flat CSV datasets.
This script trains sequence-based neural networks to predict Leaf Area Index (LAI) from meteorological, ecological, and land-cover features stored in two flat CSV files containing daily predictors and sparse LAI observations.
The workflow is intended for datasets that fit comfortably in memory and provides a complete training pipeline including dataset construction, normalization, model initialization, validation, checkpointing, and diagnostic visualization.
Problem Formulation
Each sample corresponds to a unique (site_id, year) pair.
- Input:
Tensor of shape:
(n_features, sequence_length)
containing a rolling history of environmental forcing variables, typically spanning approximately two years.
- Output:
Tensor of shape:
(1, 36)
containing 36 LAI observations for the target year, corresponding to days 5, 15, and 25 of each month.
The model predicts the complete annual LAI trajectory from the historical environmental context.
Supported Model Architectures
- LSTM
Multi-layer recurrent neural network using Long Short-Term Memory units.
- GRU
Multi-layer recurrent neural network using Gated Recurrent Units.
- Transformer
Self-attention encoder model for sequence modeling.
- BiTransformer
Transformer architecture incorporating environmental forcing and plant functional type information.
All models are wrapped by Every10DaysWrapper to produce LAI predictions
at the observation frequency used by the target dataset.
Dataset Splitting
Two validation strategies are supported.
- Site Split
Training and validation use disjoint sets of sites.
This evaluates spatial generalization and answers the question:
“Can the model predict LAI at previously unseen locations?”
- Year Split
All sites are retained, but training and validation use different years.
This evaluates temporal generalization and answers the question:
“Can the model predict vegetation dynamics in unseen years?”
Normalization
Feature normalization statistics are computed from the training set and stored in a JSON file for reproducibility.
If a normalization file already exists, it can be reused to avoid recomputation.
The normalization pipeline:
Computes feature means and standard deviations.
Applies z-score normalization to input features.
Normalizes target values for training stability.
Stores statistics alongside model checkpoints.
Training Features
Mini-batch training with PyTorch DataLoaders.
Configurable model architectures.
Multiple loss functions (MSE, MAE, Huber, SmoothL1, normalized losses, and gradient-aware losses).
Gradient clipping.
Adaptive learning-rate scheduling.
Early stopping.
Best-model checkpointing.
Training and validation diagnostics.
Reproducible experiment logging.
Evaluation Metrics
Validation performance is reported using:
- Loss
Training objective selected by
--loss_type.- RMSE
Root Mean Squared Error computed across all predicted LAI values.
- R²
Coefficient of determination computed across all validation samples.
Data Requirements
- Feature CSV
Daily meteorological, ecological, and land-cover predictors indexed by site and date.
- Target CSV
Sparse LAI observations containing three measurements per month (days 5, 15, and 25).
The dataset builder constructs fixed-length historical windows ending in the target year and aligns them with the corresponding annual LAI sequence.
Examples
Train an LSTM model:
>>> python -m phenonn.run_train_flat ... --features_csv data/features.csv ... --target_csv data/targets.csv ... --type lstm ... --hidden_size 128 ... --num_layers 2 ... --num_epochs 50 ... --batch_size 32
Train a transformer model:
>>> python -m phenonn.run_train_flat ... --features_csv data/features.csv ... --target_csv data/targets.csv ... --type transformer ... --embed_size 128 ... --num_layers 4
Notes
This training script is intended for moderate-sized datasets that can be
indexed efficiently from flat CSV files. For very large archives distributed
across yearly files, the streaming workflow implemented in
main_big.py provides a more scalable alternative.
- phenonn.training.train_flat.parse_year_list(s: str)[source]
Parse ‘2000,2001,2002’ or ‘2000-2002’ into [2000, 2001, 2002].
- phenonn.training.train_flat.build_model(args) torch.nn.Module[source]
Instantiate base model and wrap with Every10DaysWrapper.
- phenonn.training.train_flat.train_one_epoch(model, loader, criterion, optimizer, device, max_grad_norm)[source]
- phenonn.training.train_flat.validate(model, loader, criterion, device)
Prediction Module
PhenoNN Prediction Module
Provides functions for running predictions with trained models: - Single-year prediction (per-site CSV format) - Flat CSV prediction (features/targets format)
LAI Prediction — Year-by-Year Inference
Loads a trained model checkpoint and predicts the full annual LAI curve. Supports both site-split and year-split models.
Usage
# Predict on validation sites, all available years: python -m phenocam.predict –checkpoint ./runs/exp01/checkpoints/best_model.pth –data_dir ./data/DB/
# Predict on all sites, specific years: python -m phenocam.predict –checkpoint ./runs/exp01/checkpoints/best_model.pth –data_dir ./data/DB/ –predict_sites all –predict_years 2022,2023
# Predict on training sites only: python -m phenocam.predict –checkpoint ./runs/exp01/checkpoints/best_model.pth –data_dir ./data/DB/ –predict_sites train –predict_years 2022
LAI Prediction — Flat CSV Inference
Loads a trained checkpoint from main_flat.py and predicts LAI at the 36 observation days (5th, 15th, 25th of each month) for every (site_id, year) pair in the chosen site set.
Output
- predictions_flat.csvstr
One row per (site, year, observation day)
- pred_vs_obs.pngstr
Scatter plot on real LAI values
- pred_vs_obs_norm.pngstr
Scatter plot on normalized values
- lai_curves.pngstr
Annual curves for 3 representative sites
- lai_curves_all.pngstr
Annual curves for all sites (grid)
Usage
- Basic prediction:
- python -m phenonn.prediction.predict_flat
–checkpoint runs/exp_flat/checkpoints/best_model.pth –features_csv data/features.csv –target_csv data/targets.csv
- Predict on all sites for specific years:
- python -m phenonn.prediction.predict_flat
–checkpoint runs/exp_flat/checkpoints/best_model.pth –predict_sites all –predict_years 2002,2003
Examples
- Run prediction on validation sites:
>>> python -m phenonn.prediction.predict_flat \ ... --checkpoint runs/exp_flat/checkpoints/best_model.pth \ ... --features_csv data/features.csv \ ... --target_csv data/targets.csv
- Run prediction on all sites for years 2020-2022:
>>> python -m phenonn.prediction.predict_flat \ ... --checkpoint runs/exp_flat/checkpoints/best_model.pth \ ... --features_csv data/features.csv \ ... --target_csv data/targets.csv \ ... --predict_sites all \ ... --predict_years 2020,2021,2022
Notes
- The input features CSV must contain daily data with columns:
site_id, date, year, month, day, pft1_frac..pft15_frac, tmin, tmax, daylength, prcp, srad, vpd, swe
- The target CSV must contain LAI observations for days 5, 15, 25 of each month:
site_id, date, year, month, day, LAI
Utils Module
PhenoNN Utility Modules
Provides logging, diagnostics, model utilities, and evaluation functions.
- class phenonn.utils.Logger(console_output=True, file_output=False, log_file='module_log_file.log', pretty_print=True, record=False)[source]
Bases:
object- __init__(console_output=True, file_output=False, log_file='module_log_file.log', pretty_print=True, record=False)[source]
- start_task(task_name: str, description: str = '', **meta)[source]
Display a clearly formatted ‘task start’ message with good spacing.
- phenonn.utils.plot_loss_histories(train_loss: Sequence[float], valid_loss: Sequence[float], filename: str = 'loss_history.png', logger=None, log_scale: bool = True, title: str = 'Training / Validation Loss') None[source]
Plot training and validation loss curves over epochs.
- Parameters:
train_loss (sequence of float) – Per-epoch training loss.
valid_loss (sequence of float) – Per-epoch validation loss (same length as train_loss).
filename (str) – Output path.
logger (phenonn.utils.logger.Logger, optional) – If provided, log the save location instead of printing.
log_scale (bool) – Use log y-axis (default True — losses usually span orders of magnitude).
title (str) – Figure title.
Notes
Uses mpltex linestyles for consistent styling
Gray vertical dashed line: best validation epoch
Includes grid for better readability
- phenonn.utils.plot_metric_histories(train_history: Dict[str, Sequence[float]], valid_history: Dict[str, Sequence[float]], filename: str = 'metric_history.png', logger=None, log_metrics: Sequence[str] | None = None, cols: int = 3) None[source]
Multi-panel figure of metric evolution over epochs.
One panel per metric. Train and validation plotted together on each panel.
- Parameters:
train_history (dict) – {metric_name: per-epoch values}. Example: {“rmse”: […], “r2”: […]}.
valid_history (dict) – Same keys as train_history, same lengths.
filename (str) – Output path.
logger (phenonn.utils.logger.Logger, optional)
log_metrics (sequence of str, optional) – Metric names that should use log y-scale. Default: all except R²-like metrics (anything with “r2” or “r²” in the name).
cols (int) – Number of columns in the grid.
Notes
Uses mpltex linestyles for consistent styling
Missing/NaN values in a metric series are skipped — useful when you record metrics conditionally and some epochs lack certain values.
Includes grid for better readability
- phenonn.utils.plot_pred_vs_obs(pred: numpy.ndarray | Sequence[float], obs: numpy.ndarray | Sequence[float], filename: str = 'pred_vs_obs.png', logger=None, title: str = 'Predicted vs Observed LAI', xlabel: str = 'Observed LAI', ylabel: str = 'Predicted LAI', gridsize: int = 40, hexbin: bool = True) Dict[str, float][source]
Scatter plot of predictions vs observations with y=x reference and metrics.
Uses hexbin density by default (fast, readable for >10k points). Falls back to a regular scatter for small sample sets where hexbin would be mostly empty.
- Parameters:
pred (array-like) – Predicted values (any shape — will be flattened).
obs (array-like) – Observed values (same shape).
filename (str) – Output path.
logger (phenonn.utils.logger.Logger, optional)
title (str) – Plot labels.
xlabel (str) – Plot labels.
ylabel (str) – Plot labels.
gridsize (int) – Hexbin resolution (number of hexagons along each axis).
hexbin (bool) – If True, use hexbin density. If False, use scatter. Default True.
- Returns:
Computed metrics: rmse, mae, bias, r2, n.
- Return type:
Notes
Errors ignored in computation: NaN and Inf pairs are dropped. Plot axis limits are set to cover both predictions and observations with a small margin, so the y=x line always appears diagonal.
- phenonn.utils.plot_gcc_curves(df: pandas.DataFrame, filename: str = 'gcc_curves_by_r2.png', logger=None, seed: int = 42, site_col: str = 'site', year_col: str = 'year', doy_col: str = 'day_index', pred_col: str = 'lai_pred', obs_col: str = 'lai_obs') Dict[str, float][source]
Plot observed vs predicted annual LAI curves for three representative sites.
Picks one random site with low R², one with medium R², and one with high R² relative to the mean across all sites. Each site gets a subplot showing all validation years overlaid, with observed LAI as a solid line and predicted LAI as a dashed line.
- Parameters:
df (pd.DataFrame) – Predictions dataframe as produced by predict.py, with columns for site, year, day index, lai_pred, and lai_obs.
filename (str) – Output path for the figure.
logger (phenonn.utils.logger.Logger, optional)
seed (int) – Random seed for reproducible site selection.
site_col (str) – Column names in df. Defaults match predict.py output.
year_col (str) – Column names in df. Defaults match predict.py output.
doy_col (str) – Column names in df. Defaults match predict.py output.
pred_col (str) – Column names in df. Defaults match predict.py output.
obs_col (str) – Column names in df. Defaults match predict.py output.
- Returns:
{site_name: r2_value} for the three selected sites.
- Return type:
Notes
Site selection: all sites are ranked by R². The site pool is split into three terciles (low / mid / high). One site is drawn randomly from each tercile. Using terciles rather than the absolute best/worst avoids always showing the same outlier sites.
- phenonn.utils.plot_gcc_curves_all(df: pandas.DataFrame, filename: str = 'gcc_curves_all.png', logger=None, cols: int = 4, site_col: str = 'site', year_col: str = 'year', doy_col: str = 'day_index', pred_col: str = 'lai_pred', obs_col: str = 'lai_obs') Dict[str, float][source]
Plot observed vs predicted annual LAI curves for every site.
One small subplot per site, arranged in a grid, sorted by R² from best (top-left) to worst (bottom-right). Each subplot overlays all validation years with observed (solid) and predicted (dashed) lines.
- Parameters:
df (pd.DataFrame) – Predictions dataframe with columns for site, year, day index, lai_pred, and lai_obs.
filename (str) – Output path.
logger (phenonn.utils.logger.Logger, optional)
cols (int) – Number of columns in the grid. Default 4.
site_col (str) – Column names in df.
year_col (str) – Column names in df.
doy_col (str) – Column names in df.
pred_col (str) – Column names in df.
obs_col (str) – Column names in df.
- Returns:
{site_name: r2_value} for all sites.
- Return type:
- phenonn.utils.make_history_dicts() tuple[source]
Shortcut for initializing matched train/valid history dicts.
- Returns:
(train_hist, valid_hist) – Each with empty lists keyed by ‘loss’, ‘rmse’, ‘r2’.
- Return type:
Example
>>> train_hist, valid_hist = make_history_dicts() >>> # inside training loop: >>> train_hist['loss'].append(train_loss) >>> valid_hist['loss'].append(val_loss) >>> valid_hist['rmse'].append(val_rmse) >>> valid_hist['r2'].append(val_r2)
- phenonn.utils.get_loss_function(loss_type, args, logger=None)[source]
Factory function to instantiate the requested loss function.
- Parameters:
loss_type (str) – Type of loss function. Options: - ‘mse’: Mean Squared Error - ‘mae’: Mean Absolute Error - ‘nmae’: Normalized Mean Absolute Error - ‘nmse’: Normalized Mean Squared Error - ‘wmse’: Weighted Mean Squared Error - ‘logcosh’: Log-Cosh loss - ‘smoothl1’: Smooth L1 Loss (Huber-like) - ‘huber’: Huber Loss
args (argparse.Namespace) – Arguments containing loss-specific parameters (e.g., beta_delta for Huber).
- Returns:
Initialized loss function.
- Return type:
torch.nn.Module
- Raises:
ValueError – If loss_type is not supported or required parameters are missing.
Examples
>>> args = argparse.Namespace(beta_delta=1.0) >>> criterion = get_loss_function('huber', args)
- class phenonn.utils.ModelUtils[source]
Bases:
objectUtility class for model inspection, checkpointing, and memory profiling.
This class provides static methods for common model operations including parameter counting, memory usage analysis, checkpoint management, and model inspection.
Examples
>>> utils = ModelUtils() >>> param_counts = ModelUtils.get_parameter_number(model) >>> ModelUtils.save_checkpoint(state, "checkpoint.pth.tar", logger)
- static get_parameter_number(model, logger=None)[source]
Calculate the total and trainable number of parameters in a model.
- Parameters:
model (torch.nn.Module) – PyTorch model to inspect
logger (phenonn.utils.logger.Logger, optional) – phenonn.utils.logger.Logger instance for output, by default None
- Returns:
Dictionary containing: - ‘Total’: Total number of parameters - ‘Trainable’: Number of trainable parameters
- Return type:
Examples
>>> model = torch.nn.Linear(10, 5) >>> counts = ModelUtils.get_parameter_number(model, logger)
- static print_model_layers(model, logger=None)[source]
Print model parameter names along with their gradient requirements.
- Parameters:
model (torch.nn.Module) – PyTorch model to inspect
logger (phenonn.utils.logger.Logger, optional) – phenonn.utils.logger.Logger instance for output, by default None
Examples
>>> model = torch.nn.Sequential( ... torch.nn.Linear(10, 5), ... torch.nn.ReLU(), ... torch.nn.Linear(5, 1) ... ) >>> ModelUtils.print_model_layers(model, logger)
- static save_checkpoint(state, filename='checkpoint.pth.tar', logger=None)[source]
Save model and optimizer state to a file.
- Parameters:
state (dict) – Dictionary containing model state_dict and other training information. Typically includes: - ‘state_dict’: Model parameters - ‘optimizer’: Optimizer state - ‘epoch’: Current epoch - ‘loss’: Current loss value
filename (str, optional) – File path to save the checkpoint, by default “checkpoint.pth.tar”
logger (phenonn.utils.logger.Logger, optional) – phenonn.utils.logger.Logger instance for output, by default None
Examples
>>> state = { ... 'state_dict': model.state_dict(), ... 'optimizer': optimizer.state_dict(), ... 'epoch': epoch, ... 'loss': loss ... } >>> ModelUtils.save_checkpoint(state, 'model_checkpoint.pth.tar', logger)
- static load_checkpoint(checkpoint, model, optimizer=None, logger=None)[source]
Load model and optimizer state from a checkpoint file.
- Parameters:
checkpoint (dict) – Loaded checkpoint dictionary
model (torch.nn.Module) – Model to load weights into
optimizer (torch.optim.Optimizer, optional) – Optimizer to restore state, by default None
logger (phenonn.utils.logger.Logger, optional) – phenonn.utils.logger.Logger instance for output, by default None
Examples
>>> checkpoint = torch.load('model_checkpoint.pth.tar') >>> ModelUtils.load_checkpoint(checkpoint, model, optimizer, logger)
- static load_training_checkpoint(checkpoint_path, model, optimizer, device, logger=None)[source]
Load comprehensive training checkpoint.
- Parameters:
checkpoint_path (str) – Path to checkpoint file
model (torch.nn.Module) – Model to load weights into
optimizer (torch.optim.Optimizer) – Optimizer to restore state
device (torch.device) – Device to load checkpoint to
logger (phenonn.utils.logger.Logger, optional) – phenonn.utils.logger.Logger instance for output
- Returns:
(epoch, samples_processed, batches_processed, best_val_loss, best_epoch, checkpoint)
- Return type:
- static count_parameters_by_layer(model, logger=None)[source]
Count parameters for each layer in the model.
- Parameters:
model (torch.nn.Module) – PyTorch model to analyze
logger (phenonn.utils.logger.Logger, optional) – phenonn.utils.logger.Logger instance for output, by default None
- Returns:
Dictionary with layer names as keys and parameter counts as values
- Return type:
Examples
>>> layer_params = ModelUtils.count_parameters_by_layer(model, logger)
- static log_model_summary(model, input_shape=None, logger=None)[source]
Log comprehensive model summary including parameters and architecture.
- Parameters:
model (torch.nn.Module) – PyTorch model to summarize
input_shape (tuple, optional) – Input shape for memory analysis, by default None
logger (phenonn.utils.logger.Logger, optional) – phenonn.utils.logger.Logger instance for output, by default None
- static save_training_checkpoint(model, optimizer, epoch, samples_processed, batches_processed, train_loss_history, valid_loss_history, valid_metrics_history, best_val_loss, best_epoch, avg_val_loss, avg_epoch_loss, args, paths, logger, checkpoint_type='epoch', save_full_model=True)[source]
Save comprehensive training checkpoint with consistent formatting.
- Parameters:
model (torch.nn.Module) – Model to save
optimizer (torch.optim.Optimizer) – Optimizer to save
epoch (int) – Current epoch
samples_processed (int) – Number of samples processed so far
batches_processed (int) – Number of batches processed so far
train_loss_history (list) – History of training losses
valid_loss_history (list) – History of validation losses
valid_metrics_history (dict) – History of validation metrics
best_val_loss (float) – Best validation loss so far
best_epoch (int) – Epoch with best validation loss
avg_val_loss (float) – Current epoch validation loss
avg_epoch_loss (float) – Current epoch training loss
args (argparse.Namespace) – Command line arguments
paths (EasyDict) – Directory paths
logger (phenonn.utils.logger.Logger) – phenonn.utils.logger.Logger instance
checkpoint_type (str) – Type of checkpoint: “samples”, “epoch”, “best”, “final”
save_full_model (bool) – Whether to also save the full model separately
- Returns:
(checkpoint_filename, full_model_filename)
- Return type:
Examples
>>> checkpoint_file, full_model_file = ModelUtils.save_training_checkpoint( ... model, optimizer, epoch, samples_processed, batches_processed, ... train_loss_history, valid_loss_history, valid_metrics_history, ... best_val_loss, best_epoch, avg_val_loss, avg_epoch_loss, ... args, paths, logger, checkpoint_type="best" ... )
- phenonn.utils.load_model(args)[source]
Instantiate and wrap a model for single-day GCC prediction.
- Parameters:
args (argparse.Namespace or EasyDict) –
Must contain at minimum:
- typestr
One of ‘lstm’, ‘gru’, ‘transformer’, ‘fcn’, ‘fullyconnected’.
- feature_channelint
Number of input feature channels (meteo + cyclic + static + PFT).
- output_channelint
Number of output channels (1 for gcc_lowess).
- seq_lengthint
Window length (365).
Plus architecture-specific parameters (see original model_loader).
- Returns:
Model whose forward returns (batch, output_channel).
- Return type:
- class phenonn.utils.FileUtils[source]
Bases:
objectUtility class for file and directory operations.
- __init__()[source]
Initialize the FileUtils class. This class does not maintain any state, so the constructor is empty.
- class phenonn.utils.EasyDict[source]
Bases:
dictA dictionary subclass that allows for attribute-style access to its items. This class extends the built-in dict and overrides the __getattr__, __setattr__, and __delattr__ methods to enable accessing dictionary keys as attributes. Original work: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. Original source: https://github.com/NVlabs/edm
- class phenonn.utils.Every10DaysWrapper(*args: Any, **kwargs: Any)[source]
Bases:
ModuleWraps any RTnn model to output predictions at the 36 LAI observation days.
Extracts the last 365 timesteps of the model output, then selects the 36 positions corresponding to days 5, 15, 25 of each month in a non-leap year.
Input : (B, C_in, L) with L ≥ 365 Output : (B, C_out, 36)
- Parameters:
base_model (nn.Module) – Any model with forward signature (B, C_in, L) -> (B, C_out, L).
Examples
>>> base = RNN_LSTM(feature_channel=31, output_channel=1, ... hidden_size=128, num_layers=2) >>> model = Every10DaysWrapper(base) >>> x = torch.randn(32, 31, 720) >>> y = model(x) >>> y.shape torch.Size([32, 1, 36])
- forward(x: torch.Tensor) torch.Tensor[source]
- Parameters:
x ((batch, feature_channels, seq_length) — seq_length ≥ 365)
- Return type:
(batch, output_channel, 36)
- class phenonn.utils.permuteWrapper(*args: Any, **kwargs: Any)[source]
Bases:
ModulePermutes input dimensions to match expected order for RTnn models.
RTnn models expect input shape (batch, feature_channels, seq_length). If your data is in (batch, seq_length, feature_channels), this wrapper permutes the dimensions before passing to the base model.
- Parameters:
base_model (nn.Module) – Any model with forward signature (batch, C_in, L) -> (batch, C_out, L).
Examples
>>> from rtnn.models.rnn import RNN_LSTM >>> base = RNN_LSTM(feature_channel=14, output_channel=1, ... hidden_size=128, num_layers=2) >>> model = permuteWrapper(base) >>> x = torch.randn(32, 365, 14) # Note seq_length and feature_channels swapped >>> y = model(x) >>> y.shape torch.Size([32, 1])
- class phenonn.utils.LastNDaysWrapper(*args: Any, **kwargs: Any)[source]
Bases:
ModuleWraps any RTnn model to output the last N timesteps.
Takes the last N timesteps of the wrapped model’s sequence output, yielding shape (batch, output_channel, N) instead of (batch, output_channel, seq_length).
Used for gradient-aware loss where we need GCC(t) and GCC(t-1) while keeping the full input window for context.
- Parameters:
base_model (nn.Module) – Any model with forward signature (batch, C_in, L) -> (batch, C_out, L).
n_days (int) – Number of trailing timesteps to keep (default: 2).
Examples
>>> base = RNN_LSTM(feature_channel=16, output_channel=1, ... hidden_size=128, num_layers=2) >>> model = LastNDaysWrapper(base, n_days=2) >>> x = torch.randn(32, 16, 365) >>> y = model(x) >>> y.shape torch.Size([32, 1, 2])
- forward(x: torch.Tensor) torch.Tensor[source]
- Parameters:
x ((batch, feature_channels, seq_length))
- Return type:
(batch, output_channel, n_days)
- class phenonn.utils.logger.Logger(console_output=True, file_output=False, log_file='module_log_file.log', pretty_print=True, record=False)[source]
Bases:
object- __init__(console_output=True, file_output=False, log_file='module_log_file.log', pretty_print=True, record=False)[source]
- start_task(task_name: str, description: str = '', **meta)[source]
Display a clearly formatted ‘task start’ message with good spacing.
- phenonn.utils.diagnostics.plot_loss_histories(train_loss: Sequence[float], valid_loss: Sequence[float], filename: str = 'loss_history.png', logger=None, log_scale: bool = True, title: str = 'Training / Validation Loss') None[source]
Plot training and validation loss curves over epochs.
- Parameters:
train_loss (sequence of float) – Per-epoch training loss.
valid_loss (sequence of float) – Per-epoch validation loss (same length as train_loss).
filename (str) – Output path.
logger (phenonn.utils.logger.Logger, optional) – If provided, log the save location instead of printing.
log_scale (bool) – Use log y-axis (default True — losses usually span orders of magnitude).
title (str) – Figure title.
Notes
Uses mpltex linestyles for consistent styling
Gray vertical dashed line: best validation epoch
Includes grid for better readability
- phenonn.utils.diagnostics.plot_metric_histories(train_history: Dict[str, Sequence[float]], valid_history: Dict[str, Sequence[float]], filename: str = 'metric_history.png', logger=None, log_metrics: Sequence[str] | None = None, cols: int = 3) None[source]
Multi-panel figure of metric evolution over epochs.
One panel per metric. Train and validation plotted together on each panel.
- Parameters:
train_history (dict) – {metric_name: per-epoch values}. Example: {“rmse”: […], “r2”: […]}.
valid_history (dict) – Same keys as train_history, same lengths.
filename (str) – Output path.
logger (phenonn.utils.logger.Logger, optional)
log_metrics (sequence of str, optional) – Metric names that should use log y-scale. Default: all except R²-like metrics (anything with “r2” or “r²” in the name).
cols (int) – Number of columns in the grid.
Notes
Uses mpltex linestyles for consistent styling
Missing/NaN values in a metric series are skipped — useful when you record metrics conditionally and some epochs lack certain values.
Includes grid for better readability
- phenonn.utils.diagnostics.plot_pred_vs_obs(pred: numpy.ndarray | Sequence[float], obs: numpy.ndarray | Sequence[float], filename: str = 'pred_vs_obs.png', logger=None, title: str = 'Predicted vs Observed LAI', xlabel: str = 'Observed LAI', ylabel: str = 'Predicted LAI', gridsize: int = 40, hexbin: bool = True) Dict[str, float][source]
Scatter plot of predictions vs observations with y=x reference and metrics.
Uses hexbin density by default (fast, readable for >10k points). Falls back to a regular scatter for small sample sets where hexbin would be mostly empty.
- Parameters:
pred (array-like) – Predicted values (any shape — will be flattened).
obs (array-like) – Observed values (same shape).
filename (str) – Output path.
logger (phenonn.utils.logger.Logger, optional)
title (str) – Plot labels.
xlabel (str) – Plot labels.
ylabel (str) – Plot labels.
gridsize (int) – Hexbin resolution (number of hexagons along each axis).
hexbin (bool) – If True, use hexbin density. If False, use scatter. Default True.
- Returns:
Computed metrics: rmse, mae, bias, r2, n.
- Return type:
Notes
Errors ignored in computation: NaN and Inf pairs are dropped. Plot axis limits are set to cover both predictions and observations with a small margin, so the y=x line always appears diagonal.
- phenonn.utils.diagnostics.plot_gcc_curves(df: pandas.DataFrame, filename: str = 'gcc_curves_by_r2.png', logger=None, seed: int = 42, site_col: str = 'site', year_col: str = 'year', doy_col: str = 'day_index', pred_col: str = 'lai_pred', obs_col: str = 'lai_obs') Dict[str, float][source]
Plot observed vs predicted annual LAI curves for three representative sites.
Picks one random site with low R², one with medium R², and one with high R² relative to the mean across all sites. Each site gets a subplot showing all validation years overlaid, with observed LAI as a solid line and predicted LAI as a dashed line.
- Parameters:
df (pd.DataFrame) – Predictions dataframe as produced by predict.py, with columns for site, year, day index, lai_pred, and lai_obs.
filename (str) – Output path for the figure.
logger (phenonn.utils.logger.Logger, optional)
seed (int) – Random seed for reproducible site selection.
site_col (str) – Column names in df. Defaults match predict.py output.
year_col (str) – Column names in df. Defaults match predict.py output.
doy_col (str) – Column names in df. Defaults match predict.py output.
pred_col (str) – Column names in df. Defaults match predict.py output.
obs_col (str) – Column names in df. Defaults match predict.py output.
- Returns:
{site_name: r2_value} for the three selected sites.
- Return type:
Notes
Site selection: all sites are ranked by R². The site pool is split into three terciles (low / mid / high). One site is drawn randomly from each tercile. Using terciles rather than the absolute best/worst avoids always showing the same outlier sites.
- phenonn.utils.diagnostics.plot_gcc_curves_all(df: pandas.DataFrame, filename: str = 'gcc_curves_all.png', logger=None, cols: int = 4, site_col: str = 'site', year_col: str = 'year', doy_col: str = 'day_index', pred_col: str = 'lai_pred', obs_col: str = 'lai_obs') Dict[str, float][source]
Plot observed vs predicted annual LAI curves for every site.
One small subplot per site, arranged in a grid, sorted by R² from best (top-left) to worst (bottom-right). Each subplot overlays all validation years with observed (solid) and predicted (dashed) lines.
- Parameters:
df (pd.DataFrame) – Predictions dataframe with columns for site, year, day index, lai_pred, and lai_obs.
filename (str) – Output path.
logger (phenonn.utils.logger.Logger, optional)
cols (int) – Number of columns in the grid. Default 4.
site_col (str) – Column names in df.
year_col (str) – Column names in df.
doy_col (str) – Column names in df.
pred_col (str) – Column names in df.
obs_col (str) – Column names in df.
- Returns:
{site_name: r2_value} for all sites.
- Return type:
- phenonn.utils.diagnostics.plot_feature_distributions(site_files: List[str], filename: str = 'feature_distributions.png', logger=None, cols: int = 4, n_bins: int = 60, max_sites: int = 20) None[source]
Plot histograms of all input features and the target variable.
Shows the raw distribution and, for log-transformed features, the distribution after log1p. Useful for checking skewness, spotting outliers, and verifying that normalization choices are appropriate.
- Parameters:
site_files (list of str) – Paths to site CSVs. A random subset of max_sites is used to keep computation fast.
filename (str) – Output path for the figure.
logger (phenonn.utils.logger.Logger, optional)
cols (int) – Number of columns in the grid.
n_bins (int) – Number of histogram bins.
max_sites (int) – Maximum number of sites to sample (for speed).
Notes
For each feature, the histogram shows: - Blue: raw values (pooled across all sampled sites) - Orange (if applicable): values after log1p transform - Vertical red dashed lines: mean ± 1 std - Title includes skewness and % of near-zero values
The target (LAI) is shown in green in the last panel.
- phenonn.utils.diagnostics.plot_feature_distributions_per_site(site_files: List[str], output_dir: str = './feature_distributions', logger=None, cols: int = 4, n_bins: int = 60) None[source]
Generate one feature distribution plot per site.
Produces one PNG file per site, named {sitename}_feature_distribution.png, in the output directory. Each file shows the same histogram layout as plot_feature_distributions but for a single site only.
- Parameters:
Examples
>>> site_files = sorted(glob.glob("./data/DB/*.csv")) >>> plot_feature_distributions_per_site(site_files, output_dir="./runs/dist_per_site") # Creates: ./runs/dist_per_site/DB_asuhighlands_feature_distribution.png # ./runs/dist_per_site/DB_bartlett_feature_distribution.png # ... (one per site)
- phenonn.utils.diagnostics.make_history_dicts() tuple[source]
Shortcut for initializing matched train/valid history dicts.
- Returns:
(train_hist, valid_hist) – Each with empty lists keyed by ‘loss’, ‘rmse’, ‘r2’.
- Return type:
Example
>>> train_hist, valid_hist = make_history_dicts() >>> # inside training loop: >>> train_hist['loss'].append(train_loss) >>> valid_hist['loss'].append(val_loss) >>> valid_hist['rmse'].append(val_rmse) >>> valid_hist['r2'].append(val_r2)
Evaluation utilities for RTnn model assessment.
This module provides comprehensive evaluation tools for radiative transfer neural network models, including custom loss functions, metric computation, and visualization helpers.
The module includes: - Custom loss functions (NMSE, NMAE, combined MSE-MAE, LogCosh, Weighted MSE) - Metric calculators for evaluation (MSE, MAE, MBE, R², NMSE, NMAE, MARE, GMRAE) - Data normalization/de-normalization utilities - Absorption rate calculations - Main evaluation loop for LSM models
Dependencies
torch : For tensor operations and loss functions numpy : For numerical operations plot_helper : For visualization utilities
- class phenonn.utils.evaluater.GradientAwareLoss(*args: Any, **kwargs: Any)[source]
Bases:
ModuleMSE + temporal gradient penalty on the last N predicted days.
- Combines two terms:
L = MSE(ŷ, y) + λ * MSE(Δŷ, Δy)
- where Δ denotes the discrete temporal difference between consecutive days:
Δy = y[…, 1:] - y[…, :-1]
Designed for n_target_days=2: the model predicts [GCC(t-1), GCC(t)] and the loss penalises both the values and the day-to-day change.
- Parameters:
grad_weight (float) – Weight λ for the gradient term. 0 = pure MSE. Typical values: 0.1–1.0.
base_loss (str) – Base reconstruction loss: ‘mse’ or ‘huber’.
huber_delta (float) – Delta for Huber loss (only used if base_loss=’huber’).
shapes (Input)
------------
pred (torch.Tensor) – Shape (batch, 1, N) — last N days predictions (typically N=2)
target (torch.Tensor) – Shape (batch, 1, N) — last N days targets
Examples
>>> criterion = GradientAwareLoss(grad_weight=0.5) >>> pred = torch.randn(32, 1, 2) # [ŷ(t-1), ŷ(t)] >>> target = torch.randn(32, 1, 2) # [y(t-1), y(t)] >>> loss = criterion(pred, target)
- class phenonn.utils.evaluater.NMSELoss(*args: Any, **kwargs: Any)[source]
Bases:
ModuleNormalized Mean Squared Error Loss.
Computes MSE normalized by the mean square of the target values. Useful when the scale of the target variable varies.
- Parameters:
eps (float, optional) – Small constant for numerical stability. Default is 1e-8.
Examples
>>> criterion = NMSELoss() >>> loss = criterion(predictions, targets)
- class phenonn.utils.evaluater.NMAELoss(*args: Any, **kwargs: Any)[source]
Bases:
ModuleNormalized Mean Absolute Error Loss.
Computes MAE normalized by the mean absolute value of the target. Provides a scale-invariant error metric.
- Parameters:
eps (float, optional) – Small constant for numerical stability. Default is 1e-8.
- class phenonn.utils.evaluater.MetricTracker[source]
Bases:
objectA utility class for tracking and computing statistics of metric values.
This class maintains a running average of metric values and provides methods to compute mean and root mean squared values.
Examples
>>> tracker = MetricTracker() >>> tracker.update(10.0, 5) # value=10.0, count=5 samples >>> tracker.update(20.0, 3) # value=20.0, count=3 samples >>> print(tracker.getmean()) # (10*5 + 20*3) / (5+3) = 110/8 = 13.75 13.75 >>> print(tracker.getsqrtmean()) # sqrt(13.75) 3.7080992435478315
- getmean()[source]
Calculate the mean of all tracked values.
- Returns:
Weighted mean of all values: total_value / total_count
- Return type:
- Raises:
ZeroDivisionError – If no values have been added (count == 0)
- getstd()[source]
Calculate the standard deviation of all tracked values.
- Returns:
Weighted standard deviation of all values: sqrt(E(x^2) - (E(x))^2)
- Return type:
- Raises:
ZeroDivisionError – If no values have been added (count == 0)
- getsqrtmean()[source]
Calculate the square root of the mean of all tracked values.
- Returns:
Square root of the weighted mean: sqrt(total_value / total_count)
- Return type:
- Raises:
ZeroDivisionError – If no values have been added (count == 0)
- phenonn.utils.evaluater.get_loss_function(loss_type, args, logger=None)[source]
Factory function to instantiate the requested loss function.
- Parameters:
loss_type (str) – Type of loss function. Options: - ‘mse’: Mean Squared Error - ‘mae’: Mean Absolute Error - ‘nmae’: Normalized Mean Absolute Error - ‘nmse’: Normalized Mean Squared Error - ‘wmse’: Weighted Mean Squared Error - ‘logcosh’: Log-Cosh loss - ‘smoothl1’: Smooth L1 Loss (Huber-like) - ‘huber’: Huber Loss
args (argparse.Namespace) – Arguments containing loss-specific parameters (e.g., beta_delta for Huber).
- Returns:
Initialized loss function.
- Return type:
torch.nn.Module
- Raises:
ValueError – If loss_type is not supported or required parameters are missing.
Examples
>>> args = argparse.Namespace(beta_delta=1.0) >>> criterion = get_loss_function('huber', args)
- phenonn.utils.evaluater.mse_all(pred, true)[source]
Compute Mean Squared Error.
- Parameters:
pred (torch.Tensor) – Predictions.
true (torch.Tensor) – Ground truth.
- Returns:
(num_elements, mse_value)
- Return type:
- phenonn.utils.evaluater.mbe_all(pred, true)[source]
Compute Mean Bias Error.
- Parameters:
pred (torch.Tensor) – Predictions.
true (torch.Tensor) – Ground truth.
- Returns:
(num_elements, mbe_value)
- Return type:
- phenonn.utils.evaluater.mae_all(pred, true)[source]
Compute Mean Absolute Error.
- Parameters:
pred (torch.Tensor) – Predictions.
true (torch.Tensor) – Ground truth.
- Returns:
(num_elements, mae_value)
- Return type:
- phenonn.utils.evaluater.r2_all(pred, true)[source]
Calculate R2 (coefficient of determination) between predicted and true values.
Computes the R2 metric and returns both the number of elements and the R2 value.
- Parameters:
pred (torch.Tensor) – Predicted values from the model
true (torch.Tensor) – Ground truth values
- Returns:
(num_elements, r2_value) where: - num_elements (int): Total number of elements in the tensors - r2_value (torch.Tensor): R2 score
- Return type:
Notes
R2 is calculated as:
R2 = 1 - sum((true - pred)^2) / sum((true - mean(true))^2)
This implementation is fully torch-based and works on CPU and GPU.
- phenonn.utils.evaluater.nmae_all(pred, true)[source]
Compute Normalized Mean Absolute Error.
- Parameters:
pred (torch.Tensor) – Predictions.
true (torch.Tensor) – Ground truth.
- Returns:
(num_elements, nmae_value)
- Return type:
- phenonn.utils.evaluater.nmse_all(pred, true)[source]
Compute Normalized Mean Squared Error.
- Parameters:
pred (torch.Tensor) – Predictions.
true (torch.Tensor) – Ground truth.
- Returns:
(num_elements, nmse_value)
- Return type:
- phenonn.utils.evaluater.mare_all(pred, true)[source]
Compute Mean Absolute Relative Error.
- Parameters:
pred (torch.Tensor) – Predictions.
true (torch.Tensor) – Ground truth.
- Returns:
(num_elements, mare_value)
- Return type:
- phenonn.utils.evaluater.gmrae_all(pred, true)[source]
Compute Geometric Mean Relative Absolute Error.
- Parameters:
pred (torch.Tensor) – Predictions.
true (torch.Tensor) – Ground truth.
- Returns:
(num_elements, gmrae_value)
- Return type:
Phenonn Model Loader
Factory module for instantiating deep learning models.
This module provides a unified interface to build different neural network architectures (RNNs, Transformers, FCNs, and linear baselines) and automatically wraps them to ensure consistent output formatting for training and evaluation pipelines.
Design
All models are constructed as base networks and then wrapped using lightweight adapters that enforce consistent output shapes:
- SingleDayWrapper:
Ensures output shape (batch, 1) for standard single-day prediction.
- LastNDaysWrapper:
Returns predictions over multiple target days (used in gradient loss or full-sequence forecasting).
- permuteWrapper:
Handles tensor dimension reordering for transformer-based models.
- Special cases:
Some models (e.g. linear baselines) are returned without wrapping because they already produce correctly shaped outputs.
Supported models
- RNN-based models:
LSTM (RNN_LSTM)
GRU (RNN_GRU)
1-year LSTM variant (sequence-to-sequence style)
- Transformer models:
Encoder-only Transformer (EncoderTorch)
BiTransformer variants
Combined Transformer-RNN hybrid (transformerbis)
- Feed-forward models:
FCN (Fully Connected Network)
- Linear baselines:
LinearBaseline
PerDayLinearBaseline
Wrapper logic
The final wrapper depends on training configuration:
- args.n_target_days > 1:
→ LastNDaysWrapper is used (multi-day regression / gradient loss)
- otherwise:
→ SingleDayWrapper is used (standard single-step prediction)
Special cases: - 1-year models automatically return LastNDaysWrapper(365)
- param args:
Configuration object containing at least:
- typestr
Model type identifier (e.g., ‘lstm’, ‘transformer’, ‘fcn’).
- feature_channelint
Number of input features (meteorology + cyclic + static + PFT).
- output_channelint
Number of output targets (typically 1 for LAI/GCC).
- seq_lengthint
Input sequence length (e.g., 365 days).
- Plus architecture-specific hyperparameters:
hidden_size, num_layers, embed_size, nhead, dropout, etc.
- type args:
argparse.Namespace or EasyDict
- returns:
Wrapped model ready for training. Output shape depends on wrapper:
(batch, 1) for SingleDayWrapper
(batch, n_target_days) for LastNDaysWrapper
- rtype:
nn.Module
- raises ValueError:
If args.type does not match any supported architecture.
Notes
This module standardizes heterogeneous architectures under a single training interface.
Wrapping ensures compatibility with loss functions and dataset outputs.
Transformer-based models may internally permute tensor dimensions using permuteWrapper.
- phenonn.utils.model_loader.load_model(args)[source]
Instantiate and wrap a model for single-day GCC prediction.
- Parameters:
args (argparse.Namespace or EasyDict) –
Must contain at minimum:
- typestr
One of ‘lstm’, ‘gru’, ‘transformer’, ‘fcn’, ‘fullyconnected’.
- feature_channelint
Number of input feature channels (meteo + cyclic + static + PFT).
- output_channelint
Number of output channels (1 for gcc_lowess).
- seq_lengthint
Window length (365).
Plus architecture-specific parameters (see original model_loader).
- Returns:
Model whose forward returns (batch, output_channel).
- Return type:
Model utility functions for PyTorch training workflows.
This module provides a collection of helper utilities for inspecting models, analyzing parameter distributions, and managing checkpoints during training. It is designed to standardize common operations such as saving/loading model states, logging architecture details, and maintaining reproducible training artifacts.
The utilities support both single-GPU and multi-GPU (DataParallel) setups and include safeguards for compatibility when loading checkpoints across different hardware configurations.
Features
Parameter counting (total and trainable)
Layer-wise parameter inspection
Model structure logging
Checkpoint saving and loading
Full training state persistence
Emergency checkpointing for crash recovery
DataParallel-aware state dictionary handling
Notes
Checkpoints include both model weights and optimizer states to enable seamless training resumption.
File naming conventions are automatically adapted based on checkpoint type (e.g., epoch, best, final, emergency).
When using torch.nn.DataParallel, the module automatically adjusts state dictionary keys to ensure compatibility between wrapped and unwrapped models.
Dependencies
torch
os
datetime
Examples
Basic usage:
>>> from model_utils import ModelUtils
>>> counts = ModelUtils.get_parameter_number(model)
>>> ModelUtils.print_model_layers(model)
Saving and loading checkpoints:
>>> state = {
... "state_dict": model.state_dict(),
... "optimizer": optimizer.state_dict(),
... "epoch": epoch,
... }
>>> ModelUtils.save_checkpoint(state, "checkpoint.pth.tar")
>>> checkpoint = torch.load("checkpoint.pth.tar")
>>> ModelUtils.load_checkpoint(checkpoint, model, optimizer)
Saving a full training checkpoint:
>>> ModelUtils.save_training_checkpoint(
... model, optimizer, epoch, samples_processed, batches_processed,
... train_loss_history, valid_loss_history, valid_metrics_history,
... best_val_loss, best_epoch, avg_val_loss, avg_epoch_loss,
... args, paths, logger, checkpoint_type="best"
... )
- class phenonn.utils.model_utils.ModelUtils[source]
Bases:
objectUtility class for model inspection, checkpointing, and memory profiling.
This class provides static methods for common model operations including parameter counting, memory usage analysis, checkpoint management, and model inspection.
Examples
>>> utils = ModelUtils() >>> param_counts = ModelUtils.get_parameter_number(model) >>> ModelUtils.save_checkpoint(state, "checkpoint.pth.tar", logger)
- static get_parameter_number(model, logger=None)[source]
Calculate the total and trainable number of parameters in a model.
- Parameters:
model (torch.nn.Module) – PyTorch model to inspect
logger (phenonn.utils.logger.Logger, optional) – phenonn.utils.logger.Logger instance for output, by default None
- Returns:
Dictionary containing: - ‘Total’: Total number of parameters - ‘Trainable’: Number of trainable parameters
- Return type:
Examples
>>> model = torch.nn.Linear(10, 5) >>> counts = ModelUtils.get_parameter_number(model, logger)
- static print_model_layers(model, logger=None)[source]
Print model parameter names along with their gradient requirements.
- Parameters:
model (torch.nn.Module) – PyTorch model to inspect
logger (phenonn.utils.logger.Logger, optional) – phenonn.utils.logger.Logger instance for output, by default None
Examples
>>> model = torch.nn.Sequential( ... torch.nn.Linear(10, 5), ... torch.nn.ReLU(), ... torch.nn.Linear(5, 1) ... ) >>> ModelUtils.print_model_layers(model, logger)
- static save_checkpoint(state, filename='checkpoint.pth.tar', logger=None)[source]
Save model and optimizer state to a file.
- Parameters:
state (dict) – Dictionary containing model state_dict and other training information. Typically includes: - ‘state_dict’: Model parameters - ‘optimizer’: Optimizer state - ‘epoch’: Current epoch - ‘loss’: Current loss value
filename (str, optional) – File path to save the checkpoint, by default “checkpoint.pth.tar”
logger (phenonn.utils.logger.Logger, optional) – phenonn.utils.logger.Logger instance for output, by default None
Examples
>>> state = { ... 'state_dict': model.state_dict(), ... 'optimizer': optimizer.state_dict(), ... 'epoch': epoch, ... 'loss': loss ... } >>> ModelUtils.save_checkpoint(state, 'model_checkpoint.pth.tar', logger)
- static load_checkpoint(checkpoint, model, optimizer=None, logger=None)[source]
Load model and optimizer state from a checkpoint file.
- Parameters:
checkpoint (dict) – Loaded checkpoint dictionary
model (torch.nn.Module) – Model to load weights into
optimizer (torch.optim.Optimizer, optional) – Optimizer to restore state, by default None
logger (phenonn.utils.logger.Logger, optional) – phenonn.utils.logger.Logger instance for output, by default None
Examples
>>> checkpoint = torch.load('model_checkpoint.pth.tar') >>> ModelUtils.load_checkpoint(checkpoint, model, optimizer, logger)
- static load_training_checkpoint(checkpoint_path, model, optimizer, device, logger=None)[source]
Load comprehensive training checkpoint.
- Parameters:
checkpoint_path (str) – Path to checkpoint file
model (torch.nn.Module) – Model to load weights into
optimizer (torch.optim.Optimizer) – Optimizer to restore state
device (torch.device) – Device to load checkpoint to
logger (phenonn.utils.logger.Logger, optional) – phenonn.utils.logger.Logger instance for output
- Returns:
(epoch, samples_processed, batches_processed, best_val_loss, best_epoch, checkpoint)
- Return type:
- static count_parameters_by_layer(model, logger=None)[source]
Count parameters for each layer in the model.
- Parameters:
model (torch.nn.Module) – PyTorch model to analyze
logger (phenonn.utils.logger.Logger, optional) – phenonn.utils.logger.Logger instance for output, by default None
- Returns:
Dictionary with layer names as keys and parameter counts as values
- Return type:
Examples
>>> layer_params = ModelUtils.count_parameters_by_layer(model, logger)
- static log_model_summary(model, input_shape=None, logger=None)[source]
Log comprehensive model summary including parameters and architecture.
- Parameters:
model (torch.nn.Module) – PyTorch model to summarize
input_shape (tuple, optional) – Input shape for memory analysis, by default None
logger (phenonn.utils.logger.Logger, optional) – phenonn.utils.logger.Logger instance for output, by default None
- static save_training_checkpoint(model, optimizer, epoch, samples_processed, batches_processed, train_loss_history, valid_loss_history, valid_metrics_history, best_val_loss, best_epoch, avg_val_loss, avg_epoch_loss, args, paths, logger, checkpoint_type='epoch', save_full_model=True)[source]
Save comprehensive training checkpoint with consistent formatting.
- Parameters:
model (torch.nn.Module) – Model to save
optimizer (torch.optim.Optimizer) – Optimizer to save
epoch (int) – Current epoch
samples_processed (int) – Number of samples processed so far
batches_processed (int) – Number of batches processed so far
train_loss_history (list) – History of training losses
valid_loss_history (list) – History of validation losses
valid_metrics_history (dict) – History of validation metrics
best_val_loss (float) – Best validation loss so far
best_epoch (int) – Epoch with best validation loss
avg_val_loss (float) – Current epoch validation loss
avg_epoch_loss (float) – Current epoch training loss
args (argparse.Namespace) – Command line arguments
paths (EasyDict) – Directory paths
logger (phenonn.utils.logger.Logger) – phenonn.utils.logger.Logger instance
checkpoint_type (str) – Type of checkpoint: “samples”, “epoch”, “best”, “final”
save_full_model (bool) – Whether to also save the full model separately
- Returns:
(checkpoint_filename, full_model_filename)
- Return type:
Examples
>>> checkpoint_file, full_model_file = ModelUtils.save_training_checkpoint( ... model, optimizer, epoch, samples_processed, batches_processed, ... train_loss_history, valid_loss_history, valid_metrics_history, ... best_val_loss, best_epoch, avg_val_loss, avg_epoch_loss, ... args, paths, logger, checkpoint_type="best" ... )
RTnn Output Wrappers for Phenonn GCC Prediction
This module defines lightweight PyTorch wrappers that adapt RTnn-style sequence models to standardized prediction targets used in Phenonn GCC / LAI regression tasks.
Most RTnn models produce dense sequence outputs of shape:
(batch, output_channel, seq_length)
However, downstream training and evaluation typically require simplified or structured outputs such as:
Single-day prediction: (batch, output_channel)
Multi-day regression: (batch, output_channel, N)
Irregular observation days: (batch, output_channel, 36)
This module provides wrappers to convert full-sequence outputs into these standardized formats without modifying the underlying models.
Core Idea
All wrappers assume a base model with signature:
(batch, C_in, L) → (batch, C_out, L)
and apply deterministic slicing or permutation to produce task-specific outputs.
Classes
- SingleDayWrapper
Extracts the last timestep of the sequence output, producing a single prediction per sample.
- permuteWrapper
Reorders input/output dimensions to match RTnn conventions when data is provided in (batch, seq_length, feature_channels) format.
- LastNDaysWrapper
Extracts the last N timesteps of the model output for temporal consistency losses (e.g., gradient-based or multi-step supervision).
- Every10DaysWrapper
Selects predictions at fixed phenological observation days (days 5, 15, 25 of each month → 36 total points per year).
Constants
- _OBS_POSITIONSlist[int]
Precomputed 0-indexed day-of-year positions (length = 36) corresponding to LAI observation dates in a non-leap year.
Design Rationale
Keeps RTnn models unchanged and reusable across tasks
Centralizes output-shaping logic in a single module
Ensures consistent tensor shapes across training, validation, and metrics
Enables flexible supervision (single-step, multi-step, sparse observations)
Notes
All wrappers inherit from torch.nn.Module
No learnable parameters are added (pure structural transforms)
Assumes base models return full sequence outputs
Indexing is deterministic and non-learned
- class phenonn.utils.wrappers.SingleDayWrapper(*args: Any, **kwargs: Any)[source]
Bases:
ModuleWraps any RTnn model to output a single scalar per sample.
Takes the last timestep of the wrapped model’s sequence output, yielding shape (batch, output_channel) instead of (batch, output_channel, seq_length).
- Parameters:
base_model (nn.Module) – Any model with forward signature (batch, C_in, L) -> (batch, C_out, L).
Examples
>>> from rtnn.models.rnn import RNN_LSTM >>> base = RNN_LSTM(feature_channel=14, output_channel=1, ... hidden_size=128, num_layers=2) >>> model = SingleDayWrapper(base) >>> x = torch.randn(32, 14, 365) >>> y = model(x) >>> y.shape torch.Size([32, 1])
- class phenonn.utils.wrappers.permuteWrapper(*args: Any, **kwargs: Any)[source]
Bases:
ModulePermutes input dimensions to match expected order for RTnn models.
RTnn models expect input shape (batch, feature_channels, seq_length). If your data is in (batch, seq_length, feature_channels), this wrapper permutes the dimensions before passing to the base model.
- Parameters:
base_model (nn.Module) – Any model with forward signature (batch, C_in, L) -> (batch, C_out, L).
Examples
>>> from rtnn.models.rnn import RNN_LSTM >>> base = RNN_LSTM(feature_channel=14, output_channel=1, ... hidden_size=128, num_layers=2) >>> model = permuteWrapper(base) >>> x = torch.randn(32, 365, 14) # Note seq_length and feature_channels swapped >>> y = model(x) >>> y.shape torch.Size([32, 1])
- class phenonn.utils.wrappers.LastNDaysWrapper(*args: Any, **kwargs: Any)[source]
Bases:
ModuleWraps any RTnn model to output the last N timesteps.
Takes the last N timesteps of the wrapped model’s sequence output, yielding shape (batch, output_channel, N) instead of (batch, output_channel, seq_length).
Used for gradient-aware loss where we need GCC(t) and GCC(t-1) while keeping the full input window for context.
- Parameters:
base_model (nn.Module) – Any model with forward signature (batch, C_in, L) -> (batch, C_out, L).
n_days (int) – Number of trailing timesteps to keep (default: 2).
Examples
>>> base = RNN_LSTM(feature_channel=16, output_channel=1, ... hidden_size=128, num_layers=2) >>> model = LastNDaysWrapper(base, n_days=2) >>> x = torch.randn(32, 16, 365) >>> y = model(x) >>> y.shape torch.Size([32, 1, 2])
- forward(x: torch.Tensor) torch.Tensor[source]
- Parameters:
x ((batch, feature_channels, seq_length))
- Return type:
(batch, output_channel, n_days)
- class phenonn.utils.wrappers.Every10DaysWrapper(*args: Any, **kwargs: Any)[source]
Bases:
ModuleWraps any RTnn model to output predictions at the 36 LAI observation days.
Extracts the last 365 timesteps of the model output, then selects the 36 positions corresponding to days 5, 15, 25 of each month in a non-leap year.
Input : (B, C_in, L) with L ≥ 365 Output : (B, C_out, 36)
- Parameters:
base_model (nn.Module) – Any model with forward signature (B, C_in, L) -> (B, C_out, L).
Examples
>>> base = RNN_LSTM(feature_channel=31, output_channel=1, ... hidden_size=128, num_layers=2) >>> model = Every10DaysWrapper(base) >>> x = torch.randn(32, 31, 720) >>> y = model(x) >>> y.shape torch.Size([32, 1, 36])
- forward(x: torch.Tensor) torch.Tensor[source]
- Parameters:
x ((batch, feature_channels, seq_length) — seq_length ≥ 365)
- Return type:
(batch, output_channel, 36)
CLI Module
PhenoNN Command Line Interface
- Usage examples:
# Train LSTM model (per-site CSV format) phenonn train –data_dir ./data/DB/ –type lstm –hidden_size 128
# Train on flat CSVs phenonn train-flat –features_csv features.csv –target_csv targets.csv
# Train big model with year-based split phenonn train-big –data_dir ./data/DB/ –type transformer –split_mode year
# Predict (per-site CSV format) phenonn predict –checkpoint ./runs/exp01/checkpoints/best_model.pth –data_dir ./data/DB/
# Predict on flat CSVs phenonn predict-flat –checkpoint ./runs/exp_flat/checkpoints/best_model.pth
# Show version phenonn –version
Version Module
Version information for PhenoNN.
EOF