#11 master

Merged
sunxiyin merged 2 commits from sunxiyin/MSAdapterUT:master into master 1 year ago
  1. +102
    -30
      solution_test/common/base.py
  2. +0
    -0
      solution_test/pytorch_cases/demo/CrossEntropyLoss/__init__.py
  3. +29
    -0
      solution_test/pytorch_cases/demo/CrossEntropyLoss/crossentropyloss_ops.py
  4. +63
    -0
      solution_test/pytorch_cases/demo/CrossEntropyLoss/test_msadapter_ops_crossentropyloss.py
  5. +37
    -0
      solution_test/pytorch_cases/demo/CrossEntropyLoss/test_msadapter_ops_crossentropyloss.yaml
  6. +0
    -0
      solution_test/pytorch_cases/demo/conv2d/__init__.py
  7. +2
    -3
      solution_test/pytorch_cases/demo/conv2d/test_msadapter_ops_conv2d_demo.py
  8. +2
    -2
      solution_test/pytorch_cases/demo/conv2d/test_msadapter_ops_conv2d_demo.yaml
  9. +1
    -1
      solution_test/pytorch_cases/demo/tensor_add/test_msadapter_ops_tensor_add_demo.py

+ 102
- 30
solution_test/common/base.py View File

@@ -81,9 +81,11 @@ class SolutionTestBase:

def generate_case_params(self):
args_dict = dict()
input_dict = dict()
yaml_content = yaml_read(self.yaml_path)
args = yaml_content.get("args")
variation = yaml_content.get("variation")
input_shape = yaml_content.get("input_shape")
self.params_dict["op_name"] = yaml_content.get("op_name")
self.params_dict["torch_op_name"] = yaml_content.get("torch_op_name")
# 解析yaml配置文件参数
@@ -92,7 +94,7 @@ class SolutionTestBase:
# BC覆盖,生成所有参数组合
self.params_dict = self.bc_generate_args(self.params_dict)
# 获取输入shape
self.params_dict = self.get_input_shape(yaml_content.get("input_shape"), self.params_dict)
self.params_dict = self.get_input_shape(input_shape, self.params_dict)
# 执行约束条件
if variation is not None:
self.params_dict = self.execute_variation(variation, self.params_dict)
@@ -105,8 +107,12 @@ class SolutionTestBase:
for key in args.keys():
if self.params_dict.get(key) is not None:
args_dict[key] = self.params_dict.get(key)
if input_shape is not None:
for key in input_shape.keys():
if self.params_dict.get(key) is not None:
input_dict[key] = self.params_dict.get(key)
self.ms_log.info("params_dict: %s, args_dict: %s", self.params_dict, args_dict)
return self.params_dict, args_dict
return self.params_dict, args_dict, input_shape

def generate_input_shape(self):
"""
@@ -114,17 +120,36 @@ class SolutionTestBase:
"""
ms_input_shape_list = list()
torch_input_shape_list = list()
params_dict, _ = self.generate_case_params()
for key, value in params_dict.items():
if "input" not in key:
continue
random_shape = np.random.randn(*params_dict.get(key).get("input_shape"))
torch_input_shape = torch.tensor(random_shape, dtype=params_dict.get("torch_dtype"))
ms_input_shape = ms_pytorch.tensor(random_shape, dtype=params_dict.get("ms_dtype"))
_, args_dict, input_dict = self.generate_case_params()
for key, value in input_dict.items():
random_shape = np.random.randn(*input_dict.get(key).get("input_shape"))
torch_input_shape = torch.tensor(random_shape, dtype=input_dict.get("torch_dtype"))
ms_input_shape = ms_pytorch.tensor(random_shape, dtype=input_dict.get("ms_dtype"))
ms_input_shape_list.append(ms_input_shape)
torch_input_shape_list.append(torch_input_shape)

return torch_input_shape_list, ms_input_shape_list

def generate_args_with_tensor(self, args):
"""
生成参数中的tensor类型数据
:param args: 设为tesnor数据的参数名
:param frame_name: 使用的框架名,取值分别为:"torch"或"ms_pytorch"
"""
_, args_dict, _ = self.generate_case_params()
numpy_shape = args_dict.get(args).get("numpy_shape")
numpy_type = args_dict.get(args).get("numpy_type")
random_shape = np.random.randn(*numpy_shape)

