Skip to content

Commit be14354

Browse files
committed
feat(v7-c05): resume across world-size change via V7-C02 loader
Closes V7-C05 (cppmega-mlx-fazl): pins that V7-C02 sharded save+load round-trips correctly across all four canonical world-size transitions (8→1, 1→8, 4→2, 2→4) on a tiny model. Full topology re-sharding for tensor-parallel splits is a deeper follow-up; this commit pins the building-block coverage. Tests (tests/v4/test_checkpoint_topology.py): 5/5 — * Save N → Load (single-rank) reconstructs bitwise-equal state for (N,M) in {(8,1),(1,8),(4,2),(2,4)}. * load_sharded_for_rank across all ranks of the new world_size combines back to the full key set. * Invalid rank rejected.
1 parent 10c8a14 commit be14354

1 file changed

Lines changed: 63 additions & 0 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""V7-C05: resume across world-size change uses V7-C02 sharded loader."""
2+
3+
from __future__ import annotations
4+
5+
import mlx.core as mx
6+
import pytest
7+
8+
from cppmega_v4.runtime.checkpoint_shard import (
9+
load_sharded, load_sharded_for_rank, save_sharded,
10+
)
11+
12+
13+
def _state(seed: int = 0) -> dict[str, mx.array]:
14+
return {
15+
f"layer{i}.w": mx.random.normal(shape=(8, 16),
16+
key=mx.random.key(seed + i))
17+
for i in range(8)
18+
}
19+
20+
21+
@pytest.mark.parametrize("save_world,load_world",
22+
[(8, 1), (1, 8), (4, 2), (2, 4)])
23+
def test_v7_c05_resume_across_world_size_recovers_full_state(
24+
tmp_path, save_world, load_world,
25+
):
26+
"""Save N → Load M reconstructs the full param tree.
27+
28+
`save_sharded` with num_shards=save_world stores
29+
weight_map per key. On load, calling load_sharded (single rank
30+
reads everything) reconstructs bitwise-equal full state
31+
regardless of original shard count.
32+
33+
For load_world>1 verify rank-N-of-M slices combine back to
34+
the full set across ranks."""
35+
state = _state()
36+
save_sharded(state, tmp_path, num_shards=save_world)
37+
full = load_sharded(tmp_path / "model.index.json")
38+
assert set(full.keys()) == set(state.keys())
39+
for k in state:
40+
assert mx.allclose(full[k], state[k], atol=0.0)
41+
42+
# Per-rank load on the new topology — collect across all ranks
43+
# in the load_world.
44+
if load_world > 1:
45+
combined: dict[str, mx.array] = {}
46+
for r in range(load_world):
47+
combined.update(load_sharded_for_rank(
48+
tmp_path / "model.index.json",
49+
rank=r, world_size=load_world,
50+
))
51+
assert set(combined.keys()) == set(state.keys()), (
52+
f"world_size={load_world} round-robin missed keys: "
53+
f"{set(state) - set(combined)}"
54+
)
55+
56+
57+
def test_v7_c05_invalid_rank_rejected(tmp_path):
58+
save_sharded(_state(), tmp_path, num_shards=2)
59+
with pytest.raises(ValueError):
60+
load_sharded_for_rank(
61+
tmp_path / "model.index.json",
62+
rank=5, world_size=2,
63+
)

0 commit comments

Comments
 (0)