Skip to content

Restore gp test - #2147

Closed
rayg1234 wants to merge 61 commits into
mainfrom
rgao_restore_gp_test
Closed

Restore gp test#2147
rayg1234 wants to merge 61 commits into
mainfrom
rgao_restore_gp_test

Conversation

@rayg1234

Copy link
Copy Markdown
Contributor

No description provided.

rgao user added 30 commits May 12, 2026 05:48
All-to-all (A2A) communication module for graph parallelism, replacing
the all-gather approach with point-to-point exchange of only boundary
atoms.

Key components:
- GPContext: dataclass holding per-rank atom assignments and A2A metadata
- build_gp_context: builds communication plan from edge connectivity
- AllToAllCollect: autograd-compatible A2A embedding exchange
- all_to_all_collect_compiled: torch.compile-friendly variant using
  functional collectives (no graph break)
- _safe_all_to_all: Gloo fallback for CPU testing
- _sparse_index_exchange: variable-split index exchange

Tests (22 total, all CPU/Gloo):
- 5 unit tests for build_gp_context (context building, global-to-local
  mapping, edge split indices)
- 9 distributed tests comparing A2A vs all-gather correctness
  (forward, backward, multi-rank, spatial partition)
- 8 distributed correctness tests (dense/sparse graphs, multi-dim
  embeddings, index_split + spatial strategies)
Model integration for all-to-all graph parallelism:

eSCN-MD backbone (escn_md.py):
- Add use_all_to_all_gp and gp_partition_strategy config options
- Replace all-gather with A2A embedding exchange when enabled
- Spatial partitioning via Morton Z-order curve
- AABB halo filtering for reduced graph generation input
- Support both autograd and compiled A2A collect variants
- Block allgather+spatial combination (unsupported)

eSCN-MD block (escn_md_block.py):
- Add A2A collect integration in message passing layers
- Use precomputed edge split indices for local/remote separation

Graph generation (compute.py):
- Extend filter_edges_by_node_partition with send_info computation
- Eliminates NCCL index-exchange collective in build_gp_context
- Pass rank_assignments through generate_graph

Embedding/execution backends:
- Thread GP context through embedding and execution layers

Tests:
- Add send_info optimization correctness test
- Expand ParallelPredictUnit tests with A2A+spatial and
  A2A+index_split GP modes (CPU: workers=2, GPU: workers=1)
- 48 parallelism tests + 25 predict tests all pass
Parametrize test_merge_mole_md_consistency with A2A+spatial GP mode
to verify that all-to-all graph parallel with spatial partitioning
works correctly across multiple MD timesteps (NVT and NPT).

Skips A2A modes when workers < 2 since GP requires multi-rank.
2 new test cases pass (NVT+A2A, NPT+A2A), 2 correctly skipped.
…coverage

- Add is_single_system guard in _generate_graph so AABB halo bails
  out for multi-system batches (prevents cell.view(3,3) crash)
- Add defensive assertion in _compute_halo_graph verifying all
  local partition atoms appear in the halo mask
- Add A2A+index_split mode to MD consistency test parametrization
- Add A2A+spatial mode to batch predict test (exercises halo
  bail-out path for multi-system batches)
- Document single-system limitation in _compute_aabb_halo docstring
Extract _resolve_send_metadata and _validate_gp_mappings from the
monolithic build_gp_context (270→120 lines). Validation now uses
fast-path .any().item() checks with full diagnostics only on error.

Add _allgather_index_exchange: packs recv_counts + needed_atoms into
one buffer for a single all-gather call (vs 2x all-to-all). Wired
into eSCN-MD via gp_index_exchange_method constructor parameter.

Benchmarks at GP=64 (8 nodes, 256K atoms): 2xA2A +22.9%, 1xAG +20.3%
vs baseline all-gather GP. Both variants beat baseline at scale.
Benchmarks showed 2xA2A is ~1.5% faster than 1xallgather at GP=64
across 8 nodes (0.593 vs 0.584 ns/day) due to lower communication
volume with variable splits. Remove the inferior allgather variant,
the index_exchange_method parameter, and the dispatch logic. Add
benchmark rationale to _sparse_index_exchange docstring.
Inference always requires autograd for force computation, so the
no-grad compile-friendly path was never hit. Remove the function,
its dispatch branch in escn_md_block, and associated tests.
The complex 13-parameter diagnostic function was hard to follow.
Replaced with two inline asserts for the only error conditions:
negative edge_index_local entries and out-of-bounds send_indices.
v2 radius graph does internal edge filtering so the full edge_index
is never exposed, making send_info derivation in compute.py
impossible. Revert compute.py to main, remove _resolve_send_metadata,
and always use _sparse_index_exchange in build_gp_context.
Remove 6 construction-only fields from GPContext (node_partition,
rank_assignments, needed_atoms, needed_from_ranks, global_to_local,
total_needed_atoms) that are never read after build_gp_context returns.
Update tests to verify through edge_index_local and message passing
instead of accessing removed intermediates.
The 10s timeout causes flaky failures in CI where runners are
resource-constrained and process rendezvous takes longer.
Benchmarks at 64 GPUs showed halo adds ~5% overhead vs plain A2A.
The _sparse_index_exchange already minimizes communication, and
radius_graph_pbc_v2 grid indexing makes graph gen fast enough that
filtering to a halo subset adds cost without measurable savings.

