transform/op_adapter_util.cc

393 lines
21 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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 <string>
#include <vector>
#include <algorithm>
#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 中的 Tensormindspore::tensor::Tensor转换为 GEGraphEngine中的TensorGeTensor
GeTensor ConvertAnyUtil(const ValuePtr &value, const AnyTraits<mindspore::tensor::Tensor> &) {
// To-DO the format may read from ME tensor
// TODO可能需要从 MEMindSpore Execution Tensor 读取格式信息format
MS_EXCEPTION_IF_NULL(value);
//// 将 value 强制转换为 MeTensorPtr 类型MeTensorPtr 是一个智能指针,表示 ME TensorMindSpore Execution Tensor
auto me_tensor = value->cast<MeTensorPtr>();
// 调用 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<int64_t> 类型。
// 转换的方式取决于传入的 name 参数和数据类型 AnyTraits<std::vector<int64_t>>。
std::vector<int64_t> ConvertAnyUtil(const ValuePtr &value, const std::string &name,
const AnyTraits<std::vector<int64_t>>) {
MS_EXCEPTION_IF_NULL(value);
std::vector<int64_t> list; // 创建一个 int64_t 类型的 vector用于存储转换后的结果。
if (name == "pad") { // 如果传入的 name 是 "pad",则执行特定的转换逻辑。
if (!value->isa<ValueSequence>()) { // 确保 value 是 ValueSequence 类型。
MS_LOG(EXCEPTION) << "Value should be ValueTuple, but got" << value->type_name();
}
auto vec = value->cast<ValueSequencePtr>(); // 将 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<int64_t>(GetValue<int64_t>(val)); });
} else { // 如果 name 不是 "pad",则执行通用的转换逻辑。
int64_t data = GetValue<int64_t>(value); // 从 value 中获取 int64_t 类型的数据。
int size = 2; // 2 int in list // 设置 vector 的大小为2以容纳两个 int64_t 类型的元素。
// 调用 TransformUtil::ConvertIntToList 函数将 int64_t 转换为 std::vector<int64_t>。
list = TransformUtil::ConvertIntToList(data, size);
}
return list; // 返回转换后的 std::vector<int64_t> 对象。
}
// ConvertAnyUtil 函数用于将一个 ValuePtr 类型的值转换为 std::string 类型。
// 转换的方式取决于传入的数据类型 AnyTraits<std::vector<int64_t>> 和 AnyTraits<std::string>。
std::string ConvertAnyUtil(const ValuePtr &value, const AnyTraits<std::vector<int64_t>>, const AnyTraits<std::string>) {
MS_EXCEPTION_IF_NULL(value);
auto vec = value->cast<ValueTuplePtr>(); // 将 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<int64_t>(it); // 将元素的值转换为 int64_t并添加到字符串流中。
i++; // 增加计数器。
}
return buffer.str(); // 返回构建的字符串。
}
// ConvertAnyUtil 函数用于将一个 ValuePtr 类型的值转换为 std::vector<float> 类型。
// 转换的方式取决于传入的数据类型 AnyTraits<std::vector<float>> 和 AnyTraits<float>。
std::vector<float> ConvertAnyUtil(const ValuePtr &value, const AnyTraits<std::vector<float>>, const AnyTraits<float>) {
MS_EXCEPTION_IF_NULL(value);
auto vec = value->cast<ValueTuplePtr>(); // 将 value 转换为 ValueTuplePtr 类型。
if (vec == nullptr) { // 如果 vec 为空指针,则抛出异常,说明传入的 value 不是 ValueTuplePtr 类型。
MS_LOG(EXCEPTION) << "not ValueTuplePtr";
}
std::vector<float> list; // 创建一个 std::vector<float> 对象,用于存储转换后的结果。
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<float>(GetValue<float>(val)); });
return list; // 返回转换后的 std::vector<float> 对象。
}
// ConvertAnyUtil 函数用于将一个 ValuePtr 类型的值转换为 std::vector<int64_t> 类型。
// 转换的方式取决于传入的 format 参数和数据类型 AnyTraits<std::vector<int64_t>> 和 AnyTraits<int64_t>。
std::vector<int64_t> ConvertAnyUtil(const ValuePtr &value, const std::string &format,
const AnyTraits<std::vector<int64_t>>, const AnyTraits<int64_t>) {
MS_EXCEPTION_IF_NULL(value);
auto vec = value->cast<ValueTuplePtr>(); // 将 value 转换为 ValueTuplePtr 类型。
if (vec == nullptr) { // 如果 vec 为空指针,则抛出异常,说明传入的 value 不是 ValueTuplePtr 类型。
MS_LOG(EXCEPTION) << "not ValueTuplePtr";
}
std::vector<int64_t> list; // 创建一个 std::vector<int64_t> 对象,用于存储转换后的结果。
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<int64_t>(GetValue<int64_t>(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<int64_t> 对象。
}
// ConvertAnyUtil 函数用于将一个 ValuePtr 类型的值转换为 GeDataTypeGraphEngine 的数据类型)。
// 转换的方式取决于传入的数据类型 AnyTraits<GEType>。
GeDataType ConvertAnyUtil(const ValuePtr &value, const AnyTraits<GEType>) {
MS_EXCEPTION_IF_NULL(value);
if (!value->isa<Type>()) { // 确保 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<TypePtr>(); // 将 value 转换为 TypePtr 类型。
MS_EXCEPTION_IF_NULL(type); // 确保转换后的 type 不为空指针。
TypeId me_type = type->type_id(); // 获取 TypePtr 对象的 TypeIdMindSpore 中的数据类型标识)。
// 如果 TypePtr 对象的 TypeId 是 kObjectTypeTensorType表示其为 TensorType 类型。
// 需要进一步获取其元素类型的 TypeId以便进行后续的 GraphEngine 数据类型转换。
if (kObjectTypeTensorType == me_type) {
me_type = dyn_cast<TensorType>(type)->element()->type_id();
}
return TransformUtil::ConvertDataType(me_type); // 调用 TransformUtil::ConvertDataType 函数将 MindSpore 的数据类型转换为 GraphEngine 的数据类型。
}
// VectorToTensorUtil 函数用于将一个 ValuePtr 类型的值转换为 GeTensorGraphEngine 的 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<ValueTuple>() ? value->cast<ValueTuplePtr>()->value() : value->cast<ValueListPtr>()->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<Int32Imm>()) {
MS_LOG(INFO) << "convert value to tensor with data type = Int32";
// 将数据转换为 int32_t 类型的 std::vector。
auto data = ConvertAnyUtil(value, AnyTraits<int32_t>(), AnyTraits<std::vector<int32_t>>());
// 获取对应的 GeTensorDesc 描述信息。
auto desc = TransformUtil::GetGeTensorDesc({static_cast<int>(vec.size())}, kNumberTypeInt32, kOpFormat_NCHW);
// 如果获取描述信息失败,则抛出异常。
if (desc == nullptr) {
MS_LOG(EXCEPTION) << "Update conversion descriptor failed!";
}
// 创建 GeTensor并使用 int32_t 类型的数据填充 Tensor 数据。
return GeTensor(*desc, reinterpret_cast<uint8_t *>(data.data()), data.size() * sizeof(int32_t));
// 如果第一个元素是 Int64Imm 类型,表示需要将数据转换为 int64_t 类型的 GeTensor。
} else if (vec[0]->isa<Int64Imm>()) {
MS_LOG(INFO) << "convert value to tensor with data type = Int64";
// 将数据转换为 int64_t 类型的 std::vector。
auto data = ConvertAnyUtil(value, AnyTraits<int64_t>(), AnyTraits<std::vector<int64_t>>());
// 获取对应的 GeTensorDesc 描述信息。
auto desc = TransformUtil::GetGeTensorDesc({static_cast<int>(vec.size())}, kNumberTypeInt64, kOpFormat_NCHW);
if (desc == nullptr) { // 如果获取描述信息失败,则抛出异常。
MS_LOG(EXCEPTION) << "Update conversion descriptor failed!";
}
// 创建 GeTensor并使用 int64_t 类型的数据填充 Tensor 数据。
return GeTensor(*desc, reinterpret_cast<uint8_t *>(data.data()), data.size() * sizeof(int64_t));
// 如果第一个元素是 FP32Imm 类型,表示需要将数据转换为 float 类型的 GeTensor。
} else if (vec[0]->isa<FP32Imm>()) {
MS_LOG(INFO) << "convert value to tensor with data type = Float32";
// 将数据转换为 float 类型的 std::vector。
auto data = ConvertAnyUtil(value, AnyTraits<float>(), AnyTraits<std::vector<float>>());
// 获取对应的 GeTensorDesc 描述信息。
auto desc = TransformUtil::GetGeTensorDesc({static_cast<int>(vec.size())}, kNumberTypeFloat32, kOpFormat_NCHW);
if (desc == nullptr) { // 如果获取描述信息失败,则抛出异常。
MS_LOG(EXCEPTION) << "Update conversion descriptor failed!";
}
// 创建 GeTensor并使用 float 类型的数据填充 Tensor 数据。
return GeTensor(*desc, reinterpret_cast<uint8_t *>(data.data()), data.size() * sizeof(float));
} else if (vec[0]->isa<BoolImm>()) { // 如果第一个元素是 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<bool>(), AnyTraits<std::vector<uint8_t>>());
auto desc = TransformUtil::GetGeTensorDesc({static_cast<int>(vec.size())}, kNumberTypeBool, kOpFormat_NCHW);
if (desc == nullptr) {
MS_LOG(EXCEPTION) << "Update conversion descriptor failed!";
}
return GeTensor(*desc, static_cast<uint8_t *>(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 类型的值转换为 GeTensorGraphEngine 的 Tensor
// 转换的方式取决于传入的数据类型 AnyTraits<AnyValue>。
GeTensor ConvertAnyUtil(const ValuePtr &value, const AnyTraits<AnyValue>) {
MS_EXCEPTION_IF_NULL(value);
if (value->isa<MeTensor>()) { // 检查 ValuePtr 是否是 MeTensor 类型,如果是,则执行 MeTensor 到 GeTensor 的转换。
// convert me tensor to ge tensor
// 将 MeTensor 转换为 GeTensor
return ConvertAnyUtil(value, AnyTraits<MeTensor>());
// 检查 ValuePtr 是否是 ValueList 或 ValueTuple 类型,如果是,则执行 List 或 Tuple 到 GeTensor 的转换。
} else if (value->isa<ValueList>() || value->isa<ValueTuple>()) {
return VectorToTensorUtil(value);
// 检查 ValuePtr 是否是 Int32Imm 类型,如果是,则执行 Int32Imm 到 GeTensor 的转换。
} else if (value->isa<Int32Imm>()) {
// 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<int32_t>(value);
desc.SetRealDimCnt(0); // 设置描述信息的实际维度数为0标量
return GeTensor(desc, reinterpret_cast<uint8_t *>(&v), sizeof(int32_t)); // 创建 GeTensor并使用 int32_t 类型的数据填充 Tensor 数据。
}
// 检查 ValuePtr 是否是 Int64Imm 类型,如果是,则执行 Int64Imm 到 GeTensor 的转换。
else if (value->isa<Int64Imm>()) {
// 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<int64_t>(value);
desc.SetRealDimCnt(0); // 设置描述信息的实际维度数为0标量
return GeTensor(desc, reinterpret_cast<uint8_t *>(&v), sizeof(int64_t)); // 创建 GeTensor并使用 int64_t 类型的数据填充 Tensor 数据。
}
// 检查 ValuePtr 是否是 FP32Imm 类型,如果是,则执行 FP32Imm 到 GeTensor 的转换。
else if (value->isa<FP32Imm>()) {
// 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<float>(value);
desc.SetRealDimCnt(0); // 设置描述信息的实际维度数为0标量
return GeTensor(desc, reinterpret_cast<uint8_t *>(&v), sizeof(float)); // 创建 GeTensor并使用 float 类型的数据填充 Tensor 数据。
}
// 检查 ValuePtr 是否是 BoolImm 类型,如果是,则执行 BoolImm 到 GeTensor 的转换。
else if (value->isa<BoolImm>()) {
// 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<bool>(value);
desc.SetRealDimCnt(0); // 设置描述信息的实际维度数为0标量
return GeTensor(desc, reinterpret_cast<uint8_t *>(&v), sizeof(bool)); // 创建 GeTensor并使用 bool 类型的数据填充 Tensor 数据。
}
// 检查 ValuePtr 是否是 StringImm 类型,如果是,则执行 StringImm 到 GeTensor 的转换。
else if (value->isa<StringImm>()) {
// convert String to GeTensor
// 将标量 String 转换为 GeTensor
MS_LOG(INFO) << "convert string to tensor with data type = String";
std::string v = GetValue<std::string>(value); // 获取 string 类型的值。
std::vector<int64_t> 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<bool>(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<CNodePtr>(); // 将 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<ValueNode>()) {
return false;
}
// 尝试将 CNode 的第一个输入转换为 ValueNode并获取其包含的 PrimitivePtr。
auto cus_prim = GetValueNode<PrimitivePtr>(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<CNodePtr>(); // 尝试将 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<ValueNode>()) { // 检查 CNode 的第一个输入是否为 ValueNode如果不是输出错误日志并返回空字符串。
MS_LOG(ERROR) << "The anf is not a value node.";
return ret;
}
auto prim = GetValueNode<PrimitivePtr>(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<std::string>(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<Int64Imm>()) {
bool converted = CheckAndConvertUtils::ConvertAttrValueToString(prim->name(), "format", &format);
if (converted) {
return GetValue<std::string>(format);
}
} else {
return GetValue<std::string>(format);
}
}
return iter->second; // 如果不是 "format" 类型的属性,直接返回 IO Format。
}
} // namespace transform
} // namespace mindspore