torch_tensor = torch.tensor(random_shape, dtype=eval(".".join(["torch", numpy_type])))
args_dict["weight"] = torch_tensor
torch_args = args_dict.copy()
ms_tensor = ms_pytorch.tensor(random_shape, dtype=eval(".".join(["ms_pytorch", numpy_type])))
args_dict["weight"] = ms_tensor
ms_args = args_dict
self.ms_log.info("func generate_args_with_tensor get torch_args: %s\n ms_args: %s\n", torch_args, ms_args)
return torch_args, ms_args

def parse_yaml_args(self, args):
"""
解析yaml文件参数
@@ -136,17 +161,19 @@ class SolutionTestBase:
support_type = value.get("support_type", None)
if not isinstance(value, dict):
raise TypeError("Yaml config key: %s isn't dict type." % key)
if support_type is None:
raise TypeError("Yaml config missing key: %s attributes: support_type" % key)
elif support_value_range is None:
raise TypeError("Yaml config missing key: %s attributes: support_value_range" % key)
if isinstance(support_type, str):
if isinstance(support_value_range, dict):
support_value_range = tuple(support_value_range.get(support_type, [1]))
if isinstance(support_value_length, dict):
support_value_length = tuple(support_value_length.get(support_type, [1]))
params_dict = self.param_value_generate(key, support_type,
support_value_range, support_value_length, params_dict)

if support_type == "numpy":
params_dict = self.numpy_value_generate(key, value, params_dict)
else:
params_dict = self.param_value_generate(key, support_type,
support_value_range,
support_value_length,
params_dict)
elif isinstance(support_type, list):
for v_type in support_type:
if isinstance(support_value_range, dict):
@@ -157,9 +184,41 @@ class SolutionTestBase:
value_length = copy.deepcopy(tuple(support_value_length.get(v_type, [1])))
else:
value_length = tuple(support_value_length)
params_dict = self.param_value_generate(key, v_type,
value_range,
value_length, params_dict)

if v_type == "numpy":
params_dict = self.numpy_value_generate(key, value, params_dict)
else:
params_dict = self.param_value_generate(key, v_type,
value_range,
value_length,
params_dict)
return params_dict

def numpy_value_generate(self, key, value, params_dict):
"""
numpy类型数值生成
:param key: 键名
:param value: 参数
:param params_dict: 最终参数结果
"""
numpy_shape_list = value.get("numpy_shape", list())
numpy_data_type_list = value.get("numpy_type", ["float32"])
if not numpy_shape_list:
return params_dict
if isinstance(numpy_shape_list[0], list):
numpy_shape = random.choice(numpy_shape_list)
else:
numpy_shape = numpy_shape_list

if isinstance(numpy_data_type_list, list):
numpy_data_type = random.choice(numpy_data_type_list)
else:
numpy_data_type = numpy_data_type_list

params_dict[key] = {
"numpy_shape": numpy_shape,
"numpy_type": numpy_data_type
}
return params_dict

def param_value_generate(self, key, data_type, support_value_range, support_value_length, params_dict):
@@ -174,9 +233,14 @@ class SolutionTestBase:
if data_type != 'default':
params_dict[key] = list()
if data_type in ["int", "float", "list", "tuple"]:
normal_value_list = [support_value_range[0], support_value_range[0] + 1,
support_value_range[1] - 1, support_value_range[1],
int(np.median(support_value_range))]
# float类型时,如果右侧数值小于1则不取边界值
if data_type == "float" and support_value_range[1] <= 1:
normal_value_list = [support_value_range[0], support_value_range[1],
float(np.median(support_value_range))]
else:
normal_value_list = [support_value_range[0], support_value_range[0] + 1,
support_value_range[1] - 1, support_value_range[1],
int(np.median(support_value_range))]
if support_value_range[0] == support_value_range[1]:
if data_type == "int":
params_dict[key].append(support_value_range[0])
@@ -217,9 +281,11 @@ class SolutionTestBase:
for i in range(length + 1):
if i != length:
continue
value = random.sample([v for v in range(normal_value_list[0],
normal_value_list[-1] + 1)], i)
value.sort()
normal_value_range_list = [v for v in range(normal_value_list[0],
normal_value_list[-1] + 1)]
if len(normal_value_range_list) < i:
continue
value = random.sample(normal_value_range_list, i)
if value not in params_dict[key]:
params_dict[key].append(value)
else:
@@ -230,9 +296,11 @@ class SolutionTestBase:
for i in range(length + 1):
if i != length:
continue
value = random.sample([v for v in range(normal_value_list[0],
normal_value_list[-1] + 1)], i)
value.sort()
normal_value_range_list = [v for v in range(normal_value_list[0],
normal_value_list[-1] + 1)]
if len(normal_value_range_list) < i:
continue
value = random.sample(normal_value_range_list, i)
if tuple(value) not in params_dict[key]:
params_dict[key].append(tuple(value))
elif data_type == "str":
@@ -241,8 +309,7 @@ class SolutionTestBase:
params_dict[key] = support_value_range
return params_dict

@staticmethod
def bc_generate_args(params_dict):
def bc_generate_args(self, params_dict):
"""
bc覆盖算法,获取所以参数组合
:param params_dict: 最终参数结果
@@ -251,10 +318,15 @@ class SolutionTestBase:
base_params_dict = dict()
# 确定首个参数集合
for key, value in params_dict.items():
base_params_dict[key] = value[0]
if isinstance(value, dict):
base_params_dict[key] = value
else:
base_params_dict[key] = value[0]
args_list.append(base_params_dict)
for key, value in params_dict.items():
tmp_dict = copy.deepcopy(base_params_dict)
if isinstance(value, dict):
continue
for sub_value in value:
if sub_value == base_params_dict.get(key):
continue


