diff --git a/mindspore/python/mindspore/dataset/transforms/py_transforms.py b/mindspore/python/mindspore/dataset/transforms/py_transforms.py index 85f42e6e8b7..8e4ba9e8ff6 100644 --- a/mindspore/python/mindspore/dataset/transforms/py_transforms.py +++ b/mindspore/python/mindspore/dataset/transforms/py_transforms.py @@ -28,11 +28,12 @@ from .c_transforms import TensorOperation def not_random(function): """ - Specify the function as "not random", i.e., it produces deterministic result. - A Python function can only be cached after it is specified as "not random". + 将函数标记为“非随机”,即它生成确定性结果。 + 只有在将函数标记为“非随机”后,Python 函数才能被缓存。 """ - function.random = False - return function + function.random = False #将函数的 random 属性设置为 False + return function #返回标记为“非随机”的函数 + class PyTensorOperation: @@ -40,78 +41,108 @@ class PyTensorOperation: Base Python Tensor Operations class """ - def to_json(self): - """ - Base to_json for Python tensor operations class - """ - json_obj = {} - json_trans = {} - if "transforms" in self.__dict__.keys(): - # operations which have transforms as input, need to call _to_json() for each transform to serialize - json_list = [] - for transform in self.transforms: - json_list.append(json.loads(transform.to_json())) - json_trans["transforms"] = json_list - self.__dict__.pop("transforms") - if "output_type" in self.__dict__.keys(): - json_trans["output_type"] = np.dtype( - self.__dict__["output_type"]).name - self.__dict__.pop("output_type") - json_obj["tensor_op_params"] = self.__dict__ - # append transforms to the tensor_op_params of the operation - json_obj["tensor_op_params"].update(json_trans) - json_obj["tensor_op_name"] = self.__class__.__name__ - json_obj["python_module"] = self.__class__.__module__ - return json.dumps(json_obj) +def to_json(self): + """ + 将 Python 张量操作对象序列化为 JSON 格式的字符串表示形式。 + + 返回: + str: 表示序列化对象的 JSON 格式字符串。 + + """ + json_obj = {} #创建一个空字典来存储 JSON 数据 + json_trans = {} #创建一个空字典来存储与数据 + + if "transforms" in self.__dict__.keys(): + #检查对象是否具有“transforms”属性(转换列表) + json_list = [] + + #遍历每个转换并将其序列化为 JSON + for transform in self.transforms: + json_list.append(json.loads(transform.to_json())) + + json_trans["transforms"] = json_list#将序列化的转换添加到 JSON 数据中 + self.__dict__.pop("transforms") #从对象中移除“transforms”属性 + + if "output_type" in self.__dict__.keys(): + #检查对象是否有“output_type”属性 + json_trans["output_type"] = np.dtype( + self.__dict__["output_type"]).name # 将数据类型序列化为名称形式 + self.__dict__.pop("output_type") # 从对象中移除“output_type”属性 + + json_obj["tensor_op_params"] = self.__dict__ #将对象的属性添加到 JSON 数据中 + json_obj["tensor_op_params"].update(json_trans) #合并与转换相关的数据 + json_obj["tensor_op_name"] = self.__class__.__name__ #添加类名 + json_obj["python_module"] = self.__class__.__module__ #添加模块名(?) + + return json.dumps(json_obj) #序列化整个 JSON 数据并以字符串形式返回 + + @classmethod @classmethod def from_json(cls, json_string): - """ - Base from_json for Python tensor operations class - """ + #从JSON字符串反序列化操作并构建新实例 + #传入的JSON字符串解析为 Python 字典 json_obj = json.loads(json_string) + + #创建一个新的操作实例 new_op = cls.__new__(cls) + + #将该实例的内部字典(__dict__)替换为从 JSON 中解析的字典 new_op.__dict__ = json_obj + + #检查是否存在"transforms" 键,如果存在,则需要对其中的 transforms 进行反序列化 if "transforms" in json_obj.keys(): - # operations which have transforms as input, need to call _from_json() for each transform to deseriallize transforms = [] + + #遍历transforms列表中的每个 JSON 表示的操作,并将其解析 for json_op in json_obj["transforms"]: + #获取操作所在的 Python 模块并根据模块和操作名称创建相应的操作实例 transforms.append(getattr( sys.modules[json_op["python_module"]], json_op["tensor_op_name"]).from_json( json.dumps(json_op["tensor_op_params"]))) + #将反序列化后的操作列表赋值给新操作实例的 transforms 属性 new_op.transforms = transforms + #检查是否存在"output_type"的键,如存在,转换为numpy.dtype数据类型,并赋值给新实例的output_type if "output_type" in json_obj.keys(): output_type = np.dtype(json_obj["output_type"]) new_op.output_type = output_type + #返回一个新操作实例 return new_op + class OneHotOp(PyTensorOperation): """ - Apply one hot encoding transformation to the input label, make label be more smoothing and continuous. + 对输入标签应用独热编码变换,使标签更平滑和连续化。 Args: - num_classes (int): Number of classes of objects in dataset. - It should be larger than the largest label number in the dataset. - smoothing_rate (float, optional): Adjustable hyperparameter for label smoothing level. - (Default=0.0 means no smoothing is applied.) + num_classes (int): 数据集中的对象类别数量。 + 应大于数据集中的最大标签数。 + smoothing_rate (float, 可选): 标签平滑级别的可调超参数。 + (默认值=0.0 表示不应用平滑处理。) Raises: - TypeError: `num_classes` is not of type int. - TypeError: `smoothing_rate` is not of type float. - ValueError: `smoothing_rate` is not in range [0.0, 1.0]. + TypeError: `num_classes` 不是整数类型。 + TypeError: `smoothing_rate` 不是浮点数类型。 + ValueError: `smoothing_rate` 不在范围 [0.0, 1.0] 内。 Supported Platforms: ``CPU`` Examples: - >>> # Assume that dataset has 10 classes, thus the label ranges from 0 to 9 + >>> # 假设数据集有 10 个类别,因此标签范围从 0 到 9 >>> transforms_list = [py_transforms.OneHotOp(num_classes=10, smoothing_rate=0.1)] >>> transform = py_transforms.Compose(transforms_list) >>> mnist_dataset = mnist_dataset.map(input_columns=["label"], operations=transform) """ @check_one_hot_op + #数据迁移处理 + """ + self.num_classes = num_classes + self.smoothing_rate = smoothing_rate + self.random = False + """ def __init__(self, num_classes, smoothing_rate=0.0): self.num_classes = num_classes self.smoothing_rate = smoothing_rate @@ -119,17 +150,19 @@ class OneHotOp(PyTensorOperation): def __call__(self, label): """ - Call method. + 调用方法。 Args: - label (numpy.ndarray): label to be applied label smoothing. + label (numpy.ndarray): 要应用标签平滑处理的标签。 Returns: - label (numpy.ndarray), label after being Smoothed. + label (numpy.ndarray): 经过平滑处理后的标签。 """ + #将其转换为独热编码 return util.one_hot_encoding(label, self.num_classes, self.smoothing_rate) + class Compose(PyTensorOperation): """ Compose a list of transforms. @@ -210,8 +243,8 @@ class Compose(PyTensorOperation): return util.compose(self.transforms, *args) @staticmethod - def reduce(operations): - """ +def reduce(operations): + """ Wraps adjacent Python operations in a Compose to allow mixing of Python and C++ operations. Args: @@ -219,32 +252,46 @@ class Compose(PyTensorOperation): Returns: list, the reduced list of operations. - """ - # import nn and ops locally for type check - from mindspore import nn, ops - for item in operations: - if isinstance(item, (nn.Cell, ops.Primitive)): - raise ValueError("Input operations should not contain network computing operator like in " - "mindspore.nn or mindspore.ops, got operation:", str(item)) - if len(operations) == 1: - if str(operations).find("c_transform") >= 0 or isinstance(operations[0], TensorOperation): - return operations - return [util.FuncWrapper(operations[0])] + """ + #从mindspore 模块中局部导入nn和ops + from mindspore import nn, ops + + #寻找列表中是否包含网络计算操作符 + for item in operations: + if isinstance(item, (nn.Cell, ops.Primitive)): + raise ValueError("Input operations should not contain network computing operator like in " + "mindspore.nn or mindspore.ops, got operation:", str(item)) + + # 如果操作列表中只有一个操作 + if len(operations) == 1: + # 如果该操作是 C++ 操作或 TensorOperation 的实例,返回该操作 + if str(operations).find("c_transform") >= 0 or isinstance(operations[0], TensorOperation): + return operations + # 将该操作包装在 util.FuncWrapper 中,并返回包装后的列表 + return [util.FuncWrapper(operations[0])] + + # 如果操作列表包含多个 + new_ops, start_ind, end_ind = [], 0, 0 + + # 遍历 + for i, op in enumerate(operations): + if str(op).find("c_transform") >= 0: + # 如果有 C++ 操作,将之前的所有操作打包成一个Compose操作 + if start_ind != end_ind: + new_ops.append(Compose(operations[start_ind:end_ind])) + new_ops.append(op) + start_ind, end_ind = i + 1, i + 1 + else: + end_ind += 1 + + #在循环结束后,检查并确保最后一组操作也被打包成 Compose 操作,并添加到新的操作列表中( + #(? + if start_ind != end_ind: + new_ops.append(Compose(operations[start_ind:end_ind])) + + # 返回经过优化的操作列表 + return new_ops - new_ops, start_ind, end_ind = [], 0, 0 - for i, op in enumerate(operations): - if str(op).find("c_transform") >= 0: - # reset counts - if start_ind != end_ind: - new_ops.append(Compose(operations[start_ind:end_ind])) - new_ops.append(op) - start_ind, end_ind = i + 1, i + 1 - else: - end_ind += 1 - # do additional check in case the last operation is a Python operation - if start_ind != end_ind: - new_ops.append(Compose(operations[start_ind:end_ind])) - return new_ops class RandomApply(PyTensorOperation): @@ -365,19 +412,31 @@ class RandomOrder(PyTensorOperation): ... py_vision.ToTensor()]) >>> image_folder_dataset = image_folder_dataset.map(operations=transforms, input_columns=["image"]) """ - @check_transforms_list def __init__(self, transforms): - self.transforms = transforms + """ + 初始化 Compose 类的实例。 + + Args: + transforms (list): 一个包含要应用的转换操作的列表。 + + Raises: + TypeError: 如果 `transforms` 不是列表类型。 + ValueError: 如果 `transforms` 列表为空。 + + Returns: + None + """ + self.transforms = transforms # 将传入的转换操作列表存储在对象属性 transforms 中 def __call__(self, img): """ - Call method. - + 调用方法,用于将一组转换操作应用到输入图像上。 Args: - img (PIL image): Image to apply transformations in a random order. - + img: 需要进行转换操作的图像。 Returns: - img (PIL image), Transformed image. + img: 转换后的图像。 + Raises: + TypeError: 如果输入图像或任何转换操作无效。 """ - return util.random_order(img, self.transforms) + return util.random_order(img, self.transforms) # 调用 random_order 函数,以随机顺序应用转换操作并返回转换后的图像 \ No newline at end of file