diff --git a/benchmark/README_CPU.md b/benchmark/README_CPU.md index 6113e2e2c..0f847ce85 100644 --- a/benchmark/README_CPU.md +++ b/benchmark/README_CPU.md @@ -205,74 +205,6 @@ We tested them on single-CPU with different thread numbers. 4 | 18074 | 118696 6 | 26607 | 102044 -2. **`Anakin`** VS **`PaddlePaddle/Fluid`** -We use private dataset and different QPS index in this benchmark. -### language model in E5-2650 v4 - -- Latency (`ms`) of one batch - - ThreadNum | Fluid | Anakin - :---: | :---: | :---: | - 1 | 42.7418 | 1.93589 - 2 | 42.7418 | 2.49537 - 6 | 42.7734 | 3.14332 - 10 | 43.0721 | 4.55329 - 12 | 42.8501 | 5.09893 - -- Throughput (`sentence/s`) - - ThreadNum | Fluid | Anakin - :---: | :---: | :---: | - 1 | 23 | 504 - 2 | 46 | 762 - 6 | 134 | 1393 - 10 | 218 | 1556 - 12 | 260 | 1541 - -### Chinese_ner model in E5-2650 v4 - -- Latency (`ms`) of one batch - - ThreadNum | Fluid | Anakin - :---: | :---: | :---: | - 1 | 0.380475 | 0.17034 - 4 | 0.380475 | 0.171143 - 6 | 0.380475 | 0.172688 - 10 | 0.380475 | 0.173269 - 12 | 0.380475 | 0.17668 - -- Throughput (`sentence/s`) - - ThreadNum | Fluid | Anakin - :---: | :---: | :---: | - 1 | 7844 | 5822 - 4 | 7844 | 11377 - 6 | 7844 | 29725 - 10 | 7844 | 41238 - 12 | 7844 | 42790 - -### text_classfication model in E5-2650 v4 - -- Latency (`ms`) of one batch - - ThreadNum | Fluid | Anakin - :---: | :---: | :---: | - 1 | 1.48578 | 1.10088 - 4 | 1.54025 | 1.11258 - 6 | 1.68529 | 1.1257 - 10 | 1.9817 | 1.13267 - 12 | 2.21864 | 1.1429 - -- Throughput (`sentence/s`) - - ThreadNum | Fluid | Anakin - :---: | :---: | :---: | - 1 | 673 | 901 - 4 | 1289 | 1665 - 6 | 3458 | 4449 - 10 | 4875 | 6183 - 12 | 5265 | 6188 - ## How to run those Benchmark models? > 1. You can just run `sh benchmark_tensorflow.sh` and `sh benchmark_anakin.sh` diff --git a/cmake/compiler_options.cmake b/cmake/compiler_options.cmake index 6d0881545..835b7d884 100644 --- a/cmake/compiler_options.cmake +++ b/cmake/compiler_options.cmake @@ -41,6 +41,8 @@ anakin_add_compile_option(-Wshadow) anakin_add_compile_option(-fpermissive) anakin_add_compile_option(-Wsign-promo) anakin_add_compile_option(-fdiagnostics-show-option) +anakin_add_compile_option(-Wno-missing-field-initializers) +anakin_add_compile_option(-Wno-extra) if(ENABLE_NOISY_WARNINGS) anakin_add_compile_option(-Wcast-align) diff --git a/docs/Manual/Converter_ch.md b/docs/Manual/Converter_ch.md index f8573f2f8..afeb37181 100644 --- a/docs/Manual/Converter_ch.md +++ b/docs/Manual/Converter_ch.md @@ -13,8 +13,8 @@ Anakin 模型转换器输入支持 Caffe 和 Fluid 两种格式的预测模型 ## 系统要求 -- Python 2.7+ -- Protobuf 3.1+(务必注意 Python 与系统环境 Protobuf 版本一致) +- Python 2.7 +- Protobuf 3.1+(务必注意 Pip Protobuf 与系统环境 Protobuf 版本一致) - PaddlePaddle 0.12.0+ (Fluid 模式下) - flask, bson, matplotlib, scikit-image - tkinter diff --git a/docs/Manual/DesignConverter_ch.md b/docs/Manual/DesignConverter_ch.md new file mode 100644 index 000000000..7031c034e --- /dev/null +++ b/docs/Manual/DesignConverter_ch.md @@ -0,0 +1,56 @@ +# Parser的编写指南 +下文称Anakin为AK,运算操作为OP,本文参考Tensorflow的Parser编写,参考代码目录为tools/external_converter_v2/parser/tensorflow +## Parser的功能和执行流程 +功能是将其他深度学习框架(如CAFFE,FLUID,TENSORFLOW,ONNEX)的模型转换为AK的模型.对AK的作用是屏蔽不同框架间的差异,这种差异包括模型存储、OP的定义、图差异 +因此Parser的执行流程是: +1. 将源框架的模型载入Parser +2. 将原框架的图解析为AK中的OP节点和OP节点的连接关系 +3. 进行OP定义的转换和图优化 +4. 将符合AK标准的图写入protobuf +## Parser的目录结构 +Parser工具在tools/external_converter_v2/parser目录下 +Parser的目录主要包含3部分: +1. Parser的运行配置文件包括 config.py, config.yaml, converter.py, 用户只用执行converter.py,Parser就会按照config.yaml中的声明去解析模型 +2. Parser的公共定义,包括operations,pbs,proto三个目录. Parser的公共工具函数 graph*.py logger.py utils.py +3. 各个框架对应的Parser,其目录的命名方式为框架名,如caffe, tensorflow +## Parser的编写流程 +### 1、声明你的Parser +1. 在config.yaml中填写你的Parser运行的必要信息,包括ProtoPath和SavePath等.OPTIONS/Framework改为你的Parser的类型,TARGET下填写对应的参数列表 +2. 添加你的Parser目录,如tensorflow,导出你的Parser符号.注意,Parser的框架默认调用你的Parser类中的__call__方法来执行解析,这个方法需要返回填写完毕的GraphProtoIO对象 +3. 在config.py中Configuration下__init__函数中增加对你的Parser的调用,将yaml中读取的配置信息传给你的Parser,此处调用你的Parser中的__init__方法 +### 2、添加你的Parser主体 +可以参考parser_tf.py +1. 你需要在Parser主体构造时获取模型路径,input,ouput名字等解析必须的信息, +2. 在__call__中返回填写好的GraphProtoIO对象,该对象为填写protobuf的辅助工具 +3. 建议Parser的解析过程分成三部分,先将原框架的模型载入并转换为一种便于修改的中间的图形式;对中间图修改使得图满足AK的要求;将满足要求的中间图利用NodeProtoIO和GraphProtoIO这两个辅助类填入protobuf.具体细节可以参考parser_tf +### 3、读取原始模型,并将模型转换为中间类型 +可以参考parse_tf_2_med.py +1. 这一步与原始框架结合紧密,你可能需要import原始框架的工具函数来完成模型的裁剪、固定、加载等操作 +2. 大部分的框架都是使用tensor来连接OP的,但AK中是OP直接相连,这点需要注意 +3. AK的shape默认是4维的,有的参数的shape不足4维,需要Parser补全 +### 4、对中间类型的图进行优化 +可以参考med_graph.py +1. 由于AK不支持普通OP多输出的情况,需要在多输出的OP后面补上Splite类型的OP节点 +2. 对于Convlution后接Batchnorm这种可以合并又不会导致OP定义改变的情况,需要Parser在这一步做掉 +3. AK规定所有的输入类型OP的名字必须是input_x这种命名方式,其中x为从0开始的数字 +### 5、将中间类型的图以GraphProtoIO的方式保存 +可以参考parse_med_2_ak.py 和 parser_tf.py +1. 你首先需要构造Node节点,Node节点的名字是OP的名字(如conv2d_1_a_0),Node节点中OP成员变量的名字是Node节点的类型(如Convlution) +2. Node节点需要按照输入的顺序用Node的add_in方法填写输入Node的名字,add_out方法按顺序填写输出Node的名字 +3. 通过调用GraphProtoIO的add_node方法将构造好的Node的__call__方法的返回值作为参数,将Node节点加入AK的graph中 +4. 调用GraphProtoIO的add_in_edge和add_out_edge完成AK图中OP间关系的构建. 如果Node中的in和out填写正确,你也可以通过调用GraphProtoIO的format_edge_from_nodes方法完成这个工作 +5. AK的模型需要Parser给出输出Node的名字,使用GraphProtoIO的add_out方法填写输出Node的名字 +### 6、检查模型解析的正确性 +1. 默认的config.yaml配置会在解析结束后启动一个web服务器展示解析后的AK模型图,你需要对比原框架的模型图进行验证.这里最容易出现的错误是边关系的错误,表现为图非常乱,你需要逐条边地检查错误.第二个容易出错的地方是参数漏填,需要你检查OP中的属性 +2. 将解析后的模型放入AK中执行,使用相同的输入,原框架与AK有相同的输出.若果输出不一致可以开启AK的DEBUG模式,在net.cpp中将没层的输出打印.如果AK在解析阶段陷入死循环,大概率是边的关系出错. +## 如何添加新OP +1. 需要在AK代码中加入该OP的实现,包括对应设备Saber的OP,Saber单测和Framework中的OP +2. 根据Framework的OP在ops.py中添加Parser公共的OP定义 +3. 从原框架的模型中解析出该OP的节点,并在AK的graph中填入该OP节点 +## AK模型与其他框架模型的不同之处 ++ AK模型与CAFFE的模型相似,因此与其他模型有很多不同的地方,需要Parser在解析过程中处理掉. ++ 最大的不同是与FLUID或TENSORFLOW这种OP粒度很细的框架,AK的模型中OP的粒度很粗,这是为了节省访存开销.这会导致解析这些框架的模型时存在大量的合并操作. ++ 其次是OP的行为不同,如TENSORFLOW中Pooling默认都是exclusive的,而AK中是inclusive的.TENSORFLOW的Padding如果是奇数pad则在右方和下方多pad,AK是在左方和上方多Pad ++ AK默认的布局是NCHW,如果其他框架的OP是其他形式的,需要在Parser中做weights的布局转换,并处理reshape的问题. ++ AK中有的weights是需要预先做布局转换的(如GRU,LSTM).AK中也支持同一OP的不同算法,如(GRU,Pooling). + diff --git a/docs/Manual/INSTALL_ch.md b/docs/Manual/INSTALL_ch.md index 16b13cd9e..40c95392f 100644 --- a/docs/Manual/INSTALL_ch.md +++ b/docs/Manual/INSTALL_ch.md @@ -43,7 +43,7 @@ #### Anakin - CPU ### -在编译 CPU 版本前,我们建议您升级 GCC-G++ 至 5.4.0 以上,链接的 libm.so 库版本高于 2.17,以发挥更佳性能。 +在编译 CPU 版本前,我们建议您升级 GCC-G++ 至 5.4.0,链接的 libm.so 库版本为 2.17 ~ 2.23,以发挥更佳性能。 #### Anakin - AMDGPU ### diff --git a/framework/core/net/net.cpp b/framework/core/net/net.cpp index c972c0c26..c39fb8938 100755 --- a/framework/core/net/net.cpp +++ b/framework/core/net/net.cpp @@ -393,9 +393,11 @@ void Net::prediction() { #define RECORD_INNER #if defined(RECORD_INNER) && defined(USE_X86_PLACE) record_tensor_to_file(*out,("record_"+executer.name).c_str()); - if(executer.name=="") #endif LOG(INFO) <data(); +#ifdef USE_CUDA + record_tensor_to_file(*out,("record_"+executer.name).c_str()); +#endif #ifdef USE_X86_PLACE // for (int i = 0; i < 10; ++i) { // std::cout << out->data()[i]<<" "; diff --git a/framework/graph/graph.cpp b/framework/graph/graph.cpp index f8ca3183f..8832b15ca 100644 --- a/framework/graph/graph.cpp +++ b/framework/graph/graph.cpp @@ -40,6 +40,21 @@ Status Graph::load(std::string model_path) EXCLUSIVE_LOCKS_ return ret; } +template +Status Graph::load(const char* buffer, size_t len) EXCLUSIVE_LOCKS_REQUIRED(_mut) { + std::unique_lock lock(this->_mut); + Status ret = Status::OK(); + if(len != _len || buffer != _buffer) { + this->Clean(); + ret = parser::load(this, buffer, len); + _buffer = buffer; + _len = len; + } + + return ret; +} + + template Status Graph::load(const char* model_path) { return parser::load(this, model_path); diff --git a/framework/graph/graph.h b/framework/graph/graph.h index e456a461e..5ae9dea27 100644 --- a/framework/graph/graph.h +++ b/framework/graph/graph.h @@ -71,6 +71,8 @@ class Graph : public GraphBase_mut); /// this make the graph optimized. bool _has_graph_optimized{false}; GUARDED_BY(this->_mut); + + const char* _buffer{NULL} GUARDED_BY(this->_mut); + size_t _len{0} GUARDED_BY(this->_mut); std::mutex _mut; }; diff --git a/framework/model_parser/parser/parser.cpp b/framework/model_parser/parser/parser.cpp index 540abdb4c..c0ff9ba6a 100644 --- a/framework/model_parser/parser/parser.cpp +++ b/framework/model_parser/parser/parser.cpp @@ -22,8 +22,29 @@ Status load(graph::Graph* graph, std::string& model_path) { return load(graph, model_path.c_str()); } -template -Status load(graph::Graph* graph, const char* model_path) { +Status parse_graph_proto(GraphProto& graph_proto, const char* buffer, size_t len) { + google::protobuf::io::ArrayInputStream* raw_input = new google::protobuf::io::ArrayInputStream(buffer, len); + google::protobuf::io::CodedInputStream* coded_input = new google::protobuf::io::CodedInputStream(raw_input); + coded_input->SetTotalBytesLimit(INT_MAX, 536870912); + bool success = graph_proto.ParseFromCodedStream(coded_input) && coded_input->ConsumedEntireMessage(); + if (!success) { + LOG(FATAL) << " Parsing GraphProto " << " ERROR"; + } + + delete coded_input; + delete raw_input; + return Status::OK(); +} + +Status parse_graph_proto(GraphProto& graph_proto, std::istream* instream){ + if (!graph_proto.ParseFromIstream(instream)) { + DLOG(ERROR) << "Fail to parse GraphProto."; + return Status::FAIL("Fail to parse GraphProto."); + } + return Status::OK(); +} + +Status parse_graph_proto(GraphProto& graph_proto, const char* model_path) { #if 0 std::fstream input(model_path, std::ios::in | std::ios::binary); @@ -41,7 +62,6 @@ Status load(graph::Graph* graph, const char* model_path) { } #else - GraphProto graph_proto; int file_descriptor = open(model_path, O_RDONLY); if (file_descriptor == -1) { @@ -65,7 +85,13 @@ Status load(graph::Graph* graph, const char* model_path) { delete coded_input; delete raw_input; close(file_descriptor); + return Status::OK(); #endif +} + +template +Status generate_graph_with_graph_proto(graph::Graph* graph, GraphProto& graph_proto) { + // fill the graph with name LOG(INFO) << "graph name: " << graph_proto.name(); graph->set_name(graph_proto.name()); @@ -158,87 +184,26 @@ Status load(graph::Graph* graph, const char* model_path) { } template -Status load(graph::Graph* graph, std::istream* instream) { - +Status load(graph::Graph* graph, const char* model_path) { GraphProto graph_proto; + parse_graph_proto(graph_proto, model_path); + return generate_graph_with_graph_proto(graph, graph_proto); +} - // parsing GraphProto from model - if (!graph_proto.ParseFromIstream(instream)) { - DLOG(ERROR) << "Fail to parse GraphProto."; - return Status::FAIL("Fail to parse GraphProto."); - } - - // fill the graph with name - LOG(INFO) << "graph name: " << graph_proto.name(); - graph->set_name(graph_proto.name()); - - // fill the graph with ins/outs - for (int i = 0; i < graph_proto.ins().size(); i++) { - LOG(INFO) << "graph in: " << graph_proto.ins()[i]; - std::string in_name(graph_proto.ins()[i]); - graph->add_in(in_name); - } - - for (int i = 0; i < graph_proto.outs().size(); i++) { - LOG(INFO) << "graph out: " << graph_proto.outs()[i]; - std::string out_name(graph_proto.outs()[i]); - graph->add_out(out_name); - } - - // fill the graph with nodes - NodeIO node_io; - - for (int i = 0; i < graph_proto.nodes().size(); i++) { - node_io >> graph_proto.nodes()[i]; - } - - node_io << *graph; - - // fill the graph with edges - auto it_in = graph_proto.edges_in().begin(); - - for (; it_in != graph_proto.edges_in().end(); ++it_in) { - DLOG(WARNING) << " Parsing in edges of node : " << it_in->first; - auto& key = it_in->first; - auto& second = it_in->second; - - for (int i = 0; i < second.val().size(); i++) { - //Tensor4dPtr tensor_p = std::make_shared>(); - graph::Edge edge(second.val()[i], key); - //edge.weight() = new Tensor4d(); - //edge.weight() = std::make_shared >(); - edge.shared() = (*graph_proto.mutable_edges_info())[edge.name()].shared(); - edge.share_from() = (*graph_proto.mutable_edges_info())[edge.name()].share_from(); - graph->add_in_arc(edge); - } - } - - auto it_out = graph_proto.edges_out().begin(); - - for (; it_out != graph_proto.edges_out().end(); ++it_out) { - auto& key = it_out->first; - auto& second = it_out->second; +template +Status load(graph::Graph* graph, std::istream* instream) { - for (int i = 0; i < second.val().size(); i++) { - //Tensor4dPtr tensor_p = std::make_shared>(); - graph::Edge edge(key, second.val()[i]); - //edge.weight() = new Tensor4d(); - //edge.weight() = std::make_shared >(); - edge.shared() = (*graph_proto.mutable_edges_info())[edge.name()].shared(); - edge.share_from() = (*graph_proto.mutable_edges_info())[edge.name()].share_from(); - graph->add_out_arc(edge); - } - } + GraphProto graph_proto; + parse_graph_proto(graph_proto, instream); + return generate_graph_with_graph_proto(graph, graph_proto);; +} - // fill the graph with info (only use the key value: is_optimized) - graph->statistics.template set_info(graph_proto.summary().is_optimized()); - graph->statistics.template set_info(graph_proto.summary().temp_mem_used()); - graph->statistics.template set_info - (graph_proto.summary().original_temp_mem_used()); - graph->statistics.template set_info(graph_proto.summary().system_mem_used()); - graph->statistics.template set_info(graph_proto.summary().model_mem_used()); +template +Status load(graph::Graph* graph, const char* buffer, size_t len) { - return Status::OK(); + GraphProto graph_proto; + parse_graph_proto(graph_proto, buffer, len); + return generate_graph_with_graph_proto(graph, graph_proto);; } template @@ -382,6 +347,25 @@ Status save(graph::Graph(graph::Graph* graph, const char* model_path); + +template +Status load(graph::Graph* graph, + const char* buffer, size_t len); +template +Status load(graph::Graph* graph, + const char* buffer, size_t len); +template +Status load(graph::Graph* graph, + const char* buffer, size_t len); + +template +Status generate_graph_with_graph_proto(graph::Graph* graph, GraphProto& graph_proto); + +template +Status generate_graph_with_graph_proto(graph::Graph* graph, GraphProto& graph_proto); + +template +Status generate_graph_with_graph_proto(graph::Graph* graph, GraphProto& graph_proto); #endif #if defined(USE_X86_PLACE) || defined(BUILD_LITE) @@ -434,6 +418,23 @@ Status save(graph::Graph(graph::Graph* graph, const char* model_path); + +template +Status load(graph::Graph* graph, + const char* buffer, size_t len); +template +Status load(graph::Graph* graph, + const char* buffer, size_t len); +template +Status load(graph::Graph* graph, + const char* buffer, size_t len); + +template +Status generate_graph_with_graph_proto(graph::Graph* graph, GraphProto& graph_proto); +template +Status generate_graph_with_graph_proto(graph::Graph* graph, GraphProto& graph_proto); +template +Status generate_graph_with_graph_proto(graph::Graph* graph, GraphProto& graph_proto); #endif #ifdef USE_ARM_PLACE @@ -453,6 +454,13 @@ Status load(graph::Graph(graph::Graph* graph, const char* model_path); + +template +Status load(graph::Graph* graph, + const char* buffer, size_t len); + +template +Status generate_graph_with_graph_proto(graph::Graph* graph, GraphProto& graph_proto); #endif #ifdef ANAKIN_TYPE_FP16 @@ -472,6 +480,13 @@ Status load(graph::Graph(graph::Graph* graph, const char* model_path); + +template +Status load(graph::Graph* graph, + const char* buffer, size_t len); + +template +Status generate_graph_with_graph_proto(graph::Graph* graph, GraphProto& graph_proto); #endif #ifdef ANAKIN_TYPE_INT8 @@ -490,6 +505,13 @@ Status load(graph::Graph(graph::Graph* graph, const char* model_path); + +template +Status load(graph::Graph* graph, + const char* buffer, size_t len); + +template +Status generate_graph_with_graph_proto(graph::Graph* graph, GraphProto& graph_proto); #endif #endif //USE_ARM_PLACE diff --git a/framework/model_parser/parser/parser.h b/framework/model_parser/parser/parser.h index b200bf00e..9d442b916 100644 --- a/framework/model_parser/parser/parser.h +++ b/framework/model_parser/parser/parser.h @@ -36,6 +36,9 @@ Status load(graph::Graph* graph, const char* model_path); template Status load(graph::Graph* graph, std::istream* instream); +template +Status load(graph::Graph* graph, const char* buffer, size_t len); + //! save graph to disk. use to save improved Graph. template Status save(graph::Graph* graph, std::string& model_path); diff --git a/framework/operators/fusion_ops/conv_3x3_batchnorm_scale_relu.cpp b/framework/operators/fusion_ops/conv_3x3_batchnorm_scale_relu.cpp index 0d6d6ee8a..0094f46fe 100644 --- a/framework/operators/fusion_ops/conv_3x3_batchnorm_scale_relu.cpp +++ b/framework/operators/fusion_ops/conv_3x3_batchnorm_scale_relu.cpp @@ -88,12 +88,17 @@ Status SassConvBatchnormScaleReluHelper::InitParam() { // get relu param auto alpha = GET_PARAMETER(float, relu_0_alpha); - ActivationParam> active_param(Active_relu);//, alpha); // TEMP - - - ConvActiveParam> conv_act_param(_conv_param, active_param, batchnorm_param, - scale_param); - _param_conv_batchnorm_scale_relu = conv_act_param; + if (alpha != 0) { + ActivationParam> active_param(Active_prelu, alpha); // TEMP + ConvActiveParam> conv_act_param(_conv_param, active_param, batchnorm_param, + scale_param); + _param_conv_batchnorm_scale_relu = conv_act_param; + } else { + ActivationParam> active_param(Active_relu); // TEMP + ConvActiveParam> conv_act_param(_conv_param, active_param, batchnorm_param, + scale_param); + _param_conv_batchnorm_scale_relu = conv_act_param; + } return Status::OK(); } @@ -102,8 +107,13 @@ template Status SassConvBatchnormScaleReluHelper::Init(OpContext& ctx, const std::vector >& ins, std::vector >& outs) { - _funcs_conv_batchnorm_scale_relu.init(ins, outs, _param_conv_batchnorm_scale_relu, SPECIFY, - SABER_IMPL, ctx); + if (_param_conv_batchnorm_scale_relu.activation_param.active == Active_relu) { + _funcs_conv_batchnorm_scale_relu.init(ins, outs, _param_conv_batchnorm_scale_relu, SPECIFY, + SABER_IMPL, ctx); + } else { + _funcs_conv_batchnorm_scale_relu.init(ins, outs, _param_conv_batchnorm_scale_relu, SPECIFY, + VENDER_IMPL, ctx); + } return Status::OK(); } diff --git a/framework/operators/fusion_ops/conv_batchnorm_scale_relu.cpp b/framework/operators/fusion_ops/conv_batchnorm_scale_relu.cpp index b8a83269d..f8ffe978e 100644 --- a/framework/operators/fusion_ops/conv_batchnorm_scale_relu.cpp +++ b/framework/operators/fusion_ops/conv_batchnorm_scale_relu.cpp @@ -83,12 +83,19 @@ Status ConvBatchnormScaleReluHelper::InitParam() { // get relu param auto alpha = GET_PARAMETER(float, relu_0_alpha); - ActivationParam> active_param(Active_relu);//, alpha); // TEMP + if (alpha != 0) { + ActivationParam> active_param(Active_prelu, alpha); // TEMP + ConvActiveParam> conv_act_param(_conv_param, active_param, batchnorm_param, + scale_param); + _param_conv_batchnorm_scale_relu = conv_act_param; + } else { + ActivationParam> active_param(Active_relu); // TEMP + ConvActiveParam> conv_act_param(_conv_param, active_param, batchnorm_param, + scale_param); + _param_conv_batchnorm_scale_relu = conv_act_param; + } - ConvActiveParam> conv_act_param(_conv_param, active_param, batchnorm_param, - scale_param); - _param_conv_batchnorm_scale_relu = conv_act_param; return Status::OK(); } @@ -115,7 +122,9 @@ Status ConvBatchnormScaleReluHelper::InferShape(const template <> Status ConvBatchnormScaleReluHelper::Init(OpContext &ctx, \ const std::vector >& ins, std::vector >& outs) { - if (_param_conv_batchnorm_scale_relu.conv_param.group == ins[0]->channel() && \ + bool use_saber = true; + use_saber = use_saber && (_param_conv_batchnorm_scale_relu.activation_param.active == Active_relu); + if (use_saber && _param_conv_batchnorm_scale_relu.conv_param.group == ins[0]->channel() && \ _param_conv_batchnorm_scale_relu.conv_param.group == outs[0]->channel()) { _funcs_conv_batchnorm_scale_relu.init(ins, outs, _param_conv_batchnorm_scale_relu, SPECIFY, SABER_IMPL, ctx); diff --git a/framework/operators/fusion_ops/conv_relu.cpp b/framework/operators/fusion_ops/conv_relu.cpp index da44143f4..757d9f901 100644 --- a/framework/operators/fusion_ops/conv_relu.cpp +++ b/framework/operators/fusion_ops/conv_relu.cpp @@ -62,11 +62,16 @@ Status ConvReluHelper::InitParam() { // get relu param auto alpha = GET_PARAMETER(float, relu_0_alpha); - ActivationParam> active_param(Active_relu);//, alpha); // TEMP - + if (alpha != 0) { + ActivationParam> active_param(Active_prelu, alpha); // TEMP + ConvActiveParam> conv_act_param(_conv_param, active_param); + _param_conv_relu = conv_act_param; + } else { + ActivationParam> active_param(Active_relu); // TEMP + ConvActiveParam> conv_act_param(_conv_param, active_param); + _param_conv_relu = conv_act_param; + } - ConvActiveParam> conv_act_param(_conv_param, active_param); - _param_conv_relu = conv_act_param; return Status::OK(); @@ -100,6 +105,7 @@ Status ConvReluHelper::Init(OpContext& ctx, \ use_saber = use_saber && (_param_conv_relu.conv_param.weight()->width()==3); use_saber = use_saber && (_param_conv_relu.conv_param.dilation_h == 1); use_saber = use_saber && (_param_conv_relu.conv_param.dilation_w == 1); + use_saber = use_saber && (_param_conv_relu.activation_param.active == Active_relu); if (((_param_conv_relu.conv_param.group == 1) && use_saber)|| (_param_conv_relu.conv_param.group == ins[0]->channel() && \ _param_conv_relu.conv_param.group == outs[0]->channel())) { _funcs_conv_relu.init(ins, outs, _param_conv_relu, SPECIFY, SABER_IMPL, ctx); diff --git a/framework/operators/normalize.cpp b/framework/operators/normalize.cpp index 56cfa921c..db8ba69de 100644 --- a/framework/operators/normalize.cpp +++ b/framework/operators/normalize.cpp @@ -32,12 +32,16 @@ Status NormalizeHelper::InitParam() { auto eps = GET_PARAMETER(float, eps); auto p = GET_PARAMETER(int, p); - using pblock_type = PBlock::type, Ttype>; - auto input_scale = GET_PARAMETER(pblock_type, weight_1); - - saber::NormalizeParam> normalize_param(is_across_spatial, is_shared_channel, \ - &(input_scale.d_tensor()), eps, p); - _param_normalize = normalize_param; + if (FIND_PARAMETER(weight_1)) { + using pblock_type = PBlock::type, Ttype>; + auto input_scale = GET_PARAMETER(pblock_type, weight_1); + saber::NormalizeParam> normalize_param(is_across_spatial, is_shared_channel, \ + &(input_scale.d_tensor()), eps, p); + _param_normalize = normalize_param; + } else { + saber::NormalizeParam> normalize_param(is_across_spatial, is_shared_channel, eps, p); + _param_normalize = normalize_param; + } return Status::OK(); } diff --git a/framework/operators/ops.h b/framework/operators/ops.h index 046b80b37..5bd3d20e6 100644 --- a/framework/operators/ops.h +++ b/framework/operators/ops.h @@ -54,6 +54,7 @@ #include "framework/operators/priorbox.h" #include "framework/operators/relu.h" #include "framework/operators/reshape.h" +#include "framework/operators/resize.h" #include "framework/operators/scale.h" #include "framework/operators/sequence_pool.h" #include "framework/operators/slice.h" diff --git a/framework/operators/resize.cpp b/framework/operators/resize.cpp new file mode 100644 index 000000000..773f206b3 --- /dev/null +++ b/framework/operators/resize.cpp @@ -0,0 +1,91 @@ +#include "framework/operators/resize.h" + +namespace anakin { + +namespace ops { + +#define INSTANCE_RESIZE(Ttype, Dtype, Ptype) \ +template<> \ +void Resize::operator()(OpContext& ctx, \ + const std::vector >& ins,\ + std::vector >& outs) { \ + auto* impl = \ + static_cast*>(this->_helper); \ + auto& param = impl->_param_resize; \ + impl->_funcs_resize(ins, outs, param, ctx); \ +} + + +template +Status ResizeHelper::InitParam() { + DLOG(WARNING) << "Parsing Resize op parameter."; + + // get resize param + auto width_scale = GET_PARAMETER(float, width_scale); + auto height_scale = GET_PARAMETER(float, height_scale); + + ResizeParam> resize_param(height_scale, width_scale); + _param_resize = resize_param; + return Status::OK(); +} + +template +Status ResizeHelper::Init(OpContext &ctx, const std::vector> &ins, + std::vector> &outs) { + SABER_CHECK(_funcs_resize.init(ins, outs, _param_resize, SPECIFY, SABER_IMPL, ctx)); + return Status::OK(); +} + +template +Status ResizeHelper::InferShape(const std::vector> &ins, + std::vector> &outs) { + SABER_CHECK(_funcs_resize.compute_output_shape(ins, outs, _param_resize)); + return Status::OK(); +} + +#ifdef USE_CUDA +INSTANCE_RESIZE(NV, AK_FLOAT, Precision::FP32); +template <> +Status ResizeHelper::Init(OpContext &ctx, + const std::vector >& ins, + std::vector >& outs) { + SABER_CHECK(_funcs_resize.init(ins, outs, _param_resize, SPECIFY, SABER_IMPL, ctx)); + return Status::OK(); +} +ANAKIN_REGISTER_OP_HELPER(Resize, ResizeHelper, NV, AK_FLOAT, Precision::FP32); +#endif + +#ifdef USE_X86_PLACE +INSTANCE_RESIZE(X86, AK_FLOAT, Precision::FP32); +template class ResizeHelper; +ANAKIN_REGISTER_OP_HELPER(Resize, ResizeHelper, X86, AK_FLOAT, Precision::FP32); +#endif + +#ifdef USE_ARM_PLACE +INSTANCE_RESIZE(ARM, AK_FLOAT, Precision::FP32); +template class ResizeHelper; +ANAKIN_REGISTER_OP_HELPER(Resize, ResizeHelper, ARM, AK_FLOAT, Precision::FP32); +#endif//arm + +//! register op +ANAKIN_REGISTER_OP(Resize) +.Doc("Resize operator") +#ifdef USE_CUDA +.__alias__("Resize") +#endif +#ifdef USE_ARM_PLACE +.__alias__("Resize") +#endif +#ifdef USE_X86_PLACE +.__alias__("Resize") +#endif +.num_in(1) +.num_out(1) +.Args("height_scale", " height scale for resize") +.Args("width_scale", " width scale for resize"); + +} /* namespace ops */ + +} /* namespace anakin */ + + diff --git a/framework/operators/resize.h b/framework/operators/resize.h new file mode 100644 index 000000000..4d6a5a7ef --- /dev/null +++ b/framework/operators/resize.h @@ -0,0 +1,99 @@ +/* Copyright (c) 2018 Anakin Authors, Inc. 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. +*/ + +#ifndef ANAKIN_OPERATOR_RESIZE_H +#define ANAKIN_OPERATOR_RESIZE_H + +#include "framework/core/base.h" +#include "framework/core/data_types.h" +#include "framework/core/operator/operator.h" +#include "utils/logger/logger.h" +#include "saber/funcs/resize.h" + +namespace anakin { + +namespace ops { + +template +class ResizeHelper; + +/// pooling op +/** + * \brief Resize implementation class + * public inherit Operator + */ +template +class Resize : public Operator { +public: + Resize() {} + + /// forward impl + virtual void operator() (OpContext &ctx, + const std::vector >& ins, + std::vector >& outs) { + LOG(ERROR) << "Not Impl Yet Operator power::type>().type_info()<<">"; + } + + friend class ResizeHelper; +}; + +/** + * \brief Resize helper class to implement Resize + * public inherit OperatorHelper + * including init resource and shape size in Resize context + */ +template +class ResizeHelper : public OperatorHelper { +public: + ResizeHelper()=default; + + ~ResizeHelper() {} + + Status InitParam() override; + + /** + * \brief initial all the resource needed by pooling + * \param ctx stand for Resize operation context + * \param ins stand for input tensor vector + * \param outs stand for output tensor vector + * \return status + */ + Status Init(OpContext &ctx, + const std::vector >& ins, + std::vector >& outs) override; + + /** + * \brief infer the shape of output and input. + * \param ins stand for input tensor vector + * \param outs stand for output tensor vector + * \return status + */ + Status InferShape(const std::vector >& ins, + std::vector >& outs) override; + +public: + ///< _param_resize stand for Resize parameter + saber::ResizeParam> _param_resize; + ///< _funcs_resize stand for Resize function + saber::Resize _funcs_resize; + +}; + +} /* namespace ops */ + +} /* namespace anakin */ + +#endif diff --git a/saber/funcs/impl/cuda/base/cuda_c/saber_activation.cu b/saber/funcs/impl/cuda/base/cuda_c/saber_activation.cu index 9f2c42b92..229e7802d 100644 --- a/saber/funcs/impl/cuda/base/cuda_c/saber_activation.cu +++ b/saber/funcs/impl/cuda/base/cuda_c/saber_activation.cu @@ -175,6 +175,34 @@ __global__ void ker_prelu_fwd(Dtype * out_data, } } +template +__global__ void ker_prelu_fwd(Dtype * out_data, + const Dtype* in_data, const int count, + const Dtype slope, bool is_channel_shared, + int in_n, int in_c, int in_h, int in_w, + int in_n_stride, int in_c_stride, int in_h_stride, int in_w_stride, + int out_n_stride, int out_c_stride, int out_h_stride, int out_w_stride) { + CUDA_KERNEL_LOOP(tid, count){ + int w = tid % in_w; + int h = (tid / (in_w)) % in_h; + int c = (tid / (in_h * in_w)) % in_c; + int n = (tid / (in_c * in_h * in_w)) % in_n; + + int in_idx = n * in_n_stride + + c * in_c_stride + + h * in_h_stride + + w * in_w_stride; + + int out_idx = n * out_n_stride + + c * out_c_stride + + h * out_h_stride + + w * out_w_stride; + + Dtype in_var = in_data[in_idx]; + out_data[out_idx] = in_var > 0 ? in_var : slope * in_var; + } +} + template <> SaberStatus SaberActivation::dispatch( \ @@ -248,12 +276,21 @@ SaberStatus SaberActivation - <<>>( - out_data, in_data, count, prelu_param.slope->data(), prelu_param.channel_shared, - in_shape[0], in_shape[1], in_shape[2], in_shape[3], - stride_in[0], stride_in[1], stride_in[2], stride_in[3], - stride_out[0], stride_out[1], stride_out[2], stride_out[3]); + if (param.prelu_param.slope == nullptr) { + ker_prelu_fwd + << < CUDA_GET_BLOCKS(count), CUDA_NUM_THREADS, 0, cuda_stream >> > ( + out_data, in_data, count, param.negative_slope, prelu_param.channel_shared, + in_shape[0], in_shape[1], in_shape[2], in_shape[3], + stride_in[0], stride_in[1], stride_in[2], stride_in[3], + stride_out[0], stride_out[1], stride_out[2], stride_out[3]); + } else { + ker_prelu_fwd + << < CUDA_GET_BLOCKS(count), CUDA_NUM_THREADS, 0, cuda_stream >> > ( + out_data, in_data, count, prelu_param.slope->data(), prelu_param.channel_shared, + in_shape[0], in_shape[1], in_shape[2], in_shape[3], + stride_in[0], stride_in[1], stride_in[2], stride_in[3], + stride_out[0], stride_out[1], stride_out[2], stride_out[3]); + } break; } diff --git a/saber/funcs/impl/cuda/base/cuda_c/saber_resize.cu b/saber/funcs/impl/cuda/base/cuda_c/saber_resize.cu index 5c2f4cbe1..6760c7f54 100644 --- a/saber/funcs/impl/cuda/base/cuda_c/saber_resize.cu +++ b/saber/funcs/impl/cuda/base/cuda_c/saber_resize.cu @@ -73,9 +73,9 @@ __global__ void resize_bilinear_2d_kernel(const int wout, const int hout, dtype br = (w > win || h > hin)? 0 : src[src_indexBR]; #else dtype tl = src[src_indexTL]; - dtype tr = w > win? 0 : src[src_indexTR];//w > win? 0 : - dtype bl = h > hin? 0 : src[src_indexBL];//h > hin? 0 : - dtype br = (w > win || h > hin)? 0 : src[src_indexBR];//(w > win || h > hin)? 0 : + dtype tr = w < win? src[src_indexTR]:0;//w > win? 0 : + dtype bl = h < hin? src[src_indexBL]:0;//h > hin? 0 : + dtype br = (w < win && h < hin) ? src[src_indexBR]: 0;//(w > win || h > hin)? 0 : #endif dst[dst_index] = static_cast(w_00 * tl + w_01 * tr + w_10 * bl + w_11 * br); src_indexBR += src_stride_c; @@ -152,19 +152,13 @@ SaberStatus SaberResizecount(height_idx + 1, dims); int dst_stride_channel = dst_real_shape.count(channel_idx + 1);//outputs[0]->count(channel_idx + 1, dims); int dst_stride_batch = dst_real_shape.count(num_idx + 1);//outputs[0]->count(num_idx + 1, dims); - const InDataType* in_data_batch = in_data; - OutDataType* out_data_batch = out_data; - for (int i = 0; i < n_out; ++i) { - resize_bilinear_2d_kernel<<>>( - w_out, h_out, n_out, c_out, - dst_stride_w, dst_stride_h, dst_stride_channel, dst_stride_batch, - w_in, h_in, - src_stride_w, src_stride_h, src_stride_channel, src_stride_batch, - 1 / param.width_scale, 1 / param.height_scale, - in_data, out_data); - in_data_batch += src_stride_batch; - out_data_batch += dst_stride_batch; - } + resize_bilinear_2d_kernel<<>>( + w_out, h_out, n_out, c_out, + dst_stride_w, dst_stride_h, dst_stride_channel, dst_stride_batch, + w_in, h_in, + src_stride_w, src_stride_h, src_stride_channel, src_stride_batch, + 1 / param.width_scale, 1 / param.height_scale, + in_data, out_data); //outputs[0]->record_event(stream); return SaberSuccess; } diff --git a/saber/funcs/impl/cuda/saber_activation.h b/saber/funcs/impl/cuda/saber_activation.h index a39004469..b799dec7b 100644 --- a/saber/funcs/impl/cuda/saber_activation.h +++ b/saber/funcs/impl/cuda/saber_activation.h @@ -65,7 +65,7 @@ class SaberActivation& inputs, std::vector& outputs, ActivationParam& param); - + OpTensor _slope; }; //template class SaberActivation; diff --git a/saber/funcs/impl/cuda/vender_conv_act.cpp b/saber/funcs/impl/cuda/vender_conv_act.cpp index 88bddf9ca..d973daef0 100644 --- a/saber/funcs/impl/cuda/vender_conv_act.cpp +++ b/saber/funcs/impl/cuda/vender_conv_act.cpp @@ -1,4 +1,5 @@ #include "saber/funcs/impl/cuda/vender_conv_act.h" +#include "saber/funcs/impl/cuda/saber_activation.h" #include "cuda_fp16.h" namespace anakin { @@ -10,6 +11,9 @@ SaberStatus VenderConv2DAct: std::vector& outputs, ConvActiveParam& param, Context& ctx) { + if (_use_saber_act) { + _saber_act.create(inputs, outputs, param.activation_param, ctx); + } if (!(&ctx == this->_ctx)) { if (_handle != NULL) { CUDNN_CHECK(cudnnDestroy(_handle)); @@ -65,7 +69,7 @@ SaberStatus VenderConv2DAct: inputs[0]->dims() - 2, pad_a, filter_stride_a, dilation_a); // set activation descriptor - if(param.has_active) { + if(param.has_active && !_use_saber_act) { cudnn::set_activation_des(&_active_descs, param.activation_param.active); } @@ -113,12 +117,11 @@ SaberStatus VenderConv2DAct: dispatch(const std::vector& inputs, std::vector& outputs, ConvActiveParam& param) { - const InDataType *in_data = (const InDataType*)inputs[0]->data(); InDataType *out_data = (InDataType*)outputs[0]->mutable_data(); const float *weight_data = (const float *) param.conv_param.weight()->data(); - if (param.has_active == false) { + if (_use_saber_act || param.has_active == false) { CUDNN_CHECK(cudnnConvolutionForward(_handle, cudnn::cudnnTypeWrapper::kOne(), _input_descs, in_data, @@ -140,6 +143,9 @@ SaberStatus VenderConv2DAct: _output_descs, out_data)); } + if (_use_saber_act) { + _saber_act.dispatch(outputs, outputs, param.activation_param); + } return SaberSuccess; } diff --git a/saber/funcs/impl/cuda/vender_conv_act.h b/saber/funcs/impl/cuda/vender_conv_act.h index ec72de353..965e6a5e5 100644 --- a/saber/funcs/impl/cuda/vender_conv_act.h +++ b/saber/funcs/impl/cuda/vender_conv_act.h @@ -17,7 +17,8 @@ #define ANAKIN_SABER_FUNCS_IMPL_CUDA_CUDNN_CONV_ACT_H #include "saber/funcs/impl/impl_conv_act.h" -#include "saber/funcs/impl/cuda/cudnn_helper.h" +#include "saber/funcs/impl/cuda/cudnn_helper.h" +#include "saber/funcs/impl/cuda/saber_activation.h" #include namespace anakin{ @@ -119,6 +120,10 @@ class VenderConv2DAct& outputs, ConvActiveParam& param, Context& ctx) { // ---- init cudnn resources ---- + if (param.activation_param.active!= Active_relu) { + _use_saber_act = true; + _saber_act.init(inputs, outputs, param.activation_param, ctx); + } _workspaceSizeInBytes = 0; _workspaceData = NULL; @@ -192,6 +197,9 @@ class VenderConv2DAct _saber_act; void *x8_data; void *y8_data; diff --git a/saber/saber_funcs_param.h b/saber/saber_funcs_param.h index c2c045cff..260caf1a8 100644 --- a/saber/saber_funcs_param.h +++ b/saber/saber_funcs_param.h @@ -1515,7 +1515,17 @@ struct NormalizeParam { eps = eps_in; CHECK_EQ(p == 2 || p == 1, true) << "only support L1 and L2 norm"; } + NormalizeParam(bool is_across_spatial, bool is_shared_channel, \ + float eps_in = 1e-6f, int pin = 2) { + across_spatial = is_across_spatial; + channel_shared = is_shared_channel; + p = pin; + has_scale = false; + scale = nullptr; + eps = eps_in; + CHECK_EQ(p == 2 || p == 1, true) << "only support L1 and L2 norm"; + } NormalizeParam(const NormalizeParam& right) { channel_shared = right.channel_shared; across_spatial = right.across_spatial; diff --git a/test/saber/cuda/test_saber_func_power.cpp b/test/saber/cuda/test_saber_func_power.cpp index 277157d73..05a9c1f1c 100644 --- a/test/saber/cuda/test_saber_func_power.cpp +++ b/test/saber/cuda/test_saber_func_power.cpp @@ -135,16 +135,16 @@ TEST(TestSaberFuncPowerNV, test_func_constructor) { PowerParam param(/*power*/1.0f, /*scale*/ float(5), /*shift*/0.0f); for (auto input_share : { - false, true + false }) { for (auto output_share : { - false, true + false }) { for (auto input_share_sub : { - false, true + false }) { for (auto output_share_sub : { - false, true + false }) { for (auto get_time : { false diff --git a/tools/external_converter_v2/config.py b/tools/external_converter_v2/config.py index 74b249674..538162457 100644 --- a/tools/external_converter_v2/config.py +++ b/tools/external_converter_v2/config.py @@ -3,6 +3,7 @@ # -*- coding: utf-8 -*- import os +import sys import subprocess from yaml import load, dump try: @@ -38,6 +39,8 @@ def __init__(self, config_file_path=ConfigFilePath): # parse TARGET info from config file. if self.framework == "CAFFE": proto_list = data['TARGET'][self.framework]['ProtoPaths'] + assert type(proto_list) == list, \ + "The ProtoPaths format maybe incorrect, please check if there is any HORIZONTAL LINE." self.__generate_pbs(proto_list) self.framework_config_dict = data['TARGET'][self.framework] elif self.framework == "PADDLE": @@ -58,9 +61,28 @@ def __init__(self, config_file_path=ConfigFilePath): except NameError: raise + def check_protobuf_version(self): + for path in sys.path: + module_path = os.path.join(path, 'google', 'protobuf', '__init__.py') + if os.path.exists(module_path): + with open(module_path) as f: + __name__ = '__main__' + exec(f.read(), locals()) + break + try: + protoc_out = subprocess.check_output(["protoc", "--version"]).split()[1] + except OSError as exc: + raise OSError('Can not find Protobuf in system environment.') + sys_versions = map(int, protoc_out.split('.')) + pip_versions = map(int, __version__.split('.')) + assert sys_versions[0] >= 3 and pip_versions[0] >= 3 , \ + "Protobuf version must be greater than 3.0. Please refer to the Anakin Docs." + assert pip_versions[1] >= sys_versions[1], \ + "ERROR: Protobuf must be the same.\nSystem Protobuf %s\nPython Protobuf %s\n" \ + % (protoc_out, __version__) + "Try to execute pip install protobuf==%s" % (protoc_out) + def generate_pbs_of_anakin(self): protoFilesStr = subprocess.check_output(["ls", "parser/proto/"]) - print(protoFilesStr) filesList = protoFilesStr.split('\n') protoFilesList = [] for file in filesList: @@ -78,6 +100,7 @@ def __generate_pbs(self, proto_list, default_save_path="parser/pbs/"): proto_list: ['/path/to/proto_0','/path/to/proto_1', ... ] default_save_path: default saved to 'parser/pbs/' """ + self.check_protobuf_version() for pFile in proto_list: subprocess.check_call(['protoc', '-I', os.path.dirname(pFile) + "/", diff --git a/tools/external_converter_v2/config.yaml b/tools/external_converter_v2/config.yaml index 2c00def1d..674774563 100644 --- a/tools/external_converter_v2/config.yaml +++ b/tools/external_converter_v2/config.yaml @@ -40,15 +40,14 @@ ##-------------------------------------------------------------- # OPTIONS: - Framework: TENSORFLOW - SavePath: /ak_model/save/path - ResultName: resnet50_v1 - + Framework: CAFFE + SavePath: ./output + ResultName: googlenet Config: LaunchBoard: ON Server: ip: 0.0.0.0 - port: 8889 + port: 8888 OptimizedGraph: enable: OFF path: /path/to/anakin_optimized/googlenet.anakin.bin.saved @@ -77,9 +76,9 @@ TARGET: ModelPath: TENSORFLOW: - ProtoPaths: /path/to/your/model/ - PrototxtPath: - ModelPath: + ProtoPaths: / + PrototxtPath: / + ModelPath: / OutPuts: ONNX: diff --git a/tools/external_converter_v2/parser/kill_caffe/.gitignore b/tools/external_converter_v2/parser/caffe/.gitignore similarity index 100% rename from tools/external_converter_v2/parser/kill_caffe/.gitignore rename to tools/external_converter_v2/parser/caffe/.gitignore diff --git a/tools/external_converter_v2/parser/kill_caffe/__init__.py b/tools/external_converter_v2/parser/caffe/__init__.py similarity index 100% rename from tools/external_converter_v2/parser/kill_caffe/__init__.py rename to tools/external_converter_v2/parser/caffe/__init__.py diff --git a/tools/external_converter_v2/parser/kill_caffe/caffe_helper.py b/tools/external_converter_v2/parser/caffe/caffe_helper.py similarity index 100% rename from tools/external_converter_v2/parser/kill_caffe/caffe_helper.py rename to tools/external_converter_v2/parser/caffe/caffe_helper.py diff --git a/tools/external_converter_v2/parser/kill_caffe/caffe_layer_param_transmit.py b/tools/external_converter_v2/parser/caffe/caffe_layer_param_transmit.py similarity index 93% rename from tools/external_converter_v2/parser/kill_caffe/caffe_layer_param_transmit.py rename to tools/external_converter_v2/parser/caffe/caffe_layer_param_transmit.py index 02043b7c7..f6a2a258e 100755 --- a/tools/external_converter_v2/parser/kill_caffe/caffe_layer_param_transmit.py +++ b/tools/external_converter_v2/parser/caffe/caffe_layer_param_transmit.py @@ -88,6 +88,17 @@ def Parser_concat(args): concat_param = layer.concat_param OpsRegister()["Concat"].axis = concat_param.axis +@ParserFeedDecorator("Resize") +def Parser_resize(args): + layer = args[1] + # parser caffe parameter + resize_param = layer.resize_param + if resize_param.HasField("out_width_scale"): + OpsRegister()["Resize"].width_scale = resize_param.out_width_scale + if resize_param.HasField("out_height_scale"): + OpsRegister()["Resize"].height_scale = resize_param.out_height_scale + + @ParserFeedDecorator("DeformConvolution") def Parser_deformable_convolution(args): @@ -721,6 +732,7 @@ def Parser_rpn_proposal_ssd(args): OpsRegister()["RPNProposalSSD"].nms_among_classes = nms_param.nms_among_classes OpsRegister()["RPNProposalSSD"].voting = list(nms_param.voting) OpsRegister()["RPNProposalSSD"].vote_iou = list(nms_param.vote_iou) + OpsRegister()["RPNProposalSSD"].nms_gpu_max_n_per_time = nms_param.nms_gpu_max_n_per_time # parsing gen_anchor_param pkg gen_anchor_param = detect_output_ssd.gen_anchor_param OpsRegister()["RPNProposalSSD"].base_size = gen_anchor_param.base_size @@ -825,6 +837,7 @@ def Parser_rcnn_net_output_with_attr(args): OpsRegister()["RCNNDetOutputWithAttr"].nms_among_classes = nms_param.nms_among_classes OpsRegister()["RCNNDetOutputWithAttr"].voting = list(nms_param.voting) OpsRegister()["RCNNDetOutputWithAttr"].vote_iou = list(nms_param.vote_iou) + OpsRegister()["RCNNDetOutputWithAttr"].nms_gpu_max_n_per_time = nms_param.nms_gpu_max_n_per_time # parsing gen_anchor_param pkg gen_anchor_param = detect_output_ssd.gen_anchor_param OpsRegister()["RCNNDetOutputWithAttr"].base_size = gen_anchor_param.base_size @@ -946,6 +959,7 @@ def Parser_rcnn_proposal(args): OpsRegister()["RCNNProposal"].nms_among_classes = nms_param.nms_among_classes OpsRegister()["RCNNProposal"].voting = list(nms_param.voting) OpsRegister()["RCNNProposal"].vote_iou = list(nms_param.vote_iou) + OpsRegister()["RCNNProposal"].nms_gpu_max_n_per_time = nms_param.nms_gpu_max_n_per_time # parsing gen_anchor_param pkg gen_anchor_param = detect_output_ssd.gen_anchor_param OpsRegister()["RCNNProposal"].base_size = gen_anchor_param.base_size @@ -1048,12 +1062,32 @@ def Parser_proposal_img_scale_to_cam_coords(args): OpsRegister()["ProposalImgScaleToCamCoords"].cords_offset_y = proposal_img_scale_to_cam_coords.cords_offset_y OpsRegister()["ProposalImgScaleToCamCoords"].bbox_size_add_one = proposal_img_scale_to_cam_coords.bbox_size_add_one OpsRegister()["ProposalImgScaleToCamCoords"].rotate_coords_by_pitch = proposal_img_scale_to_cam_coords.rotate_coords_by_pitch - OpsRegister()["ProposalImgScaleToCamCoords"].refine_coords_by_bbox = proposal_img_scale_to_cam_coords.refine_coords_by_bbox - OpsRegister()["ProposalImgScaleToCamCoords"].refine_min_dist = proposal_img_scale_to_cam_coords.refine_min_dist - OpsRegister()["ProposalImgScaleToCamCoords"].refine_dist_for_height_ratio_one = proposal_img_scale_to_cam_coords.refine_dist_for_height_ratio_one - OpsRegister()["ProposalImgScaleToCamCoords"].max_3d2d_height_ratio_for_min_dist = proposal_img_scale_to_cam_coords.max_3d2d_height_ratio_for_min_dist + #OpsRegister()["ProposalImgScaleToCamCoords"].refine_coords_by_bbox = proposal_img_scale_to_cam_coords.refine_coords_by_bbox + #OpsRegister()["ProposalImgScaleToCamCoords"].refine_min_dist = proposal_img_scale_to_cam_coords.refine_min_dist + #OpsRegister()["ProposalImgScaleToCamCoords"].refine_dist_for_height_ratio_one = proposal_img_scale_to_cam_coords.refine_dist_for_height_ratio_one + #OpsRegister()["ProposalImgScaleToCamCoords"].max_3d2d_height_ratio_for_min_dist = proposal_img_scale_to_cam_coords.max_3d2d_height_ratio_for_min_dist OpsRegister()["ProposalImgScaleToCamCoords"].with_trunc_ratio = proposal_img_scale_to_cam_coords.with_trunc_ratio + OpsRegister()["ProposalImgScaleToCamCoords"].regress_ph_rh_as_whole = proposal_img_scale_to_cam_coords.regress_ph_rh_as_whole + OpsRegister()["ProposalImgScaleToCamCoords"].real_h_means_as_whole = list(proposal_img_scale_to_cam_coords.real_h_means_as_whole) + OpsRegister()["ProposalImgScaleToCamCoords"].real_h_stds_as_whole = list(proposal_img_scale_to_cam_coords.real_h_stds_as_whole) +@ParserFeedDecorator("RoisAnchorFeature") +def Parser_rois_anchor_feature(args): + layer = args[1] + # parser caffe parameter + rois_anchor_feature_param = layer.rois_anchor_feature_param + OpsRegister()["RoisAnchorFeature"].min_anchor_size = rois_anchor_feature_param.min_anchor_size + OpsRegister()["RoisAnchorFeature"].num_anchor_scales = rois_anchor_feature_param.num_anchor_scales + OpsRegister()["RoisAnchorFeature"].anchor_scale_pow_base = rois_anchor_feature_param.anchor_scale_pow_base + OpsRegister()["RoisAnchorFeature"].anchor_wph_ratios = list(rois_anchor_feature_param.anchor_wph_ratios) + OpsRegister()["RoisAnchorFeature"].num_top_iou_anchor = rois_anchor_feature_param.num_top_iou_anchor + OpsRegister()["RoisAnchorFeature"].min_num_top_iou_anchor = rois_anchor_feature_param.min_num_top_iou_anchor + OpsRegister()["RoisAnchorFeature"].iou_thr = rois_anchor_feature_param.iou_thr + OpsRegister()["RoisAnchorFeature"].ft_ratio_h = rois_anchor_feature_param.ft_ratio_h + OpsRegister()["RoisAnchorFeature"].ft_ratio_w = rois_anchor_feature_param.ft_ratio_w + OpsRegister()["RoisAnchorFeature"].ft_log_ratio_h = rois_anchor_feature_param.ft_log_ratio_h + OpsRegister()["RoisAnchorFeature"].ft_log_ratio_w = rois_anchor_feature_param.ft_log_ratio_w + OpsRegister()["RoisAnchorFeature"].bbox_size_add_one = rois_anchor_feature_param.bbox_size_add_one @ParserFeedDecorator("Axpy") def Parser_axpy(args): @@ -1064,13 +1098,14 @@ def Parser_axpy(args): def Parser_priorbox(args): layer = args[1] prior_box_param = layer.prior_box_param - OpsRegister()["PriorBox"].min_size = list(prior_box_param.min_size) - OpsRegister()["PriorBox"].max_size = list(prior_box_param.max_size) - OpsRegister()["PriorBox"].aspect_ratio = list(prior_box_param.aspect_ratio) - OpsRegister()["PriorBox"].fixed_size = list(prior_box_param.fixed_size) - OpsRegister()["PriorBox"].fixed_ratio = list(prior_box_param.fixed_ratio) - OpsRegister()["PriorBox"].density = list(prior_box_param.density) - OpsRegister()["PriorBox"].aspect_ratio = list(prior_box_param.aspect_ratio) + if len(prior_box_param.aspect_ratio) > 0: + OpsRegister()["PriorBox"].min_size = list(prior_box_param.min_size) + OpsRegister()["PriorBox"].max_size = list(prior_box_param.max_size) + OpsRegister()["PriorBox"].aspect_ratio = list(prior_box_param.aspect_ratio) + if len(prior_box_param.density) > 0: + OpsRegister()["PriorBox"].fixed_size = list(prior_box_param.fixed_size) + OpsRegister()["PriorBox"].fixed_ratio = list(prior_box_param.fixed_ratio) + OpsRegister()["PriorBox"].density = list(prior_box_param.density) OpsRegister()["PriorBox"].is_flip = prior_box_param.flip OpsRegister()["PriorBox"].is_clip = prior_box_param.clip OpsRegister()["PriorBox"].variance = list(prior_box_param.variance) @@ -1139,6 +1174,16 @@ def Parser_relu6(args): OpsRegister()["Activation"].type = "ClippedRelu" OpsRegister()["Activation"].clip_relu_num = 6 +@ParserFeedDecorator("Interp") +def Parser_interp(args): + layer = args[1] + interp_param = layer.interp_param + OpsRegister()["Interp"].height = interp_param.height + OpsRegister()["Interp"].width = interp_param.width + OpsRegister()["Interp"].zoom_factor = interp_param.zoom_factor + OpsRegister()["Interp"].shrink_factor = interp_param.shrink_factor + OpsRegister()["Interp"].pad_beg = interp_param.pad_beg + OpsRegister()["Interp"].pad_end = interp_param.pad_end # caffe layer parameter parser map CAFFE_LAYER_PARSER = { @@ -1205,6 +1250,10 @@ def Parser_relu6(args): "DetectionOutput": OpsParam().set_parser(Parser_detectionoutput), # vis add "ArgMax": OpsParam().set_parser(Parser_argmax), "Normalize": OpsParam().set_parser(Parser_normalize), + "Resize": OpsParam().set_parser(Parser_resize), "ReLU6": OpsParam().set_parser(Parser_relu6), - "ShuffleChannel": OpsParam().set_parser(Parser_ShuffleChannel) + "Normalization": OpsParam().set_parser(Parser_normalize), + "ShuffleChannel": OpsParam().set_parser(Parser_ShuffleChannel), + "RoisAnchorFeature": OpsParam().set_parser(Parser_rois_anchor_feature), + "Interp": OpsParam().set_parser(Parser_interp) } diff --git a/tools/external_converter_v2/parser/kill_caffe/parser_caffe.py b/tools/external_converter_v2/parser/caffe/parser_caffe.py similarity index 68% rename from tools/external_converter_v2/parser/kill_caffe/parser_caffe.py rename to tools/external_converter_v2/parser/caffe/parser_caffe.py index f83ba2557..43a6d8fe9 100644 --- a/tools/external_converter_v2/parser/kill_caffe/parser_caffe.py +++ b/tools/external_converter_v2/parser/caffe/parser_caffe.py @@ -39,11 +39,151 @@ def _DetectionArch(self): self._ParserPrototxt() self._UpgradeNetAsNeeded() self._FilterNet() + self._SplitInception(False) + self._InsSplitBtwSliceConcat() + self._InsSplitBtwSliceEltwise() self._InsertSplits() self._ScatterInputLayer() # create input node #self._CreateInputNode() maybe not need + + def _SplitInception(self, is_weight): + print is_weight + net = self.net_parameter + + if is_weight: + net = self.net_param_weights + else: + print net + layers = net.layers or net.layer; + new_layers = [] + net_param = NetParameter() + blob_name_dict = {} + for idx, layer in enumerate(layers): + if layer.type != "Inception": + for b_id, blob in enumerate(layer.bottom): + if blob in blob_name_dict: + layer.bottom[b_id] = blob_name_dict[blob] + new_layers.append(layer) + if is_weight: + if (layer.type == "Slice"): + print layer + else: + for b_id, blob in enumerate(layer.bottom): + if blob in blob_name_dict: + layer.bottom[b_id] = blob_name_dict[blob] + #if is_weight: + #print layer + inception_top = layer.top + bottom_name = layer.bottom + inception_param = layer.inception_param + relu_param = inception_param.relu_param + need_relu = inception_param.need_relu + relu_at_top = inception_param.relu_at_top + columns = inception_param.inception_column + columns_top = [] + blob_id = 0 + inception = [] + blobs = layer.blobs + if len(blobs) != 0: + print "****************************************" + for b in blobs: + print "inception blob shape", b.shape + for cl_id, column in enumerate(columns): + convs = column.convolution_param + col_name = inception_top[0] + "_" + column.column_name + bottom = bottom_name[0] + for conv_id, conv in enumerate(convs): + conv_layer = net_param.layer.add() + conv_layer.type = "Convolution" + top = col_name + "_" + str(conv_id + 1) + "_conv" + conv_layer.convolution_param.CopyFrom(conv) + if conv_layer.convolution_param.HasField("kernel_size"): + conv_layer.convolution_param.pad = (conv_layer.convolution_param.kernel_size - 1) / 2 + else: + conv_layer.convolution_param.pad_h = (conv_layer.convolution_param.kernel_h - 1) / 2 + conv_layer.convolution_param.pad_w = (conv_layer.convolution_param.kernel_w - 1) / 2 + + conv_layer.top.append(top) + conv_layer.bottom.append(bottom) + conv_layer.name = top; + inception.append(conv_layer) + if len(blobs) != 0: + if conv_layer.convolution_param.bias_term: + # conv_layer.blobs.append(blobs[blob_id]) + # conv_layer.blobs.append(blobs[blob_id+1]) + blob_id += 2 + else: + # conv_layer.blobs.append(blobs[blob_id+1]) + blob_id += 1 + bottom = top + if (need_relu): + if relu_at_top: + relu_layer = net_param.layer.add() + relu_layer.type = "ReLU" + relu_layer.top.append(bottom) + relu_layer.bottom.append(bottom) + relu_layer.relu_param.CopyFrom(inception_param.relu_param) + relu_layer.name = col_name + "_" + str(conv_id + 1) + "relu"; + inception.append(relu_layer) + else: + relu_layer = net_param.layer.add() + relu_layer.type = "ReLU" + top = col_name + "_relu_" + str(conv_id) + relu_layer.name = col_name + "_" + str(conv_id + 1) + "relu"; + relu_layer.bottom.append(bottom) + relu_layer.top.append(top) + if inception_param.HasField("relu_param"): + relu_layer.relu_param.CopyFrom(inception_param.relu_param) + else: + relu_layer.relu_param = ReLUParameter() + bottom = top + inception.append(relu_layer) + + if column.HasField("pooling_param"): + pool_layer = net_param.layer.add() + pool_layer.type = "Pool" + top = col_name + "_pool" + pool_layer.name = top + pool_layer.top.append(top) + pool_layer.bottom.append(bottom) + pool_layer.pooling_param.CopyFrom(column.pooling_param) + bottom = top + inception.append(pool_layer) + columns_top.append(bottom) + if len(columns_top) > 1: + concat_layer = net_param.layer.add() + for bot in columns_top: + concat_layer.bottom.append(bot) + concat_layer.top.append(inception_top[0]) + concat_layer.type = "Concat" + concat_layer.name = top + "_concat" + inception.append(concat_layer) + bottom = inception_top[0] + else: + blob_name_dict[inception_top[0]] = bottom + + new_layers.extend(inception) + #print inception + #for com in inception: + # new_layers.append(com) + if is_weight: + if self.net_param_weights.layers: + del self.net_param_weights.layers[:] + self.net_param_weights.layers.extend(new_layers) + if self.net_param_weights.layer: + del self.net_param_weights.layer[:] + self.net_param_weights.layer.extend(new_layers) + else: + if self.net_parameter.layers: + del self.net_parameter.layers[:] + self.net_parameter.layers.extend(new_layers) + if self.net_parameter.layer: + del self.net_parameter.layer[:] + self.net_parameter.layer.extend(new_layers) + + def _ParserPrototxt(self): """ don't need to be used. @@ -51,6 +191,13 @@ def _ParserPrototxt(self): with open(self.PrototxtPath, "r") as f: text_format.Merge(f.read(), self.net_parameter) + def _ParserPrototxtWithModel(self): + """ + don't need to be used. + """ + with open(self.ModelPath, "r") as f: + self.net_parameter.MergeFromString(f.read()) + def _ParserModel(self): with open(self.ModelPath, "r") as f: self.net_param_weights.MergeFromString(f.read()) @@ -70,7 +217,7 @@ def _UpgradeNetAsNeeded(self): logger(verbose.FATAL).feed("[ Upgrade Level 1 ] Details: need to upgrade from V0 to V1 [ FAILED ]") exit() if NetNeedsDataUpgrade(self.net_parameter): - logger(verbose.INFO).feed("[ Upgrade Level 2 ] Details: need Data upgrade [ IGNORED ]") + logger(verbose.ERROR).feed("[ Upgrade Level 2 ] Details: need Data upgrade [ IGNORED ]") if NetNeedsV1ToV2Upgrade(self.net_parameter): logger(verbose.INFO).feed("[ Upgrade Level 3 ] Details: need to upgrade from V1 to V2 [ ... ]") original_param = NetParameter() @@ -81,7 +228,7 @@ def _UpgradeNetAsNeeded(self): logger(verbose.FATAL).feed("[ Upgrade Level 3 ] Details: need to upgrade from V1 to V2 [ FAILED ]") exit() if NetNeedsInputUpgrade(self.net_parameter): - logger(verbose.INFO).feed("[ Upgrade Level 4 ] Details: need Input upgrade [ ... ]") + logger(verbose.INFO).feed("[ Upgrade Level 4 ] Details: need Input upgrade [ ... ]") UpgradeNetInput(self.net_parameter) logger(verbose.WARNING).feed("[ Upgrade Level 4 ] Details: need Input upgrade [ SUC ]") if NetNeedsBatchNormUpgrade(self.net_parameter): @@ -89,6 +236,70 @@ def _UpgradeNetAsNeeded(self): UpgradeNetBatchNorm(self.net_parameter) logger(verbose.INFO).feed("[ Upgrade Level 5 ] Details: need BatchNorm upgrade [ ... ]") + def _InsSplitBtwSliceConcat(self): + ''' + Currently, the connection between Slice and Concat must be implemented via Split. + ''' + layers = self.net_parameter.layer or self.net_parameter.layers + top_blobs_of_slices = list() + btm_blobs_of_concats = list() + for layer in layers: + if layer.type == 'Slice': + top_blobs_of_slices.extend(layer.top) + elif layer.type == 'Concat': + btm_blobs_of_concats.extend(layer.bottom) + intersection_blobs = list(set(top_blobs_of_slices).intersection(set(btm_blobs_of_concats))) + new_param = NetParameter() + for layer in layers: + new_layer = new_param.layer.add() + new_layer.CopyFrom(layer) + if layer.type == 'Slice': + for top_blob in layer.top: + if top_blob in intersection_blobs: + split_param = new_param.layer.add() + split_param.bottom.append(top_blob) + split_param.top.append(top_blob) + split_param.name = 'Split_' + top_blob + split_param.type = 'Split' + if self.net_parameter.layer: + del self.net_parameter.layer[:] + self.net_parameter.layer.extend(new_param.layer) + else: + del self.net_parameter.layers[:] + self.net_parameter.layers.extend(new_param.layer) + + def _InsSplitBtwSliceEltwise(self): + ''' + Currently, the connection between Slice and Concat must be implemented via Split. + ''' + layers = self.net_parameter.layer or self.net_parameter.layers + top_blobs_of_slices = list() + btm_blobs_of_concats = list() + for layer in layers: + if layer.type == 'Slice': + top_blobs_of_slices.extend(layer.top) + elif layer.type == 'Eltwise': + btm_blobs_of_concats.extend(layer.bottom) + intersection_blobs = list(set(top_blobs_of_slices).intersection(set(btm_blobs_of_concats))) + new_param = NetParameter() + for layer in layers: + new_layer = new_param.layer.add() + new_layer.CopyFrom(layer) + if layer.type == 'Slice': + for top_blob in layer.top: + if top_blob in intersection_blobs: + split_param = new_param.layer.add() + split_param.bottom.append(top_blob) + split_param.top.append(top_blob) + split_param.name = 'Split_' + top_blob + split_param.type = 'Split' + if self.net_parameter.layer: + del self.net_parameter.layer[:] + self.net_parameter.layer.extend(new_param.layer) + else: + del self.net_parameter.layers[:] + self.net_parameter.layers.extend(new_param.layer) + def _InsertSplits(self): """ Same as caffe InsertSplits. @@ -112,7 +323,7 @@ def _InsertSplits(self): layer_idx_to_name[idx] = layer.name for j, btm in enumerate(layer.bottom): if btm not in self.blob_name_to_last_top_idx.keys(): - logger(verbose.FATAL).feed("Unknown bottom (blob: %s) in (layer: '%s')" % (btm, layer.name)) + logger(verbose.FATAL).feed("Unknown bottom (blob: %s) in (layer: '%s')" % (btm, layer.name)) exit() bottom_idx = (idx, j) top_idx = self.blob_name_to_last_top_idx[btm] @@ -250,19 +461,20 @@ def _CreateInputNode(self): if not input_dim: if len(self.net_parameter.input_shape) > 0: input_dim = map(int, self.net_parameter.input_shape[0].dim) - node_io.set_name(in_name) - node_io.add_in(in_name) - # leak out name , need to be added later. - shape = TensorShape() - shape.dim.value[:] = input_dim - shape.dim.size = len(input_dim) - node_io.add_attr("shape", shape, "shape") - op_io.set_name("Input") - op_io.set_in_num(1) - op_io.set_commutative(True) - node_io.set_op(op_io()) - self.graphIO.add_node(node_io()) - self.graphIO.add_in(in_name) + for in_name in inputs: + node_io.set_name(in_name) + node_io.add_in(in_name) + # leak out name , need to be added later. + shape = TensorShape() + shape.dim.value[:] = input_dim + shape.dim.size = len(input_dim) + node_io.add_attr("shape", shape, "shape") + op_io.set_name("Input") + op_io.set_in_num(1) + op_io.set_commutative(True) + node_io.set_op(op_io()) + self.graphIO.add_node(node_io()) + self.graphIO.add_in(in_name) else: # parser InputParameter instead. logger(verbose.INFO).feed(" Need to parse the layer of type InputParameter.") @@ -309,11 +521,12 @@ def _Parsing_new(self): blob_top_to_layer_name[top].put(tmp_rlayer.name) # set graph proto's name self.graphIO.set_name(self.net_parameter.name) - logger(verbose.INFO).feed(" [CAFFE] Archtecture Parsing ...") + logger(verbose.ERROR).feed(" [CAFFE] Archtecture Parsing ...") # parsing model - logger(verbose.INFO).feed(" [CAFFE] Model Parameter Parsing ...") + logger(verbose.ERROR).feed(" [CAFFE] Model Parameter Parsing ...") self._ParserModel() + self._SplitInception(True) model_layers = self.net_param_weights.layers or self.net_param_weights.layer # we must setting graph edge first @@ -429,11 +642,12 @@ def _Parsing(self): #blob_btm_to_layer_name[top] = tmp_rlayer.name # set graph proto's name self.graphIO.set_name(self.net_parameter.name) - logger(verbose.INFO).feed(" [CAFFE] Archtecture Parsing ...") + logger(verbose.ERROR).feed(" [CAFFE] Archtecture Parsing ...") # parsing model - logger(verbose.INFO).feed(" [CAFFE] Model Parameter Parsing ...") + logger(verbose.ERROR).feed(" [CAFFE] Model Parameter Parsing ...") self._ParserModel() + #self._SplitInception(True) model_layers = self.net_param_weights.layers or self.net_param_weights.layer for idx, rlayer in enumerate(real_layers): source_layer_name = rlayer.name diff --git a/tools/external_converter_v2/parser/kill_fluid/__init__.py b/tools/external_converter_v2/parser/fluid/__init__.py similarity index 57% rename from tools/external_converter_v2/parser/kill_fluid/__init__.py rename to tools/external_converter_v2/parser/fluid/__init__.py index 4d8ee7a14..4d195813c 100644 --- a/tools/external_converter_v2/parser/kill_fluid/__init__.py +++ b/tools/external_converter_v2/parser/fluid/__init__.py @@ -1,5 +1,4 @@ #! /usr/bin/env python -# Copyright (c) 2017, Cuichaowen. All rights reserved. # -*- coding: utf-8 -*- from parser_fluid import * diff --git a/tools/external_converter_v2/parser/fluid/fluid_debugger.py b/tools/external_converter_v2/parser/fluid/fluid_debugger.py new file mode 100644 index 000000000..9cfa4499c --- /dev/null +++ b/tools/external_converter_v2/parser/fluid/fluid_debugger.py @@ -0,0 +1,65 @@ +from ..proto import * +from ..graph_io import * +import copy +import paddle.fluid as fluid +import numpy as np +from paddle.fluid.core import VarDesc, AttrType + + +class Fluid_debugger: + def var_names_of_fetch(self, fetch_targets): + """ + """ + var_names_list = [] + for var in fetch_targets: + var_names_list.append(var.name) + return var_names_list + def fetch_tmp_vars(self, block, fetch_targets, var_names_list=None): + """ + """ + fetch_var = block.var('fetch') + old_fetch_names = self.var_names_of_fetch(fetch_targets) + new_fetch_vars = [] + for var_name in old_fetch_names: + var = block.var(var_name) + new_fetch_vars.append(var) + i = len(new_fetch_vars) + if var_names_list is None: + var_names_list = block.vars.keys() + for var_name in var_names_list: + if '.tmp_' in var_name and var_name not in old_fetch_names: + var = block.var(var_name) + new_fetch_vars.append(var) + block.append_op( + type='fetch', + inputs={'X': [var_name]}, + outputs={'Out': [fetch_var]}, + attrs={'col': i}) + i = i + 1 + return new_fetch_vars + + def print_tmp_vars(self, block, var_names_list): + """ + Print the temporary variable for fluid. + """ + for var_name in var_names_list: + var_to_print = block.var(var_name) + out_to_print = block.create_var( + name=var_name + '.print', + dtype="float32", + persistable=True, + stop_gradient=False) + block.append_op( + type='print', + inputs={'In': var_to_print}, + attrs={ + 'first_n': -1, + 'summarize': -1, + 'message': "", + 'print_tensor_name': True, + 'print_tensor_type': True, + 'print_tensor_shape': True, + 'print_tensor_lod': True, + 'print_phase': 'FORWARD' + }, + outputs={'Out': out_to_print}) diff --git a/tools/external_converter_v2/parser/fluid/fluid_helper.py b/tools/external_converter_v2/parser/fluid/fluid_helper.py new file mode 100644 index 000000000..73ad3f931 --- /dev/null +++ b/tools/external_converter_v2/parser/fluid/fluid_helper.py @@ -0,0 +1,617 @@ +from ..proto import * +from ..graph_io import * +import paddle.fluid as fluid +import numpy as np +from paddle.fluid.core import VarDesc, AttrType + + +def union(list_a, list_b): + ''' + ''' + return list(set(list_a).union(set(list_b))) + +def difference(list_a, list_b): + ''' + ''' + return list(set(list_a).difference(set(list_b))) + + +class Edge_for_fluid: + + def __init__(self, param, target, var): + ''' + ''' + self.param = param + self.target = target + self.var = var + + +class Fluid_edger: + + def __init__(self, param = None, target = None, var = None): + ''' + ''' + self.edges = [] + if param is not None and target is not None: + edge = Edge_for_fluid(param, target, var) + self.edges.append(edge) + + def __call__(self): + ''' + ''' + return self.all_targets() + + def add(self, param, target, var = None): + ''' + ''' + edge = Edge_for_fluid(param, target, var) + self.edges.append(edge) + + def rm_edges_by_param(self, param): + ''' + ''' + for edge in self.edges: + if edge.param == param: + edge_idx = self.edges.index(edge) + del self.edges[edge_idx] + + def rm(self, target): + ''' + ''' + res = -1 + for edge in self.edges: + if target == edge.target: + edge_idx = self.edges.index(edge) + del self.edges[edge_idx] + res = res + 1 + if res != 0: + pass + + def mv(self, old_target, new_target): + ''' + ''' + res = -1 + for edge in self.edges: + if old_target == edge.target: + edge.target = new_target + res = res + 1 + if res != 0: + pass + + def all_params(self): + ''' + ''' + params = [] + for edge in self.edges: + if edge.param not in params: + params.append(edge.param) + return params + + def all_targets(self): + ''' + ''' + targets = [] + for edge in self.edges: + targets.append(edge.target) + return targets + + def targets(self, param): + ''' + ''' + targets = [] + for edge in self.edges: + if edge.param == param: + targets.append(edge.target) + return targets + + def target(self, param, idx = 0): + ''' + ''' + return self.targets(param)[idx] + + def clear(self): + ''' + ''' + targets_list = self.all_targets() + for target in targets_list: + self.rm(target) + + def targets_with_params(self): + ''' + ''' + list_of_targets_and_params = [] + for edge in self.edges: + target_and_param = [edge.target, edge.param] + list_of_targets_and_params.append(target_and_param) + return list_of_targets_and_params + + def vars_by_target(self, target): + ''' + ''' + vars = [] + for edge in self.edges: + if edge.target == target and edge.var is not None: + vars.append(edge.var) + return vars + + def __getitem__(self, idx): + ''' + ''' + if idx < len(self.edges): + return self.edges[idx] + return None + + +class Fluid_helper: + ''' + ''' + def __init__(self, scope, block): + ''' + ''' + self.scope = scope + self.block = block + + def args_by_input_param(self, op, param_name): + ''' + ''' + if param_name in op.input_names: + return op.input(param_name) + else: + raise NameError('ERROR: param_name %s is not exists.' % (param_name)) + + def args_by_output_param(self, op, param_name): + ''' + ''' + if param_name in op.output_names: + return op.output(param_name) + else: + raise NameError('ERROR: param_name %s is not exists.' % (param_name)) + + def var_by_input_param(self, op, param_name, var_idx = 0): + ''' + ''' + var_name = self.args_by_input_param(op, param_name)[var_idx] + var = self.block.var(var_name) + return var + + def var_by_output_param(self, op, param_name, var_idx = 0): + ''' + ''' + var_name = self.args_by_output_param(op, param_name)[var_idx] + var = self.block.var(var_name) + return var + + def var_name_by_param(self, op, param_name, var_idx = 0): + ''' + ''' + if param_name not in op.input_names + op.output_names: + raise NameError('ERROR: param_name %s is not exists.' % (param_name)) + elif param_name in op.input_names: + if len(op.input(param_name)) > 0: + var_name_unicode = op.input(param_name)[var_idx] + else: + raise NameError('ERROR: param %s has not var.' % (param_name)) + elif param_name in op.output_names: + if len(op.output(param_name)) > 0: + var_name_unicode = op.output(param_name)[var_idx] + else: + raise NameError('ERROR: param %s has not var.' % (param_name)) + var = self.block.var(var_name_unicode) + var_name = var.name + return var_name + + def var_by_param(self, op, param_name, var_idx = 0): + ''' + ''' + var_name = self.var_name_by_param(op, param_name, var_idx) + var = self.block.var(var_name) + return var + + def shape_by_var_name(self, var_name, layout = 'NCHW'): + ''' + ''' + var = self.block.var(var_name) + long_tuple = var.shape + long_list = list(long_tuple) + if layout == 'NCHW': + int_list_4d = map(int, [1] * (4 - len(long_list)) + long_list) + return int_list_4d + elif layout == 'UNMODIFIED': + return long_list + else: + raise NameError('ERROR: layout %s is not implemented yet.' % (layout)) + + def np_data_by_var_name(self, var_name): + ''' + ''' + if hasattr(fluid.executor, '_fetch_var'): + numpy_array = fluid.executor._fetch_var(str(var_name), self.scope, True) + elif hasattr(fluid.executor, 'fetch_var'): + numpy_array = fluid.executor.fetch_var(var_name, self.scope, True) + else: + raise NameError('ERROR: Unknown Fluid version.') + return numpy_array + + def dtype_by_var_name(self, var_name): + ''' + ''' + var = self.block.var(var_name) + fluid_var_type = var.dtype + dtype = ANAKIN_TENSOR_DTYPE[fluid_var_type] + return dtype + + def is_persistable_param(self, op, param_name, var_idx = 0): + ''' + ''' + var = self.var_by_param(op, param_name, var_idx) + is_persistable_var = var.persistable + return is_persistable_var + + def var_shape_by_param(self, transpose, op, param_name, var_idx = 0, layout = 'NCHW'): + ''' + ''' + if transpose is True: + raise NameError('ERROR: var_shape transpose is not implemented yet.') + else: + var_name = self.var_name_by_param(op, param_name, var_idx) + shape = self.shape_by_var_name(var_name, layout) + return shape + + def data_with_shape_by_param(self, + op, + param_name, + transpose = False, + axes = None, + var_idx = 0, + is_flat_list = True, + layout = 'NCHW'): + ''' + ''' + np.set_printoptions(threshold=np.inf, suppress=True) + + var_name = self.var_name_by_param(op, param_name, var_idx) + np_array = self.np_data_by_var_name(var_name) + if transpose is True: + np_array = np.transpose(np_array, axes) + np_shape = np.shape(np_array) + if layout == 'NCHW': + np_shape = map(int, [1] * (4 - len(np_shape)) + list(np_shape)) + if is_flat_list is True: + flat_list = list(np_array.flatten()) + return [flat_list, np_shape] + else: + return [np_array, np_shape] + + def np_param(self, + op, + param_name, + transpose = False, + axes = None, + var_idx = 0): + ''' + ''' + [data, np_shape] = self.data_with_shape_by_param(op, param_name, transpose, \ + axes, var_idx, False) + return data + + def dtype_by_param(self, op, param_name, var_idx = 0): + ''' + ''' + var_name = self.var_name_by_param(op, param_name, var_idx) + dtype = self.dtype_by_var_name(var_name) + return dtype + + def is_list_type(self, op, attr_name): + ''' + ''' + if op.has_attr(attr_name): + fluid_attr_type = op.attr_type(attr_name) + if fluid_attr_type in ANAKIN_ATTR_IS_LIST.keys(): + return ANAKIN_ATTR_IS_LIST[fluid_attr_type] + else: + return False # AttrType.LONG + else: + raise NameError('ERROR: attr_name %s is not exists.' % (attr_name)) + + def dtype_of_attr(self, op, attr_name): + ''' + ''' + if op.has_attr(attr_name): + fluid_attr_type = op.attr_type(attr_name) + if fluid_attr_type in ANAKIN_ATTR_DTYPE.keys(): + return ANAKIN_ATTR_DTYPE[fluid_attr_type] + else: + return INT32 # AttrType.LONG + else: + raise NameError('ERROR: attr_name %s is not exists.' % (attr_name)) + + def attr_data_required(self, op, attr_name): + ''' + ''' + data = op.attr(attr_name) + is_list = self.is_list_type(op, attr_name) + dtype = self.dtype_of_attr(op, attr_name) + if dtype not in [INT32, FLOAT, STR]: + return data + elif dtype == INT32: + return map(int, data) if is_list else int(data) + elif dtype == FLOAT: + return map(float, data) if is_list else float(data) + elif dtype == STR: + return bytes(data) + + def attr_data(self, op, attr_name, default_value = 0, type = None): + ''' + ''' + if op.has_attr(attr_name): + return self.attr_data_required(op, attr_name) + else: + #raise NameError('ERROR: attr_name %s is not exists.' % ( attr_name ) ) + return default_value + + def param_tensor_sh(self, + op, + param_name, + transpose = False, + axes = None, + reshape = None, + var_idx = 0, + layout = 'NCHW'): + ''' + ''' + tensor = TensorProtoIO() + [flat_data, shape] = self.data_with_shape_by_param(op, param_name, transpose, \ + axes, var_idx, True, layout) + dtype = self.dtype_by_param(op, param_name, var_idx) + tensor.set_data_type(dtype) + if dtype in ANAKIN_TENSOR_DTYPESTR.keys(): + tensor.set_data(flat_data, ANAKIN_TENSOR_DTYPESTR[dtype]) + #pass #debug + else: + raise NameError('ERROR: Unknown data type (%s)' % (dtype)) + if reshape is not None: + tensor.set_shape(reshape) + else: + tensor.set_shape(shape) + return [tensor, shape] + + def param_tensor(self, + op, + param_name, + transpose = False, + axes = None, + reshape = None, + var_idx = 0, + layout = 'NCHW'): + ''' + ''' + [tensor, shape] = self.param_tensor_sh(op, param_name, transpose, axes, \ + reshape, var_idx, layout) + return tensor + + def create_tensor(self, data_list, data_shape, dtype): + ''' + ''' + tensor = TensorProtoIO() + tensor.set_data_type(dtype) + tensor.set_data(data_list, ANAKIN_TENSOR_DTYPESTR[dtype]) + tensor.set_shape(data_shape) + return tensor + + def gru_tensor_convert(self, origin_h2h, origin_i2h, origin_b, offset=[2, 1, 0]): + ''' + ''' + hidden_size = int(origin_b.size // 3) + word_size = int(origin_i2h.size // hidden_size // 3) + tar_h2h = np.array(origin_h2h.flatten().tolist()[2 * hidden_size * hidden_size:]\ + + np.array(origin_h2h.flatten().tolist()[: 2 * hidden_size * hidden_size])\ + .reshape(hidden_size, 2, hidden_size)[:, [1, 0], :].flatten().tolist())\ + .reshape(1, 1, hidden_size, 3 * hidden_size) + tar_i2h = origin_i2h.reshape(word_size, 3, hidden_size)[:, offset, :]\ + .reshape(1, 1, word_size, 3 * hidden_size) + tar_b = origin_b.reshape(3, hidden_size)[offset, :].reshape(1, 1, 1, 3 * hidden_size) + tar_i2h_h2h = np.concatenate([tar_i2h.flatten(), tar_h2h.flatten()])\ + .reshape(1, 1, 1, 3 * hidden_size * hidden_size + 3 * word_size * hidden_size) + return tar_i2h_h2h, tar_b + + def lstm_fc_tensor_merge_convert(self, + origin_hidden_size, + origin_lstm_w, + origin_lstm_b, + origin_fc_w, + origin_fc_b): + ''' + ''' + layer_size = int(origin_hidden_size // 4) + input_size = int(origin_fc_w.size // origin_hidden_size) + lstm_bias_num = int(origin_lstm_b.size // layer_size) + tar_w = np.vstack((np.hstack((origin_fc_w[:, 1 * layer_size: 2 * layer_size], + origin_fc_w[:, 2 * layer_size: 3 * layer_size], + origin_fc_w[:,: 1 * layer_size], + origin_fc_w[:, 3 * layer_size:])), + np.hstack((origin_lstm_w[:, 1 * layer_size: 2 * layer_size], + origin_lstm_w[:, 2 * layer_size: 3 * layer_size], + origin_lstm_w[:, : 1 * layer_size], + origin_lstm_w[:, 3 * layer_size:])))) + + if origin_fc_b is not None: + split_fc_bc = origin_fc_b.flatten()[: 1 * layer_size] + split_fc_bi = origin_fc_b.flatten()[1 * layer_size : 2 * layer_size] + split_fc_bf = origin_fc_b.flatten()[2 * layer_size : 3 * layer_size] + split_fc_bo = origin_fc_b.flatten()[3 * layer_size : 4 * layer_size] + else: + split_fc_bc = np.zeros(layer_size) + split_fc_bi = np.zeros(layer_size) + split_fc_bf = np.zeros(layer_size) + split_fc_bo = np.zeros(layer_size) + + split_lstm_bc = origin_lstm_b.flatten()[: 1 * layer_size] + split_lstm_bi = origin_lstm_b.flatten()[1 * layer_size: 2 * layer_size] + split_lstm_bf = origin_lstm_b.flatten()[2 * layer_size: 3 * layer_size] + split_lstm_bo = origin_lstm_b.flatten()[3 * layer_size: 4 * layer_size] + split_lstm_bc = np.add(split_lstm_bc, split_fc_bc) + split_lstm_bi = np.add(split_lstm_bi, split_fc_bi) + split_lstm_bf = np.add(split_lstm_bf, split_fc_bf) + split_lstm_bo = np.add(split_lstm_bo, split_fc_bo) + + if lstm_bias_num == 4: + tar_b = np.array(split_lstm_bi.flatten().tolist() + + split_lstm_bf.flatten().tolist() + + split_lstm_bc.flatten().tolist() + + split_lstm_bo.flatten().tolist()) + else: + split_lstm_wic = origin_lstm_b.flatten()[4 * layer_size : 5 * layer_size] + split_lstm_wfc = origin_lstm_b.flatten()[5 * layer_size : 6 * layer_size] + split_lstm_woc = origin_lstm_b.flatten()[6 * layer_size :] + tar_b = np.array(split_lstm_bi.flatten().tolist() + + split_lstm_bf.flatten().tolist() + + split_lstm_bc.flatten().tolist() + + split_lstm_bo.flatten().tolist() + + split_lstm_wic.flatten().tolist() + + split_lstm_wfc.flatten().tolist() + + split_lstm_woc.flatten().tolist()) + return tar_w.reshape(input_size + layer_size, 4 * layer_size, 1, 1),\ + tar_b.reshape(1, origin_lstm_b.size, 1, 1) + + +class Fluid_comparator: + """ + """ + def __init__(self, helper): + """ + """ + self.helper = helper + self.only_list = ['feed', 'fetch'] + + def compare_by_param(self, op_a, op_b, param): + """ + """ + is_weight_a = self.helper.is_persistable_param(op_a, param) + is_weight_b = self.helper.is_persistable_param(op_b, param) + if is_weight_a and is_weight_b: + np_a = self.helper.np_param(op_a, param) + np_b = self.helper.np_param(op_b, param) + if (np_a == np_b).all() == True: + return True + else: + return False + elif is_weight_a is is_weight_b: + return True + else: + return False + + def have_same_weights(self, op_a, op_b): + """ + """ + is_same = True + if op_a.input_names == op_b.input_names: + params = op_a.input_names + for param in params: + if self.compare_by_param(op_a, op_b, param) is False: + is_same = False + return is_same + else: + return False + + def compare_by_attr(self, op_a, op_b, attr_name): + """ + """ + data_a = self.helper.attr_data(op_a, attr_name) + data_b = self.helper.attr_data(op_b, attr_name) + return data_a == data_b + + def have_same_attrs(self, op_a, op_b): + """ + """ + is_same = True + if op_a.attr_names == op_b.attr_names: + attrs = op_a.attr_names + for attr in attrs: + if self.compare_by_attr(op_a, op_b, attr) is False: + is_same = False + return is_same + else: + return False + + def brothers(self, op_list): + """ + """ + is_same = True + if len(op_list) > 1: + idx = 0 + for op_b in op_list[1:]: + if op_b.type not in self.only_list: + idx = op_list.index(op_b) + op_a = op_list[idx - 1] + if op_a.type not in self.only_list: + same_weights = self.have_same_weights(op_a, op_b) + same_attrs = self.have_same_attrs(op_a, op_b) + if (same_weights and same_attrs) is False: + is_same = False + else: + raise NameError('ERROR: %s is in only_list.' % (op_a.type)) + else: + raise NameError('ERROR: %s is in only_list.' % (op_b.type)) + return is_same + else: + raise NameError('ERROR: Members of op_list must be greater than 2.') + + +ANAKIN_TENSOR_DTYPE = { + VarDesc.VarType.BOOL: BOOLEN, + VarDesc.VarType.INT32: INT32, + VarDesc.VarType.FP16: FLOAT16, + VarDesc.VarType.FP32: FLOAT, + VarDesc.VarType.FP64: DOUBLE, +} + +ANAKIN_TENSOR_DTYPESTR = { + STR: "string", + INT32: "int", + FLOAT: "float", + BOOLEN: "bool", +} + +ANAKIN_ATTR_DTYPE = { + AttrType.INT: INT32, + AttrType.INTS: INT32, + AttrType.FLOAT: FLOAT, + AttrType.FLOATS: FLOAT, + AttrType.STRING: STR, + AttrType.STRINGS: STR, + AttrType.BOOL: BOOLEN, + AttrType.BOOLS: BOOLEN, +} + +ANAKIN_ATTR_IS_LIST = { + AttrType.INT: False, + AttrType.INTS: True, + AttrType.FLOAT: False, + AttrType.FLOATS: True, + AttrType.STRING: False, + AttrType.STRINGS: True, + AttrType.BOOL: False, + AttrType.BOOLS: True, +} + +APPEND_BIAS_OP_TYPE = [ + 'FC', + 'mul', + 'sequence_conv', + 'conv2d', + 'conv2d_transpose', + 'depthwise_conv2d', + 'elementwise_mul', +] + +APPEND_ACT_OP_TYPE = [ + 'FC', + 'mul', + 'sequence_conv', + 'conv2d', + 'conv2d_transpose', + 'batch_norm', + 'layer_norm', + 'row_conv', + 'reshape', +] diff --git a/tools/external_converter_v2/parser/fluid/fluid_layer_param_transmit.py b/tools/external_converter_v2/parser/fluid/fluid_layer_param_transmit.py new file mode 100644 index 000000000..cfc1cd252 --- /dev/null +++ b/tools/external_converter_v2/parser/fluid/fluid_layer_param_transmit.py @@ -0,0 +1,505 @@ +from ..operations import OpsParam, OpsRegister +from ..logger import * +from ..proto import * +from fluid_helper import * + + +def ParserFeedDecorator(OpName): + def warpper(Parser): + def warpper_args(args): + Parser(args) + OpsRegister()[OpName].feed_node_attr(args[0]) + args[2].set_name(OpName) + args[0].set_op(args[2]()) + return warpper_args + return warpper + +# common +def NotNeededInInference(args): + # args is tuple object + node_io = args[0] + layer = args[1] + +@ParserFeedDecorator("Input") +def Parser_feed(args): + private_data = args[4] + input_shape = private_data['input_shape'] + alias = private_data['alias'] + OpsRegister()["Input"].input_shape = input_shape + OpsRegister()["Input"].alias = alias + +@ParserFeedDecorator("Convolution") +def Parser_conv2d(args): + op = args[1] + helper = args[3] + private_data = args[4] + [weights_tensor, weights_shape] = helper.param_tensor_sh(op, 'Filter') + OpsRegister()["Convolution"].weight_1 = weights_tensor + OpsRegister()["Convolution"].filter_num = weights_shape[0] + OpsRegister()["Convolution"].kernel_size = weights_shape[-2:] + OpsRegister()["Convolution"].strides = helper.attr_data(op, 'strides') + OpsRegister()["Convolution"].padding = helper.attr_data(op, 'paddings') + OpsRegister()["Convolution"].dilation_rate = helper.attr_data(op, 'dilations') + OpsRegister()["Convolution"].group = helper.attr_data(op, 'groups') + OpsRegister()["Convolution"].axis = 1 + if 'bias' in private_data.keys(): + OpsRegister()["Convolution"].bias_term = True + OpsRegister()["Convolution"].weight_2 = private_data['bias'] + else: + OpsRegister()["Convolution"].bias_term = False + +@ParserFeedDecorator("ReLU") +def Parser_relu(args): + OpsRegister()["ReLU"].alpha = 0.0 + +@ParserFeedDecorator("Pooling") +def Parser_pool2d(args): + op = args[1] + helper = args[3] + OpsRegister()["Pooling"].pool_size = helper.attr_data(op, 'ksize') + OpsRegister()["Pooling"].strides = helper.attr_data(op, 'strides') + OpsRegister()["Pooling"].padding = helper.attr_data(op, 'paddings') + OpsRegister()["Pooling"].global_pooling = helper.attr_data(op, 'global_pooling') + if helper.attr_data(op, 'pooling_type') == 'max': + OpsRegister()["Pooling"].method = "MAX" + elif helper.attr_data(op, 'pooling_type') in ['average', 'avg']: + OpsRegister()["Pooling"].method = "AVG" + if helper.attr_data(op, 'ceil_mode') == False: + OpsRegister()["Pooling"].cmp_out_shape_floor_as_conv = True + else: + OpsRegister()["Pooling"].cmp_out_shape_floor_as_conv = False + +@ParserFeedDecorator("Dense") +def Parser_mul(args): + op = args[1] + helper = args[3] + private_data = args[4] + weights_needs_trans = True + [weights_tensor, weights_shape] = helper.param_tensor_sh(op, 'Y', weights_needs_trans) + OpsRegister()["Dense"].weight_1 = weights_tensor + OpsRegister()["Dense"].out_dim = weights_shape[2] + OpsRegister()["Dense"].axis = helper.attr_data(op, 'x_num_col_dims') + if 'bias' in private_data.keys(): + OpsRegister()["Dense"].bias_term = True + OpsRegister()["Dense"].weight_2 = private_data['bias'] + else: + OpsRegister()["Dense"].bias_term = False + +@ParserFeedDecorator("Softmax") +def Parser_softmax(args): + private_data = args[4] + if 'axis' in private_data.keys(): + axis = private_data['axis'] + else: + axis = 1 + OpsRegister()["Softmax"].axis = axis + +@ParserFeedDecorator("Activation") +def Parser_sigmoid(args): + OpsRegister()["Activation"].type = "Sigmoid" + +@ParserFeedDecorator("Axpy") +def Parser_axpy(args): + pass + +@ParserFeedDecorator("BatchNorm") +def Parser_batch_norm(args): + op = args[1] + helper = args[3] + OpsRegister()["BatchNorm"].weight_1 = helper.param_tensor(op, 'Mean') + OpsRegister()["BatchNorm"].weight_2 = helper.param_tensor(op, 'Variance') + OpsRegister()["BatchNorm"].weight_3 = helper.create_tensor([1], [1, 1, 1, 1], FLOAT) + OpsRegister()["BatchNorm"].momentum = helper.attr_data(op, 'momentum') + OpsRegister()["BatchNorm"].epsilon = helper.attr_data(op, 'epsilon') + +@ParserFeedDecorator("Scale") +def Parser_scale_disc_bn(args): + op = args[1] + helper = args[3] + mean = helper.np_param(op, 'Mean') + var = helper.np_param(op, 'Variance') + alpha = helper.np_param(op, 'Scale') + beta = helper.np_param(op, 'Bias') + eps = helper.attr_data(op, 'epsilon') + var = np.sqrt(var + eps) + np_scale = alpha / var + np_bias = beta - (alpha * mean / var) + np_scale_shape = map(int, [1] * (4 - len(np_scale.shape)) + list(np_scale.shape)) + np_bias_shape = map(int, [1] * (4 - len(np_bias.shape)) + list(np_bias.shape)) + np_scale_tensor = helper.create_tensor(list(np_scale.flatten()), np_scale_shape, FLOAT) + np_bias_tensor = helper.create_tensor(list(np_bias.flatten()), np_bias_shape, FLOAT) + OpsRegister()["Scale"].bias_term = True + OpsRegister()["Scale"].weight_1 = np_scale_tensor + OpsRegister()["Scale"].weight_2 = np_bias_tensor + OpsRegister()["Scale"].axis = 1 + OpsRegister()["Scale"].num_axes = 1 + +@ParserFeedDecorator("Scale") +def Parser_scale_of_bn(args): + op = args[1] + helper = args[3] + OpsRegister()["Scale"].weight_1 = helper.param_tensor(op, 'Scale') + OpsRegister()["Scale"].axis = 1 + OpsRegister()["Scale"].num_axes = 1 + has_bias = helper.is_persistable_param(op, 'Bias') + if has_bias is True: + OpsRegister()["Scale"].bias_term = True + OpsRegister()["Scale"].weight_2 = helper.param_tensor(op, 'Bias') + else: + OpsRegister()["Scale"].bias_term = False + +@ParserFeedDecorator("Split") +def Parser_split(args): + private_data = args[4] + split_num = private_data['split_num'] + OpsRegister()["Split"].split_num = split_num + +@ParserFeedDecorator("Reshape") +def Parser_reshape(args): + op = args[1] + helper = args[3] + private_data = args[4] + if 'new_shape' in private_data.keys(): + shape = private_data['new_shape'] + else: + shape = helper.attr_data(op, 'shape') + shape = map(int, shape + [1] * (4 - len(shape))) + OpsRegister()["Reshape"].dims = shape + +@ParserFeedDecorator("Concat") +def Parser_concat(args): + op = args[1] + helper = args[3] + OpsRegister()["Concat"].axis = helper.attr_data(op, 'axis') + +@ParserFeedDecorator("Concat") +def Parser_concat_btw_priorbox_boxcoder(args): + op = args[1] + helper = args[3] + OpsRegister()["Concat"].axis = 3 + +@ParserFeedDecorator("Permute") +def Parser_transpose(args): + op = args[1] + helper = args[3] + fluid_dims = helper.attr_data(op, 'axis') + n = 4 - len(fluid_dims) + dims = range(0, n) + tail_dims = [i + n for i in fluid_dims] + dims.extend(tail_dims) + OpsRegister()["Permute"].dims = dims + + +########## SSD Model ########## + +@ParserFeedDecorator("PriorBox") +def Parser_prior_box(args): + op = args[1] + helper = args[3] + OpsRegister()["PriorBox"].min_size = helper.attr_data(op, 'min_sizes') + OpsRegister()["PriorBox"].max_size = helper.attr_data(op, 'max_sizes') + OpsRegister()["PriorBox"].aspect_ratio = helper.attr_data(op, 'aspect_ratios') + OpsRegister()["PriorBox"].is_flip = helper.attr_data(op, 'flip') + OpsRegister()["PriorBox"].is_clip = helper.attr_data(op, 'clip') + OpsRegister()["PriorBox"].variance = helper.attr_data(op, 'variances') + OpsRegister()["PriorBox"].img_h = 0 + OpsRegister()["PriorBox"].img_w = 0 + OpsRegister()["PriorBox"].step_h = helper.attr_data(op, 'step_h') + OpsRegister()["PriorBox"].step_w = helper.attr_data(op, 'step_w') + OpsRegister()["PriorBox"].offset = helper.attr_data(op, 'offset') + OpsRegister()["PriorBox"].order = ['MIN', 'COM', 'MAX'] + +@ParserFeedDecorator("box_coder") +def Parser_box_coder(args): + pass + +@ParserFeedDecorator("DetectionOutput") +def Parser_multiclass_nms(args): + op = args[1] + helper = args[3] + private_data = args[4] + OpsRegister()["DetectionOutput"].share_location = True + OpsRegister()["DetectionOutput"].variance_encode_in_target = False + OpsRegister()["DetectionOutput"].class_num = 0 + OpsRegister()["DetectionOutput"].background_id = helper.attr_data(op, 'background_label') + OpsRegister()["DetectionOutput"].keep_top_k = helper.attr_data(op, 'keep_top_k') + OpsRegister()["DetectionOutput"].conf_thresh = helper.attr_data(op, 'score_threshold') + OpsRegister()["DetectionOutput"].nms_top_k = helper.attr_data(op, 'nms_top_k') + OpsRegister()["DetectionOutput"].nms_thresh = helper.attr_data(op, 'nms_threshold') + OpsRegister()["DetectionOutput"].nms_eta = helper.attr_data(op, 'nms_eta') + if 'code_type' in private_data.keys(): + if private_data['code_type'] == 'decode_center_size': + OpsRegister()["DetectionOutput"].code_type = "CENTER_SIZE" + else: + OpsRegister()["DetectionOutput"].code_type = "CORNER" + + +########## VIS Model ########## + +@ParserFeedDecorator("Im2Sequence") +def Parser_im2sequence(args): + op = args[1] + helper = args[3] + OpsRegister()["Im2Sequence"].paddings = helper.attr_data(op, 'paddings') + OpsRegister()["Im2Sequence"].strides = helper.attr_data(op, 'strides') + OpsRegister()["Im2Sequence"].window_size = helper.attr_data(op, 'kernels') + OpsRegister()["Im2Sequence"].dilations = helper.attr_data(op, 'dilations', [1, 1]) + +@ParserFeedDecorator("Cast") +def Parser_cast(args): + op = args[1] + helper = args[3] + OpsRegister()["Cast"].in_type = helper.attr_data(op, 'in_dtype') + OpsRegister()["Cast"].out_type = helper.attr_data(op, 'out_dtype') + +@ParserFeedDecorator("Argmax") # new256 +def Parser_top_k(args): + op = args[1] + helper = args[3] + OpsRegister()["Argmax"].out_max_val = True + OpsRegister()["Argmax"].top_k = helper.attr_data(op, 'k') + OpsRegister()["Argmax"].axis_term = False + +@ParserFeedDecorator("CtcAlign") +def Parser_ctc_align(args): + op = args[1] + helper = args[3] + OpsRegister()["CtcAlign"].merge_repeated = helper.attr_data(op, 'merge_repeated') + OpsRegister()["CtcAlign"].blank = helper.attr_data(op, 'blank') + +@ParserFeedDecorator("Eltwise") +def Parser_sum(args): + OpsRegister()["Eltwise"].type = "Add" + OpsRegister()["Eltwise"].coeff = [1.0, 1.0] + +@ParserFeedDecorator("LRN") +def Parser_lrn(args): + op = args[1] + helper = args[3] + OpsRegister()["LRN"].local_size = helper.attr_data(op, 'n') + OpsRegister()["LRN"].alpha = helper.attr_data(op, 'alpha') + OpsRegister()["LRN"].beta = helper.attr_data(op, 'beta') + OpsRegister()["LRN"].norm_region = "ACROSS_CHANNELS" + OpsRegister()["LRN"].k = helper.attr_data(op, 'k') + +@ParserFeedDecorator("Gru") +def Parser_gru(args): + op = args[1] + helper = args[3] + private_data = args[4] + OpsRegister()["Gru"].is_reverse = helper.attr_data(op, 'is_reverse') + OpsRegister()["Gru"].gate_activation = helper.attr_data(op, 'gate_activation') + '_fluid' + OpsRegister()["Gru"].activation = helper.attr_data(op, 'activation') + '_fluid' + OpsRegister()["Gru"].gru_formula = "gru_origin" + if bool(private_data) is True: + ori_bx = private_data['np_bias_x'] + ori_bh = helper.np_param(op, 'Bias') + ori_b = ori_bx + ori_bh + ori_wx = private_data['np_weight_x'] + ori_wh = helper.np_param(op, 'Weight') + new_tensors = helper.gru_tensor_convert(ori_wh, ori_wx, ori_b) + weights = [] + for tensor in new_tensors: + weights.append(helper.create_tensor(list(tensor.flatten()), \ + list(np.shape(tensor)), FLOAT)) + OpsRegister()["Gru"].weight_1 = weights[0] + OpsRegister()["Gru"].weight_2 = weights[1] + else: + OpsRegister()["Gru"].weight_1 = helper.param_tensor(op, 'Weight') + OpsRegister()["Gru"].weight_2 = helper.create_tensor([0], [-1], FLOAT) + +@ParserFeedDecorator("LSTM") +def Parser_lstm(args): + op = args[1] + helper = args[3] + private_data = args[4] + OpsRegister()["LSTM"].candidate_activation = helper.attr_data(op, 'candidate_activation') + OpsRegister()["LSTM"].cell_activation = helper.attr_data(op, 'cell_activation') + OpsRegister()["LSTM"].gate_activation = helper.attr_data(op, 'gate_activation') + OpsRegister()["LSTM"].is_reverse = helper.attr_data(op, 'is_reverse') + OpsRegister()["LSTM"].use_peepholes = helper.attr_data(op, 'use_peepholes') + OpsRegister()["LSTM"].num_direction = 1 + OpsRegister()["LSTM"].dropout_param = 1.0 + OpsRegister()["LSTM"].num_layers = 1 + OpsRegister()["LSTM"].input_activation = "null" + if bool(private_data) is True: + np_fc_bias = private_data['np_flat_fc_bias'] + np_fc_weight = private_data['np_flat_fc_weight'] + np_fc_outdim = private_data['np_fc_outdim'] + np_lstm_bias = helper.np_param(op, 'Bias') + np_lstm_weight = helper.np_param(op, 'Weight') + np_tensors = helper.lstm_fc_tensor_merge_convert(np_fc_outdim, np_lstm_weight, \ + np_lstm_bias, np_fc_weight, np_fc_bias) + np_weight = np_tensors[0] + np_bias = np_tensors[1] + np_weight_shape = map(int, [1] * (4 - len(np_weight.shape)) + list(np_weight.shape)) + np_bias_shape = map(int, [1] * (4 - len(np_bias.shape)) + list(np_bias.shape)) + np_weight_tensor = helper.create_tensor(list(np_weight.flatten()), np_weight_shape, FLOAT) + np_bias_tensor = helper.create_tensor(list(np_bias.flatten()), np_bias_shape, FLOAT) + OpsRegister()["LSTM"].weight_1 = np_weight_tensor + OpsRegister()["LSTM"].weight_2 = np_bias_tensor + else: + OpsRegister()["LSTM"].weight_1 = helper.param_tensor(op, 'Weight') + OpsRegister()["LSTM"].weight_2 = helper.create_tensor([0], [-1], FLOAT) + + +############### RNN ############### + +@ParserFeedDecorator("Embedding") +def Parser_lookup_table(args): + op = args[1] + helper = args[3] + [weights_tensor, weights_shape] = helper.param_tensor_sh(op, 'W') + OpsRegister()["Embedding"].weight_1 = weights_tensor + OpsRegister()["Embedding"].padding_idx = helper.attr_data(op, 'padding_idx') + OpsRegister()["Embedding"].word_num = weights_shape[2] + OpsRegister()["Embedding"].emb_dim = weights_shape[3] + +@ParserFeedDecorator("SequencePool") +def Parser_sequence_pool(args): + op = args[1] + helper = args[3] + OpsRegister()["SequencePool"].pooltype = helper.attr_data(op, 'pooltype') + +@ParserFeedDecorator("Activation") +def Parser_tanh(args): + OpsRegister()["Activation"].type = "TanH" + +@ParserFeedDecorator("SequenceConv") +def Parser_sequence_conv(args): + op = args[1] + helper = args[3] + private_data = args[4] + [weights_tensor, weights_shape] = helper.param_tensor_sh(op, 'Filter') + OpsRegister()["SequenceConv"].weight_1 = weights_tensor + OpsRegister()["SequenceConv"].filter_num = weights_shape[0] + OpsRegister()["SequenceConv"].kernel_size = weights_shape[-2:] + OpsRegister()["SequenceConv"].padding_trainable = helper.attr_data(op, 'paddingTrainable') + OpsRegister()["SequenceConv"].context_stride = helper.attr_data(op, 'contextStride') + OpsRegister()["SequenceConv"].context_start = helper.attr_data(op, 'contextStart') + OpsRegister()["SequenceConv"].context_length = helper.attr_data(op, 'contextLength') + if 'bias' in private_data.keys(): + OpsRegister()["SequenceConv"].bias_term = True + OpsRegister()["SequenceConv"].weight_2 = private_data['bias'] + else: + OpsRegister()["SequenceConv"].bias_term = False + +@ParserFeedDecorator("CrfDecoding") +def Parser_crf_decoding(args): + op = args[1] + helper = args[3] + [weights_tensor, weights_shape] = helper.param_tensor_sh(op, 'Transition') + OpsRegister()["CrfDecoding"].weight_1 = weights_tensor + +@ParserFeedDecorator("MatMul") +def Parser_matmul(args): + op = args[1] + helper = args[3] + private_data = args[4] + if 'coeff' in private_data.keys(): + coeff = private_data['coeff'] + else: + coeff = 1.0 + OpsRegister()["MatMul"].transpose_x = helper.attr_data(op, 'transpose_X') + OpsRegister()["MatMul"].transpose_y = helper.attr_data(op, 'transpose_Y') + OpsRegister()["MatMul"].coeff = coeff + +@ParserFeedDecorator("Scale") +def Parser_scale(args): + op = args[1] + helper = args[3] + scale_val = helper.attr_data(op, 'scale') + OpsRegister()["Scale"].axis = 0 + OpsRegister()["Scale"].num_axes = 0 + OpsRegister()["Scale"].bias_term = False + OpsRegister()["Scale"].weight_1 = helper.create_tensor([scale_val], [1, 1, 1, 1], FLOAT) + +@ParserFeedDecorator("LayerNorm") +def Parser_layer_norm(args): + op = args[1] + helper = args[3] + OpsRegister()["LayerNorm"].weight_1 = helper.param_tensor(op, 'Scale') + OpsRegister()["LayerNorm"].weight_2 = helper.param_tensor(op, 'Bias') + OpsRegister()["LayerNorm"].begin_norm_axis = helper.attr_data(op, 'begin_norm_axis') + OpsRegister()["LayerNorm"].eps = helper.attr_data(op, 'epsilon') + +@ParserFeedDecorator("Scale") +def Parser_dropout(args): + op = args[1] + helper = args[3] + scale_val = 1 - helper.attr_data(op, 'dropout_prob') + OpsRegister()["Scale"].axis = 0 + OpsRegister()["Scale"].num_axes = 0 + OpsRegister()["Scale"].bias_term = False + OpsRegister()["Scale"].weight_1 = helper.create_tensor([scale_val], [1, 1, 1, 1], FLOAT) + +@ParserFeedDecorator("Scale") +def Parser_elementwise_mul(args): + op = args[1] + helper = args[3] + private_data = args[4] + OpsRegister()["Scale"].weight_1 = helper.param_tensor(op, 'Y') + OpsRegister()["Scale"].axis = helper.attr_data(op, 'axis') + OpsRegister()["Scale"].num_axes = 1 + if 'bias' in private_data.keys(): + OpsRegister()["Scale"].bias_term = True + OpsRegister()["Scale"].weight_2 = private_data['bias'] + else: + OpsRegister()["Scale"].bias_term = False + +@ParserFeedDecorator("Flatten") +def Parser_flatten(args): + pass + +@ParserFeedDecorator("assign_value") +def Parser_assign_value(args): + pass + +@ParserFeedDecorator("shape") +def Parser_shape(args): + pass + +FLUID_NODE_FILLER = { + "feed":OpsParam().set_parser(Parser_feed), + "conv2d":OpsParam().set_parser(Parser_conv2d), + "elementwise_add":OpsParam().set_parser(Parser_sum), + "relu":OpsParam().set_parser(Parser_relu), + "pool2d":OpsParam().set_parser(Parser_pool2d), + "mul":OpsParam().set_parser(Parser_mul), + "softmax":OpsParam().set_parser(Parser_softmax), + "sigmoid":OpsParam().set_parser(Parser_sigmoid), + "axpy":OpsParam().set_parser(Parser_axpy), + "batch_norm":OpsParam().set_parser(Parser_batch_norm), + "disc_bn":OpsParam().set_parser(Parser_scale_disc_bn), + "scale_of_bn":OpsParam().set_parser(Parser_scale_of_bn), + "elementwise_mul":OpsParam().set_parser(Parser_elementwise_mul), + "split":OpsParam().set_parser(Parser_split), + "depthwise_conv2d":OpsParam().set_parser(Parser_conv2d), + "reshape":OpsParam().set_parser(Parser_reshape), + "concat":OpsParam().set_parser(Parser_concat), + "transpose":OpsParam().set_parser(Parser_transpose), + "prior_box":OpsParam().set_parser(Parser_prior_box), + "box_coder":OpsParam().set_parser(Parser_box_coder), + "multiclass_nms":OpsParam().set_parser(Parser_multiclass_nms), + "concat_btw_priorbox_boxcoder":OpsParam().set_parser(Parser_concat_btw_priorbox_boxcoder), + "im2sequence":OpsParam().set_parser(Parser_im2sequence), + "gru":OpsParam().set_parser(Parser_gru), + "sum":OpsParam().set_parser(Parser_sum), + "lrn":OpsParam().set_parser(Parser_lrn), + "top_k":OpsParam().set_parser(Parser_top_k), + "ctc_align":OpsParam().set_parser(Parser_ctc_align), + "cast":OpsParam().set_parser(Parser_cast), + "lookup_table":OpsParam().set_parser(Parser_lookup_table), + "sequence_pool":OpsParam().set_parser(Parser_sequence_pool), + "tanh":OpsParam().set_parser(Parser_tanh), + "sequence_conv":OpsParam().set_parser(Parser_sequence_conv), + "crf_decoding":OpsParam().set_parser(Parser_crf_decoding), + "lstm":OpsParam().set_parser(Parser_lstm), + "matmul":OpsParam().set_parser(Parser_matmul), + "layer_norm":OpsParam().set_parser(Parser_layer_norm), + "dropout":OpsParam().set_parser(Parser_dropout), + "scale":OpsParam().set_parser(Parser_scale), + "flatten":OpsParam().set_parser(Parser_flatten), + "assign_value":OpsParam().set_parser(Parser_assign_value), + "shape":OpsParam().set_parser(Parser_shape), +} diff --git a/tools/external_converter_v2/parser/fluid/parser_fluid.py b/tools/external_converter_v2/parser/fluid/parser_fluid.py new file mode 100644 index 000000000..84efb8949 --- /dev/null +++ b/tools/external_converter_v2/parser/fluid/parser_fluid.py @@ -0,0 +1,932 @@ +import numpy as np +import paddle.fluid as fluid +import os +from ..graph_io import * +from ..logger import * +from ..proto import * +from fluid_layer_param_transmit import * + +class FluidParser: + + def __init__(self, fluid_config_dict): + # anakin graph model io + self.graphIO = None + # config info + self.ModelPath = fluid_config_dict['ModelPath'] + self.NetType = fluid_config_dict['NetType'] + self.Debug = fluid_config_dict['Debug'] + # config fluid + self.place = fluid.CPUPlace() + self.exe = fluid.Executor(self.place) + self.scope = fluid.core.Scope() + # in and out edges of node + self.ins = {} + self.outs = {} + # inplaced main node + self.inplace_nodes = {} + self.graph_ins = [] + self.graph_outs = [] + + def __call__(self): + return self._Parsing() + + def _NameNodeMid(self, op): + first_outparam = op.output_names[0] + arg_name = str(op.output(first_outparam)[0]).split('.')[0] + #new_name = op.type + '_' + bytes(op.idx) + new_name = op.type + '#' + bytes(op.idx) + '(' + arg_name + ')' + return new_name + + def _NameNodeIn(self, in_name): + new_name = 'input_' + bytes(self.graph_ins.index(in_name)) + return new_name + + def _NameNodeOut(self, out_name): + new_name = out_name + '_gout' + return new_name + + def _AddPairEdges(self, start_node_name, end_node_name, out_param, in_param): + self.outs[start_node_name].add(out_param, end_node_name) + self.ins[end_node_name].add(in_param, start_node_name) + + def _RmPairEdges(self, start_node_name, end_node_name): + self.outs[start_node_name].rm(end_node_name) + self.ins[end_node_name].rm(start_node_name) + + def _InitEdges(self, node_name): + self.ins[node_name] = Fluid_edger() + self.outs[node_name] = Fluid_edger() + + def _ClearEdges(self, node_name): + if node_name.startswith('input_') is False: + del self.ins[node_name] + if node_name.endswith('_gout') is False: + del self.outs[node_name] + + def _GetOp(self, ops, mid_node_name): + mid_op = None + for op in ops: + node_name = self._NameNodeMid(op) + if mid_node_name == node_name: + mid_op = op + return mid_op + + def _OpTypes(self, ops): + types_cache = [] + for op in ops: + if op.type not in types_cache: + types_cache.append(op.type) + return types_cache + + def _AddProtoNode(self, node_name, op_of_node, helper, private_data, op_type=None): + nodeIO = NodeProtoIO() + opIO = OpsProtoIO() + nodeIO.set_name(node_name) + if op_type is None: + op_type = op_of_node.type + FLUID_NODE_FILLER[op_type](nodeIO, op_of_node, opIO, helper, private_data) + self.graphIO.add_node(nodeIO()) + + def _RmProtoNode(self, node_name): + self.graphIO.rm_node(self.graphIO.find_node_proto(node_name)) + + def _InplaceNodes(self, position): + inplace_heads = self.inplace_nodes.keys() + inplace_mids = [] + inplace_ends = [] + for main_node_name in self.inplace_nodes.keys(): + mid_nodes_name = self.inplace_nodes[main_node_name][1: -1] + inplace_mids.extend(mid_nodes_name) + for main_node_name in self.inplace_nodes.keys(): + end_node_name = self.inplace_nodes[main_node_name][-1] + inplace_ends.append(end_node_name) + if position == 'Head': + return inplace_heads + elif position == 'Mid': + return inplace_mids + elif position == 'End': + return inplace_ends + elif position == 'All': + return inplace_heads + inplace_mids + inplace_ends + + def _EdgeInplace(self, source_ops, helper): + for source_op in source_ops: + if source_op.type not in ['feed', 'fetch']: + if len(source_op.input_arg_names) == 1 \ + and source_op.input_arg_names == source_op.output_arg_names: + source_node_name = self._NameNodeMid(source_op) + inplace_arg = source_op.input_arg_names[0] + for tmp_op in source_ops: + if tmp_op.idx != source_op.idx and inplace_arg in tmp_op.output_arg_names: + main_node_name = self._NameNodeMid(tmp_op) + if main_node_name not in self.inplace_nodes.keys(): + self.inplace_nodes[main_node_name] = [main_node_name] + self.inplace_nodes[main_node_name].append(source_node_name) + for main_node_name in self.inplace_nodes.keys(): + inplace_list = self.inplace_nodes[main_node_name] + for inplace_node in inplace_list: + idx = inplace_list.index(inplace_node) + if idx != 0: + self.ins[inplace_node] = Fluid_edger('_In', inplace_list[idx - 1]) + if idx != len(inplace_list) - 1: + self.outs[inplace_node] = Fluid_edger('_Out', inplace_list[idx + 1]) + + def _GetDebugOuts(self, source_ops, helper): + if self.Debug == 'DEBUG': + debug_fetch_list = [] + for source_op in source_ops: + if source_op.type == 'fetch': + var_name = source_op.input_arg_names[0] + for tmp_op in source_ops: + if tmp_op.idx != source_op.idx and var_name in tmp_op.input_arg_names: + if var_name not in debug_fetch_list: + debug_fetch_list.append(var_name) + elif tmp_op.type == 'gru' and var_name in tmp_op.output_arg_names: + if var_name not in debug_fetch_list: + debug_fetch_list.append(var_name) + else: + pass + return debug_fetch_list + else: + return [] + + def _ParseBase(self, source_ops, helper, sub_graph_nodes=None): + # Create the original base graph as described in fluid program. + if sub_graph_nodes is None: + sub_graph_nodes = list() + self.graphIO = GraphProtoIO() + self.graphIO.set_name('default_graph_name') + debug_fetch_list = self._GetDebugOuts(source_ops, helper) + self._EdgeInplace(source_ops, helper) + for source_op in source_ops: + if source_op.type not in ['feed', 'fetch']: + main_node_name = self._NameNodeMid(source_op) + in_edges = Fluid_edger() + out_edges = Fluid_edger() + for param in source_op.input_names: + for idx in range(0, len(helper.args_by_input_param(source_op, param))): + arg = helper.var_name_by_param(source_op, param, idx) + for tmp_op in source_ops: + if tmp_op.idx != source_op.idx and arg in tmp_op.output_arg_names: + if tmp_op.type == 'feed': + if arg not in self.graph_ins: + self.graph_ins.append(arg) + self.graphIO.add_in(self._NameNodeIn(arg)) + in_edges.add(param, self._NameNodeIn(arg), arg) + else: + tmp_node_name = self._NameNodeMid(tmp_op) + if tmp_node_name in self.inplace_nodes.keys(): + inplace_node_name = self.inplace_nodes[tmp_node_name][-1] + in_edges.add(param, inplace_node_name, arg) + elif tmp_node_name not in self._InplaceNodes('All'): + in_edges.add(param, tmp_node_name, arg) + for param in source_op.output_names: + for idx in range(0, len(helper.args_by_output_param(source_op, param))): + arg = helper.var_name_by_param(source_op, param, idx) + for tmp_op in source_ops: + if tmp_op.idx != source_op.idx and arg in tmp_op.input_arg_names: + if tmp_op.type == 'fetch': + if arg not in debug_fetch_list: + arg_node_name = self._NameNodeOut(arg) + if arg not in self.graph_outs: + self.graph_outs.append(arg) + self.graphIO.add_out_fluid(arg_node_name, \ + main_node_name) + out_edges.add(param, arg_node_name, arg) + self.ins[arg_node_name] = Fluid_edger(bytes(source_op.idx), \ + main_node_name) + else: + out_edges.add(param, self._NameNodeMid(tmp_op), arg) + self._AddProtoNode(main_node_name, source_op, helper, {}) + if main_node_name not in self._InplaceNodes('Mid'): + if main_node_name not in self._InplaceNodes('End'): + self.ins[main_node_name] = in_edges + if main_node_name not in self._InplaceNodes('Head'): + if main_node_name not in self._InplaceNodes('End'): + self.outs[main_node_name] = out_edges + else: + inplace_node_name = self.inplace_nodes[main_node_name][-1] + self.outs[inplace_node_name] = out_edges + for redundant_target in self.inplace_nodes[main_node_name][1:]: + self.outs[inplace_node_name].rm(redundant_target) + + def _PrintEdge(self, node, target, direction): + var_name = 'Unknown' + if direction == 'in': + var = self.ins[node].vars_by_target(target) + elif direction == 'out': + var = self.outs[node].vars_by_target(target) + if len(var) > 0: + var_name = var[0] + print node + ",\t" + target + ",\t" + var_name + + def _Graph(self, need_print=False): + for node in self.ins.keys(): + targets_list = self.ins[node]() + for target in targets_list: + self.graphIO.add_in_edge(target, node) + for node in self.outs.keys(): + targets_list = self.outs[node]() + for target in targets_list: + self.graphIO.add_out_edge(node, target) + if need_print is True: + self._PrintEdge(node, target, 'out') + + def _ReplaceInputs(self, source_ops, helper, reshape_dict=None, layout='NCHW'): + if reshape_dict is None: + reshape_dict = dict() + for source_op in source_ops: + if source_op.type in ['feed']: + out_edges = Fluid_edger() + for param in source_op.output_names: + private_data = {} + arg = helper.var_name_by_param(source_op, param) + input_node_name = self._NameNodeIn(arg) + for tmp_op in source_ops: + if tmp_op.idx != source_op.idx and arg in tmp_op.input_arg_names: + out_edges.add(param, self._NameNodeMid(tmp_op)) + arg_idx = source_op.output_arg_names.index(arg) + shape = helper.var_shape_by_param(False, source_op, \ + "Out", arg_idx, 'UNMODIFIED') + if shape[0] == -1: + shape[0] = 1 + if layout == 'NCHW': + shape = map(int, [1] * (4 - len(shape)) + shape) + if input_node_name in reshape_dict.keys(): + shape = reshape_dict[input_node_name] + private_data['input_shape'] = shape + private_data['alias'] = arg + self.outs[input_node_name] = out_edges + self._AddProtoNode(input_node_name, source_op, helper, private_data) + + def _InsertSplit(self, source_ops, helper): + # If a layer has two identical output tensors, add a split layer. + for node in self.outs.keys(): + if node.startswith('split#') is False: + out_edges = self.outs[node] + for param in out_edges.all_params(): + out_targets_list = out_edges.targets(param) + if len(out_targets_list) > 1: + private_data = {} + private_data['split_num'] = len(out_targets_list) + split_node_name = 'split#' + \ + bytes(out_edges.all_params().index(param)) + '#' + node + self._InitEdges(split_node_name) + for out_target in out_targets_list: + self.outs[node].rm(out_target) + self.ins[out_target].mv(node, split_node_name) + self.outs[split_node_name].add('_Out', out_target) + self._AddPairEdges(node, split_node_name, param, '_In') + self._AddProtoNode(split_node_name, None, helper, private_data, 'split') + + def _Subgraph(self, starts, ends): + """ + """ + out_idx = {} + results = union(starts, ends) + def outs(node): + """ + """ + if node in self.outs.keys(): + return self.outs[node]() + else: + return [] + def next_out(node): + """ + """ + next_out = '' + if len(outs(node)) == 0: + return -1 + elif node not in out_idx.keys(): + out_idx[node] = 0 + if out_idx[node] < len(outs(node)): + next_out = outs(node)[out_idx[node]] + out_idx[node] += 1 + return next_out + for start in starts: + cache = [start] + while len(cache) > 0: + target = next_out(cache[-1]) + while target != -1 and target not in results: + if bool(target) is True: + cache.append(target) + target = next_out(target) + else: + if cache[-1] in results: + results = union(results, cache) + break + if target in results: + cache.append(target) + results = union(results, cache) + cache.pop() + return results + + def _CropGraph(self, ins_of_subgraph, outs_of_subgraph, helper, need_io = True): + ''' + ''' + def all_nodes(): + ''' + ''' + all_nodes = [] + for main_node in self.ins.keys(): + all_nodes.extend(self.ins[main_node].all_targets()) + for main_node in self.outs.keys(): + all_nodes.extend(self.outs[main_node].all_targets()) + return list(set(all_nodes)) + stayed_nodes = self._Subgraph(ins_of_subgraph, outs_of_subgraph) + all_nodes = all_nodes() + extra_nodes = difference(all_nodes, stayed_nodes) + for node_name in extra_nodes: + self._RmProtoNode(node_name) + self._ClearEdges(node_name) + if node_name in self.graphIO.ins(): + self.graphIO.rm_in(node_name) + if node_name in self.graphIO.outs(): + self.graphIO.rm_out(node_name) + for node_name in ins_of_subgraph: + if node_name in self.ins: + self.ins[node_name].clear() + for node_name in outs_of_subgraph: + if node_name in self.outs: + self.outs[node_name].clear() + if need_io is True: + for node_name in outs_of_subgraph: + if node_name not in self.graphIO.outs(): + out_node_name = node_name + '_crop_out' + self.ins[out_node_name] = Fluid_edger('_In', node_name) + self.outs[node_name] = Fluid_edger('_Out', out_node_name) + self.graphIO.add_out_fluid(out_node_name, node_name) + for node_name in ins_of_subgraph: + if node_name not in self.graphIO.ins(): + in_node_name = node_name + '_crop_in' + private_data = {'input_shape': [-1, -1, -1, -1]} + self.ins[node_name] = Fluid_edger('_In', in_node_name) + self.outs[in_node_name] = Fluid_edger('_Out', node_name) + self._AddProtoNode(in_node_name, None, helper, private_data, 'feed') + + def _IntegrateNodes(self, main_op, main_node_name, sec_node_name, helper, private_data): + # Merge secondary nodes to the primary node and process the edges. + self._RmProtoNode(main_node_name) + self._RmProtoNode(sec_node_name) + target_nodes_names = self.outs[sec_node_name]() + for target_node_name in target_nodes_names: + self.ins[target_node_name].mv(sec_node_name, main_node_name) + self.outs[main_node_name].mv(sec_node_name, target_node_name) + self.ins[target_node_name].rm(sec_node_name) + self.outs[sec_node_name].rm(target_node_name) + self.ins[sec_node_name].rm(main_node_name) + self.outs[main_node_name].rm(sec_node_name) + self._AddProtoNode(main_node_name, main_op, helper, private_data) + + def _DealWithBias(self, source_ops, helper): + # In fluid, the bias parameter of the conv2d is split into elementwise_add. + for source_op in source_ops: + if source_op.type in APPEND_BIAS_OP_TYPE: + private_data = {} + main_node_name = self._NameNodeMid(source_op) + if main_node_name in self.outs.keys(): + tmp_nodes_names = self.outs[main_node_name]() + if len(tmp_nodes_names) == 1 and \ + tmp_nodes_names[0].startswith('elementwise_add'): + elt_node_name = tmp_nodes_names[0] + elt_op = self._GetOp(source_ops, elt_node_name) + has_weights = helper.is_persistable_param(elt_op, 'Y') + if self._NameNodeMid(elt_op) == elt_node_name and has_weights: + [elt_tensor, shape] = helper.param_tensor_sh(elt_op, 'Y') + new_shape = [1, shape[3], 1, 1] + elt_tensor.set_shape(new_shape) + private_data['bias'] = elt_tensor + self._IntegrateNodes(source_op, main_node_name, \ + elt_node_name, helper, private_data) + + def _DealWithBatchnorm(self, source_ops, helper): + # In anakin, the scale part of batchnorm layer is independent. + for source_op in source_ops: + if source_op.type == 'batch_norm': + discrete_flag = True + main_node_name = self._NameNodeMid(source_op) + input_name = self.ins[main_node_name].target('X') + has_scale = helper.is_persistable_param(source_op, 'Scale') + if input_name.startswith('elementwise_add'): + elt_op = self._GetOp(source_ops, input_name) + x_of_elt = self.ins[input_name].target('X') + has_weights = helper.is_persistable_param(elt_op, 'Y') + if (x_of_elt.startswith('conv2d') or \ + x_of_elt.startswith('depthwise_conv2d')) and has_weights: + discrete_flag = False + elif input_name.startswith('conv2d') or input_name.startswith('depthwise_conv2d'): + discrete_flag = False + if discrete_flag is True: + self._RmProtoNode(main_node_name) + self._AddProtoNode(main_node_name, source_op, helper, {}, 'disc_bn') + elif has_scale is True: + append_node_name = main_node_name + '__scale' + tmp_all_targets_params = self.outs[main_node_name].targets_with_params() + self._InitEdges(append_node_name) + for [tmp_node_name, tmp_param_name] in tmp_all_targets_params: + self.outs[append_node_name].add(tmp_param_name, tmp_node_name) + self.ins[tmp_node_name].mv(main_node_name, append_node_name) + self.outs[main_node_name].rm(tmp_node_name) + self.ins[tmp_node_name].rm(main_node_name) + self.outs[main_node_name].add('_Scale_out', append_node_name) + self.ins[append_node_name].add('_Ins', main_node_name) + self._AddProtoNode(append_node_name, source_op, helper, {}, 'scale_of_bn') + + def _DealWithAxpy(self, source_ops, helper): + for source_op in source_ops: + if source_op.type == 'elementwise_mul': + mul_node_name = self._NameNodeMid(source_op) + out_targets = self.outs[mul_node_name]() + if len(out_targets) == 1 and out_targets[0].startswith('elementwise_add'): + add_node_name = out_targets[0] + self._RmProtoNode(add_node_name) + a_node_name = self.ins[mul_node_name].target('Y') + x_node_name = self.ins[mul_node_name].target('X') + y_node_name = self.ins[add_node_name].target('X') + self._ClearEdges(mul_node_name) + self.ins[add_node_name].clear() + self.outs[a_node_name].mv(mul_node_name, add_node_name) + self.outs[x_node_name].mv(mul_node_name, add_node_name) + self.ins[add_node_name].add('A', a_node_name) + self.ins[add_node_name].add('X', x_node_name) + self.ins[add_node_name].add('Y', y_node_name) + self._RmProtoNode(mul_node_name) + self._AddProtoNode(add_node_name, None, helper, {}, 'axpy') + + def _DealWithPriorBox(self, source_ops, helper): + nodes_to_del = [] + for source_op in source_ops: + if source_op.type == 'prior_box': + pb_node_name = self._NameNodeMid(source_op) + br_node_name = self.outs[pb_node_name].target('Boxes') + vr_node_name = self.outs[pb_node_name].target('Variances') + bc_node_name = self.outs[br_node_name].target('Out') + vc_node_name = self.outs[vr_node_name].target('Out') + boxcoder_node_name = self.outs[bc_node_name].target('Out') + self.outs[pb_node_name].mv(br_node_name, bc_node_name) + self.outs[pb_node_name].rm(vr_node_name) + self.ins[bc_node_name].mv(br_node_name, pb_node_name) + self.ins[boxcoder_node_name].rm(vc_node_name) + for node_name in [br_node_name, vr_node_name, vc_node_name]: + if node_name not in nodes_to_del: + nodes_to_del.append(node_name) + input_node_name = self.ins[pb_node_name].target('Input') + image_node_name = self.ins[pb_node_name].target('Image') + self.ins[pb_node_name].rm(input_node_name) + self.ins[pb_node_name].rm(image_node_name) + self.ins[pb_node_name].add('Input', input_node_name) + self.ins[pb_node_name].add('Image', image_node_name) + self._RmProtoNode(bc_node_name) + self._AddProtoNode(bc_node_name, None, helper, {}, 'concat_btw_priorbox_boxcoder') + for node_name in nodes_to_del: + self._RmProtoNode(node_name) + self._ClearEdges(node_name) + + def _DealWithDetectionOutput(self, source_ops, helper): + for source_op in source_ops: + if source_op.type == 'box_coder': + bc_node_name = self._NameNodeMid(source_op) + out_targets = self.outs[bc_node_name]() + if len(out_targets) == 1 and out_targets[0].startswith('multiclass_nms'): + private_data = {} + private_data['code_type'] = helper.attr_data(source_op, 'code_type') + bc_out_arg = helper.var_name_by_param(source_op, 'OutputBox') + for tmp_op in source_ops: + if tmp_op.idx != source_op.idx and bc_out_arg in tmp_op.input_arg_names: + nms_op = tmp_op + nms_node_name = out_targets[0] + loc_node_name = self.ins[bc_node_name].target('TargetBox') + conf_node_name = self.ins[nms_node_name].target('Scores') + box_node_name = self.ins[bc_node_name].target('PriorBox') + self._ClearEdges(bc_node_name) + self.ins[nms_node_name].clear() + self.outs[loc_node_name].mv(bc_node_name, nms_node_name) + self.outs[box_node_name].mv(bc_node_name, nms_node_name) + self.ins[nms_node_name].add('mbox_loc', loc_node_name) + self.ins[nms_node_name].add('mbox_conf_flatten', conf_node_name) + self.ins[nms_node_name].add('mbox_prior_box', box_node_name) + self._RmProtoNode(bc_node_name) + self._RmProtoNode(nms_node_name) + self._AddProtoNode(nms_node_name, nms_op, helper, \ + private_data, 'multiclass_nms') + + def _DealWithMultiFC(self, source_ops, helper): + for source_op in source_ops: + if source_op.type == 'sum': + sum_node_name = self._NameNodeMid(source_op) + mul_names_list = self.ins[sum_node_name].targets('X') + elt_node_name = self.outs[sum_node_name].target('Out') + if elt_node_name.startswith('elementwise_add') and len(mul_names_list) > 1: + elt_op = self._GetOp(source_ops, elt_node_name) + elt_has_weights = helper.is_persistable_param(elt_op, 'Y') + fc_flag = True + for mul_node_name in mul_names_list: + if mul_node_name.startswith('mul') is False: + fc_flags = False + if fc_flag and elt_has_weights: + private_data = {} + first_mul_name = mul_names_list[0] + first_mul_op = self._GetOp(source_ops, first_mul_name) + in_of_mul_name = self.ins[first_mul_name].target('X') + out_of_elt_name = self.outs[elt_node_name].target('Out') + self.outs[sum_node_name].mv(elt_node_name, out_of_elt_name) + self.ins[out_of_elt_name].mv(elt_node_name, sum_node_name) + self._ClearEdges(elt_node_name) + [elt_tensor, shape] = helper.param_tensor_sh(elt_op, 'Y') + new_shape = [1, shape[3], 1, 1] + elt_tensor.set_shape(new_shape) + private_data['bias'] = elt_tensor + self._RmProtoNode(elt_node_name) + self._RmProtoNode(first_mul_name) + self._AddProtoNode(first_mul_name, first_mul_op, helper, private_data) + + def _DealWithGru(self, source_ops, helper): + for source_op in source_ops: + if source_op.type == 'gru': + private_data = {} + gru_flags = [False, False] + gru_node_name = self._NameNodeMid(source_op) + gru_op = self._GetOp(source_ops, gru_node_name) + input_list_of_gru = self.ins[gru_node_name].targets('Input') + if len(input_list_of_gru) == 1 and \ + input_list_of_gru[0].startswith('elementwise_add'): + elt_node_name = input_list_of_gru[0] + elt_op = self._GetOp(source_ops, elt_node_name) + has_weights = helper.is_persistable_param(elt_op, 'Y') + if has_weights is True: + private_data['np_bias_x'] = helper.np_param(elt_op, 'Y') + gru_flags[0] = True + input_list_of_elt = self.ins[elt_node_name].targets('X') + if len(input_list_of_elt) == 1 and input_list_of_elt[0].startswith('mul'): + mul_node_name = input_list_of_elt[0] + mul_op = self._GetOp(source_ops, mul_node_name) + if helper.var_name_by_param(mul_op, 'Y').startswith('fc'): + if helper.attr_data(mul_op, 'x_num_col_dims') == 1: + input_list_of_mul = self.ins[mul_node_name].targets('X') + input_name_of_mul = input_list_of_mul[0] + private_data['np_weight_x'] = helper.np_param(mul_op, 'Y') + gru_flags[1] = True + else: + raise NameError('ERROR: Axis of GRU_FC must be 1.') + if gru_flags == [True, True]: + self.outs[input_name_of_mul].mv(mul_node_name, gru_node_name) + self.ins[gru_node_name].mv(elt_node_name, input_name_of_mul) + for node_to_del_name in [mul_node_name, elt_node_name, gru_node_name]: + self._RmProtoNode(node_to_del_name) + if node_to_del_name is not gru_node_name: + self._ClearEdges(node_to_del_name) + self._AddProtoNode(gru_node_name, gru_op, helper, private_data) + + def _SearchBilstm(self, source_ops, helper): + comp = Fluid_comparator(helper) + lstm_ops = [] + for source_op in source_ops: + if source_op.type == 'lstm': + lstm_ops.append(source_op) + if len(lstm_ops) == 2: + lstm_a = lstm_ops[0] + lstm_b = lstm_ops[1] + same_bias = comp.compare_by_param(lstm_a, lstm_b, 'Bias') + same_weight = comp.compare_by_param(lstm_a, lstm_b, 'Weight') + if same_bias and same_weight: + return True + else: + return False + else: + return False + + def _DealWithLstm(self, source_ops, helper): + for source_op in source_ops: + if source_op.type == 'lstm': + private_data = {} + lstm_flags = [False, False] + lstm_node_name = self._NameNodeMid(source_op) + lstm_op = self._GetOp(source_ops, lstm_node_name) + input_list_of_lstm = self.ins[lstm_node_name].targets('Input') + input_list = [] + if len(input_list_of_lstm) == 1: + in_lstm_node_name = input_list_of_lstm[0] + if input_list_of_lstm[0].split('#')[0] == 'elementwise_add': + elt_op = self._GetOp(source_ops, in_lstm_node_name) + has_weights = helper.is_persistable_param(elt_op, 'Y') + if has_weights is True: + private_data['np_flat_fc_bias'] = helper.np_param(elt_op, 'Y') + lstm_flags[0] = True + input_list = self.ins[in_lstm_node_name].targets('X') + elif input_list_of_lstm[0].split('#')[0] == 'mul': + private_data['np_flat_fc_bias'] = None + input_list = input_list_of_lstm + lstm_flags[0] = True + if lstm_flags[0] is True and len(input_list) == 1: + if input_list[0].split('#')[0] == 'mul': + mul_node_name = input_list[0] + mul_op = self._GetOp(source_ops, mul_node_name) + #if helper.var_name_by_param(mul_op, 'Y').startswith('fc'): + if helper.attr_data(mul_op, 'x_num_col_dims') == 1: + input_list_of_mul = self.ins[mul_node_name].targets('X') + input_name_of_mul = input_list_of_mul[0] + [w_np, w_sh] = helper.data_with_shape_by_param(mul_op, 'Y', \ + False, None, 0, False) + private_data['np_flat_fc_weight'] = w_np + private_data['np_fc_outdim'] = w_sh[3] + lstm_flags[1] = True + else: + raise NameError('ERROR: Axis of LSTM_FC must be 1.') + if lstm_flags == [True, True]: + self.outs[input_name_of_mul].mv(mul_node_name, lstm_node_name) + self.ins[lstm_node_name].mv(in_lstm_node_name, input_name_of_mul) + if in_lstm_node_name == mul_node_name: + nodes_to_del = [mul_node_name, lstm_node_name] + else: + nodes_to_del = [mul_node_name, in_lstm_node_name, lstm_node_name] + for node_to_del_name in nodes_to_del: + self._RmProtoNode(node_to_del_name) + if node_to_del_name is not lstm_node_name: + self._ClearEdges(node_to_del_name) + self._AddProtoNode(lstm_node_name, lstm_op, helper, private_data) + + def _DealWithCast(self, source_ops, helper): + for source_op in source_ops: + if source_op.type == 'cast': + if helper.attr_data(source_op, 'out_dtype') == 5: + cast_node_name = self._NameNodeMid(source_op) + if cast_node_name in self.ins: + input_name_of_cast = self.ins[cast_node_name].target('X') + if input_name_of_cast.startswith('top_k') is False: + output_name_of_cast = self.outs[cast_node_name].target('Out') + self.outs[input_name_of_cast].mv(cast_node_name, output_name_of_cast) + self.ins[output_name_of_cast].mv(cast_node_name, input_name_of_cast) + self._RmProtoNode(cast_node_name) + self._ClearEdges(cast_node_name) + else: + print 'Cannot find the layer corresponding to cast.' + else: + raise NameError('The out type of cast must be float32.') + + def _DealWithArgmax(self, source_ops, helper): + for source_op in source_ops: + if source_op.type == 'top_k': + private_data = {} + topk_node_name = self._NameNodeMid(source_op) + out_list = self.outs[topk_node_name].targets('Out') + index_list = self.outs[topk_node_name].targets('Indices') + if len(index_list) > 0: + if len(out_list) == 1 and index_list[0].startswith('cast'): + private_data['out_max_val'] = True + idxcast_node_name = index_list[0] + output_name_of_idxcast = self.outs[idxcast_node_name].target('Out') + if output_name_of_idxcast == out_list[0] and \ + out_list[0].startswith('concat'): + concat_node_name = out_list[0] + output_name_of_concat = self.outs[concat_node_name].target('Out') + self.outs[topk_node_name].rm(idxcast_node_name) + self.outs[topk_node_name].mv(concat_node_name, output_name_of_concat) + self.ins[output_name_of_concat].mv(concat_node_name, topk_node_name) + for node_to_del_name in [concat_node_name, idxcast_node_name]: + self._RmProtoNode(node_to_del_name) + self._ClearEdges(node_to_del_name) + elif output_name_of_idxcast != out_list[0]: + if output_name_of_idxcast.endswith('_gout') and \ + out_list[0].endswith('_gout'): + gout_node_name = out_list[0] + idx_gout_node_name = output_name_of_idxcast + self.outs[topk_node_name].rm(idxcast_node_name) + for node_to_del_name in [idx_gout_node_name, idxcast_node_name]: + self._RmProtoNode(node_to_del_name) + self._ClearEdges(node_to_del_name) + self.graphIO.rm_out(idx_gout_node_name) + elif len(out_list) == 0: + private_data['out_max_val'] = False + self._DealWithCast(source_ops, helper) + else: + raise NameError('ERROR: Unknown top_k layer.') + self._RmProtoNode(topk_node_name) + self._AddProtoNode(topk_node_name, source_op, helper, private_data) + + def _RefreshReshape(self, source_ops, helper, need_assign=False): + for source_op in source_ops: + if source_op.type == 'reshape': + reshape_node_name = self._NameNodeMid(source_op) + # Make sure this node exists in this graph. + if reshape_node_name in self.ins: + shape_inputs = self.ins[reshape_node_name].targets('Shape') + tensor_inputs = self.ins[reshape_node_name].targets('X') + if len(shape_inputs) == 1 and len(tensor_inputs) == 1: + self.ins[reshape_node_name].rm(shape_inputs[0]) + if shape_inputs[0].split('#')[0] != 'assign_value' \ + or need_assign is True: + self.ins[reshape_node_name].add('Shape', shape_inputs[0]) + else: + self._RmProtoNode(shape_inputs[0]) + self._ClearEdges(shape_inputs[0]) + + def _CutReshape(self, reshape_node_name): + branch = [] + branch.append(reshape_node_name) + shape_inputs = self.ins[reshape_node_name].targets('Shape') + tensor_input = self.ins[reshape_node_name].target('X') + tensor_output = self.outs[reshape_node_name].target('Out') + if len(shape_inputs) == 1: + branch.append(shape_inputs[0]) + if len(branch) == 2 and branch[1].split('#')[0] == 'split': + split_node_name = branch[1] + self.outs[split_node_name].rm(reshape_node_name) + self.ins[reshape_node_name].rm(split_node_name) + if len(self.outs[split_node_name].targets('_Out')) == 0: + input_of_split = self.ins[split_node_name].target('_In') + branch.append(input_of_split) + self._RmProtoNode(split_node_name) + self._ClearEdges(split_node_name) + elif len(branch) == 2 and branch[1].split('#')[0] == 'shape': + shape_node_name = branch[1] + input_of_shape = self.ins[shape_node_name].targets('Input') + assert len(input_of_shape) == 1 + self.outs[input_of_shape[0]].rm(shape_node_name) + self.ins[reshape_node_name].rm(shape_node_name) + self._RmProtoNode(shape_node_name) + self._ClearEdges(shape_node_name) + elif len(branch) == 2 and branch[1].split('#')[0] == 'assign_value': + assign_node_name = branch[1] + self.ins[reshape_node_name].rm(assign_node_name) + self._RmProtoNode(assign_node_name) + self._ClearEdges(assign_node_name) + elif len(branch) == 2 and branch[1].startswith('input'): + raise NameError('ERROR: None-split input of Softmax has not supported.') + else: + pass + self.outs[tensor_input].mv(reshape_node_name, tensor_output) + self.ins[tensor_output].mv(reshape_node_name, tensor_input) + self._RmProtoNode(reshape_node_name) + self._ClearEdges(reshape_node_name) + if len(branch) == 3 and branch[2].startswith('input'): + input_node_name = branch[2] + self._RmProtoNode(input_node_name) + self._ClearEdges(input_node_name) + + def _RefreshSplit(self, split_node_name, helper): + outputs_of_split = self.outs[split_node_name].targets('_Out') + inputs_of_split = self.ins[split_node_name].targets('_In') + assert len(inputs_of_split) == 1 + split_num = len(outputs_of_split) + if split_num == 1: + self.ins[outputs_of_split[0]].mv(split_node_name, inputs_of_split[0]) + self.outs[inputs_of_split[0]].mv(split_node_name, outputs_of_split[0]) + self._RmProtoNode(split_node_name) + self._ClearEdges(split_node_name) + else: + private_data = {'split_num': split_num} + self._RmProtoNode(split_node_name) + self._AddProtoNode(split_node_name, None, helper, private_data, 'split') + + def _DealWithSoftmax(self, source_ops, helper): + for source_op in source_ops: + if source_op.type == 'softmax': + softmax_node_name = self._NameNodeMid(source_op) + outs_of_softmax = self.outs[softmax_node_name].targets('Out') + ins_of_softmax = self.ins[softmax_node_name].targets('X') + if outs_of_softmax[0].split('#')[0] == 'reshape': + if ins_of_softmax[0].split('#')[0] == 'reshape' or \ + ins_of_softmax[0].split('#')[0] == 'flatten': + private_data = {} + private_data['axis'] = 3 + self._CutReshape(outs_of_softmax[0]) + self._CutReshape(ins_of_softmax[0]) + self._RmProtoNode(softmax_node_name) + self._AddProtoNode(softmax_node_name, source_op, helper, private_data) + ins_of_softmax = self.ins[softmax_node_name].targets('X') + print 'ins_of_softmax', ins_of_softmax + assert len(ins_of_softmax) == 1 + self._RefreshSplit(ins_of_softmax[0], helper) + + def _DealWithMatmal(self, source_ops, helper): + for source_op in source_ops: + if source_op.type == 'matmul': + matmul_node_name = self._NameNodeMid(source_op) + x_input_name = self.ins[matmul_node_name].target('X') + y_input_name = self.ins[matmul_node_name].target('Y') + flag = False + coeff = 1.0 + for node_name in [x_input_name, y_input_name]: + if node_name.startswith('scale') or node_name.startswith('dropout'): + op = self._GetOp(source_ops, node_name) + if node_name.startswith('scale'): + scale = helper.attr_data(op, 'scale') + elif node_name.startswith('dropout'): + scale = 1 - helper.attr_data(op, 'dropout_prob') + input_node = self.ins[node_name].target('X') + self.outs[input_node].mv(node_name, matmul_node_name) + self.ins[matmul_node_name].mv(node_name, input_node) + self._RmProtoNode(node_name) + self._ClearEdges(node_name) + coeff = coeff * scale + flag = True + if flag is True: + private_data = {} + private_data['coeff'] = coeff + self._RmProtoNode(matmul_node_name) + self._AddProtoNode(matmul_node_name, source_op, helper, private_data) + + def _DealWithDiscBatchNorm(self, source_ops, helper): + for source_op in source_ops: + if source_op.type == 'batch_norm': + discrete_flag = True + bn_node_name = self._NameNodeMid(source_op) + input_name = self.ins[bn_node_name].target('X') + if input_name.startswith('elementwise_add'): + input_of_elt = self.ins[input_name].target('X') + if input_of_elt.startswith('conv2d'): + discrete_flag = False + elif input_name.startswith('conv2d'): + discrete_flag = False + if discrete_flag is True: + self._RmProtoNode(bn_node_name) + self._AddProtoNode(bn_node_name, source_op, helper, {}, 'disc_bn') + + def _DealWithSSD(self, source_ops, helper): + for source_op in source_ops: + if source_op.type == 'reshape': + rh_node_name = self._NameNodeMid(source_op) + if rh_node_name in self.ins: + private_data = dict() + input_name = self.ins[rh_node_name].target('X') + shape = helper.attr_data(source_op, 'shape') + if input_name.startswith('concat'): + private_data['new_shape'] = [0, shape[0], shape[1], 0] + else: + private_data['new_shape'] = [0, -1, 1, 1] + self._RmProtoNode(rh_node_name) + self._AddProtoNode(rh_node_name, source_op, helper, private_data, 'reshape') + for source_op in source_ops: + if source_op.type == 'softmax': + private_data = dict() + sm_node_name = self._NameNodeMid(source_op) + private_data['axis'] = 2 + self._RmProtoNode(sm_node_name) + self._AddProtoNode(sm_node_name, source_op, helper, private_data, 'softmax') + + def _NewCommonLayer(self, + source_ops, + in_target, + in_param, + out_target, + out_param, + layer_type, + private_data, + helper, + insert_mode=True): + main_layer = layer_type + '_after_' + in_target + if insert_mode is True: + if in_target in self.ins[out_target].all_targets() and \ + out_target in self.outs[in_target].all_targets(): + self.ins[out_target].mv(in_target, main_layer) + self.outs[in_target].mv(out_target, main_layer) + else: + raise NameError('ERROR: Usage of InsertCommonLayer has not supported.') + else: + self.ins[out_target].add(in_param + '_insert', main_layer) + self.outs[in_target].add(out_param + '_insert', main_layer) + self.ins[main_layer] = Fluid_edger(in_param, in_target) + self.outs[main_layer] = Fluid_edger(out_param, out_target) + self._AddProtoNode(main_layer, None, helper, private_data, layer_type) + + def _ParseNetwork(self, source_ops, helper): + self._ParseBase(source_ops, helper) + if self.NetType == "FLUIDBASE": + pass + else: + reshape_dict = {} + if self.NetType == "OCR": + reshape_dict['input_0'] = [1, 1, 48, 1500] + self._ReplaceInputs(source_ops, helper, reshape_dict) + self._InsertSplit(source_ops, helper) + self._DealWithGru(source_ops, helper) + self._DealWithLstm(source_ops, helper) + self._DealWithBias(source_ops, helper) + self._DealWithBatchnorm(source_ops, helper) + self._DealWithMultiFC(source_ops, helper) + self._DealWithArgmax(source_ops, helper) + self._DealWithAxpy(source_ops, helper) + if self.NetType == "SSD": + self._DealWithPriorBox(source_ops, helper) + self._DealWithDetectionOutput(source_ops, helper) + self._DealWithSSD(source_ops, helper) + self._DealWithSoftmax(source_ops, helper) + self._RefreshReshape(source_ops, helper) + self._Graph() + + def _Parsing(self): + with fluid.scope_guard(self.scope): + if os.path.exists(self.ModelPath + 'model') and \ + os.path.exists(self.ModelPath + 'params'): + [self.net_program, feed_target_names, fetch_targets] = \ + fluid.io.load_inference_model(self.ModelPath, self.exe, 'model', 'params') + else: + [self.net_program, feed_target_names, fetch_targets] = \ + fluid.io.load_inference_model(self.ModelPath, self.exe) + + global_block = self.net_program.global_block() + source_ops = list(global_block.ops) + helper = Fluid_helper(self.scope, global_block) + + self._ParseNetwork(source_ops, helper) + return self.graphIO diff --git a/tools/external_converter_v2/parser/fluid/tools/feed_ones.py b/tools/external_converter_v2/parser/fluid/tools/feed_ones.py new file mode 100644 index 000000000..06238f598 --- /dev/null +++ b/tools/external_converter_v2/parser/fluid/tools/feed_ones.py @@ -0,0 +1,138 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +''' +A separate Fluid test file for feeding specific data. +''' + +import sys +import numpy as np +import os +import paddle.fluid as fluid +from paddle.fluid import debugger +from paddle.fluid import core +import subprocess + +GLB_model_path = '' +GLB_arg_name = '' +GLB_batch_size = 1 + +def load_inference_model(model_path, exe): + ''' + ''' + model_abs_path = os.path.join(model_path, 'model') + param_abs_path = os.path.join(model_path, 'params') + if os.path.exists(model_abs_path) and os.path.exists(param_abs_path): + return fluid.io.load_inference_model(model_path, exe, 'model', 'params') + else: + return fluid.io.load_inference_model(model_path, exe) + +def feed_ones(block, feed_target_names, batch_size=1): + """ + """ + feed_dict = dict() + def set_batch_size(shape, batch_size): + if shape[0] == -1: + shape[0] = batch_size + return shape + def fill_ones(var_name, batch_size): + var = block.var(var_name) + np_shape = set_batch_size(list(var.shape), 1) + var_np = { + core.VarDesc.VarType.BOOL: np.bool_, + core.VarDesc.VarType.INT32: np.int32, + core.VarDesc.VarType.INT64: np.int64, + core.VarDesc.VarType.FP16: np.float16, + core.VarDesc.VarType.FP32: np.float32, + core.VarDesc.VarType.FP64: np.float64, + } + np_dtype = var_np[var.dtype] + return np.ones(np_shape, dtype=np_dtype) + for feed_target_name in feed_target_names: + feed_dict[feed_target_name] = fill_ones(feed_target_name, batch_size) + return feed_dict + +def draw(block, filename='debug'): + """ + """ + dot_path = './' + filename + '.dot' + pdf_path = './' + filename + '.pdf' + debugger.draw_block_graphviz(block, path=dot_path) + cmd = ["dot", "-Tpdf", dot_path, "-o", pdf_path] + subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + +def fetch_tmp_vars(block, fetch_targets, var_names_list=None): + """ + """ + def var_names_of_fetch(fetch_targets): + var_names_list = [] + for var in fetch_targets: + var_names_list.append(var.name) + return var_names_list + + fetch_var = block.var('fetch') + old_fetch_names = var_names_of_fetch(fetch_targets) + new_fetch_vars = [] + for var_name in old_fetch_names: + var = block.var(var_name) + new_fetch_vars.append(var) + i = len(new_fetch_vars) + if var_names_list is None: + var_names_list = block.vars.keys() + for var_name in var_names_list: + if '.tmp_' in var_name and var_name not in old_fetch_names: + var = block.var(var_name) + new_fetch_vars.append(var) + block.append_op( + type='fetch', + inputs={'X': [var_name]}, + outputs={'Out': [fetch_var]}, + attrs={'col': i}) + i = i + 1 + return new_fetch_vars + +def print_results(results, fetch_targets, need_save=True): + """ + """ + for result in results: + idx = results.index(result) + print fetch_targets[idx] + print np.array(result) + if need_save is True: + fluid_fetch_list = list(np.array(result).flatten()) + fetch_txt_fp = open('result_' + fetch_targets[idx].name + '.txt', 'w') + for num in fluid_fetch_list: + fetch_txt_fp.write(str(num) + '\n') + fetch_txt_fp.close() + +def fluid_inference_test(model_path): + """ + """ + place = fluid.CPUPlace() + exe = fluid.Executor(place) + scope = fluid.core.Scope() + with fluid.scope_guard(scope): + [net_program, + feed_target_names, + fetch_targets] = load_inference_model(model_path, exe) + global_block = net_program.global_block() + draw(global_block) + feed_list = feed_ones(global_block, feed_target_names) + fetch_targets = fetch_tmp_vars(global_block, fetch_targets, [GLB_arg_name]) + results = exe.run(program=net_program, + feed=feed_list, + fetch_list=fetch_targets, + return_numpy=False) + print_results(results, fetch_targets) + +if __name__ == "__main__": + if len(sys.argv) == 1: + raise NameError('Usage: python ./all_ones.py path/to/model arg_name batch_size') + if len(sys.argv) > 1: + GLB_model_path = sys.argv[1] + if len(sys.argv) > 2: + GLB_arg_name = sys.argv[2] + if len(sys.argv) > 3: + GLB_batch_size = sys.argv[3] + fluid_inference_test(GLB_model_path) + diff --git a/tools/external_converter_v2/parser/fluid/tools/feed_txt.py b/tools/external_converter_v2/parser/fluid/tools/feed_txt.py new file mode 100644 index 000000000..03ef81104 --- /dev/null +++ b/tools/external_converter_v2/parser/fluid/tools/feed_txt.py @@ -0,0 +1,182 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A separate Fluid test file for feeding specific data. +""" + +import sys +import numpy as np +import os +import paddle.fluid as fluid +from paddle.fluid import debugger +from paddle.fluid import core +from prettytable import PrettyTable +from operator import mul +import subprocess + +GLB_model_path = '/path/to/fluid/inference/model/' +GLB_feed_example = { + 'var_name': 'data', + 'tensor_shape': [n, c, h, w], + 'txt_path': '/path/to/input/txt/', +} +GLB_feed_list = [GLB_feed_example] + +# Do not modify +GLB_arg_name = '' +GLB_batch_size = 1 + +def load_inference_model(model_path, exe): + """ + """ + model_abs_path = os.path.join(model_path, 'model') + param_abs_path = os.path.join(model_path, 'params') + if os.path.exists(model_abs_path) and os.path.exists(param_abs_path): + return fluid.io.load_inference_model(model_path, exe, 'model', 'params') + else: + return fluid.io.load_inference_model(model_path, exe) + +def print_feed_fetch(block, feed_target_names, fetch_targets): + """ + """ + tag_list = ["Index", "Name", "Shape", "Data Type", "Tensor Type"] + def add_var_table(table, var, idx): + table.add_row([idx, var.name, var.shape, str(var.dtype), str(var.type)]) + def feed_table(block, var_name_list): + table = PrettyTable(tag_list) + for var_name in var_name_list: + idx = var_name_list.index(var_name) + var = block.var(var_name) + add_var_table(table, var, idx) + return table + def fetch_table(var_list): + idx = 0 + table = PrettyTable(tag_list) + for var in var_list: + add_var_table(table, var, idx) + idx = idx + 1 + return table + print "\n", "=========== FEED TABLE ===========" + print feed_table(block, feed_target_names) + print "\n", "=========== FETCH TABLE ===========" + print fetch_table(fetch_targets), "\n" + +def add_feed_list(feed_list, fluid_feed_dict=None): + """ + """ + if fluid_feed_dict is None: + fluid_feed_dict = dict() + def numpy_from_txt(txt_path, + tensor_shape=list(), + dtype=np.float32, + delimiter=None, + comments='#'): + data = np.loadtxt(txt_path, dtype, comments, delimiter) + data_size = np.size(data) + tensor_size = reduce(mul, tensor_shape) + assert (data_size == tensor_size), \ + "data size of txt (%d) must be equal to shape size (%d)." % (data_size, tensor_size) + return np.reshape(data, tensor_shape) + + def add_feed_var(input_dict, fluid_feed_dict): + var_name = input_dict['var_name'] + tensor_shape = input_dict['tensor_shape'] + txt_path = input_dict['txt_path'] + if 'data_type' in input_dict.keys(): + dtype = input_dict['data_type'] + else: + dtype = np.float32 + if 'delimiter' in input_dict.keys(): + delim = input_dict['delimiter'] + else: + delim = None + fluid_feed_dict[var_name] = numpy_from_txt(txt_path, tensor_shape, dtype, delim) + return fluid_feed_dict + for input_dict in feed_list: + add_feed_var(input_dict, fluid_feed_dict) + return fluid_feed_dict + +def draw(block, filename='debug'): + """ + """ + dot_path = './' + filename + '.dot' + pdf_path = './' + filename + '.pdf' + debugger.draw_block_graphviz(block, path=dot_path) + cmd = ["dot", "-Tpdf", dot_path, "-o", pdf_path] + subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + +def fetch_tmp_vars(block, fetch_targets, var_names_list=None): + """ + """ + def var_names_of_fetch(fetch_targets): + var_names_list = [] + for var in fetch_targets: + var_names_list.append(var.name) + return var_names_list + fetch_var = block.var('fetch') + old_fetch_names = var_names_of_fetch(fetch_targets) + new_fetch_vars = [] + for var_name in old_fetch_names: + var = block.var(var_name) + new_fetch_vars.append(var) + i = len(new_fetch_vars) + if var_names_list is None: + var_names_list = block.vars.keys() + for var_name in var_names_list: + if '.tmp_' in var_name and var_name not in old_fetch_names: + var = block.var(var_name) + new_fetch_vars.append(var) + block.append_op( + type='fetch', + inputs={'X': [var_name]}, + outputs={'Out': [fetch_var]}, + attrs={'col': i}) + i = i + 1 + return new_fetch_vars + +def print_results(results, fetch_targets, need_save=True): + """ + """ + for result in results: + idx = results.index(result) + print fetch_targets[idx] + print np.array(result) + if need_save is True: + fluid_fetch_list = list(np.array(result).flatten()) + fetch_txt_fp = open('result_' + fetch_targets[idx].name + '.txt', 'w') + for num in fluid_fetch_list: + fetch_txt_fp.write(str(num) + '\n') + fetch_txt_fp.close() + +def fluid_inference_test(model_path, feed_list): + """ + """ + place = fluid.CPUPlace() + exe = fluid.Executor(place) + scope = fluid.core.Scope() + with fluid.scope_guard(scope): + [net_program, + feed_target_names, + fetch_targets] = load_inference_model(model_path, exe) + global_block = net_program.global_block() + print_feed_fetch(global_block, feed_target_names, fetch_targets) + draw(global_block) + feed_list = add_feed_list(feed_list) + fetch_targets = fetch_tmp_vars(global_block, fetch_targets, [GLB_arg_name]) + results = exe.run(program=net_program, + feed=feed_list, + fetch_list=fetch_targets, + return_numpy=False) + print_results(results, fetch_targets) + +if __name__ == "__main__": + if len(sys.argv) == 1 and GLB_model_path == '': + raise NameError('Usage: python ./all_ones.py path/to/model arg_name batch_size') + if len(sys.argv) > 1 and GLB_model_path == '': + GLB_model_path = sys.argv[1] + if len(sys.argv) > 2: + GLB_arg_name = sys.argv[2] + if len(sys.argv) > 3: + GLB_batch_size = sys.argv[3] + fluid_inference_test(GLB_model_path, GLB_feed_list) diff --git a/tools/external_converter_v2/parser/graph.py b/tools/external_converter_v2/parser/graph.py index 030817195..9d94a6900 100644 --- a/tools/external_converter_v2/parser/graph.py +++ b/tools/external_converter_v2/parser/graph.py @@ -20,19 +20,19 @@ def __init__(self, config): """ self.save_file_path = config.SavePath + config.ResultName + ".anakin.bin" if config.framework == 'CAFFE': - from kill_caffe import CaffeParser + from caffe import CaffeParser self.parser = CaffeParser(config.framework_config_dict) elif config.framework == 'PADDLE': pass elif config.framework == 'LEGO': pass elif config.framework == 'TENSORFLOW': - from kill_tf import TFParser + from tensorflow import TFParser self.parser=TFParser(config.framework_config_dict) elif config.framework == 'MXNET': pass elif config.framework == 'FLUID': - from kill_fluid import FluidParser + from fluid import FluidParser self.parser = FluidParser(config.framework_config_dict) else: raise NameError('ERROR: GrapProtoIO not support %s model.' % (config.framework)) @@ -105,11 +105,17 @@ def serialization(self): self.graph_io.serialization(self.save_file_path) def info_table(self): + """ + print input table. + """ tables = list() in_table = PrettyTable(["Input Name", "Shape", "Alias", "Data Type"]) out_table = PrettyTable(["Output Name"]) def ins_attr(): + """ + get inputs attr. + """ ins = list() for graph_in in self.ins(): attr = dict() diff --git a/tools/external_converter_v2/parser/graph_io.py b/tools/external_converter_v2/parser/graph_io.py index a471afa39..ba9acc70c 100644 --- a/tools/external_converter_v2/parser/graph_io.py +++ b/tools/external_converter_v2/parser/graph_io.py @@ -336,26 +336,25 @@ def rm_out(self, node_name): self.graph_proto.outs[:] = graph_outs def format_edge_from_nodes(self): - in_set=set() + in_set = set() out_set = set() for node in self.graph_proto.nodes: - name=node.name + name = node.name for node_name in node.ins: - self.add_in_edge(node_name,name) - in_set.add((node_name,name)) + self.add_in_edge(node_name, name) + in_set.add((node_name, name)) for node_name in node.outs: - self.add_out_edge(name,node_name) - out_set.add((name,node_name)) - ab_set=in_set-out_set - ba_set=out_set-in_set + self.add_out_edge(name, node_name) + out_set.add((name, node_name)) + ab_set = in_set - out_set + ba_set = out_set - in_set print(ab_set) print('------') print(ba_set) - assert len(ab_set)==0 and len(ba_set)==0,'in edge must equal with out edge' + assert len(ab_set) == 0 and len(ba_set) == 0, 'in edge must equal with out edge' def __call__(self): - return self.graph_proto diff --git a/tools/external_converter_v2/parser/kill_fluid/fluid_debugger.py b/tools/external_converter_v2/parser/kill_fluid/fluid_debugger.py deleted file mode 100644 index d07e97799..000000000 --- a/tools/external_converter_v2/parser/kill_fluid/fluid_debugger.py +++ /dev/null @@ -1,60 +0,0 @@ -from ..proto import * -from ..graph_io import * -import copy -import paddle.fluid as fluid -import numpy as np -from paddle.fluid.core import VarDesc, AttrType - - -class Fluid_debugger: - - def var_names_of_fetch(self, fetch_targets): - var_names_list = [] - for var in fetch_targets: - var_names_list.append(var.name) - return var_names_list - - def fetch_tmp_vars(self, block, fetch_targets, var_names_list = None): - fetch_var = block.var('fetch') - old_fetch_names = self.var_names_of_fetch(fetch_targets) - new_fetch_vars = [] - for var_name in old_fetch_names: - var = block.var(var_name) - new_fetch_vars.append(var) - i = len(new_fetch_vars) - if var_names_list is None: - var_names_list = block.vars.keys() - for var_name in var_names_list: - if '.tmp_' in var_name and var_name not in old_fetch_names: - var = block.var(var_name) - new_fetch_vars.append(var) - block.append_op( - type='fetch', - inputs={'X': [var_name]}, - outputs={'Out': [fetch_var]}, - attrs={'col': i}) - i = i + 1 - return new_fetch_vars - - def print_tmp_vars(self, block, var_names_list = []): - for var_name in var_names_list: - var_to_print = block.var(var_name) - out_to_print = block.create_var( - name=var_name+'.print', - dtype="float32", - persistable=True, - stop_gradient=False) - block.append_op( - type='print', - inputs={'In': var_to_print}, - attrs={ - 'first_n': -1, - 'summarize': -1, - 'message': "", - 'print_tensor_name': True, - 'print_tensor_type': True, - 'print_tensor_shape': True, - 'print_tensor_lod': True, - 'print_phase': 'FORWARD' - }, - outputs={'Out': out_to_print}) diff --git a/tools/external_converter_v2/parser/kill_fluid/fluid_helper.py b/tools/external_converter_v2/parser/kill_fluid/fluid_helper.py deleted file mode 100644 index f702a0679..000000000 --- a/tools/external_converter_v2/parser/kill_fluid/fluid_helper.py +++ /dev/null @@ -1,516 +0,0 @@ -from ..proto import * -from ..graph_io import * -import paddle.fluid as fluid -import numpy as np -from paddle.fluid.core import VarDesc, AttrType - - -def union(list_a, list_b): - return list(set(list_a).union(set(list_b))) - -def difference(list_a, list_b): - return list(set(list_a).difference(set(list_b))) - - -class Edge_for_fluid: - - def __init__(self, param, target, var): - self.param = param - self.target = target - self.var = var - - -class Fluid_edger: - - def __init__(self, param = None, target = None, var = None): - self.edges = [] - if param is not None and target is not None: - edge = Edge_for_fluid(param, target, var) - self.edges.append(edge) - - def __call__(self): - return self.all_targets() - - def add(self, param, target, var = None): - edge = Edge_for_fluid(param, target, var) - self.edges.append(edge) - - def rm_edges_by_param(self, param): - for edge in self.edges: - if edge.param == param: - edge_idx = self.edges.index(edge) - del self.edges[edge_idx] - - def rm(self, target): - res = -1 - for edge in self.edges: - if target == edge.target: - edge_idx = self.edges.index(edge) - del self.edges[edge_idx] - res = res + 1 - if res != 0: - pass - - def mv(self, old_target, new_target): - res = -1 - for edge in self.edges: - if old_target == edge.target: - edge.target = new_target - res = res + 1 - if res != 0: - pass - - def all_params(self): - params = [] - for edge in self.edges: - if edge.param not in params: - params.append(edge.param) - return params - - def all_targets(self): - targets = [] - for edge in self.edges: - targets.append(edge.target) - return targets - - def targets(self, param): - targets = [] - for edge in self.edges: - if edge.param == param: - targets.append(edge.target) - return targets - - def target(self, param, idx = 0): - return self.targets(param)[idx] - - def clear(self): - targets_list = self.all_targets() - for target in targets_list: - self.rm(target) - - def targets_with_params(self): - list_of_targets_and_params = [] - for edge in self.edges: - target_and_param = [edge.target, edge.param] - list_of_targets_and_params.append(target_and_param) - return list_of_targets_and_params - - def vars_by_target(self, target): - vars = [] - for edge in self.edges: - if edge.target == target and edge.var is not None: - vars.append(edge.var) - return vars - - def __getitem__(self, idx): - if idx < len(self.edges): - return self.edges[idx] - return None - - -class Fluid_helper: - - def __init__(self, scope, block): - self.scope = scope - self.block = block - - def args_by_input_param(self, op, param_name): - if param_name in op.input_names: - return op.input(param_name) - else: - raise NameError('ERROR: param_name %s is not exists.' % ( param_name ) ) - - def args_by_output_param(self, op, param_name): - if param_name in op.output_names: - return op.output(param_name) - else: - raise NameError('ERROR: param_name %s is not exists.' % ( param_name ) ) - - def var_by_input_param(self, op, param_name, var_idx = 0): - var_name = self.args_by_input_param(op, param_name)[var_idx] - var = self.block.var(var_name) - return var - - def var_by_output_param(self, op, param_name, var_idx = 0): - var_name = self.args_by_output_param(op, param_name)[var_idx] - var = self.block.var(var_name) - return var - - def var_name_by_param(self, op, param_name, var_idx = 0): - if param_name not in op.input_names + op.output_names: - raise NameError('ERROR: param_name %s is not exists.' % ( param_name ) ) - elif param_name in op.input_names: - if len(op.input(param_name)) > 0: - var_name_unicode = op.input(param_name)[var_idx] - else: - raise NameError('ERROR: param %s has not var.' % ( param_name ) ) - elif param_name in op.output_names: - if len(op.output(param_name)) > 0: - var_name_unicode = op.output(param_name)[var_idx] - else: - raise NameError('ERROR: param %s has not var.' % ( param_name ) ) - var = self.block.var(var_name_unicode) - var_name = var.name - return var_name - - def var_by_param(self, op, param_name, var_idx = 0): - var_name = self.var_name_by_param(op, param_name, var_idx) - var = self.block.var(var_name) - return var - - def shape_by_var_name(self, var_name, layout = 'NCHW'): - var = self.block.var(var_name) - long_tuple = var.shape - long_list = list(long_tuple) - if layout == 'NCHW': - int_list_4d = map(int, [1]*(4-len(long_list)) + long_list) - return int_list_4d - elif layout == 'UNMODIFIED': - return long_list - else: - raise NameError('ERROR: layout %s is not implemented yet.' % ( layout ) ) - - def np_data_by_var_name(self, var_name): - numpy_array = fluid.executor.fetch_var(var_name, self.scope, True) - return numpy_array - - def dtype_by_var_name(self, var_name): - var = self.block.var(var_name) - fluid_var_type = var.dtype - dtype = ANAKIN_TENSOR_DTYPE[fluid_var_type] - return dtype - - def is_persistable_param(self, op, param_name, var_idx = 0): - var = self.var_by_param(op, param_name, var_idx) - is_persistable_var = var.persistable - return is_persistable_var - - def var_shape_by_param(self, transpose, op, param_name, var_idx = 0, layout = 'NCHW'): - if transpose is True: - raise NameError('ERROR: var_shape transpose is not implemented yet.') - else: - var_name = self.var_name_by_param(op, param_name, var_idx) - shape = self.shape_by_var_name(var_name, layout) - return shape - - def data_with_shape_by_param(self, - op, - param_name, - transpose = False, - axes = None, - var_idx = 0, - is_flat_list = True, - layout = 'NCHW'): - - np.set_printoptions(threshold=np.inf, suppress=True) - - var_name = self.var_name_by_param(op, param_name, var_idx) - np_array = self.np_data_by_var_name(var_name) - if transpose is True: - np_array = np.transpose(np_array, axes) - np_shape = np.shape(np_array) - if layout == 'NCHW': - np_shape = map(int, [1]*(4-len(np_shape)) + list(np_shape)) - if is_flat_list is True: - flat_list = list(np_array.flatten()) - return [flat_list, np_shape] - else: - return [np_array, np_shape] - - def np_param(self, - op, - param_name, - transpose = False, - axes = None, - var_idx = 0): - - [data, np_shape] = self.data_with_shape_by_param(op, param_name, transpose, \ - axes, var_idx, False) - return data - - def dtype_by_param(self, op, param_name, var_idx = 0): - var_name = self.var_name_by_param(op, param_name, var_idx) - dtype = self.dtype_by_var_name(var_name) - return dtype - - def is_list_type(self, op, attr_name): - if op.has_attr(attr_name): - fluid_attr_type = op.attr_type(attr_name) - if fluid_attr_type in ANAKIN_ATTR_IS_LIST.keys(): - return ANAKIN_ATTR_IS_LIST[fluid_attr_type] - else: - return False # AttrType.LONG - else: - raise NameError('ERROR: attr_name %s is not exists.' % ( attr_name ) ) - - def dtype_of_attr(self, op, attr_name): - if op.has_attr(attr_name): - fluid_attr_type = op.attr_type(attr_name) - if fluid_attr_type in ANAKIN_ATTR_DTYPE.keys(): - return ANAKIN_ATTR_DTYPE[fluid_attr_type] - else: - return INT32 # AttrType.LONG - else: - raise NameError('ERROR: attr_name %s is not exists.' % ( attr_name ) ) - - def attr_data_required(self, op, attr_name): - data = op.attr(attr_name) - is_list = self.is_list_type(op, attr_name) - dtype = self.dtype_of_attr(op, attr_name) - if dtype not in [INT32, FLOAT, STR]: - return data - elif dtype == INT32: - return map(int, data) if is_list else int(data) - elif dtype == FLOAT: - return map(float, data) if is_list else float(data) - elif dtype == STR: - return bytes(data) - - def attr_data(self, op, attr_name, default_value = 0, type = None): - if op.has_attr(attr_name): - return self.attr_data_required(op, attr_name) - else: - #raise NameError('ERROR: attr_name %s is not exists.' % ( attr_name ) ) - return default_value - - def param_tensor_sh(self, - op, - param_name, - transpose = False, - axes = None, - reshape = None, - var_idx = 0, - layout = 'NCHW'): - - tensor = TensorProtoIO() - [flat_data, shape] = self.data_with_shape_by_param(op, param_name, transpose, \ - axes, var_idx, True, layout) - dtype = self.dtype_by_param(op, param_name, var_idx) - tensor.set_data_type(dtype) - if dtype in ANAKIN_TENSOR_DTYPESTR.keys(): - tensor.set_data(flat_data, ANAKIN_TENSOR_DTYPESTR[dtype]) - #pass #debug - else: - raise NameError('ERROR: Unknown data type (%s)' % ( dtype ) ) - if reshape is not None: - tensor.set_shape(reshape) - else: - tensor.set_shape(shape) - return [tensor, shape] - - def param_tensor(self, - op, - param_name, - transpose = False, - axes = None, - reshape = None, - var_idx = 0, - layout = 'NCHW'): - - [tensor, shape] = self.param_tensor_sh(op, param_name, transpose, axes, \ - reshape, var_idx, layout) - return tensor - - def create_tensor(self, data_list, data_shape, dtype): - tensor = TensorProtoIO() - tensor.set_data_type(dtype) - tensor.set_data(data_list, ANAKIN_TENSOR_DTYPESTR[dtype]) - tensor.set_shape(data_shape) - return tensor - - def gru_tensor_convert(self, origin_h2h, origin_i2h, origin_b, offset=[2, 1, 0]): - hidden_size = int(origin_b.size // 3) - word_size = int(origin_i2h.size // hidden_size // 3) - tar_h2h=np.array(origin_h2h.flatten().tolist()[2*hidden_size*hidden_size:]\ - +np.array(origin_h2h.flatten().tolist()[:2*hidden_size*hidden_size])\ - .reshape(hidden_size,2,hidden_size)[:,[1,0],:].flatten().tolist())\ - .reshape(1,1,hidden_size,3*hidden_size) - tar_i2h=origin_i2h.reshape(word_size,3,hidden_size)[:,offset,:]\ - .reshape(1,1,word_size,3*hidden_size) - tar_b=origin_b.reshape(3, hidden_size)[offset, :].reshape(1,1,1,3 * hidden_size) - tar_i2h_h2h=np.concatenate([tar_i2h.flatten(),tar_h2h.flatten()])\ - .reshape(1,1,1,3*hidden_size*hidden_size+3*word_size*hidden_size) - return tar_i2h_h2h, tar_b - - def lstm_fc_tensor_merge_convert(self, origin_hidden_size, origin_lstm_w, origin_lstm_b, origin_fc_w, origin_fc_b): - - layer_size = int (origin_hidden_size // 4) - input_size = int (origin_fc_w.size // origin_hidden_size) - lstm_bias_num = int (origin_lstm_b.size // layer_size) - tar_w = np.vstack((np.hstack((origin_fc_w[:, 1 * layer_size : 2 * layer_size], - origin_fc_w[:, 2 * layer_size : 3 * layer_size], - origin_fc_w[:, : 1 * layer_size], - origin_fc_w[:, 3 * layer_size :])), - np.hstack((origin_lstm_w[:, 1 * layer_size : 2 * layer_size], - origin_lstm_w[:, 2 * layer_size : 3 * layer_size], - origin_lstm_w[:, : 1 * layer_size], - origin_lstm_w[:, 3 * layer_size : ])))) - - if origin_fc_b is not None: - split_fc_bc = origin_fc_b.flatten()[: 1 * layer_size] - split_fc_bi = origin_fc_b.flatten()[1 * layer_size : 2 * layer_size] - split_fc_bf = origin_fc_b.flatten()[2 * layer_size : 3 * layer_size] - split_fc_bo = origin_fc_b.flatten()[3 * layer_size : 4 * layer_size] - else: - split_fc_bc = np.zeros(layer_size) - split_fc_bi = np.zeros(layer_size) - split_fc_bf = np.zeros(layer_size) - split_fc_bo = np.zeros(layer_size) - - split_lstm_bc = origin_lstm_b.flatten()[: 1 * layer_size] - split_lstm_bi = origin_lstm_b.flatten()[1 * layer_size: 2 * layer_size] - split_lstm_bf = origin_lstm_b.flatten()[2 * layer_size: 3 * layer_size] - split_lstm_bo = origin_lstm_b.flatten()[3 * layer_size: 4 * layer_size] - split_lstm_bc = np.add(split_lstm_bc, split_fc_bc) - split_lstm_bi = np.add(split_lstm_bi, split_fc_bi) - split_lstm_bf = np.add(split_lstm_bf, split_fc_bf) - split_lstm_bo = np.add(split_lstm_bo, split_fc_bo) - - if lstm_bias_num == 4: - tar_b = np.array(split_lstm_bi.flatten().tolist() - + split_lstm_bf.flatten().tolist() - + split_lstm_bc.flatten().tolist() - + split_lstm_bo.flatten().tolist()) - else: - split_lstm_wic = origin_lstm_b.flatten()[4 * layer_size : 5 * layer_size] - split_lstm_wfc = origin_lstm_b.flatten()[5 * layer_size : 6 * layer_size] - split_lstm_woc = origin_lstm_b.flatten()[6 * layer_size :] - tar_b = np.array(split_lstm_bi.flatten().tolist() - + split_lstm_bf.flatten().tolist() - + split_lstm_bc.flatten().tolist() - + split_lstm_bo.flatten().tolist() - + split_lstm_wic.flatten().tolist() - + split_lstm_wfc.flatten().tolist() - + split_lstm_woc.flatten().tolist()) - return tar_w.reshape(input_size+ layer_size, 4 * layer_size, 1, 1),\ - tar_b.reshape(1, origin_lstm_b.size, 1, 1) - - -class Fluid_comparator: - - def __init__(self, helper): - self.helper = helper - self.only_list = ['feed', 'fetch'] - - def compare_by_param(self, op_a, op_b, param): - is_weight_a = self.helper.is_persistable_param(op_a, param) - is_weight_b = self.helper.is_persistable_param(op_b, param) - if is_weight_a and is_weight_b: - np_a = self.helper.np_param(op_a, param) - np_b = self.helper.np_param(op_b, param) - if (np_a == np_b).all() == True: - return True - else: - return False - elif is_weight_a is is_weight_b: - return True - else: - return False - - def have_same_weights(self, op_a, op_b): - is_same = True - if op_a.input_names == op_b.input_names: - params = op_a.input_names - for param in params: - if self.compare_by_param(op_a, op_b, param) is False: - is_same = False - return is_same - else: - return False - - def compare_by_attr(self, op_a, op_b, attr_name): - data_a = self.helper.attr_data(op_a, attr_name) - data_b = self.helper.attr_data(op_b, attr_name) - return data_a == data_b - - def have_same_attrs(self, op_a, op_b): - is_same = True - if op_a.attr_names == op_b.attr_names: - attrs = op_a.attr_names - for attr in attrs: - if self.compare_by_attr(op_a, op_b, attr) is False: - is_same = False - return is_same - else: - return False - - def brothers(self, op_list): - is_same = True - if len(op_list) > 1: - idx = 0 - for op_b in op_list[1:]: - if op_b.type not in self.only_list: - idx = op_list.index(op_b) - op_a = op_list[idx - 1] - if op_a.type not in self.only_list: - same_weights = self.have_same_weights(op_a, op_b) - same_attrs = self.have_same_attrs(op_a, op_b) - if (same_weights and same_attrs) is False: - is_same = False - else: - raise NameError('ERROR: %s is in only_list.' % ( op_a.type )) - else: - raise NameError('ERROR: %s is in only_list.' % ( op_b.type )) - return is_same - else: - raise NameError('ERROR: Members of op_list must be greater than 2.') - - -ANAKIN_TENSOR_DTYPE = { - VarDesc.VarType.BOOL: BOOLEN, - VarDesc.VarType.INT32: INT32, - VarDesc.VarType.FP16: FLOAT16, - VarDesc.VarType.FP32: FLOAT, - VarDesc.VarType.FP64: DOUBLE, -} - -ANAKIN_TENSOR_DTYPESTR = { - STR: "string", - INT32: "int", - FLOAT: "float", - BOOLEN: "bool", -} - -ANAKIN_ATTR_DTYPE = { - AttrType.INT: INT32, - AttrType.INTS: INT32, - AttrType.FLOAT: FLOAT, - AttrType.FLOATS: FLOAT, - AttrType.STRING: STR, - AttrType.STRINGS: STR, - AttrType.BOOL: BOOLEN, - AttrType.BOOLS: BOOLEN, -} - -ANAKIN_ATTR_IS_LIST = { - AttrType.INT: False, - AttrType.INTS: True, - AttrType.FLOAT: False, - AttrType.FLOATS: True, - AttrType.STRING: False, - AttrType.STRINGS: True, - AttrType.BOOL: False, - AttrType.BOOLS: True, -} - -APPEND_BIAS_OP_TYPE = [ - 'FC', - 'mul', - 'sequence_conv', - 'conv2d', - 'conv2d_transpose', - 'depthwise_conv2d', - 'elementwise_mul', -] - -APPEND_ACT_OP_TYPE = [ - 'FC', - 'mul', - 'sequence_conv', - 'conv2d', - 'conv2d_transpose', - 'batch_norm', - 'layer_norm', - 'row_conv', - 'reshape', -] diff --git a/tools/external_converter_v2/parser/kill_fluid/fluid_layer_param_transmit.py b/tools/external_converter_v2/parser/kill_fluid/fluid_layer_param_transmit.py deleted file mode 100644 index 46ed42324..000000000 --- a/tools/external_converter_v2/parser/kill_fluid/fluid_layer_param_transmit.py +++ /dev/null @@ -1,490 +0,0 @@ -from ..operations import OpsParam, OpsRegister -from ..logger import * -from ..proto import * -from fluid_helper import * - - -def ParserFeedDecorator(OpName): - def warpper(Parser): - def warpper_args(args): - Parser(args) - OpsRegister()[OpName].feed_node_attr(args[0]) - args[2].set_name(OpName) - args[0].set_op(args[2]()) - return warpper_args - return warpper - -# common -def NotNeededInInference(args): - # args is tuple object - node_io = args[0] - layer = args[1] - -@ParserFeedDecorator("Input") -def Parser_feed(args): - private_data = args[4] - input_shape = private_data['input_shape'] - alias = private_data['alias'] - OpsRegister()["Input"].input_shape = input_shape - OpsRegister()["Input"].alias = alias - -@ParserFeedDecorator("Convolution") -def Parser_conv2d(args): - op = args[1] - helper = args[3] - private_data = args[4] - [weights_tensor, weights_shape] = helper.param_tensor_sh(op, 'Filter') - OpsRegister()["Convolution"].weight_1 = weights_tensor - OpsRegister()["Convolution"].filter_num = weights_shape[0] - OpsRegister()["Convolution"].kernel_size = weights_shape[-2:] - OpsRegister()["Convolution"].strides = helper.attr_data(op, 'strides') - OpsRegister()["Convolution"].padding = helper.attr_data(op, 'paddings') - OpsRegister()["Convolution"].dilation_rate = helper.attr_data(op, 'dilations') - OpsRegister()["Convolution"].group = helper.attr_data(op, 'groups') - OpsRegister()["Convolution"].axis = 1 - if 'bias' in private_data.keys(): - OpsRegister()["Convolution"].bias_term = True - OpsRegister()["Convolution"].weight_2 = private_data['bias'] - else: - OpsRegister()["Convolution"].bias_term = False - -@ParserFeedDecorator("ReLU") -def Parser_relu(args): - OpsRegister()["ReLU"].alpha = 0.0 - -@ParserFeedDecorator("Pooling") -def Parser_pool2d(args): - op = args[1] - helper = args[3] - OpsRegister()["Pooling"].pool_size = helper.attr_data(op, 'ksize') - OpsRegister()["Pooling"].strides = helper.attr_data(op, 'strides') - OpsRegister()["Pooling"].padding = helper.attr_data(op, 'paddings') - OpsRegister()["Pooling"].global_pooling = helper.attr_data(op, 'global_pooling') - if helper.attr_data(op, 'pooling_type') == 'max': - OpsRegister()["Pooling"].method = "MAX" - elif helper.attr_data(op, 'pooling_type') in ['average', 'avg']: - OpsRegister()["Pooling"].method = "AVG" - if helper.attr_data(op, 'ceil_mode') == False: - OpsRegister()["Pooling"].cmp_out_shape_floor_as_conv = True - else: - OpsRegister()["Pooling"].cmp_out_shape_floor_as_conv = False - -@ParserFeedDecorator("Dense") -def Parser_mul(args): - op = args[1] - helper = args[3] - private_data = args[4] - weights_needs_trans = True - [weights_tensor, weights_shape] = helper.param_tensor_sh(op, 'Y', weights_needs_trans) - OpsRegister()["Dense"].weight_1 = weights_tensor - OpsRegister()["Dense"].out_dim = weights_shape[2] - OpsRegister()["Dense"].axis = helper.attr_data(op, 'x_num_col_dims') - if 'bias' in private_data.keys(): - OpsRegister()["Dense"].bias_term = True - OpsRegister()["Dense"].weight_2 = private_data['bias'] - else: - OpsRegister()["Dense"].bias_term = False - -@ParserFeedDecorator("Softmax") -def Parser_softmax(args): - private_data = args[4] - if 'axis' in private_data.keys(): - axis = private_data['axis'] - else: - axis = 1 - OpsRegister()["Softmax"].axis = axis - -@ParserFeedDecorator("Activation") -def Parser_sigmoid(args): - OpsRegister()["Activation"].type = "Sigmoid" - -@ParserFeedDecorator("Axpy") -def Parser_axpy(args): - pass - -@ParserFeedDecorator("BatchNorm") -def Parser_batch_norm(args): - op = args[1] - helper = args[3] - OpsRegister()["BatchNorm"].weight_1 = helper.param_tensor(op, 'Mean') - OpsRegister()["BatchNorm"].weight_2 = helper.param_tensor(op, 'Variance') - OpsRegister()["BatchNorm"].weight_3 = helper.create_tensor([1], [1, 1, 1, 1], FLOAT) - OpsRegister()["BatchNorm"].momentum = helper.attr_data(op, 'momentum') - OpsRegister()["BatchNorm"].epsilon = helper.attr_data(op, 'epsilon') - -@ParserFeedDecorator("Scale") -def Parser_scale_disc_bn(args): - op = args[1] - helper = args[3] - mean = helper.np_param(op, 'Mean') - var = helper.np_param(op, 'Variance') - alpha = helper.np_param(op, 'Scale') - beta = helper.np_param(op, 'Bias') - eps = helper.attr_data(op, 'epsilon') - var = np.sqrt(var + eps) - np_scale = alpha / var - np_bias = beta - (alpha * mean / var) - np_scale_shape = map(int, [1]*(4-len(np_scale.shape)) + list(np_scale.shape)) - np_bias_shape = map(int, [1]*(4-len(np_bias.shape)) + list(np_bias.shape)) - np_scale_tensor = helper.create_tensor(list(np_scale.flatten()), np_scale_shape, FLOAT) - np_bias_tensor = helper.create_tensor(list(np_bias.flatten()), np_bias_shape, FLOAT) - OpsRegister()["Scale"].bias_term = True - OpsRegister()["Scale"].weight_1 = np_scale_tensor - OpsRegister()["Scale"].weight_2 = np_bias_tensor - OpsRegister()["Scale"].axis = 1 - OpsRegister()["Scale"].num_axes = 1 - -@ParserFeedDecorator("Scale") -def Parser_scale_of_bn(args): - op = args[1] - helper = args[3] - OpsRegister()["Scale"].weight_1 = helper.param_tensor(op, 'Scale') - OpsRegister()["Scale"].axis = 1 - OpsRegister()["Scale"].num_axes = 1 - has_bias = helper.is_persistable_param(op, 'Bias') - if has_bias is True: - OpsRegister()["Scale"].bias_term = True - OpsRegister()["Scale"].weight_2 = helper.param_tensor(op, 'Bias') - else: - OpsRegister()["Scale"].bias_term = False - -@ParserFeedDecorator("Split") -def Parser_split(args): - private_data = args[4] - split_num = private_data['split_num'] - OpsRegister()["Split"].split_num = split_num - -@ParserFeedDecorator("Reshape") # NMT -def Parser_reshape(args): - op = args[1] - helper = args[3] - private_data = args[4] - if 'new_shape' in private_data.keys(): - shape = private_data['new_shape'] - else: - shape = helper.attr_data(op, 'shape') - shape = map(int, shape + [1] * (4 - len(shape))) - OpsRegister()["Reshape"].dims = shape - -@ParserFeedDecorator("Concat") -def Parser_concat(args): - op = args[1] - helper = args[3] - OpsRegister()["Concat"].axis = helper.attr_data(op, 'axis') - -@ParserFeedDecorator("Concat") -def Parser_concat_btw_priorbox_boxcoder(args): - op = args[1] - helper = args[3] - OpsRegister()["Concat"].axis = 3 - -@ParserFeedDecorator("Permute") -def Parser_transpose(args): - op = args[1] - helper = args[3] - fluid_dims = helper.attr_data(op, 'axis') - n = 4 - len(fluid_dims) - dims = range(0, n) - tail_dims = [i + n for i in fluid_dims] - dims.extend(tail_dims) - OpsRegister()["Permute"].dims = dims - - -########## SSD Model ########## - -@ParserFeedDecorator("PriorBox") -def Parser_prior_box(args): - op = args[1] - helper = args[3] - OpsRegister()["PriorBox"].min_size = helper.attr_data(op, 'min_sizes') - OpsRegister()["PriorBox"].max_size = helper.attr_data(op, 'max_sizes') - OpsRegister()["PriorBox"].aspect_ratio = helper.attr_data(op, 'aspect_ratios') - OpsRegister()["PriorBox"].is_flip = helper.attr_data(op, 'flip') - OpsRegister()["PriorBox"].is_clip = helper.attr_data(op, 'clip') - OpsRegister()["PriorBox"].variance = helper.attr_data(op, 'variances') - OpsRegister()["PriorBox"].img_h = 0 - OpsRegister()["PriorBox"].img_w = 0 - OpsRegister()["PriorBox"].step_h = helper.attr_data(op, 'step_h') - OpsRegister()["PriorBox"].step_w = helper.attr_data(op, 'step_w') - OpsRegister()["PriorBox"].offset = helper.attr_data(op, 'offset') - OpsRegister()["PriorBox"].order = ['MIN', 'COM', 'MAX'] - -@ParserFeedDecorator("box_coder") -def Parser_box_coder(args): - pass - -@ParserFeedDecorator("DetectionOutput") -def Parser_multiclass_nms(args): - op = args[1] - helper = args[3] - private_data = args[4] - OpsRegister()["DetectionOutput"].share_location = True - OpsRegister()["DetectionOutput"].variance_encode_in_target = False - OpsRegister()["DetectionOutput"].class_num = 0 - OpsRegister()["DetectionOutput"].background_id = helper.attr_data(op, 'background_label') - OpsRegister()["DetectionOutput"].keep_top_k = helper.attr_data(op, 'keep_top_k') - OpsRegister()["DetectionOutput"].conf_thresh = helper.attr_data(op, 'score_threshold') - OpsRegister()["DetectionOutput"].nms_top_k = helper.attr_data(op, 'nms_top_k') - OpsRegister()["DetectionOutput"].nms_thresh = helper.attr_data(op, 'nms_threshold') - OpsRegister()["DetectionOutput"].nms_eta = helper.attr_data(op, 'nms_eta') - if 'code_type' in private_data.keys(): - if private_data['code_type'] == 'decode_center_size': - OpsRegister()["DetectionOutput"].code_type = "CENTER_SIZE" - else: - OpsRegister()["DetectionOutput"].code_type = "CORNER" - - -########## VIS Model ########## - -@ParserFeedDecorator("Im2Sequence") -def Parser_im2sequence(args): - op = args[1] - helper = args[3] - OpsRegister()["Im2Sequence"].paddings = helper.attr_data(op, 'paddings') - OpsRegister()["Im2Sequence"].strides = helper.attr_data(op, 'strides') - OpsRegister()["Im2Sequence"].window_size = helper.attr_data(op, 'kernels') - OpsRegister()["Im2Sequence"].dilations = helper.attr_data(op, 'dilations', [1, 1]) - -@ParserFeedDecorator("Cast") -def Parser_cast(args): - op = args[1] - helper = args[3] - OpsRegister()["Cast"].in_type = helper.attr_data(op, 'in_dtype') - OpsRegister()["Cast"].out_type = helper.attr_data(op, 'out_dtype') - -@ParserFeedDecorator("Argmax") # new256 -def Parser_top_k(args): - op = args[1] - helper = args[3] - OpsRegister()["Argmax"].out_max_val = True - OpsRegister()["Argmax"].top_k = helper.attr_data(op, 'k') - OpsRegister()["Argmax"].axis_term = False - -@ParserFeedDecorator("CtcAlign") -def Parser_ctc_align(args): - op = args[1] - helper = args[3] - OpsRegister()["CtcAlign"].merge_repeated = helper.attr_data(op, 'merge_repeated') - OpsRegister()["CtcAlign"].blank = helper.attr_data(op, 'blank') - -@ParserFeedDecorator("Eltwise") -def Parser_sum(args): - OpsRegister()["Eltwise"].type = "Add" - OpsRegister()["Eltwise"].coeff = [1.0, 1.0] - -@ParserFeedDecorator("LRN") -def Parser_lrn(args): - op = args[1] - helper = args[3] - OpsRegister()["LRN"].local_size = helper.attr_data(op, 'n') - OpsRegister()["LRN"].alpha = helper.attr_data(op, 'alpha') - OpsRegister()["LRN"].beta = helper.attr_data(op, 'beta') - OpsRegister()["LRN"].norm_region = "ACROSS_CHANNELS" - OpsRegister()["LRN"].k = helper.attr_data(op, 'k') - -@ParserFeedDecorator("Gru") -def Parser_gru(args): - op = args[1] - helper = args[3] - private_data = args[4] - OpsRegister()["Gru"].is_reverse = helper.attr_data(op, 'is_reverse') - OpsRegister()["Gru"].gate_activation = helper.attr_data(op, 'gate_activation') + '_fluid' - OpsRegister()["Gru"].activation = helper.attr_data(op, 'activation') + '_fluid' - OpsRegister()["Gru"].gru_formula = "gru_origin" - if bool(private_data) is True: - ori_bx = private_data['np_bias_x'] - ori_bh = helper.np_param(op, 'Bias') - ori_b = ori_bx + ori_bh - ori_wx = private_data['np_weight_x'] - ori_wh = helper.np_param(op, 'Weight') - new_tensors = helper.gru_tensor_convert(ori_wh, ori_wx, ori_b) - weights = [] - for tensor in new_tensors: - weights.append(helper.create_tensor(list(tensor.flatten()), list(np.shape(tensor)), FLOAT)) - OpsRegister()["Gru"].weight_1 = weights[0] - OpsRegister()["Gru"].weight_2 = weights[1] - else: - OpsRegister()["Gru"].weight_1 = helper.param_tensor(op, 'Weight') - OpsRegister()["Gru"].weight_2 = helper.create_tensor([0], [-1], FLOAT) - -@ParserFeedDecorator("LSTM") -def Parser_lstm(args): - op = args[1] - helper = args[3] - private_data = args[4] - OpsRegister()["LSTM"].candidate_activation = helper.attr_data(op, 'candidate_activation') - OpsRegister()["LSTM"].cell_activation = helper.attr_data(op, 'cell_activation') - OpsRegister()["LSTM"].gate_activation = helper.attr_data(op, 'gate_activation') - OpsRegister()["LSTM"].is_reverse = helper.attr_data(op, 'is_reverse') - OpsRegister()["LSTM"].use_peepholes = helper.attr_data(op, 'use_peepholes') - OpsRegister()["LSTM"].num_direction = 1 - OpsRegister()["LSTM"].dropout_param = 1.0 - OpsRegister()["LSTM"].num_layers = 1 - OpsRegister()["LSTM"].input_activation = "null" - if bool(private_data) is True: - np_fc_bias = private_data['np_flat_fc_bias'] - np_fc_weight = private_data['np_flat_fc_weight'] - np_fc_outdim = private_data['np_fc_outdim'] - np_lstm_bias = helper.np_param(op, 'Bias') - np_lstm_weight = helper.np_param(op, 'Weight') - np_tensors = helper.lstm_fc_tensor_merge_convert(np_fc_outdim, np_lstm_weight, \ - np_lstm_bias, np_fc_weight, np_fc_bias) - np_weight = np_tensors[0] - np_bias = np_tensors[1] - np_weight_shape = map(int, [1]*(4-len(np_weight.shape)) + list(np_weight.shape)) - np_bias_shape = map(int, [1]*(4-len(np_bias.shape)) + list(np_bias.shape)) - np_weight_tensor = helper.create_tensor(list(np_weight.flatten()), np_weight_shape, FLOAT) - np_bias_tensor = helper.create_tensor(list(np_bias.flatten()), np_bias_shape, FLOAT) - OpsRegister()["LSTM"].weight_1 = np_weight_tensor - OpsRegister()["LSTM"].weight_2 = np_bias_tensor - else: - OpsRegister()["LSTM"].weight_1 = helper.param_tensor(op, 'Weight') - OpsRegister()["LSTM"].weight_2 = helper.create_tensor([0], [-1], FLOAT) - - -############### RNN ############### - -@ParserFeedDecorator("Embedding") -def Parser_lookup_table(args): - op = args[1] - helper = args[3] - [weights_tensor, weights_shape] = helper.param_tensor_sh(op, 'W') - OpsRegister()["Embedding"].weight_1 = weights_tensor - OpsRegister()["Embedding"].padding_idx = helper.attr_data(op, 'padding_idx') - OpsRegister()["Embedding"].word_num = weights_shape[2] - OpsRegister()["Embedding"].emb_dim = weights_shape[3] - -@ParserFeedDecorator("SequencePool") -def Parser_sequence_pool(args): - op = args[1] - helper = args[3] - OpsRegister()["SequencePool"].pooltype = helper.attr_data(op, 'pooltype') - -@ParserFeedDecorator("Activation") -def Parser_tanh(args): - OpsRegister()["Activation"].type = "TanH" - -@ParserFeedDecorator("SequenceConv") -def Parser_sequence_conv(args): - op = args[1] - helper = args[3] - private_data = args[4] - [weights_tensor, weights_shape] = helper.param_tensor_sh(op, 'Filter') - OpsRegister()["SequenceConv"].weight_1 = weights_tensor - OpsRegister()["SequenceConv"].filter_num = weights_shape[0] - OpsRegister()["SequenceConv"].kernel_size = weights_shape[-2:] - OpsRegister()["SequenceConv"].padding_trainable = helper.attr_data(op, 'paddingTrainable') - OpsRegister()["SequenceConv"].context_stride = helper.attr_data(op, 'contextStride') - OpsRegister()["SequenceConv"].context_start = helper.attr_data(op, 'contextStart') - OpsRegister()["SequenceConv"].context_length = helper.attr_data(op, 'contextLength') - if 'bias' in private_data.keys(): - OpsRegister()["SequenceConv"].bias_term = True - OpsRegister()["SequenceConv"].weight_2 = private_data['bias'] - else: - OpsRegister()["SequenceConv"].bias_term = False - -@ParserFeedDecorator("CrfDecoding") -def Parser_crf_decoding(args): - op = args[1] - helper = args[3] - [weights_tensor, weights_shape] = helper.param_tensor_sh(op, 'Transition') - OpsRegister()["CrfDecoding"].weight_1 = weights_tensor - -@ParserFeedDecorator("MatMul") -def Parser_matmul(args): - op = args[1] - helper = args[3] - private_data = args[4] - if 'coeff' in private_data.keys(): - coeff = private_data['coeff'] - else: - coeff = 1.0 - OpsRegister()["MatMul"].transpose_x = helper.attr_data(op, 'transpose_X') - OpsRegister()["MatMul"].transpose_y = helper.attr_data(op, 'transpose_Y') - OpsRegister()["MatMul"].coeff = coeff - -@ParserFeedDecorator("Scale") -def Parser_scale(args): - op = args[1] - helper = args[3] - scale_val = helper.attr_data(op, 'scale') - OpsRegister()["Scale"].axis = 0 - OpsRegister()["Scale"].num_axes = 0 - OpsRegister()["Scale"].bias_term = False - OpsRegister()["Scale"].weight_1 = helper.create_tensor([scale_val], [1, 1, 1, 1], FLOAT) - -@ParserFeedDecorator("LayerNorm") -def Parser_layer_norm(args): - op = args[1] - helper = args[3] - OpsRegister()["LayerNorm"].weight_1 = helper.param_tensor(op, 'Scale') - OpsRegister()["LayerNorm"].weight_2 = helper.param_tensor(op, 'Bias') - OpsRegister()["LayerNorm"].begin_norm_axis = helper.attr_data(op, 'begin_norm_axis') - OpsRegister()["LayerNorm"].eps = helper.attr_data(op, 'epsilon') - -@ParserFeedDecorator("Scale") -def Parser_dropout(args): - op = args[1] - helper = args[3] - scale_val = 1 - helper.attr_data(op, 'dropout_prob') - OpsRegister()["Scale"].axis = 0 - OpsRegister()["Scale"].num_axes = 0 - OpsRegister()["Scale"].bias_term = False - OpsRegister()["Scale"].weight_1 = helper.create_tensor([scale_val], [1, 1, 1, 1], FLOAT) - -@ParserFeedDecorator("Scale") -def Parser_elementwise_mul(args): - op = args[1] - helper = args[3] - private_data = args[4] - OpsRegister()["Scale"].weight_1 = helper.param_tensor(op, 'Y') - OpsRegister()["Scale"].axis = helper.attr_data(op, 'axis') - OpsRegister()["Scale"].num_axes = 1 - if 'bias' in private_data.keys(): - OpsRegister()["Scale"].bias_term = True - OpsRegister()["Scale"].weight_2 = private_data['bias'] - else: - OpsRegister()["Scale"].bias_term = False - - -FLUID_NODE_FILLER = { - "feed":OpsParam().set_parser(Parser_feed), - "conv2d":OpsParam().set_parser(Parser_conv2d), - "elementwise_add":OpsParam().set_parser(Parser_sum), - "relu":OpsParam().set_parser(Parser_relu), - "pool2d":OpsParam().set_parser(Parser_pool2d), - "mul":OpsParam().set_parser(Parser_mul), - "softmax":OpsParam().set_parser(Parser_softmax), - "sigmoid":OpsParam().set_parser(Parser_sigmoid), - "axpy":OpsParam().set_parser(Parser_axpy), - "batch_norm":OpsParam().set_parser(Parser_batch_norm), - "disc_bn":OpsParam().set_parser(Parser_scale_disc_bn), - "scale_of_bn":OpsParam().set_parser(Parser_scale_of_bn), - "elementwise_mul":OpsParam().set_parser(Parser_elementwise_mul), - "split":OpsParam().set_parser(Parser_split), - "depthwise_conv2d":OpsParam().set_parser(Parser_conv2d), - "reshape":OpsParam().set_parser(Parser_reshape), - "concat":OpsParam().set_parser(Parser_concat), - "transpose":OpsParam().set_parser(Parser_transpose), - "prior_box":OpsParam().set_parser(Parser_prior_box), - "box_coder":OpsParam().set_parser(Parser_box_coder), - "multiclass_nms":OpsParam().set_parser(Parser_multiclass_nms), - "concat_btw_priorbox_boxcoder":OpsParam().set_parser(Parser_concat_btw_priorbox_boxcoder), - "im2sequence":OpsParam().set_parser(Parser_im2sequence), - "gru":OpsParam().set_parser(Parser_gru), - "sum":OpsParam().set_parser(Parser_sum), - "lrn":OpsParam().set_parser(Parser_lrn), - "top_k":OpsParam().set_parser(Parser_top_k), - "ctc_align":OpsParam().set_parser(Parser_ctc_align), - "cast":OpsParam().set_parser(Parser_cast), - "lookup_table":OpsParam().set_parser(Parser_lookup_table), - "sequence_pool":OpsParam().set_parser(Parser_sequence_pool), - "tanh":OpsParam().set_parser(Parser_tanh), - "sequence_conv":OpsParam().set_parser(Parser_sequence_conv), - "crf_decoding":OpsParam().set_parser(Parser_crf_decoding), - "lstm":OpsParam().set_parser(Parser_lstm), - "matmul":OpsParam().set_parser(Parser_matmul), - "layer_norm":OpsParam().set_parser(Parser_layer_norm), - "dropout":OpsParam().set_parser(Parser_dropout), - "scale":OpsParam().set_parser(Parser_scale), -} diff --git a/tools/external_converter_v2/parser/kill_fluid/parser_fluid.py b/tools/external_converter_v2/parser/kill_fluid/parser_fluid.py deleted file mode 100644 index 088b0d84c..000000000 --- a/tools/external_converter_v2/parser/kill_fluid/parser_fluid.py +++ /dev/null @@ -1,868 +0,0 @@ -import numpy as np -import paddle.fluid as fluid -import os -from ..graph_io import * -from ..logger import * -from ..proto import * -from fluid_layer_param_transmit import * - -class FluidParser: - - def __init__(self, fluid_config_dict): - # anakin graph model io - self.graphIO = None - # config info - self.ModelPath = fluid_config_dict['ModelPath'] - self.NetType = fluid_config_dict['NetType'] - self.Debug = fluid_config_dict['Debug'] - # config fluid - self.place = fluid.CPUPlace() - self.exe = fluid.Executor(self.place) - self.scope = fluid.core.Scope() - # in and out edges of node - self.ins = {} - self.outs = {} - # inplaced main node - self.inplace_nodes = {} - self.graph_ins = [] - self.graph_outs = [] - - def __call__(self): - return self._Parsing() - - def _NameNodeMid(self, op): - first_outparam = op.output_names[0] - arg_name = str(op.output(first_outparam)[0]).split('.')[0] - #new_name = op.type + '_' + bytes(op.idx) - new_name = op.type + '#' + bytes(op.idx) + '(' + arg_name + ')' - return new_name - - def _NameNodeIn(self, in_name): - new_name = 'input_' + bytes(self.graph_ins.index(in_name)) - return new_name - - def _NameNodeOut(self, out_name): - new_name = out_name + '_gout' - return new_name - - def _AddPairEdges(self, start_node_name, end_node_name, out_param, in_param): - self.outs[start_node_name].add(out_param, end_node_name) - self.ins[end_node_name].add(in_param, start_node_name) - - def _RmPairEdges(self, start_node_name, end_node_name): - self.outs[start_node_name].rm(end_node_name) - self.ins[end_node_name].rm(start_node_name) - - def _InitEdges(self, node_name): - self.ins[node_name] = Fluid_edger() - self.outs[node_name] = Fluid_edger() - - def _ClearEdges(self, node_name): - if node_name.startswith('input_') is False: - del self.ins[node_name] - if node_name.endswith('_gout') is False: - del self.outs[node_name] - - def _GetOp(self, ops, mid_node_name): - mid_op = None - for op in ops: - node_name = self._NameNodeMid(op) - if mid_node_name == node_name: - mid_op = op - return mid_op - - def _OpTypes(self, ops): - types_cache = [] - for op in ops: - if op.type not in types_cache: - types_cache.append(op.type) - return types_cache - - def _AddProtoNode(self, node_name, op_of_node, helper, private_data, op_type = None): - nodeIO = NodeProtoIO() - opIO = OpsProtoIO() - nodeIO.set_name(node_name) - if op_type is None: - op_type = op_of_node.type - FLUID_NODE_FILLER[op_type](nodeIO, op_of_node, opIO, helper, private_data) - self.graphIO.add_node(nodeIO()) - - def _RmProtoNode(self, node_name): - self.graphIO.rm_node(self.graphIO.find_node_proto(node_name)) - - def _InplaceNodes(self, position): - inplace_heads = self.inplace_nodes.keys() - inplace_mids = [] - inplace_ends = [] - for main_node_name in self.inplace_nodes.keys(): - mid_nodes_name = self.inplace_nodes[main_node_name][1: -1] - inplace_mids.extend(mid_nodes_name) - for main_node_name in self.inplace_nodes.keys(): - end_node_name = self.inplace_nodes[main_node_name][-1] - inplace_ends.append(end_node_name) - if position == 'Head': - return inplace_heads - elif position == 'Mid': - return inplace_mids - elif position == 'End': - return inplace_ends - elif position == 'All': - return inplace_heads + inplace_mids + inplace_ends - - def _EdgeInplace(self, source_ops, helper): - for source_op in source_ops: - if source_op.type not in ['feed', 'fetch']: - if len(source_op.input_arg_names) == 1 \ - and source_op.input_arg_names == source_op.output_arg_names: - source_node_name = self._NameNodeMid(source_op) - inplace_arg = source_op.input_arg_names[0] - for tmp_op in source_ops: - if tmp_op.idx != source_op.idx and inplace_arg in tmp_op.output_arg_names: - main_node_name = self._NameNodeMid(tmp_op) - if main_node_name not in self.inplace_nodes.keys(): - self.inplace_nodes[main_node_name] = [main_node_name] - self.inplace_nodes[main_node_name].append(source_node_name) - for main_node_name in self.inplace_nodes.keys(): - inplace_list = self.inplace_nodes[main_node_name] - for inplace_node in inplace_list: - idx = inplace_list.index(inplace_node) - if idx != 0: - self.ins[inplace_node] = Fluid_edger('_In', inplace_list[idx - 1]) - if idx != len(inplace_list) - 1: - self.outs[inplace_node] = Fluid_edger('_Out', inplace_list[idx + 1]) - - def _GetDebugOuts(self, source_ops, helper): - if self.Debug == 'DEBUG': - debug_fetch_list = [] - for source_op in source_ops: - if source_op.type == 'fetch': - var_name = source_op.input_arg_names[0] - for tmp_op in source_ops: - if tmp_op.idx != source_op.idx and var_name in tmp_op.input_arg_names: - if var_name not in debug_fetch_list: - debug_fetch_list.append(var_name) - elif tmp_op.type == 'gru' and var_name in tmp_op.output_arg_names: - if var_name not in debug_fetch_list: - debug_fetch_list.append(var_name) - else: - pass - return debug_fetch_list - else: - return [] - - def _ParseBase(self, source_ops, helper, sub_graph_nodes = []): - # Create the original base graph as described in fluid program. - self.graphIO = GraphProtoIO() - self.graphIO.set_name('default_graph_name') - debug_fetch_list = self._GetDebugOuts(source_ops, helper) - self._EdgeInplace(source_ops, helper) - for source_op in source_ops: - if source_op.type not in ['feed', 'fetch']: - main_node_name = self._NameNodeMid(source_op) - in_edges = Fluid_edger() - out_edges = Fluid_edger() - for param in source_op.input_names: - for idx in range(0, len(helper.args_by_input_param(source_op, param))): - arg = helper.var_name_by_param(source_op, param, idx) - for tmp_op in source_ops: - if tmp_op.idx != source_op.idx and arg in tmp_op.output_arg_names: - if tmp_op.type == 'feed': - if arg not in self.graph_ins: - self.graph_ins.append(arg) - self.graphIO.add_in(self._NameNodeIn(arg)) - in_edges.add(param, self._NameNodeIn(arg), arg) - else: - tmp_node_name = self._NameNodeMid(tmp_op) - if tmp_node_name in self.inplace_nodes.keys(): - inplace_node_name = self.inplace_nodes[tmp_node_name][-1] - in_edges.add(param, inplace_node_name, arg) - elif tmp_node_name not in self._InplaceNodes('All'): - in_edges.add(param, tmp_node_name, arg) - for param in source_op.output_names: - for idx in range(0, len(helper.args_by_output_param(source_op, param))): - arg = helper.var_name_by_param(source_op, param, idx) - for tmp_op in source_ops: - if tmp_op.idx != source_op.idx and arg in tmp_op.input_arg_names: - if tmp_op.type == 'fetch': - if arg not in debug_fetch_list: - arg_node_name = self._NameNodeOut(arg) - if arg not in self.graph_outs: - self.graph_outs.append(arg) - self.graphIO.add_out_fluid(arg_node_name, main_node_name) - out_edges.add(param, arg_node_name, arg) - self.ins[arg_node_name] = Fluid_edger(bytes(source_op.idx), \ - main_node_name) - else: - out_edges.add(param, self._NameNodeMid(tmp_op), arg) - self._AddProtoNode(main_node_name, source_op, helper, {}) - if main_node_name not in self._InplaceNodes('Mid'): - if main_node_name not in self._InplaceNodes('End'): - self.ins[main_node_name] = in_edges - if main_node_name not in self._InplaceNodes('Head'): - if main_node_name not in self._InplaceNodes('End'): - self.outs[main_node_name] = out_edges - else: - inplace_node_name = self.inplace_nodes[main_node_name][-1] - self.outs[inplace_node_name] = out_edges - for redundant_target in self.inplace_nodes[main_node_name][1:]: - self.outs[inplace_node_name].rm(redundant_target) - - def _PrintEdge(self, node, target, direction): - var_name = 'Unknown' - if direction == 'in': - var = self.ins[node].vars_by_target(target) - elif direction == 'out': - var = self.outs[node].vars_by_target(target) - if len(var) > 0: - var_name = var[0] - print node + ",\t" + target + ",\t" + var_name - - def _Graph(self, need_print = False): - for node in self.ins.keys(): - targets_list = self.ins[node]() - for target in targets_list: - self.graphIO.add_in_edge(target, node) - for node in self.outs.keys(): - targets_list = self.outs[node]() - for target in targets_list: - self.graphIO.add_out_edge(node, target) - if need_print is True: - self._PrintEdge(node, target, 'out') - - def _ReplaceInputs(self, source_ops, helper, reshape_dict = {}, layout = 'NCHW'): - for source_op in source_ops: - if source_op.type in ['feed']: - out_edges = Fluid_edger() - for param in source_op.output_names: - private_data = {} - arg = helper.var_name_by_param(source_op, param) - input_node_name = self._NameNodeIn(arg) - for tmp_op in source_ops: - if tmp_op.idx != source_op.idx and arg in tmp_op.input_arg_names: - out_edges.add(param, self._NameNodeMid(tmp_op)) - arg_idx = source_op.output_arg_names.index(arg) - shape = helper.var_shape_by_param(False, source_op, "Out", arg_idx, 'UNMODIFIED') - if shape[0] == -1: - shape[0] = 1 - if layout == 'NCHW': - shape = map(int, [1] * (4 - len(shape)) + shape) - if input_node_name in reshape_dict.keys(): - shape = reshape_dict[input_node_name] - private_data['input_shape'] = shape - private_data['alias'] = arg - self.outs[input_node_name] = out_edges - self._AddProtoNode(input_node_name, source_op, helper, private_data) - - def _InsertSplit(self, source_ops, helper): - # If a layer has two identical output tensors, add a split layer. - for node in self.outs.keys(): - if node.startswith('split#') is False: - out_edges = self.outs[node] - for param in out_edges.all_params(): - out_targets_list = out_edges.targets(param) - if len(out_targets_list) > 1: - private_data = {} - private_data['split_num'] = len(out_targets_list) - split_node_name = 'split#' + bytes(out_edges.all_params().index(param)) + '#' + node - self._InitEdges(split_node_name) - for out_target in out_targets_list: - self.outs[node].rm(out_target) - self.ins[out_target].mv(node, split_node_name) - self.outs[split_node_name].add('_Out', out_target) - self._AddPairEdges(node, split_node_name, param, '_In') - self._AddProtoNode(split_node_name, None, helper, private_data, 'split') - - def _Subgraph(self, starts, ends): - out_idx = {} - results = union(starts, ends) - def outs(node): - if node in self.outs.keys(): - return self.outs[node]() - else: - return [] - def next_out(node): - next_out = '' - if len(outs(node)) == 0: - return -1 - elif node not in out_idx.keys(): - out_idx[node] = 0 - if out_idx[node] < len(outs(node)): - next_out = outs(node)[out_idx[node]] - out_idx[node] += 1 - return next_out - for start in starts: - cache = [start] - while len(cache) > 0: - target = next_out(cache[-1]) - while target != -1 and target not in results: - if bool(target) is True: - cache.append(target) - target = next_out(target) - else: - if cache[-1] in results: - results = union(results, cache) - break - if target in results: - cache.append(target) - results = union(results, cache) - cache.pop() - return results - - def _CropGraph(self, ins_of_subgraph, outs_of_subgraph, helper, need_io = True): - def all_nodes(): - all_nodes = [] - for main_node in self.ins.keys(): - all_nodes.extend(self.ins[main_node].all_targets()) - for main_node in self.outs.keys(): - all_nodes.extend(self.outs[main_node].all_targets()) - return list(set(all_nodes)) - stayed_nodes = self._Subgraph(ins_of_subgraph, outs_of_subgraph) - all_nodes = all_nodes() - extra_nodes = difference(all_nodes, stayed_nodes) - for node_name in extra_nodes: - self._RmProtoNode(node_name) - self._ClearEdges(node_name) - if node_name in self.graphIO.ins(): - self.graphIO.rm_in(node_name) - if node_name in self.graphIO.outs(): - self.graphIO.rm_out(node_name) - for node_name in ins_of_subgraph: - if node_name in self.ins: - self.ins[node_name].clear() - for node_name in outs_of_subgraph: - if node_name in self.outs: - self.outs[node_name].clear() - if need_io is True: - for node_name in outs_of_subgraph: - if node_name not in self.graphIO.outs(): - out_node_name = node_name + '_crop_out' - self.ins[out_node_name] = Fluid_edger('_In', node_name) - self.outs[node_name] = Fluid_edger('_Out', out_node_name) - self.graphIO.add_out_fluid(out_node_name, node_name) - for node_name in ins_of_subgraph: - if node_name not in self.graphIO.ins(): - in_node_name = node_name + '_crop_in' - private_data = {'input_shape': [-1, -1, -1, -1]} - self.ins[node_name] = Fluid_edger('_In', in_node_name) - self.outs[in_node_name] = Fluid_edger('_Out', node_name) - self._AddProtoNode(in_node_name, None, helper, private_data, 'feed') - - def _IntegrateNodes(self, main_op, main_node_name, sec_node_name, helper, private_data): - # Merge secondary nodes to the primary node and process the edges. - self._RmProtoNode(main_node_name) - self._RmProtoNode(sec_node_name) - target_nodes_names = self.outs[sec_node_name]() - for target_node_name in target_nodes_names: - self.ins[target_node_name].mv(sec_node_name, main_node_name) - self.outs[main_node_name].mv(sec_node_name, target_node_name) - self.ins[target_node_name].rm(sec_node_name) - self.outs[sec_node_name].rm(target_node_name) - self.ins[sec_node_name].rm(main_node_name) - self.outs[main_node_name].rm(sec_node_name) - self._AddProtoNode(main_node_name, main_op, helper, private_data) - - def _DealWithBias(self, source_ops, helper): - # In fluid, the bias parameter of the conv2d is split into elementwise_add. - for source_op in source_ops: - if source_op.type in APPEND_BIAS_OP_TYPE: - private_data = {} - main_node_name = self._NameNodeMid(source_op) - if main_node_name in self.outs.keys(): - tmp_nodes_names = self.outs[main_node_name]() - if len(tmp_nodes_names) == 1 and tmp_nodes_names[0].startswith('elementwise_add'): - elt_node_name = tmp_nodes_names[0] - elt_op = self._GetOp(source_ops, elt_node_name) - has_weights = helper.is_persistable_param(elt_op, 'Y') - if self._NameNodeMid(elt_op) == elt_node_name and has_weights: - [elt_tensor, shape] = helper.param_tensor_sh(elt_op, 'Y') - new_shape = [1, shape[3], 1, 1] - elt_tensor.set_shape(new_shape) - private_data['bias'] = elt_tensor - self._IntegrateNodes(source_op, main_node_name, elt_node_name, helper, private_data) - - def _DealWithBatchnorm(self, source_ops, helper): - # In anakin, the scale part of batchnorm layer is independent. - for source_op in source_ops: - if source_op.type == 'batch_norm': - discrete_flag = True - main_node_name = self._NameNodeMid(source_op) - input_name = self.ins[main_node_name].target('X') - has_scale = helper.is_persistable_param(source_op, 'Scale') - if input_name.startswith('elementwise_add'): - elt_op = self._GetOp(source_ops, input_name) - x_of_elt = self.ins[input_name].target('X') - has_weights = helper.is_persistable_param(elt_op, 'Y') - if (x_of_elt.startswith('conv2d') or x_of_elt.startswith('depthwise_conv2d')) and has_weights: - discrete_flag = False - elif input_name.startswith('conv2d') or input_name.startswith('depthwise_conv2d'): - discrete_flag = False - if discrete_flag is True: - self._RmProtoNode(main_node_name) - self._AddProtoNode(main_node_name, source_op, helper, {}, 'disc_bn') - elif has_scale is True: - append_node_name = main_node_name + '__scale' - tmp_all_targets_params = self.outs[main_node_name].targets_with_params() - self._InitEdges(append_node_name) - for [tmp_node_name, tmp_param_name] in tmp_all_targets_params: - self.outs[append_node_name].add(tmp_param_name, tmp_node_name) - self.ins[tmp_node_name].mv(main_node_name, append_node_name) - self.outs[main_node_name].rm(tmp_node_name) - self.ins[tmp_node_name].rm(main_node_name) - self.outs[main_node_name].add('_Scale_out', append_node_name) - self.ins[append_node_name].add('_Ins', main_node_name) - self._AddProtoNode(append_node_name, source_op, helper, {}, 'scale_of_bn') - - def _DealWithAxpy(self, source_ops, helper): - for source_op in source_ops: - if source_op.type == 'elementwise_mul': - mul_node_name = self._NameNodeMid(source_op) - out_targets = self.outs[mul_node_name]() - if len(out_targets) == 1 and out_targets[0].startswith('elementwise_add'): - add_node_name = out_targets[0] - self._RmProtoNode(add_node_name) - a_node_name = self.ins[mul_node_name].target('Y') - x_node_name = self.ins[mul_node_name].target('X') - y_node_name = self.ins[add_node_name].target('X') - self._ClearEdges(mul_node_name) - self.ins[add_node_name].clear() - self.outs[a_node_name].mv(mul_node_name, add_node_name) - self.outs[x_node_name].mv(mul_node_name, add_node_name) - self.ins[add_node_name].add('A', a_node_name) - self.ins[add_node_name].add('X', x_node_name) - self.ins[add_node_name].add('Y', y_node_name) - self._RmProtoNode(mul_node_name) - self._AddProtoNode(add_node_name, None, helper, {}, 'axpy') - - def _DealWithPriorBox(self, source_ops, helper): - nodes_to_del = [] - for source_op in source_ops: - if source_op.type == 'prior_box': - pb_node_name = self._NameNodeMid(source_op) - br_node_name = self.outs[pb_node_name].target('Boxes') - vr_node_name = self.outs[pb_node_name].target('Variances') - bc_node_name = self.outs[br_node_name].target('Out') - vc_node_name = self.outs[vr_node_name].target('Out') - boxcoder_node_name = self.outs[bc_node_name].target('Out') - self.outs[pb_node_name].mv(br_node_name, bc_node_name) - self.outs[pb_node_name].rm(vr_node_name) - self.ins[bc_node_name].mv(br_node_name, pb_node_name) - self.ins[boxcoder_node_name].rm(vc_node_name) - for node_name in [br_node_name, vr_node_name, vc_node_name]: - if node_name not in nodes_to_del: - nodes_to_del.append(node_name) - input_node_name = self.ins[pb_node_name].target('Input') - image_node_name = self.ins[pb_node_name].target('Image') - self.ins[pb_node_name].rm(input_node_name) - self.ins[pb_node_name].rm(image_node_name) - self.ins[pb_node_name].add('Input', input_node_name) - self.ins[pb_node_name].add('Image', image_node_name) - self._RmProtoNode(bc_node_name) - self._AddProtoNode(bc_node_name, None, helper, {}, 'concat_btw_priorbox_boxcoder') - for node_name in nodes_to_del: - self._RmProtoNode(node_name) - self._ClearEdges(node_name) - - def _DealWithDetectionOutput(self, source_ops, helper): - for source_op in source_ops: - if source_op.type == 'box_coder': - bc_node_name = self._NameNodeMid(source_op) - out_targets = self.outs[bc_node_name]() - if len(out_targets) == 1 and out_targets[0].startswith('multiclass_nms'): - private_data = {} - private_data['code_type'] = helper.attr_data(source_op, 'code_type') - bc_out_arg = helper.var_name_by_param(source_op, 'OutputBox') - for tmp_op in source_ops: - if tmp_op.idx != source_op.idx and bc_out_arg in tmp_op.input_arg_names: - nms_op = tmp_op - nms_node_name = out_targets[0] - loc_node_name = self.ins[bc_node_name].target('TargetBox') - conf_node_name = self.ins[nms_node_name].target('Scores') - box_node_name = self.ins[bc_node_name].target('PriorBox') - self._ClearEdges(bc_node_name) - self.ins[nms_node_name].clear() - self.outs[loc_node_name].mv(bc_node_name, nms_node_name) - self.outs[box_node_name].mv(bc_node_name, nms_node_name) - self.ins[nms_node_name].add('mbox_loc', loc_node_name) - self.ins[nms_node_name].add('mbox_conf_flatten', conf_node_name) - self.ins[nms_node_name].add('mbox_prior_box', box_node_name) - self._RmProtoNode(bc_node_name) - self._RmProtoNode(nms_node_name) - self._AddProtoNode(nms_node_name, nms_op, helper, private_data, 'multiclass_nms') - - def _DealWithMultiFC(self, source_ops, helper): - for source_op in source_ops: - if source_op.type == 'sum': - sum_node_name = self._NameNodeMid(source_op) - mul_names_list = self.ins[sum_node_name].targets('X') - elt_node_name = self.outs[sum_node_name].target('Out') - if elt_node_name.startswith('elementwise_add') and len(mul_names_list) > 1: - elt_op = self._GetOp(source_ops, elt_node_name) - elt_has_weights = helper.is_persistable_param(elt_op, 'Y') - fc_flag = True - for mul_node_name in mul_names_list: - if mul_node_name.startswith('mul') is False: - fc_flags = False - if fc_flag and elt_has_weights: - private_data = {} - first_mul_name = mul_names_list[0] - first_mul_op = self._GetOp(source_ops, first_mul_name) - in_of_mul_name = self.ins[first_mul_name].target('X') - out_of_elt_name = self.outs[elt_node_name].target('Out') - self.outs[sum_node_name].mv(elt_node_name, out_of_elt_name) - self.ins[out_of_elt_name].mv(elt_node_name, sum_node_name) - self._ClearEdges(elt_node_name) - [elt_tensor, shape] = helper.param_tensor_sh(elt_op, 'Y') - new_shape = [1, shape[3], 1, 1] - elt_tensor.set_shape(new_shape) - private_data['bias'] = elt_tensor - self._RmProtoNode(elt_node_name) - self._RmProtoNode(first_mul_name) - self._AddProtoNode(first_mul_name, first_mul_op, helper, private_data) - - def _DealWithGru(self, source_ops, helper): - for source_op in source_ops: - if source_op.type == 'gru': - private_data = {} - gru_flags = [False, False] - gru_node_name = self._NameNodeMid(source_op) - gru_op = self._GetOp(source_ops, gru_node_name) - input_list_of_gru = self.ins[gru_node_name].targets('Input') - if len(input_list_of_gru) == 1 and input_list_of_gru[0].startswith('elementwise_add'): - elt_node_name = input_list_of_gru[0] - elt_op = self._GetOp(source_ops, elt_node_name) - has_weights = helper.is_persistable_param(elt_op, 'Y') - if has_weights is True: - private_data['np_bias_x'] = helper.np_param(elt_op, 'Y') - gru_flags[0] = True - input_list_of_elt = self.ins[elt_node_name].targets('X') - if len(input_list_of_elt) == 1 and input_list_of_elt[0].startswith('mul'): - mul_node_name = input_list_of_elt[0] - mul_op = self._GetOp(source_ops, mul_node_name) - if helper.var_name_by_param(mul_op, 'Y').startswith('fc'): - if helper.attr_data(mul_op, 'x_num_col_dims') == 1: - input_list_of_mul = self.ins[mul_node_name].targets('X') - input_name_of_mul = input_list_of_mul[0] - private_data['np_weight_x'] = helper.np_param(mul_op, 'Y') - gru_flags[1] = True - else: - raise NameError('ERROR: Axis of GRU_FC must be 1.') - if gru_flags == [True, True]: - self.outs[input_name_of_mul].mv(mul_node_name, gru_node_name) - self.ins[gru_node_name].mv(elt_node_name, input_name_of_mul) - for node_to_del_name in [mul_node_name, elt_node_name, gru_node_name]: - self._RmProtoNode(node_to_del_name) - if node_to_del_name is not gru_node_name: - self._ClearEdges(node_to_del_name) - self._AddProtoNode(gru_node_name, gru_op, helper, private_data) - - def _SearchBilstm(self, source_ops, helper): - comp = Fluid_comparator(helper) - lstm_ops = [] - for source_op in source_ops: - if source_op.type == 'lstm': - lstm_ops.append(source_op) - if len(lstm_ops) == 2: - lstm_a = lstm_ops[0] - lstm_b = lstm_ops[1] - same_bias = comp.compare_by_param(lstm_a, lstm_b, 'Bias') - same_weight = comp.compare_by_param(lstm_a, lstm_b, 'Weight') - if same_bias and same_weight: - return True - else: - return False - else: - return False - - def _DealWithLstm(self, source_ops, helper): - for source_op in source_ops: - if source_op.type == 'lstm': - private_data = {} - lstm_flags = [False, False] - lstm_node_name = self._NameNodeMid(source_op) - lstm_op = self._GetOp(source_ops, lstm_node_name) - input_list_of_lstm = self.ins[lstm_node_name].targets('Input') - input_list = [] - if len(input_list_of_lstm) == 1: - in_lstm_node_name = input_list_of_lstm[0] - if input_list_of_lstm[0].split('#')[0] == 'elementwise_add': - elt_op = self._GetOp(source_ops, in_lstm_node_name) - has_weights = helper.is_persistable_param(elt_op, 'Y') - if has_weights is True: - private_data['np_flat_fc_bias'] = helper.np_param(elt_op, 'Y') - lstm_flags[0] = True - input_list = self.ins[in_lstm_node_name].targets('X') - elif input_list_of_lstm[0].split('#')[0] == 'mul': - private_data['np_flat_fc_bias'] = None - input_list = input_list_of_lstm - lstm_flags[0] = True - if lstm_flags[0] is True and len(input_list) == 1: - if input_list[0].split('#')[0] == 'mul': - mul_node_name = input_list[0] - mul_op = self._GetOp(source_ops, mul_node_name) - #if helper.var_name_by_param(mul_op, 'Y').startswith('fc'): - if helper.attr_data(mul_op, 'x_num_col_dims') == 1: - input_list_of_mul = self.ins[mul_node_name].targets('X') - input_name_of_mul = input_list_of_mul[0] - [w_np, w_sh] = helper.data_with_shape_by_param(mul_op, 'Y', \ - False, None, 0, False) - private_data['np_flat_fc_weight'] = w_np - private_data['np_fc_outdim'] = w_sh[3] - lstm_flags[1] = True - else: - raise NameError('ERROR: Axis of LSTM_FC must be 1.') - if lstm_flags == [True, True]: - self.outs[input_name_of_mul].mv(mul_node_name, lstm_node_name) - self.ins[lstm_node_name].mv(in_lstm_node_name, input_name_of_mul) - if in_lstm_node_name == mul_node_name: - nodes_to_del = [mul_node_name, lstm_node_name] - else: - nodes_to_del = [mul_node_name, in_lstm_node_name, lstm_node_name] - for node_to_del_name in nodes_to_del: - self._RmProtoNode(node_to_del_name) - if node_to_del_name is not lstm_node_name: - self._ClearEdges(node_to_del_name) - self._AddProtoNode(lstm_node_name, lstm_op, helper, private_data) - - def _DealWithCast(self, source_ops, helper): - for source_op in source_ops: - if source_op.type == 'cast': - if helper.attr_data(source_op, 'out_dtype') == 5: - cast_node_name = self._NameNodeMid(source_op) - if cast_node_name in self.ins: - input_name_of_cast = self.ins[cast_node_name].target('X') - if input_name_of_cast.startswith('top_k') is False: - output_name_of_cast = self.outs[cast_node_name].target('Out') - self.outs[input_name_of_cast].mv(cast_node_name, output_name_of_cast) - self.ins[output_name_of_cast].mv(cast_node_name, input_name_of_cast) - self._RmProtoNode(cast_node_name) - self._ClearEdges(cast_node_name) - else: - print 'Cannot find the layer corresponding to cast.' - else: - raise NameError('The out type of cast must be float32.') - - def _DealWithArgmax(self, source_ops, helper): - for source_op in source_ops: - if source_op.type == 'top_k': - private_data = {} - topk_node_name = self._NameNodeMid(source_op) - out_list = self.outs[topk_node_name].targets('Out') - index_list = self.outs[topk_node_name].targets('Indices') - if len(index_list) > 0: - if len(out_list) == 1 and index_list[0].startswith('cast'): - private_data['out_max_val'] = True - idxcast_node_name = index_list[0] - output_name_of_idxcast = self.outs[idxcast_node_name].target('Out') - if output_name_of_idxcast == out_list[0] and out_list[0].startswith('concat'): - concat_node_name = out_list[0] - output_name_of_concat = self.outs[concat_node_name].target('Out') - self.outs[topk_node_name].rm(idxcast_node_name) - self.outs[topk_node_name].mv(concat_node_name, output_name_of_concat) - self.ins[output_name_of_concat].mv(concat_node_name, topk_node_name) - for node_to_del_name in [concat_node_name, idxcast_node_name]: - self._RmProtoNode(node_to_del_name) - self._ClearEdges(node_to_del_name) - elif output_name_of_idxcast != out_list[0]: - if output_name_of_idxcast.endswith('_gout') and \ - out_list[0].endswith('_gout'): - gout_node_name = out_list[0] - idx_gout_node_name = output_name_of_idxcast - self.outs[topk_node_name].rm(idxcast_node_name) - for node_to_del_name in [idx_gout_node_name, idxcast_node_name]: - self._RmProtoNode(node_to_del_name) - self._ClearEdges(node_to_del_name) - self.graphIO.rm_out(idx_gout_node_name) - elif len(out_list) == 0: - private_data['out_max_val'] = False - self._DealWithCast(source_ops, helper) - else: - raise NameError('ERROR: Unknown top_k layer.') - self._RmProtoNode(topk_node_name) - self._AddProtoNode(topk_node_name, source_op, helper, private_data) - - def _DealWithReshape(self, source_ops, helper): - for source_op in source_ops: - if source_op.type == 'reshape': - reshape_node_name = self._NameNodeMid(source_op) - if reshape_node_name in self.ins: - shape_inputs = self.ins[reshape_node_name].targets('Shape') - tensor_inputs = self.ins[reshape_node_name].targets('X') - if len(shape_inputs) == 1 and len(tensor_inputs) == 1: - self.ins[reshape_node_name].rm(shape_inputs[0]) - self.ins[reshape_node_name].add('Shape', shape_inputs[0]) - else: - pass - - def _DealWithSoftmax(self, source_ops, helper): - for source_op in source_ops: - if source_op.type == 'softmax': - softmax_node_name = self._NameNodeMid(source_op) - outs_of_softmax = self.outs[softmax_node_name].targets('Out') - ins_of_softmax = self.ins[softmax_node_name].targets('X') - def prune(reshape_node_name): - branch = [] - branch.append(reshape_node_name) - shape_inputs = self.ins[reshape_node_name].targets('Shape') - tensor_input = self.ins[reshape_node_name].target('X') - tensor_output = self.outs[reshape_node_name].target('Out') - if len(shape_inputs) == 1: - branch.append(shape_inputs[0]) - if len(branch) == 2 and branch[1].split('#')[0] == 'split': - split_node_name = branch[1] - self.outs[split_node_name].rm(reshape_node_name) - self.ins[reshape_node_name].rm(split_node_name) - if len(self.outs[split_node_name].targets('_Out')) == 0: - input_of_split = self.ins[split_node_name].target('_In') - branch.append(input_of_split) - self._RmProtoNode(split_node_name) - self._ClearEdges(split_node_name) - elif len(branch) == 2 and branch[1].startswith('input'): - raise NameError('ERROR: None-split input of Softmax has not supported.') - self.outs[tensor_input].mv(reshape_node_name, tensor_output) - self.ins[tensor_output].mv(reshape_node_name, tensor_input) - self._RmProtoNode(reshape_node_name) - self._ClearEdges(reshape_node_name) - if len(branch) == 3 and branch[2].startswith('input'): - input_node_name = branch[2] - self._RmProtoNode(input_node_name) - self._ClearEdges(input_node_name) - if outs_of_softmax[0].split('#')[0] == 'reshape' and \ - ins_of_softmax[0].split('#')[0] == 'reshape': - private_data = {} - private_data['axis'] = 3 - prune(outs_of_softmax[0]) - prune(ins_of_softmax[0]) - self._RmProtoNode(softmax_node_name) - self._AddProtoNode(softmax_node_name, source_op, helper, private_data) - - def _DealWithMatmal(self, source_ops, helper): - for source_op in source_ops: - if source_op.type == 'matmul': - matmul_node_name = self._NameNodeMid(source_op) - x_input_name = self.ins[matmul_node_name].target('X') - y_input_name = self.ins[matmul_node_name].target('Y') - flag = False - coeff = 1.0 - for node_name in [x_input_name, y_input_name]: - if node_name.startswith('scale') or node_name.startswith('dropout'): - op = self._GetOp(source_ops, node_name) - if node_name.startswith('scale'): - scale = helper.attr_data(op, 'scale') - elif node_name.startswith('dropout'): - scale = 1 - helper.attr_data(op, 'dropout_prob') - input_node = self.ins[node_name].target('X') - self.outs[input_node].mv(node_name, matmul_node_name) - self.ins[matmul_node_name].mv(node_name, input_node) - self._RmProtoNode(node_name) - self._ClearEdges(node_name) - coeff = coeff * scale - flag = True - if flag is True: - private_data = {} - private_data['coeff'] = coeff - self._RmProtoNode(matmul_node_name) - self._AddProtoNode(matmul_node_name, source_op, helper, private_data) - - def _DealWithDiscBatchNorm(self, source_ops, helper): - for source_op in source_ops: - if source_op.type == 'batch_norm': - discrete_flag = True - bn_node_name = self._NameNodeMid(source_op) - input_name = self.ins[bn_node_name].target('X') - if input_name.startswith('elementwise_add'): - input_of_elt = self.ins[input_name].target('X') - if input_of_elt.startswith('conv2d'): - discrete_flag = False - elif input_name.startswith('conv2d'): - discrete_flag = False - if discrete_flag is True: - self._RmProtoNode(bn_node_name) - self._AddProtoNode(bn_node_name, source_op, helper, {}, 'disc_bn') - - def _DealWithSSD(self, source_ops, helper): - for source_op in source_ops: - if source_op.type == 'reshape': - rh_node_name = self._NameNodeMid(source_op) - if rh_node_name in self.ins: - private_data = dict() - input_name = self.ins[rh_node_name].target('X') - shape = helper.attr_data(source_op, 'shape') - if input_name.startswith('concat'): - private_data['new_shape'] = [0, shape[0], shape[1], 0] - else: - private_data['new_shape'] = [0, -1, 1, 1] - self._RmProtoNode(rh_node_name) - self._AddProtoNode(rh_node_name, source_op, helper, private_data, 'reshape') - for source_op in source_ops: - if source_op.type == 'softmax': - private_data = dict() - sm_node_name = self._NameNodeMid(source_op) - private_data['axis'] = 2 - self._RmProtoNode(sm_node_name) - self._AddProtoNode(sm_node_name, source_op, helper, private_data, 'softmax') - - def _NewCommonLayer(self, - source_ops, - in_target, - in_param, - out_target, - out_param, - layer_type, - private_data, - helper, - insert_mode = True): - main_layer = layer_type + '_after_' + in_target - if insert_mode is True: - if in_target in self.ins[out_target].all_targets() and \ - out_target in self.outs[in_target].all_targets(): - self.ins[out_target].mv(in_target, main_layer) - self.outs[in_target].mv(out_target, main_layer) - else: - raise NameError('ERROR: Usage of InsertCommonLayer has not supported.') - else: - self.ins[out_target].add(in_param + '_insert', main_layer) - self.outs[in_target].add(out_param + '_insert', main_layer) - self.ins[main_layer] = Fluid_edger(in_param, in_target) - self.outs[main_layer] = Fluid_edger(out_param, out_target) - self._AddProtoNode(main_layer, None, helper, private_data, layer_type) - - def _ParseNetwork(self, source_ops, helper): - self._ParseBase(source_ops, helper) - if self.NetType == "FLUIDBASE": - pass - else: - reshape_dict = {} - if self.NetType == "OCR": - reshape_dict['input_0'] = [1, 1, 48, 1500] - self._ReplaceInputs(source_ops, helper, reshape_dict) - self._InsertSplit(source_ops, helper) - self._DealWithGru(source_ops, helper) - self._DealWithLstm(source_ops, helper) - self._DealWithBias(source_ops, helper) - self._DealWithBatchnorm(source_ops, helper) - self._DealWithMultiFC(source_ops, helper) - self._DealWithArgmax(source_ops, helper) - self._DealWithAxpy(source_ops, helper) - if self.NetType == "SSD": - self._DealWithPriorBox(source_ops, helper) - self._DealWithDetectionOutput(source_ops, helper) - self._DealWithSSD(source_ops, helper) - self._Graph() - - - - def _Parsing(self): - with fluid.scope_guard(self.scope): - if os.path.exists(self.ModelPath + 'model') and os.path.exists(self.ModelPath + 'params'): - [self.net_program, feed_target_names, fetch_targets] = \ - fluid.io.load_inference_model(self.ModelPath, self.exe, 'model', 'params') - else: - [self.net_program, feed_target_names, fetch_targets] = \ - fluid.io.load_inference_model(self.ModelPath, self.exe) - - global_block = self.net_program.global_block() - source_ops = list(global_block.ops) - helper = Fluid_helper(self.scope, global_block) - - self._ParseNetwork(source_ops, helper) - return self.graphIO diff --git a/tools/external_converter_v2/parser/kill_tf/auto_debug.py b/tools/external_converter_v2/parser/kill_tf/auto_debug.py deleted file mode 100644 index ffa2c16a5..000000000 --- a/tools/external_converter_v2/parser/kill_tf/auto_debug.py +++ /dev/null @@ -1,124 +0,0 @@ -import tensorflow as tf -import numpy as np -import os -import tempfile -from parse_tf_2_med import ParseTF2Med -from med_graph import MedGraphUtil -from tf_trans_util import load_graph -from tf_util import TfUtil -class AutoDebug: - - def __init__(self,tf_model_path,ak_output_dir,workspace=None): - self.ak_perfix='record_' - self.tf_model_path=tf_model_path - self.ak_output_dir=os.path.dirname(ak_output_dir) - med_graph = ParseTF2Med(self.tf_model_path).parse() - MedGraphUtil.solve(med_graph) - self.med_graph = med_graph - # if workspace is None: - # self.workspace=tempfile.mkdtemp() - # else: - # self.workspace = workspace - # print('workspace is ', self.workspace) - - - def _debug_graph(self,graph): - for i in graph.values(): - print(i) - exit() - - def _convert_name_tf2ak(self,tf_name): - ak_name = tf_name[:] - for index, x in enumerate(tf_name): - if x == '/': - ak_name = ak_name[:index] + '_' + ak_name[index + 1:] - return self.ak_perfix + ak_name - - def _find_ak_output(self): - result = {} - for file_name in os.listdir(self.ak_output_dir): - real_path=os.path.join(self.ak_output_dir,file_name) - if not os.path.isdir(real_path) and file_name.startswith(self.ak_perfix) and not file_name.startswith(self.ak_perfix+'_'): - result[file_name]=[float(i.split(' ')[1]) for i in open(real_path,'r').readlines()] - return result - - def _creat_and_clear_workspace(self): - if os.path.exists(self.workspace): - assert os.path.isdir(self.workspace) - ls = os.listdir(self.workspace) - for i in ls: - c_path = os.path.join(self.workspace, i) - os.remove(c_path) - else: - os.mkdir(self.workspace) - - def _prepare_data(self,med_graph): - input_cnt=0 - inputs={} - result = {} - np.random.seed(1234567) - for i in med_graph.values(): - if i['ak_type'] == 'Input': - shape=i['output'][0]['shape'] - size=1 - for k in shape: - size*=k - tensor=np.random.randn(size).reshape(shape) - inputs['input_'+str(input_cnt)]=tensor - result[i['name']+':0']=tensor - input_cnt+=1 - - for i in inputs.keys(): - import struct - with open(os.path.join(self.ak_output_dir,i), "wb") as file: - x_value_new = inputs[i].transpose((0, 3, 1, 2)) - for value in x_value_new.flatten(): - file.write(struct.pack('f', value)) - - return result - - - def run_ak(self): - self._prepare_data(self.med_graph) - - def run(self): - inputs = self._prepare_data(self.med_graph) - akopname2ak_out=self._find_ak_output() - for i in akopname2ak_out: - print(i) - compare_dic={} - for node in self.med_graph.values(): - print(node['name'], node['ak_type']) - if node['ak_type'] is not None and node['type'] is not None: - - name=node['name'] - if node.get('fusion_out_name') is not None: - name=node['fusion_out_name'] - ak_name=self._convert_name_tf2ak(name) - print('key ',ak_name) - if akopname2ak_out.get(ak_name) is not None: - compare_dic[name+':0']=akopname2ak_out[ak_name] - outlist=compare_dic.keys() - out=TfUtil.tf_run_model(self.tf_model_path,inputs,outlist) - for index,name in enumerate(outlist): - correct=out[index].transpose() - ak_result=akopname2ak_out[name] - assert len() - for i in range(len(ak_result)): - if abs() - # tensor_shape = {} - # graph={} - # for node in tf_ops: - # for out in node.outputs: - # tensor_shape[out.name] = out.get_shape().as_list() - # input_names = [i.name for i in node.inputs] - # output_names = [i.name for i in node.outputs] - # graph[node.name]={'name':node.name,'input':input_names,'output':output_names} - # self._fix_self_output(graph,tensor_shape) - # self._debug_graph(graph) -ak_work_space='/home/ljj/docker_mount_dev2/anakin2_developing_parser/build/' - -debug=AutoDebug('./resnet_model/frozen_resnet_v1_50.pb',ak_work_space) -debug.run_ak() -debug.run() - diff --git a/tools/external_converter_v2/parser/kill_tf/freeze_graph.py b/tools/external_converter_v2/parser/kill_tf/freeze_graph.py deleted file mode 100644 index 73a430866..000000000 --- a/tools/external_converter_v2/parser/kill_tf/freeze_graph.py +++ /dev/null @@ -1,404 +0,0 @@ -# Copyright 2015 The TensorFlow Authors. 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. -# ============================================================================== -r"""Converts checkpoint variables into Const ops in a standalone GraphDef file. - -This script is designed to take a GraphDef proto, a SaverDef proto, and a set of -variable values stored in a checkpoint file, and output a GraphDef with all of -the variable ops converted into const ops containing the values of the -variables. - -It's useful to do this when we need to load a single file in C++, especially in -environments like mobile or embedded where we may not have access to the -RestoreTensor ops and file loading calls that they rely on. - -An example of command-line usage is: -bazel build tensorflow/python/tools:freeze_graph && \ -bazel-bin/tensorflow/python/tools/freeze_graph \ ---input_graph=some_graph_def.pb \ ---input_checkpoint=model.ckpt-8361242 \ ---output_graph=/tmp/frozen_graph.pb --output_node_names=softmax - -You can also look at freeze_graph_test.py for an example of how to use it. - -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import argparse -import re -import sys - -from google.protobuf import text_format - -from tensorflow.core.framework import graph_pb2 -from tensorflow.core.protobuf import saver_pb2 -from tensorflow.core.protobuf.meta_graph_pb2 import MetaGraphDef -from tensorflow.python import pywrap_tensorflow -from tensorflow.python.client import session -from tensorflow.python.framework import graph_util -from tensorflow.python.framework import importer -from tensorflow.python.platform import app -from tensorflow.python.platform import gfile -from tensorflow.python.saved_model import loader -from tensorflow.python.saved_model import tag_constants -from tensorflow.python.tools import saved_model_utils -from tensorflow.python.training import saver as saver_lib - - -def freeze_graph_with_def_protos(input_graph_def, - input_saver_def, - input_checkpoint, - output_node_names, - restore_op_name, - filename_tensor_name, - output_graph, - clear_devices, - initializer_nodes, - variable_names_whitelist="", - variable_names_blacklist="", - input_meta_graph_def=None, - input_saved_model_dir=None, - saved_model_tags=None, - checkpoint_version=saver_pb2.SaverDef.V2): - """Converts all variables in a graph and checkpoint into constants.""" - del restore_op_name, filename_tensor_name # Unused by updated loading code. - - if not output_node_names: - print("You need to supply the name of a node to --output_node_names.") - return -1 - - # Remove all the explicit device specifications for this node. This helps to - # make the graph more portable. - if clear_devices: - if input_meta_graph_def: - for node in input_meta_graph_def.graph_def.node: - node.device = "" - elif input_graph_def: - for node in input_graph_def.node: - node.device = "" - - if input_graph_def: - _ = importer.import_graph_def(input_graph_def, name="") - with session.Session() as sess: - if input_saver_def: - saver = saver_lib.Saver( - saver_def=input_saver_def, write_version=checkpoint_version) - saver.restore(sess, input_checkpoint) - elif input_meta_graph_def: - restorer = saver_lib.import_meta_graph( - input_meta_graph_def, clear_devices=True) - restorer.restore(sess, input_checkpoint) - if initializer_nodes: - sess.run(initializer_nodes.replace(" ", "").split(",")) - elif input_saved_model_dir: - if saved_model_tags is None: - saved_model_tags = [] - loader.load(sess, saved_model_tags, input_saved_model_dir) - else: - var_list = {} - reader = pywrap_tensorflow.NewCheckpointReader(input_checkpoint) - var_to_shape_map = reader.get_variable_to_shape_map() - - # List of all partition variables. Because the condition is heuristic - # based, the list could include false positives. - all_parition_variable_names = [ - tensor.name.split(":")[0] - for op in sess.graph.get_operations() - for tensor in op.values() - if re.search(r"/part_\d+/", tensor.name) - ] - has_partition_var = False - - for key in var_to_shape_map: - try: - tensor = sess.graph.get_tensor_by_name(key + ":0") - if any(key in name for name in all_parition_variable_names): - has_partition_var = True - except KeyError: - # This tensor doesn't exist in the graph (for example it's - # 'global_step' or a similar housekeeping element) so skip it. - continue - var_list[key] = tensor - - try: - saver = saver_lib.Saver( - var_list=var_list, write_version=checkpoint_version) - except TypeError as e: - # `var_list` is required to be a map of variable names to Variable - # tensors. Partition variables are Identity tensors that cannot be - # handled by Saver. - if has_partition_var: - print("Models containing partition variables cannot be converted " - "from checkpoint files. Please pass in a SavedModel using " - "the flag --input_saved_model_dir.") - return -1 - else: - raise e - - saver.restore(sess, input_checkpoint) - if initializer_nodes: - sess.run(initializer_nodes.replace(" ", "").split(",")) - - variable_names_whitelist = ( - variable_names_whitelist.replace(" ", "").split(",") - if variable_names_whitelist else None) - variable_names_blacklist = ( - variable_names_blacklist.replace(" ", "").split(",") - if variable_names_blacklist else None) - - if input_meta_graph_def: - output_graph_def = graph_util.convert_variables_to_constants( - sess, - input_meta_graph_def.graph_def, - output_node_names.replace(" ", "").split(","), - variable_names_whitelist=variable_names_whitelist, - variable_names_blacklist=variable_names_blacklist) - else: - output_graph_def = graph_util.convert_variables_to_constants( - sess, - input_graph_def, - output_node_names.replace(" ", "").split(","), - variable_names_whitelist=variable_names_whitelist, - variable_names_blacklist=variable_names_blacklist) - - # Write GraphDef to file if output path has been given. - if output_graph: - with gfile.GFile(output_graph, "wb") as f: - f.write(output_graph_def.SerializeToString()) - - return output_graph_def - - -def _parse_input_graph_proto(input_graph, input_binary): - """Parser input tensorflow graph into GraphDef proto.""" - if not gfile.Exists(input_graph): - print("Input graph file '" + input_graph + "' does not exist!") - return -1 - input_graph_def = graph_pb2.GraphDef() - mode = "rb" if input_binary else "r" - with gfile.FastGFile(input_graph, mode) as f: - if input_binary: - input_graph_def.ParseFromString(f.read()) - else: - text_format.Merge(f.read(), input_graph_def) - return input_graph_def - - -def _parse_input_meta_graph_proto(input_graph, input_binary): - """Parser input tensorflow graph into MetaGraphDef proto.""" - if not gfile.Exists(input_graph): - print("Input meta graph file '" + input_graph + "' does not exist!") - return -1 - input_meta_graph_def = MetaGraphDef() - mode = "rb" if input_binary else "r" - with gfile.FastGFile(input_graph, mode) as f: - if input_binary: - input_meta_graph_def.ParseFromString(f.read()) - else: - text_format.Merge(f.read(), input_meta_graph_def) - print("Loaded meta graph file '" + input_graph) - return input_meta_graph_def - - -def _parse_input_saver_proto(input_saver, input_binary): - """Parser input tensorflow Saver into SaverDef proto.""" - if not gfile.Exists(input_saver): - print("Input saver file '" + input_saver + "' does not exist!") - return -1 - mode = "rb" if input_binary else "r" - with gfile.FastGFile(input_saver, mode) as f: - saver_def = saver_pb2.SaverDef() - if input_binary: - saver_def.ParseFromString(f.read()) - else: - text_format.Merge(f.read(), saver_def) - return saver_def - - -def freeze_graph(input_graph, - input_saver, - input_binary, - input_checkpoint, - output_node_names, - restore_op_name, - filename_tensor_name, - output_graph, - clear_devices, - initializer_nodes, - variable_names_whitelist="", - variable_names_blacklist="", - input_meta_graph=None, - input_saved_model_dir=None, - saved_model_tags=tag_constants.SERVING, - checkpoint_version=saver_pb2.SaverDef.V2): - """Converts all variables in a graph and checkpoint into constants.""" - input_graph_def = None - if input_saved_model_dir: - input_graph_def = saved_model_utils.get_meta_graph_def( - input_saved_model_dir, saved_model_tags).graph_def - elif input_graph: - input_graph_def = _parse_input_graph_proto(input_graph, input_binary) - input_meta_graph_def = None - if input_meta_graph: - input_meta_graph_def = _parse_input_meta_graph_proto( - input_meta_graph, input_binary) - input_saver_def = None - if input_saver: - input_saver_def = _parse_input_saver_proto(input_saver, input_binary) - freeze_graph_with_def_protos( - input_graph_def, - input_saver_def, - input_checkpoint, - output_node_names, - restore_op_name, - filename_tensor_name, - output_graph, - clear_devices, - initializer_nodes, - variable_names_whitelist, - variable_names_blacklist, - input_meta_graph_def, - input_saved_model_dir, - saved_model_tags.replace(" ", "").split(","), - checkpoint_version=checkpoint_version) - - -def main(unused_args, flags): - if flags.checkpoint_version == 1: - checkpoint_version = saver_pb2.SaverDef.V1 - elif flags.checkpoint_version == 2: - checkpoint_version = saver_pb2.SaverDef.V2 - else: - print("Invalid checkpoint version (must be '1' or '2'): %d" % - flags.checkpoint_version) - return -1 - freeze_graph(flags.input_graph, flags.input_saver, flags.input_binary, - flags.input_checkpoint, flags.output_node_names, - flags.restore_op_name, flags.filename_tensor_name, - flags.output_graph, flags.clear_devices, flags.initializer_nodes, - flags.variable_names_whitelist, flags.variable_names_blacklist, - flags.input_meta_graph, flags.input_saved_model_dir, - flags.saved_model_tags, checkpoint_version) - -def run_main(): - parser = argparse.ArgumentParser() - parser.register("type", "bool", lambda v: v.lower() == "true") - parser.add_argument( - "--input_graph", - type=str, - default="", - help="TensorFlow \'GraphDef\' file to load.") - parser.add_argument( - "--input_saver", - type=str, - default="", - help="TensorFlow saver file to load.") - parser.add_argument( - "--input_checkpoint", - type=str, - default="", - help="TensorFlow variables file to load.") - parser.add_argument( - "--checkpoint_version", - type=int, - default=2, - help="Tensorflow variable file format") - parser.add_argument( - "--output_graph", - type=str, - default="", - help="Output \'GraphDef\' file name.") - parser.add_argument( - "--input_binary", - nargs="?", - const=True, - type="bool", - default=False, - help="Whether the input files are in binary format.") - parser.add_argument( - "--output_node_names", - type=str, - default="", - help="The name of the output nodes, comma separated.") - parser.add_argument( - "--restore_op_name", - type=str, - default="save/restore_all", - help="""\ - The name of the master restore operator. Deprecated, unused by updated \ - loading code. - """) - parser.add_argument( - "--filename_tensor_name", - type=str, - default="save/Const:0", - help="""\ - The name of the tensor holding the save path. Deprecated, unused by \ - updated loading code. - """) - parser.add_argument( - "--clear_devices", - nargs="?", - const=True, - type="bool", - default=True, - help="Whether to remove device specifications.") - parser.add_argument( - "--initializer_nodes", - type=str, - default="", - help="Comma separated list of initializer nodes to run before freezing.") - parser.add_argument( - "--variable_names_whitelist", - type=str, - default="", - help="""\ - Comma separated list of variables to convert to constants. If specified, \ - only those variables will be converted to constants.\ - """) - parser.add_argument( - "--variable_names_blacklist", - type=str, - default="", - help="""\ - Comma separated list of variables to skip converting to constants.\ - """) - parser.add_argument( - "--input_meta_graph", - type=str, - default="", - help="TensorFlow \'MetaGraphDef\' file to load.") - parser.add_argument( - "--input_saved_model_dir", - type=str, - default="", - help="Path to the dir with TensorFlow \'SavedModel\' file and variables.") - parser.add_argument( - "--saved_model_tags", - type=str, - default="serve", - help="""\ - Group of tag(s) of the MetaGraphDef to load, in string format,\ - separated by \',\'. For tag-set contains multiple tags, all tags \ - must be passed in.\ - """) - flags, unparsed = parser.parse_known_args() - - my_main = lambda unused_args: main(unused_args, flags) - app.run(main=my_main, argv=[sys.argv[0]] + unparsed) - -if __name__ == '__main__': - run_main() diff --git a/tools/external_converter_v2/parser/kill_tf/parser_tf.py b/tools/external_converter_v2/parser/kill_tf/parser_tf.py deleted file mode 100644 index a62684340..000000000 --- a/tools/external_converter_v2/parser/kill_tf/parser_tf.py +++ /dev/null @@ -1,57 +0,0 @@ -import numpy as np -import os -from ..graph_io import * -from ..logger import * -from ..proto import * -import tensorflow as tf -from parse_tf_2_med import ParseTF2Med -from parse_med_2_ak import MedTransAK -from med_graph import MedGraphUtil,MedNodeUtil - - -class TFParser: - - def __init__(self, fluid_config_dict): - # anakin graph model io - # config info - self.ProtoPaths = fluid_config_dict['ProtoPaths'] - - self.OutPuts = fluid_config_dict['OutPuts'] - if self.OutPuts is not None: - self.OutPuts=[i for i in fluid_config_dict['OutPuts'].split(',')] - - self.med_trans_tool = MedTransAK() - self.input_count=0 - - def __call__(self): - med_graph = self._conver_tf_2_med() - if self.OutPuts is None: - self.OutPuts=MedGraphUtil.search_output_list(med_graph) - - MedGraphUtil.solve(med_graph) - anakin_graph = self._conver_med_2_anakin(med_graph) - return anakin_graph - - def _conver_tf_2_med(self): - parser = ParseTF2Med(self.ProtoPaths) - return parser.parse() - - def _add_protonode(self, ak_graph,med_node): - ak_type = med_node['ak_type'] - if ak_type is None: - return - nodeIO = NodeProtoIO() - nodeIO.set_name(med_node['name']) - self.med_trans_tool.map_med_2_ak(nodeIO,med_node) - ak_graph.add_node(nodeIO()) - if nodeIO().Op.name=='Input': - ak_graph.add_in(nodeIO().name) - - def _conver_med_2_anakin(self, med_graph): - anakin_graph = GraphProtoIO() - for node in med_graph.values(): - self._add_protonode(anakin_graph,node) - anakin_graph.format_edge_from_nodes() - for out_node_name in self.OutPuts: - anakin_graph.add_out('output_'+out_node_name,out_node_name) - return anakin_graph diff --git a/tools/external_converter_v2/parser/kill_tf/run_pb.py b/tools/external_converter_v2/parser/kill_tf/run_pb.py deleted file mode 100644 index 2b6d3a254..000000000 --- a/tools/external_converter_v2/parser/kill_tf/run_pb.py +++ /dev/null @@ -1,74 +0,0 @@ -import numpy as np -from tf_util import TfUtil - -def convert_name_tf2ak(tf_name,perfix='record_'): - ak_name=tf_name[:] - for index,x in enumerate(tf_name): - if x=='/': - ak_name=ak_name[:index]+'_'+ak_name[index+1:] - return perfix+ak_name -ak_work_space='/home/ljj/docker_mount_dev2/anakin2_developing_parser/build/' -# ak_work_space='/your/anakin/workspace' -output_compare_op=None - - -# graph_path='./vgg_model/frozen_vgg_16_i.pb' -# input_name='graph/input:0' -# output_op='graph/vgg_16/fc8/BiasAdd' -# output_compare_op='graph/vgg_16/fc8/convolution' - -graph_path='./resnet_model/frozen_resnet_v1_50.pb' -input_name='graph/input:0' -output_op='graph/resnet_v1_50/predictions/Reshape_1' - -# graph_path='./mobilnetv2/frozen_mobilnet_v2.pb' -# input_name='graph/input:0' -# output_op='graph/MobilenetV2/Predictions/Reshape_1' - -# graph_path='./inception_model/frozen_inception_v2.pb' -# input_name='graph/input:0' -# output_op='graph/InceptionV2/Predictions/Reshape_1' - - -is_compared=True -output_name=output_op+':0' -if output_compare_op is None: - compare_path=ak_work_space+convert_name_tf2ak(output_op) -else: - compare_path=ak_work_space+convert_name_tf2ak(output_compare_op) - -np.random.seed(1234567) -x_location=ak_work_space+'input_x' -x_value=np.random.randn(1,224,224,3) -outs=TfUtil.tf_run_model(graph_path,{input_name:x_value},[output_name]) - -import struct -with open(x_location, "wb") as file: - x_value_new=x_value.transpose((0,3,1,2)) - for value in x_value_new.flatten(): - file.write(struct.pack('f', value)) - -if is_compared: - out=outs[0] - if len(out.shape)==4: - out=out.transpose((0,3,1,2)) - else: - print('out shape :',out.shape) - print(out.flatten()[:10]) - try: - with open(compare_path,'r')as file: - ans=[] - for value_str in file.readlines(): - ans.append(float(value_str.split(' ')[1])) - correct=out.flatten() - assert len(correct)==len(ans) - for i in range(len(ans)): - if abs(ans[i]-correct[i])>0.0001 and abs(ans[i]-correct[i])/abs(correct[i])>0.0001: - print(i,'=',ans[i],'correct = ',correct[i]) - exit() - print('passed') - except Exception,e: - print(out) - print('can`t find file : '+compare_path) - - diff --git a/tools/external_converter_v2/parser/operations/op_io.py b/tools/external_converter_v2/parser/operations/op_io.py index 11539f38e..d7c647bb1 100644 --- a/tools/external_converter_v2/parser/operations/op_io.py +++ b/tools/external_converter_v2/parser/operations/op_io.py @@ -41,7 +41,8 @@ def __call__(self): use_soft_nms=list(), nms_among_classes=bool(), voting=list(), - vote_iou=list()) + vote_iou=list(), + nms_gpu_max_n_per_time=int()) # BBoxRegParameter bbox_reg_param = Dictionary().set_attr(bbox_mean=list(), @@ -189,11 +190,14 @@ def __call__(self): cords_offset_y=float(), bbox_size_add_one=bool(), rotate_coords_by_pitch=bool(), - refine_coords_by_bbox=bool(), - refine_min_dist=float(), - refine_dist_for_height_ratio_one=float(), - max_3d2d_height_ratio_for_min_dist=float(), - with_trunc_ratio=bool()) + #refine_coords_by_bbox=bool(), + #refine_min_dist=float(), + #refine_dist_for_height_ratio_one=float(), + #max_3d2d_height_ratio_for_min_dist=float(), + with_trunc_ratio=bool(), + regress_ph_rh_as_whole=bool(), + real_h_means_as_whole=list(), + real_h_stds_as_whole=list()) # RPNProposalSSD parameter RPNProposalSSD_param = Dictionary().set_attr(detection_output_ssd=detection_output_ssd_param(), bbox_reg=bbox_reg_param()) diff --git a/tools/external_converter_v2/parser/operations/ops.py b/tools/external_converter_v2/parser/operations/ops.py index 854b744e0..118d33909 100755 --- a/tools/external_converter_v2/parser/operations/ops.py +++ b/tools/external_converter_v2/parser/operations/ops.py @@ -355,6 +355,8 @@ begin_norm_axis=int(), eps=float()) +OpsRegister.Register("Resize").set_attr(height_scale=float(), + width_scale=float()) OpsRegister.Register("Normalize").set_attr(begin_norm_axis=int(), is_across_spatial=bool(), @@ -367,4 +369,24 @@ pad_w=list()) -OpsRegister.Register("ShuffleChannel").set_attr(group=int()) \ No newline at end of file +OpsRegister.Register("ShuffleChannel").set_attr(group=int()) + +OpsRegister.Register("RoisAnchorFeature").set_attr(min_anchor_size=float(), + num_anchor_scales=int(), + anchor_scale_pow_base=float(), + anchor_wph_ratios=list(), + num_top_iou_anchor=int(), + min_num_top_iou_anchor=int(), + iou_thr=float(), + ft_ratio_h=bool(), + ft_ratio_w=bool(), + ft_log_ratio_h=bool(), + ft_log_ratio_w=bool(), + bbox_size_add_one=bool()) + +OpsRegister.Register("Interp").set_attr(height=int(), + width=int(), + zoom_factor=int(), + shrink_factor=int(), + pad_beg=int(), + pad_end=int()) diff --git a/tools/external_converter_v2/parser/operations/ops_fluid.py b/tools/external_converter_v2/parser/operations/ops_fluid.py index a802e287c..9025a1dd9 100755 --- a/tools/external_converter_v2/parser/operations/ops_fluid.py +++ b/tools/external_converter_v2/parser/operations/ops_fluid.py @@ -27,8 +27,22 @@ OpsRegister.Register("sequence_conv").set_attr() OpsRegister.Register("stanh").set_attr() - OpsRegister.Register("matmul").set_attr() OpsRegister.Register("layer_norm").set_attr() OpsRegister.Register("dropout").set_attr() OpsRegister.Register("scale").set_attr() +OpsRegister.Register("norm").set_attr() + +OpsRegister.Register("lod_reset").set_attr() +OpsRegister.Register("fill_constant").set_attr() +OpsRegister.Register("lod_rank_table").set_attr() +OpsRegister.Register("max_sequence_len").set_attr() +OpsRegister.Register("less_than").set_attr() +OpsRegister.Register("lod_tensor_to_array").set_attr() +OpsRegister.Register("write_to_array").set_attr() +OpsRegister.Register("reorder_lod_tensor_by_rank").set_attr() +OpsRegister.Register("while").set_attr() +OpsRegister.Register("array_to_lod_tensor").set_attr() + +OpsRegister.Register("assign_value").set_attr() +OpsRegister.Register("shape").set_attr() diff --git a/tools/external_converter_v2/parser/pbs/__init__.py b/tools/external_converter_v2/parser/pbs/__init__.py index 40e5a387c..9e1c738fc 100644 --- a/tools/external_converter_v2/parser/pbs/__init__.py +++ b/tools/external_converter_v2/parser/pbs/__init__.py @@ -1,9 +1,21 @@ #! /usr/bin/env python # Copyright (c) 2017, Cuichaowen. All rights reserved. # -*- coding: utf-8 -*- +import os +from ..logger import verbose +from ..logger import shellcolors +from ..logger import with_color +from ..logger import logger -try: - from caffe_pb2 import * -except ImportError: - raise ImportError(' No module named caffe_pb2 . ') - +for module in os.listdir(os.path.dirname(__file__)): + if module == '__init__.py' or module[-3:] != '.py': + continue + m = __import__(module[:-3], locals(), globals()) + try: + attrlist = m.__all__ + except AttributeError: + attrlist = dir(m) + for attr in attrlist: + globals()[attr] = getattr(m, attr) + logger(verbose.INFO).feed("Import Module: ", module[:-3]) +del module diff --git a/tools/external_converter_v2/parser/kill_tf/__init__.py b/tools/external_converter_v2/parser/tensorflow/__init__.py similarity index 100% rename from tools/external_converter_v2/parser/kill_tf/__init__.py rename to tools/external_converter_v2/parser/tensorflow/__init__.py diff --git a/tools/external_converter_v2/parser/tensorflow/auto_debug.py b/tools/external_converter_v2/parser/tensorflow/auto_debug.py new file mode 100644 index 000000000..3865666a4 --- /dev/null +++ b/tools/external_converter_v2/parser/tensorflow/auto_debug.py @@ -0,0 +1,158 @@ +import tensorflow as tf +import numpy as np +import os +import tempfile +from parse_tf_2_med import ParseTF2Med +from med_graph import MedGraphUtil +from tf_trans_util import load_graph +from tf_util import TfUtil + + +class AutoDebug: + + def __init__(self, tf_model_path, ak_output_dir, workspace=None): + self.ak_perfix = 'record_' + self.tf_model_path = tf_model_path + self.ak_output_dir = os.path.dirname(ak_output_dir) + med_graph = ParseTF2Med(self.tf_model_path).parse() + MedGraphUtil.solve(med_graph) + self.med_graph = med_graph + # if workspace is None: + # self.workspace=tempfile.mkdtemp() + # else: + # self.workspace = workspace + # print('workspace is ', self.workspace) + + def _debug_graph(self, graph): + ''' + print debug info + :param graph: + :return: + ''' + for i in graph.values(): + print(i) + exit() + + def _convert_name_tf2ak(self, tf_name): + ''' + conver name from tf 2 ak + :param tf_name: + :return: + ''' + ak_name = tf_name[:] + for index, x in enumerate(tf_name): + if x == '/': + ak_name = ak_name[:index] + '_' + ak_name[index + 1:] + return self.ak_perfix + ak_name + + def _find_ak_output(self): + ''' + find output name in graph + :return: + ''' + result = {} + for file_name in os.listdir(self.ak_output_dir): + real_path = os.path.join(self.ak_output_dir, file_name) + if not os.path.isdir(real_path) and file_name.startswith(self.ak_perfix) and not file_name.startswith( + self.ak_perfix + '_'): + result[file_name] = [float(i.split(' ')[1]) for i in open(real_path, 'r').readlines()] + return result + + def _creat_and_clear_workspace(self): + ''' + remove temp workspace + :return: + ''' + if os.path.exists(self.workspace): + assert os.path.isdir(self.workspace) + ls = os.listdir(self.workspace) + for i in ls: + c_path = os.path.join(self.workspace, i) + os.remove(c_path) + else: + os.mkdir(self.workspace) + + def _prepare_data(self, med_graph): + ''' + gen input data + :param med_graph: + :return: + ''' + input_cnt = 0 + inputs = {} + result = {} + np.random.seed(1234567) + for i in med_graph.values(): + if i['ak_type'] == 'Input': + shape = i['output'][0]['shape'] + size = 1 + for k in shape: + size *= k + tensor = np.random.randn(size).reshape(shape) + inputs['input_' + str(input_cnt)] = tensor + result[i['name'] + ':0'] = tensor + input_cnt += 1 + + for i in inputs.keys(): + import struct + with open(os.path.join(self.ak_output_dir, i), "wb") as file: + x_value_new = inputs[i].transpose((0, 3, 1, 2)) + for value in x_value_new.flatten(): + file.write(struct.pack('f', value)) + + return result + + def run_ak(self): + ''' + run ak mode + :return: + ''' + self._prepare_data(self.med_graph) + + def run(self): + ''' + run debug mode + :return: + ''' + pass + # inputs = self._prepare_data(self.med_graph) + # akopname2ak_out=self._find_ak_output() + # for i in akopname2ak_out: + # print(i) + # compare_dic={} + # for node in self.med_graph.values(): + # print(node['name'], node['ak_type']) + # if node['ak_type'] is not None and node['type'] is not None: + # + # name=node['name'] + # if node.get('fusion_out_name') is not None: + # name=node['fusion_out_name'] + # ak_name=self._convert_name_tf2ak(name) + # print('key ',ak_name) + # if akopname2ak_out.get(ak_name) is not None: + # compare_dic[name+':0']=akopname2ak_out[ak_name] + # outlist=compare_dic.keys() + # out=TfUtil.tf_run_model(self.tf_model_path,inputs,outlist) + # for index,name in enumerate(outlist): + # correct=out[index].transpose() + # ak_result=akopname2ak_out[name] + # assert len() + # for i in range(len(ak_result)): + # if abs() + # tensor_shape = {} + # graph={} + # for node in tf_ops: + # for out in node.outputs: + # tensor_shape[out.name] = out.get_shape().as_list() + # input_names = [i.name for i in node.inputs] + # output_names = [i.name for i in node.outputs] + # graph[node.name]={'name':node.name,'input':input_names,'output':output_names} + # self._fix_self_output(graph,tensor_shape) + # self._debug_graph(graph) + + +ak_work_space = '' + +debug = AutoDebug('./resnet_model/frozen_resnet_v1_50.pb', ak_work_space) +debug.run_ak() +debug.run() diff --git a/tools/external_converter_v2/parser/kill_tf/freeze.py b/tools/external_converter_v2/parser/tensorflow/freeze.py similarity index 94% rename from tools/external_converter_v2/parser/kill_tf/freeze.py rename to tools/external_converter_v2/parser/tensorflow/freeze.py index bc5b77631..c45ccba51 100644 --- a/tools/external_converter_v2/parser/kill_tf/freeze.py +++ b/tools/external_converter_v2/parser/tensorflow/freeze.py @@ -6,7 +6,13 @@ dir = os.path.dirname(os.path.realpath(__file__)) -def freeze_graph(model_folder,output_name): +def freeze_graph(model_folder, output_name): + ''' + freeze graph from meta input + :param model_folder: + :param output_name: + :return: + ''' # We retrieve our checkpoint fullpath checkpoint = tf.train.get_checkpoint_state(model_folder) input_checkpoint = checkpoint.model_checkpoint_path @@ -59,4 +65,3 @@ def freeze_graph(model_folder,output_name): # freeze_graph('/tmp/pycharm_project_635/tensorflow/RNN/model/language_model_tf','Softmax') freeze_graph('./ease_model/', 'add_2') - diff --git a/tools/external_converter_v2/parser/tensorflow/freeze_graph.py b/tools/external_converter_v2/parser/tensorflow/freeze_graph.py new file mode 100644 index 000000000..d6e369f4d --- /dev/null +++ b/tools/external_converter_v2/parser/tensorflow/freeze_graph.py @@ -0,0 +1,416 @@ +# Copyright 2015 The TensorFlow Authors. 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. +# ============================================================================== +r"""Converts checkpoint variables into Const ops in a standalone GraphDef file. + +This script is designed to take a GraphDef proto, a SaverDef proto, and a set of +variable values stored in a checkpoint file, and output a GraphDef with all of +the variable ops converted into const ops containing the values of the +variables. + +It's useful to do this when we need to load a single file in C++, especially in +environments like mobile or embedded where we may not have access to the +RestoreTensor ops and file loading calls that they rely on. + +An example of command-line usage is: +bazel build tensorflow/python/tools:freeze_graph && \ +bazel-bin/tensorflow/python/tools/freeze_graph \ +--input_graph=some_graph_def.pb \ +--input_checkpoint=model.ckpt-8361242 \ +--output_graph=/tmp/frozen_graph.pb --output_node_names=softmax + +You can also look at freeze_graph_test.py for an example of how to use it. + +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import argparse +import re +import sys + +from google.protobuf import text_format + +from tensorflow.core.framework import graph_pb2 +from tensorflow.core.protobuf import saver_pb2 +from tensorflow.core.protobuf.meta_graph_pb2 import MetaGraphDef +from tensorflow.python import pywrap_tensorflow +from tensorflow.python.client import session +from tensorflow.python.framework import graph_util +from tensorflow.python.framework import importer +from tensorflow.python.platform import app +from tensorflow.python.platform import gfile +from tensorflow.python.saved_model import loader +from tensorflow.python.saved_model import tag_constants +from tensorflow.python.tools import saved_model_utils +from tensorflow.python.training import saver as saver_lib + + +def freeze_graph_with_def_protos(input_graph_def, + input_saver_def, + input_checkpoint, + output_node_names, + restore_op_name, + filename_tensor_name, + output_graph, + clear_devices, + initializer_nodes, + variable_names_whitelist="", + variable_names_blacklist="", + input_meta_graph_def=None, + input_saved_model_dir=None, + saved_model_tags=None, + checkpoint_version=saver_pb2.SaverDef.V2): + """Converts all variables in a graph and checkpoint into constants.""" + del restore_op_name, filename_tensor_name # Unused by updated loading code. + + if not output_node_names: + print("You need to supply the name of a node to --output_node_names.") + return -1 + + # Remove all the explicit device specifications for this node. This helps to + # make the graph more portable. + if clear_devices: + if input_meta_graph_def: + for node in input_meta_graph_def.graph_def.node: + node.device = "" + elif input_graph_def: + for node in input_graph_def.node: + node.device = "" + + if input_graph_def: + _ = importer.import_graph_def(input_graph_def, name="") + with session.Session() as sess: + if input_saver_def: + saver = saver_lib.Saver( + saver_def=input_saver_def, write_version=checkpoint_version) + saver.restore(sess, input_checkpoint) + elif input_meta_graph_def: + restorer = saver_lib.import_meta_graph( + input_meta_graph_def, clear_devices=True) + restorer.restore(sess, input_checkpoint) + if initializer_nodes: + sess.run(initializer_nodes.replace(" ", "").split(",")) + elif input_saved_model_dir: + if saved_model_tags is None: + saved_model_tags = [] + loader.load(sess, saved_model_tags, input_saved_model_dir) + else: + var_list = {} + reader = pywrap_tensorflow.NewCheckpointReader(input_checkpoint) + var_to_shape_map = reader.get_variable_to_shape_map() + + # List of all partition variables. Because the condition is heuristic + # based, the list could include false positives. + all_parition_variable_names = [ + tensor.name.split(":")[0] + for op in sess.graph.get_operations() + for tensor in op.values() + if re.search(r"/part_\d+/", tensor.name) + ] + has_partition_var = False + + for key in var_to_shape_map: + try: + tensor = sess.graph.get_tensor_by_name(key + ":0") + if any(key in name for name in all_parition_variable_names): + has_partition_var = True + except KeyError: + # This tensor doesn't exist in the graph (for example it's + # 'global_step' or a similar housekeeping element) so skip it. + continue + var_list[key] = tensor + + try: + saver = saver_lib.Saver( + var_list=var_list, write_version=checkpoint_version) + except TypeError as e: + # `var_list` is required to be a map of variable names to Variable + # tensors. Partition variables are Identity tensors that cannot be + # handled by Saver. + if has_partition_var: + print("Models containing partition variables cannot be converted " + "from checkpoint files. Please pass in a SavedModel using " + "the flag --input_saved_model_dir.") + return -1 + else: + raise e + + saver.restore(sess, input_checkpoint) + if initializer_nodes: + sess.run(initializer_nodes.replace(" ", "").split(",")) + + variable_names_whitelist = ( + variable_names_whitelist.replace(" ", "").split(",") + if variable_names_whitelist else None) + variable_names_blacklist = ( + variable_names_blacklist.replace(" ", "").split(",") + if variable_names_blacklist else None) + + if input_meta_graph_def: + output_graph_def = graph_util.convert_variables_to_constants( + sess, + input_meta_graph_def.graph_def, + output_node_names.replace(" ", "").split(","), + variable_names_whitelist=variable_names_whitelist, + variable_names_blacklist=variable_names_blacklist) + else: + output_graph_def = graph_util.convert_variables_to_constants( + sess, + input_graph_def, + output_node_names.replace(" ", "").split(","), + variable_names_whitelist=variable_names_whitelist, + variable_names_blacklist=variable_names_blacklist) + + # Write GraphDef to file if output path has been given. + if output_graph: + with gfile.GFile(output_graph, "wb") as f: + f.write(output_graph_def.SerializeToString()) + + return output_graph_def + + +def _parse_input_graph_proto(input_graph, input_binary): + """Parser input tensorflow graph into GraphDef proto.""" + if not gfile.Exists(input_graph): + print("Input graph file '" + input_graph + "' does not exist!") + return -1 + input_graph_def = graph_pb2.GraphDef() + mode = "rb" if input_binary else "r" + with gfile.FastGFile(input_graph, mode) as f: + if input_binary: + input_graph_def.ParseFromString(f.read()) + else: + text_format.Merge(f.read(), input_graph_def) + return input_graph_def + + +def _parse_input_meta_graph_proto(input_graph, input_binary): + """Parser input tensorflow graph into MetaGraphDef proto.""" + if not gfile.Exists(input_graph): + print("Input meta graph file '" + input_graph + "' does not exist!") + return -1 + input_meta_graph_def = MetaGraphDef() + mode = "rb" if input_binary else "r" + with gfile.FastGFile(input_graph, mode) as f: + if input_binary: + input_meta_graph_def.ParseFromString(f.read()) + else: + text_format.Merge(f.read(), input_meta_graph_def) + print("Loaded meta graph file '" + input_graph) + return input_meta_graph_def + + +def _parse_input_saver_proto(input_saver, input_binary): + """Parser input tensorflow Saver into SaverDef proto.""" + if not gfile.Exists(input_saver): + print("Input saver file '" + input_saver + "' does not exist!") + return -1 + mode = "rb" if input_binary else "r" + with gfile.FastGFile(input_saver, mode) as f: + saver_def = saver_pb2.SaverDef() + if input_binary: + saver_def.ParseFromString(f.read()) + else: + text_format.Merge(f.read(), saver_def) + return saver_def + + +def freeze_graph(input_graph, + input_saver, + input_binary, + input_checkpoint, + output_node_names, + restore_op_name, + filename_tensor_name, + output_graph, + clear_devices, + initializer_nodes, + variable_names_whitelist="", + variable_names_blacklist="", + input_meta_graph=None, + input_saved_model_dir=None, + saved_model_tags=tag_constants.SERVING, + checkpoint_version=saver_pb2.SaverDef.V2): + """Converts all variables in a graph and checkpoint into constants.""" + input_graph_def = None + if input_saved_model_dir: + input_graph_def = saved_model_utils.get_meta_graph_def( + input_saved_model_dir, saved_model_tags).graph_def + elif input_graph: + input_graph_def = _parse_input_graph_proto(input_graph, input_binary) + input_meta_graph_def = None + if input_meta_graph: + input_meta_graph_def = _parse_input_meta_graph_proto( + input_meta_graph, input_binary) + input_saver_def = None + if input_saver: + input_saver_def = _parse_input_saver_proto(input_saver, input_binary) + freeze_graph_with_def_protos( + input_graph_def, + input_saver_def, + input_checkpoint, + output_node_names, + restore_op_name, + filename_tensor_name, + output_graph, + clear_devices, + initializer_nodes, + variable_names_whitelist, + variable_names_blacklist, + input_meta_graph_def, + input_saved_model_dir, + saved_model_tags.replace(" ", "").split(","), + checkpoint_version=checkpoint_version) + + +def main(unused_args, flags): + ''' + main function + :param unused_args: + :param flags: + :return: + ''' + if flags.checkpoint_version == 1: + checkpoint_version = saver_pb2.SaverDef.V1 + elif flags.checkpoint_version == 2: + checkpoint_version = saver_pb2.SaverDef.V2 + else: + print("Invalid checkpoint version (must be '1' or '2'): %d" % + flags.checkpoint_version) + return -1 + freeze_graph(flags.input_graph, flags.input_saver, flags.input_binary, + flags.input_checkpoint, flags.output_node_names, + flags.restore_op_name, flags.filename_tensor_name, + flags.output_graph, flags.clear_devices, flags.initializer_nodes, + flags.variable_names_whitelist, flags.variable_names_blacklist, + flags.input_meta_graph, flags.input_saved_model_dir, + flags.saved_model_tags, checkpoint_version) + + +def run_main(): + ''' + excution entry + :return: + ''' + parser = argparse.ArgumentParser() + parser.register("type", "bool", lambda v: v.lower() == "true") + parser.add_argument( + "--input_graph", + type=str, + default="", + help="TensorFlow \'GraphDef\' file to load.") + parser.add_argument( + "--input_saver", + type=str, + default="", + help="TensorFlow saver file to load.") + parser.add_argument( + "--input_checkpoint", + type=str, + default="", + help="TensorFlow variables file to load.") + parser.add_argument( + "--checkpoint_version", + type=int, + default=2, + help="Tensorflow variable file format") + parser.add_argument( + "--output_graph", + type=str, + default="", + help="Output \'GraphDef\' file name.") + parser.add_argument( + "--input_binary", + nargs="?", + const=True, + type="bool", + default=False, + help="Whether the input files are in binary format.") + parser.add_argument( + "--output_node_names", + type=str, + default="", + help="The name of the output nodes, comma separated.") + parser.add_argument( + "--restore_op_name", + type=str, + default="save/restore_all", + help="""\ + The name of the master restore operator. Deprecated, unused by updated \ + loading code. + """) + parser.add_argument( + "--filename_tensor_name", + type=str, + default="save/Const:0", + help="""\ + The name of the tensor holding the save path. Deprecated, unused by \ + updated loading code. + """) + parser.add_argument( + "--clear_devices", + nargs="?", + const=True, + type="bool", + default=True, + help="Whether to remove device specifications.") + parser.add_argument( + "--initializer_nodes", + type=str, + default="", + help="Comma separated list of initializer nodes to run before freezing.") + parser.add_argument( + "--variable_names_whitelist", + type=str, + default="", + help="""\ + Comma separated list of variables to convert to constants. If specified, \ + only those variables will be converted to constants.\ + """) + parser.add_argument( + "--variable_names_blacklist", + type=str, + default="", + help="""\ + Comma separated list of variables to skip converting to constants.\ + """) + parser.add_argument( + "--input_meta_graph", + type=str, + default="", + help="TensorFlow \'MetaGraphDef\' file to load.") + parser.add_argument( + "--input_saved_model_dir", + type=str, + default="", + help="Path to the dir with TensorFlow \'SavedModel\' file and variables.") + parser.add_argument( + "--saved_model_tags", + type=str, + default="serve", + help="""\ + Group of tag(s) of the MetaGraphDef to load, in string format,\ + separated by \',\'. For tag-set contains multiple tags, all tags \ + must be passed in.\ + """) + flags, unparsed = parser.parse_known_args() + + my_main = lambda unused_args: main(unused_args, flags) + app.run(main=my_main, argv=[sys.argv[0]] + unparsed) + + +if __name__ == '__main__': + run_main() diff --git a/tools/external_converter_v2/parser/kill_tf/get_empt_infer_pb.py b/tools/external_converter_v2/parser/tensorflow/get_empt_infer_pb.py similarity index 76% rename from tools/external_converter_v2/parser/kill_tf/get_empt_infer_pb.py rename to tools/external_converter_v2/parser/tensorflow/get_empt_infer_pb.py index 16b9b0f06..11be45be9 100644 --- a/tools/external_converter_v2/parser/kill_tf/get_empt_infer_pb.py +++ b/tools/external_converter_v2/parser/tensorflow/get_empt_infer_pb.py @@ -4,11 +4,11 @@ from tensorflow.python.platform import gfile from google.protobuf import text_format -graph_path='./inception_model/inception_v2_inf_graph.pb' -output_node_names='InceptionV2/Predictions/Reshape_1' -output_graph='./inception_model/inception_v2_inf_graph_empty.pb' +graph_path = './inception_model/inception_v2_inf_graph.pb' +output_node_names = 'InceptionV2/Predictions/Reshape_1' +output_graph = './inception_model/inception_v2_inf_graph_empty.pb' -sess=tf.Session() +sess = tf.Session() if graph_path.endswith('.pbtxt'): input_binary = False else: @@ -29,11 +29,11 @@ tf.import_graph_def(graph_def, name='graph') output_graph_def = graph_util.convert_variables_to_constants( - sess, - graph_def, - output_node_names.split(",") # We split on comma for convenience - ) + sess, + graph_def, + output_node_names.split(",") # We split on comma for convenience +) # Finally we serialize and dump the output graph to the filesystem with tf.gfile.GFile(output_graph, "wb") as f: f.write(output_graph_def.SerializeToString()) -print("%d ops in the final graph." % len(output_graph_def.node)) \ No newline at end of file +print("%d ops in the final graph." % len(output_graph_def.node)) diff --git a/tools/external_converter_v2/parser/kill_tf/med_graph.py b/tools/external_converter_v2/parser/tensorflow/med_graph.py similarity index 58% rename from tools/external_converter_v2/parser/kill_tf/med_graph.py rename to tools/external_converter_v2/parser/tensorflow/med_graph.py index aacbc5e15..d17cc8702 100644 --- a/tools/external_converter_v2/parser/kill_tf/med_graph.py +++ b/tools/external_converter_v2/parser/tensorflow/med_graph.py @@ -1,15 +1,26 @@ import numpy as np - class MedNodeUtil: @staticmethod def new_med_node(): - return {'name':None,'ak_type': None, 'input': [], 'output': [], 'ak_attr': {},'type':None,'med_visted':False} + ''' + return instance of empty standard med graph node + :return: + ''' + return {'name': None, 'ak_type': None, 'input': [], 'output': [], 'ak_attr': {}, 'type': None, + 'med_visted': False} @staticmethod def replace_name_with_list(origin_list, name, replace_list): + ''' + replace name in input or output with replace_list + :param origin_list: + :param name: + :param replace_list: + :return: + ''' new_list = [] for index, ori_object in enumerate(origin_list): if ori_object['name'] == name: @@ -23,6 +34,12 @@ def replace_name_with_list(origin_list, name, replace_list): @staticmethod def retain_input(node, input_list): + ''' + remove node input except element in input_list + :param node: + :param input_list: + :return: + ''' new_input = [] for index, node_object in enumerate(node['input']): if node_object in input_list: @@ -31,17 +48,35 @@ def retain_input(node, input_list): node['input'] = new_input @staticmethod - def redirecto_outputs_input_to_this(node,graph,this_name,this_shape): + def redirecto_outputs_input_to_this(node, graph, this_name, this_shape): + ''' + get node_x in node`s outputs + make node_x`s inputs reference to node + :param node: + :param graph: + :param this_name: + :param this_shape: + :return: + ''' for i in node['output']: - tar_node=graph[i['name']] - tar_node['input']=MedNodeUtil.replace_name_with_list(tar_node['input'],node['name'],[{'name':this_name,'shape':this_shape}]) + tar_node = graph[i['name']] + tar_node['input'] = MedNodeUtil.replace_name_with_list(tar_node['input'], node['name'], + [{'name': this_name, 'shape': this_shape}]) + +MedGraph_Input_Cnt = 0 -MedGraph_Input_Cnt=0 class MedGraphUtil: @staticmethod def append_node(father_node, son_node, graph): + ''' + add the son_node after father_node in graph + :param father_node: + :param son_node: + :param graph: + :return: + ''' output = father_node['output'] son_shape = father_node['output'][0]['shape'] son_node['input'] = [{'name': father_node['name'], 'shape': son_shape}] @@ -54,7 +89,13 @@ def append_node(father_node, son_node, graph): graph[son_node['name']] = son_node @staticmethod - def check_one_of_input_is_const(node,graph): + def check_one_of_input_is_const(node, graph): + ''' + check one of input is const + :param node: + :param graph: + :return: + ''' for i in node['input']: if graph[i['name']]['type'] == 'Const': return True @@ -62,26 +103,45 @@ def check_one_of_input_is_const(node,graph): @staticmethod def _auto_split(med_node, med_graph): + ''' + add split to node which output size >=2 + :param med_node: + :param med_graph: + :return: + ''' output = med_node['output'] if len(output) > 1: split_node = MedNodeUtil.new_med_node() - split_node['name']=med_node['name']+'_split#' - split_node['ak_type']='Split' - split_node['ak_attr']['split_num'] =len(output) - MedGraphUtil.append_node(med_node,split_node,graph=med_graph) + split_node['name'] = med_node['name'] + '_split#' + split_node['ak_type'] = 'Split' + split_node['ak_attr']['split_num'] = len(output) + MedGraphUtil.append_node(med_node, split_node, graph=med_graph) pass @staticmethod def _auto_input_name(med_node, med_graph): - assert med_node['ak_type']=='Input' - old_name=med_node['name'] - med_node['name']='input_'+str(MedGraph_Input_Cnt) + ''' + gen input name + :param med_node: + :param med_graph: + :return: + ''' + assert med_node['ak_type'] == 'Input' + old_name = med_node['name'] + med_node['name'] = 'input_' + str(MedGraph_Input_Cnt) for i in med_node['output']: - out_node=med_graph[i['name']] - out_node['input']=MedNodeUtil.replace_name_with_list(out_node['input'],old_name,[{'name':med_node['name'],'shape':i['shape']}]) + out_node = med_graph[i['name']] + out_node['input'] = MedNodeUtil.replace_name_with_list(out_node['input'], old_name, + [{'name': med_node['name'], 'shape': i['shape']}]) @staticmethod def _fusionScale(med_node, med_graph): + ''' + fusion scale node after convolution node + :param med_node: + :param med_graph: + :return: + ''' if len(med_node['input']) == 1: input_node = med_graph[med_node['input'][0]['name']] med_ak_attr = med_node['ak_attr'] @@ -100,14 +160,22 @@ def _fusionScale(med_node, med_graph): else: input_attr['bias_weights'] = med_ak_attr['bias_weights'] med_node['ak_type'] = None - input_node['output'] = MedNodeUtil.replace_name_with_list(input_node['output'], med_node['name'], med_node['output']) - MedNodeUtil.redirecto_outputs_input_to_this(med_node,med_graph,input_node['name'],med_node['input'][0]['shape']) - input_node['fusion_out_name']=med_node['name'] + input_node['output'] = MedNodeUtil.replace_name_with_list(input_node['output'], med_node['name'], + med_node['output']) + MedNodeUtil.redirecto_outputs_input_to_this(med_node, med_graph, input_node['name'], + med_node['input'][0]['shape']) + input_node['fusion_out_name'] = med_node['name'] pass @staticmethod def _all_search_table(graph, table): + ''' + search template for dict + :param graph: + :param table: + :return: + ''' for tf_node in graph.values(): if tf_node['med_visted']: continue @@ -117,6 +185,12 @@ def _all_search_table(graph, table): @staticmethod def _all_search_fusion(graph, fusion_func): + ''' + search template for func + :param graph: + :param fusion_func: + :return: + ''' for tf_node in graph.values(): if tf_node['med_visted']: continue @@ -125,14 +199,24 @@ def _all_search_fusion(graph, fusion_func): @staticmethod def solve(med_graph): + ''' + do fusion and adjust for med graph that we can convert med graph to ak graph + :param med_graph: + :return: + ''' for node in med_graph.values(): node['med_visted'] = False MedGraphUtil._all_search_table(med_graph, {'Scale': MedGraphUtil._fusionScale}) MedGraphUtil._all_search_fusion(med_graph, MedGraphUtil._auto_split) - MedGraphUtil._all_search_table(med_graph, {'Input':MedGraphUtil._auto_input_name}) + MedGraphUtil._all_search_table(med_graph, {'Input': MedGraphUtil._auto_input_name}) @staticmethod def search_output_list(graph): + ''' + search output list in recursive method + :param graph: + :return: + ''' output_list = set() graph_cp = graph.copy() diff --git a/tools/external_converter_v2/parser/kill_tf/parse_med_2_ak.py b/tools/external_converter_v2/parser/tensorflow/parse_med_2_ak.py similarity index 69% rename from tools/external_converter_v2/parser/kill_tf/parse_med_2_ak.py rename to tools/external_converter_v2/parser/tensorflow/parse_med_2_ak.py index fa0df3c7a..2cc53107e 100644 --- a/tools/external_converter_v2/parser/kill_tf/parse_med_2_ak.py +++ b/tools/external_converter_v2/parser/tensorflow/parse_med_2_ak.py @@ -4,11 +4,21 @@ def shape_2_ak_shape(shape): + ''' + convert med shape to ak shape + :param shape: + :return: + ''' mini_shape = [i for i in shape if (i != None and i > 0)] return map(int, [1] * (4 - len(mini_shape)) + list(mini_shape)) def np_2_ak_tensor(np_tensor): + ''' + conver med tensor to ak tensor + :param np_tensor: + :return: + ''' data_type_map = { np.dtype('float32'): 'float', np.dtype('int32'): 'int', @@ -29,6 +39,12 @@ def __init__(self): self.input_count = 0 def Convolution(self, med_attr, param): + ''' + fill convlution param in ak graph + :param med_attr: + :param param: + :return: + ''' np_filters = med_attr['weights'] param.weight_1 = np_2_ak_tensor(np_filters) param.filter_num = np_filters.shape[0] @@ -48,6 +64,12 @@ def Convolution(self, med_attr, param): pass def Dense(self, med_attr, param): + ''' + fill Dense param in ak graph + :param med_attr: + :param param: + :return: + ''' param.weight_1 = np_2_ak_tensor(med_attr['weights']) param.axis = 1 if med_attr.get('bias_weights') is not None: @@ -58,18 +80,35 @@ def Dense(self, med_attr, param): pass def Relu(self, med_attr, param): + ''' + fill Relu param in ak graph + :param med_attr: + :param param: + :return: + ''' if med_attr.get('alpha') is None: param.alpha = 0.0 else: param.alpha = med_attr['type'] def Activation(self, med_attr, param): + ''' + fill Activation param in ak graph + :param med_attr: + :param param: + :return: + ''' param.type = med_attr['type'] - if med_attr['type']=='ClippedRelu': - param.clip_relu_num=med_attr['clip_relu_num'] - + if med_attr['type'] == 'ClippedRelu': + param.clip_relu_num = med_attr['clip_relu_num'] def Softmax(self, med_attr, param): + ''' + fill Softmax param in ak graph + :param med_attr: + :param param: + :return: + ''' if med_attr.get('axis') is None: param.axis = 3 else: @@ -77,17 +116,41 @@ def Softmax(self, med_attr, param): pass def Concat(self, med_attr, param): + ''' + fill Concat param in ak graph + :param med_attr: + :param param: + :return: + ''' param.axis = med_attr['axis'] def Split(self, med_attr, param): + ''' + fill Split param in ak graph + :param med_attr: + :param param: + :return: + ''' param.split_num = med_attr['split_num'] def Eltwise(self, med_attr, param): + ''' + fill Eltwise param in ak graph + :param med_attr: + :param param: + :return: + ''' assert med_attr['type'] == 'Add' param.type = med_attr['type'] param.coeff = [1.0, 1.0] def Scale(self, med_attr, param): + ''' + fill Scale param in ak graph + :param med_attr: + :param param: + :return: + ''' param.weight_1 = np_2_ak_tensor(med_attr['scale_weights']) if med_attr.get('bias_weights') is not None: param.weight_2 = np_2_ak_tensor(med_attr['bias_weights']) @@ -98,6 +161,12 @@ def Scale(self, med_attr, param): param.num_axes = 1 def Reshape(self, med_attr, param): + ''' + fill Reshape param in ak graph + :param med_attr: + :param param: + :return: + ''' shape = med_attr['shape'] if isinstance(shape, type(np.array([]))): shape = [int(i) for i in shape] @@ -105,6 +174,12 @@ def Reshape(self, med_attr, param): pass def Pooling(self, med_attr, param): + ''' + fill Pooling param in ak graph + :param med_attr: + :param param: + :return: + ''' param.method = med_attr['type'] param.pool_size = med_attr['window'] param.strides = med_attr['strides'] @@ -121,19 +196,35 @@ def Pooling(self, med_attr, param): pass - def Pad(self, med_attr, param): - param.pad_c=med_attr['pad_c'] + ''' + fill Pad param in ak graph + :param med_attr: + :param param: + :return: + ''' + param.pad_c = med_attr['pad_c'] param.pad_h = med_attr['pad_h'] param.pad_w = med_attr['pad_w'] - def Input(self, med_attr, param): + ''' + fill Input param in ak graph + :param med_attr: + :param param: + :return: + ''' param.input_shape = shape_2_ak_shape(med_attr['shape']) if med_attr.get('alias') is not None: param.alias = med_attr['alias'] def map_med_2_ak(self, ak_node, med_node): + ''' + entrance for trans med graph 2 ak graph + :param ak_node: + :param med_node: + :return: + ''' type_name = med_node['ak_type'] func = getattr(self, type_name, None) param = OpsParam() diff --git a/tools/external_converter_v2/parser/kill_tf/parse_tf_2_med.py b/tools/external_converter_v2/parser/tensorflow/parse_tf_2_med.py similarity index 73% rename from tools/external_converter_v2/parser/kill_tf/parse_tf_2_med.py rename to tools/external_converter_v2/parser/tensorflow/parse_tf_2_med.py index 14705878b..6f26d8a55 100644 --- a/tools/external_converter_v2/parser/kill_tf/parse_tf_2_med.py +++ b/tools/external_converter_v2/parser/tensorflow/parse_tf_2_med.py @@ -4,23 +4,26 @@ import logging as log import collections from tf_trans_util import * -class ParseTF2Med: - def __init__(self,tf_forzen_pb_path): - self.model_path=tf_forzen_pb_path - def _debug_nodes(self,nodes): + +class ParseTF2Med: + def __init__(self, tf_forzen_pb_path): + self.model_path = tf_forzen_pb_path + + def _debug_nodes(self, nodes): + ''' + print debug info and exit + :param nodes: + :return: + ''' for i in nodes.values(): - print(i['name'],i['input'],i['output'],i['out_shape']) + print(i['name'], i['input'], i['output'], i['out_shape']) print('debug end') exit() - - def _parse_tf_node(self,tf_graph,shape_override): - - + def _parse_tf_node(self, tf_graph, shape_override): """ - Load tensorflow graph into an onnx graph with minimal rewrites so - we can use the onnx graph as intermediate graph. + Load tensorflow graph into an raw med graph """ # ignore the following attributes @@ -37,11 +40,10 @@ def _parse_tf_node(self,tf_graph,shape_override): # find outputs ops = tf_graph.get_operations() - tensor_shape={} + tensor_shape = {} for node in ops: for out in node.outputs: - tensor_shape[out.name]=out.get_shape().as_list() - + tensor_shape[out.name] = out.get_shape().as_list() # minimal conversion of attributes for node in ops: @@ -50,7 +52,7 @@ def _parse_tf_node(self,tf_graph,shape_override): op_cnt[node.type] += 1 for a in node.node_def.attr: - a=str(a) + a = str(a) attr_cnt[a] += 1 if a == "dtype": attr[a] = map_tf_dtype(node.get_attr("dtype")) @@ -92,11 +94,17 @@ def _parse_tf_node(self,tf_graph,shape_override): log.error("pass1 convert failed for %s, ex=%s", node, ex) raise - self._fix_self_output(anakin_nodes,tensor_shape) + self._fix_self_output(anakin_nodes, tensor_shape) return anakin_nodes def _fix_self_output(self, nodes, tensor_shape_dict): + ''' + convert tensor connection to op connection + :param nodes: + :param tensor_shape_dict: + :return: + ''' out2nodename = {} for node in nodes.values(): for out_name in node['output']: @@ -114,23 +122,28 @@ def _fix_self_output(self, nodes, tensor_shape_dict): in2nodename[in_name].append(node['name']) for node in nodes.values(): - new_output=[] - new_input=[] + new_output = [] + new_input = [] for tensor_name in node['output']: if in2nodename.get(tensor_name) is not None: - new_output+=[{'name':op_name,'shape':tensor_shape_dict[tensor_name]} for op_name in in2nodename[tensor_name]] + new_output += [{'name': op_name, 'shape': tensor_shape_dict[tensor_name]} for op_name in + in2nodename[tensor_name]] for tensor_name in node['input']: if out2nodename.get(tensor_name) is not None: - new_input+=[{'name':op_name,'shape':tensor_shape_dict[tensor_name]} for op_name in out2nodename[tensor_name]] - - node['output']=new_output - node['input']=new_input - + new_input += [{'name': op_name, 'shape': tensor_shape_dict[tensor_name]} for op_name in + out2nodename[tensor_name]] + node['output'] = new_output + node['input'] = new_input - def _parse_tf_graph(self,nodes): + def _parse_tf_graph(self, nodes): + ''' + conver op in tf graph to med graph + :param nodes: + :return: + ''' def all_search(graph, table): for tf_node in graph.values(): @@ -145,19 +158,19 @@ def all_search(graph, table): 'Shape': parse_Shape }) - all_search(nodes, {'Reshape': parse_fusionReshape,}) + all_search(nodes, {'Reshape': parse_fusionReshape, }) all_search(nodes, {'MatMul': parse_MatMul, 'Conv2D': parse_Conv2D, 'DepthwiseConv2dNative': parse_Conv2D, - 'FusedBatchNorm':parse_BatchNorm, - 'Rsqrt': parse_CustmerBatchNorm,}) + 'FusedBatchNorm': parse_BatchNorm, + 'Rsqrt': parse_CustmerBatchNorm, }) - all_search(nodes, {'Add':parse_Add, + all_search(nodes, {'Add': parse_Add, 'AvgPool': parse_Pooling, 'ConcatV2': parse_Concat, 'MaxPool': parse_Pooling, - 'Mean':parse_Mean, + 'Mean': parse_Mean, 'Pad': parse_Pad, 'Relu': parse_Act, 'Relu6': parse_Act, @@ -170,12 +183,16 @@ def all_search(graph, table): return nodes def parse(self): + ''' + entrance to load tf graph and convert it to med graph + :return: + ''' tf_graph = load_graph(self.model_path) nodes = self._parse_tf_node(tf_graph, {}) - med_graph=self._parse_tf_graph(nodes) - filter_graph={i:med_graph[i] for i in med_graph.keys() if med_graph[i]['ak_type'] is not None} + med_graph = self._parse_tf_graph(nodes) + filter_graph = {i: med_graph[i] for i in med_graph.keys() if med_graph[i]['ak_type'] is not None} for node in filter_graph.values(): - node['input']=[i for i in node['input'] if filter_graph.get(i['name']) is not None] + node['input'] = [i for i in node['input'] if filter_graph.get(i['name']) is not None] node['output'] = [i for i in node['output'] if filter_graph.get(i['name']) is not None] - return filter_graph \ No newline at end of file + return filter_graph diff --git a/tools/external_converter_v2/parser/tensorflow/parser_tf.py b/tools/external_converter_v2/parser/tensorflow/parser_tf.py new file mode 100644 index 000000000..7e800f2a3 --- /dev/null +++ b/tools/external_converter_v2/parser/tensorflow/parser_tf.py @@ -0,0 +1,72 @@ +import numpy as np +import os +from ..graph_io import * +from ..logger import * +from ..proto import * +import tensorflow as tf +from parse_tf_2_med import ParseTF2Med +from parse_med_2_ak import MedTransAK +from med_graph import MedGraphUtil, MedNodeUtil + + +class TFParser: + + def __init__(self, fluid_config_dict): + # anakin graph model io + # config info + self.ProtoPaths = fluid_config_dict['ProtoPaths'] + + self.OutPuts = fluid_config_dict['OutPuts'] + if self.OutPuts is not None: + self.OutPuts = [i for i in fluid_config_dict['OutPuts'].split(',')] + + self.med_trans_tool = MedTransAK() + self.input_count = 0 + + def __call__(self): + med_graph = self._conver_tf_2_med() + if self.OutPuts is None: + self.OutPuts = MedGraphUtil.search_output_list(med_graph) + + MedGraphUtil.solve(med_graph) + anakin_graph = self._conver_med_2_anakin(med_graph) + return anakin_graph + + def _conver_tf_2_med(self): + ''' + convert tf graph to med graph + :return: + ''' + parser = ParseTF2Med(self.ProtoPaths) + return parser.parse() + + def _add_protonode(self, ak_graph, med_node): + ''' + add protobuf node in ak graph + :param ak_graph: + :param med_node: + :return: + ''' + ak_type = med_node['ak_type'] + if ak_type is None: + return + nodeIO = NodeProtoIO() + nodeIO.set_name(med_node['name']) + self.med_trans_tool.map_med_2_ak(nodeIO, med_node) + ak_graph.add_node(nodeIO()) + if nodeIO().Op.name == 'Input': + ak_graph.add_in(nodeIO().name) + + def _conver_med_2_anakin(self, med_graph): + ''' + convert med graph to ak graph + :param med_graph: + :return: + ''' + anakin_graph = GraphProtoIO() + for node in med_graph.values(): + self._add_protonode(anakin_graph, node) + anakin_graph.format_edge_from_nodes() + for out_node_name in self.OutPuts: + anakin_graph.add_out('output_' + out_node_name, out_node_name) + return anakin_graph diff --git a/tools/external_converter_v2/parser/tensorflow/run_pb.py b/tools/external_converter_v2/parser/tensorflow/run_pb.py new file mode 100644 index 000000000..5b44bc23e --- /dev/null +++ b/tools/external_converter_v2/parser/tensorflow/run_pb.py @@ -0,0 +1,80 @@ +import numpy as np +from tf_util import TfUtil + + +def convert_name_tf2ak(tf_name, perfix='record_'): + ''' + conver tf name to ak name + :param tf_name: + :param perfix: + :return: + ''' + ak_name = tf_name[:] + for index, x in enumerate(tf_name): + if x == '/': + ak_name = ak_name[:index] + '_' + ak_name[index + 1:] + return perfix + ak_name + + +# ak_work_space='/your/anakin/workspace' +output_compare_op = None + +# graph_path='./vgg_model/frozen_vgg_16_i.pb' +# input_name='graph/input:0' +# output_op='graph/vgg_16/fc8/BiasAdd' +# output_compare_op='graph/vgg_16/fc8/convolution' + +graph_path = './resnet_model/frozen_resnet_v1_50.pb' +input_name = 'graph/input:0' +output_op = 'graph/resnet_v1_50/predictions/Reshape_1' + +# graph_path='./mobilnetv2/frozen_mobilnet_v2.pb' +# input_name='graph/input:0' +# output_op='graph/MobilenetV2/Predictions/Reshape_1' + +# graph_path='./inception_model/frozen_inception_v2.pb' +# input_name='graph/input:0' +# output_op='graph/InceptionV2/Predictions/Reshape_1' + + +is_compared = True +output_name = output_op + ':0' +if output_compare_op is None: + compare_path = ak_work_space + convert_name_tf2ak(output_op) +else: + compare_path = ak_work_space + convert_name_tf2ak(output_compare_op) + +np.random.seed(1234567) +x_location = ak_work_space + 'input_x' +x_value = np.random.randn(1, 224, 224, 3) +outs = TfUtil.tf_run_model(graph_path, {input_name: x_value}, [output_name]) + +import struct + +with open(x_location, "wb") as file: + x_value_new = x_value.transpose((0, 3, 1, 2)) + for value in x_value_new.flatten(): + file.write(struct.pack('f', value)) + +if is_compared: + out = outs[0] + if len(out.shape) == 4: + out = out.transpose((0, 3, 1, 2)) + else: + print('out shape :', out.shape) + print(out.flatten()[:10]) + try: + with open(compare_path, 'r')as file: + ans = [] + for value_str in file.readlines(): + ans.append(float(value_str.split(' ')[1])) + correct = out.flatten() + assert len(correct) == len(ans) + for i in range(len(ans)): + if abs(ans[i] - correct[i]) > 0.0001 and abs(ans[i] - correct[i]) / abs(correct[i]) > 0.0001: + print(i, '=', ans[i], 'correct = ', correct[i]) + exit() + print('passed') + except Exception, e: + print(out) + print('can`t find file : ' + compare_path) diff --git a/tools/external_converter_v2/parser/kill_tf/run_pb_get_ckp.py b/tools/external_converter_v2/parser/tensorflow/run_pb_get_ckp.py similarity index 80% rename from tools/external_converter_v2/parser/kill_tf/run_pb_get_ckp.py rename to tools/external_converter_v2/parser/tensorflow/run_pb_get_ckp.py index 38ca29178..d9816c8f8 100644 --- a/tools/external_converter_v2/parser/kill_tf/run_pb_get_ckp.py +++ b/tools/external_converter_v2/parser/tensorflow/run_pb_get_ckp.py @@ -11,12 +11,12 @@ # graph_path='./ease_model/graph.pb' # graph_path='./ease_model/frozen_mnist.pb' # graph_path='./vgg_model/frozen_vgg_16_i.pb' -graph_path='./inception_model/inception_v2_inf_graph.pb' -cpkt_path='./inception_model/' +graph_path = './inception_model/inception_v2_inf_graph.pb' +cpkt_path = './inception_model/' # graph_path='./resnet_model/frozen_resnet_v1_50.pb' -sess=tf.Session() +sess = tf.Session() if graph_path.endswith('.pbtxt'): input_binary = False else: @@ -35,17 +35,17 @@ tf.train.import_meta_graph(graph_path, clear_devices=True) tf.import_graph_def(graph_def, name='graph') -sess=tf.Session(graph=graph) +sess = tf.Session(graph=graph) x = graph.get_tensor_by_name('graph/input:0') y = graph.get_tensor_by_name('graph/InceptionV2/Predictions/Reshape_1:0') for var in tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES): - print(var.name) -init_table=tf.tables_initializer() + print(var.name) +init_table = tf.tables_initializer() sess.run(init_table) -init=tf.global_variables_initializer() +init = tf.global_variables_initializer() sess.run(init) -out=sess.run(y,{x:np.ones((1,224,224,3))}) +out = sess.run(y, {x: np.ones((1, 224, 224, 3))}) saver = tf.train.Saver() -saver.save(sess, cpkt_path+'/model.cpkt') \ No newline at end of file +saver.save(sess, cpkt_path + '/model.cpkt') diff --git a/tools/external_converter_v2/parser/kill_tf/summary.py b/tools/external_converter_v2/parser/tensorflow/summary.py similarity index 84% rename from tools/external_converter_v2/parser/kill_tf/summary.py rename to tools/external_converter_v2/parser/tensorflow/summary.py index 5edcb8358..cc1eac454 100644 --- a/tools/external_converter_v2/parser/kill_tf/summary.py +++ b/tools/external_converter_v2/parser/tensorflow/summary.py @@ -12,15 +12,21 @@ from tensorflow.python.platform import gfile - # graph_path = './resnet_v1_50_graph.pb' # graph_path = './frozen_graph.pb' # graph_path='./vgg_model/frozen_vgg_16_i.pb' # graph_path='./inception_model/frozen_inception_v2.pb' -graph_path='./resnet_model/frozen_resnet_v1_50.pb' +graph_path = './resnet_model/frozen_resnet_v1_50.pb' + + # graph_path='./mobilnetv2/frozen_mobilnet_v2.pb' def get_graph(graph_path): + ''' + get tensor board graph from pb file or meta file + :param graph_path: + :return: + ''' if graph_path.endswith('.pbtxt'): input_binary = False else: @@ -41,5 +47,5 @@ def get_graph(graph_path): return graph -graph=get_graph(graph_path) -summaryWriter = tf.summary.FileWriter('log/', graph) \ No newline at end of file +graph = get_graph(graph_path) +summaryWriter = tf.summary.FileWriter('log/', graph) diff --git a/tools/external_converter_v2/parser/kill_tf/tf_trans_util.py b/tools/external_converter_v2/parser/tensorflow/tf_trans_util.py similarity index 76% rename from tools/external_converter_v2/parser/kill_tf/tf_trans_util.py rename to tools/external_converter_v2/parser/tensorflow/tf_trans_util.py index cc8a48823..581a313bc 100644 --- a/tools/external_converter_v2/parser/kill_tf/tf_trans_util.py +++ b/tools/external_converter_v2/parser/tensorflow/tf_trans_util.py @@ -2,7 +2,7 @@ import numpy as np from tensorflow.core.framework import types_pb2, tensor_pb2 from google.protobuf import text_format -from med_graph import MedNodeUtil,MedGraphUtil +from med_graph import MedNodeUtil, MedGraphUtil TF_TO_ANAKIN_DTYPE = { types_pb2.DT_FLOAT: np.float32, @@ -62,6 +62,11 @@ def get_tf_tensor_data(tensor): def map_tf_dtype(dtype): + ''' + wraper for TF_TO_ANAKIN_DTYPE + :param dtype: + :return: + ''' return TF_TO_ANAKIN_DTYPE.get(dtype) @@ -92,9 +97,9 @@ def tf_to_anakin_tensor(tensor): if dims == [0]: dims = [1] is_raw, data = get_tf_tensor_data(tensor) - dim_size=1 + dim_size = 1 for i in dims: - dim_size*=i + dim_size *= i # print(type(data),data,tensor.dtype,is_raw) if is_raw: if len(dims) > 0: @@ -103,14 +108,19 @@ def tf_to_anakin_tensor(tensor): else: anakin_tensor = np.zeros(0) return anakin_tensor - elif dim_size >1 and len(data)==1: + elif dim_size > 1 and len(data) == 1: - return np.array([data]*dim_size).reshape(dims) + return np.array([data] * dim_size).reshape(dims) else: return data def load_graph(graph_path): + ''' + load tensorflow graph + :param graph_path: + :return: + ''' if graph_path.endswith('.pbtxt'): input_binary = False else: @@ -138,6 +148,12 @@ def load_graph(graph_path): def spatial_map(shape, perm): + ''' + convert shape in different layout + :param shape: + :param perm: + :return: + ''' # print('HI ',type(shape),shape) new_shape = shape[:] for i in perm: @@ -146,6 +162,12 @@ def spatial_map(shape, perm): def trans_move_attr(attr, format): + ''' + get h,w shape from attr + :param attr: + :param format: + :return: + ''' if attr is None: return attr if len(attr) == 2: @@ -158,24 +180,40 @@ def trans_move_attr(attr, format): raise Exception('not support format ' + format) return [h, w] -def add_special_pad(padding,tf_node,graph): + +def add_special_pad(padding, tf_node, graph): + ''' + add pad op to solve different pad method in caffe and tensorflow + :param padding: + :param tf_node: + :param graph: + :return: + ''' # print(tf_node['name']) - assert len(tf_node['input'])<=2 - now_shape=tf_node['input'][0]['shape'] - tar_shape =now_shape[:] - tar_shape[1]=now_shape[1]+padding[0]+padding[1] + assert len(tf_node['input']) <= 2 + now_shape = tf_node['input'][0]['shape'] + tar_shape = now_shape[:] + tar_shape[1] = now_shape[1] + padding[0] + padding[1] tar_shape[2] = now_shape[2] + padding[2] + padding[3] tf_name = tf_node['name'] - padding_node={'name':tf_node['name']+'_pad','ak_type':'Pad','type':None,'visted':True, - 'ak_attr':{'pad_c':[0,0],'pad_h':[padding[0],padding[1]],'pad_w':[padding[2],padding[3]]}, - 'input':[tf_node['input'][0]],'output':[{'name':tf_name,'shape':tar_shape}]} + padding_node = {'name': tf_node['name'] + '_pad', 'ak_type': 'Pad', 'type': None, 'visted': True, + 'ak_attr': {'pad_c': [0, 0], 'pad_h': [padding[0], padding[1]], 'pad_w': [padding[2], padding[3]]}, + 'input': [tf_node['input'][0]], 'output': [{'name': tf_name, 'shape': tar_shape}]} + + input_0 = graph[tf_node['input'][0]['name']] + input_0['output'] = MedNodeUtil.replace_name_with_list(input_0['output'], tf_name, + [{'name': padding_node['name'], 'shape': now_shape}]) + tf_node['input'][0] = {'name': padding_node['name'], 'shape': tar_shape} + graph[padding_node['name']] = padding_node - input_0=graph[tf_node['input'][0]['name']] - input_0['output']=MedNodeUtil.replace_name_with_list(input_0['output'],tf_name,[{'name':padding_node['name'],'shape':now_shape}]) - tf_node['input'][0]={'name':padding_node['name'],'shape':tar_shape} - graph[padding_node['name']]=padding_node def parse_Identity(tf_node, graph): + ''' + remove identity in tensorflow graph + :param tf_node: + :param graph: + :return: + ''' tf_node['visted'] = True outputs = tf_node['output'] input_0 = tf_node['input'][0] @@ -189,6 +227,12 @@ def parse_Identity(tf_node, graph): def parse_Shape(tf_node, graph): + ''' + parse shape for tensorflow graph + :param tf_node: + :param graph: + :return: + ''' assert len(tf_node['input']) == 1 tf_node['type'] = 'Const' tf_node['tf_attr']['value'] = tf_node['input'][0]['shape'] @@ -196,6 +240,12 @@ def parse_Shape(tf_node, graph): def parse_Squeeze(tf_node, graph): + ''' + convert squeeze to reshape + :param tf_node: + :param graph: + :return: + ''' tf_node['visted'] = True tf_node['ak_type'] = 'Reshape' tf_node['ak_attr']['shape'] = tf_node['output'][0]['shape'] @@ -203,30 +253,54 @@ def parse_Squeeze(tf_node, graph): def parse_Placeholder(tf_node, graph): + ''' + conver placeholder to input op + :param tf_node: + :param graph: + :return: + ''' tf_node['visted'] = True tf_node['ak_type'] = 'Input' tf_node['ak_attr']['shape'] = spatial_map(tf_node['output'][0]['shape'], NHWC_TO_NCHW) def parse_Pad(tf_node, graph): + ''' + convert pad op + :param tf_node: + :param graph: + :return: + ''' tf_node['visted'] = True tf_node['ak_type'] = 'Pad' pad_shape_node = graph[tf_node['input'][1]['name']] assert pad_shape_node['type'] == 'Const' - pad_shape=pad_shape_node['tf_attr']['value'] - ak_attr=tf_node['ak_attr'] + pad_shape = pad_shape_node['tf_attr']['value'] + ak_attr = tf_node['ak_attr'] ak_attr['pad_c'] = pad_shape[3].flatten().tolist() ak_attr['pad_h'] = pad_shape[1].flatten().tolist() ak_attr['pad_w'] = pad_shape[2].flatten().tolist() def parse_Softmax(tf_node, graph): + ''' + convert softmax op, default axis is 3 + :param tf_node: + :param graph: + :return: + ''' tf_node['visted'] = True tf_node['ak_type'] = 'Softmax' - tf_node['ak_attr']['axis']=3 + tf_node['ak_attr']['axis'] = 3 def parse_Reshape(tf_node, graph): + ''' + convert reshape op + :param tf_node: + :param graph: + :return: + ''' tf_node['visted'] = True tf_node['ak_type'] = 'Reshape' shape = graph[tf_node['input'][1]['name']] @@ -238,9 +312,15 @@ def parse_Reshape(tf_node, graph): def parse_Act(tf_node, graph): + ''' + convert activate op + :param tf_node: + :param graph: + :return: + ''' tf_node['visted'] = True tf_node['ak_type'] = 'Activation' - if tf_node['type'] == 'Relu' : + if tf_node['type'] == 'Relu': tf_node['ak_type'] = 'Relu' tf_node['ak_attr']['type'] = 'Relu' elif tf_node['type'] == 'Relu6': @@ -252,16 +332,28 @@ def parse_Act(tf_node, graph): def parse_Concat(tf_node, graph): + ''' + convert concat op + :param tf_node: + :param graph: + :return: + ''' tf_node['visted'] = True tf_node['ak_type'] = 'Concat' N = tf_node['tf_attr']['N'] axis_node = graph[tf_node['input'][N]['name']] assert axis_node['type'] == 'Const' - nhwc2hchw={0:0,1:2,2:3,3:1} + nhwc2hchw = {0: 0, 1: 2, 2: 3, 3: 1} tf_node['ak_attr']['axis'] = nhwc2hchw[axis_node['tf_attr']['value'][0]] def parse_Add(tf_node, graph): + ''' + convert add op + :param tf_node: + :param graph: + :return: + ''' tf_node['visted'] = True assert len(tf_node['input']) == 2 input_0 = graph[tf_node['input'][0]['name']] @@ -278,33 +370,47 @@ def parse_Add(tf_node, graph): tf_node['ak_type'] = 'Eltwise' ak_attr['type'] = 'Add' + def parse_Mean(tf_node, graph): + ''' + convert mean op to pooling op + :param tf_node: + :param graph: + :return: + ''' tf_node['visted'] = True tf_node['ak_type'] = 'Pooling' ak_attr = tf_node['ak_attr'] tf_attr = tf_node['tf_attr'] - ak_attr['type']='AVG' - reduction_shape=None - keep_dims=tf_attr['keep_dims'] - - if len(tf_node['input'])>1: - reduction_shape_node=graph[tf_node['input'][1]['name']] - assert reduction_shape_node['type']=='Const' - reduction_shape=reduction_shape_node['tf_attr']['value'].flatten().tolist() + ak_attr['type'] = 'AVG' + reduction_shape = None + keep_dims = tf_attr['keep_dims'] + + if len(tf_node['input']) > 1: + reduction_shape_node = graph[tf_node['input'][1]['name']] + assert reduction_shape_node['type'] == 'Const' + reduction_shape = reduction_shape_node['tf_attr']['value'].flatten().tolist() assert reduction_shape is not None assert keep_dims is True - assert reduction_shape == [1,2] - ak_attr['strides'] = [1,1] - ak_attr['window'] = [tf_node['input'][0]['shape'][reduction_shape[0]],tf_node['input'][0]['shape'][reduction_shape[1]]] - ak_attr['padding'] = [0,0] + assert reduction_shape == [1, 2] + ak_attr['strides'] = [1, 1] + ak_attr['window'] = [tf_node['input'][0]['shape'][reduction_shape[0]], + tf_node['input'][0]['shape'][reduction_shape[1]]] + ak_attr['padding'] = [0, 0] def parse_Pooling(tf_node, graph): + ''' + convert pooling op + :param tf_node: + :param graph: + :return: + ''' tf_node['visted'] = True tf_node['ak_type'] = 'Pooling' ak_attr = tf_node['ak_attr'] tf_attr = tf_node['tf_attr'] - #TODO TF default pad is exclusive method + # TODO TF default pad is exclusive method map_tf_pool = {'MaxPool': 'MAX', 'AvgPool': 'AVGEXC'} @@ -322,26 +428,38 @@ def parse_Pooling(tf_node, graph): padding = cal_padding(padding, kernel_shape, strides, dilations, data_format, tf_node['input'][0]['shape'], tf_node['output'][0]['shape']) - if padding[0]!=padding[1] or padding[2]!=padding[3]: - add_special_pad(padding,tf_node,graph) - padding=[0,0] + if padding[0] != padding[1] or padding[2] != padding[3]: + add_special_pad(padding, tf_node, graph) + padding = [0, 0] else: - padding=[padding[0],padding[2]] + padding = [padding[0], padding[2]] ak_attr['window'] = kernel_shape ak_attr['padding'] = padding ak_attr['strides'] = strides - ak_attr['cmp_out_shape_floor_as_conv']=True + ak_attr['cmp_out_shape_floor_as_conv'] = True def cal_padding(padding, kernel_shape, strides, dilations, data_format, input_shape, output_shape, spatial=2): - pads = [0] * spatial*2 + ''' + convert pad string to pad list + :param padding: + :param kernel_shape: + :param strides: + :param dilations: + :param data_format: + :param input_shape: + :param output_shape: + :param spatial: + :return: + ''' + pads = [0] * spatial * 2 if type(padding) == bytes: padding = padding.decode() if dilations is None: dilations = [1] * spatial * 2 if padding == 'SAME': - pads = [0] * spatial*2 + pads = [0] * spatial * 2 if data_format == 'NHWC': # print('in out shape = ',input_shape,output_shape) input_shape = spatial_map(input_shape, NHWC_TO_NCHW) @@ -353,7 +471,7 @@ def cal_padding(padding, kernel_shape, strides, dilations, data_format, input_sh pad = max(pad, 0) pads1 = pad // 2 pads2 = pad - pad // 2 - pads[i*2+0]=pads1 + pads[i * 2 + 0] = pads1 pads[i * 2 + 1] = pads2 return pads elif padding == 'VALID': @@ -363,6 +481,12 @@ def cal_padding(padding, kernel_shape, strides, dilations, data_format, input_sh def get_const_from_biinput(inputs, graph): + ''' + search const input of node`s input + :param inputs: + :param graph: + :return: + ''' assert len(inputs) <= 2 input_0 = graph[inputs[0]['name']] input_1 = graph[inputs[1]['name']] @@ -374,6 +498,12 @@ def get_const_from_biinput(inputs, graph): def get_bias(tf_node, graph): + ''' + try to fetch const value form node + :param tf_node: + :param graph: + :return: + ''' bias_weight = None output = tf_node['output'] output_0 = graph[output[0]['name']] @@ -383,12 +513,18 @@ def get_bias(tf_node, graph): if bias_weight is not None: output_0['visted'] = True tf_node['output'] = output_0['output'] - MedNodeUtil.redirecto_outputs_input_to_this(output_0,graph,tf_node['name'],output[0]['shape']) + MedNodeUtil.redirecto_outputs_input_to_this(output_0, graph, tf_node['name'], output[0]['shape']) return bias_weight def parse_Conv2D(tf_node, graph): + ''' + convert conv2D to convolution + :param tf_node: + :param graph: + :return: + ''' tf_node['visted'] = True tf_node['ak_type'] = 'Convolution' weights_node = graph[tf_node['input'][1]['name']] @@ -407,18 +543,18 @@ def parse_Conv2D(tf_node, graph): # print('name ',tf_node['name'],input_node['name'],input_node['out_shape']) padding = cal_padding(padding, kernel_shape, strides, dilations, data_format, tf_node['input'][0]['shape'], tf_node['output'][0]['shape']) - if padding[0]!=padding[1] or padding[2]!=padding[3]: - add_special_pad(padding,tf_node,graph) - padding=[0,0] + if padding[0] != padding[1] or padding[2] != padding[3]: + add_special_pad(padding, tf_node, graph) + padding = [0, 0] else: - padding=[padding[0],padding[2]] + padding = [padding[0], padding[2]] group = 1 if tf_node['type'] == 'DepthwiseConv2dNative': weights = weights.transpose((1, 0, 2, 3)) group = weights.shape[0] - out_c=weights.shape[0]*weights.shape[1] - weights=weights.reshape(out_c,1,weights.shape[2],weights.shape[3]) + out_c = weights.shape[0] * weights.shape[1] + weights = weights.reshape(out_c, 1, weights.shape[2], weights.shape[3]) ak_attr = tf_node['ak_attr'] ak_attr['weights'] = weights @@ -431,6 +567,12 @@ def parse_Conv2D(tf_node, graph): def parse_MatMul(tf_node, graph): + ''' + convert matmul to dense + :param tf_node: + :param graph: + :return: + ''' tf_node['visted'] = True tf_node['ak_type'] = 'Dense' in_name_0 = tf_node['input'][0]['name'] @@ -457,6 +599,12 @@ def parse_MatMul(tf_node, graph): def parse_fusionReshape(tf_node, graph): + ''' + convert reshape + :param tf_node: + :param graph: + :return: + ''' assert tf_node['type'] == 'Reshape' input_0 = graph[tf_node['input'][0]['name']] input_1 = graph[tf_node['input'][1]['name']] @@ -472,6 +620,7 @@ def parse_fusionReshape(tf_node, graph): def parse_CustmerBatchNorm(tf_node, graph): + '''convert user custmer batchnorm to scale''' assert tf_node['type'] == 'Rsqrt' assert len(tf_node['input']) == 1 and len(tf_node['output']) == 1 rsqrt_mul_node = graph[tf_node['output'][0]['name']] @@ -485,7 +634,7 @@ def parse_CustmerBatchNorm(tf_node, graph): var_value = var_node['tf_attr']['value'].flatten() assert rsqrt_mul_node['type'] == 'Mul' and len(rsqrt_mul_node['input']) == 2 and len(rsqrt_mul_node['output']) == 2 const_mul_node_input_1 = graph[rsqrt_mul_node['input'][1]['name']] - if MedGraphUtil.check_one_of_input_is_const(graph[rsqrt_mul_node['output'][0]['name']],graph): + if MedGraphUtil.check_one_of_input_is_const(graph[rsqrt_mul_node['output'][0]['name']], graph): mul_mul_1_node = graph[rsqrt_mul_node['output'][1]['name']] mul_mul_2_node = graph[rsqrt_mul_node['output'][0]['name']] else: @@ -503,7 +652,7 @@ def parse_CustmerBatchNorm(tf_node, graph): assert mul_add_node['type'] == 'Add' and mul2_sub_node['type'] == 'Sub' and mean_node['type'] == 'Const' beta_node = graph[mul2_sub_node['input'][0]['name']] - assert beta_node['type']=='Const' + assert beta_node['type'] == 'Const' beta_value = beta_node['tf_attr']['value'].flatten() mean_value = mean_node['tf_attr']['value'].flatten() assert mul_add_node['input'][1]['name'] == mul2_sub_node['name'] @@ -518,13 +667,14 @@ def parse_CustmerBatchNorm(tf_node, graph): var = np.sqrt(var_value + epse_value) np_scale = alpha_value / var - np_bias = beta_value -np_scale * mean_value + np_bias = beta_value - np_scale * mean_value mul_mul_1_node['output'] = mul_add_node['output'] mul_mul_1_node['type'] = 'CustomerBN' mul_mul_1_node['ak_type'] = 'Scale' MedNodeUtil.retain_input(mul_mul_1_node, [mul_mul_1_node['input'][0]]) - MedNodeUtil.redirecto_outputs_input_to_this(mul_add_node,graph,mul_mul_1_node['name'],mul_mul_1_node['output'][0]['shape']) + MedNodeUtil.redirecto_outputs_input_to_this(mul_add_node, graph, mul_mul_1_node['name'], + mul_mul_1_node['output'][0]['shape']) ak_attr = mul_mul_1_node['ak_attr'] ak_attr['scale_weights'] = np_scale.astype('float32') ak_attr['bias_weights'] = np_bias.astype('float32') @@ -532,6 +682,12 @@ def parse_CustmerBatchNorm(tf_node, graph): def parse_BatchNorm(tf_node, graph): + ''' + convert fused batchnorm to scale + :param tf_node: + :param graph: + :return: + ''' tf_node['visted'] = True tf_node['ak_type'] = 'Scale' assert len(tf_node['input']) == 5 @@ -556,4 +712,4 @@ def parse_BatchNorm(tf_node, graph): ak_attr['scale_weights'] = np_scale.astype('float32') ak_attr['bias_weights'] = np_bias.astype('float32') - MedNodeUtil.retain_input(tf_node, [tf_node['input'][0]]) \ No newline at end of file + MedNodeUtil.retain_input(tf_node, [tf_node['input'][0]]) diff --git a/tools/external_converter_v2/parser/kill_tf/tf_util.py b/tools/external_converter_v2/parser/tensorflow/tf_util.py similarity index 83% rename from tools/external_converter_v2/parser/kill_tf/tf_util.py rename to tools/external_converter_v2/parser/tensorflow/tf_util.py index 8baed082d..b8dfe78d9 100644 --- a/tools/external_converter_v2/parser/kill_tf/tf_util.py +++ b/tools/external_converter_v2/parser/tensorflow/tf_util.py @@ -3,9 +3,17 @@ from google.protobuf import text_format import numpy as np + class TfUtil: @staticmethod def tf_run_model(graph_path, inputs, output_tensor_list): + ''' + fill inputs, run tensorflow mode and fetch output in output_tensor_list + :param graph_path: + :param inputs: + :param output_tensor_list: + :return: + ''' sess = tf.Session() if graph_path.endswith('.pbtxt'): input_binary = False @@ -30,4 +38,4 @@ def tf_run_model(graph_path, inputs, output_tensor_list): output_list = [graph.get_tensor_by_name(i) for i in output_tensor_list] print(output_list) out = sess.run(output_list, inputs_dict) - return out \ No newline at end of file + return out