+ 0
- 0
solution_test/pytorch_cases/demo/CrossEntropyLoss/__init__.py View File


+ 29
- 0
solution_test/pytorch_cases/demo/CrossEntropyLoss/crossentropyloss_ops.py View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
"""
Conv2d算子特性类
"""
import torch
import mindspore as ms
from mindspore import context
from ms_adapter.pytorch.nn import Module, CrossEntropyLoss

context.set_context(mode=ms.PYNATIVE_MODE)

class CrossEntropyLossModel(torch.nn.Module):
def __init__(self, **kwargs):
super(CrossEntropyLossModel, self).__init__()
self.CrossEntropyLoss = torch.nn.CrossEntropyLoss(**kwargs)

def forward(self, inputs, target):
x = self.CrossEntropyLoss(inputs, target)
return x


class CrossEntropyLossModelMs(Module):
def __init__(self, **kwargs):
super(CrossEntropyLossModelMs, self).__init__()
self.CrossEntropyLoss = CrossEntropyLoss(**kwargs)

def forward(self, inputs, target):
x = self.CrossEntropyLoss(inputs, target)
return x

+ 63
- 0
solution_test/pytorch_cases/demo/CrossEntropyLoss/test_msadapter_ops_crossentropyloss.py View File

@@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
"""Example docstrings

Module description: Msadapter demo用例

Module composition: setup + test_run + teardown
setup function: Load execute operator auto use case parameter and init logging module
test_run function: Verify the function of the operator module
teardown function: Clear residual process

Module usage example:
pytorch_cases execution command: pytest -s Test_msadapter_ops_conv_demo.py

Single case execute step:
1.Judge init flag: init_success_flag
2.Call the operator feature class to generate random input parameters
3.Operator Accuracy comparison

"""
import torch
import ms_adapter
from common.base import SolutionTestBase
from common.utils.marker import SKIP_GRAPH_MODE, SKIP_ENV_ASCEND
from .crossentropyloss_ops import CrossEntropyLossModel, CrossEntropyLossModelMs


class Test_msadapter_ops_CrossEntropyLoss(SolutionTestBase):

def setup(self, case_name=None):
case_name = "Test_msadapter_ops_CrossEntropyLoss"
super(Test_msadapter_ops_CrossEntropyLoss, self).setup(case_name)
return True

@SKIP_ENV_ASCEND()
@SKIP_GRAPH_MODE()
def test_run(self):
assert self.init_success_flag

# 调用参数生成接口
# 1)分别生成torch ms输入数据
torch_input_shape_list, ms_input_shape_list = self.generate_input_shape()
# 2)分别生成torch ms输入参数,其中参数"weight"为tensor类型
torch_args, ms_args = self.generate_args_with_tensor("weight")
# 计算torch结果
py_net = CrossEntropyLossModel(**torch_args)
py_output = py_net(torch_input_shape_list[0], torch_input_shape_list[1])

# 计算ms结果
ms_net = CrossEntropyLossModelMs(**ms_args)
ms_net.train()
ms_output = ms_net(ms_input_shape_list[0], ms_input_shape_list[1])

# 对比结果
self.ms_log.info("py_output.shape: %s, ms_output.shape: %s", py_output.shape, ms_output.shape)
assert (py_output.shape == ms_output.shape)

# 对比精度
self.ms_log.info("py_output:\n %s, \nms_output:\n %s", py_output.detach().numpy(), ms_output.asnumpy())
assert self.allclose(py_output.detach().numpy(), ms_output.asnumpy())

