Skip to content

Commit 2e4247e

Browse files
committed
[AutoTP] Allow ZeRO stage 3 inference with tensor parallelism
Replace the unconditional `zero_optimization_stage() <= 2` guard with one that only blocks `autotp + zero_stage == 3` when an optimizer is present. The inference path (no optimizer -> DummyOptim -> DeepSpeedZeRoOffload) is now permitted; the training path (optimizer -> DeepSpeedZeroOptimizer_Stage3) is blocked with a clear NotImplementedError. Rationale: training under autotp+ZeRO-3 itself works (forward/backward/step and gradient norms match the non-TP baseline), but the TP-aware checkpoint consolidation path (`_consolidated_16bit_state_dict` / `save_16bit_model`) gathers only the ZeRO data-parallel partition and would silently write rank 0's TP shard instead of the full weight, producing incomplete checkpoints. Training support will land alongside the checkpoint fix (tracked separately). Signed-off-by: Guokai Ma <guokai.ma@intel.com>
1 parent 4c275f9 commit 2e4247e

5 files changed

Lines changed: 64 additions & 7 deletions

File tree

deepspeed/runtime/engine.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -628,10 +628,15 @@ def _configure_tensor_parallel_states(self, model):
628628
and registering a pre-hook to ensure that the Dataloader inputs are consistent across ranks.
629629
"""
630630
self._set_client_model(model)
631-
# sanity check
632-
# currently, the compatibility between 'autotp' and 'zero > 1' has not been validated
633-
assert self.zero_optimization_stage(
634-
) <= 2, "Currently, the compatibility between 'autotp' and 'zero_stage = 3' has not been validated"
631+
# AutoTP + ZeRO-3 is supported only for ZeRO-Inference (no optimizer).
632+
# With an optimizer the TP-aware checkpoint consolidation path is not yet
633+
# implemented, so save_16bit_model()/save_checkpoint would silently drop
634+
# TP shards. Block the training path until that is fixed (tracked separately).
635+
if self.zero_optimization_stage() > 2 and (self.client_optimizer or self.optimizer_name()):
636+
raise NotImplementedError("AutoTP together with ZeRO stage 3 is currently supported only for inference "
637+
"(no optimizer). Running it with an optimizer is disabled because TP-aware "
638+
"checkpoint consolidation is not yet implemented and would silently produce "
639+
"incomplete checkpoints.")
635640

636641
self.mpu = groups
637642
self.mpu._init_tp_mesh_device(tensor_model_parallel_size=self.autotp_size())

docs/_pages/config-json.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,7 @@ Configuring the asynchronous I/O module for offloading parameter and optimizer s
763763
| Submit requests to storage device in an overlapped fashion without waiting for completion of earlier requests. | `true` |
764764

765765
### Tensor Parallel (AutoTP)
766-
Configure AutoTP tensor parallelism for training via the DeepSpeed config and hybrid TP + ZeRO. AutoTP supports ZeRO stages 0, 1, and 2 (stage 3 is not supported). `deepspeed.tp_model_init()` remains supported for backward compatibility but is not required when `tensor_parallel` is set in the config.
766+
Configure AutoTP tensor parallelism for training via the DeepSpeed config and hybrid TP + ZeRO. AutoTP supports ZeRO stages 0, 1, and 2. ZeRO stage 3 is supported only for inference (no optimizer); training with stage 3 is not yet supported. `deepspeed.tp_model_init()` remains supported for backward compatibility but is not required when `tensor_parallel` is set in the config.
767767

768768
When a HuggingFace model provides a built-in `tp_plan` (via `model.config.base_model_tp_plan`), DeepSpeed automatically detects and uses it. In this case, neither `preset_model` nor `partition_config` is required -- just set `autotp_size`. If `partition_config` is also provided, it takes precedence over the model's `tp_plan`.
769769
```json

docs/_tutorials/autotp-training.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ For Grouped Query Attention with different Q/K/V sizes:
212212

213213
## Limitations
214214

215-
1. **ZeRO Stage 3 not supported**: AutoTP currently only works with ZeRO stages 0, 1, and 2.
215+
1. **ZeRO Stage 3 training not supported**: AutoTP with ZeRO stage 3 is supported only for inference (no optimizer). Training with an optimizer is blocked until TP-aware checkpoint consolidation is implemented.
216216

217217
2. **TP size must divide model dimensions**: The tensor parallel size must evenly divide the attention head count and hidden dimensions.
218218

docs/code-docs/source/training.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ See :ref:`autotp-training-init-details` for more details.
392392
)
393393
394394
.. note::
395-
AutoTP training supports ZeRO stages 0, 1, and 2. ZeRO Stage 3 is not supported.
395+
AutoTP training supports ZeRO stages 0, 1, and 2. ZeRO stage 3 is supported only for inference (no optimizer).
396396

397397
.. _autotp-training-init-details:
398398

tests/unit/model_parallelism/test_autotp_training.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,58 @@ def test(self, tp_size: int):
185185
assert groups.get_data_parallel_world_size() == dp_size
186186

187187

188+
@pytest.mark.parametrize("tp_size", [2, 4])
189+
class TestAutoTpZeroStage3(DistributedTest):
190+
"""AutoTP + ZeRO stage 3 is supported only for ZeRO-Inference (no optimizer).
191+
192+
The training path (optimizer present) is blocked because TP-aware checkpoint
193+
consolidation is not yet implemented; the inference path (no optimizer ->
194+
DummyOptim -> DeepSpeedZeRoOffload) must initialize.
195+
"""
196+
197+
world_size = 4
198+
reuse_dist_env = False
199+
200+
def _build_config(self, tp_size: int, with_optimizer: bool) -> dict:
201+
config_dict = {
202+
"train_micro_batch_size_per_gpu": 1,
203+
"tensor_parallel": {
204+
"autotp_size": tp_size,
205+
"partition_config": {
206+
"use_default_specs": False,
207+
"layer_specs": [{
208+
"patterns": [r".*\.weight$"],
209+
"partition_type": "column",
210+
}],
211+
}
212+
},
213+
"zero_optimization": {
214+
"stage": 3
215+
}
216+
}
217+
if with_optimizer:
218+
config_dict["optimizer"] = {"type": "Adam", "params": {"lr": 1e-6}}
219+
if preferred_dtype() is torch.float16:
220+
config_dict["fp16"] = {"enabled": True}
221+
elif preferred_dtype() is torch.bfloat16:
222+
config_dict["bf16"] = {"enabled": True}
223+
return config_dict
224+
225+
def test_autotp_zero3_training_blocked(self, tp_size: int):
226+
skip_on_device()
227+
model = SimpleModel(hidden_dim=64)
228+
config_dict = self._build_config(tp_size, with_optimizer=True)
229+
with pytest.raises(NotImplementedError, match="only for inference"):
230+
deepspeed.initialize(model=model, model_parameters=model.parameters(), config=config_dict)
231+
232+
def test_autotp_zero3_inference(self, tp_size: int):
233+
skip_on_device()
234+
model = SimpleModel(hidden_dim=64)
235+
config_dict = self._build_config(tp_size, with_optimizer=False)
236+
model, _, _, _ = deepspeed.initialize(model=model, model_parameters=model.parameters(), config=config_dict)
237+
assert groups.get_tensor_model_parallel_world_size() == tp_size
238+
239+
188240
class TestTpModelInitCompatibility(DistributedTest):
189241
world_size = 4
190242
reuse_dist_env = False

0 commit comments

Comments
 (0)