diff --git a/FAQ.md b/FAQ.md index 995df712fc330bcacd8e2206d9428ac60406341d..4c087d71feb93714d47076216146cece2e317651 100644 --- a/FAQ.md +++ b/FAQ.md @@ -2,3 +2,32 @@ **Q1. TensorFlow模型转换过程中,提示『Unknown shape for input tensor[tensor name: "input"], Please define shape of input here』?** A:该提示信息表示无法从TensorFlow的pb模型中获取到输入tensor(tensor名为"input:)的shape信息,所以需要用户手动在提示后输入详细的shape信息,如None,224,224,3 其中None表示Batch + + +**Q2. TensorFlow模型转换失败怎么解决?** +A: 目前TensorFlow模型转换失败存在几个问题。1) 存在暂未支持的OP,此信息会在转换时输出; 2) NHWC优化导致部分参数出错;3)Batch维度带来的出错 4)其它 + +对于(1)问题,建议自行添加或发起Issue; + +其中(2)、(3)、(4)问题目前没有明确的报错信息,当您遇到模型转换失败时,请尝试如下的步骤后,再进行转换测试 + +``` +x2paddle -f tensorflow -m tf.pb -s pd-model --without_data_format_optimization --define_input_shape +``` + +#### without_data_format_optimization : 关闭NHWC优化 +TensorFlow的CV模型,大多的输入格式为`NHWC`,而Paddle目前仅支持`NCHW`,如若直接转换,需要在conv2d、pool2d等操作前后添加transpose解决,这样会带来性能的损耗。X2Paddle在模型转换过程中,对此问题进行了优化,避免transpose操作带来的性能问题,但目前仅在部分模型上进行了测试,不一定适用于其它模型,因此,如若模型转换存在问题时,我们建议你关闭NHWC的优化。 + +在模型转换时添加参数 --without_data_format_optimization +``` +x2paddle -f tensorflow -m tf.pb -s pd-model --without_data_format_optimization +``` + +### define_input_shape : 固定Batch大小 +受限于不同框架的运行机制,在转换过程中,Batch维度也有一定可能会带来模型转换失败的问题。可以尝试固定Batch维度后再转换 + +在模型转换时添加参数 --define_input_shape +``` +x2paddle -f tensorflow -m tf.pb -s pd-model --define_input_shape +``` +如原tensorflow模型的输入shape为`[None, 224, 224, 3]`,可添加参数后,根据提示,把输入的shape修改为`[2, 224, 224, 3]` diff --git a/x2paddle/op_mapper/tf_op_mapper.py b/x2paddle/op_mapper/tf_op_mapper.py index ba33d6d25705b8764bd5633c4bc34bf002979407..87dfccfe893bc986c93af58fdfe60c04ae80b1ee 100644 --- a/x2paddle/op_mapper/tf_op_mapper.py +++ b/x2paddle/op_mapper/tf_op_mapper.py @@ -17,6 +17,7 @@ from x2paddle.core.op_mapper import OpMapper from x2paddle.core.util import * import inspect import numpy +import sys # compute padding size for SAME mode @@ -83,18 +84,31 @@ class TFOpMapper(OpMapper): del self.graph.input_nodes[idx] print("Total nodes: {}".format(len(self.graph.topo_sort))) + unsupported_ops = set() for node_name in self.graph.topo_sort: node = self.graph.get_node(node_name) op = node.layer_type if op in self.directly_map_ops: + if len(unsupported_ops) > 0: + continue self.directly_map(node) elif op in self.elementwise_ops: + if len(unsupported_ops) > 0: + continue self.elementwise_map(node) elif hasattr(self, op): + if len(unsupported_ops) > 0: + continue func = getattr(self, op) func(node) else: - raise Exception("OP: [{}] not support yet".format(op)) + unsupported_ops.add(op) + if len(unsupported_ops) > 0: + print("=========={} Ops are not supported yet======".format( + len(unsupported_ops))) + for op in unsupported_ops: + print("========== {} ==========".format(op)) + sys.exit(-1) def directly_map(self, node): assert node.layer_type in self.directly_map_ops @@ -773,7 +787,15 @@ class TFOpMapper(OpMapper): begin = [begin[i] for i in [0, 3, 1, 2]] end = [end[i] for i in [0, 3, 1, 2]] - attr = {"axes": range(len(strides)), "starts": begin, "ends": end} + for i in range(len(end)): + if end[i] == 0: + end[i] = 999999 + + attr = { + "axes": [i for i in range(len(strides))], + "starts": begin, + "ends": end + } node.fluid_code.add_layer("slice", inputs=input, output=node, @@ -955,3 +977,37 @@ class TFOpMapper(OpMapper): inputs=input, output=node, param_attr=attr) + + def ResizeNearestNeighbor(self, node): + input = self.graph.get_node(node.layer.input[0], copy=True) + resize_shape = self.graph.get_node(node.layer.input[1], copy=True) + self.omit_nodes.append(resize_shape.layer_name) + if resize_shape.layer_type == "Const": + resize_shape = resize_shape.value.tolist() + else: + resize_shape = self.decoder.infer_shape_tensor(resize_shape) + align_corners = node.get_attr("align_corners") + attr = {"align_corners": align_corners, "out_shape": resize_shape} + node.fluid_code.add_layer("resize_nearest", + inputs=input, + output=node, + param_attr=attr) + + def ResizeBilinear(self, node): + input = self.graph.get_node(node.layer.input[0], copy=True) + resize_shape = self.graph.get_node(node.layer.input[1], copy=True) + self.omit_nodes.append(resize_shape.layer_name) + if resize_shape.layer_type == "Const": + resize_shape = resize_shape.value.tolist() + else: + resize_shape = self.decoder.infer_shape_tensor(resize_shape) + align_corners = node.get_attr("align_corners") + attr = { + "align_corners": align_corners, + "out_shape": resize_shape, + "align_mode": 1 + } + node.fluid_code.add_layer("resize_bilinear", + inputs=input, + output=node, + param_attr=attr)