Add Cross-Unet model for photovoltaic power forecasting#1833
Add Cross-Unet model for photovoltaic power forecasting#1833ipe-zhangyz wants to merge 8 commits into
Conversation
Greptile SummaryThis PR adds an experimental CrossUnet workflow for PV power forecasting. The main changes are:
Important Files Changed
Reviews (1): Last reviewed commit: "refined cross_unet scripts and docs" | Re-trigger Greptile |
| if use_bottleneck_in_decoder and dec_seg_num < out_seg_num: | ||
| raise ValueError( | ||
| f"pred_len={pred_len} (decoder segments={dec_seg_num}) is shorter " | ||
| f"than the encoder bottleneck (segments={out_seg_num}) implied by " | ||
| f"seq_len={seq_len}, seg_len={seg_len}, e_layers={e_layers}. " | ||
| f"Either increase pred_len, decrease e_layers, or decrease seg_len." | ||
| ) |
There was a problem hiding this comment.
When use_bottleneck_in_decoder=True and the decoder has more segments than the encoder bottleneck, the first decoder layer truncates the decoder input to the bottleneck length. The documented 1d and 7d horizons reach this state, so the model can return fewer timesteps than pred_len, and training or evaluation then fails or compares mismatched forecast lengths.
| if use_bottleneck_in_decoder and dec_seg_num < out_seg_num: | |
| raise ValueError( | |
| f"pred_len={pred_len} (decoder segments={dec_seg_num}) is shorter " | |
| f"than the encoder bottleneck (segments={out_seg_num}) implied by " | |
| f"seq_len={seq_len}, seg_len={seg_len}, e_layers={e_layers}. " | |
| f"Either increase pred_len, decrease e_layers, or decrease seg_len." | |
| ) | |
| if use_bottleneck_in_decoder and dec_seg_num != out_seg_num: | |
| raise ValueError( | |
| f"pred_len={pred_len} (decoder segments={dec_seg_num}) must match " | |
| f"the encoder bottleneck (segments={out_seg_num}) implied by " | |
| f"seq_len={seq_len}, seg_len={seg_len}, e_layers={e_layers} when " | |
| f"use_bottleneck_in_decoder=True. Adjust pred_len/seg_len/e_layers " | |
| f"or disable the bottleneck decoder path." | |
| ) |
| frame = _load_generic_csv(cfg) | ||
| if len(frame) < 2 * cfg.seq_len + max(cfg.seq_len, cfg.pred_len): | ||
| raise ValueError( | ||
| f"{cfg.data_file} has {len(frame)} usable rows; at least " |
There was a problem hiding this comment.
This check only verifies that the full CSV can hold one 2 * seq_len + max(seq_len, pred_len) window, but validation and test use 10% splits. For the documented 7d horizon, a file with 2,017 rows passes here while the valid/test splits are only about 200 rows, so RealPVDataset later raises Split ... has no usable windows instead of running the documented workflow.
| saved_data_cfg = checkpoint["data_config"] | ||
| data_cfg = RealPVDataConfig( | ||
| data_file=Path(to_absolute_path(str(saved_data_cfg["data_file"]))), |
There was a problem hiding this comment.
Prediction rebuilds data_cfg from the absolute data_file saved during training, ignoring the data_file override used for the predict or evaluate run. If a user moves the CSV or passes a new copy with the same columns, the workflow still tries to read the original path and fails with FileNotFoundError, or evaluates the old file instead of the requested one.
- Add full Apache-2.0 license headers to real_data.yaml and test_pv_power_cross_unet_real_data.py - Add docstrings to ArrayScaler methods and RealPVDataset properties - Add docstring to main() in train_cross_unet.py - Fix markdown line-length and multiple-blank-lines in CROSS_UNET_USAGE.md and CROSS_UNET_USAGE.zh.md
1fae31d to
d910e01
Compare
- Bug 2: After splitting, verify each val/test partition has at least pred_len rows so RealPVDataset raises a clear error early rather than failing later with a cryptic 'no usable windows' message. - Bug 3: In _run_prediction, prefer cfg.data_file when it resolves to an existing file, falling back to the checkpoint-saved path only when the config still holds the placeholder default. This lets users redirect predict/evaluate to a new CSV without editing the checkpoint.
PhysicsNeMo Pull Request
Description
Summary
This PR adds Cross-Unet, a Transformer-based architecture for photovoltaic (PV) power forecasting, featuring multi-scale temporal encoding, correlation-aware channel attention, and hierarchical cross-attention decoding to fuse historical generation data with weather forecasts, as an experimental model in PhysicsNeMo.
The model is adapted from the paper "Rethinking the use of deep learning methods for photovoltaic power forecasting" (Nat Commun (2026), Zhang Y. et al.), ported to PhysicsNeMo with explicit typed kwargs and integration with PhysicsNeMo training primitives.
What is added
physicsnemo/experimental/models/pv_power/— Cross-Unet implementation including cross-attention, embedding, encoder/decoder componentsexamples/weather/pv_power_cross_unet/— synthetic-data training script (train_cross_unet.py), real-data training script (train_real_cross_unet.py), Hydra configs, and bilingual usage documentationtest/experimental/models/pv_power/cross_unet/test_cross_unet.py— unit tests covering forward pass, state channels, and edge cases;test/examples/weather/test_pv_power_cross_unet_real_data.py— real-data workflow testsKey design
two_stage, etc.)Checklist
Dependencies
Review Process
All PRs are reviewed by the PhysicsNeMo team before merging.
Depending on which files are changed, GitHub may automatically assign a maintainer for review.
We are also testing AI-based code review tools (e.g., Greptile), which may add automated comments with a confidence score.
This score reflects the AI’s assessment of merge readiness and is not a qualitative judgment of your work, nor is
it an indication that the PR will be accepted / rejected.
AI-generated feedback should be reviewed critically for usefulness.
You are not required to respond to every AI comment, but they are intended to help both authors and reviewers.
Please react to Greptile comments with 👍 or 👎 to provide feedback on their accuracy.