}
};
+class DeconvolutionValidKerasSubgraph : public Subgraph
+{
+public:
+ DeconvolutionValidKerasSubgraph()
+ {
+ int input = addNodeToMatch("");
+ int shape = addNodeToMatch("Shape", input);
+ int kernel = addNodeToMatch("Const");
+
+ int stack = addNodeToMatch("Const");
+ int stack_1 = addNodeToMatch("Const");
+ int stack_2 = addNodeToMatch("Const");
+ int strided_slice = addNodeToMatch("StridedSlice", shape, stack, stack_1, stack_2);
+
+ stack = addNodeToMatch("Const");
+ stack_1 = addNodeToMatch("Const");
+ stack_2 = addNodeToMatch("Const");
+ int strided_slice_1 = addNodeToMatch("StridedSlice", shape, stack, stack_1, stack_2);
+
+ stack = addNodeToMatch("Const");
+ stack_1 = addNodeToMatch("Const");
+ stack_2 = addNodeToMatch("Const");
+ int strided_slice_2 = addNodeToMatch("StridedSlice", shape, stack, stack_1, stack_2);
+
+ int mul = addNodeToMatch("Mul", strided_slice_1, addNodeToMatch("Const"));
+ int add = addNodeToMatch("Add", mul, addNodeToMatch("Const"));
+
+ int mul_1 = addNodeToMatch("Mul", strided_slice_2, addNodeToMatch("Const"));
+ int add_1 = addNodeToMatch("Add", mul_1, addNodeToMatch("Const"));
+ int pack = addNodeToMatch("Pack", strided_slice, add, add_1, addNodeToMatch("Const"));
+ addNodeToMatch("Conv2DBackpropInput", pack, kernel, input);
+ // Put any unused Const op to the first input.
+ setFusedNode("Conv2DBackpropInput", stack, kernel, input);
+ }
+
+ virtual void finalize(tensorflow::GraphDef&, tensorflow::NodeDef* fusedNode,
+ std::vector<tensorflow::NodeDef*>& inputNodes) CV_OVERRIDE
+ {
+ // Disable adjusted paddings (see Conv2DBackpropInput layer at tf_importer.cpp)
+ // adj_w = (outW - (pad == "SAME") ? 1 : kernelW) % strideX;
+ // adj_h = (outH - (pad == "SAME") ? 1 : kernelH) % strideY;
+ // Where outH and outW are 1st and 2nd dimensions (NHWC) or 2nd and third (NCHW).
+ std::string padMode = fusedNode->attr().at("padding").s();
+ CV_Assert(padMode == "VALID");
+
+ const tensorflow::TensorShapeProto& kernelShape =
+ inputNodes[1]->mutable_attr()->at("value").tensor().tensor_shape();
+
+ CV_Assert(kernelShape.dim_size() == 4);
+ const int kernelHeight = kernelShape.dim(0).size();
+ const int kernelWidth = kernelShape.dim(1).size();
+
+ tensorflow::TensorProto* outShape = inputNodes[0]->mutable_attr()->at("value").mutable_tensor();
+ outShape->clear_int_val();
+ outShape->add_int_val(-1);
+ outShape->add_int_val(kernelHeight);
+ outShape->add_int_val(kernelWidth);
+ outShape->add_int_val(-1);
+ }
+};
+
+class DeconvolutionSameKerasSubgraph : public Subgraph
+{
+public:
+ DeconvolutionSameKerasSubgraph()
+ {
+ int input = addNodeToMatch("");
+ int shape = addNodeToMatch("Shape", input);
+ int kernel = addNodeToMatch("Const");
+
+ int stack = addNodeToMatch("Const");
+ int stack_1 = addNodeToMatch("Const");
+ int stack_2 = addNodeToMatch("Const");
+ int strided_slice = addNodeToMatch("StridedSlice", shape, stack, stack_1, stack_2);
+
+ stack = addNodeToMatch("Const");
+ stack_1 = addNodeToMatch("Const");
+ stack_2 = addNodeToMatch("Const");
+ int strided_slice_1 = addNodeToMatch("StridedSlice", shape, stack, stack_1, stack_2);
+
+ stack = addNodeToMatch("Const");
+ stack_1 = addNodeToMatch("Const");
+ stack_2 = addNodeToMatch("Const");
+ int strided_slice_2 = addNodeToMatch("StridedSlice", shape, stack, stack_1, stack_2);
+
+ int mul = addNodeToMatch("Mul", strided_slice_1, addNodeToMatch("Const"));
+
+ int mul_1 = addNodeToMatch("Mul", strided_slice_2, addNodeToMatch("Const"));
+ int pack = addNodeToMatch("Pack", strided_slice, mul, mul_1, addNodeToMatch("Const"));
+ addNodeToMatch("Conv2DBackpropInput", pack, kernel, input);
+ // Put any unused Const op to the first input.
+ setFusedNode("Conv2DBackpropInput", stack, kernel, input);
+ }
+
+ virtual void finalize(tensorflow::GraphDef&, tensorflow::NodeDef* fusedNode,
+ std::vector<tensorflow::NodeDef*>& inputNodes) CV_OVERRIDE
+ {
+ // Disable adjusted paddings (see Conv2DBackpropInput layer at tf_importer.cpp)
+ // adj_w = (outW - (pad == "SAME") ? 1 : kernelW) % strideX;
+ // adj_h = (outH - (pad == "SAME") ? 1 : kernelH) % strideY;
+ // Where outH and outW are 1st and 2nd dimensions (NHWC) or 2nd and third (NCHW).
+ std::string padMode = fusedNode->attr().at("padding").s();
+ CV_Assert(padMode == "SAME");
+
+ const tensorflow::AttrValue_ListValue& strides = fusedNode->attr().at("strides").list();
+ CV_Assert(strides.i_size() == 4);
+
+ const int strideY = strides.i(1);
+ const int strideX = strides.i(2);
+
+ tensorflow::TensorProto* outShape = inputNodes[0]->mutable_attr()->at("value").mutable_tensor();
+ outShape->clear_int_val();
+ outShape->add_int_val(-1);
+ outShape->add_int_val(strideY);
+ outShape->add_int_val(strideX);
+ outShape->add_int_val(-1);
+ }
+};
+
void simplifySubgraphs(tensorflow::GraphDef& net)
{
std::vector<Ptr<Subgraph> > subgraphs;
subgraphs.push_back(Ptr<Subgraph>(new ReLU6KerasSubgraph()));
subgraphs.push_back(Ptr<Subgraph>(new ReshapeKerasSubgraph(3)));
subgraphs.push_back(Ptr<Subgraph>(new L2NormalizeSubgraph()));
+ subgraphs.push_back(Ptr<Subgraph>(new DeconvolutionValidKerasSubgraph()));
+ subgraphs.push_back(Ptr<Subgraph>(new DeconvolutionSameKerasSubgraph()));
int numNodes = net.node_size();
std::vector<int> matchedNodesIds;