Skip to content

Feature/encoder and decoder healpix cell parallelism - #2705

Open
pkuyyj wants to merge 15 commits into
ecmwf:developfrom
pkuyyj:feature/decoder-healpix-cell-parallelism
Open

Feature/encoder and decoder healpix cell parallelism#2705
pkuyyj wants to merge 15 commits into
ecmwf:developfrom
pkuyyj:feature/decoder-healpix-cell-parallelism

Conversation

@pkuyyj

@pkuyyj pkuyyj commented Jul 31, 2026

Copy link
Copy Markdown

Description

Based on #2700, we further implemented the spatial parallelism of the decoder. This is also done during the Hackathon in Zurich.

Memory allocation profiling results:

  • Before:
image
  • After encoder parallelization (16 ranks):
image
  • After encoder and decoder parallelization (16 ranks):
image

Issue Number

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

@github-actions github-actions Bot added the model Related to model training or definition (not generic infra) label Jul 31, 2026

@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.

Didn't go through the code in detail but here are some high level comments, in addition to what we already discussed yesterday. For some pieces I probably also need an explanation at some point.

Comment thread config/default_config.yml Outdated

# Split the encoder's HEALPix/location dimension across this many consecutive
# distributed ranks through local assimilation.
encoder_spatial_parallel_size: 4

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.

We should have a section distributed where we collect everything related to parallelization, including with_ddp, with_fsdp etc. Please try to structure it well so that we can pass sub-dicts of it to the relevant parts

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.

Remove encoder_ since we will have homogeneous domain decomposition througout the model

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed. The corresponding configs are also updated.

Comment thread src/weathergen/utils/distributed.py Outdated
import torch.distributed as dist

SYNC_TIMEOUT_SEC = 60 * 60 # 1 hour
_ENCODER_SPATIAL_GROUPS: dict[int, tuple[dist.ProcessGroup, int]] = {}

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.

Remove ENCODER

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed

Comment thread src/weathergen/utils/distributed.py Outdated
return dist.get_rank()


def get_encoder_spatial_parallel_size(cf) -> int:

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.

Remove _encoder

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed

num_cells: int,
cell_start: int,
cell_end: int,
) -> list[np.typing.NDArray[np.int64]]:

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.

What are the assumptions on cell_start and cell_end? The goal of the function is to split the data in all healpix cells according to regions?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The assumptions are based on the nested Healpix cell numbering. Detailed explanation can be found below.

self.world_size = cf.world_size
# Ranks in one encoder-spatial group must consume the same batch. Data
# parallelism therefore operates across groups, not across individual ranks.
spatial_parallel_size = get_encoder_spatial_parallel_size(cf)

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 information should be organized in a small class that is defined in utils.distributed. This will also be need in model.

Comment thread src/weathergen/model/encoder.py Outdated
"""

cell_lens = torch.sum(batch.tokens_lens, 2).flatten()
tokens_lens_global = batch.tokens_lens

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 encapsulate this into a separate function

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed

Comment thread src/weathergen/model/engines.py Outdated

if batch.tokens_lens.shape[2] == 1:
if not x_embeds:
# A spatial rank can legitimately own a domain with no observations

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.

Tighten comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed

Comment thread src/weathergen/model/model.py Outdated
self.q_cells: torch.Tensor | None = None
self.streams: dict[str, typing.Any] = cf.streams
self.target_token_engines = None
self.decoder_spatial_parallel_group = None

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 in MultiStreamDataSampler: we want a class for this

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed

Comment thread src/weathergen/model/model.py Outdated
# Decoder cells follow the encoder's contiguous spatial-rank ownership.
# Keeping the same group also means a cell's nine-token HEALPix
# neighbourhood is sent to the rank that already owns that cell.
self.decoder_spatial_parallel_group = self.encoder.spatial_parallel_group

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
Author

Choose a reason for hiding this comment

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

Agreed

Comment thread src/weathergen/model/model.py Outdated
],
dim=1,
)
gathered_pred = all_gather(pred, group=self.decoder_spatial_parallel_group)

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.

Anemoi has this function wrapped. Worth to have a discussion of what the pros and cons are.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed. A wrapper could centralize the process-group handling and hide the tensor-collective details. For now, I would keep the explicit call because this is the only use site and the required operation is clear, but we can revisit this if the pattern appears elsewhere.

@pkuyyj
pkuyyj force-pushed the feature/decoder-healpix-cell-parallelism branch from 211eb4a to 2e3f59a Compare August 11, 2026 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

model Related to model training or definition (not generic infra)

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants