Skip to content

Add CNN predictor#645

Open
Milan933-coder wants to merge 10 commits into
mllam:mainfrom
Milan933-coder:cnn-predictor
Open

Add CNN predictor#645
Milan933-coder wants to merge 10 commits into
mllam:mainfrom
Milan933-coder:cnn-predictor

Conversation

@Milan933-coder

@Milan933-coder Milan933-coder commented May 23, 2026

Copy link
Copy Markdown

Describe your changes

Adds a regular-grid CNN predictor path for Neural-LAM.

This PR adds reusable node/grid tensor transforms, ResHRRR-inspired CNN layers, a CNNPredictor StepPredictor, CLI construction for --model cnn_predictor, checkpoint reconstruction support, and focused tests.

The CNN backbone is inspired by the ResHRRR model from HRRRCast: https://arxiv.org/abs/2507.05658.

It includes residual CNN blocks, Squeeze-and-Excitation, and optional FiLM conditioning, but it is not a full HRRRCast reproduction.

Multi-lead training, DDIM/diffusion sampling, and a U-Net backbone are left out of this PR.

No new runtime dependency is required.

Issue Link

refs #590

Type of change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation (Addition or improvements to documentation)

Checklist before requesting a review

  • My branch is up-to-date with the target branch - if not update your fork with the changes from the target branch (use pull with --rebase option if possible).
  • I have performed a self-review of my code
  • For any new/modified functions/classes I have added docstrings that clearly describe its purpose, expected inputs and returned values
  • I have placed in-line comments to clarify the intent of any hard-to-understand passages of my code
  • I have updated the README to cover introduced code changes. Not applicable for this initial predictor implementation.
  • I have added tests that prove my fix is effective or that my feature works
  • I have given the PR a name that clearly describes the change, written in imperative form (context).
  • I have requested a reviewer and an assignee (assignee is responsible for merging). This applies only if you have write access to the repo, otherwise feel free to tag a maintainer to add a reviewer and assignee.

Checklist for reviewers

Each PR comes with its own improvements and flaws. The reviewer should check the following:

  • the code is readable
  • the code is well tested
  • the code is documented (including return types and parameters)
  • the code is easy to maintain

Author checklist after completed review

  • I have added a line to the CHANGELOG describing this change, in a section
    reflecting type of change (add section where missing):
    • added: when you have added new functionality
    • changed: when default behaviour of the code has been changed
    • fixes: when your contribution fixes a bug
    • maintenance: when your contribution is relates to repo maintenance, e.g. CI/CD or documentation

Checklist for assignee

  • PR is up to date with the base branch
  • the tests pass
  • (if the PR is not just maintenance/bugfix) the PR is assigned to the next milestone. If it is not, propose it for a future milestone.
  • author has added an entry to the changelog (and designated the change as added, changed, fixed or maintenance)
  • Once the PR is ready to be merged, squash commits and merge the PR.

@Milan933-coder

Copy link
Copy Markdown
Author

@joeloskarsson please check it .I will move forward after it

@sadamov sadamov added the enhancement New feature or request label Jun 6, 2026
@sadamov sadamov added this to the v0.8.0 (proposed) milestone Jun 6, 2026
Co-authored-by: Codex <codex@openai.com>
@joeloskarsson
joeloskarsson self-requested a review June 8, 2026 07:01
@joeloskarsson

Copy link
Copy Markdown
Collaborator

Please add the full PR template.

Is the CNN the backbone from https://arxiv.org/abs/2507.05658? Would be good to add a reference. I would maybe add just a U-net as a first CNN architecture (to figure out the details that comes with requiring a regular grid), but I am not opposed to this one.

@Milan933-coder

Copy link
Copy Markdown
Author

@joeloskarsson Yes this is ResHRRR Inspired i used the exact blocks used in the paper but not the full implementation .
And about the unet Do you want me to add the setup where the user can change the cnn_backbone as unet or res_hrr .

@Milan933-coder Milan933-coder changed the title CNN_Predictor small Blocks Added Add CNN predictor Jun 28, 2026
Co-authored-by: Codex <codex@openai.com>
@Milan933-coder

Copy link
Copy Markdown
Author

@joeloskarsson yes it is done .I have not addded the unet backbone .If you want i can add

@Sir-Sloth-The-Lazy Sir-Sloth-The-Lazy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry this was a mistake

@Sir-Sloth-The-Lazy Sir-Sloth-The-Lazy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, sorry for the empty review before, I this is really nice, just some issue that I found and thought might bring it to your attention. Thank for your time !

Comment thread neural_lam/cnn_layers.py
Comment on lines +227 to +250
padding_mode: str = "zeros",
):
"""Initialize a shape-preserving residual convolution block."""
super().__init__()
if channels <= 0:
raise ValueError("channels must be positive")
if kernel_size <= 0 or kernel_size % 2 == 0:
raise ValueError("kernel_size must be a positive odd integer")

padding = kernel_size // 2
self.conv1 = nn.Conv2d(
channels,
channels,
kernel_size=kernel_size,
padding=padding,
padding_mode=padding_mode,
)
self.act = nn.SiLU()
self.conv2 = nn.Conv2d(
channels,
channels,
kernel_size=kernel_size,
padding=padding,
padding_mode=padding_mode,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

padding_mode gets passed straight into nn.Conv2d here with nothing checking it against the actual grid shape. PyTorch's reflect mode needs padding < input_size on the padded axis, and circular needs the padding to not wrap around more than once. A grid with a spatial dimension of 1 will crash on the first forward pass here even with the default cnn_kernel_size=3 and reflect, and circular will crash on bigger grids too once the kernel gets large enough. Since --cnn_padding_mode is just an open CLI choice right now, nothing stops someone from hitting this. Might be worth validating grid shape against kernel size and padding mode at construction time, or at least documenting the constraint.

)
grid_features = node_to_grid(grid_features, self.grid_shape)

context = forcing.mean(dim=1) if self.cnn_film else None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This averages forcing over every grid node, so every cell ends up with the exact same FiLM conditioning no matter what the local forcing looks like (boundary vs interior, etc). Not a crash, just seems like it throws away the spatial signal a regional CNN would otherwise want to use per pixel. Was this a deliberate choice (matching how HRRRCast conditions globally), or was per node conditioning the intent?

Comment on lines +92 to +108
da_state_stats = datastore.get_standardization_dataarray("state")
self.register_buffer(
"diff_mean",
torch.tensor(
da_state_stats.state_diff_mean_standardized.values,
dtype=torch.float32,
),
persistent=False,
)
self.register_buffer(
"diff_std",
torch.tensor(
da_state_stats.state_diff_std_standardized.values,
dtype=torch.float32,
),
persistent=False,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block is basically identical to what's already in BaseGraphModel.__init__ (neural_lam/models/step_predictors/graph/base.py, around L76 to L89). Since any delta predicting StepPredictor needs this rescale logic, seems like a good candidate to move up into the shared StepPredictor.__init__ next to state_mean/state_std rather than copying it into every subclass.

@Milan933-coder

Copy link
Copy Markdown
Author

Okay I will look into it

Co-authored-by: Codex <codex@openai.com>
@Milan933-coder

Copy link
Copy Markdown
Author

@joeloskarsson i need yor review .This will be my first PR for the a issue who is being assigned to me so i am excited for your comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants