/** * Copyright (c) Huawei Technologies Co., Ltd. 2020~2022. All rights reserved. * * 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 "parser/caffe/caffe_parser.h" #include #include #include #include #include #include #include #include #include #include #include #include "common/convert/message2operator.h" #include "parser/common/convert/pb2json.h" #include "parser/common/acl_graph_parser_util.h" #include "common/op_map.h" #include "common/util/error_manager/error_manager.h" #include "common/string_util.h" #include "external/graph/operator_factory.h" #include "external/parser/caffe_parser.h" #include "external/ge/ge_api_types.h" #include "framework/common/debug/ge_log.h" #include "graph/utils/graph_utils.h" #include "omg/parser/op_parser.h" #include "omg/parser/parser_factory.h" #include "omg/parser/parser_inner_ctx.h" #include "parser/caffe/caffe_custom_parser_adapter.h" #include "parser/caffe/caffe_op_parser.h" #include "parser/common/op_parser_factory.h" #include "parser/common/prototype_pass_manager.h" #include "framework/omg/parser/parser_types.h" #include "parser/common/model_saver.h" #include "parser/common/acl_graph_parser_util.h" #include "parser/common/proto_file_parser.h" #include "register/op_registry.h" #include "register/register_fmk_types.h" #include "mmpa/mmpa_api.h" #include "parser/common/parser_utils.h" using domi::caffe::ConvolutionParameter; using domi::caffe::InnerProductParameter; using domi::caffe::LayerParameter; using domi::caffe::NetParameter; using domi::ParseParamByOpFunc; using ge::parser::ModelSaver; using std::ifstream; #define CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(val, errormsg) \ do { \ if ((val) == nullptr) { \ GELOGE(ge::PARAM_INVALID, errormsg); \ REPORT_INNER_ERROR("E19999", errormsg); \ return ge::PARAM_INVALID; \ } \ } while (0) namespace { const size_t kMaxErrStrLen = 128U; std::map, std::vector> params_share_map; } // namespace namespace ge { graphStatus aclgrphParseCaffe(const char *model_file, const char *weights_file, ge::Graph &graph) { ErrorManager::GetInstance().SetStage(error_message::kModelCompile, error_message::kParser); GE_CHECK_NOTNULL(model_file); GetParserContext().type = domi::CAFFE; std::map options; options.insert(std::pair(string(ge::FRAMEWORK_TYPE), to_string(domi::CAFFE))); // load custom plugin so and proto AclGrphParseUtil acl_graph_parse_util; domi::Status status = acl_graph_parse_util.AclParserInitialize(options); if (status != domi::SUCCESS) { REPORT_CALL_ERROR("E19999", "AclParserInitialize failed, ret:%d.", status); GELOGE(GRAPH_FAILED, "[Parser][Initialize] failed, ret:%d.", status); return GRAPH_FAILED; } // Create an empty computegraph ge::ComputeGraphPtr compute_graph = ge::parser::MakeShared("tmpGraph"); GE_CHECK_NOTNULL(compute_graph); graph = ge::GraphUtils::CreateGraphFromComputeGraph(compute_graph); auto model_parser = domi::ModelParserFactory::Instance()->CreateModelParser(domi::CAFFE); GE_CHECK_NOTNULL(model_parser); // parse caffe model_file and weights_file to GE graph ge::graphStatus ret = model_parser->Parse(model_file, graph); if (ret != ge::SUCCESS) { REPORT_CALL_ERROR("E19999", "parse param:model_file %s failed, graph:%s.", model_file, ParserUtils::GetGraphName(graph).c_str()); GELOGE(ret, "[Parser][Param]ModelFile %s failed, graph:%s.", model_file, ParserUtils::GetGraphName(graph).c_str()); return ge::FAILED; } GELOGI("Parser graph %s success.", ParserUtils::GetGraphName(graph).c_str()); auto weights_parser = domi::WeightsParserFactory::Instance()->CreateWeightsParser(domi::CAFFE); GE_CHECK_NOTNULL(weights_parser); ret = weights_parser->Parse(weights_file, graph); if (ret != ge::SUCCESS) { REPORT_CALL_ERROR("E19999", "parse param:weights_file %s failed, graph:%s", weights_file, ParserUtils::GetGraphName(graph).c_str()); GELOGE(ret, "[Parse][Param]WeightsFile %s failed. graph: %s", weights_file, ParserUtils::GetGraphName(graph).c_str()); return ret; } GELOGI("Weights parse success. graph: %s", ParserUtils::GetGraphName(graph).c_str()); std::map parser_params; if (acl_graph_parse_util.SetOutputNodeInfo(graph, parser_params) != ge::SUCCESS) { REPORT_CALL_ERROR("E19999", "SetOutputNodeInfo failed, model file:%s graph:%s", model_file, ParserUtils::GetGraphName(graph).c_str()); GELOGE(ret, "[Invoke][SetOutputNodeInfo]Set graph %s default output node failed, model file:%s.", ParserUtils::GetGraphName(graph).c_str(), model_file); return ge::FAILED; } return ge::SUCCESS; } graphStatus aclgrphParseCaffe(const char *model_file, const char *weights_file, const std::map &parser_params, ge::Graph &graph) { ErrorManager::GetInstance().SetStage(error_message::kModelCompile, error_message::kParser); GE_CHECK_NOTNULL(model_file); GetParserContext().type = domi::CAFFE; std::map options; options.insert(std::pair(string(ge::FRAMEWORK_TYPE), to_string(domi::CAFFE))); // load custom plugin so and proto AclGrphParseUtil acl_graph_parse_util; domi::Status status = acl_graph_parse_util.AclParserInitialize(options); if (status != domi::SUCCESS) { REPORT_CALL_ERROR("E19999", "AclParserInitialize failed, ret:%d.", status); GELOGE(GRAPH_FAILED, "[Parser][Initialize] failed ret:%d.", status); return GRAPH_FAILED; } string output_name; if (acl_graph_parse_util.ParseParamsBeforeGraph(parser_params, output_name) != ge::SUCCESS) { GELOGE(ge::FAILED, "[Parse][Params]Before Graph failed."); return ge::FAILED; } // Create an empty computegraph string graph_name = output_name.empty() ? "tmpGraph" : output_name; ge::ComputeGraphPtr compute_graph = ge::parser::MakeShared(graph_name); GE_CHECK_NOTNULL(compute_graph); graph = ge::GraphUtils::CreateGraphFromComputeGraph(compute_graph); auto model_parser = domi::ModelParserFactory::Instance()->CreateModelParser(domi::CAFFE); GE_CHECK_NOTNULL(model_parser); // parse caffe model_file and weights_file to GE graph ge::graphStatus ret = model_parser->Parse(model_file, graph); if (ret != ge::SUCCESS) { REPORT_CALL_ERROR("E19999", "Parse param:model_file %s failed, graph:%s", model_file, ParserUtils::GetGraphName(graph).c_str()); GELOGE(ret, "[Parser][Param]ModelFile %s failed, graph %s.", model_file, ParserUtils::GetGraphName(graph).c_str()); return ge::FAILED; } GELOGI("Parser graph %s success.", ParserUtils::GetGraphName(graph).c_str()); if (acl_graph_parse_util.ParseParamsAfterGraph(graph, parser_params) != ge::SUCCESS) { REPORT_CALL_ERROR("E19999", "ParseParamsAfterGraph failed, graph:%s.", ParserUtils::GetGraphName(graph).c_str()); GELOGE(ge::FAILED, "[Parser][Params] after graph failed, graph:%s.", ParserUtils::GetGraphName(graph).c_str()); return ge::FAILED; } auto weights_parser = domi::WeightsParserFactory::Instance()->CreateWeightsParser(domi::CAFFE); GE_CHECK_NOTNULL(weights_parser); ret = weights_parser->Parse(weights_file, graph); if (ret != ge::SUCCESS) { REPORT_CALL_ERROR("E19999", "parse param:weights_file %s failed, graph: %s", weights_file, ParserUtils::GetGraphName(graph).c_str()); GELOGE(ret, "[Parse][Param]WeightsFile %s failed. graph: %s", weights_file, ParserUtils::GetGraphName(graph).c_str()); return ret; } GELOGI("Weights parse success. graph: %s", ParserUtils::GetGraphName(graph).c_str()); if (acl_graph_parse_util.SetOutputNodeInfo(graph, parser_params) != ge::SUCCESS) { REPORT_CALL_ERROR("E19999", "SetOutputNodeInfo failed, graph:%s", ParserUtils::GetGraphName(graph).c_str()); GELOGE(ge::FAILED, "[Invoke][SetOutputNodeInfo]Set graph %s default output node failed.", ParserUtils::GetGraphName(graph).c_str()); return ge::FAILED; } GELOGI("AclgrphParse graph %s success.", ParserUtils::GetGraphName(graph).c_str()); return ge::SUCCESS; } } // namespace ge namespace ge { namespace { const int32_t kAnchorIndexOne = 1; const int32_t kAnchorIndexTwo = 2; const int32_t kAnchorIndexThree = 3; const int32_t kNumOne = 1; const size_t kTensorNum = 2; const int32_t kMinLineWorldSize = 3; const int32_t kMaxIdentifier = 536870911; // 2^29 - 1 const int32_t kBase = 10; const char *const kPython = "Python"; const char *const kProposalLayer = "ProposalLayer"; const char *const kDetectionOutput = "DetectionOutput"; const char *const kProjectRoot = "project_root"; const char *const kBeginningMessageType = "domi.caffe.NetParameter"; const char *const kLayerMessageType = "domi.caffe.LayerParameter"; const char *const kLayerName = "layer"; const char *const kLayersName = "layers"; const char *const kFieldName = "name"; const char *const kFieldType = "type"; const char *const kFieldBottom = "bottom"; const char *const kFieldTop = "top"; const char *const kFieldBlobs = "blobs"; const char *const kFieldShape = "shape"; const char *const kFieldConvParam = "convolution_param"; const char *const kFieldInnerPro = "inner_product_param"; const char *const kFieldDim = "dim"; const char *const kFieldBiasTerm = "bias_term"; const char *const kDevNull = "/dev/null"; const char *const kCustom = "custom"; const char *const kBuiltin = "built-in"; std::vector kAddTensorIrSkipNodes = {ge::parser::DATA, ge::parser::YOLODETECTIONOUTPUT, ge::parser::NETOUTPUT}; const std::set kCustomProtoLayerCommonField = {"name", "type"}; const std::set kCaffeProtoLayerCommonField = {"name", "type", "bottom", "top", "phase", "loss_weight", "param", "blobs", "propagate_down", "include", "exclude"}; Status CheckPathValid(const char *model_path, const string &custom_proto, string &custom_proto_path, string &custom_proto_name) { string path_model = ge::parser::RealPath(model_path); if (path_model.empty()) { char_t err_buf[kMaxErrStrLen + 1U] = {}; const auto err_msg = mmGetErrorFormatMessage(mmGetErrorCode(), &err_buf[0], kMaxErrStrLen); ErrorManager::GetInstance().ATCReportErrMessage("E19000", {"path", "errmsg"}, {model_path, err_msg}); GELOGE(FAILED, "[Check][Param]ModelPath %s is Invalid path of model", model_path); return FAILED; } custom_proto_name = kProjectRoot; auto pos = custom_proto.find_last_of("/\\"); if (pos == string::npos) { custom_proto_path = "./"; custom_proto_name += '/' + custom_proto; } else { custom_proto_path = custom_proto.substr(0, pos); custom_proto_name += '/' + custom_proto.substr(pos + 1); } GELOGI("Check validity of model file: %s and proto file: %s success.", model_path, custom_proto.c_str()); return SUCCESS; } } // namespace /* MultiLabelLMDB?The negligible layer for weight analysis in license plate recognition network of Safe city. Python: Currently, python custom layer only supports proposal, and there is no corresponding data in the proposal weight file, so Python layer is ignored. */ const set CaffeWeightsParser::skiped_layer_type_ = {"Split", "SoftmaxWithLoss", "Accuracy", "Data", "Dropout", "MultiLabelLMDB", "Python", "AnnotatedData"}; Status CaffeModelParser::ParseInput(domi::caffe::NetParameter &proto_message, bool &input_data_flag) const { if (proto_message.input_size() <= 0) { return SUCCESS; } GELOGI("This net exsit input."); if (proto_message.input_dim_size() > 0) { if (proto_message.input_shape_size() > 0) { ErrorManager::GetInstance().ATCReportErrMessage("E11001"); GELOGE(FAILED, "[Check][Size]input_dim and input_shape can not both exist!"); return FAILED; } const int32_t input_dim_size = proto_message.input_dim_size(); const bool is_input_invalid = (((input_dim_size / proto_message.input_size()) != parser::DIM_DEFAULT_SIZE) || ((input_dim_size % proto_message.input_size()) != 0)); if (is_input_invalid) { ErrorManager::GetInstance().ATCReportErrMessage("E11003", {"input_dim_size", "input_size"}, {std::to_string(input_dim_size), std::to_string(proto_message.input_size())}); GELOGE(FAILED, "[Check][Size]Model input_dim size[%d] is not 4 times of input size[%d].", input_dim_size, proto_message.input_size()); return FAILED; } for (int i = 0; i < proto_message.input_size(); i++) { domi::caffe::LayerParameter *layer = proto_message.add_layer(); GE_CHECK_NOTNULL(layer); layer->set_name(proto_message.input(i)); layer->set_type(ge::parser::INPUT_TYPE); layer->add_top(proto_message.input(i)); domi::caffe::InputParameter *input_param = layer->mutable_input_param(); GE_CHECK_NOTNULL(input_param); domi::caffe::BlobShape *shape = input_param->add_shape(); GE_CHECK_NOTNULL(shape); for (int j = 0; j < parser::DIM_DEFAULT_SIZE; j++) { // Can guarantee that it will not cross the border shape->add_dim(static_cast(proto_message.input_dim(j + i * parser::DIM_DEFAULT_SIZE))); } input_data_flag = true; } } else if (proto_message.input_shape_size() > 0) { if (proto_message.input_shape_size() != proto_message.input_size()) { ErrorManager::GetInstance().ATCReportErrMessage("E11004", {"input_shape_size", "input_size"}, {std::to_string(proto_message.input_shape_size()), std::to_string(proto_message.input_size())}); GELOGE(FAILED, "[Check][Size]caffe net input_shape size(%d) is not equal input size(%d).", proto_message.input_shape_size(), proto_message.input_size()); return FAILED; } for (int i = 0; i < proto_message.input_size(); i++) { int dim_size = proto_message.input_shape(i).dim_size(); domi::caffe::LayerParameter *layer = proto_message.add_layer(); GE_CHECK_NOTNULL(layer); layer->set_name(proto_message.input(i)); layer->set_type(ge::parser::INPUT_TYPE); layer->add_top(proto_message.input(i)); domi::caffe::InputParameter *input_param = layer->mutable_input_param(); GE_CHECK_NOTNULL(input_param); domi::caffe::BlobShape *shape = input_param->add_shape(); GE_CHECK_NOTNULL(shape); for (int j = 0; j < dim_size; j++) { // Can guarantee that it will not cross the border shape->add_dim(static_cast(proto_message.input_shape(i).dim(j))); } input_data_flag = true; } } else { const ge::ParserContext &ctx = ge::GetParserContext(); std::map> input_dims = ctx.input_dims; for (int i = 0; i < proto_message.input_size(); i++) { string name = proto_message.input(i); if (input_dims.count(name) == 0) { // Input defined by model does not exist in input of external input REPORT_INPUT_ERROR("E11005", std::vector({"input"}), std::vector({name})); GELOGE(FAILED, "[Find][Dim]Model has no input shape."); return FAILED; } std::vector dims = input_dims.at(name); size_t dim_size = dims.size(); domi::caffe::LayerParameter *layer = proto_message.add_layer(); GE_CHECK_NOTNULL(layer); layer->set_name(name); layer->set_type(ge::parser::INPUT_TYPE); layer->add_top(proto_message.input(i)); domi::caffe::InputParameter *input_param = layer->mutable_input_param(); GE_CHECK_NOTNULL(input_param); domi::caffe::BlobShape *shape = input_param->add_shape(); GE_CHECK_NOTNULL(shape); for (size_t j = 0; j < dim_size; j++) { shape->add_dim(dims.at(j)); } input_data_flag = true; } } return SUCCESS; } Status CaffeModelParser::ParseNetModelByCustomProto(const char *model_path, const string &custom_proto_path, const string &custom_proto_name, vector &operators) const { google::protobuf::compiler::DiskSourceTree source_tree; source_tree.MapPath(kProjectRoot, custom_proto_path); google::protobuf::compiler::Importer importer(&source_tree, nullptr); importer.Import(custom_proto_name.c_str()); GELOGI("Import custom proto %s success.", custom_proto_path.c_str()); const google::protobuf::Descriptor *descriptor = importer.pool()->FindMessageTypeByName(kBeginningMessageType); GE_CHECK_NOTNULL(descriptor); google::protobuf::DynamicMessageFactory factory; const google::protobuf::Message *proto = factory.GetPrototype(descriptor); GE_CHECK_NOTNULL(proto); google::protobuf::Message *message = proto->New(); GE_CHECK_NOTNULL(message); if (ReadModelWithoutWarning(model_path, message) != SUCCESS) { delete message; GELOGE(FAILED, "[Invoke][ReadModelWithoutWarning] %s failed.", model_path); return FAILED; } GELOGI("Start to parse model file: %s.", model_path); const google::protobuf::Descriptor *layer_descriptor = importer.pool()->FindMessageTypeByName(kLayerMessageType); if (layer_descriptor == nullptr) { delete message; REPORT_INPUT_ERROR("E11032", std::vector({"message_type", "name", "reason"}), std::vector({"model", "LayerParameter", "Does not find domi.caffe.LayerParameter in google::protobuf::Descriptor"})); GELOGE(FAILED, "[Invoke][FindMessageTypeByName]Does not find domi.caffe.LayerParameter" "in google::protobuf::Descriptor"); return FAILED; } if (ParseLayerParameter(*layer_descriptor, *message, operators) != SUCCESS) { delete message; GELOGE(FAILED, "[Parse][LayerParameter] failed, model path:%s.", model_path); return FAILED; } delete message; GELOGI("Parse model: %s by proto: %s success.", model_path, custom_proto_path.c_str()); return SUCCESS; } Status CaffeModelParser::CustomProtoParse(const char *model_path, const string &custom_proto, const string &caffe_proto, vector &operators) { (void)caffe_proto; string custom_proto_path = ge::parser::RealPath(custom_proto.c_str()); if (custom_proto_path.empty()) { GELOGW("Valid custom proto: %s does not exist, skip parsing custom proto", custom_proto.c_str()); return SUCCESS; } string custom_proto_name; if (CheckPathValid(model_path, custom_proto, custom_proto_path, custom_proto_name) != SUCCESS) { GELOGE(FAILED, "[Check][PathValid] of model and proto failed, path:%s.", model_path); return FAILED; } GELOGI("Start to parse model: %s by custom proto: %s.", model_path, custom_proto.c_str()); Status ret = ParseNetModelByCustomProto(model_path, custom_proto_path, custom_proto_name, operators); if (ret != SUCCESS) { GELOGE(FAILED, "[Parse][NetModel]By CustomProto failed, path:%s.", model_path); } return ret; } Status CaffeModelParser::ReadModelWithoutWarning(const char *model_path, google::protobuf::Message *message) const { int32_t copy_fd = mmDup(STDERR_FILENO); if (copy_fd < 0) { char_t err_buf[kMaxErrStrLen + 1U] = {}; const auto err_msg = mmGetErrorFormatMessage(mmGetErrorCode(), &err_buf[0], kMaxErrStrLen); REPORT_CALL_ERROR("E19999", "Duplicate to file STDERR_FILENO failed, errmsg:%s", err_msg); GELOGE(FAILED, "[Invoke][Dup] failed:%d, reason:%s", copy_fd, err_msg); return FAILED; } int32_t fd = mmOpen(kDevNull, M_RDWR); if (fd < 0) { (void)mmClose(copy_fd); char_t err_buf[kMaxErrStrLen + 1U] = {}; const auto err_msg = mmGetErrorFormatMessage(mmGetErrorCode(), &err_buf[0], kMaxErrStrLen); ErrorManager::GetInstance().ATCReportErrMessage("E19001", {"file", "errmsg"}, {kDevNull, err_msg}); GELOGE(FAILED, "[Open][File] %s failed. reason:%s", kDevNull, err_msg); return FAILED; } if (mmDup2(fd, STDERR_FILENO) < 0) { (void)mmClose(fd); (void)mmClose(copy_fd); char_t err_buf[kMaxErrStrLen + 1U] = {}; const auto err_msg = mmGetErrorFormatMessage(mmGetErrorCode(), &err_buf[0], kMaxErrStrLen); REPORT_CALL_ERROR("E19999", "Duplicate to file STDERR_FILENO failed, errmsg:%s", err_msg); GELOGE(FAILED, "[Invoke][Dup2] Re-orient failed. reason:%s", err_msg); return FAILED; } if (ReadCaffeModelFromText(model_path, message) != SUCCESS) { (void)mmClose(fd); (void)mmClose(copy_fd); GELOGE(FAILED, "[Read][CaffeModel] From Text %s failed.", model_path); return FAILED; } if (mmDup2(copy_fd, STDERR_FILENO) < 0) { (void)mmClose(fd); (void)mmClose(copy_fd); char_t err_buf[kMaxErrStrLen + 1U] = {}; const auto err_msg = mmGetErrorFormatMessage(mmGetErrorCode(), &err_buf[0], kMaxErrStrLen); REPORT_CALL_ERROR("E19999", "Duplicate to file STDERR_FILENO failed, errmsg:%s", err_msg); GELOGE(FAILED, "[Invoke][Dup2] Re-orient failed. reason:%s", err_msg); return FAILED; } (void)mmClose(fd); (void)mmClose(copy_fd); return SUCCESS; } Status CaffeModelParser::ReadCaffeModelFromText(const char *model_path, google::protobuf::Message *message) const { GE_CHECK_NOTNULL(model_path); GE_CHECK_NOTNULL(message); GELOGI("Start to read model file: %s.", model_path); std::ifstream fs(model_path, std::ifstream::in); if (!fs.is_open()) { ErrorManager::GetInstance().ATCReportErrMessage("E19001", {"file", "errmsg"}, {model_path, "ifstream open failed"}); GELOGE(FAILED, "[Open][File] %s failed.", model_path); return FAILED; } google::protobuf::io::IstreamInputStream input(&fs); google::protobuf::TextFormat::Parser model_parser; model_parser.AllowUnknownField(true); if (!model_parser.Parse(&input, message)) { fs.close(); ErrorManager::GetInstance().ATCReportErrMessage("E19005", {"file"}, {model_path}); GELOGE(FAILED, "[Parse][ModelFile] %s failed.", model_path); return FAILED; } fs.close(); GELOGI("Read model file: %s success.", model_path); return SUCCESS; } Status CaffeModelParser::ParseLayerParameter(const google::protobuf::Descriptor &layer_descriptor, const google::protobuf::Message &message, vector &operators) const { auto field_name = layer_descriptor.FindFieldByName(kFieldName); CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(field_name, "Does not find name in google::protobuf::Descriptor"); auto field_type = layer_descriptor.FindFieldByName(kFieldType); CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(field_type, "Does not find type in google::protobuf::Descriptor"); const google::protobuf::Reflection *reflection = message.GetReflection(); CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(reflection, "Get Reflection failed in google::protobuf::Message"); vector field_desc; reflection->ListFields(message, &field_desc); for (auto &field : field_desc) { CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(field, "Get FieldDescriptor failed in google::protobuf::Message"); // Only care about layers if (field->name() != kLayerName) { continue; } if (!field->is_repeated()) { REPORT_INPUT_ERROR("E11032", std::vector({"message_type", "name", "reason"}), std::vector({"model", field->name(), "LayerParameter should be repeated"})); GELOGE(FAILED, "[Check][Param] LayerParameter should be repeated."); return FAILED; } int field_size = reflection->FieldSize(message, field); GELOGI("Total Layer num of model file is %d", field_size); for (int i = 0; i < field_size; ++i) { const google::protobuf::Message &layer_message = reflection->GetRepeatedMessage(message, field, i); const google::protobuf::Reflection *layer_reflection = layer_message.GetReflection(); CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(layer_reflection, "Get Reflection failed in google::protobuf::Message"); GE_CHECK_NOTNULL(layer_reflection); string op_name = layer_reflection->GetString(layer_message, field_name); string op_type = layer_reflection->GetString(layer_message, field_type); if (domi::OpRegistry::Instance()->GetParseParamByOperatorFunc(op_type) == nullptr) { continue; } if (CreateCustomOperator(op_name, op_type, &layer_message, i, operators) != SUCCESS) { GELOGE(FAILED, "[Create][CustomOperator] failed, name: %s, type: %s.", op_name.c_str(), op_type.c_str()); return FAILED; } } } return SUCCESS; } Status CaffeModelParser::CreateCustomOperator(string op_name, string op_type, const google::protobuf::Message *message, int index, vector &operators) const { if (op_name.empty() || op_type.empty()) { REPORT_INNER_ERROR("E19999", "[Check][Param]Name or type of layer is empty, name: %s, type: %s.", op_name.c_str(), op_type.c_str()); GELOGE(FAILED, "[Check][Param]Name or type of layer is empty, name: %s, type: %s.", op_name.c_str(), op_type.c_str()); return FAILED; } GELOGI("Start to create new operator, name: %s, type: %s, index: %d.", op_name.c_str(), op_type.c_str(), index); ge::Operator ops(op_name.c_str(), op_type.c_str()); if (ParserUtils::GetOperatorName(ops) != op_name) { REPORT_INNER_ERROR("E19999", "Create Operator failed, name: %s, type: %s, index: %d.", op_name.c_str(), op_type.c_str(), index); GELOGE(FAILED, "[Create][Operator] failed, name: %s, type: %s, index: %d.", op_name.c_str(), op_type.c_str(), index); return FAILED; } if (Message2Operator::ParseOperatorAttrs(message, 1, ops) != SUCCESS) { GELOGE(FAILED, "[Parse][OperatorAttrs] of %s failed.", op_name.c_str()); return FAILED; } operators.emplace_back(ops); GELOGI("Create new operator success, name: %s, type: %s, index: %d.", op_name.c_str(), op_type.c_str(), index); return SUCCESS; } void CaffeModelParser::AddOutputInfoToContext(string layer_name, int32_t top_index) const { auto iter_node_name = ge::GetParserContext().out_nodes_map.find(layer_name); if (iter_node_name != ge::GetParserContext().out_nodes_map.end()) { iter_node_name->second.emplace_back(top_index); } else { std::vector index_v; index_v.emplace_back(top_index); ge::GetParserContext().out_nodes_map.emplace(layer_name, index_v); } ge::GetParserContext().user_out_nodes.push_back(std::make_pair(layer_name, top_index)); } Status CaffeModelParser::ParseOutputNodeTopInfo(const domi::caffe::NetParameter &proto_message) const { if (ge::GetParserContext().user_out_tensors.empty()) { return SUCCESS; } ge::GetParserContext().out_nodes_map.clear(); ge::GetParserContext().user_out_nodes.clear(); int32_t layer_count = proto_message.layer_size(); const std::vector &user_out_tensors = ge::GetParserContext().user_out_tensors; for (const auto &top_name : user_out_tensors) { bool find_node_falg = false; string layer_name; int32_t top_index = 0; for (int32_t i = layer_count - 1; i >= 0; --i) { domi::caffe::LayerParameter &layer = const_cast(proto_message.layer(i)); for (int j = 0; j < layer.top_size(); ++j) { string top_blob_name = layer.top(j); if (top_blob_name != top_name) { continue; } find_node_falg = true; layer_name.assign(layer.name()); top_index = static_cast(j); break; } if (find_node_falg) { break; } } if (!find_node_falg || layer_name.empty()) { REPORT_INPUT_ERROR("E11017", std::vector({"opname"}), std::vector({top_name})); GELOGE(PARAM_INVALID, "[Check][Param]Cannot find top_name[%s], which is invalid", top_name.c_str()); return PARAM_INVALID; } GELOGD("Node[%s] find top_name[%s], top_index[%d]", layer_name.c_str(), top_name.c_str(), top_index); AddOutputInfoToContext(layer_name, top_index); } return SUCCESS; } Status CaffeModelParser::AddBlobsToMap(const domi::caffe::LayerParameter &layer, std::map &inplace_blob_name_remapping) { if (layer.top_size() <= 0) { ErrorManager::GetInstance().ATCReportErrMessage("E11037", {"opname"}, {layer.name()}); GELOGE(FAILED, "[Check][Size]The output size of layer %s needs to be greater than zero.", layer.name().c_str()); return FAILED; } // Need to check if the input is the output of 'inplace' for (int i = 0; i < layer.bottom_size(); ++i) { std::string blob_name = layer.bottom(i); auto iter = inplace_blob_name_remapping.find(blob_name); if (iter != inplace_blob_name_remapping.end()) { blob_name = iter->second; } bottom_blobs_map_[blob_name].emplace_back(std::make_pair(layer.name(), i)); } // Handling 'inplace' scenarios for (int j = 0; j < layer.top_size(); ++j) { std::string top_blob_name = layer.top(j); if (IsInplaceTopBlob(layer, top_blob_name)) { std::string remapped_blob_name = RemapTopNameByLayer(layer, top_blob_name, j); inplace_blob_name_remapping[top_blob_name] = remapped_blob_name; top_blob_name = remapped_blob_name; } top_blobs_map_[top_blob_name].emplace_back(std::make_pair(layer.name(), j)); } return SUCCESS; } bool CaffeModelParser::IsOpAttrEmpty(const ge::Operator &op, const std::string &type) const { std::map attrs; (void)op.GetAllAttrNamesAndTypes(attrs); if (type == kCustom) { for (const auto &attr : attrs) { if (kCustomProtoLayerCommonField.count(attr.first.GetString()) == 0) { GELOGI("Custom op[%s] attr name[%s] exists, not empty.", ParserUtils::GetOperatorName(op).c_str(), attr.first.GetString()); return false; } } } else if (type == kBuiltin) { for (const auto &attr : attrs) { if (kCaffeProtoLayerCommonField.count(attr.first.GetString()) == 0) { GELOGI("Built-in op[%s] attr name[%s] exists, not empty.", ParserUtils::GetOperatorName(op).c_str(), attr.first.GetString()); return false; } } } return true; } Status CaffeModelParser::GetCustomOp(const domi::caffe::LayerParameter &layer, vector &operators) { string op_type = layer.type(); string op_name = layer.name(); bool is_search_built_in_layer = false; for (ge::Operator &custom_op : custom_operator_) { if (ParserUtils::GetOperatorName(custom_op) == layer.name() && ParserUtils::GetOperatorType(custom_op) == op_type) { if (IsOpAttrEmpty(custom_op, kCustom)) { GELOGW("Custom op attr is empty, should try to get op params from built-in layer."); is_search_built_in_layer = true; } else { operators.emplace_back(custom_op); GELOGI("Find custom op success."); return SUCCESS; } break; } } if (custom_operator_.empty()) { GELOGW("Custom operator is empty, should try to get op params from built-in layer."); is_search_built_in_layer = true; } if (is_search_built_in_layer) { const google::protobuf::Message *layer_message = PtrToPtr(&layer); Status status = CreateCustomOperator(op_name, op_type, layer_message, 0, operators); if (status != SUCCESS || operators.empty()) { GELOGE(status, "[Create][CustomOperator] failed, name: %s, type: %s.", op_name.c_str(), op_type.c_str()); return FAILED; } if (IsOpAttrEmpty(operators[0], kBuiltin)) { GELOGW("Custom and built-in op attr param is empty, name: %s, type: %s.", op_name.c_str(), op_type.c_str()); } GELOGI("Search built-in layer success."); } return SUCCESS; } Status CaffeModelParser::ParseOpParam(const domi::caffe::LayerParameter &layer, ge::OpDescPtr &op, std::shared_ptr &op_parser) { GE_CHECK_NOTNULL(op); GE_CHECK_NOTNULL(op_parser); string op_type = layer.type(); Status status = FAILED; ParseParamByOpFunc parse_param_func = domi::OpRegistry::Instance()->GetParseParamByOperatorFunc(op_type); if (parse_param_func == nullptr) { // Parsing weight information through opparser status = op_parser->ParseParams(&layer, op); } else { // The custom op defined by customer deals with parse params separately std::shared_ptr caffe_custom_op_parser = std::dynamic_pointer_cast(op_parser); vector custom_operator; status = GetCustomOp(layer, custom_operator); if (status != SUCCESS || custom_operator.empty()) { REPORT_CALL_ERROR("E19999", "Get CustomOp failed for op:%s(%s)", layer.name().c_str(), op_type.c_str()); GELOGE(status, "[Get][CustomOp]failed for op [%s], optype [%s]", layer.name().c_str(), op_type.c_str()); return status; } status = caffe_custom_op_parser->ParseParams(custom_operator[0], op); } if (status != SUCCESS) { REPORT_CALL_ERROR("E19999", "Parse param for op:%s(%s) failed", layer.name().c_str(), op_type.c_str()); GELOGE(status, "[Parse][Params] for op [%s] fail, optype [%s]", layer.name().c_str(), op_type.c_str()); return status; } return SUCCESS; } Status CaffeModelParser::AddNode(const domi::caffe::LayerParameter &layer, ge::ComputeGraphPtr &graph) { GE_CHECK_NOTNULL(graph); // Release in node destructor string op_type; op_type = layer.type(); // User defined duplicate name operator processing auto m_iter = ge::GetParserContext().op_conf_map.find(op_type); // User specified configuration item found if (m_iter != ge::GetParserContext().op_conf_map.end()) { op_type = m_iter->second; } // General layer layer, search optype auto iter = caffe_op_map.find(op_type); if (iter == caffe_op_map.end()) { if (op_type == kDetectionOutput) { ErrorManager::GetInstance().ATCReportErrMessage("E11008"); GELOGE(FAILED, "[Check][Type] Op type 'DetectionOutput' is confused. Suggest you modify the model file " "and use a explicit type, such as 'FSRDetectionOutput' or 'SSDDetectionOutput'."); } else { ErrorManager::GetInstance().ATCReportErrMessage("E11009", {"opname", "optype"}, {layer.name(), op_type}); GELOGE(FAILED, "[Check][Type]Unsupport op[%s] optype[%s], you should customize the op at first.", layer.name().c_str(), op_type.c_str()); } return FAILED; } op_type = iter->second; GELOGD("Caffe layer name:%s, layer type %s", layer.name().c_str(), op_type.c_str()); // create OpParser std::shared_ptr factory = OpParserFactory::Instance(domi::CAFFE); GE_CHECK_NOTNULL(factory); std::shared_ptr op_parser = factory->CreateOpParser(op_type); if (op_parser == nullptr) { ErrorManager::GetInstance().ATCReportErrMessage("E11009", {"opname", "optype"}, {layer.name(), op_type}); GELOGE(FAILED, "op_parser is null, op_type: %s.", op_type.c_str()); return FAILED; } ge::OpDescPtr op; // Process change of tensordesc initialization of opdesc, // The previous process tensordesc was constructed according to the graph structure in the builder stage // The current process requires tensordesc to determine before the opdesc of the operator is added to the graph GE_RETURN_IF_ERROR(AddTensorDescToOpDescByIr(op, layer, op_type)); GELOGI("After AddTensorDescToOpDescByIr op[%s] type[%s] have input size: %zu, output size: %zu", op->GetName().c_str(), op->GetType().c_str(), op->GetInputsSize(), op->GetOutputsSize()); // op parser execute GE_RETURN_IF_ERROR(ParseOpParam(layer, op, op_parser)); GELOGI("After op parser op[%s] type[%s] have input size: %zu, output size: %zu", op->GetName().c_str(), op->GetType().c_str(), op->GetInputsSize(), op->GetOutputsSize()); // Caffe has also been plug-in at present. Here it is directly set to NCHW // Set input and output format GELOGI("Enter caffe parser. op name:%s, type:%s", op->GetName().c_str(), op->GetType().c_str()); // inputDescsPtr and outputDescsPtr are guaranteed not to be nullptr auto inputDescsPtr = op->GetAllInputsDescPtr(); auto outputDescsPtr = op->GetAllOutputsDescPtr(); ge::Format format = ge::FORMAT_NCHW; for (auto &inputDescPtr : inputDescsPtr) { GE_CHECK_NOTNULL(inputDescPtr); inputDescPtr->SetFormat(format); inputDescPtr->SetOriginFormat(format); } for (auto &outputDescPtr : outputDescsPtr) { GE_CHECK_NOTNULL(outputDescPtr); outputDescPtr->SetFormat(format); outputDescPtr->SetOriginFormat(format); } ge::NodePtr node = graph->AddNode(op); if (node == nullptr) { REPORT_INNER_ERROR("E19999", "AddNode failed, op name:%s, type:%s", op->GetName().c_str(), op->GetType().c_str()); GELOGE(FAILED, "[Add][Node] failed, op name:%s, type:%s", op->GetName().c_str(), op->GetType().c_str()); return FAILED; } // Caffe's reshape is different from IR definition, which has only one input. // In caffe process, after constructing reshape according to IR, the second input of reshape is empty. // So a constant node needs to be added to reshape as the second input. // AddConstInput is a function defined in caffe_op_parser, override in caffe_reshape_parser. std::shared_ptr caffe_op_parser = std::static_pointer_cast(op_parser); GE_CHECK_NOTNULL(caffe_op_parser); Status status = caffe_op_parser->AddConstInput(node); if (status != SUCCESS) { REPORT_CALL_ERROR("E19999", "AddConstInput failed for node:%s", node->GetOpDesc()->GetName().c_str()); GELOGE(FAILED, "[Add][ConstInput] to node %s fail.", node->GetOpDesc()->GetName().c_str()); return status; } node_map[layer.name()] = node; return SUCCESS; } Status CaffeModelParser::AddTensorDescToOpDesc(ge::OpDescPtr &op_desc, const domi::caffe::LayerParameter &layer) const { GE_CHECK_NOTNULL(op_desc); // Data node input and output tensordesc added in parserparam if (op_desc->GetType() == ge::parser::DATA) { return SUCCESS; } for (int i = 0; i < layer.bottom_size(); i++) { ge::GeTensorDesc input_tensor; GE_RETURN_IF_ERROR(op_desc->AddInputDesc(input_tensor)); } GELOGD("AddTensorInputDescToOpDesc, op name: %s, type: %s, input num: %d", op_desc->GetName().c_str(), op_desc->GetType().c_str(), layer.bottom_size()); // Output number int32_t output_tensor_num = layer.top_size(); GELOGD("AddTensorOutputDescToOpDesc, op name: %s, type: %s, output num: %d", op_desc->GetName().c_str(), op_desc->GetType().c_str(), output_tensor_num); for (int32_t j = 0; j < output_tensor_num; j++) { ge::GeTensorDesc output_tensor; GE_RETURN_IF_ERROR(op_desc->AddOutputDesc(output_tensor)); } // yolo v2 YoloDetectionOutput if (op_desc->GetType() == ge::parser::YOLODETECTIONOUTPUT) { ge::GeTensorDesc input_tensor; GE_RETURN_IF_ERROR(op_desc->AddInputDesc(input_tensor)); GE_RETURN_IF_ERROR(op_desc->AddInputDesc(input_tensor)); GELOGD( "Current op type is YOLODETECTIONOUTPUT, add 2 additional inputs" "while it's original input num is: %d", layer.bottom_size()); } return SUCCESS; } Status CaffeModelParser::AddTensorDescToOpDescByIr(ge::OpDescPtr &op_desc, const domi::caffe::LayerParameter &layer, const string &op_type) const { if (std::find(kAddTensorIrSkipNodes.begin(), kAddTensorIrSkipNodes.end(), op_type) != kAddTensorIrSkipNodes.end()) { op_desc = ge::parser::MakeShared(layer.name(), op_type); GE_CHECK_NOTNULL(op_desc); Status ret = AddTensorDescToOpDesc(op_desc, layer); if (ret != SUCCESS) { GELOGE(FAILED, "[Add][TensorDesc]To OpDesc failed for op[%s] type[%s].", layer.name().c_str(), op_type.c_str()); } return ret; } // Get opDesc by ir string layer_name = layer.name(); ge::Operator op_factory = ge::OperatorFactory::CreateOperator(layer_name.c_str(), op_type.c_str()); if (ParserUtils::GetOperatorName(op_factory) != layer.name()) { ErrorManager::GetInstance().ATCReportErrMessage("E10501", {"opname", "optype"}, {layer_name, op_type}); GELOGE(FAILED, "[Invoke][CreateOperator]IR for op[%s] optype[%s] is not registered.", layer_name.c_str(), op_type.c_str()); return FAILED; } else { op_desc = ge::OpDescUtils::GetOpDescFromOperator(op_factory); GE_CHECK_NOTNULL(op_desc); auto valid_input_size = layer.bottom_size(); auto blob_size = layer.blobs_size(); GELOGI("After GetOpDescFromOperator op[%s] type[%s] have all input size: %zu, " "caffe_input_size:%d blob_size %d output size: %zu", op_desc->GetName().c_str(), op_desc->GetType().c_str(), op_desc->GetAllInputsSize(), valid_input_size, blob_size, op_desc->GetOutputsSize()); bool update_in_turn = (static_cast(op_desc->GetAllInputsSize()) == (valid_input_size + blob_size)); for (int i = 0; i < valid_input_size; i++) { ge::GeTensorDesc input_tensor; std::string input_name; ge::graphStatus ret = ge::GRAPH_SUCCESS; // Below cases are supported fow now when there are optional inputs // x means optional, o means requierd input // a. ooxxx, number of o and x>=layer.bottom_size+layer.blobs_size>=number of o // b. oxoxoxox, layer.bottom_size+layer.blobs_size=number of o // c. oxoxoxox, layer.bottom_size+layer.blobs_size=number of o and x if (update_in_turn) { ret = op_desc->UpdateInputDesc(op_desc->GetInputNameByIndex(static_cast(i)), input_tensor); } else { if (static_cast(i) >= op_desc->GetInputsSize()) { ret = op_desc->UpdateInputDesc(static_cast(i), input_tensor); } else { input_name = op_desc->GetValidInputNameByIndex(static_cast(i)); ret = op_desc->UpdateInputDesc(input_name, input_tensor); } } GELOGI("op [%s], type[%s], update input(%d) with name %s %s", op_desc->GetName().c_str(), op_desc->GetType().c_str(), i, input_name.c_str(), ret == ge::GRAPH_SUCCESS ? "success" : "not success"); } for (int i = 0; i < layer.top_size(); i++) { ge::GeTensorDesc output_tensor; auto ret = op_desc->UpdateOutputDesc(op_desc->GetOutputNameByIndex(static_cast(i)), output_tensor); GELOGI("op [%s], type[%s], update output(%d) with name %s %s", op_desc->GetName().c_str(), op_desc->GetType().c_str(), i, op_desc->GetOutputNameByIndex(i).c_str(), ret == ge::GRAPH_SUCCESS ? "success" : "not success"); } } return SUCCESS; } Status CaffeModelParser::AddEdges(ge::ComputeGraphPtr &graph) { GE_CHECK_NOTNULL(graph); // Traversal input for (auto b_iter = bottom_blobs_map_.begin(); b_iter != bottom_blobs_map_.end(); b_iter++) { // Find the top blob corresponding to the bottom blob auto t_iter = top_blobs_map_.find(b_iter->first); // Unable to find the output corresponding to the input, error reported if (t_iter == top_blobs_map_.end()) { ErrorManager::GetInstance().ATCReportErrMessage("E11012", {"bottom_blob", "layer", "bottom_index"}, {b_iter->first, b_iter->second[0].first, std::to_string(b_iter->second[0].second)}); GELOGE(FAILED, "[Find][Blob]Unknown bottom blob '%s', in layer '%s', bottom index:%d.", b_iter->first.c_str(), b_iter->second[0].first.c_str(), b_iter->second[0].second); return PARAM_INVALID; } vector> &top_blob_layers = t_iter->second; vector> &bottom_blob_layers = b_iter->second; // 1.Traversal output, all input layers of the current blob for (auto &top_blob_layer_pair : top_blob_layers) { // 2.Traversal input, all output layers of the current blob for (auto &bottom_blob_layer_pair : bottom_blob_layers) { // Find the layer for this output auto top_node_iter = node_map.find(top_blob_layer_pair.first); // Find the layer for this input std::map::const_iterator bottom_node_iter = node_map.find(bottom_blob_layer_pair.first); if (top_node_iter != node_map.end() && bottom_node_iter != node_map.end()) { // Output node top_node_iter->second, // Output index top_blob_layer_pair.second // input node bottom_node_iter->second // input index bottom_blob_layer_pair.second GELOGD("Start add edge: From %s:%d To %s:%d.", top_node_iter->second->GetName().c_str(), top_blob_layer_pair.second, bottom_node_iter->second->GetName().c_str(), bottom_blob_layer_pair.second); ge::OutDataAnchorPtr out_archor_ptr = top_node_iter->second->GetOutDataAnchor(top_blob_layer_pair.second); GE_CHECK_NOTNULL(out_archor_ptr); ge::InDataAnchorPtr in_archor_ptr = bottom_node_iter->second->GetInDataAnchor(bottom_blob_layer_pair.second); GE_CHECK_NOTNULL(in_archor_ptr); GE_IF_BOOL_EXEC(ge::GraphUtils::AddEdge(out_archor_ptr, in_archor_ptr) != ge::GRAPH_SUCCESS, REPORT_CALL_ERROR("E19999", "Add edge between %s and %s failed", top_node_iter->second->GetName().c_str(), bottom_node_iter->second->GetName().c_str()); GELOGE(INTERNAL_ERROR, "[Invoke][AddEdge]Add link failed from op[%s] to op[%s].", top_node_iter->second->GetName().c_str(), bottom_node_iter->second->GetName().c_str()); return INTERNAL_ERROR;); auto op_desc = bottom_node_iter->second->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); auto out_op_desc = top_node_iter->second->GetOpDesc(); GE_CHECK_NOTNULL(out_op_desc); (void) op_desc->UpdateInputDesc((static_cast(in_archor_ptr->GetIdx())), out_op_desc->GetOutputDesc(static_cast(out_archor_ptr->GetIdx()))); } GE_IF_BOOL_EXEC(top_node_iter == node_map.end(), ErrorManager::GetInstance().ATCReportErrMessage("E11014", {"opname"}, {top_blob_layer_pair.first}); GELOGE(INTERNAL_ERROR, "[Find][TopLayer] %s failed.", top_blob_layer_pair.first.c_str()); return ge::FAILED;) GE_IF_BOOL_EXEC(bottom_node_iter == node_map.end(), ErrorManager::GetInstance().ATCReportErrMessage("E11015", {"opname"}, {bottom_blob_layer_pair.first}); GELOGE(INTERNAL_ERROR, "[Find][BottomLayer] %s failed.", bottom_blob_layer_pair.first.c_str()); return ge::FAILED;) } } } return SUCCESS; } bool CaffeModelParser::IsOutputTop(const string &op_name, const int32_t index) const { bool ret = false; auto iter = ge::GetParserContext().out_nodes_map.find(op_name); if (iter != ge::GetParserContext().out_nodes_map.end()) { std::vector tmp_index_v; for (int32_t id : iter->second) { if (index == id) { ret = true; } else { tmp_index_v.emplace_back(id); } } // To prevent specifying network output again in the build phase, need to delete the output node in the map list. if (ret) { ge::GetParserContext().out_nodes_map.erase(op_name); ge::GetParserContext().out_nodes_map.emplace(op_name, tmp_index_v); } } return ret; } Status CaffeModelParser::AddUserOutNodesTop() { int32_t index = 0; const std::vector> &user_out_nodes = ge::GetParserContext().user_out_nodes; int net_output_num = user_out_nodes.size(); for (const auto &out_pair : user_out_nodes) { std::map>::const_iterator layer_iter = layer_tops_map_.find(out_pair.first); GELOGI("Add to output, node name: %s", out_pair.first.c_str()); if (layer_iter != layer_tops_map_.end()) { if (static_cast(out_pair.second) >= (layer_iter->second).size()) { ErrorManager::GetInstance().ATCReportErrMessage( "E11016", {"opname", "outputindex", "totlaloutputindex", "inputindex", "totlalinputindex"}, {out_pair.first.c_str(), std::to_string(out_pair.second), std::to_string((layer_iter->second).size()), std::to_string(index), std::to_string(net_output_num)}); GELOGE(INTERNAL_ERROR, "[Check][Size]Add op %s to NetOutput faild, current node output index:%d should < %zu. " "NetOutput input_index:%d should < %u.", out_pair.first.c_str(), out_pair.second, (layer_iter->second).size(), index, net_output_num); return INTERNAL_ERROR; } string top_name = layer_iter->second[out_pair.second]; std::map::const_iterator top_node_iter = node_map.find(out_pair.first); if (top_node_iter != node_map.end()) { ge::GetParserContext().out_tensor_names.push_back(top_name); GELOGI("The top of out node [%s] is [%s]", out_pair.first.c_str(), top_name.c_str()); } ++index; } else { ErrorManager::GetInstance().ATCReportErrMessage("E11017", {"opname"}, {out_pair.first}); GELOGE(PARAM_INVALID, "[Find][Node]Can not find out_node:%s, you should check --out_nodes.", out_pair.first.c_str()); return PARAM_INVALID; } } return SUCCESS; } Status CaffeModelParser::AddOutputTop(const domi::caffe::NetParameter &proto_message) { for (int32_t layer_index = 0; layer_index < proto_message.layer_size(); ++layer_index) { const domi::caffe::LayerParameter &layer = proto_message.layer(layer_index); if (!CheckValidLayer(layer)) { continue; } for (int32_t i = 0; i < layer.top_size(); i++) { string top = layer.top(i); string top_origin = top; // Handling 'inplace' scenarios if (IsInplaceTopBlob(layer, top)) { top = RemapTopNameByLayer(layer, top, i); } std::map>>::const_iterator t_iter = top_blobs_map_.find(top); GE_RETURN_WITH_LOG_IF_FALSE(t_iter != top_blobs_map_.end(), "[Check][Param]Failed to find top: %s, layer name:%s", top.c_str(), layer.name().c_str()); // Find the bottom blob corresponding to the top blob auto b_iter = bottom_blobs_map_.find(t_iter->first); if (b_iter != bottom_blobs_map_.end() && !IsOutputTop(layer.name(), i)) { continue; } // If not found, add to the output side of the output // Find the layer for this output std::map::const_iterator top_node_iter = node_map.find(layer.name()); GELOGI("output in top_blob: %s", layer.name().c_str()); if (top_node_iter != node_map.end()) { ge::GetParserContext().out_tensor_names.push_back(top_origin); ge::GetParserContext().default_out_nodes.push_back(std::make_pair(layer.name(), i)); GELOGI("The top of out node [%s] is [%s]", layer.name().c_str(), top_origin.c_str()); } } } return SUCCESS; } bool CaffeModelParser::CheckValidLayer(const domi::caffe::LayerParameter &layer) const { if (layer.include_size() != 0) { bool filter_flag = false; for (int32_t j = 0; j < layer.include_size(); j++) { // Determine whether there is a data node for train in a Caffe model if (layer.include(j).phase() == domi::caffe::TRAIN) { filter_flag = true; break; } } if (filter_flag) { // If the phase of the data node's include is train, the data node ignores return false; } } return true; } bool CaffeModelParser::IsInplaceTopBlob(const domi::caffe::LayerParameter &layer, const std::string &top_name) const { for (auto &bottom_name : layer.bottom()) { if (top_name == bottom_name) { return true; } } return false; } std::string CaffeModelParser::RemapTopNameByLayer(const domi::caffe::LayerParameter &layer, const std::string &top_name, int index) const { return (top_name + "_" + layer.name() + "_" + std::to_string(index)); } Status CaffeModelParser::PreCheck(const domi::caffe::NetParameter &net) const { // Add layer in the model to PreChecker and check the general parameters PreChecker::Instance().SetModelName(net.name()); for (int i = 0; i < net.layer_size(); i++) { const LayerParameter &layer = net.layer(i); // Skip training related layers and python layers if (!CheckValidLayer(layer) || layer.type() == kPython) { continue; } // validate opname string mode = "^[A-Za-z0-9./_-]+$"; if (!ge::parser::ValidateStr(layer.name(), mode)) { ErrorManager::GetInstance().ATCReportErrMessage("E11018", {"opname"}, {layer.name()}); GELOGE(ge::FAILED, "[Invoke][ValidateStr]Parse caffe pbtxt validate op[%s] failed, opname can only contain " "'a-z' 'A-Z' '0-9' '-' '.' '_' '/'", layer.name().c_str()); return ge::FAILED; } GE_RETURN_WITH_LOG_IF_ERROR(PreChecker::Instance().AddOp(&layer, layer.name(), layer.type()), "[Invoke][AddOp]Add layer to PreChecker failed, layer name: %s.", layer.name().c_str()); if (PreChecker::Instance().CheckName(&layer) != SUCCESS) { GELOGE(FAILED, "[Invoke][CheckName]Check op[%s] failed, name repeat in caffe prototxt.", layer.name().c_str()); return FAILED; } if (PreChecker::Instance().CheckType(&layer) != SUCCESS) { GELOGE(FAILED, "[Invoke][CheckType]Check op[%s]'s optype failed, type is not supported.", layer.name().c_str()); return FAILED; } } return SUCCESS; } Status CaffeModelParser::ParseFromMemory(const char *data, uint32_t size, ge::ComputeGraphPtr &graph) { ErrorManager::GetInstance().SetStage(error_message::kModelCompile, error_message::kParser); bool has_error = false; GE_CHK_BOOL_RET_STATUS(data != nullptr, FAILED, "[Check][Param]model data is nullptr."); GE_CHK_BOOL_RET_STATUS(graph != nullptr, FAILED, "[Check][Param]graph is nullptr."); domi::caffe::NetParameter proto_message; // Get Caffe network model information if (!ge::parser::ReadProtoFromMem(data, static_cast(size), &proto_message)) { GELOGE(FAILED, "[Read][ProtoFromMem] ret fail"); return FAILED; } GE_CHK_BOOL_RET_STATUS(!(proto_message.layer_size() == 0 && proto_message.layers_size() > 0), FAILED, "[Check][Size]The model file is consisted of layers-structure which is deprecated in caffe and unsupport in OMG." "It is recommended to convert layers-structure to layer-structure by caffe tool."); GE_CHK_BOOL_RET_STATUS((proto_message.layer_size() != 0), FAILED, "[Check][Size]net layer num is zero, prototxt file may be invalid."); GE_RETURN_WITH_LOG_IF_ERROR(ProtoTypePassManager::Instance().Run(&proto_message, domi::CAFFE), "Run ProtoType Pass Failed"); // Set network name GE_IF_BOOL_EXEC((proto_message.has_name()), graph->SetName(proto_message.name())); // Add layer in the model to PreChecker, and perform general checks GE_RETURN_IF_ERROR(PreCheck(proto_message)); has_error = PreChecker::Instance().HasError(); if (ReorderInput(proto_message) != SUCCESS) { GELOGE(INTERNAL_ERROR, "[Reorder][Input] failed."); return INTERNAL_ERROR; } bool input_data_flag = false; // Process input of type input CHECK_FALSE_EXEC(ParseInput(proto_message, input_data_flag) == SUCCESS, has_error = true; GELOGE(FAILED, "[Parse][Input] ret fail.")); int32_t layer_count = proto_message.layer_size(); std::map inplace_blob_name_remapping; // Map of operator name and occurrence times std::map layer_name_map; // std::map> layer_params_map; // same param name set // std::map, std::vector> params_share_map; for (int32_t layer_index = 0; layer_index < layer_count; ++layer_index) { domi::caffe::LayerParameter &layer = const_cast(proto_message.layer(layer_index)); if (!CheckValidLayer(layer)) { GELOGI("[Check][Layer]layer phase is train, skip this layer, name:%s, type:%s.", layer.name().c_str(), layer.type().c_str()); continue; } CHECK_FALSE_EXEC(!((layer.type() == ge::parser::DATA_TYPE) && input_data_flag), has_error = true; REPORT_INNER_ERROR("E19999", "net %s has input and data layer simultaneously, check invalid." "layer name:%s, layer type:%s", proto_message.name().c_str(), layer.name().c_str(), layer.type().c_str()); GELOGE(FAILED, "[Check][Layer]net %s has input and data layer simultaneously, check invalid." "layer name:%s, layer type:%s", proto_message.name().c_str(), layer.name().c_str(), layer.type().c_str())); // All layer names cannot be duplicate // 20181208 Modified to support the existence of duplicate operators in Caffe model GE_IF_BOOL_EXEC(layer_name_map.find(layer.name()) != layer_name_map.end(), // duplicate operator modification string new_name = layer.name() + "_same_" + std::to_string(layer_name_map[layer.name()]); // Times accumulation of duplicate operators layer_name_map[layer.name()]++; // Set the name in proto and layer domi::caffe::LayerParameter *duplicate_name_layer = proto_message.mutable_layer(layer_index); duplicate_name_layer->set_name(new_name); layer.set_name(new_name);) // Insert the new operator name, the number of times of duplicate name is recorded as 1 layer_name_map.insert(std::make_pair(layer.name(), kNumOne)); // Do not exit immediately when there is an error, wait until all errors are collected before exiting Status ret = AddNode(layer, graph); if (ret != SUCCESS) { GELOGE(FAILED, "[Add][Node]failed for layer:%s.", layer.name().c_str()); has_error = true; continue; } // parse ParamSpec std::vector v_param_names; for (int32_t i = 0; i < layer.param_size(); i++) { const domi::caffe::ParamSpec ¶m = layer.param(i); GE_IF_BOOL_EXEC((param.has_name()), v_param_names.emplace_back(param.name())); } // Save the layer with param name parameter to map GE_IF_BOOL_EXEC((v_param_names.size() > 0), layer_params_map.emplace(layer.name(), v_param_names)); GE_RETURN_WITH_LOG_IF_ERROR(AddBlobsToMap(layer, inplace_blob_name_remapping), "[Add][Blobs]To Map ret fail, layer:%s.", layer.name().c_str()); } // Find a layer with the same param name and save it to graph GE_RETURN_WITH_LOG_IF_ERROR(FindShareParamLayers(layer_params_map), "[Find][ShareParamLayers] by Caffe parser ret fail."); // Exit if an error occurs GE_IF_BOOL_EXEC(has_error, return FAILED); GE_CHK_BOOL_RET_STATUS(top_blobs_map_.size() > 0, FAILED, "[Check][Size]current net has no output!"); GE_RETURN_WITH_LOG_IF_ERROR(AddEdges(graph), "[Add][Edges] failed by Caffe parser, graph:%s.", graph->GetName().c_str()); if (!(ge::GetParserContext().user_out_nodes.empty())) { GE_RETURN_WITH_LOG_IF_ERROR(AddUserOutNodesTop(), "[Add][UserOutNodesTop] by Caffe parser failed."); } else { GE_RETURN_WITH_LOG_IF_ERROR(AddOutputTop(proto_message), "[Add][OutputTop] by Caffe parser failed."); } GE_RETURN_WITH_LOG_IF_ERROR(graph->TopologicalSorting(), "[Call][TopologicalSorting] by Caffe parser failed, graph:%s.", graph->GetName().c_str()); auto nodes = graph->GetDirectNode(); GELOGI("graph node size = %zu.", nodes.size()); for (auto &node : nodes) { GELOGI("node name = %s.", node->GetName().c_str()); for (auto &out_node : node->GetOutDataNodes()) { GELOGI("out node name = %s.", out_node->GetName().c_str()); } } return SUCCESS; } Status CaffeModelParser::Parse(const char *model_path, ge::Graph &graph) { ErrorManager::GetInstance().SetStage(error_message::kModelCompile, error_message::kParser); GE_CHECK_NOTNULL(model_path); ge::ComputeGraphPtr compute_graph = ge::GraphUtils::GetComputeGraph(graph); GE_CHECK_NOTNULL(compute_graph); Status ret = Parse(model_path, compute_graph); if (ret != SUCCESS) { GELOGE(ret, "[Parser][Model] %s for graph %s failed.", model_path, ParserUtils::GetGraphName(graph).c_str()); return ret; } GELOGI("Parser model for graph %s success.", ParserUtils::GetGraphName(graph).c_str()); return SUCCESS; } void CaffeModelParser::SaveOrigionLayerTops(domi::caffe::LayerParameter &layer) { string name = layer.name(); vector tops; for (auto top : layer.top()) { tops.push_back(top); } std::map>::const_iterator it = layer_tops_map_.find(name); if (it == layer_tops_map_.end()) { layer_tops_map_[name] = tops; } return; } Status CaffeModelParser::SaveDataLayerTops(const domi::caffe::LayerParameter &layer) { string name = layer.name(); if (node_map.find(name) == node_map.end()) { REPORT_INNER_ERROR("E19999", "layer:%s not find in node_map after AddNode, exist error before", name.c_str()); GELOGE(FAILED, "[Find][Node]Node can not be found by layer name: %s", name.c_str()); return FAILED; } ge::NodePtr node = node_map[name]; GE_CHECK_NOTNULL(node); if (node->GetType() == ge::parser::DATA) { if (layer.top_size() != 1) { ErrorManager::GetInstance().ATCReportErrMessage("E11035", {"opname", "size"}, {name, std::to_string(layer.top_size())}); GELOGE(FAILED, "[Check][Type]Data layer[%s] top size must be 1, real size: %d", name.c_str(), layer.top_size()); return FAILED; } string top_name = layer.top(0); auto data_tensor_names = ge::GetParserContext().data_tensor_names; if (find(data_tensor_names.begin(), data_tensor_names.end(), top_name) != data_tensor_names.end()) { ErrorManager::GetInstance().ATCReportErrMessage("E11036", {"topname"}, {top_name}); GELOGE(FAILED, "[Check][Node]Different data node can not have same top name: %s.", top_name.c_str()); return FAILED; } ge::GetParserContext().data_tensor_names.push_back(top_name); } return SUCCESS; } Status CaffeModelParser::ReportLayerInvalid(const domi::caffe::NetParameter &proto, const std::string &path) const { if (proto.layers_size() > 0) { ErrorManager::GetInstance().ATCReportErrMessage("E11021", {"realpath"}, {path}); GELOGE(FAILED, "[Check][Size]The model file[%s] is consisted of layers-structure which is deprecated in Caffe " "and unsupported in ATC. The \"layers\" should be changed to \"layer\".", path.c_str()); } else { ErrorManager::GetInstance().ATCReportErrMessage("E11022"); GELOGE(FAILED, "[Check][Size]net layer num is zero, prototxt file may be invalid."); } return FAILED; } Status CaffeModelParser::Parse(const char *model_path, ge::ComputeGraphPtr &graph) { bool has_error = false; GE_CHECK_NOTNULL(model_path); GE_CHECK_NOTNULL(graph); GELOGI("Caffe Parse model file [%s]", model_path); PreChecker::Instance().Clear(); domi::caffe::NetParameter proto_message; // Get Caffe network model information if (ReadModelWithoutWarning(model_path, &proto_message) != SUCCESS) { GELOGE(FAILED, "[Read][Model] from text ret fail, model path: %s.", model_path); return FAILED; } // parse network model by custom proto and get custom operators string custom_proto_path = ge::GetParserContext().custom_proto_path + "custom.proto"; string caffe_proto_path = ge::GetParserContext().caffe_proto_path + "caffe.proto"; GE_CHK_STATUS(CustomProtoParse(model_path, custom_proto_path, caffe_proto_path, custom_operator_), "[Parse][Model] by custom proto failed, model path: %s.", model_path); if (proto_message.layer_size() == 0) { return ReportLayerInvalid(proto_message, model_path); } GE_RETURN_WITH_LOG_IF_ERROR(ProtoTypePassManager::Instance().Run(&proto_message, domi::CAFFE), "Run ProtoType Pass Failed"); // Set network name GE_IF_BOOL_EXEC((proto_message.has_name() && !proto_message.name().empty()), graph->SetName(proto_message.name())); // Add layer in the model to PreChecker, and perform general checks GE_RETURN_IF_ERROR(PreCheck(proto_message)); if (PreChecker::Instance().HasError()) { REPORT_INNER_ERROR("E19999", "Precheck failed. a report of json format will be create, Please read it."); GELOGE(INTERNAL_ERROR, "[Has][Error]Precheck failed. a report of json format will be create, Please read it."); return FAILED; } if (ReorderInput(proto_message) != SUCCESS) { GELOGE(INTERNAL_ERROR, "[Reorder][Input] failed."); return INTERNAL_ERROR; } bool input_data_flag = false; // Process input of type input CHECK_FALSE_EXEC(ParseInput(proto_message, input_data_flag) == SUCCESS, has_error = true; GELOGE(FAILED, "[Parse][Input] ret fail.")); int32_t layer_count = proto_message.layer_size(); if (!ge::GetParserContext().user_out_tensors.empty()) { GELOGW("The out_put info has top_name items."); GE_RETURN_WITH_LOG_IF_ERROR(ParseOutputNodeTopInfo(proto_message), "[Parse][OutputNodeTopInfo] failed."); ge::GetParserContext().user_out_tensors.clear(); } std::map inplace_blob_name_remapping; // Map of operator name and occurrence times std::map layer_name_map; GetParserContext().data_tensor_names.clear(); // std::map> layer_params_map; // same param name set for (int32_t layer_index = 0; layer_index < layer_count; ++layer_index) { domi::caffe::LayerParameter &layer = const_cast(proto_message.layer(layer_index)); SaveOrigionLayerTops(layer); if (!CheckValidLayer(layer)) { GELOGI("[Check][Layer]layer phase is train, skip this layer, name:%s, type:%s.", layer.name().c_str(), layer.type().c_str()); continue; } CHECK_FALSE_EXEC(!((layer.type() == ge::parser::DATA_TYPE) && input_data_flag), has_error = true; GELOGE(FAILED, "[Check][Layer]net %s has input and data layer simultaneously, check invalid." "layer name:%s, layer type:%s", proto_message.name().c_str(), layer.name().c_str(), layer.type().c_str())); // All layer names cannot be duplicate // Modified to support the existence of duplicate operators in Caffe model GE_IF_BOOL_EXEC(layer_name_map.find(layer.name()) != layer_name_map.end(), // duplicate operator modification string new_name = layer.name() + "_same_" + std::to_string(layer_name_map[layer.name()]); // Times accumulation of duplicate operators layer_name_map[layer.name()]++; // Set the name in proto and layer domi::caffe::LayerParameter *duplicate_name_layer = proto_message.mutable_layer(layer_index); duplicate_name_layer->set_name(new_name); layer.set_name(new_name);) // Insert the new operator name, the number of times of duplicate name is recorded as 1 layer_name_map.insert(std::make_pair(layer.name(), kNumOne)); // Do not exit immediately when there is an error, wait until all errors are collected before exiting Status ret = AddNode(layer, graph); if (ret != SUCCESS) { GELOGE(FAILED, "[Add][Node] fail, layer:%s.", layer.name().c_str()); has_error = true; continue; } // parse ParamSpec std::vector v_param_names; for (int32_t i = 0; i < layer.param_size(); i++) { const domi::caffe::ParamSpec ¶m = layer.param(i); GE_IF_BOOL_EXEC((param.has_name()), v_param_names.emplace_back(param.name())); } // Save the layer with param name parameter to map GE_IF_BOOL_EXEC((v_param_names.size() > 0), layer_params_map.emplace(layer.name(), v_param_names)); GE_RETURN_WITH_LOG_IF_ERROR(AddBlobsToMap(layer, inplace_blob_name_remapping), "[Add][blobs] to map ret fail, layer:%s.", layer.name().c_str()); if (SaveDataLayerTops(layer) != SUCCESS) { GELOGE(FAILED, "[Save][DataLayerTops] failed, layer:%s.", layer.name().c_str()); return FAILED; } } // Find a layer with the same param name and save it to graph GE_RETURN_WITH_LOG_IF_ERROR(FindShareParamLayers(layer_params_map), "[Find][ShareParamLayers] ret fail."); // Exit if an error occurs GE_IF_BOOL_EXEC(has_error, return FAILED); GE_CHK_BOOL_RET_STATUS(top_blobs_map_.size() > 0, FAILED, "[Check][Size]current net has no output!"); GE_RETURN_WITH_LOG_IF_ERROR(AddEdges(graph), "[Add][Edges] fail, graph:%s.", graph->GetName().c_str()); if (!(ge::GetParserContext().user_out_nodes.empty())) { GE_RETURN_WITH_LOG_IF_ERROR(AddUserOutNodesTop(), "[Add][UserOutNodesTop] failed."); } else { GE_RETURN_WITH_LOG_IF_ERROR(AddOutputTop(proto_message), "[Add][OutputTop] failed."); } GE_RETURN_WITH_LOG_IF_ERROR(graph->TopologicalSorting(), "[Call][TopologicalSorting] failed, graph:%s.", graph->GetName().c_str()); auto nodes = graph->GetDirectNode(); GELOGI("graph node size = %zu.", nodes.size()); for (auto &node : nodes) { GELOGI("node name = %s.", node->GetName().c_str()); for (auto &out_node : node->GetOutDataNodes()) { GELOGI("out node name = %s.", out_node->GetName().c_str()); } } return SUCCESS; } Status CaffeModelParser::FindShareParamLayers( const std::map> &layer_params_map) const { for (auto p_iter = layer_params_map.begin(); p_iter != layer_params_map.end(); ++p_iter) { for (auto p2_iter = p_iter; p2_iter != layer_params_map.end(); ++p2_iter) { if (p_iter->first != p2_iter->first && p_iter->second == p2_iter->second) { if (params_share_map.find(p_iter->second) == params_share_map.end()) { // Unsaved layer vector tmp_v; tmp_v.push_back(p_iter->first); tmp_v.push_back(p2_iter->first); params_share_map.emplace(p_iter->second, tmp_v); } else { vector::iterator iter = find(params_share_map[p_iter->second].begin(), params_share_map[p_iter->second].end(), p2_iter->first); if (iter == params_share_map[p_iter->second].end()) { params_share_map[p_iter->second].push_back(p2_iter->first); } } } } } return SUCCESS; } Status CaffeModelParser::ToJson(const char *model_file, const char *json_file) { GE_CHK_BOOL_RET_STATUS(model_file != nullptr, FAILED, "[Check][Param]model_file is nullptr."); GE_CHK_BOOL_RET_STATUS(json_file != nullptr, FAILED, "[Check][Param]json_file is nullptr."); domi::caffe::NetParameter net; nlohmann::json j; GE_RETURN_WITH_LOG_IF_FALSE(ReadModelWithoutWarning(model_file, &net) == SUCCESS, "[Read][Model]Without Warning failed, Please Check file:%s.", model_file); Pb2Json::Message2Json(net, set(), j, true); return ModelSaver::SaveJsonToFile(json_file, j); } Status CaffeModelParser::ReorderInput(domi::caffe::NetParameter &net) const { int layer_size = net.layer_size(); for (int i = 0; i < layer_size; ++i) { domi::caffe::LayerParameter *layer = net.mutable_layer(i); const std::vector &move_input_vec = domi::OpRegistry::Instance()->GetRemoveInputConfigure(layer->type()); if (move_input_vec.empty()) { continue; } for (const auto &it : move_input_vec) { if (it.moveType == domi::RemoveInputType::OMG_INPUT_REORDER) { auto inputs = layer->bottom(); if (static_cast(inputs.size()) != it.input_order.size()) { REPORT_INNER_ERROR("E19999", "Size of input is mismatched, check invalid," "new order size is %zu, input size is %d.", it.input_order.size(), inputs.size()); GELOGE(INTERNAL_ERROR, "[Check][Size]Size of input is mismatched, new order size is %zu, input size is %d.", it.input_order.size(), inputs.size()); return INTERNAL_ERROR; } for (size_t j = 0; j < it.input_order.size(); ++j) { int new_index = it.input_order[j]; if (new_index < 0 || new_index >= inputs.size()) { REPORT_INNER_ERROR("E19999", "New order of %s has invalid index %d, which is out of range, " "inputs size:%d.", layer->name().c_str(), new_index, inputs.size()); GELOGE(INTERNAL_ERROR, "[Check][Param]New order of %s has invalid index %d, which is out of range, " "inputs size:%d.", layer->name().c_str(), new_index, inputs.size()); return INTERNAL_ERROR; } layer->set_bottom(j, inputs[new_index]); } GELOGI("The input sequence of the node has been rearranged, node name:%s.", layer->name().c_str()); } } } return SUCCESS; } Status CaffeWeightsParser::ParseFromMemory(const char *data, uint32_t size, ge::ComputeGraphPtr &graph) { ErrorManager::GetInstance().SetStage(error_message::kModelCompile, error_message::kParser); if (data == nullptr) { REPORT_INNER_ERROR("E19999", "param data is nullptr."); GELOGE(PARAM_INVALID, "[Check][Param]Caffe weights data is nullptr"); return PARAM_INVALID; } if (graph == nullptr) { REPORT_INNER_ERROR("E19999", "param graph is nullptr."); GELOGE(PARAM_INVALID, "[Check][Param]Caffe weights graph is nullptr"); return PARAM_INVALID; } // Resolve proto file to netparameter NetParameter proto; bool success = ge::parser::ReadProtoFromArray(data, static_cast(size), &proto); if (!success) { REPORT_CALL_ERROR("E19999", "ReadProtoFromArray failed."); GELOGE(domi::PARSE_WEIGHTS_FAILED, "[Read][Proto] from Memory fail"); return domi::PARSE_WEIGHTS_FAILED; } // Convert netparameter to opdef and save to graph Status status = ConvertNetParameter(proto, graph); GE_IF_BOOL_EXEC(status != SUCCESS, GELOGE(FAILED, "[Convert][NetParameter] failed, status=%d", status); return domi::PARSE_WEIGHTS_FAILED;); return SUCCESS; } Status CaffeWeightsParser::Parse(const char *file, ge::Graph &graph) { ErrorManager::GetInstance().SetStage(error_message::kModelCompile, error_message::kParser); GE_CHECK_NOTNULL(file); ge::ComputeGraphPtr compute_graph = ge::GraphUtils::GetComputeGraph(graph); GE_CHECK_NOTNULL(compute_graph); Status ret = Parse(file, compute_graph); if (ret != SUCCESS) { GELOGE(ret, "[Parser][Weight] %s for graph %s failed.", file, ParserUtils::GetGraphName(graph).c_str()); return ret; } GELOGI("Parser weight for graph %s success.", ParserUtils::GetGraphName(graph).c_str()); return SUCCESS; } Status CaffeWeightsParser::Parse(const char *file, ge::ComputeGraphPtr &graph) { if (file == nullptr) { REPORT_INNER_ERROR("E19999", "param file is nullptr, check invalid."); GELOGE(FAILED, "[Check][Param]Caffe weights parse fail, Parameter file invalid"); return PARAM_INVALID; } if (graph == nullptr) { REPORT_INNER_ERROR("E19999", "param graph is nullptr, check invalid."); GELOGE(FAILED, "[Check][Param]Caffe weights parse fail, Parameter graph invalid"); return PARAM_INVALID; } GELOGI("Parse weights file:%s", file); string caffe_proto_path = ge::GetParserContext().caffe_proto_path + "caffe.proto"; string custom_proto_path = ge::GetParserContext().custom_proto_path + "custom.proto"; ProtoFileParser proto_file_parser; GELOGD("caffe_proto_path:%s custom_proto_path:%s", caffe_proto_path.c_str(), custom_proto_path.c_str()); string fusion_proto_file; string custom_proto_file = ge::parser::RealPath(custom_proto_path.c_str()); if (custom_proto_file.empty()) { GELOGW("custom_proto_path:%s is not existed", custom_proto_path.c_str()); fusion_proto_file = caffe_proto_path; } else { if (proto_file_parser.CombineProtoFile(caffe_proto_path.c_str(), custom_proto_path.c_str(),\ fusion_proto_file) != SUCCESS) { REPORT_INNER_ERROR("E19999", "CombineProtoFile failed, caffe_proto_path:%s, custom_proto_path:%s.", caffe_proto_path.c_str(), custom_proto_path.c_str()); GELOGE(FAILED, "[Invoke][CombineProtoFile]Create tmp fusion proto file from caffe and custom proto failed."); return FAILED; } } string fusion_proto_path = ge::parser::RealPath(fusion_proto_file.c_str()); GELOGI("Get fusion proto file[%s]-[%s].", fusion_proto_file.c_str(), fusion_proto_path.c_str()); if (fusion_proto_path.empty()) { REPORT_INNER_ERROR("E19999", "Fusion proto file path [%s] is not real existed.", fusion_proto_file.c_str()); GELOGE(FAILED, "[Invoke][RealPath]Fusion proto file path [%s]-[%s] is not real existed.", fusion_proto_file.c_str(), fusion_proto_path.c_str()); return FAILED; } string fusion_proto_name; if (CheckPathValid(file, fusion_proto_file, fusion_proto_path, fusion_proto_name) != SUCCESS) { GELOGE(FAILED, "[Check][PathValid] of weight file[%s] and tmp proto[%s] failed.", file, fusion_proto_file.c_str()); return FAILED; } GELOGI("Start to parse weight: %s by fusion proto: %s.", file, fusion_proto_file.c_str()); Status status = ParseWeightByFusionProto(file, fusion_proto_path, fusion_proto_name, graph); if (status != SUCCESS) { GELOGE(FAILED, "[Invoke][ParseWeightByFusionProto] failed. ret:%u", status); return status; } status = CheckNodes(graph); if (status != SUCCESS) { GELOGE(ge::GRAPH_FAILED, "[Check][Nodes] failed, status=%u", status); return domi::PARSE_WEIGHTS_FAILED; } return SUCCESS; } Status CaffeWeightsParser::ParseWeightByFusionProto(const char *weight_path, const string &fusion_proto_path, const string &fusion_proto_name, ge::ComputeGraphPtr &graph) { google::protobuf::compiler::DiskSourceTree source_tree; source_tree.MapPath(kProjectRoot, fusion_proto_path); google::protobuf::compiler::Importer importer(&source_tree, nullptr); importer.Import(fusion_proto_name.c_str()); GELOGI("Import fusion proto %s success, proto_name %s.", fusion_proto_path.c_str(), fusion_proto_name.c_str()); const google::protobuf::Descriptor *descriptor = importer.pool()->FindMessageTypeByName(kBeginningMessageType); if (descriptor == nullptr) { REPORT_INPUT_ERROR("E11032", std::vector({"message_type", "name", "reason"}), std::vector({"weight", "NetParameter", "Does not find domi.caffe.NetParameter in google::protobuf::Descriptor."})); GELOGE(FAILED, "[Invoke][FindMessageTypeByName]Does not find domi.caffe.NetParameter in " "google::protobuf::Descriptor, which may be caused by problematic fusion proto."); return FAILED; } google::protobuf::DynamicMessageFactory factory; const google::protobuf::Message *proto = factory.GetPrototype(descriptor); GE_CHECK_NOTNULL(proto); google::protobuf::Message *message = proto->New(); GE_CHECK_NOTNULL(message); if (!ge::parser::ReadProtoFromBinaryFile(weight_path, message)) { delete message; message = nullptr; REPORT_CALL_ERROR("E19999", "ReadProtoFromBinaryFile based on fusion proto failed from weight file:%s.", weight_path); GELOGE(FAILED, "[Invoke][ReadProtoFromBinaryFile] %s failed.", weight_path); return FAILED; } GELOGI("Start to parse weight file: %s.", weight_path); const google::protobuf::Descriptor *layer_descriptor = importer.pool()->FindMessageTypeByName(kLayerMessageType); if (layer_descriptor == nullptr) { delete message; message = nullptr; REPORT_INPUT_ERROR("E11032", std::vector({"message_type", "name", "reason"}), std::vector({"weight", "NetParameter", "Does not find domi.caffe.LayerParameter in google::protobuf::Descriptor"})); GELOGE(FAILED, "[Invoke][FindMessageTypeByName]Does not find domi.caffe.LayerParameter in google::protobuf::Descriptor"); return FAILED; } if (CheckLayersSize(*message) != SUCCESS) { delete message; message = nullptr; return FAILED; } if (ParseLayerParameter(*layer_descriptor, *message, graph) != SUCCESS) { delete message; message = nullptr; REPORT_CALL_ERROR("E19999", "ParseLayerParameter failed failed from weight file:%s.", weight_path); GELOGE(FAILED, "[Parse][LayerParameter] failed."); return FAILED; } delete message; message = nullptr; GELOGI("Parse weight: %s by proto: %s success.", weight_path, fusion_proto_path.c_str()); return SUCCESS; } Status CaffeWeightsParser::ParseLayerParameter(const google::protobuf::Descriptor &layer_descriptor, const google::protobuf::Message &message, ge::ComputeGraphPtr &graph) { auto field_name = layer_descriptor.FindFieldByName(kFieldName); CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(field_name, "Does not find name in google::protobuf::Descriptor"); auto field_type = layer_descriptor.FindFieldByName(kFieldType); CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(field_type, "Does not find type in google::protobuf::Descriptor"); const google::protobuf::Reflection *reflection = message.GetReflection(); CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(reflection, "Get Reflection failed in google::protobuf::Message"); vector field_desc; reflection->ListFields(message, &field_desc); NetParameter tmp_net; for (auto &field : field_desc) { CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(field, "Get FieldDescriptor failed in google::protobuf::Message"); // Only care about layers GE_CHECK_NOTNULL(field); if (field->name() != kLayerName) { continue; } if (!field->is_repeated()) { REPORT_INPUT_ERROR("E11032", std::vector({"message_type", "name", "reason"}), std::vector({"weight", field->name(), "LayerParameter should be repeated"})); GELOGE(FAILED, "[Check][Param] LayerParameter should be repeated, field:%s.", field->name().c_str()); return FAILED; } int field_size = reflection->FieldSize(message, field); GELOGI("Total Layer num of model file is %d", field_size); for (int i = 0; i < field_size; ++i) { const google::protobuf::Message &layer_message = reflection->GetRepeatedMessage(message, field, i); LayerParameter *layer = tmp_net.add_layer(); if (ConvertLayerProto(layer_message, layer) != SUCCESS) { GELOGE(FAILED, "[Invoke][ConvertLayerProto] Convert message to layer proto failed."); return FAILED; } const string &layer_name = layer->name(); if (skiped_layer_type_.find(layer->type()) != skiped_layer_type_.end()) { GELOGI("Skip layer %s", layer_name.c_str()); continue; } GELOGI("Parse layer %s", layer_name.c_str()); auto ret = ConvertLayerParameter(layer, graph); if (ret != SUCCESS) { return ret; } } } return SUCCESS; } Status CaffeWeightsParser::ConvertLayerProto(const google::protobuf::Message &message, google::protobuf::Message *layer) { const google::protobuf::Reflection *layer_reflection = message.GetReflection(); CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(layer_reflection, "Get Reflection failed in google::protobuf::Message"); vector field_desc; layer_reflection->ListFields(message, &field_desc); for (auto &field : field_desc) { GE_CHECK_NOTNULL(field); if (ParseLayerField(*layer_reflection, message, *field, layer) != SUCCESS) { GELOGE(FAILED, "[Invoke][ParseLayerField] Parse field %s failed.", field->name().c_str()); return FAILED; } } return SUCCESS; } Status CaffeWeightsParser::ParseLayerField(const google::protobuf::Reflection &reflection, const google::protobuf::Message &message, const google::protobuf::FieldDescriptor &field, google::protobuf::Message *layer) const { GELOGD("Start to parse field: %s.", field.name().c_str()); domi::caffe::LayerParameter *layer_proto = PtrToPtr(layer); string filed_name = field.name(); #define CASE_FIELD_NAME(kName, method, inner_message, field_ptr) \ if (filed_name == kField##kName) { \ string value = reflection.GetString(inner_message, field_ptr); \ GELOGD("Parse res: (%s : %s)", filed_name.c_str(), value.c_str()); \ layer_proto->set_##method(value); \ return SUCCESS; \ } CASE_FIELD_NAME(Name, name, message, &field); CASE_FIELD_NAME(Type, type, message, &field); #undef CASE_FIELD_NAME #define CASE_FIELD_NAME_REPEATED(kName, method, inner_message, field_ptr) \ if (filed_name == kField##kName) { \ int field_size = reflection.FieldSize(inner_message, field_ptr); \ for (int i = 0; i < field_size; ++i) { \ auto value = reflection.GetRepeatedString(inner_message, field_ptr, i); \ layer_proto->add_##method(value); \ } \ return SUCCESS; \ } CASE_FIELD_NAME_REPEATED(Bottom, bottom, message, &field); CASE_FIELD_NAME_REPEATED(Top, top, message, &field); #undef CASE_FIELD_NAME_REPEATED if (filed_name == kFieldBlobs) { int field_size = reflection.FieldSize(message, &field); for (int i = 0; i < field_size; ++i) { domi::caffe::BlobProto *item_message = layer_proto->add_blobs(); const google::protobuf::Message &sub_message = reflection.GetRepeatedMessage(message, &field, i); if (ConvertBlobsProto(sub_message, item_message) != SUCCESS) { GELOGE(FAILED, "[Invoke][ConvertBlobsProto] ParseLayerField of field: %s failed.", field.name().c_str()); return FAILED; } } return SUCCESS; } if (filed_name == kFieldConvParam) { const google::protobuf::Message &sub_message = reflection.GetMessage(message, &field); ConvolutionParameter *conv_param = layer_proto->mutable_convolution_param(); ConvertConvParamProto(sub_message, conv_param); } if (filed_name == kFieldInnerPro) { const google::protobuf::Message &sub_message = reflection.GetMessage(message, &field); InnerProductParameter *inner_product = layer_proto->mutable_inner_product_param(); ConvertInnerProdcutProto(sub_message, inner_product); } return SUCCESS; } Status CaffeWeightsParser::ConvertBlobsProto(const google::protobuf::Message &message, google::protobuf::Message *blobs) const { const google::protobuf::Reflection *blobs_reflection = message.GetReflection(); CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(blobs_reflection, "Get Reflection failed in google::protobuf::Message"); vector field_desc; blobs_reflection->ListFields(message, &field_desc); domi::caffe::BlobProto *blobs_proto = PtrToPtr(blobs); for (auto &field : field_desc) { GE_CHECK_NOTNULL(field); string feild_name = field->name(); #define CASE_BLOBS_FIELD_NAME_REPEATED(kName, method, valuetype, name, inner_message, inner_field) \ if (feild_name == #kName) { \ int field_size = blobs_reflection->FieldSize(inner_message, inner_field); \ for (int i = 0; i < field_size; ++i) { \ valuetype value = blobs_reflection->GetRepeated##method(inner_message, inner_field, i); \ blobs_proto->add_##name(value); \ } \ continue; \ } CASE_BLOBS_FIELD_NAME_REPEATED(data, Float, float, data, message, field); CASE_BLOBS_FIELD_NAME_REPEATED(diff, Float, float, diff, message, field); CASE_BLOBS_FIELD_NAME_REPEATED(double_data, Double, double, double_data, message, field); CASE_BLOBS_FIELD_NAME_REPEATED(double_diff, Double, double, double_diff, message, field); CASE_BLOBS_FIELD_NAME_REPEATED(int32_data, Int32, int32_t, int32_data, message, field); CASE_BLOBS_FIELD_NAME_REPEATED(uint64_data, UInt64, uint64_t, uint64_data, message, field); #undef CASE_BLOBS_FIELD_NAME_REPEATED #define CASE_BLOBS_FIELD_NAME(kName, method, valuetype, name, inner_message, inner_field) \ if (feild_name == #kName) { \ valuetype value = blobs_reflection->Get##method(inner_message, inner_field); \ blobs_proto->set_##name(value); \ continue; \ } CASE_BLOBS_FIELD_NAME(int8_data, String, string, int8_data, message, field); CASE_BLOBS_FIELD_NAME(num, Int32, int32_t, num, message, field); CASE_BLOBS_FIELD_NAME(channels, Int32, int32_t, channels, message, field); CASE_BLOBS_FIELD_NAME(height, Int32, int32_t, height, message, field); CASE_BLOBS_FIELD_NAME(width, Int32, int32_t, width, message, field); #undef CASE_BLOBS_FIELD_NAME if (feild_name == kFieldShape) { const google::protobuf::Message &sub_message = blobs_reflection->GetMessage(message, field); domi::caffe::BlobShape *blob_shape = blobs_proto->mutable_shape(); ConvertBlobShapeProto(sub_message, blob_shape); } } return SUCCESS; } Status CaffeWeightsParser::ConvertBlobShapeProto(const google::protobuf::Message &message, google::protobuf::Message *dest_message) const { const google::protobuf::Reflection *reflection = message.GetReflection(); CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(reflection, "Get Reflection failed in google::protobuf::Message"); vector field_desc; reflection->ListFields(message, &field_desc); domi::caffe::BlobShape *shape_proto = PtrToPtr(dest_message); for (auto &field : field_desc) { if (field->name() != kFieldDim) { continue; } int field_size = reflection->FieldSize(message, field); for (int i = 0; i < field_size; ++i) { int64_t value = reflection->GetRepeatedInt64(message, field, i); shape_proto->add_dim(value); } } return SUCCESS; } Status CaffeWeightsParser::ConvertConvParamProto(const google::protobuf::Message &message, google::protobuf::Message *dest_message) const { const google::protobuf::Reflection *reflection = message.GetReflection(); CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(reflection, "Get Reflection failed in google::protobuf::Message"); vector field_desc; reflection->ListFields(message, &field_desc); domi::caffe::ConvolutionParameter *conv_param_proto = PtrToPtr(dest_message); for (auto &field : field_desc) { if (field->name() != kFieldBiasTerm) { continue; } bool value = reflection->GetBool(message, field); conv_param_proto->set_bias_term(value); } return SUCCESS; } Status CaffeWeightsParser::ConvertInnerProdcutProto(const google::protobuf::Message &message, google::protobuf::Message *dest_message) const { const google::protobuf::Reflection *reflection = message.GetReflection(); CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(reflection, "Get Reflection failed in google::protobuf::Message"); vector field_desc; reflection->ListFields(message, &field_desc); domi::caffe::InnerProductParameter *inner_product_proto = PtrToPtr(dest_message); for (auto &field : field_desc) { if (field->name() != kFieldBiasTerm) { continue; } bool value = reflection->GetBool(message, field); inner_product_proto->set_bias_term(value); } return SUCCESS; } Status CaffeWeightsParser::CheckLayersSize(const google::protobuf::Message &message) const { const google::protobuf::Reflection *reflection = message.GetReflection(); CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(reflection, "Get Reflection failed in google::protobuf::Message"); vector field_desc; reflection->ListFields(message, &field_desc); int num_layer = 0; int num_layers = 0; for (auto &field : field_desc) { CAFFE_CHECK_NULL_AND_REPROT_ERRORMSG(field, "Get FieldDescriptor failed in google::protobuf::Message"); // Only care about layers if (field->name() != kLayerName && field->name() != kLayersName) { continue; } if (!field->is_repeated()) { REPORT_INPUT_ERROR("E11032", std::vector({"message_type", "name", "reason"}), std::vector({"weight", field->name(), "LayerParameter should be repeated"})); GELOGE(FAILED, "[Check][Param] LayerParameter should be repeated. field:%s", field->name().c_str()); return FAILED; } int field_size = reflection->FieldSize(message, field); if (field->name() == kLayerName) { num_layer = field_size; } else { num_layers = field_size; } } if (num_layer == 0 && num_layers > 0) { ErrorManager::GetInstance().ATCReportErrMessage("E11023"); GELOGE(FAILED, "[Check][Param]The weight file is consisted of layers-structure which is deprecated " "in Caffe and unsupported in ATC. The \"layers\" should be changed to \"layer\"."); return FAILED; } if (num_layer == 0) { ErrorManager::GetInstance().ATCReportErrMessage("E11024"); GELOGE(FAILED, "[Check][Param] Weight layer num is zero, weight file may be invalid."); return FAILED; } return SUCCESS; } Status CaffeWeightsParser::ConvertLayerParameter(const google::protobuf::Message *layer_message, ge::ComputeGraphPtr &graph) { vector need_share_layers; const domi::caffe::LayerParameter *layer = PtrToPtr(layer_message); const string &shared_layer_name = layer->name(); const string &layer_type = layer->type(); for (auto p_iter = params_share_map.begin(); p_iter != params_share_map.end(); ++p_iter) { if (find(p_iter->second.begin(), p_iter->second.end(), shared_layer_name) != p_iter->second.end()) { GELOGI("layer:%s need share weights !", shared_layer_name.c_str()); need_share_layers = p_iter->second; } } if (need_share_layers.size() == 0) { need_share_layers.push_back(shared_layer_name); } for (auto share_iter = need_share_layers.begin(); share_iter != need_share_layers.end(); ++share_iter) { // Find created nodes string layer_name = *share_iter; GE_IF_BOOL_EXEC(layer_name_record_map_.find(layer_name) != layer_name_record_map_.end(), string temp_layer_name = layer_name; // duplicate operator modification layer_name = temp_layer_name + "_same_" + std::to_string(layer_name_record_map_[temp_layer_name]); // Times accumulation of duplicate operators layer_name_record_map_[temp_layer_name]++; // Set the name in proto and layer ) ge::NodePtr node = graph->FindNode(layer_name); layer_name_record_map_.insert(std::make_pair(layer_name, kNumOne)); if (node == nullptr) { // If there are redundant layers in the weight file, they should be skipped rather than returned with an error. GELOGI("Layer %s not found in graph", layer_name.c_str()); continue; } // The weight processing also needs to judge the duplicate operator, which is reserved here and processed later. std::map::const_iterator iter = caffe_op_map.find(layer_type); if (iter == caffe_op_map.end()) { GELOGW("Unrecognized layer type %s , layer name: %s, layer ignored.", layer_type.c_str(), layer_name.c_str()); continue; } GELOGD("Caffe layer name: %s , layer type: %s.", layer_name.c_str(), layer_type.c_str()); string op_type = iter->second; // create OpParser std::shared_ptr factory = OpParserFactory::Instance(domi::CAFFE); GE_CHECK_NOTNULL(factory); std::shared_ptr op_parser = factory->CreateOpParser(op_type); if (op_parser.get() == nullptr) { REPORT_INPUT_ERROR("E11009", std::vector({"opname", "optype"}), std::vector({layer_name, op_type})); GELOGE(FAILED, "[Create][OpParser] failed for Op[%s], optype is %s", layer_name.c_str(), op_type.c_str()); return FAILED; } // Parsing weight information through op parser Status status = op_parser->ParseWeights(layer_message, node); if (status != SUCCESS) { REPORT_CALL_ERROR("E19999", "Parse weight for op:%s(%s) failed", layer_name.c_str(), op_type.c_str()); GELOGE(FAILED, "[Parse][Weights] for op[%s] failed", layer_name.c_str()); return status; } } return SUCCESS; } Status CaffeWeightsParser::CheckNodes(ge::ComputeGraphPtr &graph) { GE_CHECK_NOTNULL(graph); for (const ge::NodePtr &node : graph->GetAllNodes()) { GE_CHECK_NOTNULL(node); auto op_desc = node->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); for (const auto &in_anchor_ptr : node->GetAllInDataAnchors()) { if (op_desc->GetType() == ge::parser::DATA || op_desc->GetType() == ge::parser::CONSTANT) { continue; } auto index = in_anchor_ptr->GetIdx(); auto input_desc = op_desc->MutableInputDesc(index); if (in_anchor_ptr->GetPeerAnchors().empty() && input_desc != nullptr) { if (layer_name_record_map_.find(node->GetName()) == layer_name_record_map_.end()) { ErrorManager::GetInstance().ATCReportErrMessage("E11029", {"opname"}, {node->GetName()}); GELOGE(ge::GRAPH_FAILED, "[Find][Node] Op[%s] in model file does not exist in weight file.", node->GetName().c_str()); PreChecker::Instance().RefreshErrorMessageByName(node->GetName(), PreChecker::ErrorCode::PARAM_INVALID, "Node does not exist in weight file."); } else { REPORT_INNER_ERROR("E19999", "Op:%s(%s)'s input %d is not linked, check invalid", node->GetName().c_str(), node->GetType().c_str(), in_anchor_ptr->GetIdx()); GELOGE(ge::GRAPH_FAILED, "[Check][Param] Op[%s]'s input %d is not linked.", node->GetName().c_str(), in_anchor_ptr->GetIdx()); string check_msg = "input " + to_string(in_anchor_ptr->GetIdx()) + "is not linked in weight file"; PreChecker::Instance().RefreshErrorMessageByName(node->GetName(), PreChecker::ErrorCode::PARAM_INVALID, check_msg); } return FAILED; } } } return SUCCESS; } Status CaffeWeightsParser::ConvertNetParameter(const NetParameter ¶m, ge::ComputeGraphPtr &graph) { GE_CHECK_NOTNULL(graph); int num_layer = param.layer_size(); int num_layers = param.layers_size(); // Operator name and occurrence map, handle duplicate operators std::map layer_name_map; if (num_layer == 0 && num_layers > 0) { ErrorManager::GetInstance().ATCReportErrMessage("E11023"); GELOGE(FAILED, "[Check][Param] The weight file is consisted of layers-structure " "which is deprecated in Caffe and unsupported in ATC. " "The \"layers\" should be changed to \"layer\"."); return FAILED; } if (num_layer == 0) { ErrorManager::GetInstance().ATCReportErrMessage("E11024"); GELOGE(FAILED, "weight layer num is zero, weight file may be invalid."); return FAILED; } for (int i = 0; i < num_layer; ++i) { const LayerParameter &layer = param.layer(i); const string ¶m_layer_name = layer.name(); // Skip some layer types if (skiped_layer_type_.find(layer.type()) != skiped_layer_type_.end()) { GELOGI("Skip layer %s", param_layer_name.c_str()); continue; } GELOGI("Parse layer %s", param_layer_name.c_str()); vector need_share_layers; for (auto p_iter = params_share_map.begin(); p_iter != params_share_map.end(); ++p_iter) { if (find(p_iter->second.begin(), p_iter->second.end(), param_layer_name) != p_iter->second.end()) { GELOGI("Layer: %s need share weights !", param_layer_name.c_str()); need_share_layers = p_iter->second; } } if (need_share_layers.size() == 0) { need_share_layers.push_back(param_layer_name); } for (auto share_iter = need_share_layers.begin(); share_iter != need_share_layers.end(); ++share_iter) { // Find created nodes string layer_name = *share_iter; GE_IF_BOOL_EXEC(layer_name_map.find(layer_name) != layer_name_map.end(), string temp_layer_name = layer_name; // duplicate operator modification layer_name = temp_layer_name + "_same_" + std::to_string(layer_name_map[temp_layer_name]); // Times accumulation of duplicate operators layer_name_map[temp_layer_name]++; // Set the name in proto and layer ) ge::NodePtr node = graph->FindNode(layer_name); layer_name_map.insert(std::make_pair(layer_name, kNumOne)); if (node == nullptr) { // If there are redundant layers in the weight file, they should be skipped rather than returned with an error. GELOGI("Layer %s not found in graph", layer_name.c_str()); continue; } // The weight processing also needs to judge the duplicate operator, which is reserved here and processed later. std::map::const_iterator iter = caffe_op_map.find(layer.type()); if (iter == caffe_op_map.end()) { GELOGW("Unrecognized layer type %s , layer name: %s, layer ignored.", layer.type().c_str(), layer_name.c_str()); continue; } GELOGD("Caffe layer name: %s , layer type: %s.", layer_name.c_str(), layer.type().c_str()); string op_type = iter->second; // create OpParser std::shared_ptr factory = OpParserFactory::Instance(domi::CAFFE); GE_CHECK_NOTNULL(factory); std::shared_ptr op_parser = factory->CreateOpParser(op_type); if (op_parser.get() == nullptr) { REPORT_INPUT_ERROR("E11009", std::vector({"opname", "optype"}), std::vector({layer_name, op_type})); GELOGE(FAILED, "[Create][OpParser] failed for Op[%s], optype is %s", layer_name.c_str(), op_type.c_str()); return FAILED; } // Parsing weight information through op parser Status status = op_parser->ParseWeights(&layer, node); if (status != SUCCESS) { REPORT_CALL_ERROR("E19999", "Parse weight for op:%s(%s) failed", layer_name.c_str(), op_type.c_str()); GELOGE(FAILED, "[Parse][Weights] for op[%s] failed", layer_name.c_str()); return status; } } } return SUCCESS; } Status CaffeModelParser::ParseProto(const google::protobuf::Message *proto, ge::ComputeGraphPtr &graph) { (void)proto; (void)graph; return SUCCESS; } Status CaffeModelParser::ParseProtoWithSubgraph(const google::protobuf::Message *root_proto, domi::GetGraphCallback callback, ge::ComputeGraphPtr &graph) { (void)root_proto; (void)callback; (void)graph; return SUCCESS; } } // namespace ge namespace domi { REGISTER_MODEL_PARSER_CREATOR(CAFFE, ge::CaffeModelParser); REGISTER_WEIGHTS_PARSER_CREATOR(CAFFE, ge::CaffeWeightsParser); }