chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# DeepSpeed Team
|
||||
@@ -0,0 +1,120 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# DeepSpeed Team
|
||||
|
||||
from typing import List
|
||||
|
||||
import pytest
|
||||
import torch
|
||||
|
||||
from deepspeed.accelerator import get_accelerator
|
||||
from deepspeed.inference.v2.model_implementations.flat_model_helpers import (
|
||||
flatten_inference_model,
|
||||
restore_inference_model,
|
||||
)
|
||||
from deepspeed.inference.v2.model_implementations.layer_container_base import LayerContainer
|
||||
from .utils import SimpleParam, DummyInferenceModel
|
||||
|
||||
|
||||
class TransformerLayerContainer(LayerContainer):
|
||||
"""
|
||||
Stub layer container
|
||||
"""
|
||||
PARAM_MAPPING = {
|
||||
"param_1": "param_1.param",
|
||||
"param_2": "param_2.param",
|
||||
}
|
||||
|
||||
param_1: SimpleParam
|
||||
|
||||
param_2: SimpleParam
|
||||
|
||||
|
||||
class NonTransformerContainer(LayerContainer):
|
||||
"""
|
||||
Stub layer container
|
||||
"""
|
||||
PARAM_MAPPING = {
|
||||
"param_1": "param_1.param",
|
||||
"param_2": "param_2.param",
|
||||
"param_3": "param_3.param",
|
||||
}
|
||||
|
||||
param_1: SimpleParam
|
||||
|
||||
param_2: SimpleParam
|
||||
|
||||
param_3: SimpleParam
|
||||
|
||||
|
||||
@pytest.mark.inference_v2
|
||||
def test_contiguify_roundtrip():
|
||||
"""
|
||||
Validate that contiguify round trips and reconstructions are correct.
|
||||
"""
|
||||
model = DummyInferenceModel()
|
||||
|
||||
n_layers = 2
|
||||
transformer_params = []
|
||||
transformer_containers = []
|
||||
|
||||
# Create parameters and populate them into the containers
|
||||
for i in range(n_layers):
|
||||
transformer_containers.append(TransformerLayerContainer(model))
|
||||
layer_params = []
|
||||
for j in range(2):
|
||||
layer_params.append(torch.rand(16, 16))
|
||||
transformer_containers[i].set_dependency(f"param_{j+1}", layer_params[j])
|
||||
|
||||
layer_params = [p.to(get_accelerator().current_device()) for p in layer_params]
|
||||
|
||||
transformer_params.append(layer_params)
|
||||
assert transformer_containers[i].is_populated == True
|
||||
|
||||
non_transformer_params = []
|
||||
non_transformer_container = NonTransformerContainer(model)
|
||||
|
||||
for i in range(3):
|
||||
non_transformer_params.append(torch.rand(16, 16).permute(1, 0))
|
||||
non_transformer_container.set_dependency(f"param_{i+1}", non_transformer_params[i])
|
||||
|
||||
non_transformer_params = [p.to(get_accelerator().current_device()) for p in non_transformer_params]
|
||||
|
||||
def validate_containers(t_containers: List[LayerContainer], n_t_containers: LayerContainer,
|
||||
t_params: List[List[torch.Tensor]], n_t_params: List[torch.Tensor]):
|
||||
"""
|
||||
Validate params match what is on the containers.
|
||||
"""
|
||||
for i in range(n_layers):
|
||||
l_c = t_containers[i]
|
||||
|
||||
assert l_c.is_initialized == True
|
||||
|
||||
assert torch.equal(l_c.param_1, t_params[i][0])
|
||||
assert torch.equal(l_c.param_2, t_params[i][1])
|
||||
|
||||
assert n_t_containers.is_initialized == True
|
||||
assert torch.equal(n_t_containers.param_1, n_t_params[0])
|
||||
assert torch.equal(n_t_containers.param_2, n_t_params[1])
|
||||
assert torch.equal(n_t_containers.param_3, n_t_params[2])
|
||||
assert not n_t_containers.param_1.is_contiguous()
|
||||
assert not n_t_containers.param_2.is_contiguous()
|
||||
assert not n_t_containers.param_3.is_contiguous()
|
||||
|
||||
buffer, metadata = flatten_inference_model(transformer_containers, non_transformer_container, "NoOpPolicy")
|
||||
|
||||
# Validate containers before contiguify
|
||||
validate_containers(transformer_containers, non_transformer_container, transformer_params, non_transformer_params)
|
||||
|
||||
# Validate restore pass
|
||||
transformer_containers_r = []
|
||||
for i in range(n_layers):
|
||||
transformer_containers_r.append(TransformerLayerContainer(model))
|
||||
|
||||
non_transformer_container_r = NonTransformerContainer(model)
|
||||
|
||||
restore_inference_model(buffer, metadata, transformer_containers_r, non_transformer_container_r)
|
||||
|
||||
validate_containers(transformer_containers_r, non_transformer_container_r, transformer_params,
|
||||
non_transformer_params)
|
||||
@@ -0,0 +1,48 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# DeepSpeed Team
|
||||
|
||||
import pytest
|
||||
import torch
|
||||
|
||||
from deepspeed.inference.v2.inference_parameter import InferenceParameter
|
||||
from deepspeed.inference.v2.model_implementations.layer_container_base import LayerContainer
|
||||
|
||||
from .utils import SimpleParam, DummyInferenceModel
|
||||
|
||||
|
||||
class ParentLayer(LayerContainer):
|
||||
"""
|
||||
A layer that has a dependency on a simple parameter.
|
||||
"""
|
||||
|
||||
param_1: SimpleParam
|
||||
|
||||
|
||||
class ChildLayer(ParentLayer):
|
||||
"""
|
||||
A layer that inherits from another layer.
|
||||
"""
|
||||
|
||||
param_2: SimpleParam
|
||||
|
||||
|
||||
@pytest.mark.inference_v2
|
||||
def test_layer_inheritance():
|
||||
inference_model = DummyInferenceModel()
|
||||
|
||||
multi_param_layer = ChildLayer(inference_model)
|
||||
|
||||
assert multi_param_layer.n_params == 2
|
||||
assert multi_param_layer.is_initialized is False
|
||||
|
||||
multi_param_layer.param_1.param = torch.ones(16, 16)
|
||||
|
||||
assert multi_param_layer.is_initialized is False
|
||||
|
||||
multi_param_layer.param_2.param = torch.full((16, 16), 2.0)
|
||||
|
||||
assert multi_param_layer.is_populated is True
|
||||
assert isinstance(multi_param_layer.param_1, InferenceParameter)
|
||||
assert isinstance(multi_param_layer.param_2, InferenceParameter)
|
||||
@@ -0,0 +1,168 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# DeepSpeed Team
|
||||
|
||||
import pytest
|
||||
import torch
|
||||
|
||||
from deepspeed.inference.v2.allocator import on_device
|
||||
from deepspeed.inference.v2.inference_parameter import InferenceParameter
|
||||
from deepspeed.inference.v2.model_implementations.parameter_base import ParameterBase, ParamList
|
||||
from deepspeed.inference.v2.model_implementations.layer_container_base import LayerContainer
|
||||
|
||||
|
||||
class MultiDependencyContainer(ParameterBase):
|
||||
|
||||
dependency_1: torch.Tensor
|
||||
|
||||
dependency_2: torch.Tensor
|
||||
|
||||
@on_device
|
||||
def finalize(self) -> torch.Tensor:
|
||||
param = torch.cat([self.dependency_1, self.dependency_2])
|
||||
return InferenceParameter.initialize(param)
|
||||
|
||||
|
||||
class ListDependencyContainer(ParameterBase):
|
||||
|
||||
dependencies: ParamList("list_items") # noqa: F821
|
||||
|
||||
@on_device
|
||||
def finalize(self) -> torch.Tensor:
|
||||
param = torch.cat(tuple(self.dependencies))
|
||||
return InferenceParameter.initialize(param)
|
||||
|
||||
|
||||
class MappingLayer(LayerContainer):
|
||||
PARAM_MAPPING = {
|
||||
"model.val.item.d_1": "multi_depend.dependency_1",
|
||||
"model.val.item.d_2": "multi_depend.dependency_2",
|
||||
"model.list_vals.*.d": "list_depend.dependencies"
|
||||
}
|
||||
|
||||
multi_depend: MultiDependencyContainer
|
||||
|
||||
list_depend: ListDependencyContainer
|
||||
|
||||
|
||||
class SubMappingLayer(MappingLayer):
|
||||
PARAM_MAPPING = {
|
||||
"model.val.item2.d_1": "multi_depend2.dependency_1",
|
||||
"model.val.item2.d_2": "multi_depend2.dependency_2",
|
||||
}
|
||||
|
||||
multi_depend2: MultiDependencyContainer
|
||||
|
||||
|
||||
class DoubleMappingLayer(LayerContainer):
|
||||
PARAM_MAPPING = {
|
||||
"model.val.item.d_1": ["multi_depend.dependency_1", "multi_depend.dependency_2"],
|
||||
}
|
||||
|
||||
multi_depend: MultiDependencyContainer
|
||||
|
||||
|
||||
class InferenceModel:
|
||||
|
||||
@property
|
||||
def list_items(self) -> int:
|
||||
return 16
|
||||
|
||||
|
||||
@pytest.mark.inference_v2
|
||||
def test_mapping_syntax():
|
||||
model = InferenceModel()
|
||||
|
||||
mapping_layer = MappingLayer(model)
|
||||
|
||||
mapping_layer.set_dependency("model.val.item.d_1", torch.ones(1))
|
||||
mapping_layer.set_dependency("model.val.item.d_2", torch.ones(1) * 2)
|
||||
|
||||
assert isinstance(mapping_layer.multi_depend, torch.Tensor)
|
||||
|
||||
for i in range(16):
|
||||
mapping_layer.set_dependency(f"model.list_vals.{i}.d", torch.ones(1) * i)
|
||||
if i != 16 - 1:
|
||||
assert mapping_layer.is_populated == False
|
||||
|
||||
assert isinstance(mapping_layer.list_depend, InferenceParameter)
|
||||
assert mapping_layer.is_populated == True
|
||||
|
||||
|
||||
@pytest.mark.inference_v2
|
||||
def test_sub_mapping_syntax():
|
||||
model = InferenceModel()
|
||||
|
||||
mapping_layer = SubMappingLayer(model)
|
||||
|
||||
mapping_layer.set_dependency("model.val.item.d_1", torch.ones(1))
|
||||
mapping_layer.set_dependency("model.val.item.d_2", torch.ones(1) * 2)
|
||||
|
||||
assert isinstance(mapping_layer.multi_depend, InferenceParameter)
|
||||
|
||||
mapping_layer.set_dependency("model.val.item2.d_1", torch.ones(1))
|
||||
mapping_layer.set_dependency("model.val.item2.d_2", torch.ones(1) * 2)
|
||||
|
||||
assert isinstance(mapping_layer.multi_depend2, InferenceParameter)
|
||||
|
||||
# We want to check into double digits to make sure that this isn't specific
|
||||
# to single difit indexing.
|
||||
for i in range(16):
|
||||
mapping_layer.set_dependency(f"model.list_vals.{i}.d", torch.ones(1) * i)
|
||||
if i != 16 - 1:
|
||||
assert mapping_layer.is_populated == False
|
||||
|
||||
assert isinstance(mapping_layer.list_depend, InferenceParameter)
|
||||
assert mapping_layer.is_populated == True
|
||||
|
||||
|
||||
@pytest.mark.inference_v2
|
||||
def test_double_mapping_syntax():
|
||||
model = InferenceModel()
|
||||
|
||||
mapping_layer = DoubleMappingLayer(model)
|
||||
mapping_layer.set_dependency("model.val.item.d_1", torch.ones(1))
|
||||
|
||||
# The single parameter setting should immediately make the parameter finalized
|
||||
# and the whole layer initialized.
|
||||
assert isinstance(mapping_layer.multi_depend, InferenceParameter)
|
||||
assert mapping_layer.is_populated == True
|
||||
|
||||
|
||||
@pytest.mark.inference_v2
|
||||
def test_insufficient_mapping_syntax():
|
||||
"""
|
||||
In the above example, we don't have a mapping for `multi_depend2.dependency_2`.
|
||||
"""
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
|
||||
class InsuffienctMappingLayer(LayerContainer):
|
||||
PARAM_MAPPING = {
|
||||
"model.val.item.d_1": "multi_depend1.dependency_1",
|
||||
"model.val.item.d_2": "multi_depend1.dependency_2",
|
||||
"model.val.item2.d_1": "multi_depend2.dependency_1",
|
||||
}
|
||||
|
||||
multi_depend1: MultiDependencyContainer
|
||||
|
||||
multi_depend2: MultiDependencyContainer
|
||||
|
||||
|
||||
@pytest.mark.inference_v2
|
||||
def test_unknown_target_mapping_syntax():
|
||||
"""
|
||||
In the above example, `multi_depend_unknown` does not exist
|
||||
"""
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
|
||||
class UnknownTargetMappingLayer(LayerContainer):
|
||||
PARAM_MAPPING = {
|
||||
"model.val.item.d_1": "multi_depend1.dependency_1",
|
||||
"model.val.item.d_2": "multi_depend1.dependency_2",
|
||||
"model.val.item2.d_1": "multi_depend_unknown.dependency_1",
|
||||
}
|
||||
|
||||
multi_depend: MultiDependencyContainer
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# DeepSpeed Team
|
||||
|
||||
import pytest
|
||||
import torch
|
||||
|
||||
from deepspeed.inference.v2.inference_parameter import InferenceParameter
|
||||
from deepspeed.inference.v2.model_implementations.layer_container_base import LayerContainer
|
||||
|
||||
from .utils import validate_device, SimpleParam, ListParam, DummyInferenceModel
|
||||
|
||||
|
||||
class MultiParameterLayer(LayerContainer):
|
||||
"""
|
||||
Two dependencies, both of which are simple parameters.
|
||||
"""
|
||||
|
||||
param_1: SimpleParam
|
||||
|
||||
param_2: SimpleParam
|
||||
|
||||
|
||||
class MixedMultiParameterLayer(LayerContainer):
|
||||
"""
|
||||
Two dependencies, one of which is a simple parameter, the other is a list parameter.
|
||||
"""
|
||||
|
||||
param_1: SimpleParam
|
||||
|
||||
param_2: ListParam
|
||||
|
||||
|
||||
@pytest.mark.inference_v2
|
||||
def test_multi_parameter_layer():
|
||||
inference_model = DummyInferenceModel()
|
||||
|
||||
multi_param_layer = MultiParameterLayer(inference_model)
|
||||
|
||||
assert multi_param_layer.n_params == 2
|
||||
assert multi_param_layer.is_populated is False
|
||||
|
||||
multi_param_layer.param_1.param = torch.ones(16, 16)
|
||||
|
||||
assert multi_param_layer.is_populated is False
|
||||
|
||||
multi_param_layer.param_2.param = torch.full((16, 16), 2.0)
|
||||
|
||||
assert multi_param_layer.is_populated is True
|
||||
assert isinstance(multi_param_layer.param_1, InferenceParameter)
|
||||
assert isinstance(multi_param_layer.param_2, InferenceParameter)
|
||||
|
||||
|
||||
@pytest.mark.inference_v2
|
||||
def test_mixed_multi_parameter_layer():
|
||||
inference_model = DummyInferenceModel()
|
||||
|
||||
mixed_multi_param_layer = MixedMultiParameterLayer(inference_model)
|
||||
|
||||
assert mixed_multi_param_layer.n_params == 2
|
||||
assert mixed_multi_param_layer.is_populated is False
|
||||
|
||||
mixed_multi_param_layer.param_2.params[1] = torch.full((16, 16), 2.0)
|
||||
assert mixed_multi_param_layer.is_populated is False
|
||||
assert not isinstance(mixed_multi_param_layer.param_2, InferenceParameter)
|
||||
|
||||
mixed_multi_param_layer.param_1.param = torch.ones(16, 16)
|
||||
assert mixed_multi_param_layer.is_populated is False
|
||||
assert isinstance(mixed_multi_param_layer.param_1, InferenceParameter)
|
||||
|
||||
validate_device(mixed_multi_param_layer.param_1)
|
||||
|
||||
mixed_multi_param_layer.param_2.params[0] = torch.full((16, 16), 2.0)
|
||||
|
||||
assert mixed_multi_param_layer.is_populated is True
|
||||
assert isinstance(mixed_multi_param_layer.param_2, InferenceParameter)
|
||||
|
||||
validate_device(mixed_multi_param_layer.param_2)
|
||||
@@ -0,0 +1,105 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# DeepSpeed Team
|
||||
|
||||
import pytest
|
||||
import torch
|
||||
|
||||
from deepspeed.inference.v2.allocator import on_device
|
||||
from deepspeed.inference.v2.inference_parameter import InferenceParameter
|
||||
from deepspeed.inference.v2.model_implementations.parameter_base import ParameterBase, ParamList
|
||||
from deepspeed.inference.v2.model_implementations.layer_container_base import LayerContainer
|
||||
from deepspeed.inference.v2.model_implementations.common_parameters import *
|
||||
|
||||
from .utils import validate_device
|
||||
|
||||
|
||||
class SimpleMoELayer(LayerContainer):
|
||||
|
||||
moe_mlp_1: UnfusedMoEMLP1Parameter
|
||||
|
||||
|
||||
class DummyInferenceModel:
|
||||
|
||||
def __init__(self, experts_per_rank: int) -> None:
|
||||
self._num_experts = experts_per_rank
|
||||
|
||||
@property
|
||||
def n_experts(self) -> int:
|
||||
return self._num_experts
|
||||
|
||||
@on_device
|
||||
def transform_moe_mlp_1_param(self, param: torch.Tensor) -> torch.Tensor:
|
||||
return InferenceParameter.initialize(param)
|
||||
|
||||
|
||||
@pytest.mark.inference_v2
|
||||
def test_simple_moe_layer():
|
||||
|
||||
inference_model = DummyInferenceModel(experts_per_rank=2)
|
||||
|
||||
simple_moe_layer = SimpleMoELayer(inference_model)
|
||||
|
||||
assert simple_moe_layer.moe_mlp_1.experts[0] is None
|
||||
assert simple_moe_layer.moe_mlp_1.experts[1] is None
|
||||
|
||||
# Set the first expert
|
||||
simple_moe_layer.moe_mlp_1.experts[0] = torch.zeros(16, 16)
|
||||
|
||||
assert simple_moe_layer.moe_mlp_1.experts[0] is not None
|
||||
assert simple_moe_layer.moe_mlp_1.experts[1] is None
|
||||
|
||||
assert not simple_moe_layer.is_initialized
|
||||
|
||||
# Set the second expert
|
||||
simple_moe_layer.moe_mlp_1.experts[1] = torch.ones(16, 16)
|
||||
|
||||
# We have all the experts, so the layer should be initialized
|
||||
assert simple_moe_layer.is_initialized
|
||||
assert isinstance(simple_moe_layer.moe_mlp_1, torch.Tensor)
|
||||
|
||||
validate_device(simple_moe_layer.moe_mlp_1)
|
||||
|
||||
|
||||
"""
|
||||
Check that we can mix the number of elements in lists in the same context and have that
|
||||
be tracked correctly.
|
||||
"""
|
||||
|
||||
|
||||
class CustomListParam1(ParameterBase):
|
||||
|
||||
deps: ParamList("attr_1")
|
||||
|
||||
|
||||
class CustomListParam2(ParameterBase):
|
||||
|
||||
deps: ParamList("attr_2")
|
||||
|
||||
|
||||
class MixedLayer(LayerContainer):
|
||||
|
||||
list_1: CustomListParam1
|
||||
list_2: CustomListParam2
|
||||
|
||||
|
||||
class MixedInferenceModel:
|
||||
|
||||
@property
|
||||
def attr_1(self) -> int:
|
||||
return 1
|
||||
|
||||
@property
|
||||
def attr_2(self) -> int:
|
||||
return 2
|
||||
|
||||
|
||||
@pytest.mark.inference_v2
|
||||
def test_mixed_param_lists():
|
||||
model = MixedInferenceModel()
|
||||
|
||||
layer = MixedLayer(model)
|
||||
|
||||
assert layer.list_1.deps.n_params == 1
|
||||
assert layer.list_2.deps.n_params == 2
|
||||
@@ -0,0 +1,60 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# DeepSpeed Team
|
||||
|
||||
import torch
|
||||
|
||||
from deepspeed.accelerator import get_accelerator
|
||||
from deepspeed.inference.v2.allocator import on_device
|
||||
from deepspeed.inference.v2.inference_parameter import InferenceParameter
|
||||
from deepspeed.inference.v2.model_implementations.parameter_base import ParameterBase, ParametrizedList
|
||||
|
||||
|
||||
class SimpleParam(ParameterBase):
|
||||
"""
|
||||
Parameter with single dependency.
|
||||
"""
|
||||
|
||||
param: torch.Tensor
|
||||
|
||||
@on_device
|
||||
def finalize(self) -> torch.Tensor:
|
||||
return self.inference_model.transform(self.param)
|
||||
|
||||
|
||||
class SimpleParametrizedList(ParametrizedList):
|
||||
"""
|
||||
Parameter list based on `num_dependencies` attribute.
|
||||
"""
|
||||
|
||||
count_attr: str = "num_dependencies"
|
||||
|
||||
|
||||
class ListParam(ParameterBase):
|
||||
"""
|
||||
Parameter with list dependency.
|
||||
|
||||
NOTE: This uses the tuple workaround for the `ParametrizedList` class
|
||||
as described in the docstring of `ParametrizedList`.
|
||||
"""
|
||||
|
||||
params: SimpleParametrizedList
|
||||
|
||||
@on_device
|
||||
def finalize(self) -> torch.Tensor:
|
||||
return self.inference_model.transform(torch.cat(tuple(self.params)))
|
||||
|
||||
|
||||
class DummyInferenceModel:
|
||||
|
||||
@property
|
||||
def num_dependencies(self) -> int:
|
||||
return 2
|
||||
|
||||
def transform(self, param: torch.Tensor) -> torch.Tensor:
|
||||
return InferenceParameter.initialize(param)
|
||||
|
||||
|
||||
def validate_device(tensor: torch.Tensor):
|
||||
assert tensor.device == torch.device(get_accelerator().current_device())
|
||||
Reference in New Issue
Block a user