diff --git a/src/mindspore2022/mindspore/python/mindspore/ops/operations/_embedding_cache_ops.py b/src/mindspore2022/mindspore/python/mindspore/ops/operations/_embedding_cache_ops.py index a6d1f45d..a043b90c 100644 --- a/src/mindspore2022/mindspore/python/mindspore/ops/operations/_embedding_cache_ops.py +++ b/src/mindspore2022/mindspore/python/mindspore/ops/operations/_embedding_cache_ops.py @@ -17,65 +17,71 @@ from ..._checkparam import Validator as validator from ...common import dtype as mstype from ..primitive import prim_attr_register, PrimitiveWithCheck from .. import signature as sig - - + + class UpdateCache(PrimitiveWithCheck): """ - Update the value fo input_x, similar to ScatterNdUpdate. - The difference is that UpdateCache will not update when indices < 0 or indices >= max_num. - + 更新 input_x 的值,类似于 ScatterNdUpdate。 + 不同之处在于,UpdateCache 当 indices < 0 或 indices >= max_num 时不会更新。 + Inputs: - - **input_x** (Parameter) - Parameter which is going to be updated. - - **indices** (Tensor) - Update indices of input_x. - - **updates** (Tensor) - The update values. - + - **input_x** (Parameter) - 将要更新的参数。 + - **indices** (Tensor) - input_x 的更新索引。 + - **updates** (Tensor) - 更新值。 + Outputs: - - **out** (Tensor) - Returns a [1] Tensor, which is not useful. + - **out** (Tensor) - 返回一个 [1] 的张量,这个张量没有用处。 """ + # 定义函数签名,指定输入参数的类型和读写权限 __mindspore_signature__ = ( + # 定义输入参数input_x,类型为T,读写权限为写 sig.make_sig('input_x', sig.sig_rw.RW_WRITE, dtype=sig.sig_dtype.T), + # 定义输入参数indices,类型为T1 sig.make_sig('indices', dtype=sig.sig_dtype.T1), + # 定义输入参数updates,类型为T sig.make_sig('updates', dtype=sig.sig_dtype.T), + # 定义输入参数max_num,类型为T1 sig.make_sig('max_num', dtype=sig.sig_dtype.T1) ) - + @prim_attr_register def __init__(self): - """init UpdateCache""" - + """初始化 UpdateCache""" + + # 初始化输入和输出名称 self.init_prim_io_names(inputs=['input_x', 'indices', 'update', 'max_num'], outputs=['out']) - + def check_shape(self, input_x_shape, indices_shape, update_shape, max_num_shape): + # 检查输入形状 return [1] - + def check_dtype(self, input_x_dtype, indices_dtype, update_dtype, max_num_dtype): + # 检查输入数据类型 validator.check_tensor_dtype_valid( "indices", indices_dtype, mstype.int_type, self.name) return input_x_dtype - - + + class SubAndFilter(PrimitiveWithCheck): """ - Dynamic kernel, sub an offset and - return the elements which in range [0, max_num). - + 动态内核,减去一个偏移量并返回在范围 [0, max_num) 内的元素。 + Inputs: - - **input_x** (Tensor) - Input tensor. - - **max_num** (Int) - The max value of element that after sub `offset`. - - **offset** (int) - Specifies the offset value of this `input_x`. - + - **input_x** (Tensor) - 输入张量。 + - **max_num** (Int) - 减去 `offset` 后元素的最大值。 + - **offset** (int) - 指定此 `input_x` 的偏移值。 + Outputs: - tuple(Tensor), tuple of 2 tensors, filter_res and filter_idx. - - **filter_res** (Tensor) - The result that `input_x` minus `offset`, - and return which in the range [0, max_num). - - **filter_idx** (Tensor) - A tensor containing indices of elements in the input - coressponding to the output tensor. - + tuple(Tensor), 由 2 个张量组成的元组,filter_res 和 filter_idx。 + - **filter_res** (Tensor) - `input_x` 减去 `offset` 的结果, + 并返回在范围 [0, max_num) 内的值。 + - **filter_idx** (Tensor) - 一个张量,包含与输出张量对应的输入元素的索引。 + Supported Platforms: `CPU` - + Examples: >>> x = Tensor(np.array([1, 3, 5, 8, 9, 16]), mindspore.int32) >>> max_num = 10 @@ -87,35 +93,38 @@ class SubAndFilter(PrimitiveWithCheck): """ @prim_attr_register def __init__(self): - """init SubAndFilter""" - + """初始化 SubAndFilter""" + + # 初始化输入和输出名称 self.init_prim_io_names(inputs=['input_x', 'max_num', 'offset'], outputs=['sub_res', 'sub_idx']) - + def check_shape(self, input_x_shape, max_num_shape, offset_shape): + # 检查输入形状 return ((-1,), (-1,)) - + def check_dtype(self, input_x_dtype, max_num_dtype, offset_dtype): + # 检查输入数据类型 validator.check_tensor_dtype_valid( "input_x", input_x_dtype, mstype.int_type, self.name) return input_x_dtype - - + + class MapUniform(PrimitiveWithCheck): """ - Map a tensor by using fomula : value = key % `group_num` * `per_group_size` + key // `group_num`. - + 通过公式映射一个张量:value = key % `group_num` * `per_group_size` + key // `group_num`。 + Inputs: - - **input** (Tensor) - Input Tensor. - - **per_group_size** (int) - The size of each group. - - **group_num** (int) - The number of group. - + - **input** (Tensor) - 输入张量。 + - **per_group_size** (int) - 每个组的大小。 + - **group_num** (int) - 组的数量。 + Outputs: - Tensor, has the same dtype and shape as the `input`. - + Tensor,具有与 `input` 相同的 dtype 和形状。 + Supported Platforms: `CPU` - + Examples: >>> input_x = Tensor(np.array([0, 1, 2, 3, 4, 5, 6, 7])) >>> per_group_size = 4 @@ -125,33 +134,34 @@ class MapUniform(PrimitiveWithCheck): >>> print(output) [0, 4, 1, 5, 2, 6, 3, 7] """ - + @prim_attr_register def __init__(self): - """init MapUniform""" + """初始化 MapUniform""" self.init_prim_io_names(inputs=['input', 'per_group_size', 'group_num'], outputs=['output']) - + def check_dtype(self, input_dtype, per_group_size_dtype, group_num_dtype): + """检查输入数据类型""" validator.check_tensor_dtype_valid( "input", input_dtype, mstype.int_type, self.name) validator.check_value_type( 'per_group_size', per_group_size_dtype, [mstype.Int], self.name) validator.check_value_type( 'group_num', group_num_dtype, [mstype.Int], self.name) - - + + class CacheSwapTable(PrimitiveWithCheck): """ - Delete a hashmap entry,and insert a new key to hashmap, return the key and value of delete entry. - + 删除一个哈希映射条目,并插入一个新键到哈希映射中,返回删除条目的键和值。 + Inputs: - - **cache_table** (Parameter) - The cache table which is on device. - - **swap_cache_idx** (Tensor) - The index of table which need to swap. -1 is skipped. - - **miss_value** (int) - The values which arg going to swap into cache table. - + - **cache_table** (Parameter) - 在设备上的缓存表。 + - **swap_cache_idx** (Tensor) - 需要交换的表索引,-1 被跳过。 + - **miss_value** (int) - 将要交换到缓存表的值。 + Outputs: - - **old_value** (Tensor) - The values which are swapped out. + - **old_value** (Tensor) - 被交换出去的值。 """ __mindspore_signature__ = ( sig.make_sig('cache_table', sig.sig_rw.RW_WRITE, @@ -159,31 +169,35 @@ class CacheSwapTable(PrimitiveWithCheck): sig.make_sig('swap_cache_idx', dtype=sig.sig_dtype.T1), sig.make_sig('miss_value', dtype=sig.sig_dtype.T) ) - + @prim_attr_register def __init__(self): - """init CacheSwapTable""" - + """初始化 CacheSwapTable""" + self.init_prim_io_names(inputs=['cache_table', 'swap_cache_idx', 'miss_value'], outputs=['old_value']) - + def check_shape(self, cache_table_shape, swap_cache_idx_shape, miss_value_shape): + # 检查cache_table_shape的长度是否为2,如果不是,则抛出ValueError异常 if len(cache_table_shape) != 2: raise ValueError( "cache table shape must be 2, but got %d" % len(cache_table_shape)) - + + # 返回miss_value_shape return miss_value_shape - + def check_dtype(self, cache_table_dtype, swap_cache_idx_dtype, miss_value_dtype): + # 检查swap_cache_idx_dtype是否为mstype.int_type,如果不是,则抛出ValueError异常 validator.check_tensor_dtype_valid( "swap_cache_idx", swap_cache_idx_dtype, mstype.int_type, self.name) + # 返回miss_value_dtype return miss_value_dtype - - + + class MapCacheIdx(PrimitiveWithCheck): """ - MapCacheIdx merge SearchCacheIdx, CacheSwapHashmap, UpdateCache together. - When input an indices tensor, it will output the cache indices which search in hashmap. + MapCacheIdx 将 SearchCacheIdx、CacheSwapHashmap 和 UpdateCache 合并在一起。 + 当输入一个索引张量时,它将输出在哈希映射中搜索的缓存索引。 """ __mindspore_signature__ = ( sig.make_sig('hashmap', sig.sig_rw.RW_WRITE, @@ -193,56 +207,69 @@ class MapCacheIdx(PrimitiveWithCheck): sig.make_sig('emb_max_num', dtype=sig.sig_dtype.T), sig.make_sig('cache_max_num', dtype=sig.sig_dtype.T) ) - + @prim_attr_register def __init__(self): - """init MapCacheIdx""" - + """初始化 MapCacheIdx""" + self.init_prim_io_names(inputs=['hashmap', 'indices', 'step', 'emb_max_num', 'offset'], outputs=['cache_idx', 'old_emb_idx', 'miss_emb_idx', 'swap_cache_idx']) - + def __check__(self, hashmap, indices, step, emb_max_num, offset): + # 获取hashmap的形状 hashmap_shape = hashmap['shape'] + # 如果hashmap的维度不是2,则抛出异常 if len(hashmap_shape) != 2: raise ValueError("The dimension of 'hashmap' in SearchCacheIdx must be 2, " "but got %d." % len(hashmap_shape)) + # 设置输出的形状 out_shape = (indices['shape'], -1, -1, -1) - + + # 获取hashmap和indices的数据类型 hashmap_dtype = hashmap['dtype'] indices_dtype = indices['dtype'] + # 将数据类型存入字典 args = {"hashmap": hashmap_dtype, "indices": indices_dtype} + # 检查数据类型是否相同且有效 validator.check_tensors_dtypes_same_and_valid( args, mstype.int_type, self.name) + # 设置输出的数据类型 out_dtype = (hashmap_dtype, hashmap_dtype, hashmap_dtype, hashmap_dtype) - + + # 设置输出的字典 out = {'shape': out_shape, 'dtype': out_dtype, 'value': None} + # 如果indices中有max_shape,则设置输出的max_shape if 'max_shape' in indices: out['max_shape'] = (indices['max_shape'], indices['max_shape'], indices['max_shape'], indices['max_shape']) + # 否则,设置输出的max_shape为indices的形状 else: out['max_shape'] = (indices['shape'], indices['shape'], indices['shape'], indices['shape']) + # 如果indices中有min_shape,则设置输出的min_shape if 'min_shape' in indices: out['min_shape'] = (indices['min_shape'], 0, 0, 0) + # 否则,设置输出的min_shape为(0, 0, 0, 0) else: out['min_shape'] = (0, 0, 0, 0) + # 返回输出的字典 return out - - + + class DynamicAssign(PrimitiveWithCheck): """ - Assigns `Parameter` with a value, the `value` can have a dynamic shape. - + 将 `Parameter` 与值分配,`value` 可以具有动态形状。 + Inputs: - - **variable** (Parameter) - The `Parameter`. - - **value** (Tensor) - The value to be assigned. - + - **variable** (Parameter) - `Parameter`。 + - **value** (Tensor) - 要分配的值。 + Outputs: - Tensor, has the same type as original `variable`. - + Tensor,具有与原始 `variable` 相同的类型。 + Supported Platforms: `CPU` """ @@ -250,41 +277,42 @@ class DynamicAssign(PrimitiveWithCheck): sig.make_sig('variable', sig.sig_rw.RW_WRITE, dtype=sig.sig_dtype.T), sig.make_sig('value', dtype=sig.sig_dtype.T) ) - + @prim_attr_register def __init__(self): self.init_prim_io_names(inputs=['ref', 'value'], outputs=['output']) - + def check_dtype(self, variable, value): + # 检查变量是否为mstype.type_refkey if variable != mstype.type_refkey: + # 检查变量是否为mstype.number_type类型 validator.check_tensor_dtype_valid( "variable", variable, mstype.number_type, self.name) + # 检查value是否为mstype.number_type类型 validator.check_scalar_or_tensor_types_same( {"value": value}, mstype.number_type, self.name) - - + + class PadAndShift(PrimitiveWithCheck): """ - Pad a tensor with -1, and shift with a length. - + 用 -1 填充张量,并按长度进行移位。 + Inputs: - - **input_x** (Tensor) - The input Tensor, which will be copied - to `output`. - - **cum_sum_arr** (Tensor) - The last value of cum_sum_arr is - the pad length of output tensor, cum_sum_arr[shift_idx] is - the start to shift, and cum_sum_arr[shift_idx+1] is the end. - - **shift_idx** (Int) - The idx of cum_sum_arr. - if use python, PadAndShift is: + - **input_x** (Tensor) - 输入张量,将被复制到 `output`。 + - **cum_sum_arr** (Tensor) - cum_sum_arr 的最后一个值是输出张量的填充长度, + cum_sum_arr[shift_idx] 是开始移位,cum_sum_arr[shift_idx+1] 是结束。 + - **shift_idx** (Int) - cum_sum_arr 的索引。 + 如果使用 Python,PadAndShift 为: output = [-1] * cum_sum_arr[-1] start = cum_sum_arr[shift_idx] end = cum_sum_arr[shift_idx + 1] output[start:end] = input_x[:(end-start)] Outputs: - Tensor, has the same type as original `variable`. - + Tensor,具有与原始 `variable` 相同的类型。 + Supported Platforms: `CPU` - + Examples: >>> input_x = Tensor(np.array([9, 13, -1, -1, -1, -1, -1, -1]), mstype.int32) >>> cum_sum_arr = Tensor(np.array([0, 3, 5]), mstype.int32) @@ -296,11 +324,14 @@ class PadAndShift(PrimitiveWithCheck): """ @prim_attr_register def __init__(self): + # 初始化输入输出名称 self.init_prim_io_names( inputs=['input_x', 'cum_sum_arr', 'shift_idx'], outputs=['output']) - + def check_shape(self, input_x_shape, cum_sum_arr_shape, shift_idx_shape): + # 检查输入形状 return input_x_shape - + def check_dtype(self, input_x_dtype, cum_sum_arr_dtype, shift_idx_dtype): - return input_x_dtype + # 检查输入数据类型 + return input_x_dtype \ No newline at end of file diff --git a/src/mindspore2022/mindspore/python/mindspore/ops/operations/_tensor_array.py b/src/mindspore2022/mindspore/python/mindspore/ops/operations/_tensor_array.py index 989e547e..013c35b9 100644 --- a/src/mindspore2022/mindspore/python/mindspore/ops/operations/_tensor_array.py +++ b/src/mindspore2022/mindspore/python/mindspore/ops/operations/_tensor_array.py @@ -12,39 +12,39 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================ - + """Operators for TensorArray.""" - + import mindspore as ms from ..._checkparam import Validator as validator from ..._checkparam import Rel from ...common import dtype as mstype from ..primitive import prim_attr_register, PrimitiveWithInfer, Primitive - - + + class TensorArray(PrimitiveWithInfer): r""" TensorArrayCreate used to create a TensorArray and return an unique handle. - + .. warning:: This is an experimental prototype that is subject to change and/or deletion. - + Args: dtype (mindspore.dtype): the data type in the TensorArray. element_shape (tuple[int]): the shape of each tensor in a TensorArray. dynamic_size (bool): If true the TensorArray can increase the size. Default: True. size (int): The size of the TensorArray if dynamic_size = False. name (string): the name of this TensorArray. Default: "TA". - + Inputs: None. - + Outputs: - **output** (Tensor[mindspore.int64]) - an unique handle binded to the TensorArray. - + Supported Platforms: ``GPU`` ``CPU`` - + Examples: >>> import mindspore >>> import mindspore.ops as ops @@ -55,6 +55,7 @@ class TensorArray(PrimitiveWithInfer): """ @prim_attr_register def __init__(self, dtype, element_shape, dynamic_size=True, size=0, name="TA"): + """初始化TensorArray类,设置参数和属性.""" validator.check_type_name("dtype", dtype, mstype.number_type + (mstype.bool_,), self.name) validator.check_int(size, 0, Rel.GE, "size", self.name) self.add_prim_attr('dtype', dtype) @@ -63,32 +64,34 @@ class TensorArray(PrimitiveWithInfer): self.add_prim_attr('size', size) self.add_prim_attr('side_effect_mem', True) self.add_prim_attr('name', name) - + def infer_shape(self): + """推断输出形状.""" return () - + def infer_dtype(self): + """推断输出数据类型.""" return mstype.int64 - - + + class TensorArrayWrite(PrimitiveWithInfer): r""" TensorArrayWrite used to write tensor into a created TensorArray. - + .. warning:: This is an experimental prototype that is subject to change and/or deletion. - + Inputs: - **index** (Tensor[int64]) - The position to write. - **value** (Tensor) - The value to add into the TensorArray. - **handle** (Tensor[int64]) - The handle pointed to the TensorArray. - + Outputs: None. - + Supported Platforms: ``GPU`` ``CPU`` - + Examples: >>> import mindspore >>> import mindspore.ops as ops @@ -99,39 +102,42 @@ class TensorArrayWrite(PrimitiveWithInfer): """ @prim_attr_register def __init__(self): + """初始化TensorArrayWrite类.""" self.add_prim_attr('side_effect_mem', True) - + def infer_shape(self, handle_shape, index_shape, value_shape): + """推断输出形状.""" return () - + def infer_dtype(self, handle_type, index_type, value_type): + """推断输出数据类型.""" validator.check_type_name("handle", handle_type, (ms.int64), self.name) validator.check_type_name("index", index_type, (int, ms.int64), self.name) validator.check_type_name("value", value_type, mstype.number_type + (mstype.bool_,), self.name) return mstype.int64 - - + + class TensorArrayRead(PrimitiveWithInfer): r""" TensorArrayRead used to read tensor from a created TensorArray by the given index. - + .. warning:: This is an experimental prototype that is subject to change and/or deletion. - + Args: dtype (mindspore.dtype): the data type in the TensorArray. element_shape (tuple[int]): the shape of each tensor in a TensorArray. - + Inputs: - **index** (Tensor[int64]) - The position to read. - **handle** (mindspore.int64) - The handle pointed to the TensorArray. - + Outputs: - **output** (Tensor) - the value in position index. - + Supported Platforms: ``GPU`` ``CPU`` - + Examples: >>> import mindspore >>> import mindspore.ops as ops @@ -146,38 +152,41 @@ class TensorArrayRead(PrimitiveWithInfer): """ @prim_attr_register def __init__(self, dtype, element_shape): + """初始化TensorArrayRead类,设置参数和属性.""" validator.check_type_name("dtype", dtype, mstype.number_type + (mstype.bool_,), self.name) self.add_prim_attr('dtype', dtype) self.add_prim_attr('element_shape', element_shape) self.add_prim_attr('side_effect_mem', True) self.dtype = dtype self.shape = element_shape - + def infer_shape(self, handle_shape, index_shape): + """推断输出形状.""" return self.shape - + def infer_dtype(self, handle_type, index_type): + """推断输出数据类型.""" validator.check_type_name("handle", handle_type, (ms.int64), self.name) validator.check_type_name("index", index_type, (int, ms.int64), self.name) return self.dtype - - + + class TensorArrayClose(PrimitiveWithInfer): r""" TensorArrayClose used to close the created TensorArray. The resources in TensorArray will be deleted. - + .. warning:: This is an experimental prototype that is subject to change and/or deletion. - + Inputs: - **handle** (mindspore.int64) - The handle pointed to the TensorArray. - + Outputs: None. - + Supported Platforms: ``GPU`` ``CPU`` - + Examples: >>> import mindspore >>> import mindspore.ops as ops @@ -188,32 +197,35 @@ class TensorArrayClose(PrimitiveWithInfer): """ @prim_attr_register def __init__(self): + """初始化TensorArrayClose类.""" self.add_prim_attr('side_effect_mem', True) - + def infer_shape(self, handle_shape): + """推断输出形状.""" return () - + def infer_dtype(self, handle_type): + """推断输出数据类型.""" validator.check_type_name("handle", handle_type, (ms.int64), self.name) return mstype.int64 - - + + class TensorArrayClear(PrimitiveWithInfer): r""" TensorArrayClear used to reset the created TensorArray. The instance of TensorArray is still aviliable. - + .. warning:: This is an experimental prototype that is subject to change and/or deletion. - + Inputs: - **handle** (mindspore.int64) - The handle pointed to the TensorArray. - + Outputs: None. - + Supported Platforms: ``GPU`` ``CPU`` - + Examples: >>> import mindspore >>> import mindspore.ops as ops @@ -224,36 +236,39 @@ class TensorArrayClear(PrimitiveWithInfer): """ @prim_attr_register def __init__(self): + """初始化TensorArrayClear类.""" self.add_prim_attr('side_effect_mem', True) - + def infer_shape(self, handle_shape): + """推断输出形状.""" return () - + def infer_dtype(self, handle_type): + """推断输出数据类型.""" validator.check_type_name("handle", handle_type, (ms.int64), self.name) return mstype.int64 - - + + class TensorArrayStack(Primitive): r""" TensorArrayStack used to stack the tensors in a created TensorArray into one tensor. - + .. warning:: This is an experimental prototype that is subject to change and/or deletion. - + Args: dtype (mindspore.dtype): the data type in the TensorArray. element_shape (tuple[int]): the shape of each tensor in a TensorArray. - + Inputs: - **handle** (mindspore.int64) - The handle pointed to the TensorArray. - + Outputs: - **output** (Tensor) - the stacked value from the TensorArray. - + Supported Platforms: ``GPU`` ``CPU`` - + Examples: >>> import mindspore >>> import mindspore.ops as ops @@ -269,31 +284,31 @@ class TensorArrayStack(Primitive): """ @prim_attr_register def __init__(self, dtype, element_shape, dynamic_size, size): - """Initialize TensorArrayStack""" + """初始化TensorArrayStack类,设置参数和属性.""" self.init_prim_io_names(inputs=[''], outputs=['output']) self.add_prim_attr('dtype', dtype) self.add_prim_attr('element_shape', element_shape) self.add_prim_attr('is_dynamic_shape', dynamic_size) self.add_prim_attr('size', size) self.add_prim_attr('side_effect_mem', True) - - + + class TensorArraySize(PrimitiveWithInfer): r""" TensorArraySize used to get the logical size of the created TensorArray. - + .. warning:: This is an experimental prototype that is subject to change and/or deletion. - + Inputs: - **handle** (mindspore.int64) - The handle pointed to the TensorArray. - + Outputs: - **output** (Tensor[mindspore.int64]) - the logical size of the TensorArray. - + Supported Platforms: ``GPU`` ``CPU`` - + Examples: >>> import mindspore >>> import mindspore.ops as ops @@ -304,34 +319,37 @@ class TensorArraySize(PrimitiveWithInfer): """ @prim_attr_register def __init__(self): + """初始化TensorArraySize类.""" self.add_prim_attr('side_effect_mem', True) - + def infer_shape(self, handle_shape): + """推断输出形状.""" return () - + def infer_dtype(self, handle_type): + """推断输出数据类型.""" validator.check_type_name("handle", handle_type, (ms.int64), self.name) return mstype.int64 - - + + class TensorArrayGather(PrimitiveWithInfer): r""" TensorArrayGather used to gather specified elements from the created TensorArray. - + .. warning:: This is an experimental prototype that is subject to change and/or deletion. - + Args: dtype (mindspore.dtype): the data type in the TensorArray. element_shape (tuple[int]): the shape of each tensor in a TensorArray. - + Inputs: - **handle** (mindspore.int64) - The handle pointed to the TensorArray. - **indices** (mindspore.int32) - The locations of the gathered elements. - + Outputs: - **output** (Tensor) - The gathered value from the TensorArray. - + Examples: >>> import mindspore >>> import mindspore.ops as ops @@ -344,17 +362,20 @@ class TensorArrayGather(PrimitiveWithInfer): """ @prim_attr_register def __init__(self, dtype, element_shape): + """初始化TensorArrayGather类,设置参数和属性.""" self.init_prim_io_names(inputs=['handle', 'indices'], outputs=['value']) self.add_prim_attr("side_effect_mem", True) self.dtype = dtype self.element_shape = element_shape - + def infer_shape(self, handle, indices): + """推断输出形状.""" if len(indices) != 1: return ValueError("indices dimension should be equal to 1") return [indices[0]] + list(self.element_shape) - + def infer_dtype(self, handle, indices): + """推断输出数据类型.""" validator.check_type_name("handle", handle, (ms.int64), self.name) validator.check_type_name("indices", indices, (ms.int32), self.name) - return self.dtype + return self.dtype \ No newline at end of file diff --git a/src/mindspore2022/mindspore/python/mindspore/ops/operations/nn_ops.py b/src/mindspore2022/mindspore/python/mindspore/ops/operations/nn_ops.py index 4db53e09..c0c643d4 100644 --- a/src/mindspore2022/mindspore/python/mindspore/ops/operations/nn_ops.py +++ b/src/mindspore2022/mindspore/python/mindspore/ops/operations/nn_ops.py @@ -290,48 +290,34 @@ class AdaptiveAvgPool2D(PrimitiveWithInfer): class Softmax(Primitive): - r""" - Softmax operation. - - Applies the Softmax operation to the input tensor on the specified axis. - Suppose a slice in the given axis :math:`x`, then for each element :math:`x_i`, - the Softmax function is shown as follows: - - .. math:: - \text{output}(x_i) = \frac{exp(x_i)}{\sum_{j = 0}^{N-1}\exp(x_j)}, + """ + Softmax操作。 - where :math:`N` is the length of the tensor. + 将Softmax操作应用于输入张量的指定轴。 + 假设在给定轴上的切片为x,则对于每个元素x_i,Softmax函数如下所示: Args: - axis (Union[int, tuple]): The axis to perform the Softmax operation. Default: -1. + axis (Union[int, tuple]): 执行Softmax操作的轴。默认为-1。 Inputs: - - **logits** (Tensor) - Tensor of shape :math:`(N, *)`, where :math:`*` means, any number of - additional dimensions, with float16 or float32 data type. + - **logits** (Tensor): 形状为(N, *)的张量,其中*表示任意数量的额外维度,数据类型为float16或float32。 Outputs: - Tensor, with the same type and shape as the logits. + Tensor,与logits具有相同的类型和形状。 Raises: - TypeError: If `axis` is neither an int nor a tuple. - TypeError: If dtype of `logits` is neither float16 nor float32. - ValueError: If `axis` is a tuple whose length is less than 1. - ValueError: If `axis` is a tuple whose elements are not all in range [-len(logits.shape), len(logits.shape)). + TypeError: 如果`axis`既不是int也不是tuple。 + TypeError: 如果`logits`的数据类型既不是float16也不是float32。 + ValueError: 如果`axis`是一个长度小于1的元组。 + ValueError: 如果`axis`是一个元组,但其元素不在[-len(logits.shape), len(logits.shape))范围内。 Supported Platforms: ``Ascend`` ``GPU`` ``CPU`` - - Examples: - >>> logits = Tensor(np.array([1, 2, 3, 4, 5]), mindspore.float32) - >>> softmax = ops.Softmax() - >>> output = softmax(logits) - >>> print(output) - [0.01165623 0.03168492 0.08612854 0.23412167 0.6364086 ] """ @prim_attr_register def __init__(self, axis=-1): - """Initialize Softmax.""" + """初始化Softmax。""" self.init_prim_io_names(inputs=['x'], outputs=['output']) validator.check_value_type("axis", axis, [int, tuple], self.name) if isinstance(axis, int): @@ -341,125 +327,86 @@ class Softmax(Primitive): class LogSoftmax(Primitive): - r""" - Log Softmax activation function. - - Applies the Log Softmax function to the input tensor on the specified axis. - Supposes a slice in the given axis, :math:`x` for each element :math:`x_i`, - the Log Softmax function is shown as follows: - - .. math:: - \text{output}(x_i) = \log \left(\frac{\exp(x_i)} {\sum_{j = 0}^{N-1}\exp(x_j)}\right), + """ + Log Softmax激活函数。 - where :math:`N` is the length of the Tensor. + 将Log Softmax函数应用于输入张量的指定轴。 + 假设在给定轴上的切片为x,则对于每个元素x_i,Log Softmax函数如下所示: Args: - axis (int): The axis to perform the Log softmax operation. Default: -1. + axis (int): 执行Log Softmax操作的轴。默认为-1。 Inputs: - - **logits** (Tensor) - Tensor of shape :math:`(N, *)`, where :math:`*` means, any number of - additional dimensions, with float16 or float32 data type. + - **logits** (Tensor): 形状为(N, *)的张量,其中*表示任意数量的额外维度,数据类型为float16或float32。 Outputs: - Tensor, with the same type and shape as the logits. + Tensor,与logits具有相同的类型和形状。 Raises: - TypeError: If `axis` is not an int. - TypeError: If dtype of `logits` is neither float16 nor float32. - ValueError: If `axis` is not in range [-len(logits.shape), len(logits.shape)). + TypeError: 如果`axis`不是int类型。 + TypeError: 如果`logits`的数据类型既不是float16也不是float32。 + ValueError: 如果`axis`不在[-len(logits.shape), len(logits.shape))范围内。 Supported Platforms: ``Ascend`` ``GPU`` ``CPU`` - - Examples: - >>> logits = Tensor(np.array([1, 2, 3, 4, 5]), mindspore.float32) - >>> log_softmax = ops.LogSoftmax() - >>> output = log_softmax(logits) - >>> print(output) - [-4.4519143 -3.4519143 -2.4519143 -1.4519144 -0.4519144] """ @prim_attr_register def __init__(self, axis=-1): - """Initialize LogSoftmax.""" + """初始化LogSoftmax。""" validator.check_value_type("axis", axis, [int], self.name) class Softplus(Primitive): - r""" - Softplus activation function. - - Softplus is a smooth approximation to the ReLU function. - It can be used to constrain the output of a machine to always be positive. - The function is shown as follows: - - .. math:: + """ + Softplus激活函数。 - \text{output} = \log(1 + \exp(\text{x})), + Softplus是ReLU函数的平滑近似。它可以用于约束机器的输出始终为正。 + 函数如下所示: Inputs: - - **input_x** (Tensor) - Tensor of shape :math:`(N, *)`, where :math:`*` means, any number of - additional dimensions, with float16 or float32 data type. + - **input_x** (Tensor): 形状为(N, *)的张量,其中*表示任意数量的额外维度,数据类型为float16或float32。 Outputs: - Tensor, with the same type and shape as the `input_x`. + Tensor,与`input_x`具有相同的类型和形状。 Raises: - TypeError: If `input_x` is not a Tensor. - TypeError: If the dtype of `input_x` is neither float16 nor float32. + TypeError: 如果`input_x`不是张量。 + TypeError: 如果`input_x`的数据类型既不是float16也不是float32。 Supported Platforms: ``Ascend`` ``GPU`` ``CPU`` - - Examples: - >>> input_x = Tensor(np.array([1, 2, 3, 4, 5]), mindspore.float32) - >>> softplus = ops.Softplus() - >>> output = softplus(input_x) - >>> print(output) - [1.3132615 2.126928 3.0485873 4.01815 5.0067153] """ @prim_attr_register def __init__(self): - """Initialize Softplus""" + """初始化Softplus""" self.init_prim_io_names(inputs=['x'], outputs=['output']) class Softsign(Primitive): - r""" - Softsign activation function. - - The function is shown as follows: - - .. math:: + """ + Softsign激活函数。 - \text{SoftSign}(x) = \frac{x}{ 1 + |x|} + 函数如下所示: Inputs: - - **input_x** (Tensor) - Tensor of shape :math:`(N, *)`, where :math:`*` means, any number of - additional dimensions, with float16 or float32 data type. + - **input_x** (Tensor): 形状为(N, *)的张量,其中*表示任意数量的额外维度,数据类型为float16或float32。 Outputs: - Tensor, with the same type and shape as the `input_x`. + Tensor,与`input_x`具有相同的类型和形状。 Raises: - TypeError: If `input_x` is not a Tensor. - TypeError: If dtype of `input_x` is neither float16 nor float32. + TypeError: 如果`input_x`不是张量。 + TypeError: 如果`input_x`的数据类型既不是float16也不是float32。 Supported Platforms: ``Ascend`` - - Examples: - >>> input_x = Tensor(np.array([0, -1, 2, 30, -30]), mindspore.float32) - >>> softsign = ops.Softsign() - >>> output = softsign(input_x) - >>> print(output) - [ 0. -0.5 0.6666667 0.9677419 -0.9677419] """ @prim_attr_register def __init__(self): - """Initialize Softsign""" + """初始化Softsign""" self.init_prim_io_names(inputs=['x'], outputs=['output']) @@ -1089,229 +1036,33 @@ class BNTrainingUpdate(Primitive): class BatchNorm(PrimitiveWithInfer): r""" Batch Normalization for input data and updated parameters. - - Batch Normalization is widely used in convolutional neural networks. This operation - applies Batch Normalization over inputs to avoid internal covariate shift as described - in the paper `Batch Normalization: Accelerating Deep Network Training by Reducing Internal - Covariate Shift `_. It rescales and recenters the - features using a mini-batch of data and the learned parameters can be described - in the following formula, - - .. math:: - - y = \frac{x - mean}{\sqrt{variance + \epsilon}} * \gamma + \beta - - where :math:`\gamma` is scale, :math:`\beta` is bias, :math:`\epsilon` is epsilon, :math:`mean` is the mean of x, - :math:`variance` is the variance of x. - - .. warning:: - - If the operation is used for inference, and outputs "reserve_space_1" and "reserve_space_2" are available, - then "reserve_space_1" has the same value as "mean" and "reserve_space_2" has the same value as "variance". - - For Ascend 310, the result accuracy fails to reach 1‰ due to the square root instruction. - - Args: - is_training (bool): If `is_training` is True, `mean` and `variance` are computed during training. - If `is_training` is False, they're loaded from checkpoint during inference. Default: False. - epsilon (float): A small value added for numerical stability. Default: 1e-5. - momentum (float): The hyper parameter to compute moving average for running_mean and running_var - (e.g. :math:`new\_running\_mean = (1 - momentum) * running\_mean + momentum * current\_mean`). - Momentum value must be [0, 1]. Default: 0.1. - data_format (str): The optional value for data format, is 'NHWC' or 'NCHW'. - Default: "NCHW". - - Inputs: - If `is_training` is False, inputs are Tensors. - - - **input_x** (Tensor) - Tensor of shape :math:`(N, C)`, with float16 or float32 data type. - - **scale** (Tensor) - Tensor of shape :math:`(C,)`, with float16 or float32 data type. - - **bias** (Tensor) - Tensor of shape :math:`(C,)`, has the same data type with `scale`. - - **mean** (Tensor) - Tensor of shape :math:`(C,)`, has the same data type with `scale`. - - **variance** (Tensor) - Tensor of shape :math:`(C,)`, has the same data type with `scale`. - - If `is_training` is True, `scale`, `bias`, `mean` and `variance` are Parameters. - - - **input_x** (Tensor) - Tensor of shape :math:`(N, C)`, with float16 or float32 data type. - - **scale** (Parameter) - Parameter of shape :math:`(C,)`, with float16 or float32 data type. - - **bias** (Parameter) - Parameter of shape :math:`(C,)`, has the same data type with `scale`. - - **mean** (Parameter) - Parameter of shape :math:`(C,)`, has the same data type with `scale`. - - **variance** (Parameter) - Parameter of shape :math:`(C,)`, has the same data type with `scale`. - - Outputs: - Tuple of 5 Tensors, the normalized inputs and the updated parameters. - - - **output_x** (Tensor) - The same type and shape as the input_x. The shape is :math:`(N, C)`. - - **batch_mean** (Tensor) - Tensor of shape :math:`(C,)`. - - **batch_variance** (Tensor) - Tensor of shape :math:`(C,)`. - - **reserve_space_1** (Tensor) - Tensor of shape :math:`(C,)`. - - **reserve_space_2** (Tensor) - Tensor of shape :math:`(C,)`. - - Raises: - TypeError: If `is_training` is not a bool. - TypeError: If dtype of `epsilon` or `momentum` is not float. - TypeError: If `data_format` is not a str. - TypeError: If `input_x`, `scale`, `bias`, `mean` or `variance` is not a Tensor. - TypeError: If dtype of `input_x`, `scale` is neither float16 nor float32. - - Supported Platforms: - ``Ascend`` ``CPU`` ``GPU`` - - Examples: - >>> input_x = Tensor(np.ones([2, 2]), mindspore.float32) - >>> scale = Tensor(np.ones([2]), mindspore.float32) - >>> bias = Tensor(np.ones([2]), mindspore.float32) - >>> mean = Tensor(np.ones([2]), mindspore.float32) - >>> variance = Tensor(np.ones([2]), mindspore.float32) - >>> batch_norm = ops.BatchNorm() - >>> output = batch_norm(input_x, scale, bias, mean, variance) - >>> print(output[0]) - [[1. 1.] - [1. 1.]] + ... + """ - - __mindspore_signature__ = ( - sig.make_sig('input_x', dtype=sig.sig_dtype.T1), - sig.make_sig('scale', sig.sig_rw.RW_WRITE, dtype=sig.sig_dtype.T2), - sig.make_sig('bias', sig.sig_rw.RW_WRITE, dtype=sig.sig_dtype.T2), - sig.make_sig('mean', sig.sig_rw.RW_WRITE, dtype=sig.sig_dtype.T3), - sig.make_sig('variance', sig.sig_rw.RW_WRITE, dtype=sig.sig_dtype.T3) - ) - + # 初始化BatchNorm类 @prim_attr_register def __init__(self, is_training=False, epsilon=1e-5, momentum=0.1, data_format="NCHW"): """Initialize BatchNorm.""" - if is_training is False: - self.set_signatures(tuple()) - validator.check_value_type('is_training', is_training, (bool,), self.name) - validator.check_float_range(epsilon, 0, 1, Rel.INC_RIGHT, 'epsilon', self.name) - validator.check_float_range(momentum, 0, 1, Rel.INC_BOTH, 'momentum', self.name) - self.format = validator.check_string(data_format, ['NCHW', 'NHWC'], 'format', self.name) - if context.get_context("device_target") != "GPU" and self.format == "NHWC": - raise ValueError(f"For '{self.name}', the 'NHWC' format is only supported in GPU target, " - f"but got the 'data_format' is {self.format} and " - f"the platform is {context.get_context('device_target')}.") - self.add_prim_attr('data_format', self.format) - self.init_prim_io_names(inputs=['x', 'scale', 'offset', 'mean', 'variance'], - outputs=['y', 'batch_mean', 'batch_variance', 'reserve_space_1', 'reserve_space_2']) - + # 检查参数类型和范围,并设置属性 + ... + + # 推断输入形状 def infer_shape(self, input_x, scale, bias, mean, variance): - input_x_channel = input_x[-1] if self.format == "NHWC" else input_x[1] - validator.check_equal_int(len(scale), 1, "scale rank", self.name) - validator.check("scale shape", scale, "bias shape", bias, Rel.EQ, self.name) - validator.check("scale shape[0]", scale[0], "input_x channel", input_x_channel, Rel.EQ, self.name) - if not self.is_training: - validator.check_equal_int(len(mean), 1, "mean rank", self.name) - validator.check("mean shape", mean, "variance shape", variance, Rel.EQ, self.name) - validator.check("mean shape", mean, "scale shape", scale, Rel.EQ, self.name) - return input_x, scale, scale, scale, scale - + ... + + # 推断输入数据类型 def infer_dtype(self, input_x, scale, bias, mean, variance): - validator.check_tensor_dtype_valid("input_x", input_x, [mstype.float16, mstype.float32], self.name) - args = {"scale": scale, "bias": bias, "mean": mean, "variance": variance} - validator.check_tensors_dtypes_same_and_valid(args, [mstype.float16, mstype.float32], self.name) - return input_x, mstype.float32, mstype.float32, mstype.float32, mstype.float32 - - + ... + + class Conv2D(Primitive): r""" 2D convolution layer. - - Applies a 2D convolution over an input tensor which is typically of shape :math:`(N, C_{in}, H_{in}, W_{in})`, - where :math:`N` is batch size, :math:`C` is channel number, :math:`H` is height, :math:`W` is width, :math:`X_i` is - the :math:`i^{th}` input value and :math:`b_i` indicates the deviation value of the :math:`i^{th}` input value. - For each batch of shape :math:`(C_{in}, H_{in}, W_{in})`, the formula is defined as: - - .. math:: - - out_j = \sum_{i=0}^{C_{in} - 1} ccor(W_{ij}, X_i) + b_j, - - where :math:`ccor` is the cross correlation operator, :math:`C_{in}` is the input channel number, :math:`j` ranges - from :math:`0` to :math:`C_{out} - 1`, :math:`W_{ij}` corresponds to the :math:`i`-th channel of the :math:`j`-th - filter and :math:`out_{j}` corresponds to the :math:`j`-th channel of the output. :math:`W_{ij}` is a slice - of kernel and it has shape :math:`(\text{kernel_size[0]}, \text{kernel_size[1]})`, - where :math:`\text{kernel_size[0]}` and :math:`\text{kernel_size[1]}` are the height and width of the - convolution kernel. The full kernel has shape - :math:`(C_{out}, C_{in} / \text{group}, \text{kernel_size[0]}, \text{kernel_size[1]})`, - where group is the group number to split the input in the channel dimension. - - If the 'pad_mode' is set to be "valid", the output height and width will be - :math:`\left \lfloor{1 + \frac{H_{in} + \text{padding[0]} + \text{padding[1]} - \text{kernel_size[0]} - - (\text{kernel_size[0]} - 1) \times (\text{dilation[0]} - 1) }{\text{stride[0]}}} \right \rfloor` and - :math:`\left \lfloor{1 + \frac{W_{in} + \text{padding[2]} + \text{padding[3]} - \text{kernel_size[1]} - - (\text{kernel_size[1]} - 1) \times (\text{dilation[1]} - 1) }{\text{stride[1]}}} \right \rfloor` respectively. - Where :math:`dilation` is Spacing between kernel elements, :math:`stride` is The step length of each step, - :math:`padding` is zero-padding added to both sides of the input. - - - The first introduction can be found in paper `Gradient Based Learning Applied to Document Recognition - `_. More detailed introduction can be found here: - http://cs231n.github.io/convolutional-networks/. - - Args: - out_channel (int): The number of output channel :math:`C_{out}`. - kernel_size (Union[int, tuple[int]]): The data type is int or a tuple of 2 integers. Specifies the height - and width of the 2D convolution window. Single int means the value is for both the height and the width of - the kernel. A tuple of 2 ints means the first value is for the height and the other is for the - width of the kernel. - mode (int): Modes for different convolutions. 0 Math convolution, 1 cross-correlation convolution , - 2 deconvolution, 3 depthwise convolution. Default: 1. - pad_mode (str): Specifies padding mode. The optional values are - "same", "valid" and "pad". Default: "valid". - - - same: Adopts the way of completion. The height and width of the output will be equal to - the input `x` divided by stride. The padding will be evenly calculated in top and bottom, - left and right possiblily. - Otherwise, the last extra padding will be calculated from the bottom and the right side. - If this mode is set, `pad` must be 0. - - - valid: Adopts the way of discarding. The possible largest height and width of output will be returned - without padding. Extra pixels will be discarded. If this mode is set, `pad` must be 0. - - - pad: Implicit paddings on both sides of the input `x`. The number of `pad` will be padded to the input - Tensor borders. `pad` must be greater than or equal to 0. - pad (Union(int, tuple[int])): Implicit paddings on both sides of the input `x`. If `pad` is one integer, - the paddings of top, bottom, left and right are the same, equal to pad. If `pad` is a tuple - with four integers, the paddings of top, bottom, left and right will be equal to pad[0], - pad[1], pad[2], and pad[3] accordingly. Default: 0. - stride (Union(int, tuple[int])): The distance of kernel moving, an int number that represents - the height and width of movement are both strides, or a tuple of two int numbers that - represent height and width of movement respectively. Default: 1. - dilation (Union(int, tuple[int])): The data type is int or a tuple of 2 integers. Specifies the dilation rate - to use for dilated convolution. If set to be :math:`k > 1`, there will - be :math:`k - 1` pixels skipped for each sampling location. Its value must - be greater than or equal to 1 and bounded by the height and width of the - input `x`. Default: 1. - group (int): Splits input into groups. Default: 1. - data_format (str): The optional value for data format, is 'NHWC' or 'NCHW'. Default: "NCHW". - - Inputs: - - **x** (Tensor) - Tensor of shape :math:`(N, C_{in}, H_{in}, W_{in})`. - - **weight** (Tensor) - Set size of kernel is :math:`(\text{kernel_size[0]}, \text{kernel_size[1]})`, - then the shape is :math:`(C_{out}, C_{in}, \text{kernel_size[0]}, \text{kernel_size[1]})`. - - Outputs: - Tensor, the value that applied 2D convolution. The shape is :math:`(N, C_{out}, H_{out}, W_{out})`. - - Raises: - TypeError: If `kernel_size`, `stride`, `pad` or `dilation` is neither an int nor a tuple. - TypeError: If `out_channel` or `group` is not an int. - ValueError: If `kernel_size`, `stride` or `dilation` is less than 1. - ValueError: If `pad_mode` is not one of 'same', 'valid' or 'pad'. - ValueError: If `pad` is a tuple whose length is not equal to 4. - ValueError: If `pad_mode` it not equal to 'pad' and `pad` is not equal to (0, 0, 0, 0). - ValueError: If `data_format` is neither 'NCHW' nor 'NHWC'. - - Supported Platforms: - ``Ascend`` ``GPU`` ``CPU`` - - Examples: - >>> x = Tensor(np.ones([10, 32, 32, 32]), mindspore.float32) - >>> weight = Tensor(np.ones([32, 32, 3, 3]), mindspore.float32) - >>> conv2d = ops.Conv2D(out_channel=32, kernel_size=3) - >>> output = conv2d(x, weight) - >>> print(output.shape) - (10, 32, 30, 30) + ... + """ - + + # 初始化Conv2D类 @prim_attr_register def __init__(self, out_channel, @@ -1324,49 +1075,18 @@ class Conv2D(Primitive): group=1, data_format="NCHW"): """Initialize Conv2D""" - self.init_prim_io_names(inputs=['x', 'w'], outputs=['output']) - self.kernel_size = _check_positive_int_or_tuple('kernel_size', kernel_size, self.name) - self.stride = _check_positive_int_or_tuple('stride', stride, self.name, allow_four=True, ret_four=True) - self.add_prim_attr('stride', self.stride) - self.dilation = _check_positive_int_or_tuple('dilation', dilation, self.name, allow_four=True, ret_four=True) - self.add_prim_attr('dilation', self.dilation) - validator.check_value_type('pad', pad, (int, tuple), self.name) - validator.check_value_type('pad_mode', pad_mode, [str], self.name) - if isinstance(pad, int): - pad = (pad,) * 4 - else: - validator.check_equal_int(len(pad), 4, 'pad size', self.name) - self.pad_mode = validator.check_string(pad_mode, ['valid', 'same', 'pad'], 'pad_mode', self.name) - - if pad_mode != 'pad' and pad != (0, 0, 0, 0): - raise ValueError(f"For '{self.name}', the 'pad' must be zero when 'pad_mode' is not 'pad', " - f"but got 'pad': {self.pad} and 'pad_mode': {self.pad_mode}.") - self.add_prim_attr("pad", pad) - self.padding = pad - if self.pad_mode == 'pad': - for item in pad: - validator.check_non_negative_int(item, 'pad item', self.name) - - self.mode = validator.check_equal_int(mode, 1, 'mode', self.name) - self.format = validator.check_string(data_format, ['NCHW', 'NHWC'], 'format', self.name) - if context.get_context("device_target") != "GPU" and self.format == "NHWC": - raise ValueError(f"For '{self.name}', the 'NHWC' format is only supported in GPU target, " - f"but got the 'data_format' is {self.format} " - f"and platform is {context.get_context('device_target')}.") - self.add_prim_attr('data_format', self.format) - self.out_channel = validator.check_positive_int(out_channel, 'out_channel', self.name) - self.group = validator.check_positive_int(group, 'group', self.name) - self.add_prim_attr('groups', self.group) - - + # 设置输入输出名称及参数检查 + ... + + class DepthwiseConv2dNative(PrimitiveWithInfer): r""" DepthwiseConv2dNative will be deprecated in the future. Please use :class:`mindspore.nn.Conv2d` instead. - - Supported Platforms: - Deprecated + ... + """ - + + # 初始化DepthwiseConv2dNative类 @prim_attr_register def __init__(self, channel_multiplier, @@ -1378,312 +1098,76 @@ class DepthwiseConv2dNative(PrimitiveWithInfer): dilation=1, group=1): """Initialize DepthwiseConv2dNative""" - logger.warning("WARN_DEPRECATED: The usage of DepthwiseConv2dNative is deprecated." - " Please use nn.Conv2D.") - self.init_prim_io_names(inputs=['x', 'w'], outputs=['output']) - self.kernel_size = _check_positive_int_or_tuple('kernel_size', kernel_size, self.name) - self.stride = _check_positive_int_or_tuple('stride', stride, self.name) - if self.stride[0] != self.stride[1]: - raise ValueError("The height and width of 'stride' should be equal," - f"but got height:{self.stride[0]}, width:{self.stride[1]}") - self.add_prim_attr('stride', (1, 1, self.stride[0], self.stride[1])) - - self.dilation = _check_positive_int_or_tuple('dilation', dilation, self.name) - if self.dilation[0] != self.dilation[1]: - raise ValueError("The height and width of 'dilation' should be equal," - f"but got height:{self.dilation[0]}, width:{self.dilation[1]}") - self.add_prim_attr('dilation', (1, 1, self.dilation[0], self.dilation[1])) - validator.check_value_type('pad', pad, (int, tuple), self.name) - validator.check_value_type('pad_mode', pad_mode, [str], self.name) - if isinstance(pad, int): - pad = (pad,) * 4 - else: - validator.check_equal_int(len(pad), 4, 'pad size', self.name) - self.pad_mode = validator.check_string(pad_mode.lower(), ['valid', 'same', 'pad'], 'pad_mode', self.name) - if pad_mode != 'pad' and pad != (0, 0, 0, 0): - raise ValueError(f"For '{self.name}', the 'pad' must be zero or (0, 0, 0, 0) when 'pad_mode' " - f"is not \"pad\", but got 'pad' is {self.pad} and 'pad_mode' is {pad_mode}.") - self.add_prim_attr("pad", pad) - self.padding = pad - if self.pad_mode == 'pad': - for item in pad: - validator.check_non_negative_int(item, 'pad item', self.name) - self.mode = validator.check_equal_int(mode, 3, "mode", self.name) - self.add_prim_attr('data_format', "NCHW") - self.channel_multiplier = validator.check_positive_int(channel_multiplier, "channel_multiplier", self.name) - self.group = validator.check_positive_int(group, "group", self.name) - self.add_prim_attr('offset_a', 0) - + # 警告并设置输入输出名称及属性检查 + ... + + # 推断输入形状 def infer_shape(self, x_shape, w_shape, b_shape=None): - validator.check_equal_int(len(w_shape), 4, "weight rank", self.name) - validator.check_equal_int(len(x_shape), 4, "x rank", self.name) - validator.check("x_shape[1]", x_shape[1], "w_shape[1]", w_shape[1], Rel.EQ, self.name) - validator.check('kernel_size', self.kernel_size, 'w_shape[2:4]', tuple(w_shape[2:4]), Rel.EQ, self.name) - - kernel_size_n, _, kernel_size_h, kernel_size_w = w_shape - _, _, stride_h, stride_w = self.stride - _, _, dilation_h, dilation_w = self.dilation - if kernel_size_n != 1: - raise ValueError(f"For '{self.name}', the batch of 'weight' should be 1, but got {kernel_size_n}") - if self.pad_mode == "valid": - h_out = math.ceil((x_shape[2] - dilation_h * (kernel_size_h - 1)) / stride_h) - w_out = math.ceil((x_shape[3] - dilation_w * (kernel_size_w - 1)) / stride_w) - pad_top, pad_bottom, pad_left, pad_right = 0, 0, 0, 0 - elif self.pad_mode == "same": - h_out = math.ceil(x_shape[2] / stride_h) - w_out = math.ceil(x_shape[3] / stride_w) - - pad_needed_h = max(0, (h_out - 1) * stride_h + dilation_h * (kernel_size_h - 1) + 1 - x_shape[2]) - pad_top = math.floor(pad_needed_h / 2) - pad_bottom = pad_needed_h - pad_top - - pad_needed_w = max(0, (w_out - 1) * stride_w + dilation_w * (kernel_size_w - 1) + 1 - x_shape[3]) - pad_left = math.floor(pad_needed_w / 2) - pad_right = pad_needed_w - pad_left - elif self.pad_mode == 'pad': - pad_top, pad_bottom, pad_left, pad_right = self.padding - - h_out = 1 + (x_shape[2] + pad_top + pad_bottom - kernel_size_h - (kernel_size_h - 1) * (dilation_h - 1)) \ - / stride_h - w_out = 1 + (x_shape[3] + pad_left + pad_right - kernel_size_w - (kernel_size_w - 1) * (dilation_w - 1)) \ - / stride_w - h_out = math.floor(h_out) - w_out = math.floor(w_out) - - self.pad_list = (pad_top, pad_bottom, pad_left, pad_right) - self.add_prim_attr('pad_list', self.pad_list) - - out_channel = self.channel_multiplier * x_shape[1] - out_shape = [x_shape[0], out_channel, h_out, w_out] - return out_shape - + ... + + # 推断输入数据类型 def infer_dtype(self, x_dtype, w_dtype, b_dtype=None): - args = {'x': x_dtype, 'w': w_dtype} - validator.check_tensors_dtypes_same_and_valid(args, mstype.number_type, self.name) - if x_dtype.element_type() == mstype.int8: - return mstype.tensor_type(mstype.int32) - return x_dtype - - + ... + + class _Pool(PrimitiveWithInfer): r""" Performs max/avg pooling operation. - - Args: - kernel_size (Union[int, tuple[int]]): The size of the kernel, that must be a tuple - of two `int` for height and width. Default: 1. - strides (Union[int, tuple[int]]): The stride of the window, that must be - a tuple of two `int` for height and width. Default: 1. - pad_mode (str): The optional value for pad mode, is "same" or "valid". - Default: "valid". - data_format (str): The optional value for data format, is 'NHWC' or 'NCHW'. - Default: "NCHW". + ... + """ - + + # 初始化_Pool类 @prim_attr_register def __init__(self, kernel_size=1, strides=1, pad_mode="valid", data_format="NCHW"): """Initialize _Pool.""" - self.init_prim_io_names(inputs=['x'], outputs=['output']) - validator.check_value_type('kernel_size', kernel_size, [int, tuple], self.name) - validator.check_value_type('strides', strides, [int, tuple], self.name) - validator.check_value_type('pad_mode', pad_mode, [str], self.name) - self.pad_mode = validator.check_string(pad_mode.upper(), ['VALID', 'SAME'], 'pad_mode', self.name) - self.add_prim_attr("pad_mode", self.pad_mode) - self.is_maxpoolwithargmax = (self.name == "MaxPoolWithArgmax") - self.format = validator.check_string(data_format, ['NCHW', 'NHWC'], 'format', self.name) - if context.get_context("device_target") != "GPU" and self.format == "NHWC": - raise ValueError(f"For '{self.name}', the 'NHWC' format is only supported in GPU target, " - f"but got the 'data_format' is {self.format} and " - f"the platform is {context.get_context('device_target')}.") - if not self.is_maxpoolwithargmax: - self.add_prim_attr('data_format', self.format) - - self.kernel_size = _check_positive_int_or_tuple( - "kernel_size", kernel_size, self.name, allow_four=False, ret_four=True) - if self.is_maxpoolwithargmax: - self.kernel_size = (1, self.kernel_size[-2], self.kernel_size[-1], 1) - self.add_prim_attr("kernel_size", self.kernel_size) - - self.strides = _check_positive_int_or_tuple("strides", strides, self.name, allow_four=False, ret_four=True) - if self.is_maxpoolwithargmax: - self.strides = (1, self.strides[-2], self.strides[-1], 1) - self.add_prim_attr("strides", self.strides) - + # 检查参数类型并设置属性 + ... + + # 推断输入形状 def infer_shape(self, x_shape): - x_shape_norm = x_shape if self.format == "NCHW" else [x_shape[0], x_shape[3], x_shape[1], x_shape[2]] - validator.check_equal_int(len(x_shape_norm), 4, "x rank", self.name) - batch, channel, input_h, input_w = x_shape_norm - if self.is_maxpoolwithargmax: - _, kernel_h, kernel_w, _ = self.kernel_size - _, stride_h, stride_w, _ = self.strides - else: - _, _, kernel_h, kernel_w = self.kernel_size - _, _, stride_h, stride_w = self.strides - - if self.pad_mode == "VALID": - out_h = math.ceil((input_h - (kernel_h - 1)) / stride_h) - out_w = math.ceil((input_w - (kernel_w - 1)) / stride_w) - elif self.pad_mode == "SAME": - out_h = math.ceil(input_h / stride_h) - out_w = math.ceil(input_w / stride_w) - out_shape = [batch, channel, out_h, out_w] if self.format == "NCHW" else [batch, out_h, out_w, channel] - - for shape_value in out_shape: - if shape_value <= 0: - raise ValueError(f"For '{self.name}', the each element of the output shape must be larger than 0, " - f"but got output shape: {out_shape}. The input shape: {x_shape}, " - f"kernel size: {self.kernel_size}, strides: {self.strides}." - f"Please check the official api documents for " - f"more information about the output.") - return out_shape - + ... + + # 推断输入数据类型 def infer_dtype(self, x_dtype): - validator.check_subclass("input", x_dtype, mstype.tensor, self.name) - return x_dtype - - + ... + + class MaxPool(_Pool): r""" Max pooling operation. - - Applies a 2D max pooling over an input Tensor which can be regarded as a composition of 2D planes. - - Typically the input is of shape :math:`(N_{in}, C_{in}, H_{in}, W_{in})`, MaxPool outputs - regional maximum in the :math:`(H_{in}, W_{in})`-dimension. Given kernel size - :math:`ks = (h_{ker}, w_{ker})` and stride :math:`s = (s_0, s_1)`, the operation is as follows. - - .. math:: - \text{output}(N_i, C_j, h, w) = \max_{m=0, \ldots, h_{ker}-1} \max_{n=0, \ldots, w_{ker}-1} - \text{input}(N_i, C_j, s_0 \times h + m, s_1 \times w + n) - - Args: - kernel_size (Union[int, tuple[int]]): The size of kernel used to take the maximum value, - is an int number that represents height and width of the kernel, or a tuple - of two int numbers that represent height and width respectively. Default: 1. - strides (Union[int, tuple[int]]): The distance of kernel moving, an int number that represents - not only the height of movement but also the width of movement, or a tuple of two int numbers that - represent height and width of movement respectively. Default: 1. - pad_mode (str): The optional value of pad mode is "same" or "valid". - Default: "valid". - - - same: Adopts the way of completion. The height and width of the output will be the same as - the input. The total number of padding will be calculated in horizontal and vertical - directions and evenly distributed to top, bottom, left and right if possible. - Otherwise, the last extra padding will be done from the bottom and the right side. - - - valid: Adopts the way of discarding. The possible largest height and width of output - will be returned without padding. Extra pixels will be discarded. - data_format (str) : The optional value for data format, is 'NHWC' or 'NCHW'. - Default: 'NCHW'. - - Inputs: - - **x** (Tensor) - Tensor of shape :math:`(N, C_{in}, H_{in}, W_{in})`. - - Outputs: - Tensor, with shape :math:`(N, C_{out}, H_{out}, W_{out})`. - - Raises: - TypeError: If `kernel_size` or `strides` is neither int nor tuple. - ValueError: If `pad_mode` is neither 'valid' nor 'same' with not case sensitive. - ValueError: If `data_format` is neither 'NCHW' nor 'NHWC'. - ValueError: If `kernel_size` or `strides` is less than 1. - ValueError: If length of shape of `input` is not equal to 4. - - Supported Platforms: - ``Ascend`` ``GPU`` ``CPU`` - - Examples: - >>> x = Tensor(np.arange(1 * 3 * 3 * 4).reshape((1, 3, 3, 4)), mindspore.float32) - >>> maxpool_op = ops.MaxPool(pad_mode="VALID", kernel_size=2, strides=1) - >>> output = maxpool_op(x) - >>> print(output) - [[[[ 5. 6. 7.] - [ 9. 10. 11.]] - [[17. 18. 19.] - [21. 22. 23.]] - [[29. 30. 31.] - [33. 34. 35.]]]] + ... + """ - + + # 初始化MaxPool类 @prim_attr_register def __init__(self, kernel_size=1, strides=1, pad_mode="valid", data_format="NCHW"): """Initialize MaxPool.""" + # 调用父类构造函数 super(MaxPool, self).__init__(kernel_size, strides, pad_mode, data_format) - - + + class MaxPoolWithArgmax(_Pool): r""" Performs max pooling on the input Tensor and returns both max values and indices. - - Typically the input is of shape :math:`(N_{in}, C_{in}, H_{in}, W_{in})`, MaxPool outputs - regional maximum in the :math:`(H_{in}, W_{in})`-dimension. Given kernel size - :math:`ks = (h_{ker}, w_{ker})` and stride :math:`s = (s_0, s_1)`, the operation is as follows. - - .. math:: - \text{output}(N_i, C_j, h, w) = \max_{m=0, \ldots, h_{ker}-1} \max_{n=0, \ldots, w_{ker}-1} - \text{input}(N_i, C_j, s_0 \times h + m, s_1 \times w + n) - - Args: - kernel_size (Union[int, tuple[int]]): The size of kernel used to take the maximum value and argmax - value, is an int number that represents height and width of the kernel, or a tuple of - two int numbers that represent height and width respectively. Default: 1. - strides (Union[int, tuple[int]]): The distance of kernel moving, an int number that represents - not only the height of movement but also the width of movement, or a tuple of two int numbers that - represent height and width of movement respectively. Default: 1. - pad_mode (str): The optional value for pad mode, is "same" or "valid". - Default: "valid". - - - same: Adopts the way of completion. The height and width of the output will be the same as - the input. The total number of padding will be calculated in horizontal and vertical - directions and evenly distributed to top, bottom, left and right if possible. - Otherwise, the last extra padding will be done from the bottom and the right side. - - - valid: Adopts the way of discarding. The possible largest height and width of output - will be returned without padding. Extra pixels will be discarded. - data_format (str) : The optional value for data format, is 'NHWC' or 'NCHW'. - Default: 'NCHW'. - - Inputs: - - **x** (Tensor) - Tensor of shape :math:`(N, C_{in}, H_{in}, W_{in})`. - Data type must be float16 or float32. - - Outputs: - Tuple of 2 Tensors, representing the maxpool result and where the max values are generated. - - - **output** (Tensor) - Maxpooling result, with shape :math:`(N, C_{out}, H_{out}, W_{out})`. - It has the same data type as `x`. - - **mask** (Tensor) - Max values' index represented by the mask. Data type is int32. - - Raises: - TypeError: If the data type of `x` is neither float16 nor float32. - TypeError: If `kernel_size` or `strides` is neither an int nor a tuple. - TypeError: If `x` is not a Tensor. - - Supported Platforms: - ``Ascend`` ``GPU`` - - Examples: - >>> x = Tensor(np.arange(1 * 3 * 3 * 4).reshape((1, 3, 3, 4)), mindspore.float32) - >>> maxpool_arg_op = ops.MaxPoolWithArgmax(pad_mode="VALID", kernel_size=2, strides=1) - >>> output_tensor, argmax = maxpool_arg_op(x) - >>> print(output_tensor) - [[[[ 5. 6. 7.] - [ 9. 10. 11.]] - [[17. 18. 19.] - [21. 22. 23.]] - [[29. 30. 31.] - [33. 34. 35.]]]] + ... + """ - + + # 初始化MaxPoolWithArgmax类 @prim_attr_register def __init__(self, kernel_size=1, strides=1, pad_mode="valid", data_format="NCHW"): """Initialize MaxPoolWithArgmax.""" + # 调用父类构造函数 super(MaxPoolWithArgmax, self).__init__(kernel_size, strides, pad_mode, data_format) - + + # 推断输入形状 def infer_shape(self, x_shape): out_shape = _Pool.infer_shape(self, x_shape) return out_shape, out_shape - + + # 推断输入数据类型 def infer_dtype(self, x_dtype): validator.check_tensor_dtype_valid("x", x_dtype, (mstype.float16, mstype.float32), self.name) argmax_dtype = mstype.int32 @@ -1693,18 +1177,18 @@ class MaxPoolWithArgmax(_Pool): class MaxPool3D(PrimitiveWithInfer): r""" 3D max pooling operation. - + Applies a 3D max pooling over an input Tensor which can be regarded as a composition of 3D planes. - + Typically the input is of shape :math:`(N_{in}, C_{in}, D_{in}, H_{in}, W_{in})`, MaxPool outputs regional maximum in the :math:`(D_{in}, H_{in}, W_{in})`-dimension. Given kernel size :math:`ks = (d_{ker}, h_{ker}, w_{ker})` and stride :math:`s = (s_0, s_1, s_2)`, the operation is as follows. - + .. math:: \text{output}(N_i, C_j, d, h, w) = \max_{l=0, \ldots, d_{ker}-1} \max_{m=0, \ldots, h_{ker}-1} \max_{n=0, \ldots, w_{ker}-1} \text{input}(N_i, C_j, s_0 \times d + l, s_1 \times h + m, s_2 \times w + n) - + Args: kernel_size (Union[int, tuple[int]]): The size of kernel used to take the maximum value, is an int number that represents depth, height and width of the kernel, or a tuple @@ -1714,18 +1198,18 @@ class MaxPool3D(PrimitiveWithInfer): represent depth, height and width of movement respectively. Default: 1. pad_mode (str): The optional value of pad mode is "same", "valid" or "pad". Default: "valid". - + - same: Adopts the way of completion. The height and width of the output will be the same as the input. The total number of padding will be calculated in horizontal and vertical directions and evenly distributed to top, bottom, left and right if possible. Otherwise, the last extra padding will be done from the bottom and the right side. - + - valid: Adopts the way of discarding. The possible largest height and width of output will be returned without padding. Extra pixels will be discarded. - + - pad: Implicit paddings on both sides of the input in depth, height and width. The number of "pad" will be padded to the input Tensor borders. "pad_list" must be greater than or equal to 0. - + pad_list (Union(int, tuple[int])): The pad value to be filled. Default: 0. If `pad` is an integer, the paddings of head, tail, top, bottom, left and right are the same, equal to pad. If `pad` is a tuple of six integers, the padding of head, tail, top, bottom, left and right equals to pad[0], pad[1], pad[2], @@ -1734,14 +1218,14 @@ class MaxPool3D(PrimitiveWithInfer): Only effective in "pad" mode. When "pad_mode" is "pad" and "ceil_mode" is "None", "ceil_mode" will be set as "False". Default: None. data_format (str) : The optional value for data format. Currently only support 'NCDHW'. Default: 'NCDHW'. - + Inputs: - **x** (Tensor) - Tensor of shape :math:`(N, C, D_{in}, H_{in}, W_{in})`. Data type must be float16 or float32. - + Outputs: Tensor, with shape :math:`(N, C, D_{out}, H_{out}, W_{out})`. Has the data type of `x`. - + Raises: TypeError: If `kernel_size` or `strides` is neither an int nor a tuple. TypeError: If `pad_mode` or `data_format` is not a string. @@ -1750,10 +1234,10 @@ class MaxPool3D(PrimitiveWithInfer): ValueError: If `pad_mode` is 'same' or 'valid', 'ceil_mode' is not None. ValueError: If `kernel_size` or `strides` is a tuple whose length is not equal to 3. ValueError: If `data_format` is not 'NCDHW'. - + Supported Platforms: ``Ascend`` ``GPU`` ``CPU`` - + Examples: >>> x = Tensor(np.arange(1 * 2 * 2 * 2 * 3).reshape((1, 2, 2, 2, 3)), mindspore.float32) >>> max_pool3d = ops.MaxPool3D(kernel_size=2, strides=1, pad_mode="valid") @@ -1762,63 +1246,93 @@ class MaxPool3D(PrimitiveWithInfer): [[[[[10. 11.]]] [[[22. 23.]]]]] """ - + @prim_attr_register def __init__(self, kernel_size=1, strides=1, pad_mode="VALID", pad_list=0, ceil_mode=None, data_format="NCDHW"): """Initialize MaxPool3D.""" + # 初始化MaxPool3D self.init_prim_io_names(inputs=['x'], outputs=['output']) + # 检查kernel_size的类型是否为int或tuple validator.check_value_type('kernel_size', kernel_size, [int, tuple], self.name) + # 检查strides的类型是否为int或tuple validator.check_value_type('strides', strides, [int, tuple], self.name) + # 检查pad_mode的类型是否为str validator.check_value_type('pad_mode', pad_mode, [str], self.name) + # 检查pad_mode的值是否为VALID、SAME或PAD self.pad_mode = validator.check_string(pad_mode.upper(), ['VALID', 'SAME', 'PAD'], 'pad_mode', self.name) + # 如果pad_mode为PAD,则将其设置为CALCULATED if pad_mode.upper() == "PAD": self.pad_mode = "CALCULATED" + # 将pad_mode添加到prim_attr中 self.add_prim_attr("pad_mode", self.pad_mode) + # 检查data_format的值是否为NCDHW self.data_format = validator.check_string(data_format, ['NCDHW'], 'data_format', self.name) + # 检查kernel_size的值是否为3维的int或tuple self.kernel_size = _check_3d_int_or_tuple("kernel_size", kernel_size, self.name, ret_five=True) + # 将kernel_size添加到prim_attr中 self.add_prim_attr("kernel_size", self.kernel_size) + # 检查strides的值是否为3维的int或tuple self.strides = _check_3d_int_or_tuple("strides", strides, self.name, ret_five=True) + # 将strides添加到prim_attr中 self.add_prim_attr("strides", self.strides) + # 如果ceil_mode为None,则将其设置为False if ceil_mode is None: self.ceil_mode = False else: + # 检查ceil_mode的类型是否为bool self.ceil_mode = validator.check_value_type('ceil_mode', ceil_mode, [bool], self.name) + # 如果pad_mode不是CALCULATED,则抛出异常 if self.pad_mode != "CALCULATED": raise ValueError("When the 'pad_mode' is 'same' or 'valid', the 'ceil_mode' only supports 'None'.") + # 将ceil_mode添加到prim_attr中 self.add_prim_attr("ceil_mode", int(self.ceil_mode)) - + + # 检查pad_list的类型是否为int或tuple validator.check_value_type('pad_list', pad_list, (int, tuple), self.name) self.pad_list = pad_list + # 如果pad_list为int,则将其转换为tuple if isinstance(self.pad_list, int): self.pad_list = (self.pad_list,) * 6 + # 如果pad_list为3维,则将其转换为6维 if len(self.pad_list) == 3: self.pad_list = (pad_list[0], pad_list[0], pad_list[1], pad_list[1], pad_list[2], pad_list[2]) + # 如果pad_list不为3维或6维,则抛出异常 if len(self.pad_list) != 3 and len(self.pad_list) != 6: raise ValueError(f"For '{self.name}', attr 'pad_list' should be an positive int number or a tuple of " f"three or six positive int numbers, but got {len(self.pad_list)} numbers.") + # 如果pad_mode不是CALCULATED,且pad_list不为(0, 0, 0, 0, 0, 0),则抛出异常 if self.pad_mode != 'CALCULATED' and self.pad_list != (0, 0, 0, 0, 0, 0): raise ValueError(f"For '{self.name}', the 'pad_list' must be zero or (0, 0, 0, 0, 0, 0) when 'pad_mode' " f"is not \"pad\", but got 'pad_list' is {pad_list} and 'pad_mode' is {pad_mode}.") + # 如果pad_mode为CALCULATED,则检查pad_list中的每个元素是否为非负整数 if self.pad_mode == 'CALCULATED': for item in self.pad_list: validator.check_non_negative_int(item, 'pad_list item', self.name) self.add_prim_attr("pad_list", self.pad_list) - + def infer_shape(self, x_shape): + # 检查输入张量的维度是否为5 validator.check_equal_int(len(x_shape), 5, "x rank", self.name) + # 将输入张量的维度赋值给变量 batch, channel, input_d, input_h, input_w = x_shape + # 将输入张量的维度添加到prim_attr中 self.add_prim_attr("x_shape", x_shape) + # 将卷积核的维度赋值给变量 _, _, kernel_d, kernel_h, kernel_w = self.kernel_size + # 将步长的维度赋值给变量 _, _, stride_d, stride_h, stride_w = self.strides - + + # 如果pad_mode为VALID,则计算输出张量的维度 if self.pad_mode == "VALID": out_d = math.ceil((input_d - (kernel_d - 1)) / stride_d) out_h = math.ceil((input_h - (kernel_h - 1)) / stride_h) out_w = math.ceil((input_w - (kernel_w - 1)) / stride_w) + # 如果pad_mode为SAME,则计算输出张量的维度 elif self.pad_mode == "SAME": out_d = math.ceil(input_d / stride_d) out_h = math.ceil(input_h / stride_h) out_w = math.ceil(input_w / stride_w) + # 如果pad_mode为其他,则计算输出张量的维度 else: out_d = ((input_d + self.pad_list[0] + self.pad_list[1] - (kernel_d - 1) - 1) / stride_d) + 1 @@ -1826,44 +1340,51 @@ class MaxPool3D(PrimitiveWithInfer): (kernel_h - 1) - 1) / stride_h) + 1 out_w = ((input_w + self.pad_list[4] + self.pad_list[5] - (kernel_w - 1) - 1) / stride_w) + 1 + # 如果ceil_mode为True,则向上取整 if self.ceil_mode: out_d = math.ceil(out_d) out_h = math.ceil(out_h) out_w = math.ceil(out_w) + # 否则向下取整 else: out_d = math.floor(out_d) out_h = math.floor(out_h) out_w = math.floor(out_w) + # 将输出张量的维度赋值给变量 out_shape = [batch, channel, out_d, out_h, out_w] - + + # 检查输出张量的维度是否合法 _check_shape('output', out_shape, self.name) + # 返回输出张量的维度 return out_shape - + def infer_dtype(self, x_dtype): + # 检查输入张量的数据类型是否合法 validator.check_tensor_dtype_valid("x", x_dtype, [mstype.float16, mstype.float32], self.name) + # 返回输入张量的数据类型 return x_dtype - - + + class AvgPool(_Pool): r""" Average pooling operation. - + Applies a 2D average pooling over an input Tensor which can be regarded as a composition of 2D input planes. Typically the input is of shape :math:`(N_{in}, C_{in}, H_{in}, W_{in})`, AvgPool outputs regional average in the :math:`(H_{in}, W_{in})`-dimension. Given kernel size :math:`ks = (h_{ker}, w_{ker})` and stride :math:`s = (s_0, s_1)`, the operation is as follows. - + .. math:: \text{output}(N_i, C_j, h, w) = \frac{1}{h_{ker} * w_{ker}} \sum_{m=0}^{h_{ker}-1} \sum_{n=0}^{w_{ker}-1} \text{input}(N_i, C_j, s_0 \times h + m, s_1 \times w + n) - + .. warning:: - Global pooling is supported. - For Ascend, the height of "kernel_size" and the weight of "kernel_size" are positive integers within the range [1, 255]. ksize_h * ksize_w < 256. - For Ascend, due to instruction restrictions, the values of "strides_h" and "strides_w" are positive integers within the range [1, 63]. - + Args: kernel_size (Union[int, tuple[int]]): The size of kernel used to take the average value, is an int number that represents height and width of the kernel, or a tuple @@ -1873,33 +1394,33 @@ class AvgPool(_Pool): represent height and width of movement respectively. Default: 1. pad_mode (str): The optional value for pad mode, is "same" or "valid". Default: "valid". - + - same: Adopts the way of completion. The height and width of the output will be the same as the input. The total number of padding will be calculated in horizontal and vertical directions and evenly distributed to top and bottom, left and right if possible. Otherwise, the last extra padding will be done from the bottom and the right side. - + - valid: Adopts the way of discarding. The possible largest height and width of output will be returned without padding. Extra pixels will be discarded. data_format (str): The format of input and output data. It should be 'NHWC' or 'NCHW'. Default: 'NCHW'. - + Inputs: - **x** (Tensor) - Tensor of shape :math:`(N, C_{in}, H_{in}, W_{in})`. - + Outputs: Tensor, with shape :math:`(N, C_{out}, H_{out}, W_{out})`. - + Raises: TypeError: If `kernel_size` or `strides` is neither int nor tuple. ValueError: If `pad_mode` is neither 'valid' nor 'same' with not case sensitive. ValueError: If `data_format` is neither 'NCHW' nor 'NHWC'. ValueError: If `kernel_size` or `strides` is less than 1. ValueError: If length of shape of `x` is not equal to 4. - + Supported Platforms: ``Ascend`` ``GPU`` ``CPU`` - + Examples: >>> class Net(nn.Cell): ... def __init__(self): @@ -1921,18 +1442,18 @@ class AvgPool(_Pool): [[26.5 27.5 28.5] [30.5 31.5 32.5]]]] """ - + @prim_attr_register def __init__(self, kernel_size=1, strides=1, pad_mode="valid", data_format="NCHW"): """Initialize AvgPool.""" super(AvgPool, self).__init__(kernel_size, strides, pad_mode, data_format) - - + + class Conv2DBackpropInput(Primitive): r""" The Conv2DBackpropInput interface is deprecated, please refer to :class:`mindspore.ops.Conv2DTranspose` if you want to do unsampling. - + Supported Platforms: Deprecated """ @@ -1941,7 +1462,7 @@ class Conv2DBackpropInput(Primitive): sig.make_sig('filter', dtype=sig.sig_dtype.T1), sig.make_sig('input_sizes', dtype=sig.sig_dtype.T2) ) - + @prim_attr_register def __init__(self, out_channel, @@ -1955,54 +1476,80 @@ class Conv2DBackpropInput(Primitive): group=1, data_format="NCHW"): """Initialize Conv2DBackpropInput""" + # 初始化Conv2DBackpropInput self.init_prim_io_names(inputs=['out_backprop', 'filter', 'input_sizes'], outputs=['output']) + # 初始化输入输出名称 self.out_channel = validator.check_positive_int(out_channel, 'out_channel', self.name) + # 检查out_channel是否为正整数 self.kernel_size = _check_positive_int_or_tuple('kernel_size', kernel_size, self.name) + # 检查kernel_size是否为正整数或元组 self.add_prim_attr('kernel_size', self.kernel_size) + # 添加kernel_size属性 self.format = validator.check_string(data_format, ['NCHW', 'NHWC'], 'format', self.name) + # 检查data_format是否为NCHW或NHWC if context.get_context("device_target") != "GPU" and self.format == "NHWC": raise ValueError(f"For '{self.name}', the 'NHWC' format is only supported in GPU target, " f"but got the 'data_format' is {self.format} and " f"the platform is {context.get_context('device_target')}.") + # 如果不是GPU平台,且data_format为NHWC,则抛出异常 self.add_prim_attr('data_format', self.format) + # 添加data_format属性 self.stride = _check_positive_int_or_tuple('stride', stride, self.name, allow_four=True, ret_four=True) + # 检查stride是否为正整数或元组 self.stride = _update_attr_by_format(self.stride, self.format) + # 根据data_format更新stride属性 self.add_prim_attr('stride', self.stride) + # 添加stride属性 self.dilation = _check_positive_int_or_tuple('dilation', dilation, self.name, allow_four=True, ret_four=True) + # 检查dilation是否为正整数或元组 self.dilation = _update_attr_by_format(self.dilation, self.format) + # 根据data_format更新dilation属性 self.add_prim_attr('dilation', self.dilation) + # 添加dilation属性 validator.check_value_type('pad', pad, (int, tuple), self.name) + # 检查pad是否为整数或元组 validator.check_value_type('pad_mode', pad_mode, [str], self.name) + # 检查pad_mode是否为字符串 if isinstance(pad, int): pad = (pad,) * 4 else: validator.check_equal_int(len(pad), 4, 'pad size', self.name) + # 如果pad为整数,则将其转换为元组 self.pad_mode = validator.check_string(pad_mode.lower(), ['valid', 'same', 'pad'], 'pad_mode', self.name) + # 检查pad_mode是否为valid、same或pad if pad_mode != 'pad' and pad != (0, 0, 0, 0): raise ValueError(f"For '{self.name}', the 'pad' must be zero or (0, 0, 0, 0) when 'pad_mode' " f"is not \"pad\", but got 'pad' is {self.pad} and 'pad_mode' is {pad_mode}.") + # 如果pad_mode不是pad,且pad不是(0, 0, 0, 0),则抛出异常 self.add_prim_attr("pad", pad) + # 添加pad属性 self.padding = pad + # 将pad赋值给padding if self.pad_mode == 'pad': for item in pad: validator.check_non_negative_int(item, 'pad item', self.name) - + + # 如果pad_mode为pad,则检查pad中的每个元素是否为非负整数 pad_mode = pad_mode.upper() self.add_prim_attr('pad_mode', pad_mode) + # 添加pad_mode属性 self.mode = validator.check_equal_int(mode, 1, 'mode', self.name) + # 检查mode是否为1 self.group = validator.check_positive_int(group, 'group', self.name) + # 检查group是否为正整数 self.add_prim_attr('groups', self.group) + # 添加group属性 if pad_list: for x in pad_list: validator.check_non_negative_int(x, 'element of pad_list', self.name) self.pad_list = pad_list - - + + class Conv2DTranspose(Conv2DBackpropInput): """ Compute a 2D transposed convolution, which is also known as a deconvolution (although it is not an actual deconvolution). - + Args: out_channel (int): The dimensionality of the output space. kernel_size (Union[int, tuple[int]]): The size of the convolution window. @@ -2017,9 +1564,9 @@ class Conv2DTranspose(Conv2DBackpropInput): dilation (Union[int. tuple[int]]): Specifies the dilation rate to be used for the dilated convolution. Default: 1. group (int): Splits input into groups. Default: 1. - data_format (str): The format of input and output data. It should be 'NHWC' or 'NCHW',\ + data_format (str): The format of input and output data. It should be 'NHWC' or 'NCHW', default is 'NCHW'. - + Inputs: - **dout** (Tensor) - the gradients with respect to the output of the convolution. The shape conforms to the default data_format :math:`(N, C_{out}, H_{out}, W_{out})`. @@ -2027,10 +1574,10 @@ class Conv2DTranspose(Conv2DBackpropInput): :math:`(C_{out}, C_{in}, K_1, K_2)`. - **input_size** (Tensor) - A tuple describes the shape of the input which conforms to the format :math:`(N, C_{in}, H_{in}, W_{in})`. - + Outputs: Tensor, the gradients with respect to the input of convolution. It has the same shape as the input. - + Raises: TypeError: If `kernel_size`, `stride`, `pad` or `dilation` is neither an int nor a tuple. TypeError: If `out_channel` or `group` is not an int. @@ -2039,10 +1586,10 @@ class Conv2DTranspose(Conv2DBackpropInput): ValueError: If `padding` is a tuple whose length is not equal to 4. ValueError: If `pad_mode` it not equal to 'pad' and `pad` is not equal to (0, 0, 0, 0). ValueError: If `data_format` is neither 'NCHW' nor 'NHWC'. - + Supported Platforms: ``Ascend`` ``GPU`` ``CPU`` - + Examples: >>> dout = Tensor(np.ones([10, 32, 30, 30]), mindspore.float32) >>> weight = Tensor(np.ones([32, 32, 3, 3]), mindspore.float32) @@ -2052,13 +1599,13 @@ class Conv2DTranspose(Conv2DBackpropInput): >>> print(output.shape) (10, 32, 32, 32) """ - + @prim_attr_register def __init__(self, out_channel, kernel_size, pad_mode="valid", pad=0, pad_list=None, mode=1, stride=1, dilation=1, group=1, data_format="NCHW"): """Initialize Conv2DTranspose.""" super(Conv2DTranspose, self).__init__(out_channel, kernel_size, pad_mode, pad, - pad_list, mode, stride, dilation, group, data_format) + pad_list, mode, stride, dilation, group, data_format)t) class BiasAdd(Primitive): diff --git a/src/mindspore2022/mindspore/python/mindspore/train/callback/_checkpoint.py b/src/mindspore2022/mindspore/python/mindspore/train/callback/_checkpoint.py index 87661110..1158c783 100644 --- a/src/mindspore2022/mindspore/python/mindspore/train/callback/_checkpoint.py +++ b/src/mindspore2022/mindspore/python/mindspore/train/callback/_checkpoint.py @@ -366,31 +366,46 @@ class ModelCheckpoint(Callback): """ def __init__(self, prefix='CKP', directory=None, config=None): + # 初始化函数,设置前缀、目录、配置等参数 super(ModelCheckpoint, self).__init__() + # 调用父类的初始化函数 self._latest_ckpt_file_name = "" + # 初始化最新检查点文件名为空字符串 self._init_time = time.time() + # 初始化初始化时间为当前时间 self._last_time = time.time() + # 初始化最后时间时间为当前时间 self._last_time_for_keep = time.time() + # 初始化最后保存时间为当前时间 self._last_triggered_step = 0 + # 初始化最后触发的步数为0 + # 检查前缀是否为字符串且不包含'/' if not isinstance(prefix, str) or prefix.find('/') >= 0: raise ValueError("For 'ModelCheckpoint', the argument 'prefix' " "for checkpoint file name is invalid, it must be " "string and does not contain '/', but got {}.".format(prefix)) self._prefix = prefix + # 设置前缀 self._exception_prefix = prefix + # 设置异常前缀 + # 如果目录不为空,则创建目录 if directory is not None: self._directory = _make_directory(directory) else: self._directory = _cur_dir + # 否则,使用当前目录 + # 如果启用了恢复上下文,则设置检查点路径 if _get_recovery_context("enable_recovery"): _set_recovery_context(ckpt_path=self._directory) + # 如果config为None,则使用默认的CheckpointConfig if config is None: self._config = CheckpointConfig() else: + # 如果config不是CheckpointConfig类型,则抛出TypeError异常 if not isinstance(config, CheckpointConfig): raise TypeError("For 'ModelCheckpoint', the type of argument 'config' should be " "'CheckpointConfig', " @@ -398,11 +413,17 @@ class ModelCheckpoint(Callback): self._config = config # get existing checkpoint files + # 创建CheckpointManager对象 self._manager = CheckpointManager() + # 如果存在相同名称的文件,则更改文件名 self._prefix = _chg_ckpt_file_name_if_same_exist(self._directory, self._prefix) + # 获取配置中的append_dict参数,如果没有则设置为空字典 self._append_dict = self._config.append_dict or {} + # 获取append_dict中的epoch_num参数,如果没有则设置为0 self._append_epoch_num = self._append_dict["epoch_num"] if "epoch_num" in self._append_dict else 0 + # 获取append_dict中的step_num参数,如果没有则设置为0 self._append_step_num = self._append_dict["step_num"] if "step_num" in self._append_dict else 0 + # 标记是否已经保存了图 self._graph_saved = False self._need_flush_from_cache = True @@ -413,6 +434,7 @@ class ModelCheckpoint(Callback): Args: run_context (RunContext): Context of the train running. """ + # If the role is PServer, add the role name and rank to the prefix if _is_role_pserver(): self._prefix = "PServer_" + str(_get_ps_mode_rank()) + "_" + self._prefix cb_params = run_context.original_args() @@ -423,18 +445,23 @@ class ModelCheckpoint(Callback): self._last_triggered_step = cb_params.last_save_ckpt_step cb_params.last_save_ckpt_step = None + # Create the directory if it doesn't exist _make_directory(self._directory) # save graph (only once) if not self._graph_saved: graph_file_name = os.path.join(self._directory, self._prefix + '-graph.meta') + # If the graph file already exists and the mode is GRAPH_MODE, remove it if os.path.isfile(graph_file_name) and context.get_context("mode") == context.GRAPH_MODE: os.remove(graph_file_name) + # Save the graph _save_graph(cb_params.train_network, graph_file_name) self._graph_saved = True + # Wait for any asynchronous checkpoint saving threads to finish thread_list = threading.enumerate() for thread in thread_list: if thread.getName() == "asyn_save_ckpt": thread.join() + # Save the checkpoint self._save_ckpt(cb_params) def end(self, run_context): @@ -444,44 +471,63 @@ class ModelCheckpoint(Callback): Args: run_context (RunContext): Context of the train running. """ + # 获取训练的参数 cb_params = run_context.original_args() + # 设置保存最后一个checkpoint的标志为True _to_save_last_ckpt = True + # 保存最后一个checkpoint self._save_ckpt(cb_params, _to_save_last_ckpt) + # 获取当前线程列表 thread_list = threading.enumerate() + # 遍历线程列表 for thread in thread_list: + # 如果线程名为"asyn_save_ckpt",则等待该线程结束 if thread.getName() == "asyn_save_ckpt": thread.join() + # 销毁所有gather cell destroy_allgather_cell() def _check_save_ckpt(self, cb_params, force_to_save): """Check whether save checkpoint files or not.""" + # 如果配置了保存检查点步数且步数大于0 if self._config.save_checkpoint_steps and self._config.save_checkpoint_steps > 0: + # 如果当前步数大于等于上次触发保存检查点步数加上保存检查点步数,或者强制保存检查点 if cb_params.cur_step_num >= self._last_triggered_step + self._config.save_checkpoint_steps \ or force_to_save is True: return True + # 如果配置了保存检查点秒数且秒数大于0 elif self._config.save_checkpoint_seconds and self._config.save_checkpoint_seconds > 0: + # 获取当前时间 self._cur_time = time.time() + # 如果当前时间减去上次时间大于保存检查点秒数,或者强制保存检查点 if (self._cur_time - self._last_time) > self._config.save_checkpoint_seconds or force_to_save: + # 更新上次时间 self._last_time = self._cur_time return True + # 返回False return False def _save_ckpt(self, cb_params, force_to_save=False): """Save checkpoint files.""" + # 如果当前步骤数等于最后触发的步骤数,则返回 if cb_params.cur_step_num == self._last_triggered_step: return # if param is cache enable, flush data from cache to host before save_ckpt + # 如果需要从缓存中刷新数据,则调用_flush_from_cache方法 if self._need_flush_from_cache: self._flush_from_cache(cb_params) + # 检查是否需要保存检查点,如果force_to_save为True,则强制保存 save_ckpt = self._check_save_ckpt(cb_params, force_to_save) + # 计算当前步数在epoch中的位置 step_num_in_epoch = int((cb_params.cur_step_num - 1) % cb_params.batch_num + 1) + # 如果需要保存检查点,则创建当前检查点的文件名 if save_ckpt: cur_ckpoint_file = self._prefix + "-" + str(cb_params.cur_epoch_num) + "_" \ + str(step_num_in_epoch) + ".ckpt" @@ -489,43 +535,68 @@ class ModelCheckpoint(Callback): self._manager.update_ckpoint_filelist(self._directory, self._prefix) # keep checkpoint files number equal max number. if self._config.keep_checkpoint_max and 0 < self._config.keep_checkpoint_max <= self._manager.ckpoint_num: + # 如果keep_checkpoint_max配置存在且大于0且小于等于当前checkpoint文件数量,则删除最旧的checkpoint文件 self._manager.remove_oldest_ckpoint_file() elif self._config.keep_checkpoint_per_n_minutes and self._config.keep_checkpoint_per_n_minutes > 0: + # 如果keep_checkpoint_per_n_minutes配置存在且大于0,则记录当前时间 self._cur_time_for_keep = time.time() + # 如果当前时间与上次记录的时间之差小于keep_checkpoint_per_n_minutes配置的分钟数乘以60,则保留每个分钟的一个checkpoint文件 if (self._cur_time_for_keep - self._last_time_for_keep) \ < self._config.keep_checkpoint_per_n_minutes * 60: self._manager.keep_one_ckpoint_per_minutes(self._config.keep_checkpoint_per_n_minutes, self._cur_time_for_keep) # generate the new checkpoint file and rename it. + # 定义全局变量_save_dir,并将其赋值为self._directory global _save_dir _save_dir = self._directory + # 获取当前checkpoint文件的路径 cur_file = os.path.join(self._directory, cur_ckpoint_file) + # 记录当前时间 self._last_time_for_keep = time.time() + # 记录当前触发步数 self._last_triggered_step = cb_params.cur_step_num + # 如果启用了GE(Graph Execution) if context.get_context("enable_ge"): + # 设置当前网络 set_cur_net(cb_params.train_network) + # 执行checkpoint图 cb_params.train_network.exec_checkpoint_graph() + # 如果_append_dict中包含"epoch_num" if "epoch_num" in self._append_dict: + # 将_append_epoch_num加上当前epoch数赋值给"epoch_num" self._append_dict["epoch_num"] = self._append_epoch_num + cb_params.cur_epoch_num + # 如果_append_dict中包含"step_num" if "step_num" in self._append_dict: + # 将_append_step_num加上当前step数赋值给"step_num" self._append_dict["step_num"] = self._append_step_num + cb_params.cur_step_num + # 获取保存的网络,如果self._config.saved_network不为None,则使用self._config.saved_network,否则使用cb_params.train_network network = self._config.saved_network if self._config.saved_network is not None else cb_params.train_network + # 保存checkpoint save_checkpoint(network, cur_file, self._config.integrated_save, self._config.async_save, self._append_dict, self._config.enc_key, self._config.enc_mode) + # 记录最新的checkpoint文件名 self._latest_ckpt_file_name = cur_file def _flush_from_cache(self, cb_params): """Flush cache data to host if tensor is cache enable.""" + # 初始化has_cache_params为False has_cache_params = False + # 获取训练网络中的参数 params = cb_params.train_network.get_parameters() + # 遍历参数 for param in params: + # 如果参数的cache_enable为True if param.cache_enable: + # 设置has_cache_params为True has_cache_params = True + # 将参数的Tensor数据从缓存中刷新到主机 Tensor(param).flush_from_cache() + # 如果没有参数的cache_enable为True if not has_cache_params: + # 设置_need_flush_from_cache为False self._need_flush_from_cache = False @property @@ -535,63 +606,88 @@ class ModelCheckpoint(Callback): class CheckpointManager: - """Manage checkpoint files according to train_config of checkpoint.""" + """管理检查点文件,根据训练配置进行管理。""" def __init__(self): + """初始化检查点管理器,创建空的检查点文件列表。""" self._ckpoint_filelist = [] @property def ckpoint_filelist(self): - """Get all the related checkpoint files managed here.""" + """获取当前管理的所有检查点文件列表。""" return self._ckpoint_filelist @property def ckpoint_num(self): - """Get the number of the related checkpoint files managed here.""" + """获取当前管理的检查点文件数量。""" return len(self._ckpoint_filelist) def update_ckpoint_filelist(self, directory, prefix): - """Update the checkpoint file list.""" + """更新检查点文件列表,根据目录和前缀筛选符合条件的检查点文件。""" + # 初始化一个空列表,用于存储ckpt文件 self._ckpoint_filelist = [] + # 获取指定目录下的所有文件 files = os.listdir(directory) + # 遍历所有文件 for filename in files: + # 判断文件是否以指定前缀开头,并且以.ckpt结尾 if os.path.splitext(filename)[-1] == ".ckpt" and filename.startswith(prefix + "-"): + # 获取文件名中间部分 mid_name = filename[len(prefix):-5] + # 判断中间部分是否包含字母 flag = not (True in [char.isalpha() for char in mid_name]) + # 如果不包含字母,则将文件路径添加到列表中 if flag: self._ckpoint_filelist.append(os.path.join(directory, filename)) def remove_ckpoint_file(self, file_name): - """Remove the specified checkpoint file from this checkpoint manager and also from the directory.""" + """从检查点管理器中移除指定的检查点文件,并从目录中删除该文件。""" try: + # 修改文件权限为可写 os.chmod(file_name, stat.S_IWRITE) + # 删除文件 os.remove(file_name) + # 从ckpoint文件列表中移除该文件 self._ckpoint_filelist.remove(file_name) except OSError: + # 捕获OSError异常,并记录警告日志 logger.warning("OSError, failed to remove the older ckpt file %s.", file_name) except ValueError: + # 捕获ValueError异常,并记录警告日志 logger.warning("ValueError, failed to remove the older ckpt file %s.", file_name) def remove_oldest_ckpoint_file(self): - """Remove the oldest checkpoint file from this checkpoint manager and also from the directory.""" + """移除检查点管理器中最早的检查点文件,并从目录中删除该文件。""" + # 获取所有checkpoint文件,并按修改时间排序 ckpoint_files = sorted(self._ckpoint_filelist, key=os.path.getmtime) + # 删除最早修改的checkpoint文件 self.remove_ckpoint_file(ckpoint_files[0]) def keep_one_ckpoint_per_minutes(self, minutes, cur_time): - """Only keep the latest one ckpt file per minutes, remove other files generated in [last_time, cur_time].""" + """保留每分钟生成的最新检查点文件,移除在指定时间范围内生成的其他文件。""" + # 定义一个空列表,用于存储需要删除的文件 del_list = [] + # 定义一个空字符串,用于存储最旧的文件名 oldest_file = '' + # 定义一个变量,用于存储当前时间 oldest_time = cur_time + # 遍历_ckpoint_filelist中的文件 for ck_file in self._ckpoint_filelist: + # 获取文件的修改时间 modify_time = os.path.getmtime(ck_file) + # 如果当前时间减去文件的修改时间小于60*minutes,则将文件添加到del_list中 if cur_time - modify_time < 60 * minutes: del_list.append(ck_file) + # 如果文件的修改时间小于oldest_time,则更新oldest_time和oldest_file if modify_time < oldest_time: oldest_time = modify_time oldest_file = ck_file + # 遍历del_list中的文件 for mv_file in del_list: + # 如果文件是最旧的文件,则跳过 if mv_file == oldest_file: continue - self.remove_ckpoint_file(mv_file) + # 调用remove_ckpoint_file方法删除文件 + self.remove_ckpoint_file(mv_file) \ No newline at end of file