From dab0e8e7ff1a693b915b211f9ef32ff94446b8bc Mon Sep 17 00:00:00 2001 From: zyf1234 Date: Sun, 27 Aug 2023 15:04:13 +0800 Subject: [PATCH] ADD file via upload --- op_adapter_util.cc | 392 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 392 insertions(+) create mode 100644 op_adapter_util.cc diff --git a/op_adapter_util.cc b/op_adapter_util.cc new file mode 100644 index 0000000..a98852c --- /dev/null +++ b/op_adapter_util.cc @@ -0,0 +1,392 @@ +/** + * Copyright 2019 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "transform/graph_ir/op_adapter_util.h" + +#include +#include +#include + +#include "include/common/utils/utils.h" +#include "utils/check_convert_utils.h" +#include "transform/graph_ir/op_adapter_base.h" +#include "transform/graph_ir/io_format_map.h" + +namespace mindspore { +namespace transform { +// ConvertAnyUtil 函数用于将 MindSpore 中的 Tensor(mindspore::tensor::Tensor)转换为 GE(GraphEngine)中的Tensor(GeTensor)。 +GeTensor ConvertAnyUtil(const ValuePtr &value, const AnyTraits &) { + // To-DO the format may read from ME tensor + // TODO:可能需要从 ME(MindSpore Execution) Tensor 读取格式信息(format) + MS_EXCEPTION_IF_NULL(value); + //// 将 value 强制转换为 MeTensorPtr 类型,MeTensorPtr 是一个智能指针,表示 ME Tensor(MindSpore Execution Tensor)。 + auto me_tensor = value->cast(); + // 调用 TransformUtil::ConvertTensor 函数将 ME Tensor 转换为 GE Tensor。 + // 这里的 kOpFormat_ND 是指定转换后的 GE Tensor 使用的格式,可能是 ND 格式(N-Dimensional)。 + auto ge_tensor = TransformUtil::ConvertTensor(me_tensor, kOpFormat_ND); + // 如果转换后的 GE Tensor 为空,则返回一个空的 GeTensor 对象,否则返回转换后的 GE Tensor。 + return ge_tensor == nullptr ? GeTensor() : *ge_tensor; +} + +// ConvertAnyUtil 函数用于将一个 ValuePtr 类型的值转换为 std::vector 类型。 +// 转换的方式取决于传入的 name 参数和数据类型 AnyTraits>。 +std::vector ConvertAnyUtil(const ValuePtr &value, const std::string &name, + const AnyTraits>) { + MS_EXCEPTION_IF_NULL(value); + std::vector list; // 创建一个 int64_t 类型的 vector,用于存储转换后的结果。 + if (name == "pad") { // 如果传入的 name 是 "pad",则执行特定的转换逻辑。 + if (!value->isa()) { // 确保 value 是 ValueSequence 类型。 + MS_LOG(EXCEPTION) << "Value should be ValueTuple, but got" << value->type_name(); + } + auto vec = value->cast(); // 将 value 转换为 ValueSequencePtr 类型。 + // 调整 vector 的大小以容纳转换后的结果。 + // 由于结果包含两个额外的元素(1和1),因此比 ValueSequence 的大小大2。 + list.resize(vec->value().size() + 2); + // 将额外的两个元素设置为 1。 + list[0] = 1; + list[1] = 1; + // 使用 std::transform 将 ValueSequence 中的元素转换为 int64_t,并存储到 vector 中。 + (void)std::transform(vec->value().begin(), vec->value().end(), list.begin() + 2, + [](const ValuePtr &val) { return static_cast(GetValue(val)); }); + } else { // 如果 name 不是 "pad",则执行通用的转换逻辑。 + int64_t data = GetValue(value); // 从 value 中获取 int64_t 类型的数据。 + int size = 2; // 2 int in list // 设置 vector 的大小为2,以容纳两个 int64_t 类型的元素。 + // 调用 TransformUtil::ConvertIntToList 函数将 int64_t 转换为 std::vector。 + list = TransformUtil::ConvertIntToList(data, size); + } + + return list; // 返回转换后的 std::vector 对象。 +} + +// ConvertAnyUtil 函数用于将一个 ValuePtr 类型的值转换为 std::string 类型。 +// 转换的方式取决于传入的数据类型 AnyTraits> 和 AnyTraits。 +std::string ConvertAnyUtil(const ValuePtr &value, const AnyTraits>, const AnyTraits) { + MS_EXCEPTION_IF_NULL(value); + auto vec = value->cast(); // 将 value 转换为 ValueTuplePtr 类型。 + if (vec == nullptr) { // 如果 vec 为空指针,则抛出异常,说明传入的 value 不是 ValueTuplePtr 类型。 + MS_LOG(EXCEPTION) << "not ValueTuplePtr"; + } + std::ostringstream buffer; // 创建一个 ostringstream 对象,用于构建字符串。 + int i = 0; // 用于辅助构建字符串的计数器。 + for (auto &it : vec->value()) { // 遍历 value 中的元素。 + if (i != 0) { // 在每个元素之前加入逗号(除了第一个元素)。 + buffer << ","; + } + buffer << GetValue(it); // 将元素的值转换为 int64_t,并添加到字符串流中。 + i++; // 增加计数器。 + } + return buffer.str(); // 返回构建的字符串。 +} + +// ConvertAnyUtil 函数用于将一个 ValuePtr 类型的值转换为 std::vector 类型。 +// 转换的方式取决于传入的数据类型 AnyTraits> 和 AnyTraits。 +std::vector ConvertAnyUtil(const ValuePtr &value, const AnyTraits>, const AnyTraits) { + MS_EXCEPTION_IF_NULL(value); + auto vec = value->cast(); // 将 value 转换为 ValueTuplePtr 类型。 + if (vec == nullptr) { // 如果 vec 为空指针,则抛出异常,说明传入的 value 不是 ValueTuplePtr 类型。 + MS_LOG(EXCEPTION) << "not ValueTuplePtr"; + } + std::vector list; // 创建一个 std::vector 对象,用于存储转换后的结果。 + list.resize(vec->value().size()); // 调整 vector 的大小以容纳转换后的结果,大小与 ValueTuple 中的元素个数相同。 + // 使用 std::transform 将 ValueTuple 中的每个元素转换为 float,并存储到 vector 中。 + (void)std::transform(vec->value().begin(), vec->value().end(), list.begin(), + [](const ValuePtr &val) { return static_cast(GetValue(val)); }); + return list; // 返回转换后的 std::vector 对象。 +} + +// ConvertAnyUtil 函数用于将一个 ValuePtr 类型的值转换为 std::vector 类型。 +// 转换的方式取决于传入的 format 参数和数据类型 AnyTraits> 和 AnyTraits。 +std::vector ConvertAnyUtil(const ValuePtr &value, const std::string &format, + const AnyTraits>, const AnyTraits) { + MS_EXCEPTION_IF_NULL(value); + auto vec = value->cast(); // 将 value 转换为 ValueTuplePtr 类型。 + if (vec == nullptr) { // 如果 vec 为空指针,则抛出异常,说明传入的 value 不是 ValueTuplePtr 类型。 + MS_LOG(EXCEPTION) << "not ValueTuplePtr"; + } + std::vector list; // 创建一个 std::vector 对象,用于存储转换后的结果。 + list.resize(vec->value().size()); // 调整 vector 的大小以容纳转换后的结果,大小与 ValueTuple 中的元素个数相同。 + // 使用 std::transform 将 ValueTuple 中的每个元素转换为 int64_t,并存储到 vector 中。 + (void)std::transform(vec->value().begin(), vec->value().end(), list.begin(), + [](const ValuePtr &val) { return static_cast(GetValue(val)); }); + if (format == kOpFormat_NHWC) { // 根据传入的 format 参数执行特定的格式转换。 + if (list.size() < 4) { // 如果格式为 NHWC,但列表大小小于4,则抛出异常。 + MS_LOG(EXCEPTION) << "The size of list is less than 4"; + } else { // 如果格式为 NHWC,并且列表大小大于等于4,则进行格式转换。 + // 将列表中的第1个元素和第2个元素交换位置,将第3个元素和第4个元素交换位置。 + int64_t temp = list[1]; + list[1] = list[2]; + list[2] = list[3]; + list[3] = temp; + } + } + return list; // 返回转换后的 std::vector 对象。 +} + +// ConvertAnyUtil 函数用于将一个 ValuePtr 类型的值转换为 GeDataType(GraphEngine 的数据类型)。 +// 转换的方式取决于传入的数据类型 AnyTraits。 +GeDataType ConvertAnyUtil(const ValuePtr &value, const AnyTraits) { + MS_EXCEPTION_IF_NULL(value); + if (!value->isa()) { // 确保 value 是 Type 类型。 + MS_LOG(EXCEPTION) << "error convert Value to TypePtr for value: " << value->ToString() + << ", type: " << value->type_name() << ", value should be a Typeptr"; + } + auto type = value->cast(); // 将 value 转换为 TypePtr 类型。 + MS_EXCEPTION_IF_NULL(type); // 确保转换后的 type 不为空指针。 + TypeId me_type = type->type_id(); // 获取 TypePtr 对象的 TypeId(MindSpore 中的数据类型标识)。 + // 如果 TypePtr 对象的 TypeId 是 kObjectTypeTensorType,表示其为 TensorType 类型。 + // 需要进一步获取其元素类型的 TypeId,以便进行后续的 GraphEngine 数据类型转换。 + if (kObjectTypeTensorType == me_type) { + me_type = dyn_cast(type)->element()->type_id(); + } + return TransformUtil::ConvertDataType(me_type); // 调用 TransformUtil::ConvertDataType 函数将 MindSpore 的数据类型转换为 GraphEngine 的数据类型。 +} + +// VectorToTensorUtil 函数用于将一个 ValuePtr 类型的值转换为 GeTensor(GraphEngine 的 Tensor)。 +// 该函数支持将 tuple 或 list 转换为 GeTensor,目前仅支持一维数据。 +GeTensor VectorToTensorUtil(const ValuePtr &value) { + // convert tuple or list to ge tensor, only supported one dim for now + // 转换 tuple 或 list 到 ge tensor,目前仅支持一维数据 + MS_EXCEPTION_IF_NULL(value); + // 获取 tuple 或 list 中的元素值。 + auto vec = value->isa() ? value->cast()->value() : value->cast()->value(); + if (vec.empty()) { // 如果 tuple 或 list 为空,则返回一个空的 GeTensor。 + MS_LOG(WARNING) << "Convert a none tuple to an empty ge tensor"; + return GeTensor(GeTensorDesc(ge::Shape({0}))); + } + MS_EXCEPTION_IF_NULL(vec[0]); // 获取第一个元素,并确保它不为空。 + // 根据第一个元素的数据类型执行相应的转换逻辑。 + // 如果第一个元素是 Int32Imm 类型,表示需要将数据转换为 int32_t 类型的 GeTensor。 + if (vec[0]->isa()) { + MS_LOG(INFO) << "convert value to tensor with data type = Int32"; + // 将数据转换为 int32_t 类型的 std::vector。 + auto data = ConvertAnyUtil(value, AnyTraits(), AnyTraits>()); + // 获取对应的 GeTensorDesc 描述信息。 + auto desc = TransformUtil::GetGeTensorDesc({static_cast(vec.size())}, kNumberTypeInt32, kOpFormat_NCHW); + // 如果获取描述信息失败,则抛出异常。 + if (desc == nullptr) { + MS_LOG(EXCEPTION) << "Update conversion descriptor failed!"; + } + // 创建 GeTensor,并使用 int32_t 类型的数据填充 Tensor 数据。 + return GeTensor(*desc, reinterpret_cast(data.data()), data.size() * sizeof(int32_t)); + // 如果第一个元素是 Int64Imm 类型,表示需要将数据转换为 int64_t 类型的 GeTensor。 + } else if (vec[0]->isa()) { + MS_LOG(INFO) << "convert value to tensor with data type = Int64"; + // 将数据转换为 int64_t 类型的 std::vector。 + auto data = ConvertAnyUtil(value, AnyTraits(), AnyTraits>()); + // 获取对应的 GeTensorDesc 描述信息。 + auto desc = TransformUtil::GetGeTensorDesc({static_cast(vec.size())}, kNumberTypeInt64, kOpFormat_NCHW); + if (desc == nullptr) { // 如果获取描述信息失败,则抛出异常。 + MS_LOG(EXCEPTION) << "Update conversion descriptor failed!"; + } + // 创建 GeTensor,并使用 int64_t 类型的数据填充 Tensor 数据。 + return GeTensor(*desc, reinterpret_cast(data.data()), data.size() * sizeof(int64_t)); + // 如果第一个元素是 FP32Imm 类型,表示需要将数据转换为 float 类型的 GeTensor。 + } else if (vec[0]->isa()) { + MS_LOG(INFO) << "convert value to tensor with data type = Float32"; + // 将数据转换为 float 类型的 std::vector。 + auto data = ConvertAnyUtil(value, AnyTraits(), AnyTraits>()); + // 获取对应的 GeTensorDesc 描述信息。 + auto desc = TransformUtil::GetGeTensorDesc({static_cast(vec.size())}, kNumberTypeFloat32, kOpFormat_NCHW); + if (desc == nullptr) { // 如果获取描述信息失败,则抛出异常。 + MS_LOG(EXCEPTION) << "Update conversion descriptor failed!"; + } + // 创建 GeTensor,并使用 float 类型的数据填充 Tensor 数据。 + return GeTensor(*desc, reinterpret_cast(data.data()), data.size() * sizeof(float)); + } else if (vec[0]->isa()) { // 如果第一个元素是 BoolImm 类型,表示需要将数据转换为 bool 类型的 GeTensor。 + MS_LOG(INFO) << "convert value to tensor with data type = Bool"; + // We use uint8_t to save bool type data + // 将数据转换为 bool 类型的 std::vector。 + // 这里使用 uint8_t + auto data = ConvertAnyUtil(value, AnyTraits(), AnyTraits>()); + auto desc = TransformUtil::GetGeTensorDesc({static_cast(vec.size())}, kNumberTypeBool, kOpFormat_NCHW); + if (desc == nullptr) { + MS_LOG(EXCEPTION) << "Update conversion descriptor failed!"; + } + return GeTensor(*desc, static_cast(data.data()), data.size() * sizeof(uint8_t)); + } else { + MS_LOG(EXCEPTION) << "Unsupported data type of tuple or list elements: " << vec[0]->type_name(); + } +} + +// ConvertAnyUtil 函数用于将一个 ValuePtr 类型的值转换为 GeTensor(GraphEngine 的 Tensor)。 +// 转换的方式取决于传入的数据类型 AnyTraits。 +GeTensor ConvertAnyUtil(const ValuePtr &value, const AnyTraits) { + MS_EXCEPTION_IF_NULL(value); + if (value->isa()) { // 检查 ValuePtr 是否是 MeTensor 类型,如果是,则执行 MeTensor 到 GeTensor 的转换。 + // convert me tensor to ge tensor + // 将 MeTensor 转换为 GeTensor + return ConvertAnyUtil(value, AnyTraits()); + // 检查 ValuePtr 是否是 ValueList 或 ValueTuple 类型,如果是,则执行 List 或 Tuple 到 GeTensor 的转换。 + } else if (value->isa() || value->isa()) { + return VectorToTensorUtil(value); + // 检查 ValuePtr 是否是 Int32Imm 类型,如果是,则执行 Int32Imm 到 GeTensor 的转换。 + } else if (value->isa()) { + // convert scalar Int to GeTensor + // 将标量 Int32 转换为 GeTensor + MS_LOG(INFO) << "convert scalar to tensor with data type = Int32"; + GeTensorDesc desc(GeShape(), ge::FORMAT_NCHW, ge::DT_INT32); // 创建 GeTensorDesc 描述信息。 + auto v = GetValue(value); + desc.SetRealDimCnt(0); // 设置描述信息的实际维度数为0(标量)。 + return GeTensor(desc, reinterpret_cast(&v), sizeof(int32_t)); // 创建 GeTensor,并使用 int32_t 类型的数据填充 Tensor 数据。 + } + // 检查 ValuePtr 是否是 Int64Imm 类型,如果是,则执行 Int64Imm 到 GeTensor 的转换。 + else if (value->isa()) { + // convert scalar Int64 to GeTensor + // 将标量 Int64 转换为 GeTensor + MS_LOG(INFO) << "convert scalar to tensor with data type = Int64"; + GeTensorDesc desc(GeShape(), ge::FORMAT_NCHW, ge::DT_INT64); // 创建 GeTensorDesc 描述信息。 + auto v = GetValue(value); + desc.SetRealDimCnt(0); // 设置描述信息的实际维度数为0(标量)。 + return GeTensor(desc, reinterpret_cast(&v), sizeof(int64_t)); // 创建 GeTensor,并使用 int64_t 类型的数据填充 Tensor 数据。 + } + // 检查 ValuePtr 是否是 FP32Imm 类型,如果是,则执行 FP32Imm 到 GeTensor 的转换。 + else if (value->isa()) { + // convert scalar FP32 to GeTensor + MS_LOG(INFO) << "convert scalar to tensor with data type = FP32"; // 将标量 FP32 转换为 GeTensor + GeTensorDesc desc(GeShape(), ge::FORMAT_NCHW, ge::DT_FLOAT); // 创建 GeTensorDesc 描述信息。 + auto v = GetValue(value); + desc.SetRealDimCnt(0); // 设置描述信息的实际维度数为0(标量)。 + return GeTensor(desc, reinterpret_cast(&v), sizeof(float)); // 创建 GeTensor,并使用 float 类型的数据填充 Tensor 数据。 + } + // 检查 ValuePtr 是否是 BoolImm 类型,如果是,则执行 BoolImm 到 GeTensor 的转换。 + else if (value->isa()) { + // convert scalar FP32 to GeTensor + // 将标量 Bool 转换为 GeTensor + MS_LOG(INFO) << "convert scalar to tensor with data type = Bool"; + GeTensorDesc desc(GeShape(), ge::FORMAT_NCHW, ge::DT_BOOL); // 创建 GeTensorDesc 描述信息。 + auto v = GetValue(value); + desc.SetRealDimCnt(0); // 设置描述信息的实际维度数为0(标量)。 + return GeTensor(desc, reinterpret_cast(&v), sizeof(bool)); // 创建 GeTensor,并使用 bool 类型的数据填充 Tensor 数据。 + } + // 检查 ValuePtr 是否是 StringImm 类型,如果是,则执行 StringImm 到 GeTensor 的转换。 + else if (value->isa()) { + // convert String to GeTensor + // 将标量 String 转换为 GeTensor + MS_LOG(INFO) << "convert string to tensor with data type = String"; + std::string v = GetValue(value); // 获取 string 类型的值。 + std::vector ge_shape; // 创建 GeTensorDesc 描述信息。 + GeShape shape(ge_shape); + GeTensorDesc desc(shape, ge::FORMAT_NCHW, ge::DT_STRING); + GeTensor str_tensor(desc); + (void)str_tensor.SetData(v); + return str_tensor; + } else { + MS_LOG(WARNING) << "Unsupported value type: " << value->type_name() + << " to convert to tensor. Value: " << value->ToString(); + } + return GeTensor(); +} + +// IsCustomPrim 函数用于判断给定的 PrimitivePtr 是否为自定义的操作(Custom Primitive)。 +bool IsCustomPrim(const PrimitivePtr &prim) { + if (prim == nullptr) { // 如果给定的 PrimitivePtr 为空指针,则返回 false。 + return false; + } + // 从 Primitive 的属性中获取名为 "_custom_op_flag" 的属性值。 + ValuePtr flag = prim->GetAttr("_custom_op_flag"); + if (flag == nullptr) { // 如果获取到的属性值为空指针,则返回 false。 + return false; + } + // 将属性值转换为 bool 类型,并存储在变量 is_custom_op 中。 + bool is_custom_op = GetValue(flag); + // 如果 is_custom_op 为 false,同时 Primitive 的属性中有名为 "_custom_op_impl_config_path" 的属性, + // 则抛出异常,提示非自定义操作不应该分配 "_custom_op_impl_config_path" 属性。 + if (!is_custom_op && prim->GetAttr("_custom_op_impl_config_path") != nullptr) { + MS_LOG(EXCEPTION) << "The custom op flag is false, but the op information config path is not null, non-custom op " + "can not assign the op information config path."; + } + + return is_custom_op; // 返回 is_custom_op,表示给定的 Primitive 是否为自定义的操作。 +} + +// IsCustomCNode 函数用于判断给定的 AnfNodePtr 是否为自定义的 CNode。 +// 自定义 CNode 是指其第一个输入是 ValueNode,而该 ValueNode 包含一个自定义的 PrimitivePtr。 +bool IsCustomCNode(const AnfNodePtr &anf) { + if (anf == nullptr) { // 如果给定的 AnfNodePtr 为空指针,则返回 false。 + return false; + } + auto node = anf->cast(); // 将 AnfNodePtr 转换为 CNodePtr。 + if (node == nullptr) { // 如果转换失败,说明给定的 AnfNodePtr 不是 CNode,返回 false。 + return false; + } + if (node->inputs().empty()) { // 检查 CNode 的输入是否为空,如果为空,抛出异常。 + MS_LOG(EXCEPTION) << "Length of node inputs is empty"; + } + MS_EXCEPTION_IF_NULL(node->inputs()[0]); // 检查 CNode 的第一个输入是否为空指针,如果是,抛出异常。 + // 检查 CNode 的第一个输入是否为 ValueNode,如果不是,返回 false,表示不是自定义 CNode。 + if (!node->inputs()[0]->isa()) { + return false; + } + // 尝试将 CNode 的第一个输入转换为 ValueNode,并获取其包含的 PrimitivePtr。 + auto cus_prim = GetValueNode(node->inputs()[0]); + if (cus_prim == nullptr) { // 如果获取的 PrimitivePtr 为空指针,返回 false,表示不是自定义 CNode。 + return false; + } + + return IsCustomPrim(cus_prim); // 调用 IsCustomPrim 函数判断获取的 PrimitivePtr 是否为自定义的操作,返回判断结果。 +} + +// GetOpIOFormat 函数用于获取给定 AnfNodePtr 对应的操作的输入输出格式(IO Format)。 +std::string GetOpIOFormat(const AnfNodePtr &anf) { + std::string ret; + if (anf == nullptr) { // 检查给定的 AnfNodePtr 是否为空指针,如果是,输出错误日志并返回空字符串。 + MS_LOG(ERROR) << "The anf is nullptr"; + return ret; + } + auto node = anf->cast(); // 尝试将 AnfNodePtr 转换为 CNodePtr。 + if (node == nullptr) { // 如果转换失败,说明给定的 AnfNodePtr 不是 CNode,输出错误日志并返回空字符串。 + MS_LOG(ERROR) << "The anf is not a cnode."; + return ret; + } + if (node->inputs().empty()) { // 检查 CNode 的输入是否为空,如果为空,抛出异常。 + MS_LOG(EXCEPTION) << "Length of node inputs is empty."; + } + MS_EXCEPTION_IF_NULL(node->inputs()[0]); // 检查 CNode 的第一个输入是否为空指针,如果是,抛出异常。 + if (!node->inputs()[0]->isa()) { // 检查 CNode 的第一个输入是否为 ValueNode,如果不是,输出错误日志并返回空字符串。 + MS_LOG(ERROR) << "The anf is not a value node."; + return ret; + } + auto prim = GetValueNode(node->inputs()[0]); // 尝试将 CNode 的第一个输入转换为 ValueNode,并获取其包含的 PrimitivePtr。 + if (prim == nullptr) { // 如果获取的 PrimitivePtr 为空指针,输出错误日志并返回空字符串。 + MS_LOG(ERROR) << "The anf is not a Primitive."; + return ret; + } + if (prim->HasAttr("io_format")) { // 检查 PrimitivePtr 是否有名为 "io_format" 的属性,如果有,则返回其属性值作为 IO Format。 + return GetValue(prim->GetAttr("io_format")); + } + // 如果 PrimitivePtr 没有名为 "io_format" 的属性,则从 IOFormatMap 中查找操作名对应的 IO Format。 + auto io_format_map = IOFormatMap::get(); + auto iter = io_format_map.find(prim->name()); + if (iter == io_format_map.end()) { // 如果在 IOFormatMap 中没有找到对应的 IO Format,则默认返回 "NCHW"。 + return "NCHW"; + } + // 检查该 IO Format 是否是 "format" 类型的属性,如果是,进一步处理后返回具体的格式值。 + if (iter->second == "format") { + ValuePtr format = prim->GetAttr("format"); + MS_EXCEPTION_IF_NULL(format); + if (format->isa()) { + bool converted = CheckAndConvertUtils::ConvertAttrValueToString(prim->name(), "format", &format); + if (converted) { + return GetValue(format); + } + } else { + return GetValue(format); + } + } + return iter->second; // 如果不是 "format" 类型的属性,直接返回 IO Format。 +} +} // namespace transform +} // namespace mindspore