Files
2026-07-13 13:18:33 +08:00

175 lines
5.7 KiB
Python

# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0
# DeepSpeed Team
import pytest
import torch
import deepspeed.comm as dist
import deepspeed
from deepspeed.accelerator import get_accelerator
from deepspeed.utils import groups
from unit.common import DistributedTest
def skip_on_device():
if get_accelerator().device_name() == "xpu":
pytest.skip("XPU requires a higher version for test")
class TestTPPlanRealHFModels(DistributedTest):
"""End-to-end tests using real HuggingFace models"""
world_size = 2
def test_qwen2_tp_plan_with_zero2(self):
"""Test Qwen2 model + tp_plan + ZeRO2"""
skip_on_device()
try:
from transformers import AutoModelForCausalLM, AutoConfig
except ImportError:
pytest.skip("transformers not installed")
# Create small Qwen2 config
config = AutoConfig.from_pretrained(
"Qwen/Qwen2-7B",
vocab_size=1000,
hidden_size=128,
intermediate_size=256,
num_hidden_layers=2,
num_attention_heads=4,
num_key_value_heads=4,
)
model = AutoModelForCausalLM.from_config(config)
ds_config = {
"train_micro_batch_size_per_gpu": 1,
"tensor_parallel": {
"autotp_size": 2
},
"optimizer": {
"type": "AdamW",
"params": {
"lr": 1e-4
}
},
"zero_optimization": {
"stage": 2
},
"bf16": {
"enabled": True
},
"steps_per_print": 1,
}
engine, _, _, _ = deepspeed.initialize(model=model, model_parameters=model.parameters(), config=ds_config)
assert engine.autotp_size() == 2
# Train for a few steps
for _ in range(3):
input_ids = torch.randint(0, 1000, (1, 16)).to(get_accelerator().current_device_name())
dist.broadcast(
input_ids,
src=groups.get_tensor_model_parallel_src_rank(),
group=groups.get_tensor_model_parallel_group(),
)
outputs = engine(input_ids, labels=input_ids)
engine.backward(outputs.loss)
engine.step()
assert not torch.isnan(outputs.loss)
def test_custom_model_with_custom_tp_plan(self):
"""Test custom model + custom tp_plan"""
skip_on_device()
class CustomTransformerModel(torch.nn.Module):
def __init__(self, hidden_size=64):
super().__init__()
self.config = type(
"Config",
(),
{
"base_model_tp_plan": {
"encoder.*.attention.query": "colwise",
"encoder.*.attention.key": "colwise",
"encoder.*.attention.value": "colwise",
"encoder.*.attention.output": "rowwise",
"encoder.*.ffn.intermediate": "colwise",
"encoder.*.ffn.output": "rowwise",
}
},
)()
# Simple encoder layers
self.encoder = torch.nn.ModuleList([
torch.nn.ModuleDict({
"attention":
torch.nn.ModuleDict({
"query": torch.nn.Linear(hidden_size, hidden_size),
"key": torch.nn.Linear(hidden_size, hidden_size),
"value": torch.nn.Linear(hidden_size, hidden_size),
"output": torch.nn.Linear(hidden_size, hidden_size),
}),
"ffn":
torch.nn.ModuleDict({
"intermediate": torch.nn.Linear(hidden_size, hidden_size * 4),
"output": torch.nn.Linear(hidden_size * 4, hidden_size),
}),
}) for _ in range(2)
])
def forward(self, x):
for layer in self.encoder:
# Simplified attention
q = layer.attention.query(x)
k = layer.attention.key(x)
v = layer.attention.value(x)
attn_out = layer.attention.output(q + k + v)
# FFN
intermediate = torch.relu(layer.ffn.intermediate(attn_out))
x = layer.ffn.output(intermediate)
return x
model = CustomTransformerModel(hidden_size=64)
ds_config = {
"train_micro_batch_size_per_gpu": 1,
"tensor_parallel": {
"autotp_size": 2
},
"optimizer": {
"type": "AdamW",
"params": {
"lr": 1e-4
}
},
"zero_optimization": {
"stage": 0
},
"bf16": {
"enabled": True
},
}
engine, _, _, _ = deepspeed.initialize(model=model, model_parameters=model.parameters(), config=ds_config)
assert engine.autotp_size() == 2
# Training step
input_tensor = torch.randn(2, 4, 64, dtype=torch.bfloat16).to(get_accelerator().current_device_name())
dist.broadcast(
input_tensor,
src=groups.get_tensor_model_parallel_src_rank(),
group=groups.get_tensor_model_parallel_group(),
)
output = engine(input_tensor)
loss = output.mean()
engine.backward(loss)
engine.step()