Removes ~150 lines: _compute_aabb_halo, _compute_halo_graph,
use_aabb_halo flag, and the halo call site in _generate_graph.
Also adds timeout_hr to slurm benchmark config.
Resolve conflict in test_predict.py: adopt main's pretrained_checkpoint
fixture and get_predict_unit_for_test helper, add back gp_mode parameter
for A2A test coverage (spatial + index_split).
…lism module

- Add GPMode enum (ALLGATHER, ALL_TO_ALL) with set/get/is_a2a accessors
  to gp_utils so non-model code can query the active GP communication
  pattern without model-level flags
- Move _compute_a2a_partition from escn_md.py to
  common/parallelism/graph_parallel_a2a.py as a public function
- Call set_gp_mode(ALL_TO_ALL) in eSCNMDBackbone.__init__ when
  use_all_to_all_gp is set
- Reset _GP_MODE in cleanup_gp()
scatter_target is now set in _generate_graph for all three paths:
- A2A: gp_ctx.edge_index_local[1]
- Allgather: global_to_local[edge_index[1]]
- No GP: edge_index[1]

This removes the ternary in forward() and the 3-way if/elif/else
for local_scatter_target in Edgewise.forward().
rgao user and others added 27 commits July 9, 2026 22:29
Move graph parallel configuration (group_size, mode, partition) out of
the model constructor into a single GraphParallelConfig dataclass stored
as a global in gp_utils. The model now reads GP config from the global
instead of owning use_all_to_all_gp and gp_partition_strategy params.

Deprecate graph_parallel_group_size in favor of job.graph_parallel block.
Raise ValueError when both are specified with conflicting group sizes.
…size

The CLI calls __post_init__ twice (once from OmegaConf.to_object, once
explicitly). The first call coerces graph_parallel_group_size into
graph_parallel, so the second call would see both set and error. Now
skip coercion when values already match.
Callers already have gp_config in scope or are guarded by
gp_utils.initialized(), so the wrapper adds no value.
The "Allow mixed PBC" PR (#2013) intentionally removed this assertion
on main. Our branch revert (fc7b45c) accidentally restored it.
setup_graph_parallel_groups was called unconditionally for all
multi-worker predict units, causing initialized() to return True
even when no GP was requested. This made _generate_graph access
get_gp_config().mode on a None config. Now GP groups are only
created when gp_config is explicitly provided.
all_to_all_collect now takes only (x_local, gp_ctx) — send_indices
is read from gp_ctx internally.
# Conflicts:
#	tests/core/units/mlip_unit/test_predict.py
Replace raw strings with StrEnum types for mode and partition fields.
StrEnum preserves backward compatibility — string comparisons and
construction with string literals still work. PartitionStrategy is
now an alias of GPPartition to avoid duplication.
Move the no-GP fallback assignment before the empty-edge block so
scatter_target is always present, eliminating both 'in data_dict'
checks.
With multiple workers and no gp_config, each worker ran a redundant
full copy of inference. Now workers > 1 auto-creates a
GraphParallelConfig(group_size=num_workers), and mismatched
group_size vs num_workers raises ValueError.
When gp_config is provided with only mode/partition but group_size
left at default (1), infer it from num_workers instead of erroring.
Only raise ValueError when group_size is explicitly set to a
different value.
# Conflicts:
#	src/fairchem/core/models/uma/escn_md_block.py
Both setup_gp() and setup_graph_parallel_groups() previously left
_GP_CONFIG untouched, so downstream code doing
    gp_utils.get_gp_config().mode
could crash with AttributeError on None. This bit tests that use
setup_gp() via spawn_multi_process (test_utils.py), where callers
never explicitly set a config.

Have both entry points install a default
GraphParallelConfig(group_size=N) when none is already set. Callers
that need non-default settings (A2A, spatial partition) still call
set_gp_config() afterwards — the guard checks `if _GP_CONFIG is None`
so intentional configs are preserved.
…_workers

Move the num_workers-vs-gp_config reconciliation out of predict.py into
gp_utils.resolve_gp_config_for_workers so other multi-worker entry
points can reuse it. Behavior unchanged; caller's config is never
mutated (uses dataclasses.replace).
Co-authored-by: Luis Barroso-Luque <lbluque@users.noreply.github.com>
Re-add the full-model GP correctness test (no-GP / allgather / A2A-spatial /
A2A-index_split at 1/2/4 workers vs single-GPU reference on energy/forces/
stress), which was silently dropped during an earlier main merge. Adapted to
the current gp_config=GraphParallelConfig(...) API and the pretrained fixture
convention. Referenced by graph_parallel_verification.md section 1d.
@meta-cla meta-cla Bot added the cla signed label Aug 11, 2026
@rayg1234 rayg1234 closed this Aug 11, 2026
@rayg1234
rayg1234 deleted the rgao_restore_gp_test branch August 11, 2026 05:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant