Skip to content

Fix bugs related to uninitialised GPU memory and istep - #2722

Open
sophie-xhonneux wants to merge 16 commits into
develop-ssl-diffusion-v1from
sophiex/dev-ssl/ssl-and-diff-july
Open

Fix bugs related to uninitialised GPU memory and istep#2722
sophie-xhonneux wants to merge 16 commits into
develop-ssl-diffusion-v1from
sophiex/dev-ssl/ssl-and-diff-july

Conversation

@sophie-xhonneux

@sophie-xhonneux sophie-xhonneux commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Description

Change torch.empty to torch.zeros in StreamEmbedder to ensure there is no uninitialised GPU memory, also skip streams
with stream embed Identity when considering memory to allocate (#2721)

Fix istep not being passed along in loss_calculator.py (#2720)

Config changes for space JEPA (no need to review)

Remark: Linting is broken, but this was true before.

Issue Number

Closes #2720 #2721

Is this PR a draft? Mark it as draft.

Checklist before asking for review

  • I have performed a self-review of my code
  • My changes comply with basic sanity checks:
    • I have fixed formatting issues with ./scripts/actions.sh lint
    • I have run unit tests with ./scripts/actions.sh unit-test
    • I have documented my code and I have updated the docstrings.
    • I have added unit tests, if relevant
  • I have tried my changes with data and code:
    • I have run the integration tests with ./scripts/actions.sh integration-test
    • (bigger changes) I have run a full training and I have written in the comment the run_id(s): launch-slurm.py --time 60
    • (bigger changes and experiments) I have shared a hegdedoc in the github issue with all the configurations and runs for this experiments
  • I have informed and aligned with people impacted by my change:
    • for config changes: the MatterMost channels and/or a design doc
    • for changes of dependencies: the MatterMost software development channel

@sophie-xhonneux
sophie-xhonneux changed the base branch from develop to develop-ssl-diffusion-v1 August 4, 2026 07:25
@github-actions github-actions Bot added infra Issues related to infrastructure model Related to model training or definition (not generic infra) labels Aug 4, 2026
…poisoning (#2717)

NaN * 0 = NaN, so a non-finite per-token loss at a mask-excluded position
poisoned the whole per-sample sum in _masked_l1_loss_per_sample. Use
torch.where(mask.bool(), ...) so excluded positions contribute exactly 0;
NaNs inside the mask still propagate as before.
…2718)

The skip decision was evaluated only on rank 0 and broadcast, so a
NaN/spike loss on any other rank was never skipped and its gradients
poisoned the all-reduce. Now every rank checks its local loss and the
per-rank flags are combined with an all-reduce MAX (logical OR), so a
spike on any rank skips the batch on all ranks. Logging remains
rank-0-only.

@clessig clessig left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Minor comments. This PR seems to have some unrelated changes and would break FSDP again, I think.

# Intermediate encoder levels are tapped before the encoder's final LayerNorm, so they
# arrive on very different (and much larger) scales than the final level. Normalize each
# level before concatenating so the fusion and the downstream SSL head see a common scale.
self.level_norms = nn.ModuleList([nn.LayerNorm(dim_embed) for _ in range(num_levels)])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This change seems unrelated to the problem that is addressed in the PR?


def forward(self, levels: list[torch.Tensor]) -> torch.Tensor:
return self.proj(torch.cat(levels, dim=-1))
normed = [norm(level) for norm, level in zip(self.level_norms, levels, strict=True)]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same as above

Comment thread src/weathergen/model/model.py Outdated
num_params_q_aux = (
np.prod(self.encoder.q_aux.shape) if self.encoder.q_aux.requires_grad else 0
)
# if self.encoder.q_aux:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This change was introduced to make FSDP work

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

see my comment below, the statement breaks in single GPU mode if q_aux exists because it is a nn.Parameter tensor so not bool or can be reduced to bool

Comment thread src/weathergen/model/model.py Outdated
print(f" Learnable spatial queries: {num_params_q_cells:,}")
if self.encoder.q_aux:
print(f" Learnable auxiliary queries: {num_params_q_aux:,}")
# if self.encoder.q_aux:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same as above

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

we are printing parameters, this should not break FSDP, it doesn't create the parameters

@@ -0,0 +1,86 @@
# (C) Copyright 2024 WeatherGenerator contributors.

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.

Configs

Comment thread src/weathergen/model/model.py Outdated
num_params_q_aux = (
np.prod(self.encoder.q_aux.shape) if self.encoder.q_aux.requires_grad else 0
)
# if self.encoder.q_aux:

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.

Need to revert this I think

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this broke in single GPU mode for me :/ can you explain the error to me?

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.

Here is the PR:

#2686

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

we are in the function that prints parameters, does not seem like it will break FSDP

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.

Yes I think you're right it is not fsdp but whether it breaks I think depends if you have register tokens or not right?

You do have register tokens (I guess), so now it works. But if we want to run with 0 register tokens with this code, we are now doing shape of None and we get an error?

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.

So I think we should actually have:

if self.encoder.q_aux is not None:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes! you are right, I couldn't think of the right check at midnight yesterday so I commented it out, but what you right is correct I think

token_counts = mask_f.sum(dim=-1)
valid_samples = token_counts > 0
per_sample_loss = (per_token_loss * mask_f).sum(dim=-1) / token_counts.clamp(min=1.0)
# torch.where (not multiply): NaN at mask-excluded positions must not poison the sum.

@shmh40 shmh40 Aug 4, 2026

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.

Can merge this PR in last so it is after the PR that explicitly does this

if OmegaConf.is_dict(conf):
for key in list(conf.keys()):
key = str(key)
# key = str(key) # this lines breaks target_source_correspondence please stop re introducing it

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.

Do we need this for anything else in the config?

I get around it with e.g. target_source_correspondence: {"0": {"0": independent}} in target source I think, in case it is necessary for something else in the config

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I would ask the question the other way around, is there any reason this line is needed, it breaks the type assumptions of YAML

@clessig clessig left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can we clean up the PR so that we don't change 20 files unrelated to the problems. In engines.py are also changes that are unrelated?

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

Labels

infra Issues related to infrastructure model Related to model training or definition (not generic infra)

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

istep not passed to loss modules

3 participants