!30321 dynamic shape feed mode

Merge pull request !30321 from Henry Shi/branch_sxy
This commit is contained in:
i-robot 2022-03-23 02:30:23 +00:00 committed by Gitee
commit eaae9961a3
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
8 changed files with 138 additions and 22 deletions

View File

@ -927,15 +927,19 @@ bool AnfRuntimeAlgorithm::IsIndependentNode(const CNodePtr &node) {
}
static inline void GetMaxOrDefaultShape(const std::vector<int64_t> &max_shape, std::vector<size_t> *device_shape) {
constexpr size_t kDefaultValueForDynamicDim = 16;
auto ConvertNegOneToDefault = [&kDefaultValueForDynamicDim](size_t size) {
return static_cast<int64_t>(size) < 0 ? kDefaultValueForDynamicDim : size;
};
if (!max_shape.empty()) {
(void)std::transform(max_shape.begin(), max_shape.end(), device_shape->begin(), IntToSize);
if (device_shape->empty()) {
std::transform(max_shape.begin(), max_shape.end(), std::back_inserter(*device_shape), ConvertNegOneToDefault);
} else {
std::transform(max_shape.begin(), max_shape.end(), device_shape->begin(), IntToSize);
}
} else {
constexpr size_t kDefaultValueForDynamicDim = 16;
auto tmp_shape = *device_shape;
auto ConvertNegOneToDefalut = [&kDefaultValueForDynamicDim](size_t size) {
return static_cast<int64_t>(size) < 0 ? kDefaultValueForDynamicDim : size;
};
(void)std::transform(tmp_shape.begin(), tmp_shape.end(), device_shape->begin(), ConvertNegOneToDefalut);
(void)std::transform(tmp_shape.begin(), tmp_shape.end(), device_shape->begin(), ConvertNegOneToDefault);
}
}
@ -948,7 +952,7 @@ static inline void GetMaxOrDefaultShape(const std::vector<int64_t> &max_shape, s
std::vector<size_t> AnfRuntimeAlgorithm::GetInputDeviceShapeAdaptively(const AnfNodePtr &anf_node, size_t index) {
auto device_shape = GetInputDeviceShape(anf_node, index);
// Initialize GPUKernel with max shape to fit 'InitDynamicOutputKernelRef()' for memory reuse.
if (AnfUtils::IsShapeDynamic(device_shape)) {
if (AnfUtils::IsShapeDynamic(device_shape) || device_shape.empty()) {
auto max_shape = common::AnfAlgo::GetInputMaxShape(anf_node, index);
GetMaxOrDefaultShape(max_shape, &device_shape);
auto format = GetInputFormat(anf_node, index);
@ -962,7 +966,7 @@ std::vector<size_t> AnfRuntimeAlgorithm::GetInputDeviceShapeAdaptively(const Anf
std::vector<size_t> AnfRuntimeAlgorithm::GetOutputDeviceShapeAdaptively(const AnfNodePtr &anf_node, size_t index) {
auto device_shape = GetOutputDeviceShape(anf_node, index);
// Initialize GPUKernel with max shape to fit 'InitDynamicOutputKernelRef()' for memory reuse.
if (AnfUtils::IsShapeDynamic(device_shape)) {
if (AnfUtils::IsShapeDynamic(device_shape) || device_shape.empty()) {
auto max_shape = common::AnfAlgo::GetOutputMaxShape(anf_node, index);
GetMaxOrDefaultShape(max_shape, &device_shape);
auto format = GetOutputFormat(anf_node, index);

View File

@ -81,6 +81,9 @@ RangePair TbeDynamicShapeUtil::GetInputDynamicRange(const AnfNodePtr &anf_node,
}
RangePair ret;
for (size_t i = 0; i < input_range_min.size(); ++i) {
if (input_range_min[i] < 0) {
input_range_min[i] = 1;
}
ret.emplace_back(input_range_min[i], input_range_max[i]);
}
return shapeRangeTransfer.GetRealRange(ret, format, data_type);
@ -108,6 +111,9 @@ RangePair TbeDynamicShapeUtil::GetOutputDynamicRange(const AnfNodePtr &anf_node,
}
RangePair ret;
for (size_t i = 0; i < output_range_min.size(); ++i) {
if (output_range_min[i] < 0) {
output_range_min[i] = 1;
}
ret.emplace_back(output_range_min[i], output_range_max[i]);
}
return shapeRangeTransfer.GetRealRange(ret, format, data_type);

View File

@ -42,8 +42,8 @@ void GetRealInputSize(const nlohmann::json &input_json, std::vector<size_t> *inp
if (j >= input_max_shape.size()) {
MS_LOG(EXCEPTION) << "Invalid Dynamic Shape Max Shape";
}
MS_LOG(INFO) << "Change -1 Shape to Max Shape:" << input_max_shape[j][1];
(*size_i) = SizetMulWithOverflowCheck((*size_i), LongToSize(input_max_shape[j][1]));
MS_LOG(INFO) << "Change -1 Shape to 1:" << input_max_shape[j][1];
(*size_i) = SizetMulWithOverflowCheck((*size_i), 1);
continue;
}
(*size_i) = SizetMulWithOverflowCheck((*size_i), static_cast<size_t>(input_json[kJShape][j]));
@ -89,8 +89,8 @@ void GetRealOutputSize(const nlohmann::json &output_json, std::vector<size_t> *o
if (j >= output_max_shape.size()) {
MS_LOG(EXCEPTION) << "Invalid Dynamic Shape Max Shape";
}
MS_LOG(INFO) << "Change -1 Shape to Max Shape:" << output_max_shape[j][1];
(*size_i) = SizetMulWithOverflowCheck(*size_i, LongToSize(output_max_shape[j][1]));
MS_LOG(INFO) << "Change -1 Shape to 1:" << output_max_shape[j][1];
(*size_i) = SizetMulWithOverflowCheck(*size_i, 1);
continue;
}
(*size_i) = SizetMulWithOverflowCheck(*size_i, static_cast<size_t>(output_json[kJShape][j]));

View File

@ -415,6 +415,7 @@ void DataPrepareActor::PrepareDataForHostTensorQueue(const std::vector<std::vect
AnfAlgo::SetOutputAddr(tensor_address, 0, input_node.get());
tensor_address->SetNodeIndex(input_node, 0);
}
device_address->SetSize(host_tensors[tensor_position]->data().nbytes());
}
}

View File

@ -149,6 +149,11 @@ def get_single_io_arg(info):
res = info
else:
res = None
if 'range' in info:
for i in range(len(info['range'])):
if info['range'][i][1] == -1:
info['range'][i][1] = None
res = info
return res

View File

@ -125,7 +125,10 @@ class Tensor(Tensor_):
_check_tensor_input(input_data, dtype, shape, init)
# If input_data is tuple/list/numpy.ndarray, it's support in check_type method.
if init is None:
if (isinstance(shape, (list, tuple)) and None in shape) or init is not None:
shape = _check_tensor_dynamic_shape(dtype, shape, init)
Tensor_.__init__(self, dtype, shape)
else:
validator.check_value_type('input_data', input_data,
(Tensor_, np.ndarray, np.str_, list, tuple, float, int, bool, complex),
'Tensor')
@ -153,8 +156,6 @@ class Tensor(Tensor_):
Tensor_.__init__(self, input_data, dtype)
else:
Tensor_.__init__(self, input_data)
else:
Tensor_.__init__(self, dtype, shape)
self.virtual_flag = False
self.init = init
@ -2898,9 +2899,6 @@ def _check_tensor_input(input_data=None, dtype=None, shape=None, init=None):
if init is not None and (shape is None or dtype is None):
raise ValueError("init, dtype and shape must have values at the same time.")
if (int(input_data is None) + int(init is None)) != 1:
raise TypeError("input_data and init can not be None at the same time.")
if input_data is not None:
if isinstance(input_data, np.ndarray) and input_data.ndim > 1 and input_data.size == 0:
raise ValueError("input_data can not contain zero dimension.")
@ -2912,4 +2910,18 @@ def _check_tensor_input(input_data=None, dtype=None, shape=None, init=None):
raise ValueError("Shape can not contain zero value.")
def _check_tensor_dynamic_shape(dtype=None, shape=None, init=None):
"""Check if the tensor has dynamic shape."""
shape_list = list(shape)
if len(shape_list) >= 1:
shape_replaced_list = [-1 if i is None else i for i in shape_list]
if isinstance(shape, tuple):
shape = tuple(shape_replaced_list)
if isinstance(shape, list):
shape = shape_replaced_list
if -1 in shape and (dtype is None or init is not None):
raise ValueError("If setting dynamic shape, dtype must not be None, init must be None")
return shape
tensor_operator_registry.register('vm_compare', _vm_compare)

View File

@ -138,6 +138,8 @@ class Cell(Cell_):
self.cast = Cast()
self._has_config_recompute = False
self._user_parameters = []
self._dynamic_shape_inputs = None
self.saved_dynamic_shape = None
def __getstate__(self):
base = Cell_.__getstate__(self)
@ -660,7 +662,7 @@ class Cell(Cell_):
exist_objs.add(item)
if item.name == PARAMETER_NAME_DEFAULT:
logger.warning("The parameter definition is deprecated.\n"
"Please set a unique name for the parameter in ParameterTuple '{}'.". format(value))
"Please set a unique name for the parameter in ParameterTuple '{}'.".format(value))
item.name = item.name + "$" + str(self._id)
self._id += 1
self.insert_param_to_cell(item.name, item, check_name_contain_dot=False)
@ -875,6 +877,40 @@ class Cell(Cell_):
self._construct_inputs_names = self._construct_inputs_names[1:self._construct_inputs_num]
self._construct_inputs_num = self._construct_inputs_num - 1
def set_inputs(self, *inputs):
"""
Save set inputs for computation graph.
Args:
inputs (tuple): Inputs of the Cell object.
Examples:
>>> n = Net()
>>> input_dyn = Tensor(shape = [3, None], dtype=type)
>>> net.set_inputs(input_dyn)
>>> input1 = Tensor(np.random.random([3, 10]), dtype=type)
>>> output = net(input1)
NOTE:
This is an experimental interface that is subject to change or deletion.
"""
self._dynamic_shape_inputs = inputs
if isinstance(self._dynamic_shape_inputs[0], (str, int, dict)):
raise TypeError(f"For 'set_inputs, the type must be tuple, but got {type(self._dynamic_shape_inputs[0])}.")
def get_inputs(self):
"""
Returns the dynamic_inputs of a cell object in one network.
Returns:
inputs (tuple): Inputs of the Cell object.
NOTE:
This is an experimental interface that is subject to change or deletion.
"""
return self._dynamic_shape_inputs
def compile(self, *inputs):
"""
Compile Cell as a computation graph, the input must be consistent with the input defined in construct.
@ -882,7 +918,20 @@ class Cell(Cell_):
Args:
inputs (tuple): Inputs of the Cell object.
"""
_cell_graph_executor.compile(self, *inputs, phase=self.phase, auto_parallel_mode=self._auto_parallel_mode)
if self._dynamic_shape_inputs is None or self._dynamic_shape_inputs[0] is None:
_cell_graph_executor.compile(self, *inputs, phase=self.phase, auto_parallel_mode=self._auto_parallel_mode)
else:
self._check_compile_dynamic_shape(*inputs)
if self.saved_dynamic_shape:
for i in range(len(self.saved_dynamic_shape)):
if self.saved_dynamic_shape[i].shape != self._dynamic_shape_inputs[i].shape \
and self.saved_dynamic_shape[i].shape != self._dynamic_shape_inputs[i].shape:
break
return
self.saved_dynamic_shape = self._dynamic_shape_inputs
_cell_graph_executor.compile(self, *self._dynamic_shape_inputs, phase=self.phase,
auto_parallel_mode=self._auto_parallel_mode)
logger.debug("Compiled Graph with dynamic shape")
def compile_and_run(self, *inputs):
"""
@ -911,7 +960,7 @@ class Cell(Cell_):
new_inputs.append(i)
elif context.get_context("grad_for_scalar") and isinstance(i, (int, float)):
new_inputs.append(i)
elif hasattr(self, "enable_tuple_broaden") and self.enable_tuple_broaden and isinstance(i, tuple) and\
elif hasattr(self, "enable_tuple_broaden") and self.enable_tuple_broaden and isinstance(i, tuple) and \
_check_all_tensor(i):
new_inputs.append(i)
@ -1245,7 +1294,7 @@ class Cell(Cell_):
for value, param in self.parameters_and_names():
if param.name in names:
raise ValueError("The value of {} is {}, its name '{}' already exists. "
"Please set a unique name for the parameter.". format(value, param, param.name))
"Please set a unique name for the parameter.".format(value, param, param.name))
names.add(param.name)
def parameters_and_names(self, name_prefix='', expand=True):
@ -2073,6 +2122,43 @@ class Cell(Cell_):
params.append(param)
return params
def _check_compile_dynamic_shape(self, *inputs):
"""
Check if graph has been compiled with dynamic shape.
Args:
inputs (tuple): Inputs of the Cell object.
"""
len_inputs = len(inputs)
len_dynamic_shape_inputs = len(self._dynamic_shape_inputs)
if len_dynamic_shape_inputs != len_inputs:
raise ValueError(
f"For 'set_inputs', the Length of Tensor should be {len_inputs}, but got {len_dynamic_shape_inputs}."
)
for tensor_index in range(len_dynamic_shape_inputs):
i_dynamic_shape_inputs = self._dynamic_shape_inputs[tensor_index]
i_inputs = inputs[tensor_index]
if i_dynamic_shape_inputs.dtype is not i_inputs.dtype:
raise TypeError(
f"For 'set_inputs', the DataType of Tensor should be {i_inputs.dtype}, but got "
f"{i_dynamic_shape_inputs.dtype}."
)
set_inputs_shape = list(i_dynamic_shape_inputs.shape)
inputs_shape = list(i_inputs.shape)
if len(inputs_shape) != len(set_inputs_shape):
raise ValueError(
f"For 'set_inputs' the Dimension of Tensor shape must be {len(inputs_shape)}, but got "
f"{len(set_inputs_shape)}."
)
for shape_index in i_dynamic_shape_inputs.shape:
if shape_index != -1:
dynamic_index = i_dynamic_shape_inputs.shape.index(shape_index)
if set_inputs_shape[dynamic_index] != inputs_shape[dynamic_index]:
raise ValueError(
f"For 'Length of Tensor shape', the value must be the same with that of inputs, but"
f" got {i_dynamic_shape_inputs.shape}."
)
class GraphCell(Cell):
"""

View File

@ -294,6 +294,8 @@ class Model:
if self._optimizer is None:
# In this case, multiple optimizer(s) is supposed to be included in 'self._network'
_set_multi_subgraphs()
if self._network.get_inputs() is not None:
network.set_inputs(*self._network.get_inputs())
return network
def _build_eval_network(self, metrics, eval_network, eval_indexes):