Update py_transforms.py
This commit is contained in:
parent
6b5026a806
commit
900bb5d1b0
|
|
@ -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 函数,以随机顺序应用转换操作并返回转换后的图像
|
||||
Loading…
Reference in New Issue