chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# DeepSpeed Team
|
||||
|
||||
import torch
|
||||
import deepspeed
|
||||
import pytest
|
||||
from unit.common import DistributedTest
|
||||
|
||||
import deepspeed.comm as dist
|
||||
from deepspeed.linear import LoRAConfig, init_lora
|
||||
from deepspeed.linear.optimized_linear import LoRAOptimizedLinear
|
||||
from unit.simple_model import random_dataloader, SimpleModel
|
||||
|
||||
try:
|
||||
import transformers
|
||||
except ImportError:
|
||||
transformers = None
|
||||
|
||||
if transformers is None:
|
||||
pytest.skip("transformers is required for this test", allow_module_level=True)
|
||||
|
||||
|
||||
def injection_assert(model):
|
||||
# pick out random linear that should have been replaced and initialized
|
||||
q_proj = model.model.layers[1].self_attn.q_proj
|
||||
|
||||
assert isinstance(q_proj, LoRAOptimizedLinear), "injection did not happen"
|
||||
assert q_proj._initialized, "lora was not initialized properly"
|
||||
assert isinstance(q_proj.lora_weight_1, torch.nn.Linear)
|
||||
assert isinstance(q_proj.lora_weight_2, torch.nn.Linear)
|
||||
|
||||
|
||||
class TestEngine(DistributedTest):
|
||||
world_size = 2
|
||||
|
||||
def test_model(self):
|
||||
lora_config = LoRAConfig(lora_r=16, lora_alpha=16, base_weight_sharding=2)
|
||||
quant_config = None
|
||||
hidden_dim = 64
|
||||
nlayers = 4
|
||||
|
||||
with deepspeed.linear.Init(lora_config=lora_config, quant_config=quant_config):
|
||||
model = SimpleModel(hidden_dim=hidden_dim, nlayers=nlayers)
|
||||
|
||||
init_lora(model)
|
||||
|
||||
model_norms = [model.linears[i].weight.norm().item() for i in range(nlayers)]
|
||||
|
||||
ds_config = {
|
||||
"train_batch_size": 2,
|
||||
"steps_per_print": 1,
|
||||
"bf16": {
|
||||
"enabled": True
|
||||
},
|
||||
"optimizer": {
|
||||
"type": "Adam",
|
||||
"params": {
|
||||
"lr": 0.00015
|
||||
}
|
||||
},
|
||||
"zero_optimization": {
|
||||
"stage": 1
|
||||
}
|
||||
}
|
||||
model, *_ = deepspeed.initialize(config=ds_config, model=model, model_parameters=model.parameters())
|
||||
|
||||
engine_norms = [model.module.linears[i].weight.norm().item() for i in range(nlayers)]
|
||||
|
||||
# Ensure that sharded weights are not broadcast during engine init
|
||||
assert engine_norms == model_norms, f"{dist.get_rank()=} base weight norms are not the same after engine init, {engine_norms=} != {model_norms=}"
|
||||
|
||||
data_loader = random_dataloader(model=model,
|
||||
total_samples=50,
|
||||
hidden_dim=hidden_dim,
|
||||
device=model.device,
|
||||
dtype=torch.bfloat16)
|
||||
for n, batch in enumerate(data_loader):
|
||||
loss = model(batch[0], batch[1])
|
||||
model.backward(loss)
|
||||
model.step()
|
||||
|
||||
|
||||
@pytest.mark.skip(
|
||||
"Skipping test for now - the context manager has an issue with ._initialized and .disabled - worked with older transformers probably because it was setting some flags with the same name"
|
||||
)
|
||||
class TestInitTransformers(DistributedTest):
|
||||
world_size = 2
|
||||
|
||||
def test_pretrained_init(self):
|
||||
lora_config = LoRAConfig(lora_r=16, lora_alpha=16, base_weight_sharding=2)
|
||||
quant_config = None
|
||||
|
||||
with deepspeed.linear.Init(lora_config=lora_config, quant_config=quant_config):
|
||||
model = transformers.AutoModelForCausalLM.from_pretrained("llamafactory/tiny-random-Llama-3")
|
||||
|
||||
injection_assert(model)
|
||||
|
||||
def test_config_init(self):
|
||||
lora_config = LoRAConfig(lora_r=16, lora_alpha=16, base_weight_sharding=2)
|
||||
quant_config = None
|
||||
|
||||
config = transformers.AutoConfig.from_pretrained("llamafactory/tiny-random-Llama-3")
|
||||
|
||||
with deepspeed.linear.Init(lora_config=lora_config, quant_config=quant_config):
|
||||
model = transformers.AutoModelForCausalLM.from_config(config)
|
||||
|
||||
injection_assert(model)
|
||||
@@ -0,0 +1,123 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# DeepSpeed Team
|
||||
|
||||
import pytest
|
||||
import torch
|
||||
import deepspeed
|
||||
import deepspeed.comm as dist
|
||||
|
||||
from deepspeed.accelerator import get_accelerator
|
||||
from deepspeed.linear import OptimizedLinear, LoRAConfig, QuantizationConfig
|
||||
from unit.common import DistributedTest
|
||||
|
||||
from deepspeed.ops.op_builder import FPQuantizerBuilder
|
||||
|
||||
if not deepspeed.ops.__compatible_ops__[FPQuantizerBuilder.NAME]:
|
||||
pytest.skip("FPQuantizer op is not available on this system", allow_module_level=True)
|
||||
|
||||
|
||||
class TestBasicLinear(DistributedTest):
|
||||
world_size = 2
|
||||
|
||||
def test(self):
|
||||
lora_config = None
|
||||
quantization_config = None
|
||||
|
||||
input_features = 64 # Number of input features
|
||||
output_features = 64 # Number of output features
|
||||
batch_size = 1 # Number of samples in a batch
|
||||
|
||||
linear_layer = OptimizedLinear(input_dim=input_features,
|
||||
output_dim=output_features,
|
||||
lora_config=lora_config,
|
||||
quantization_config=quantization_config,
|
||||
dtype=torch.bfloat16)
|
||||
|
||||
dummy_input = torch.rand(batch_size, input_features, dtype=torch.bfloat16)
|
||||
output = linear_layer(dummy_input)
|
||||
assert output.shape == (batch_size, output_features)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("base_weight_sharding", [1, 2])
|
||||
class TestLoRALinear(DistributedTest):
|
||||
world_size = 2
|
||||
|
||||
def test(self, base_weight_sharding):
|
||||
rank = dist.get_rank()
|
||||
quantization_config = None
|
||||
|
||||
input_features = 64 # Number of input features
|
||||
output_features = 64 # Number of output features
|
||||
batch_size = 5 # Number of samples in a batch
|
||||
|
||||
lora_config = LoRAConfig(lora_r=16, lora_alpha=16, base_weight_sharding=base_weight_sharding)
|
||||
|
||||
linear_layer = OptimizedLinear(input_dim=input_features,
|
||||
output_dim=output_features,
|
||||
lora_config=lora_config,
|
||||
quantization_config=quantization_config,
|
||||
dtype=torch.bfloat16)
|
||||
device = get_accelerator().current_device_name()
|
||||
linear_layer = linear_layer.to(device)
|
||||
if rank == 0:
|
||||
for n, p in linear_layer.named_parameters():
|
||||
print(f"{n}, {p.shape}")
|
||||
|
||||
dummy_input = torch.rand(batch_size, input_features, device=device, dtype=torch.bfloat16)
|
||||
|
||||
output = linear_layer(dummy_input)
|
||||
assert output.shape == (batch_size, output_features)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("q_bits", [8, 6])
|
||||
class TestQuantLinear(DistributedTest):
|
||||
world_size = 2
|
||||
|
||||
def test(self, q_bits):
|
||||
input_features = 64 # Number of input features
|
||||
output_features = 64 # Number of output features
|
||||
batch_size = 5 # Number of samples in a batch
|
||||
|
||||
lora_config = None
|
||||
quantization_config = QuantizationConfig(q_bits=q_bits)
|
||||
quantization_config.q_dtype = FPQuantizerBuilder.get_default_quant_dtype()
|
||||
|
||||
linear_layer = OptimizedLinear(input_dim=input_features,
|
||||
output_dim=output_features,
|
||||
lora_config=lora_config,
|
||||
quantization_config=quantization_config,
|
||||
dtype=torch.bfloat16)
|
||||
device = get_accelerator().current_device_name()
|
||||
linear_layer = linear_layer.to(device)
|
||||
dummy_input = torch.rand([batch_size, input_features], device=device, dtype=torch.bfloat16)
|
||||
|
||||
output = linear_layer(dummy_input)
|
||||
assert output.shape == (batch_size, output_features)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("base_weight_sharding", [1, 2], ids=['bws1', 'bws2'])
|
||||
@pytest.mark.parametrize("q_bits", [8, 6], ids=['qbit8', 'qbit6'])
|
||||
class TestOptimizedLinear(DistributedTest):
|
||||
world_size = 2
|
||||
|
||||
def test(self, base_weight_sharding, q_bits):
|
||||
input_features = 64 # Number of input features
|
||||
output_features = 64 # Number of output features
|
||||
batch_size = 5 # Number of samples in a batch
|
||||
|
||||
lora_config = LoRAConfig(lora_r=16, lora_alpha=16, base_weight_sharding=base_weight_sharding)
|
||||
quantization_config = QuantizationConfig(q_bits=q_bits)
|
||||
quantization_config.q_dtype = FPQuantizerBuilder.get_default_quant_dtype()
|
||||
|
||||
linear_layer = OptimizedLinear(input_dim=input_features,
|
||||
output_dim=output_features,
|
||||
lora_config=lora_config,
|
||||
quantization_config=quantization_config,
|
||||
dtype=torch.bfloat16)
|
||||
device = get_accelerator().current_device_name()
|
||||
linear_layer = linear_layer.to(device)
|
||||
dummy_input = torch.rand([batch_size, input_features], device=device, dtype=torch.bfloat16)
|
||||
output = linear_layer(dummy_input)
|
||||
assert output.shape == (batch_size, output_features)
|
||||
@@ -0,0 +1,60 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# DeepSpeed Team
|
||||
|
||||
import pytest
|
||||
import torch
|
||||
import deepspeed
|
||||
|
||||
from deepspeed.accelerator import get_accelerator
|
||||
from deepspeed.linear.quantization import QuantizedParameter
|
||||
from deepspeed.linear.config import QuantizationConfig
|
||||
|
||||
from deepspeed.ops.op_builder import FPQuantizerBuilder
|
||||
|
||||
from unit.common import DistributedTest
|
||||
|
||||
if not deepspeed.ops.__compatible_ops__[FPQuantizerBuilder.NAME]:
|
||||
pytest.skip("FPQuantizer op is not available on this system", allow_module_level=True)
|
||||
|
||||
|
||||
class TestQuantParam(DistributedTest):
|
||||
world_size = 1
|
||||
|
||||
@pytest.mark.parametrize('dtype', [torch.half, torch.float])
|
||||
def test_unsupported_dtypes(self, dtype):
|
||||
device = get_accelerator().current_device_name()
|
||||
data = torch.rand(5, 5, device='cpu', dtype=dtype)
|
||||
qp = QuantizedParameter(data)
|
||||
with pytest.raises(AssertionError):
|
||||
qp.to(device)
|
||||
|
||||
def test_requires_grad(self):
|
||||
data = torch.rand(5, 5, dtype=torch.bfloat16)
|
||||
with pytest.raises(ValueError):
|
||||
QuantizedParameter(data, requires_grad=True)
|
||||
|
||||
def test_move_to_accelerator(self):
|
||||
device = get_accelerator().current_device()
|
||||
data = torch.rand(5, 5, device='cpu', dtype=torch.bfloat16)
|
||||
quantization_config = QuantizationConfig()
|
||||
quantization_config.q_dtype = FPQuantizerBuilder.get_default_quant_dtype()
|
||||
qp = QuantizedParameter(data, quantization_config=quantization_config)
|
||||
assert qp.device == torch.device('cpu')
|
||||
qp = qp.to(get_accelerator().current_device_name())
|
||||
assert qp.device == torch.device(device)
|
||||
assert qp.dtype == quantization_config.q_dtype
|
||||
|
||||
def test_hf_clone(self):
|
||||
device = get_accelerator().current_device_name()
|
||||
data = torch.rand(5, 5, device=device, dtype=torch.bfloat16)
|
||||
|
||||
quantization_config = QuantizationConfig(q_bits=6)
|
||||
qp = QuantizedParameter(data, quantization_config=quantization_config)
|
||||
|
||||
# should be able to clone parameter via dict, HF expects this to work
|
||||
qp_copy = QuantizedParameter(qp.data, **qp.__dict__)
|
||||
|
||||
assert all(qp.data == qp_copy.data)
|
||||
assert qp.quantization_config == qp_copy.quantization_config
|
||||
Reference in New Issue
Block a user