Skip to content

Commit 94dedfd

Browse files
committed
Exercise the shared-param traversal without an accelerator
The end-to-end conversion test needs an accelerator and is skipped in most environments, so it cannot show this defect. _get_shared_params reads only self.module, zero_optimization_partition_weights() and the rank, so the tree walk can be driven directly -- the level the bug lives at. Signed-off-by: Udaya Tejas <udayatejas2004@gmail.com>
1 parent b7d2231 commit 94dedfd

1 file changed

Lines changed: 38 additions & 0 deletions

File tree

‎tests/unit/checkpoint/test_convert_checkpoint.py‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,3 +207,41 @@ def test_convert_zero_checkpoint_with_shared_submodule(self, tmpdir):
207207

208208
model = ModelWithSharedSubmodule()
209209
model.load_state_dict(state_dict, strict=True)
210+
211+
212+
class _SharedSubmoduleModel(nn.Module):
213+
"""A module that aliases an entire child under a second attribute name."""
214+
215+
def __init__(self):
216+
super().__init__()
217+
self.layer0 = nn.Linear(4, 4)
218+
self.layer1 = nn.Linear(4, 4)
219+
self.layer2 = self.layer1
220+
221+
222+
def test_get_shared_params_records_aliased_submodule(monkeypatch):
223+
"""The traversal itself must not drop an aliased submodule's params.
224+
225+
The end-to-end conversion test above needs an accelerator and is skipped in
226+
most environments, so it cannot demonstrate this defect. `_get_shared_params`
227+
only reads `self.module`, `zero_optimization_partition_weights()` and the
228+
rank, so the tree walk can be exercised directly -- which is the level the
229+
bug actually lives at.
230+
"""
231+
from deepspeed.runtime.engine import DeepSpeedEngine
232+
import deepspeed.comm as dist
233+
234+
monkeypatch.setattr(dist, "get_rank", lambda *a, **k: 0)
235+
236+
class _Engine:
237+
module = _SharedSubmoduleModel()
238+
239+
def zero_optimization_partition_weights(self):
240+
return False
241+
242+
shared = DeepSpeedEngine._get_shared_params(_Engine())
243+
244+
# layer2 aliases layer1 in full, so BOTH of its params must be recorded as
245+
# shared -- otherwise they are absent from the reconstructed state dict.
246+
assert shared.get("layer2.weight") == "layer1.weight"
247+
assert shared.get("layer2.bias") == "layer1.bias"

0 commit comments

Comments
 (0)