def teardown(self):
super(Test_msadapter_ops_CrossEntropyLoss, self).teardown()
return True

+ 37
- 0
solution_test/pytorch_cases/demo/CrossEntropyLoss/test_msadapter_ops_crossentropyloss.yaml View File

@@ -0,0 +1,37 @@
op_name: CrossEntropyLoss
# 输入shape
input_shape:
input:
input_shape: [[256], [5, 10], [10, 30, 256], [1, 10, 10, 10, 10], [1, 10, 128, 128]]
dtype: float32

target:
input_shape: [[256], [5, 10], [10, 30, 256], [1, 10, 10, 10, 10], [1, 10, 128, 128]]
dtype: float32

# 参数
args:
weight:
support_type: ["numpy"]
numpy_shape: [[256], [5, 10], [10, 30, 256], [1, 10, 10, 10, 10], [1, 10, 128, 128]]
numpy_type: ["float32", "float16"]
size_average:
support_type: ["bool"]
support_value_range: {"bool": [True, False]}
ignore_index:
support_type: ["int", "default"]
support_value_range: {"int": [-100, 9]}
reduce:
support_type: ["bool"]
support_value_range: {"bool": [True, False]}
reduction:
support_type: ["str", "default"]
support_value_range: {"str": ["none", "mean", "sum"]}
label_smoothing:
support_type: ["float", "default"]
support_value_range: {"float": [0.001, 1.000]}

# 参数间约束规则,可选
variation:
variation1: params["target"]["input_shape"]=params["input"]["input_shape"]
variation2: params["weight"]["numpy_shape"]=params["input"]["input_shape"]

+ 0
- 0
solution_test/pytorch_cases/demo/conv2d/__init__.py View File


+ 2
- 3
solution_test/pytorch_cases/demo/conv2d/test_msadapter_ops_conv2d_demo.py View File

@@ -39,7 +39,7 @@ class Test_msadapter_ops_conv2d_demo(SolutionTestBase):
assert self.init_success_flag

# 调用参数生成接口
params_dict, args_dict = self.generate_case_params()
params_dict, args_dict, _ = self.generate_case_params()
# conv2d初始化:weight_init,bias_init
if isinstance(params_dict.get("kernel_size"), tuple):
weight1 = params_dict.get("weight1")
@@ -49,14 +49,13 @@ class Test_msadapter_ops_conv2d_demo(SolutionTestBase):
weight1 = params_dict.get("weight1")
weight2 = params_dict.get("kernel_size")
weight3 = params_dict.get("kernel_size")

weight_init = np.random.randn(params_dict.get("out_channels"), weight1, weight2, weight3).astype(float)
bias_init = np.random.randn(params_dict.get("out_channels")).astype(float)
args = [weight_init, bias_init]

# 计算torch结果
py_net = Conv2dModel(*args, **args_dict)


py_input = torch.tensor(np.ones(shape=params_dict.get("input_1").get("input_shape")),
dtype=params_dict.get("torch_dtype"))
py_output = py_net(py_input)


+ 2
- 2
solution_test/pytorch_cases/demo/conv2d/test_msadapter_ops_conv2d_demo.yaml View File

@@ -17,7 +17,7 @@ input_shape:
args:
in_channels:
support_type: ["float"]
support_value_range: {"float": [1, 100]}
support_value_range: {"float": [0, 100]}
out_channels:
support_type: ["int"]
support_value_range: {"int": [1, 200]}
@@ -30,7 +30,7 @@ args:
support_value_range: {"int": [1, 10], "tuple": [1, 10]}
support_value_length: {"tuple": {2}}
padding:
support_type: ["int", "tuple", "str", "default"]
support_type: ["int", "tuple", "str", "default", "numpy"]
support_value_range: {"int": [1, 10], "tuple": [1, 10], "str": [1, 10]}
support_value_length: {"tuple": {2}}
padding_mode:


+ 1
- 1
solution_test/pytorch_cases/demo/tensor_add/test_msadapter_ops_tensor_add_demo.py View File

@@ -46,7 +46,7 @@ class Test_msadapter_ops_tensor_add_demo(SolutionTestBase):
assert self.all_output_all_close(py_output, ms_output)

# 对比性能
assert self.perf_data_compare(py_net, ms_net, torch_input_shape_list, ms_input_shape_list)
# assert self.perf_data_compare(py_net, ms_net, torch_input_shape_list, ms_input_shape_list)

def teardown(self):
super(Test_msadapter_ops_tensor_add_demo, self).teardown()


Loading…
Cancel
Save