Compare commits

..

No commits in common. "master" and "master" have entirely different histories.

12 changed files with 337 additions and 541 deletions

View File

@ -1,5 +1,5 @@
![MindSpore Logo](https://gitee.com/mindspore/mindspore/raw/master/docs/MindSpore-logo.png "MindSpore logo")
X
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/mindspore.svg)](https://pypi.org/project/mindspore)
[![PyPI](https://badge.fury.io/py/mindspore.svg)](https://badge.fury.io/py/mindspore)
[![Downloads](https://pepy.tech/badge/mindspore)](https://pepy.tech/project/mindspore)

View File

@ -29,7 +29,6 @@ class Base;
}
namespace mindspore::api {
/// \brief Base is the base class of many api classes, which provides basic interfaces.
class MIND_API Base {
public:
@ -46,9 +45,9 @@ class MIND_API Base {
/// \return The id of this class.
static uint32_t ClassId();
/// \brief Get the shared_ptr to the underlying implementation object.
/// \brief Get the shared_ptr to the underly implementation object.
///
/// \return The shared_ptr to the underlying implementation object.
/// \return The shared_ptr to the underly implementation object.
const std::shared_ptr<mindspore::Base> &impl() const { return impl_; }
/// \brief Get the string representation of this object.

View File

@ -632,111 +632,72 @@ class GeneratorDataset(MappableDataset, UnionBaseDataset):
def __init__(self, source, column_names=None, column_types=None, schema=None, num_samples=None,
num_parallel_workers=1, shuffle=None, sampler=None, num_shards=None, shard_id=None,
python_multiprocessing=True, max_rowsize=6):
#调用父类构造函数将num_parallel_workers sampler sampler shuffle num_shards shard_id传入
super().__init__(num_parallel_workers=num_parallel_workers, sampler=sampler, num_samples=num_samples,
shuffle=shuffle, num_shards=num_shards, shard_id=shard_id)
##如果source是一个zip对象转换为列表
if isinstance(source, builtins.zip):
# Although zip is iterable, it does not have the feature of repeated iteration, so pass it to the array.
#zip是迭代器 不能重复迭代这里把zip转换成列表再赋值给source
# Although zip is iteratable, it does not have the feature of repeated iteration, so pass it to the array.
self.source = [item for item in source]
#若source不是zip对象输入的直接赋值给self.source
else:
self.source = source
#self.prepared_source赋值为none
self.prepared_source = None # source to be sent to C++
##若对象有operator_mixed属性且该属性为true
if hasattr(self, 'operator_mixed') and getattr(self, 'operator_mixed') is True:
#对象的num_parallel_workers赋值为1
self.num_parallel_workers = 1
#输出警告信息:存在一些不支持多线程编译的运算符,建议将它们替换为 Python 实现的运算符
logger.warning(
"Input 'source' of 'GeneratorDataset' includes network computing operators like in mindspore.nn, "
"mindspore.ops, mindspore.numpy module and etc, which do not support multi-thread compiling, recommend"
" to replace it with python implemented operator like numpy etc. Here decrease 'num_parallel_workers' "
"into 1.")
#若当前平台为windows且num_parallel_workers > 1输出警告信息“Python 的多进程功能在 Windows 平台上不受支持”
if platform.system().lower() == 'windows' and num_parallel_workers > 1 and python_multiprocessing:
logger.warning("Python multiprocessing is not supported on Windows platform.")
#若当前操作系统是windows,把python_multiprocessing赋值给self.python_multiprocessing若不是后者赋值为false
self.python_multiprocessing = python_multiprocessing if platform.system().lower() != 'windows' else False
#若self.python_multiprocessing 属性的值为 True且当前处于调试模式警告多进程功能在调试模式下不受支持并把python_multiprocessing设置回false
if self.python_multiprocessing and get_debug_mode():
logger.warning("Python multiprocessing is not supported in debug mode."
" Ignoring Python multiprocessing for GeneratorDataset.")
self.python_multiprocessing = False
#把column_names转换成列表赋值给self.column_names
self.python_multiprocessing = python_multiprocessing
self.column_names = to_list(column_names)
#若column_types不为None调用mstypelist_to_detypelist函数把column_types赋值给self.column_types
#mstypelist_to_detypelist函数将 MindSpore 类型列表转换为 DE 类型列表。
if column_types is not None:
self.column_types = mstypelist_to_detypelist(column_types)
else:
self.column_types = []
#把self.schema赋值为schema值仅在None值时有用
self.schema = schema
##若schema不为None,即构造时传入了schema的值时将传入的 schema 参数赋值给 self.schema并保证schema是Schema 类的实例
if schema is not None:
self.schema = schema
#若schema 不为 Schema 类的实例,使用 Schema 类的构造函数创建一个新的 Schema 对象,并将其赋值给 self.schema
if not isinstance(schema, Schema):
self.schema = Schema(schema)
# Move get dataset_size by len from parse to here, because self.source will
# lose attribution of '__len__' after deepcopy.
#self.source 在进行deepcopy后会丢失 __len__ 属性
self.source_len = -1 # 表示未知
#若self.source 对象有 __len__ 属性获取self.source长度到self.source_len里
self.source_len = -1 # unknown
if hasattr(self.source, "__len__"):
self.source_len = len(self.source)
# if user defined sampler, update the self.source_len
#如果用户定义了采样器,要更新数据集的大小
#若self.sampler为samplers.Sampler类的实例或者self.sampler有__iter__属性
#然后将 sampler 转换为列表并获取其长度,然后将结果赋值给 self.source_len
if isinstance(self.sampler, samplers.Sampler) or hasattr(self.sampler, "__iter__"):
self.source_len = len(list(sampler))
self.max_rowsize = max_rowsize
self.sample_fn = None
#该函数进行深拷贝处理
def __deepcopy__(self, memodict):
#如果memodict 里已经存在当前对象的拷贝(已经拷贝过)(检查了 memodict 字典中是否存在键为 id(self) 的项),直接返回拷贝
if id(self) in memodict:
return memodict[id(self)]
#用 __safe_deepcopy__创建新对象排除了"source", "__transfer_dataset__"
new_op = self.__safe_deepcopy__(memodict, exclude=("source", "__transfer_dataset__"))
sample_fn = None
## 如果new_op中的 sampler 不是空的而且原对象的source可以操作索引`__getitem__` 方法存在)
if new_op.sampler is not None and hasattr(self.source, "__getitem__"):
# The reason why there is a try catch here is because when the new op is being constructed with shared
# memory enabled, there will be an exception thrown if there is not enough shared memory available
#内存不够可能会错误
if self.source_len == -1:#若长度还是未知,警告 需要“__len__”方法
if self.source_len == -1:
raise RuntimeError("Attempt to construct a random access dataset, '__len__' method is required!")
try:
#若num_parallel_workers 大于 1
if new_op.num_parallel_workers > 1:
#调用此方法 似乎是检查内存使用情况
self.__validate_memory_usage()
#创建SamplerFn对象
sample_fn = SamplerFn(self.source, new_op.num_parallel_workers, self.python_multiprocessing,
self.max_rowsize)
new_op.prepared_source = (lambda sample_ids: _cpp_sampler_fn_mp(sample_ids, sample_fn))
else:
new_op.prepared_source = (lambda sample_ids: _cpp_sampler_fn(sample_ids, self.source))
new_op.sample_fn = sample_fn
#遇到问题抛出异常
except RuntimeError as e:
raise Exception(str(e))
else:
try:
#如果新对象的sampler为空设置sample_fn为None
new_op.sampler = None
new_op.sample_fn = sample_fn
#设置source_len为num_samples和source_len中的较小值
new_op.source_len = min(new_op.source_len,
new_op.num_samples) if new_op.num_samples != 0 else new_op.source_len
iter(self.source)
@ -749,30 +710,18 @@ class GeneratorDataset(MappableDataset, UnionBaseDataset):
new_op.prepared_source = (lambda: _iter_fn(self.source, new_op.num_samples))
return new_op
#查询其是否已经打乱
def is_shuffled(self):
if self.sampler:
return self.sampler.is_shuffled()
return False
#查询是否sharded分片
return self.sampler.is_shuffled()
def is_sharded(self):
if self.sampler:
return self.sampler.is_sharded()
return False
#似乎用来分割元素
def split(self, sizes, randomize=True):
if hasattr(self.source, "__getitem__"):
# If the source has __getitem__ attribute, call the split method of MappableDataset.
# Otherwise, call the split method of Dataset.
return super().split(sizes, randomize)
return super(MappableDataset, self).split(sizes, randomize)
return self.sampler.is_sharded()
def parse(self, children=None):
if self.schema is None:
return cde.GeneratorNode(self.prepared_source, self.column_names, self.column_types, self.source_len,
self.sampler, self.num_parallel_workers)
schema = self.schema
#如果schema是Schema对象赋值为self.schema.cpp_schema
if isinstance(schema, Schema):
schema = self.schema.cpp_schema
return cde.GeneratorNode(self.prepared_source, schema, self.source_len, self.sampler,
@ -785,7 +734,6 @@ class GeneratorDataset(MappableDataset, UnionBaseDataset):
if self.python_multiprocessing:
# if use num_parallel_workers is to large when python_multiprocessing=True which would cause
# OOM error get the num_shards
#检查内存的使用情况,在多进程模式下,当内存使用量达到 85% 时丢出警告,达到 100% 时报错。
valid_num_shards = 1
if isinstance(self.sampler, samplers.DistributedSampler):
valid_num_shards = self.sampler.num_shards
@ -796,7 +744,7 @@ class GeneratorDataset(MappableDataset, UnionBaseDataset):
process = psutil.Process(os.getpid())
process_memory = process.memory_info().rss
sys_memory_free = psutil.virtual_memory().free
#内存使用量超过可用内存的85%,警告
total_memory_maybe_used = process_memory * self.num_parallel_workers * valid_num_shards
if total_memory_maybe_used / sys_memory_free > 0.85:
valid_num_worker = math.floor(sys_memory_free * 0.85 / valid_num_shards / process_memory)
@ -808,7 +756,6 @@ class GeneratorDataset(MappableDataset, UnionBaseDataset):
logger.warning(info)
class _NumpySlicesDataset:
"""
Mainly for dealing with several kinds of formats of Python data, and return one row each time.

View File

@ -28,12 +28,11 @@ from .c_transforms import TensorOperation
def not_random(function):
"""
将函数标记为非随机即它生成确定性结果
只有在将函数标记为非随机Python 函数才能被缓存
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".
"""
function.random = False #将函数的 random 属性设置为 False
return function #返回标记为“非随机”的函数
function.random = False
return function
class PyTensorOperation:
@ -41,108 +40,78 @@ class PyTensorOperation:
Base Python Tensor Operations class
"""
def to_json(self):
"""
Python 张量操作对象序列化为 JSON 格式的字符串表示形式
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)
返回:
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):
#从JSON字符串反序列化操作并构建新实例
#传入的JSON字符串解析为 Python 字典
"""
Base from_json for Python tensor operations class
"""
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): 数据集中的对象类别数量
应大于数据集中的最大标签数
smoothing_rate (float, 可选): 标签平滑级别的可调超参数
默认值=0.0 表示不应用平滑处理
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.)
Raises:
TypeError: `num_classes` 不是整数类型
TypeError: `smoothing_rate` 不是浮点数类型
ValueError: `smoothing_rate` 不在范围 [0.0, 1.0]
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].
Supported Platforms:
``CPU``
Examples:
>>> # 假设数据集有 10 个类别,因此标签范围从 0 到 9
>>> # Assume that dataset has 10 classes, thus the label ranges from 0 to 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
@ -150,19 +119,17 @@ class OneHotOp(PyTensorOperation):
def __call__(self, label):
"""
调用方法
Call method.
Args:
label (numpy.ndarray): 要应用标签平滑处理的标签
label (numpy.ndarray): label to be applied label smoothing.
Returns:
label (numpy.ndarray): 经过平滑处理后的标签
label (numpy.ndarray), label after being Smoothed.
"""
#将其转换为独热编码
return util.one_hot_encoding(label, self.num_classes, self.smoothing_rate)
class Compose(PyTensorOperation):
"""
Compose a list of transforms.
@ -243,8 +210,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:
@ -252,46 +219,32 @@ def reduce(operations):
Returns:
list, the reduced list of operations.
"""
#从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
"""
# 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])]
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):
@ -412,31 +365,19 @@ 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):
"""
初始化 Compose 类的实例
Args:
transforms (list): 一个包含要应用的转换操作的列表
Raises:
TypeError: 如果 `transforms` 不是列表类型
ValueError: 如果 `transforms` 列表为空
Returns:
None
"""
self.transforms = transforms # 将传入的转换操作列表存储在对象属性 transforms 中
self.transforms = transforms
def __call__(self, img):
"""
调用方法用于将一组转换操作应用到输入图像上
Call method.
Args:
img: 需要进行转换操作的图像
img (PIL image): Image to apply transformations in a random order.
Returns:
img: 转换后的图像
Raises:
TypeError: 如果输入图像或任何转换操作无效
img (PIL image), Transformed image.
"""
return util.random_order(img, self.transforms) # 调用 random_order 函数,以随机顺序应用转换操作并返回转换后的图像
return util.random_order(img, self.transforms)

View File

@ -24,29 +24,15 @@ from ..core.py_util_helpers import is_numpy, ExceptionHandler
def all_numpy(args):
"""
检查给定的参数是否全部为 NumPy 数组
Args:
args: 可以是单个值或一个包含多个值的元组
Returns:
bool: 如果全部都是 NumPy 数组则返回 True否则返回 False
"""
""" for multi-input lambdas"""
if isinstance(args, tuple):
#若参数是一个tuple则迭代遍历元组中的每个值
for value in args:
#使用 is_numpy 函数检查每个值是否为 NumPy 数组
if not is_numpy(value):
#如果发现任何一个值不是 NumPy 数组,则返回 False
return False
#如果所有的值都是 NumPy 数组,则返回 True
return True
#如果参数不是元组,而是单个值
return is_numpy(args)
def compose(transforms, *args):
"""
Compose a list of transforms and apply on the image.
@ -72,39 +58,35 @@ def compose(transforms, *args):
def one_hot_encoding(label, num_classes, epsilon):
#独热编码处理并进行平滑转换
"""
对输入的标签进行独热编码并应用标签平滑转换使标签更平滑和连续
Apply label smoothing transformation to the input label, and make label be more smoothing and continuous.
Args:
label (numpy.ndarray): 要应用标签平滑的标签
num_classes (int): 数据集中的对象类别数必须大于0
epsilon (float): 可调整的超参数默认值为0.0
label (numpy.ndarray): label to be applied label smoothing.
num_classes (int): Num class of object in dataset, value should over 0.
epsilon (float): The adjustable Hyper parameter. Default is 0.0.
Returns:
one_hot_label (numpy.ndarray): 经过独热编码和标签平滑后的标签
img (numpy.ndarray), label after being one hot encoded and done label smoothed.
Examples:
>>> # 假设 num_classes = 5
>>> # 1) 输入 np.array(3) 输出 [0, 0, 0, 1, 0]
>>> # 2) 输入 np.array([4, 2, 0]) 输出 [[0, 0, 0, 0, 1], [0, 0, 1, 0, 0], [1, 0, 0, 0, 0]]
>>> # 3) 输入 np.array([[4], [2], [0]]) 输出 [[[0, 0, 0, 0, 1]], [[0, 0, 1, 0, 0][, [[1, 0, 0, 0, 0]]]
>>> # assume num_classes = 5
>>> # 1) input np.array(3) output [0, 0, 0, 1, 0]
>>> # 2) input np.array([4, 2, 0]) output [[0, 0, 0, 0, 1], [0, 0, 1, 0, 0], [1, 0, 0, 0, 0]]
>>> # 3) input np.array([[4], [2], [0]]) output [[[0, 0, 0, 0, 1]], [[0, 0, 1, 0, 0][, [[1, 0, 0, 0, 0]]]
"""
if isinstance(label, np.ndarray): # 检查输入是否为 NumPy 数组
#判断label的数据类型是否为指定的整数类型np.int8, np.int16, np.int32, np.int64, np.uint8, np.uint16, np.uint32, np.uint64之一。
if isinstance(label, np.ndarray): # the numpy should be () or (1, ) or shape: (n, 1)
if label.dtype not in [np.int8, np.int16, np.int32, np.int64,
np.uint8, np.uint16, np.uint32, np.uint64]:
raise ValueError('the input numpy type should be int, but the input is: ' + str(label.dtype))
if label.ndim == 0: # 处理标量标签的情况
if label.ndim == 0:
if label >= num_classes:
raise ValueError('the num_classes is smaller than the category number.')
#创建一个全零的独热编码数组将标签对应的位置设为1
one_hot_label = np.zeros((num_classes), dtype=int)
one_hot_label[label] = 1
else: # 处理多维标签的情况
# 使用.flatten()将多维标签展平成一维数组,以便于处理
else:
label_flatten = label.flatten()
for item in label_flatten:
if item >= num_classes:
@ -112,46 +94,38 @@ def one_hot_encoding(label, num_classes, epsilon):
' is smaller than the category number:' + str(item))
num_elements = label_flatten.size
#创建一个形状为(num_elements, num_classes)的使用零填充的numpy数组
one_hot_label = np.zeros((num_elements, num_classes), dtype=int)
for index in range(num_elements):
one_hot_label[index][label_flatten[index]] = 1
#设置新的数组形状
new_shape = []new_shape
#将原label.shape移到里面
new_shape = []
for dim in label.shape:
new_shape.append(dim)
#对象类别扔到维度里面
new_shape.append(num_classes)
one_hot_label = one_hot_label.reshape(new_shape)
else:
#报错:数据格式无效,应该是一个 NumPy 数组
raise ValueError('the input is invalid, it should be numpy.ndarray.')
# 应用标签平滑,通过将原始独热编码乘以 (1 - epsilon) 并加上 epsilon / num_classes 来平滑标签epsilon默认为0
return (1 - epsilon) * one_hot_label + epsilon / num_classes
def random_order(img, transforms):
"""
将一系列变换以随机顺序应用到图像上
Applies a list of transforms in a random order.
Args:
img: 要以随机顺序应用变换的图像
transforms (list): 要应用的变换的列表
img: Image to be applied transformations in a random order.
transforms (list): List of the transformations to be applied.
Returns:
img: 经过变换的图像
img, Transformed image.
"""
# 随机打乱transforms元素顺序
random.shuffle(transforms)
for transform in transforms:
# 对图像应用每个变换
img = transform(img)
#返回img
return img
def random_apply(img, transforms, prob):
"""
Apply a list of transformation, randomly with a given probability.
@ -182,51 +156,42 @@ def random_choice(img, transforms):
Returns:
img, Transformed image.
"""
#用 Python 的 random.choice 函数从 transforms 列表中随机选择一个变换方法非常ez
return random.choice(transforms)(img)
class FuncWrapper:
"""
用于包装函数并添加 try except 逻辑主要用于包装 Python 函数
包装后的函数会捕获异常并重新引发以便处理 Python 函数的错误
Wrap function with try except logic, mainly for warping python function.
Args:
transform: 可调用的 Python 函数
transform: Callable python function.
Returns:
result, 应用变换后的数据
result, data after apply transformation.
"""
def __init__(self, transform):
#检查输入是否是可以调用的 Python 函数
if not callable(transform):
raise ValueError("Input operations should be callable python function, but got: " + str(transform))
self.transform = transform
try:
#如果函数有属性"random"并且其值为 False则将 self.random 设置为 False
if hasattr(self.transform, "random") and not self.transform.random:
self.random = False
except KeyError:
# 如果属性 "random" 不存在把self.random设置为 True
self.random = True
def __call__(self, *args):
result = None
try:
#调用包装的函数,并捕获可能的异常
result = self.transform(*args)
except Exception:
#发生异常后,创建一个异常处理器对象,并重新引发异常
result = ExceptionHandler(where="in map(or batch) worker and execute python function")
result.reraise()
return result
def to_json(self):
# 如果包装的函数是 FunctionType 类型,将其序列化为 JSON 对象
if isinstance(self.transform, FunctionType):
json_obj = {}
json_obj["tensor_op_name"] = self.transform.__name__
json_obj["python_module"] = self.__class__.__module__
return json.dumps(json_obj)
# 否则,调用包装的函数的 to_json 方法
return self.transform.to_json()

View File

@ -43,35 +43,39 @@ class FileWriter:
Args:
file_name (str): File name of MindRecord file.
shard_num (int, optional): The Number of MindRecord files.
It should be between [1, 1000]. Default: ``1`` .
overwrite (bool, optional): Whether to overwrite if the file already exists. Default: ``False`` .
It should be between [1, 1000]. Default: 1.
overwrite (bool, optional): Whether to overwrite if the file already exists. Default: False.
Raises:
ParamValueError: If `file_name` or `shard_num` or `overwrite` is invalid.
Examples:
from mindspore.mindrecord import FileWriter
writer = FileWriter(file_name="test.mindrecord", shard_num=1, overwrite=True)
schema_json = {"file_name": {"type": "string"}, "label": {"type": "int32"}, "data": {"type": "bytes"}}
schema_id = writer.add_schema(schema_json, "test_schema")
indexes = ["file_name", "label"]
status = writer.add_index(indexes)
for i in range(10):
... data = [{"file_name": str(i) + ".jpg", "label": i,
... "data": b"\x10c\xb3w\xa8\xee$o&<q\x8c\x8e(\xa2\x90\x90\x96\xbc\xb1\x1e\xd4QER\x13?\xff"}]
... status = writer.write_raw_data(data)
status = writer.commit()
>>> from mindspore.mindrecord import FileWriter
>>> schema_json = {"file_name": {"type": "string"}, "label": {"type": "int32"}, "data": {"type": "bytes"}}
>>> indexes = ["file_name", "label"]
>>> data = [{"file_name": "1.jpg", "label": 0,
... "data": b"\x10c\xb3w\xa8\xee$o&<q\x8c\x8e(\xa2\x90\x90\x96\xbc\xb1\x1e\xd4QER\x13?\xff"},
... {"file_name": "2.jpg", "label": 56,
... "data": b"\xe6\xda\xd1\xae\x07\xb8>\xd4\x00\xf8\x129\x15\xd9\xf2q\xc0\xa2\x91YFUO\x1dsE1"},
... {"file_name": "3.jpg", "label": 99,
... "data": b"\xaf\xafU<\xb8|6\xbd}\xc1\x99[\xeaj+\x8f\x84\xd3\xcc\xa0,i\xbb\xb9-\xcdz\xecp{T\xb1"}]
>>> writer = FileWriter(file_name="test.mindrecord", shard_num=1, overwrite=True)
>>> writer.add_schema(schema_json, "test_schema")
0
>>> writer.add_index(indexes)
MSRStatus.SUCCESS
>>> writer.write_raw_data(data)
MSRStatus.SUCCESS
>>> writer.commit()
MSRStatus.SUCCESS
"""
def __init__(self, file_name, shard_num=1, overwrite=False):
#若平台是windows 将文件名中\\替换成/
if platform.system().lower() == "windows":
file_name = file_name.replace("\\", "/")
#检查文件名,并使用
check_filename(file_name)
self._file_name = file_name
#若有shard_num检查其数值存在且数值为整数且在MIN_SHARD_COUNT和MAX_SHARD_COUNT之间否则抛出异常
if shard_num is not None:
if isinstance(shard_num, int):
if shard_num < MIN_SHARD_COUNT or shard_num > MAX_SHARD_COUNT:
@ -81,7 +85,7 @@ class FileWriter:
raise ParamValueError("Parameter shard_num's type is not int.")
else:
raise ParamValueError("Parameter shard_num is None.")
#若overwrite类型不是bool也抛出异常
if not isinstance(overwrite, bool):
raise ParamValueError("Parameter overwrite's type is not bool.")
@ -95,7 +99,7 @@ class FileWriter:
self._paths = ["{}{}".format(self._file_name,
str(x).rjust(suffix_shard_size, '0'))
for x in range(self._shard_num)]
self._overwrite = overwrite
self._append = False
self._flush = False
@ -103,13 +107,6 @@ class FileWriter:
self._writer = ShardWriter()
self._generator = None
# parallel write mode
self._parallel_writer = None
self._writers = None
self._queue = None
self._workers = None
self._index_workers = None
@classmethod
def open_for_append(cls, file_name):
r"""
@ -128,22 +125,22 @@ class FileWriter:
MRMOpenForAppendError: If failed to open file for appending data.
Examples:
from mindspore.mindrecord import FileWriter
data = [{"file_name": "0.jpg", "label": 0,
>>> from mindspore.mindrecord import FileWriter
>>> schema_json = {"file_name": {"type": "string"}, "label": {"type": "int32"}, "data": {"type": "bytes"}}
>>> data = [{"file_name": "1.jpg", "label": 0,
... "data": b"\x10c\xb3w\xa8\xee$o&<q\x8c\x8e(\xa2\x90\x90\x96\xbc\xb1\x1e\xd4QER\x13?\xff"}]
writer = FileWriter(file_name="test.mindrecord", shard_num=1, overwrite=True)
schema_json = {"file_name": {"type": "string"}, "label": {"type": "int32"}, "data": {"type": "bytes"}}
schema_id = writer.add_schema(schema_json, "test_schema")
status = writer.write_raw_data(data)
status = writer.commit()
write_append = FileWriter.open_for_append("test.mindrecord")
for i in range(9):
... data = [{"file_name": str(i+1) + ".jpg", "label": i,
... "data": b"\x10c\xb3w\xa8\xee$o&<q\x8c\x8e(\xa2\x90\x90\x96\xbc\xb1\x1e\xd4QER\x13?\xff"}]
... status = write_append.write_raw_data(data)
status = write_append.commit()
>>> writer = FileWriter(file_name="test.mindrecord", shard_num=1, overwrite=True)
>>> writer.add_schema(schema_json, "test_schema")
0
>>> writer.write_raw_data(data)
MSRStatus.SUCCESS
>>> writer.commit()
MSRStatus.SUCCESS
>>> write_append = FileWriter.open_for_append("test.mindrecord")
>>> write_append.write_raw_data(data)
MSRStatus.SUCCESS
>>> write_append.commit()
MSRStatus.SUCCESS
"""
if platform.system().lower() == "windows":
file_name = file_name.replace("\\", "/")
@ -175,49 +172,11 @@ class FileWriter:
The schema is added to describe the raw data to be written.
Note:
Please refer to the Examples of :class:`mindspore.mindrecord.FileWriter` .
.. list-table:: The data types supported by MindRecord.
:widths: 25 25 50
:header-rows: 1
* - Data Type
- Data Shape
- Details
* - int32
- /
- integer number
* - int64
- /
- integer number
* - float32
- /
- real number
* - float64
- /
- real number
* - string
- /
- string data
* - bytes
- /
- binary data
* - int32
- [-1] / [-1, 32, 32] / [3, 224, 224]
- numpy ndarray
* - int64
- [-1] / [-1, 32, 32] / [3, 224, 224]
- numpy ndarray
* - float32
- [-1] / [-1, 32, 32] / [3, 224, 224]
- numpy ndarray
* - float64
- [-1] / [-1, 32, 32] / [3, 224, 224]
- numpy ndarray
Please refer to the Examples of class: `mindspore.mindrecord.FileWriter`.
Args:
content (dict): Dictionary of schema content.
desc (str, optional): String of schema description, Default: ``None`` .
desc (str, optional): String of schema description, Default: None.
Returns:
int, schema id.
@ -226,14 +185,7 @@ class FileWriter:
MRMInvalidSchemaError: If schema is invalid.
MRMBuildSchemaError: If failed to build schema.
MRMAddSchemaError: If failed to add schema.
Examples:
# Examples of available schemas
schema1 = {"file_name": {"type": "string"}, "label": {"type": "int32"}, "data": {"type": "bytes"}}
schema2 = {"input_ids": {"type": "int32", "shape": [-1]},
... "input_masks": {"type": "int32", "shape": [-1]}}
"""
#加入schema若无效抛出MRMInvalidSchemaError
ret, error_msg = self._validate_schema(content)
if ret is False:
raise MRMInvalidSchemaError(error_msg)
@ -243,14 +195,13 @@ class FileWriter:
def add_index(self, index_fields):
"""
Select index fields from schema to accelerate reading.
schema is added through `add_schema` .
Note:
The index fields should be primitive type. e.g. int/float/str.
If the function is not called, the fields of the primitive type
in schema are set as indexes by default.
Please refer to the Examples of :class:`mindspore.mindrecord.FileWriter` .
Please refer to the Examples of class: `mindspore.mindrecord.FileWriter`.
Args:
index_fields (list[str]): fields from schema.
@ -266,7 +217,7 @@ class FileWriter:
"""
if not index_fields or not isinstance(index_fields, list):
raise ParamTypeError('index_fields', 'list')
#若index_fields其中元素在_header.blob_fields中是字符串类型才可通过。不是原始数据抛出MRMDefineIndexError
for field in index_fields:
if field in self._header.blob_fields:
raise MRMDefineIndexError("Failed to set field {} since it's not primitive type.".format(field))
@ -274,13 +225,66 @@ class FileWriter:
raise ParamTypeError('index field', 'str')
return self._header.add_index_fields(index_fields)
def _verify_based_on_schema(self, raw_data):
"""
Verify data according to schema and remove invalid data if validation failed.
1) allowed data type contains: "int32", "int64", "float32", "float64", "string", "bytes".
Args:
raw_data (list[dict]): List of raw data.
"""
error_data_dic = {}
schema_content = self._header.schema
for field in schema_content:
for i, v in enumerate(raw_data):
if i in error_data_dic:
continue
if field not in v:
error_data_dic[i] = "for schema, {} th data is wrong, " \
"there is not '{}' object in the raw data.".format(i, field)
continue
field_type = type(v[field]).__name__
if field_type not in VALUE_TYPE_MAP:
error_data_dic[i] = "for schema, {} th data is wrong, " \
"data type for '{}' is not matched.".format(i, field)
continue
if schema_content[field]["type"] not in VALUE_TYPE_MAP[field_type]:
error_data_dic[i] = "for schema, {} th data is wrong, " \
"data type for '{}' is not matched.".format(i, field)
continue
if field_type == 'ndarray':
if 'shape' not in schema_content[field]:
error_data_dic[i] = "for schema, {} th data is wrong, " \
"data type for '{}' is not matched.".format(i, field)
else:
try:
np.reshape(v[field], schema_content[field]['shape'])
except ValueError:
error_data_dic[i] = "for schema, {} th data is wrong, " \
"data type for '{}' is not matched.".format(i, field)
error_data_dic = sorted(error_data_dic.items(), reverse=True)
for i, v in error_data_dic:
raw_data.pop(i)
logger.warning(v)
def open_and_set_header(self):
#该接口将在未来被删除或隐藏
logger.warning("This interface will be deleted or invisible in the future.")
#若_writer没被打开打开文件
"""
Open writer and set header which stores meta information. The function is only used for parallel \
writing and is called before the `write_raw_data`.
Returns:
MSRStatus, SUCCESS or FAILED.
Raises:
MRMOpenError: If failed to open MindRecord file.
MRMSetHeaderError: If failed to set header.
"""
if not self._writer.is_open:
ret = self._writer.open(self._paths, self._overwrite)
#若无文件头则获取
if not self._writer.get_shard_header():
return self._writer.set_shard_header(self._header)
return ret

View File

@ -15,7 +15,7 @@
"""
Cifar10 convert tool for MindRecord.
"""
#用于把CIFAR-10数据转换为MindRecord
from importlib import import_module
import os
import numpy as np
@ -27,34 +27,30 @@ from ..filewriter import FileWriter
from ..shardutils import check_filename, ExceptionThread, SUCCESS, FAILED
try:
cv_import = import_module("cv2")
cv2 = import_module("cv2")
except ModuleNotFoundError:
cv_import = None
cv2 = None
__all__ = ['Cifar10ToMR']
# Cifar10ToMR 类 把CIFAR-10数据转换为MindRecord
#The CIFAR-10 dataset consists of 60000 32x32 colour images in 10 classes, with 6000 images per class. There are 50000 training images and 10000 test images.
class Cifar10ToMR:
"""
用于将 CIFAR-10 数据转换为 MindRecord 格式的一个类
参数:
source (str) - 待转换的CIFAR-10数据集文件所在目录的路径
destination (str) - 转换生成的MindRecord文件路径需提前创建目录并且目录下不能存在同名文件
报错:
ValueError: 如果 source destination 无效
Examples:
from mindspore.mindrecord import Cifar10ToMR
cifar10_dir = "/path/to/cifar10"
mindrecord_file = "/path/to/mindrecord/file"
cifar10_to_mr = Cifar10ToMR(cifar10_dir, mindrecord_file)
status = cifar10_to_mr.transform()
"""
A class to transform from cifar10 to MindRecord.
Note:
For details about Examples, please refer to `Converting the CIFAR-10 Dataset <https://
www.mindspore.cn/docs/programming_guide/en/master/dataset_conversion.html#converting-the-cifar-10-dataset>`_.
Args:
source (str): The cifar10 directory to be transformed.
destination (str): MindRecord file path to transform into, ensure that no file with the same name
exists in the directory.
Raises:
ValueError: If source or destination is invalid.
"""
def __init__(self, source, destination):
check_filename(source)
self.source = source
@ -63,12 +59,10 @@ class Cifar10ToMR:
train_data_flag = False
test_data_flag = False
for file in files:
#检查当前文件名是否以data_batch_或者test_batch开头
if file.startswith("data_batch_"):
train_data_flag = True
if file.startswith("test_batch"):
test_data_flag = True
#若没有train_data_flag或者test_data_flag为False报错
if not train_data_flag:
raise PathNotExistsError("data_batch_*")
@ -79,30 +73,36 @@ class Cifar10ToMR:
self.destination = destination
self.writer = None
# pylint: disable=missing-docstring
def run(self, fields=None):
#若fields不是列表报错The parameter fields should be None or list
"""
Execute transformation from cifar10 to MindRecord.
Args:
fields (list[str], optional): A list of index fields. Default: None.
Returns:
MSRStatus, SUCCESS or FAILED.
"""
if fields and not isinstance(fields, list):
raise ValueError("The parameter fields should be None or list")
# 创建一个Cifar10类的实例
cifar10_data = Cifar10(self.source, False)
cifar10_data.load_data()
images = cifar10_data.images
logger.info("train images: {}".format(images.shape))
#加载并记录数据集图像的形状
labels = cifar10_data.labels
logger.info("train images label: {}".format(labels.shape))
test_images = cifar10_data.Test.images
logger.info("test images: {}".format(test_images.shape))
#记录测试标签的形状
test_labels = cifar10_data.Test.labels
logger.info("test images label: {}".format(test_labels.shape))
data_list = _construct_raw_data(images, labels)
test_data_list = _construct_raw_data(test_images, test_labels)
# 若有转换MindRecord文件的失败则返回FAILED
if _generate_mindrecord(self.destination, data_list, fields, "img_train") != SUCCESS:
return FAILED
if _generate_mindrecord(self.destination + "_test", test_data_list, fields, "img_test") != SUCCESS:
@ -111,36 +111,15 @@ class Cifar10ToMR:
def transform(self, fields=None):
"""
Execute transformation from cifar10 to MindRecord.
Note:
Please refer to the Examples of :class:`mindspore.mindrecord.Cifar10ToMR` .
Encapsulate the run function to exit normally
Args:
fields (list[str], optional): A list of index fields. Default: ``None`` . For index field settings,
please refer to :func:`mindspore.mindrecord.FileWriter.add_index` .
fields (list[str], optional): A list of index fields. Default: None.
Returns:
MSRStatus, SUCCESS or FAILED.
Raises:
ParamTypeError: If index field is invalid.
MRMOpenError: If failed to open MindRecord file.
MRMValidateDataError: If data does not match blob fields.
MRMSetHeaderError: If failed to set header.
MRMWriteDatasetError: If failed to write dataset.
TypeError: If `parallel_writer` is not bool.
ValueError: If parameter `fields` is invalid.
异常 ParamTypeError: 如果索引字段无效
MRMOpenError: 如果无法打开 MindRecord 文件
MRMValidateDataError: 如果数据与 blob 字段不匹配
MRMSetHeaderError: 如果无法设置标题
MRMWriteDatasetError: 如果无法写入数据集
TypeError: 如果 parallel_writer 不是布尔值
ValueError: 如果参数 fields 无效
"""
#一个ExceptionThread线程类对象 目标为 self.run
t = ExceptionThread(target=self.run, kwargs={'fields': fields})
t.daemon = True
t.start()
@ -150,66 +129,55 @@ class Cifar10ToMR:
return t.res
def _construct_raw_data(images, labels):
#从cifar10中构建原始数据
"""
Construct raw data from cifar10 data.
def _construct_raw_data(images, labels):
"""
Construct raw data from cifar10 data.
Args:
images (list): image list from cifar10.
labels (list): label list from cifar10.
Args:
images (list): image list from cifar10.
labels (list): label list from cifar10.
Returns:
list[dict], data dictionary constructed from cifar10.
"""
#imageslabels表示来自cifar10的图像和标签
Returns:
list[dict], data dictionary constructed from cifar10.
"""
#若没有导入opencv-python模块报错
if not cv_import:
raise ModuleNotFoundError("opencv-python module not found, please use pip install it.")
if not cv2:
raise ModuleNotFoundError("opencv-python module not found, please use pip install it.")
raw_data = []
#遍历图像数据和标签数据
for i, img in enumerate(images):
label = np.int(labels[i][0])
_, img = cv_import.imencode(".jpeg", img[..., [2, 1, 0]])
#创建一个整合信息用的字典
row_data = {"id": int(i),
"data": img.tobytes(),#将数组的内容转换为一个字节字符串对象
"label": int(label)}#将标签转换为整数
raw_data.append(row_data)
return raw_data
raw_data = []
for i, img in enumerate(images):
label = np.int(labels[i][0])
_, img = cv2.imencode(".jpeg", img[..., [2, 1, 0]])
row_data = {"id": int(i),
"data": img.tobytes(),
"label": int(label)}
raw_data.append(row_data)
return raw_data
def _generate_mindrecord(file_name, raw_data, fields, schema_desc):
"""
Generate MindRecord file from raw data.
def _generate_mindrecord(file_name, raw_data, fields, schema_desc):
"""
Generate MindRecord file from raw data.
Args:
file_name (str): File name of MindRecord File.
fields (list[str]): Fields would be set as index which
could not belong to blob fields and type could not be 'array' or 'bytes'.
raw_data (dict): dict of raw data.
schema_desc (str): String of schema description.
# 参数:
# file_name (str): MindRecord文件的文件名。
# fields (list[str]): 将被设置为索引的字段不能属于blob字段且类型不能为 'array' 或 'bytes'。
# raw_data (dict): 原始数据的字典。
# schema_desc (str): schema 描述的字符串。
Returns:
MSRStatus, SUCCESS or FAILED.
"""
Args:
file_name (str): File name of MindRecord File.
fields (list[str]): Fields would be set as index which
could not belong to blob fields and type could not be 'array' or 'bytes'.
raw_data (dict): dict of raw data.
schema_desc (str): String of schema description.
schema = {"id": {"type": "int64"}, "label": {"type": "int64"},
"data": {"type": "bytes"}}
#记录MindRecord schema
logger.info("transformed MindRecord schema is: {}".format(schema))
Returns:
MSRStatus, SUCCESS or FAILED.
"""
writer = FileWriter(file_name, 1)
writer.add_schema(schema, schema_desc)
# 若有fields参数且它是一个列表为它添加索引字段
if fields and isinstance(fields, list):
writer.add_index(fields)
writer.write_raw_data(raw_data)
#返回结果
return writer.commit()
schema = {"id": {"type": "int64"}, "label": {"type": "int64"},
"data": {"type": "bytes"}}
logger.info("transformed MindRecord schema is: {}".format(schema))
writer = FileWriter(file_name, 1)
writer.add_schema(schema, schema_desc)
if fields and isinstance(fields, list):
writer.add_index(fields)
writer.write_raw_data(raw_data)
return writer.commit()

View File

@ -99,22 +99,20 @@ class ReduceLogSumExp(Cell):
def __init__(self, axis, keep_dims=False):
"""Initialize ReduceLogSumExp."""
super(ReduceLogSumExp, self).__init__()
# Checking and assigning the axis and keep_dims values
validator.check_value_type('axis', axis, [int, list, tuple], self.cls_name)
validator.check_value_type('keep_dims', keep_dims, [bool], self.cls_name)
self.axis = axis
# Creating necessary operators for calculation
self.exp = P.Exp()
self.sum = P.ReduceSum(keep_dims)
self.log = P.Log()
def construct(self, x):
# Performing the ReduceLogSumExp operation
exp = self.exp(x)
sumexp = self.sum(exp, self.axis)
logsumexp = self.log(sumexp)
return logsumexp
class Range(Cell):
r"""
Creates a sequence of numbers in range [start, limit) with step size delta.
@ -134,7 +132,7 @@ class Range(Cell):
delta (Union[int, float]): Increment of the range. It can not be equal to zero. Default: 1.
Outputs:
Tensor, the dtype is int if the dtype of `start`, `limit`, and `delta` all are int. Otherwise, dtype is float.
Tensor, the dtype is int if the dtype of `start`, `limit` and `delta` all are int. Otherwise, dtype is float.
Supported Platforms:
``Ascend`` ``GPU`` ``CPU``
@ -149,24 +147,16 @@ class Range(Cell):
def __init__(self, start, limit=None, delta=1):
"""Initialize Range."""
super(Range, self).__init__()
# Checking if delta is zero, which is not allowed
if delta == 0:
raise ValueError(f"For '{self.cls_name}', the 'delta' can not be zero.")
# Creating a numpy array with the specified range
data = np.arange(start, limit, delta)
# Determining the dtype of the tensor based on the data type of start, limit, and delta
if data.dtype == np.float:
self.ms_dtype = mstype.float32
else:
self.ms_dtype = mstype.int32
# Creating a MindSpore tensor with the specified data and dtype
self.result_tensor = Tensor(data, dtype=self.ms_dtype)
def construct(self):
# Returning the result tensor
return self.result_tensor
@ -256,13 +246,10 @@ class LGamma(Cell):
self.isfinite = P.IsFinite()
def construct(self, x):
# Checking the dtype of the input x
input_dtype = self.dtype(x)
_check_input_dtype("x", input_dtype, [mstype.float16, mstype.float32], self.cls_name)
# Defining some constant values
infinity = self.fill(input_dtype, self.shape(x), self.inf)
# Using Euler's reflection formula if x is less than 0.5
need_to_reflect = self.less(x, 0.5)
neg_input = -x
z = self.select(need_to_reflect, neg_input, x - 1)
@ -363,10 +350,8 @@ class DiGamma(Cell):
self.logicaland = P.LogicalAnd()
def construct(self, x):
# Checking the dtype of the input x
input_dtype = self.dtype(x)
_check_input_dtype("x", input_dtype, [mstype.float16, mstype.float32], self.cls_name)
# Applying Euler's reflection formula if x is less than 0.5
need_to_reflect = self.less(x, 0.5)
neg_input = -x
z = self.select(need_to_reflect, neg_input, x - 1)
@ -395,7 +380,6 @@ class DiGamma(Cell):
nan, real_result)
eps_fp32 = Tensor(np.finfo(np.float32).eps, mstype.float32)

View File

@ -318,7 +318,7 @@ class RMSELoss(LossBase):
r"""
RMSELoss creates a criterion to measure the root mean square error between :math:`x` and :math:`y`
element-wise, where :math:`x` is the input and :math:`y` is the labels.
For simplicity, let :math:`x` and :math:`y` be 1-dimensional Tensor with length :math:`N`,
the loss of :math:`x` and :math:`y` is given as:
@ -354,30 +354,29 @@ class RMSELoss(LossBase):
>>> print(output)
1.0
"""
def __init__(self):
"""Initialize RMSELoss."""
super(RMSELoss, self).__init__() # 调用父类的初始化方法
self.MSELoss = MSELoss() # 创建一个MSELoss的实例用于后续的计算
super(RMSELoss, self).__init__()
self.MSELoss = MSELoss()
def construct(self, logits, label):
# 计算均方误差并取平方根得到RMSE
rmse_loss = F.sqrt(self.MSELoss(logits, label))
return rmse_loss # 返回RMSE作为损失值
return rmse_loss
class MAELoss(LossBase):
r"""
MAELoss creates a criterion to measure the average absolute error between :math:`x` and :math:`y`
element-wise, where :math:`x` is the input and :math:`y` is the labels.
For simplicity, let :math:`x` and :math:`y` be 1-dimensional Tensor with length :math:`N`,
the unreduced loss (i.e. with argument reduction set to 'none') of :math:`x` and :math:`y` is given as:
.. math::
\ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad \text{with } l_n = \left| x_n - y_n \right|,
where :math:`N` is the batch size. If `reduction` is not 'none', then:
.. math::
@ -428,14 +427,14 @@ class MAELoss(LossBase):
def __init__(self, reduction='mean'):
"""Initialize MAELoss."""
super(MAELoss, self).__init__(reduction) # 调用父类的初始化方法,同时传入 reduction 参数
self.abs = P.Abs() # 创建一个 P.Abs() 的实例并存储在 self.abs 中
super(MAELoss, self).__init__(reduction)
self.abs = P.Abs()
def construct(self, logits, label):
_check_is_tensor('logits', logits, self.cls_name) # 检查 logits 是否是 Tensor 类型
_check_is_tensor('labels', label, self.cls_name) # 检查 labels 是否是 Tensor 类型
x = self.abs(logits - label) # 计算 |logits - label|
return self.get_loss(x) # 调用 get_loss 方法计算损失值,并返回
_check_is_tensor('logits', logits, self.cls_name)
_check_is_tensor('labels', label, self.cls_name)
x = self.abs(logits - label)
return self.get_loss(x)
class SmoothL1Loss(LossBase):

View File

@ -68,7 +68,6 @@ class CrossEntropyLoss(Cell):
if not isinstance(parallel_config, OpParallelConfig) and not isinstance(parallel_config):
raise TypeError("For 'CrossEntropyLoss', the class variable 'parallel_config' must be OpParallelConfig"
", but got the type: {}.".format(type(parallel_config)))
#确保 parallel_config 的类型是 OpParallelConfig 或者其子类,如果不是则提供一个错误信息
dp = parallel_config.data_parallel
mp = parallel_config.model_parallel
self.sum = P.ReduceSum().shard(((dp, mp),))
@ -94,38 +93,38 @@ class CrossEntropyLoss(Cell):
self.div2 = P.RealDiv()
def construct(self, logits, label, input_mask):
self._check_input(logits, label, input_mask)#检查数据是否符合要求
self._check_input(logits, label, input_mask)
# the shape is [bs*seq_length, vocab_size]
logits = F.cast(logits, mstype.float32)#将logits强制转换为32位float的形式
logits = F.cast(logits, mstype.float32)
# LogSoftmax for logits over last dimension
_, logit_max = self.max(logits)#计算logits样本中的最大值
logit_sub = self.sub(logits, logit_max)#令logits减去最大值
logit_exp = self.exp(logit_sub)#计算logit_sub的指数值
_, logit_max = self.max(logits)
logit_sub = self.sub(logits, logit_max)
logit_exp = self.exp(logit_sub)
exp_sum = self.sum(logit_exp, -1)
exp_sum = P.Reshape()(exp_sum, (F.shape(exp_sum)[0], 1))#对指数值进行求和
softmax_result = self.div(logit_exp, exp_sum)#计算softmax
log_softmax_result = self.log(self.add(softmax_result, self.eps_const))#计算对数softmax
exp_sum = P.Reshape()(exp_sum, (F.shape(exp_sum)[0], 1))
softmax_result = self.div(logit_exp, exp_sum)
log_softmax_result = self.log(self.add(softmax_result, self.eps_const))
# Flatten label to [bs*seq_length]
label = P.Reshape()(label, (-1,))#将label变为一维向量
label = P.Reshape()(label, (-1,))
# Get onehot label [bs*seq_length, vocab_size]
one_hot_label = self.onehot(label, F.shape(logits)[-1], self.on_value,
self.off_value)#将label转换为独热编码格式
self.off_value)
# Cross-Entropy loss
loss = self.mul(log_softmax_result, one_hot_label)#将softmax的对数值与标签的独热编码相乘
loss_unsum = self.neg(loss)#将计算的loss取负数
loss_reduce = self.sum(loss_unsum, -1)#对损失进行求和
loss = self.mul(log_softmax_result, one_hot_label)
loss_unsum = self.neg(loss)
loss_reduce = self.sum(loss_unsum, -1)
# input_mask indicates whether there is padded inputs and for padded inputs it will not be counted into loss
input_mask = P.Reshape()(input_mask, (-1,))#将input_mask变为一维向量
numerator = self.sum2(self.mul2(loss_reduce, input_mask))#计算分子将损失值与input_mask相乘并将结果相加
input_mask = P.Reshape()(input_mask, (-1,))
numerator = self.sum2(self.mul2(loss_reduce, input_mask))
denominator = self.add2(
self.sum2(input_mask),
P.Cast()(F.tuple_to_array((1e-5,)), mstype.float32))#计算分母部分将input_mask进行求和并且加上一个1e-5避免分母为0
loss = self.div2(numerator, denominator)#计算最终的损失值,将分子除以分母
return loss#返回损失值
P.Cast()(F.tuple_to_array((1e-5,)), mstype.float32))
loss = self.div2(numerator, denominator)
return loss
def _check_input(self, logits, label, input_mask):
r"""Check the input tensor shape and type"""
_check_is_tensor('logits', logits, self.cls_name)

View File

@ -26,7 +26,6 @@ Note:
- dtypes.py defines all the mindspore.numpy dtypes (mainly redirected from mindspore)
"""
# Importing necessary modules and functions from other files
from .array_ops import (transpose, expand_dims, squeeze, rollaxis, swapaxes, reshape,
ravel, concatenate, where, atleast_1d, atleast_2d, atleast_3d,
column_stack, hstack, dstack, vstack, stack, unique, moveaxis,
@ -34,7 +33,6 @@ from .array_ops import (transpose, expand_dims, squeeze, rollaxis, swapaxes, res
flip, flipud, fliplr, hsplit, dsplit, take_along_axis, take, repeat,
rot90, select, array_split, choose, size, array_str, apply_along_axis,
piecewise, unravel_index, apply_over_axes)
from .array_creations import copy_ as copy
from .array_creations import (array, asarray, asfarray, ones, zeros, full, randn, rand, randint, arange,
linspace, logspace, eye, identity, empty, empty_like,
@ -43,11 +41,9 @@ from .array_creations import (array, asarray, asfarray, ones, zeros, full, randn
diag, diag_indices, ix_, indices, geomspace, vander, hamming,
hanning, bartlett, blackman, triu_indices, tril_indices,
triu_indices_from, tril_indices_from, histogram_bin_edges, pad)
from .dtypes import (int_, int8, int16, int32, int64, uint, uint8, uint16,
uint32, uint64, float_, float16, float32, float64, bool_, inf, nan, pi,
numeric_types, PINF, NINF)
from .math_ops import (mean, inner, add, subtract, multiply, divide, true_divide, power,
dot, outer, tensordot, absolute, std, var, average, minimum,
matmul, square, sqrt, reciprocal, log, maximum, heaviside, amax, amin,
@ -62,13 +58,11 @@ from .math_ops import (mean, inner, add, subtract, multiply, divide, true_divide
histogramdd, histogram2d, matrix_power, around, polyadd, polysub, polyval,
polyder, polymul, polyint, result_type, unwrap, cumprod, ravel_multi_index,
norm, bitwise_and, bitwise_or, bitwise_xor, invert, rint, correlate, radians)
from .logic_ops import (not_equal, less_equal, less, greater_equal, greater, equal, isfinite,
isnan, isinf, isposinf, isneginf, isscalar, logical_and, logical_not,
logical_or, logical_xor, in1d, isin, isclose, signbit, sometrue,
array_equal, array_equiv)
# Aliasing some functions for convenience
mod = remainder
fabs = absolute
round = around # pylint: disable=redefined-builtin
@ -81,7 +75,6 @@ sum = sum_ # pylint: disable=redefined-builtin
del sum_
bitwise_not = invert
# Creating module-specific lists for easy management
array_ops_module = ['transpose', 'expand_dims', 'squeeze', 'rollaxis', 'swapaxes', 'reshape',
'ravel', 'concatenate', 'where', 'atleast_1d', 'atleast_2d', 'atleast_3d',
'column_stack', 'hstack', 'dstack', 'vstack', 'stack', 'unique', 'moveaxis',
@ -120,8 +113,6 @@ logic_module = ['not_equal', 'less_equal', 'less', 'greater_equal', 'greater', '
'logical_or', 'logical_xor', 'in1d', 'isin', 'isclose', 'signbit', 'sometrue',
'array_equal', 'array_equiv']
# Combining all the modules and functions into a single list
__all__ = array_ops_module + array_creations_module + math_module + logic_module + numeric_types
# Sorting the list alphabetically
__all__.sort()

View File

@ -34,9 +34,8 @@ def _check_mul():
finally:
pass
print(f"MindSpore version: ", ms.__version__) # Print MindSpore version
print(f"MindSpore version: ", ms.__version__)
# Create tensors and perform multiplication
input_x = ms.Tensor(np.array([1.0, 2.0, 3.0]), ms.float32)
input_y = ms.Tensor(np.array([4.0, 5.0, 6.0]), ms.float32)
mul = ms.ops.Mul()
@ -56,10 +55,10 @@ def run_check():
The result of multiplication calculation is correct, MindSpore has been installed successfully!
"""
try:
_check_mul() # Call _check_mul function to perform the check
_check_mul()
# pylint: disable=broad-except
except Exception as e:
print("MindSpore running check failed.") # Print error message if check fails
print(str(e)) # Print specific error message
print("MindSpore running check failed.")
print(str(e))
finally:
pass # Cleanup code if needed
pass