175 lines
5.7 KiB
Python
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()
|