// Tencent is pleased to support the open source community by making ncnn available. // // Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. // // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // https://opensource.org/licenses/BSD-3-Clause // // 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 #include #include #include #include #include #include #include #include #include #include #include "graph.pb.h" static bool read_proto_from_binary(const char* filepath, google::protobuf::Message* message) { std::ifstream fs(filepath, std::ifstream::in | std::ifstream::binary); if (!fs.is_open()) { fprintf(stderr, "open failed %s\n", filepath); return false; } google::protobuf::io::IstreamInputStream input(&fs); google::protobuf::io::CodedInputStream codedstr(&input); codedstr.SetTotalBytesLimit(INT_MAX, INT_MAX / 2); bool success = message->ParseFromCodedStream(&codedstr); fs.close(); return success; } static bool find_tensor_proto(const std::map& weights, const tensorflow::NodeDef& node, tensorflow::TensorProto& tensor) { for (int j=0; j::const_iterator it = weights.find(input_name); if (it != weights.end()) { tensor = it->second; return true; } } return false; } static bool get_tensor_proto(const std::map& consts, const tensorflow::NodeDef& node, tensorflow::TensorProto& tensor) { const std::string& output_name = node.name(); const std::map::const_iterator it = consts.find(output_name); if (it != consts.end()) { tensor = it->second; return true; } return false; } static bool find_attr_value(const tensorflow::NodeDef& node, const char* key, tensorflow::AttrValue& value) { const google::protobuf::Map& attr = node.attr(); const google::protobuf::Map::const_iterator it = attr.find(key); if (it != attr.end()) { value = it->second; return true; } return false; } static int parse_tensor_reduction_dim(const tensorflow::TensorProto& tensor) { int dim = 0; // dim == 0 // w h c -> X X X // dim == 1 // w h c -> X X c // dim == 2 // w h c -> X h c // dim == -1 // w h c -> w X X // dim == -2 // w h c -> w h X if (!tensor.tensor_content().empty() && tensor.dtype() == 3)// int32 { const int* data = reinterpret_cast(tensor.tensor_content().c_str()); int size = tensor.tensor_content().size() / sizeof(int); // n h w c // n h w // n w // TODO investigate two stage / three stage reduction if (size == 2) { if (data[0] == 1 && data[1] == 2) { dim = 1; } } } else { int axis = tensor.int_val(0); if (axis == 1) dim = 0; else if (axis == 3) dim = -2; } return dim; } int main(int argc, char** argv) { const char* tensorflowpb = argv[1]; const char* ncnn_prototxt = argc >= 4 ? argv[2] : "ncnn.proto"; const char* ncnn_modelbin = argc >= 4 ? argv[3] : "ncnn.bin"; tensorflow::GraphDef graph; // load bool s1 = read_proto_from_binary(tensorflowpb, &graph); if (!s1) { fprintf(stderr, "read_proto_from_binary failed\n"); return -1; } FILE* pp = fopen(ncnn_prototxt, "wb"); FILE* bp = fopen(ncnn_modelbin, "wb"); // magic fprintf(pp, "7767517\n"); int node_count = graph.node_size(); // fprintf(stderr, "node_count = %d\n\n", node_count); // node reference std::map node_reference; // mapping for Const and Const-Identity std::map weights; // Dropout like Identity std::set dropouts; // Const before BinaryOp std::map binaryop_consts; // global definition line // [layer count] [blob count] std::set blob_names; for (int i=0; i::iterator it = weights.find(input_name); if (it != weights.end()) { // binary op with const, insert MemoryData layer and const blob binaryop_consts[input_name] = it->second; weights.erase(it); } } } } // input for (int j=0; j::iterator it = node_reference.begin(); while (it != node_reference.end()) { if (it->second == 1) { node_reference.erase(it++); } else { splitncnn_blob_count += it->second; // fprintf(stderr, "%s %d\n", it->first.c_str(), it->second); ++it; } } fprintf(pp, "%lu %lu\n", node_count + node_reference.size() - weights.size(), blob_names.size() + splitncnn_blob_count); int internal_split = 0; for (int i=0; i(tensor.tensor_content().c_str()); weight_data_size = tensor.tensor_content().size() / sizeof(float); if (c == 0) fwrite(data, sizeof(float), weight_data_size, bp); else { float tmp; // h-w-c to c-h-w for (int p=0; p(tensor.tensor_content().c_str()); weight_data_size = tensor.tensor_content().size() / sizeof(int); float tmp; if (c == 0) { for (int i=0; i(tensor.tensor_content().c_str()); weight_data_size = tensor.tensor_content().size() / sizeof(float); float tmp; for (int p=0; p(tensor.tensor_content().c_str()); weight_data_size = tensor.tensor_content().size() / sizeof(int); float tmp; for (int p=0; p(tensor.tensor_content().c_str()); weight_data_size = tensor.tensor_content().size() / sizeof(float); float tmp; for (int p=0; p(tensor.tensor_content().c_str()); weight_data_size = tensor.tensor_content().size() / sizeof(int); float tmp; for (int p=0; p(tensor.tensor_content().c_str()); weight_data_size = tensor.tensor_content().size() / sizeof(float); float tmp; for (int p=0; p(tensor.tensor_content().c_str()); weight_data_size = tensor.tensor_content().size() / sizeof(int); float tmp; for (int p=0; p(tensor.tensor_content().c_str()); int size = tensor.tensor_content().size() / sizeof(int); if (size == 8) { // n h w c top = data[2]; bottom = data[3]; left = data[4]; right = data[5]; } } } tensorflow::AttrValue value_Tpaddings; if (find_attr_value(node, "Tpaddings", value_Tpaddings)) { type = value_Tpaddings.i(); } tensorflow::AttrValue value_T; if (find_attr_value(node, "T", value_T)) { value = value_T.f(); } fprintf(pp, " 0=%d", top); fprintf(pp, " 1=%d", bottom); fprintf(pp, " 2=%d", left); fprintf(pp, " 3=%d", right); fprintf(pp, " 4=%d", type); fprintf(pp, " 5=%f", value); } else if (node.op() == "Placeholder") { // TODO pass through fprintf(pp, " 0=0 1=0 2=0"); } else if (node.op() == "Prod") { int operation = 6; int dim = 0; float coeff = 1.f; // check weights tensorflow::TensorProto tensor; if (find_tensor_proto(weights, node, tensor)) { dim = parse_tensor_reduction_dim(tensor); } fprintf(pp, " 0=%d", operation); fprintf(pp, " 1=%d", dim); fprintf(pp, " 2=%f", coeff); } else if (node.op() == "Reciprocal") { int op_type = 15; fprintf(pp, " 0=%d", op_type); } else if (node.op() == "Relu") { float slope = 0.f; fprintf(pp, " 0=%f", slope); } else if (node.op() == "Reshape") { tensorflow::TensorProto tensor; if (find_tensor_proto(weights, node, tensor)) { if (!tensor.tensor_content().empty() && tensor.dtype() == 3)// int32 { const int* data = reinterpret_cast(tensor.tensor_content().c_str()); int size = tensor.tensor_content().size() / sizeof(int); // n h w c // n h w // n w if (size == 4) { fprintf(pp, " 0=%d 1=%d 2=%d 3=0", data[2], data[1], data[3]); } if (size == 3) { fprintf(pp, " 0=%d 1=%d 2=-233 3=1", data[2], data[1]); } if (size == 2) { fprintf(pp, " 0=%d 1=-233 2=-233 3=1", data[1]); } } } else { // pass through fprintf(pp, " 0=0 1=0 2=0 3=0"); } } else if (node.op() == "Rsqrt") { int op_type = 6; fprintf(pp, " 0=%d", op_type); } else if (node.op() == "Sigmoid") { } else if (node.op() == "Softmax") { } else if (node.op() == "Square") { int op_type = 4; fprintf(pp, " 0=%d", op_type); } else if (node.op() == "Squeeze") { int squeeze_w = 0; int squeeze_h = 0; int squeeze_c = 0; tensorflow::AttrValue value_squeeze_dims; if (find_attr_value(node, "squeeze_dims", value_squeeze_dims)) { for (int i = 0; i& attr = node.attr(); google::protobuf::Map::const_iterator it = attr.begin(); for (; it != attr.end(); it++) { std::cerr << it->first << " #" << it->second.type() << std::endl; } } fprintf(pp, "\n"); std::string output_name = node.name(); if (node_reference.find(output_name) != node_reference.end()) { int refcount = node_reference[output_name]; if (refcount > 1) { char splitname[256]; sprintf(splitname, "splitncnn_%d", internal_split); fprintf(pp, "%-16s %-32s %d %d", "Split", splitname, 1, refcount); fprintf(pp, " %s", output_name.c_str()); for (int j=0; j