提交 b670c23e 编写于 作者: J jiangjiajun

modify program

上级 842108b5
...@@ -8,10 +8,10 @@ name_counter = dict() ...@@ -8,10 +8,10 @@ name_counter = dict()
def gen_name(op_name, var_name): def gen_name(op_name, var_name):
name = "{}.{}".format(op_name, var_name) name = "{}_{}".format(op_name, var_name)
if name not in name_counter: if name not in name_counter:
name_counter[name] = 0 name_counter[name] = 0
else: else:
name_counter[name] += 1 name_counter[name] += 1
name = name + "." + str(name_counter[name]) name = name + "_" + str(name_counter[name])
return name return name
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
# limitations under the License. # limitations under the License.
from six import text_type as _text_type from six import text_type as _text_type
from x2paddle import program
import argparse import argparse
import sys import sys
...@@ -120,29 +121,10 @@ def tf2paddle(model_path, ...@@ -120,29 +121,10 @@ def tf2paddle(model_path,
print("Now translating model from tensorflow to paddle.") print("Now translating model from tensorflow to paddle.")
model = TFDecoder(model_path, define_input_shape=define_input_shape) model = TFDecoder(model_path, define_input_shape=define_input_shape)
if not without_data_format_optimization:
mapper = TFOpMapper(model)
optimizer = TFOptimizer(mapper)
# neccesary optimization
optimizer.delete_redundance_code()
# optimizer below is experimental
optimizer.optimize_elementwise_op()
optimizer.merge_activation()
optimizer.merge_bias()
optimizer.optimize_sub_graph()
# optimizer.merge_batch_norm()
# optimizer.merge_prelu()
else:
mapper = TFOpMapperNHWC(model) mapper = TFOpMapperNHWC(model)
optimizer = TFOptimizer(mapper) program.build()
optimizer.delete_redundance_code() program.gen_model(save_dir)
optimizer.strip_graph()
optimizer.merge_activation()
optimizer.merge_bias()
optimizer.make_nchw_input_output()
optimizer.remove_transpose()
mapper.save_inference_model(save_dir, params_merge)
def caffe2paddle(proto, weight, save_dir, caffe_proto, params_merge=False): def caffe2paddle(proto, weight, save_dir, caffe_proto, params_merge=False):
......
...@@ -14,8 +14,13 @@ ...@@ -14,8 +14,13 @@
from __future__ import print_function from __future__ import print_function
from __future__ import division from __future__ import division
import paddle.fluid as fluid
from paddle.fluid.proto import framework_pb2
import numpy
import collections import collections
import sys
import os import os
import six
class PaddleLayer(object): class PaddleLayer(object):
...@@ -25,7 +30,21 @@ class PaddleLayer(object): ...@@ -25,7 +30,21 @@ class PaddleLayer(object):
dict), "parameter 'inputs' for PaddleLayer should be type of dict" dict), "parameter 'inputs' for PaddleLayer should be type of dict"
assert isinstance( assert isinstance(
outputs, outputs,
list), "parameter, 'outputs' for PaddleLayer should be type of list" list), "parameter 'outputs' for PaddleLayer should be type of list"
for k, v in inputs.items():
if isinstance(v, list):
for i in v:
assert isinstance(
i, six.string_types
), "value in inputs should be type of string or list of string"
else:
assert isinstance(v, six.string_types) or isinstance(
v, list
), "value in inputs should be type of string or list of string"
for v in outputs:
assert isinstance(
v, six.
string_types), "elements in outputs should be type of string"
self.kernel = kernel self.kernel = kernel
self.inputs = inputs self.inputs = inputs
self.outputs = outputs self.outputs = outputs
...@@ -41,22 +60,31 @@ class PaddleProgram(object): ...@@ -41,22 +60,31 @@ class PaddleProgram(object):
self.outputs = list() self.outputs = list()
self.parameters = dict() self.parameters = dict()
def clear(self):
self.layers = list()
self.edges_out = dict()
self.edges_in = dict()
self.inputs = list()
self.outputs = list()
self.parameters = dict()
def add_layer(self, kernel, inputs, outputs, **kwargs): def add_layer(self, kernel, inputs, outputs, **kwargs):
layer = PaddleLayer(kernel, inputs, outputs, **kwargs) layer = PaddleLayer(kernel, inputs, outputs, **kwargs)
index = len(self.layers)
self.layers.append(layer) self.layers.append(layer)
return index
def build(self): def build(self):
outputs = dict() outputs_from_nodes = dict()
for i in range(len(self.layers)): for i, layer in enumerate(self.layers):
layer = self.layers[i] for input_key, input_var in layer.inputs.items():
for output in layer.outputs: vs = input_var
outputs[output] = i if not isinstance(vs, list):
vs = [vs]
for k, v in layer.inputs.items(): for v in vs:
assert v in outputs, "Couldn't find {} in previous layers, the layers should be make by topological sort".format( assert v in outputs_from_nodes, "Couldn't find {} in previous layers, the layers should be make by topological sort".format(
v) v)
in_layer_index = outputs[v] in_layer_index = outputs_from_nodes[v]
if in_layer_index not in self.edges_out: if in_layer_index not in self.edges_out:
self.edges_out[in_layer_index] = list() self.edges_out[in_layer_index] = list()
self.edges_out[in_layer_index].append(i) self.edges_out[in_layer_index].append(i)
...@@ -64,6 +92,8 @@ class PaddleProgram(object): ...@@ -64,6 +92,8 @@ class PaddleProgram(object):
if i not in self.edges_in: if i not in self.edges_in:
self.edges_in[i] = list() self.edges_in[i] = list()
self.edges_in[i].append(in_layer_index) self.edges_in[i].append(in_layer_index)
for output in layer.outputs:
outputs_from_nodes[output] = i
def get_layer_outputs(self, i): def get_layer_outputs(self, i):
return self.edges_out[i] return self.edges_out[i]
...@@ -80,7 +110,9 @@ class PaddleProgram(object): ...@@ -80,7 +110,9 @@ class PaddleProgram(object):
else: else:
f.write(indent_blank + code_line + '\n') f.write(indent_blank + code_line + '\n')
f = open(os.path.join(code_dir, 'model.py'), 'w') if not os.path.exists(code_dir):
os.makedirs(code_dir)
f = open(os.path.join(code_dir, 'x2paddle_model.py'), 'w')
write_code( write_code(
f, [ f, [
...@@ -90,9 +122,10 @@ class PaddleProgram(object): ...@@ -90,9 +122,10 @@ class PaddleProgram(object):
"", "def x2paddle_net():" "", "def x2paddle_net():"
], ],
indent=0) indent=0)
for i, layer in enumerate(self.layers): for i, layer in enumerate(self.layers):
if self.edges_in.get(i, 0) == 0 and self.edges_out.get(i, 0) == 0: edges_in = self.edges_in.get(i, [])
edges_out = self.edges_out.get(i, [])
if len(edges_in) == 0 and len(edges_out) == 0:
continue continue
line = "" line = ""
...@@ -106,16 +139,87 @@ class PaddleProgram(object): ...@@ -106,16 +139,87 @@ class PaddleProgram(object):
line += " = {}(".format(layer.kernel) line += " = {}(".format(layer.kernel)
for k, v in layer.inputs.items(): for k, v in layer.inputs.items():
if isinstance(v, list):
line += "{}=[{}], ".format(k, ", ".join(v))
else:
line += "{}={}, ".format(k, v) line += "{}={}, ".format(k, v)
for k, v in layer.attrs.items(): for k, v in layer.attrs.items():
line += "{}={}, ".format(k, v) line += "{}={}, ".format(k, v)
line = line.strip(", ") line = line.strip(", ")
line += ")" line += ")"
write_code(f, [line], indent=1) write_code(f, [line], indent=1)
f.close()
def gen_parameters(self, code_dir): write_code(
pass f, [
"return [{}], [{}]".format(", ".join(self.inputs),
", ".join(self.outputs))
],
indent=1)
f.close()
def gen_inference_model(self, model_dir): def gen_model(self, save_dir):
pass code_dir = os.path.join(save_dir, 'model_with_code')
infer_dir = os.path.join(save_dir, 'inference_model')
self.gen_code(code_dir)
sys.path.append(code_dir)
import x2paddle_model
scope = fluid.Scope()
startup_program = fluid.Program()
main_program = fluid.Program()
with fluid.scope_guard(scope):
with fluid.program_guard(main_program, startup_program):
inputs, outputs = x2paddle_model.x2paddle_net()
exe = fluid.Executor(fluid.CPUPlace())
exe.run(startup_program)
param_dir = os.path.join(code_dir, 'weights')
for k, v in self.parameters.items():
if scope.find_var(k):
self.dump_parameter(k, v, param_dir)
def if_exist(var):
b = os.path.exists(
os.path.join(os.path.join(param_dir, var.name)))
return b
fluid.io.load_vars(
exe, param_dir, main_program, predicate=if_exist)
fluid.io.save_inference_model(
dirname=infer_dir,
feeded_var_names=[i.name for i in inputs],
target_vars=outputs,
executor=exe)
def dump_parameter(self, param_name, param, save_dir):
if not os.path.exists(save_dir):
os.makedirs(save_dir)
dtype_map = {
"int16": [framework_pb2.VarType.INT16, 'h'],
"int32": [framework_pb2.VarType.INT32, 'i'],
"int64": [framework_pb2.VarType.INT64, 'q'],
"float16": [framework_pb2.VarType.FP16, 'e'],
"float32": [framework_pb2.VarType.FP32, 'f'],
"float64": [framework_pb2.VarType.FP64, 'd'],
"bool": [framework_pb2.VarType.BOOL, None]
}
shape = param.shape
if str(param.dtype) in ['uint8', 'uint_8', 'bool']:
param = param.astype('int64')
if len(shape) == 0:
assert param.size == 1, "Unexpected situation happend!"
shape = [1]
assert str(
param.dtype) in dtype_map, "Unknown dtype {} of params: {}.".format(
str(param.dtype), param_name)
fp = open(os.path.join(save_dir, param_name), 'wb')
numpy.array([0], dtype='int32').tofile(fp)
numpy.array([0], dtype='int64').tofile(fp)
numpy.array([0], dtype='int32').tofile(fp)
tensor_desc = framework_pb2.VarType.TensorDesc()
tensor_desc.data_type = dtype_map[str(param.dtype)][0]
tensor_desc.dims.extend(shape)
desc_size = tensor_desc.ByteSize()
numpy.array([desc_size], dtype='int32').tofile(fp)
fp.write(tensor_desc.SerializeToString())
param.tofile(fp)
fp.close()
...@@ -89,6 +89,16 @@ class TFGraphNode(GraphNode): ...@@ -89,6 +89,16 @@ class TFGraphNode(GraphNode):
field = getattr(attr, attr.WhichOneof('value')) field = getattr(attr, attr.WhichOneof('value'))
return tensor_util.MakeNdarray(field) return tensor_util.MakeNdarray(field)
@property
def name(self):
multi_out_ops = ['Split', 'SplitV', 'IteratorV2']
if self.layer_type in multi_out_ops:
if self.layer_name.count(':') > 0:
return self.layer_name.replace(':', '_p')
else:
return "{}_p0".format(self.layer_name)
return self.layer_name
def get_attr(self, name): def get_attr(self, name):
if name not in self.layer.attr: if name not in self.layer.attr:
return None return None
......
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
from x2paddle.decoder.tf_decoder import TFGraph from x2paddle.decoder.tf_decoder import TFGraph
from x2paddle.core.op_mapper import OpMapper from x2paddle.core.op_mapper import OpMapper
from x2paddle.core.util import * from x2paddle.core.util import *
from x2paddle import program
from x2paddle import gen_name
import traceback
import math import math
import inspect import inspect
import numpy import numpy
...@@ -36,7 +39,6 @@ class TFOpMapperNHWC(OpMapper): ...@@ -36,7 +39,6 @@ class TFOpMapperNHWC(OpMapper):
directly_map_ops = { directly_map_ops = {
'Relu': ['relu'], 'Relu': ['relu'],
'Relu6': ['relu6'], 'Relu6': ['relu6'],
'Shape': ['shape'],
'Abs': ['abs'], 'Abs': ['abs'],
'Sigmoid': ['sigmoid'], 'Sigmoid': ['sigmoid'],
'Exp': ['exp'], 'Exp': ['exp'],
...@@ -59,6 +61,7 @@ class TFOpMapperNHWC(OpMapper): ...@@ -59,6 +61,7 @@ class TFOpMapperNHWC(OpMapper):
'Maximum': 'elementwise_max', 'Maximum': 'elementwise_max',
'Minimum': 'elementwise_min', 'Minimum': 'elementwise_min',
'LessEqual': 'less_equal', 'LessEqual': 'less_equal',
'GreaterEqual': 'greater_equal',
'Mul': 'elementwise_mul', 'Mul': 'elementwise_mul',
'FloorDiv': 'elementwise_floordiv' 'FloorDiv': 'elementwise_floordiv'
} }
...@@ -68,9 +71,9 @@ class TFOpMapperNHWC(OpMapper): ...@@ -68,9 +71,9 @@ class TFOpMapperNHWC(OpMapper):
self.decoder = decoder self.decoder = decoder
self.graph = decoder.tf_graph self.graph = decoder.tf_graph
self.weights = dict() self.weights = dict()
self.batch_node = None
self.omit_nodes = list() self.omit_nodes = list()
self.used_custom_layers = dict() self.used_custom_layers = dict()
program.clear()
not_placeholder = list() not_placeholder = list()
for name in self.graph.input_nodes: for name in self.graph.input_nodes:
...@@ -84,6 +87,9 @@ class TFOpMapperNHWC(OpMapper): ...@@ -84,6 +87,9 @@ class TFOpMapperNHWC(OpMapper):
idx = self.graph.input_nodes.index(name) idx = self.graph.input_nodes.index(name)
del self.graph.input_nodes[idx] del self.graph.input_nodes[idx]
program.inputs = self.graph.input_nodes
program.outputs = self.graph.output_nodes
unsupported_ops = set() unsupported_ops = set()
sys.stderr.write("Total nodes: {}\n".format(len(self.graph.topo_sort))) sys.stderr.write("Total nodes: {}\n".format(len(self.graph.topo_sort)))
for i, node_name in enumerate(self.graph.topo_sort): for i, node_name in enumerate(self.graph.topo_sort):
...@@ -106,30 +112,21 @@ class TFOpMapperNHWC(OpMapper): ...@@ -106,30 +112,21 @@ class TFOpMapperNHWC(OpMapper):
func(node) func(node)
except Exception as e: except Exception as e:
unsupported_ops.add(op) unsupported_ops.add(op)
print(e) print("\n{}\n".format(traceback.format_exc()))
else: else:
unsupported_ops.add(op) unsupported_ops.add(op)
if len(unsupported_ops) > 0: if len(unsupported_ops) > 0:
print("========= {} OPs are not supported yet ===========".format( print("\n========= {} OPs are not supported yet ===========".format(
len(unsupported_ops))) len(unsupported_ops)))
for op in unsupported_ops: for op in unsupported_ops:
print("========== {} ============".format(op)) print("========== {} ============".format(op))
sys.exit(-1) sys.exit(-1)
sys.stderr.write("\nDone!\n") sys.stderr.write("\nDone!\n")
def add_omit_nodes(self, in_node_name, out_node_name):
in_node = self.graph.get_node(in_node_name)
out_node = self.graph.get_node(out_node_name)
index = in_node.outputs.index(out_node_name)
del in_node.outputs[index]
index = out_node.inputs.index(in_node_name)
del out_node.inputs[index]
self.omit_nodes.append(in_node.layer_name)
def directly_map(self, node): def directly_map(self, node):
assert node.layer_type in self.directly_map_ops assert node.layer_type in self.directly_map_ops
op_info = self.directly_map_ops[node.layer_type] op_info = self.directly_map_ops[node.layer_type]
input = self.graph.get_node(node.layer.input[0], copy=True) input = self.graph.get_node(node.layer.input[0])
attr = dict() attr = dict()
for param in op_info[1:]: for param in op_info[1:]:
tf_param_name = list(param.keys())[0] tf_param_name = list(param.keys())[0]
...@@ -137,46 +134,35 @@ class TFOpMapperNHWC(OpMapper): ...@@ -137,46 +134,35 @@ class TFOpMapperNHWC(OpMapper):
tf_param = node.get_attr(tf_param_name) tf_param = node.get_attr(tf_param_name)
attr[pd_param_name] = tf_param attr[pd_param_name] = tf_param
if len(input.out_shapes[0]) == 4 and op_info[0] != 'shape': program.add_layer(
attr1 = {"perm": [0, 3, 1, 2]} kernel="fluid.layers.{}".format(op_info[0]),
node.fluid_code.add_layer( inputs={"x": input.name},
'transpose', inputs=input, output=node, param_attr=attr1) outputs=[node.name],
input = node **attr)
node.fluid_code.add_layer(
op_info[0], inputs=input, output=node, param_attr=attr)
input = node
attr2 = {"perm": [0, 2, 3, 1]}
node.fluid_code.add_layer(
'transpose', inputs=input, output=node, param_attr=attr2)
else:
node.fluid_code.add_layer(
op_info[0], inputs=input, output=node, param_attr=attr)
def elementwise_map(self, node): def elementwise_map(self, node):
assert node.layer_type in self.elementwise_ops assert node.layer_type in self.elementwise_ops
op_type = self.elementwise_ops[node.layer_type] op_type = self.elementwise_ops[node.layer_type]
x = self.graph.get_node(node.layer.input[0], copy=True) x = self.graph.get_node(node.layer.input[0])
y = self.graph.get_node(node.layer.input[1], copy=True) y = self.graph.get_node(node.layer.input[1])
inputs = {"x": x, "y": y} program.add_layer(
node.fluid_code.add_layer( kernel="fluid.layers.{}".format(op_type),
op_type, inputs=inputs, output=node, param_attr=None) inputs={"x": x.name,
"y": y.name},
outputs=[node.name])
def Placeholder(self, node): def Placeholder(self, node):
shape = node.out_shapes[0] shape = node.out_shapes[0]
assert len(shape) != 0, "Unknown shape of input nodes[{}].".format( assert len(shape) != 0, "Unknown shape of input nodes[{}].".format(
node.layer_name) node.layer_name)
dtype = node.dtype dtype = node.dtype
if shape[0] < 0: program.add_layer(
self.batch_node = node kernel="fluid.data",
attr = { inputs={},
'dtype': string(dtype), outputs=[node.name],
'shape': shape, dtype=string(dtype),
'name': string(node.layer_name), shape=shape,
'append_batch_size': False name=string(node.name))
}
node.fluid_code.add_layer(
"data", inputs=None, output=node, param_attr=attr)
def Const(self, node): def Const(self, node):
shape = node.out_shapes[0] shape = node.out_shapes[0]
...@@ -188,74 +174,94 @@ class TFOpMapperNHWC(OpMapper): ...@@ -188,74 +174,94 @@ class TFOpMapperNHWC(OpMapper):
shape = [1] shape = [1]
initializer = "Constant({})".format(value) initializer = "Constant({})".format(value)
self.weights[node.layer_name] = node.value program.parameters[node.name] = node.value
program.add_layer(
attr = { kernel="fluid.layers.create_parameter",
'dtype': string(dtype), inputs={},
'shape': shape, outputs=[node.name],
'name': string(node.layer_name), dtype=string(dtype),
'default_initializer': initializer shape=shape,
} name=string(node.name),
node.fluid_code.add_layer( default_initializer=initializer)
"create_parameter", inputs=None, output=node, param_attr=attr)
def Transpose(self, node): def Transpose(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True) input = self.graph.get_node(node.layer.input[0])
perm = self.graph.get_node(node.layer.input[1], copy=True) perm = self.graph.get_node(node.layer.input[1])
assert perm.layer_type == "Const", "Perm of transpose OP should be Const" assert perm.layer_type == "Const", "Perm of transpose OP should be Const"
del self.weights[perm.layer_name.replace('/', '_')]
perm.fluid_code.clear()
perm = perm.value.tolist() perm = perm.value.tolist()
attr = {'perm': perm} program.add_layer(
node.fluid_code.add_layer( kernel="fluid.layers.transpose",
"transpose", inputs=input, output=node, param_attr=attr) inputs={"x": input.name},
outputs=[node.name],
perm=perm)
def Fill(self, node): def Fill(self, node):
dims = self.graph.get_node(node.layer.input[0], copy=True) dims = self.graph.get_node(node.layer.input[0], copy=True)
input_value = self.graph.get_node(node.layer.input[1], copy=True) input_value = self.graph.get_node(node.layer.input[1], copy=True)
assert input_value.layer_type == "Const", "Value of fill OP should be Const" assert input_value.layer_type == "Const", "Value of fill OP should be Const"
self.add_omit_nodes(input_value.layer_name, node.layer_name)
input_value = input_value.value input_value = input_value.value
input_dtype = string(input_value.dtype) input_dtype = string(input_value.dtype)
attr = {'value': input_value, 'dtype': input_dtype} program.add_layer(
"fluid.layers.fill_constant",
node.fluid_code.add_layer( inputs={},
"fill_constant", inputs=dims, output=node, param_attr=attr) outputs=[node.name],
shape=dims,
dtype=string(input_dtype),
value=input_value)
def DepthToSpace(self, node): def DepthToSpace(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True) input = self.graph.get_node(node.layer.input[0], copy=True)
block_size = node.get_attr("block_size") block_size = node.get_attr("block_size")
data_format = node.get_attr("data_format").decode() data_format = node.get_attr("data_format").decode()
if data_format == "NHWC":
attr = {"perm": [0, 3, 1, 2]}
node.fluid_code.add_layer(
"transpose", inputs=input, output=input, param_attr=attr)
n, h, w, c = input.out_shapes[0] n, h, w, c = input.out_shapes[0]
attr = {'shape': [0, block_size * block_size, -1, h, w]} input_name = input.name
node.fluid_code.add_layer( if data_format == "NHWC":
"reshape", inputs=input, output=input, param_attr=attr) transpose_name = gen_name("depth_to_space", "transpose")
program.add_layer(
attr = {'perm': [0, 2, 1, 3, 4]} kernel="fluid.layers.transpose",
node.fluid_code.add_layer( inputs={"x": input.name},
"transpose", inputs=input, output=input, param_attr=attr) outputs=[transpose_name],
attr = {'shape': [0, c, h, w]} perm=[0, 3, 1, 2])
node.fluid_code.add_layer( input_name = transpose_name
"reshape", inputs=input, output=input, param_attr=attr)
shape = [0, block_size * block_size, -1, h, w]
attr = {'upscale_factor': block_size} reshape_name = gen_name("depth_to_space", "reshape")
node.fluid_code.add_layer( program.add_layer(
"pixel_shuffle", inputs=input, output=node, param_attr=attr) kernel="fluid.layers.reshape",
inputs={"x": input_name},
outputs=[reshape_name],
shape=shape)
transpose_name = gen_name("depth_to_space", "transpose")
program.add_layer(
kernel="fluid.layers.transpose",
inputs={"x": reshape_name},
outputs=[transpose_name],
perm=[0, 2, 1, 3, 4])
reshape_name = gen_name("depth_to_space", "reshape")
program.add_layer(
kernel="fluid.layers.reshape",
inputs={"x": transpose_name},
outputs=[reshape_name],
shape=[0, c, h, w])
program.add_layer(
kernel="fluid.layers.pixed_shuffle",
inputs={"input": reshape_name},
outputs=[node.name],
upscale_factor=block_size)
if data_format == "NHWC": if data_format == "NHWC":
attr = {"perm": [0, 2, 3, 1]} program.add_layer(
node.fluid_code.add_layer( kernel="fluid.layers.transpose",
"transpose", inputs=node, output=node, param_attr=attr) inputs={"x": node.name},
outputs=[node.name],
perm=[0, 2, 3, 1])
def MaxPool(self, node): def MaxPool(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True) input = self.graph.get_node(node.layer.input[0], copy=True)
...@@ -264,41 +270,44 @@ class TFOpMapperNHWC(OpMapper): ...@@ -264,41 +270,44 @@ class TFOpMapperNHWC(OpMapper):
strides = node.get_attr("strides") strides = node.get_attr("strides")
data_format = node.get_attr("data_format").decode() data_format = node.get_attr("data_format").decode()
pad_mode = node.get_attr("padding").decode() pad_mode = node.get_attr("padding").decode()
channel_first = data_format == "NCHW"
if not channel_first: input_name = input.name
attr = {"perm": [0, 3, 1, 2]} if data_format == "NHWC":
node.fluid_code.add_layer( transpose_name = gen_name("max_pool", "transpose")
"transpose", inputs=input, output=node, param_attr=attr) program.add_layer(
kernel="fluid.layers.transpose",
inputs={"x": input.name},
outputs=[transpose_name],
perm=[0, 3, 1, 2])
strides = [strides[i] for i in [0, 3, 1, 2]] strides = [strides[i] for i in [0, 3, 1, 2]]
k_size = [k_size[i] for i in [0, 3, 1, 2]] k_size = [k_size[i] for i in [0, 3, 1, 2]]
input = node input_name = transpose_name
attr = { program.add_layer(
"pool_size": k_size[2:4], kernel="fluid.layers.pool2d",
"pool_type": string("max"), inputs={"input": input_name},
"pool_stride": strides[2:4], outputs=[node.name],
"pool_padding": string(pad_mode) pool_size=k_size[2:4],
} pool_type=string("max"),
node.fluid_code.add_layer( pool_stride=strides[2:4],
"pool2d", inputs=input, output=node, param_attr=attr) pool_padding=string(pad_mode))
if not channel_first: if data_format == "NHWC":
attr = {"perm": [0, 2, 3, 1]} program.add_layer(
node.fluid_code.add_layer( kernel="fluid.layers.transpose",
"transpose", inputs=node, output=node, param_attr=attr) inputs={"x": node.name},
outputs=[node.name],
perm=[0, 2, 3, 1])
def Conv2D(self, node): def Conv2D(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True) input = self.graph.get_node(node.layer.input[0])
kernel = self.graph.get_node(node.layer.input[1], copy=True) kernel = self.graph.get_node(node.layer.input[1])
self.add_omit_nodes(kernel.layer_name, node.layer_name)
k_size = kernel.out_shapes[0] k_size = kernel.out_shapes[0]
strides = node.get_attr("strides") strides = node.get_attr("strides")
dilations = node.get_attr("dilations") dilations = node.get_attr("dilations")
data_format = node.get_attr("data_format").decode() data_format = node.get_attr("data_format").decode()
pad_mode = node.get_attr("padding").decode() pad_mode = node.get_attr("padding").decode()
channel_first = data_format == "NCHW"
if kernel.layer_type == 'Const': if kernel.layer_type == 'Const':
kernel_value = kernel.value kernel_value = kernel.value
...@@ -310,369 +319,330 @@ class TFOpMapperNHWC(OpMapper): ...@@ -310,369 +319,330 @@ class TFOpMapperNHWC(OpMapper):
kernel.layer_name) kernel.layer_name)
else: else:
kernel_weight_name = kernel.layer_name.replace('/', '_') kernel_weight_name = kernel.layer_name.replace('/', '_')
self.weights[kernel_weight_name] = numpy.transpose(kernel_value, program.parameters[kernel_weight_name] = numpy.transpose(kernel_value,
(3, 2, 0, 1)) (3, 2, 0, 1))
if not channel_first: input_name = input.name
if data_format == "NHWC":
strides = [strides[i] for i in [0, 3, 1, 2]] strides = [strides[i] for i in [0, 3, 1, 2]]
dilations = [dilations[i] for i in [0, 3, 1, 2]] dilations = [dilations[i] for i in [0, 3, 1, 2]]
attr = {"perm": [0, 3, 1, 2]} transpose_name = gen_name("conv2d", "transpose")
node.fluid_code.add_layer( program.add_layer(
"transpose", inputs=input, output=node, param_attr=attr) kernel="fluid.layers.transpose",
input = node inputs={"x": input.name},
attr = { outputs=[transpose_name],
"bias_attr": False, perm=[0, 3, 1, 2])
"param_attr": string(kernel_weight_name), input_name = transpose_name
"num_filters": k_size[3],
"filter_size": k_size[0:2], program.add_layer(
"stride": strides[2:4], kernel="fluid.layers.conv2d",
"dilation": dilations[2:4], inputs={"input": input_name},
"padding": string(pad_mode) outputs=[node.name],
} bias_attr=False,
param_attr=string(kernel_weight_name),
num_filters=k_size[3],
filter_size=k_size[0:2],
stride=strides[2:4],
dilation=dilations[2:4],
padding=string(pad_mode))
if hasattr(node, 'dilation') and attr['dilation'] == [1, 1]: if data_format == "NHWC":
if len(node.dilation) == 1: program.add_layer(
attr['dilation'] = [1, node.dilation[0]] kernel="fluid.layers.transpose",
node.fluid_code.add_layer( inputs={"x": node.name},
"conv2d", inputs=input, output=node, param_attr=attr) outputs=[node.name],
if not channel_first: perm=[0, 2, 3, 1])
attr = {"perm": [0, 2, 3, 1]}
node.fluid_code.add_layer(
"transpose", inputs=node, output=node, param_attr=attr)
def BiasAdd(self, node): def BiasAdd(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True) input = self.graph.get_node(node.layer.input[0])
bias = self.graph.get_node(node.layer.input[1], copy=True) bias = self.graph.get_node(node.layer.input[1])
inputs = {"x": input, "y": bias} program.add_layer(
node.fluid_code.add_layer( kernel="fluid.layers.elementwise_add",
"elementwise_add", inputs=inputs, output=node, param_attr=None) inputs={"x": input.name,
"y": bias.name},
outputs=[node.name])
def FusedBatchNorm(self, node): def FusedBatchNorm(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True) input = self.graph.get_node(node.layer.input[0])
gamma = self.graph.get_node(node.layer.input[1], copy=True) gamma = self.graph.get_node(node.layer.input[1])
beta = self.graph.get_node(node.layer.input[2], copy=True) beta = self.graph.get_node(node.layer.input[2])
moving_mean = self.graph.get_node(node.layer.input[3], copy=True) moving_mean = self.graph.get_node(node.layer.input[3])
moving_var = self.graph.get_node(node.layer.input[4], copy=True) moving_var = self.graph.get_node(node.layer.input[4])
data_format = node.get_attr("data_format").decode() data_format = node.get_attr("data_format").decode()
channel_first = data_format == "NCHW"
assert gamma.layer_type == "Const" assert gamma.layer_type == "Const"
assert beta.layer_type == "Const" assert beta.layer_type == "Const"
assert moving_mean.layer_type == "Const" assert moving_mean.layer_type == "Const"
assert moving_var.layer_type == "Const" assert moving_var.layer_type == "Const"
self.add_omit_nodes(gamma.layer_name, node.layer_name)
self.add_omit_nodes(beta.layer_name, node.layer_name)
self.add_omit_nodes(moving_mean.layer_name, node.layer_name)
self.add_omit_nodes(moving_var.layer_name, node.layer_name)
if not channel_first:
attr = {"perm": [0, 3, 1, 2]}
node.fluid_code.add_layer(
"transpose", inputs=input, output=node, param_attr=attr)
input = node
attr = {
"epsilon": node.get_attr("epsilon"),
"param_attr": string(gamma.layer_name),
"bias_attr": string(beta.layer_name),
"moving_mean_name": string(moving_mean.layer_name),
"moving_variance_name": string(moving_var.layer_name),
"is_test": True
}
node.fluid_code.add_layer(
"batch_norm", inputs=input, output=node, param_attr=attr)
if not channel_first:
attr = {"perm": [0, 2, 3, 1]}
node.fluid_code.add_layer(
"transpose", inputs=node, output=node, param_attr=attr)
def DepthwiseConv2dNative(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True)
kernel = self.graph.get_node(node.layer.input[1], copy=True)
assert kernel.layer_type == "Const", "Kernel of DepthwiseConv2DNative should be Const"
self.add_omit_nodes(kernel.layer_name, node.layer_name)
in_shape = input.out_shapes[0] input_name = input.name
k_size = kernel.out_shapes[0] if data_format == "NHWC":
strides = node.get_attr("strides") transpose_name = gen_name("batch_norm", "transpose")
dilations = node.get_attr("dilations") program.add_layer(
data_format = node.get_attr("data_format").decode() kernel="fluid.layers.transpose",
pad_mode = node.get_attr("padding").decode() inputs={"x": input.name},
channel_first = data_format == "NCHW" outputs=[transpose_name],
perm=[0, 3, 1, 2])
input_name = transpose_name
program.add_layer(
kernel="fluid.layers.batch_norm",
inputs={"input": input_name},
outputs=[node.name],
epsilon=node.get_attr("epsilon"),
param_attr=string(gamma.name),
bias_attr=string(beta.name),
moving_mean_name=string(moving_mean.name),
moving_variance_name=string(moving_var.name),
is_test=True)
self.weights[kernel.layer_name.replace('/', '_')] = numpy.transpose( if data_format == "NHWC":
kernel.value, (2, 3, 0, 1)) program.add_layer(
kernel="fluid.layers.transpose",
inputs={"x": node.name},
outputs=[node.name],
perm=[0, 2, 3, 1])
if not channel_first: def Mean(self, node):
in_shape = [in_shape[i] for i in [0, 3, 1, 2]] input = self.graph.get_node(node.layer.input[0])
strides = [strides[i] for i in [0, 3, 1, 2]] reduce_idx = self.graph.get_node(node.layer.input[1])
dilations = [dilations[i] for i in [0, 3, 1, 2]] assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]"
attr = {"perm": [0, 3, 1, 2]} dims = reduce_idx.value.tolist()
node.fluid_code.add_layer( keep_dims = node.get_attr("keep_dims")
"transpose", inputs=input, output=node, param_attr=attr)
input = node
attr = {
"bias_attr": False,
"param_attr": string(kernel.layer_name),
"num_filters": in_shape[1],
"filter_size": k_size[0:2],
"stride": strides[2:4],
"dilation": dilations[2:4],
"groups": k_size[3] * in_shape[1],
"use_cudnn": False,
"padding": string(pad_mode)
}
node.fluid_code.add_layer(
"conv2d", inputs=input, output=node, param_attr=attr)
if not channel_first: program.add_layer(
attr = {"perm": [0, 2, 3, 1]} kernel="fluid.layers.reduce_mean",
node.fluid_code.add_layer( inputs={"input": input.name},
"transpose", inputs=node, output=node, param_attr=attr) outputs=[node.name],
dim=dims,
keep_dim=keep_dims)
def Reshape(self, node): def Reshape(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True) input = self.graph.get_node(node.layer.input[0])
param = self.graph.get_node(node.layer.input[1], copy=True) param = self.graph.get_node(node.layer.input[1])
if param.layer_type == "Const": if param.layer_type == "Const":
self.add_omit_nodes(param.layer_name, node.layer_name)
shape = param.value.tolist() shape = param.value.tolist()
program.add_layer(
kernel="fluid.layers.reshape",
inputs={"x": input.name},
outputs=[node.name],
shape=shape)
else: else:
shape = param program.add_layer(
inputs = {"x": input, "shape": shape} kernel="fluid.layers.reshape",
node.fluid_code.add_layer( inputs={"x": input.name,
"reshape", inputs=inputs, output=node, param_attr=None) "shape": param.name},
outputs=[node.name])
if param.layer_type != "Const": if param.layer_type != "Const":
out_shape = numpy.array(node.out_shapes[0]) out_shape = numpy.array(node.out_shapes[0])
if (out_shape > 0).any(): if (out_shape > 0).any():
out_shape[out_shape < 0] = 0 out_shape[out_shape < 0] = 0
attr = {'shape': out_shape.tolist()} program.add_layer(
node.fluid_code.add_layer( kernel="fluid.layers.reshape",
"reshape", inputs=node, output=node, param_attr=attr) inputs={"x": node.name},
outputs=[node.name],
def AvgPool(self, node): shape=out_shape.tolist())
input = self.graph.get_node(node.layer.input[0], copy=True)
k_size = node.get_attr("ksize")
strides = node.get_attr("strides")
data_format = node.get_attr("data_format").decode()
pad_mode = node.get_attr("padding").decode()
channel_first = data_format == "NCHW"
if not channel_first:
strides = [strides[i] for i in [0, 3, 1, 2]]
k_size = [k_size[i] for i in [0, 3, 1, 2]]
attr = {"perm": [0, 3, 1, 2]}
node.fluid_code.add_layer(
"transpose", inputs=input, output=node, param_attr=attr)
input = node
attr = {
"pool_size": k_size[2:4],
"pool_type": string("avg"),
"pool_stride": strides[2:4],
"pool_padding": string(pad_mode)
}
node.fluid_code.add_layer(
"pool2d", inputs=input, output=node, param_attr=attr)
if not channel_first:
attr = {"perm": [0, 2, 3, 1]}
node.fluid_code.add_layer(
"transpose", inputs=node, output=node, param_attr=attr)
def SplitV(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True)
num_sections = self.graph.get_node(node.layer.input[1], copy=True)
dim = self.graph.get_node(node.layer.input[2], copy=True)
assert num_sections.layer_type == "Const"
assert dim.layer_type == "Const"
self.add_omit_nodes(num_sections.layer_name, node.layer_name)
self.add_omit_nodes(dim.layer_name, node.layer_name)
dim = dim.value
attr = {
"num_or_sections": num_sections.value.tolist(),
"dim": dim.value
}
node.fluid_code.add_layer(
"split", inputs=input, output=node, param_attr=attr)
def ConcatV2(self, node):
inputs = [
self.graph.get_node(
name, copy=True) for name in node.layer.input[:-1]
]
axis = self.graph.get_node(node.layer.input[-1], copy=True)
assert axis.layer_type == "Const"
self.add_omit_nodes(axis.layer_name, node.layer_name)
axis = axis.value
if axis < 0:
axis += len(inputs[0].out_shapes[0])
attr = {"axis": axis}
node.fluid_code.add_layer(
"concat", inputs=inputs, output=node, param_attr=attr)
def Tile(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True)
expand_times = self.graph.get_node(node.layer.input[1], copy=True)
if expand_times.layer_type == "Const":
self.add_omit_nodes(expand_times.layer_name, node.layer_name)
expand_times = expand_times.value.tolist()
else:
expand_times = expand_times
inputs = {"x": input, "expand_times": expand_times}
node.fluid_code.add_layer(
"expand", inputs=inputs, output=node, param_attr=None)
def Pack(self, node):
inputs = [
self.graph.get_node(
name, copy=True) for name in node.layer.input
]
reshape_shape = list()
for input_node in inputs:
k_size = input_node.out_shapes[0]
if len(k_size) and k_size[-1] != -1:
reshape_shape = [0] * len(k_size)
reshape_shape[-1] = k_size[-1]
break
if len(reshape_shape):
for i, input_node in enumerate(inputs):
node.fluid_code.add_layer(
"reshape",
inputs=input_node,
output='tmp_{}'.format(i),
param_attr={"shape": reshape_shape})
axis = node.get_attr("axis")
attr = {"axis": axis}
if len(reshape_shape):
inputs = ['tmp_{}'.format(i) for i in range(len(inputs))]
node.fluid_code.add_layer(
"stack", inputs=inputs, output=node, param_attr=attr)
def Pad(self, node): def Pad(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True) input = self.graph.get_node(node.layer.input[0])
paddings = self.graph.get_node(node.layer.input[1], copy=True) paddings = self.graph.get_node(node.layer.input[1])
assert paddings.layer_type == "Const", "Padding should be Const" assert paddings.layer_type == "Const", "Padding should be Const"
self.add_omit_nodes(paddings.layer_name, node.layer_name)
paddings = paddings.value.flatten().tolist() paddings = paddings.value.flatten().tolist()
data_format = input.tf_data_format
if len(input.out_shapes[0]) == 4: if len(input.out_shapes[0]) == 4:
new_padding = None
if input.tf_data_format == "NHWC":
if paddings[0] + paddings[1] + paddings[6] + paddings[7] == 0: if paddings[0] + paddings[1] + paddings[6] + paddings[7] == 0:
new_padding = paddings[2:6] new_padding = paddings[2:6]
else: transpose_name = gen_name("pad", "transpose")
if paddings[0] + paddings[1] + paddings[2] + paddings[3] == 0: program.add_layer(
new_padding = paddings[4:] kernel="fluid.layers.transpose",
if new_padding is not None: inputs={"x": input.name},
if input.tf_data_format == "NHWC": outputs=[transpose_name],
attr = {"perm": [0, 3, 1, 2]} perm=[0, 3, 1, 2])
node.fluid_code.add_layer( program.add_layer(
"transpose", inputs=input, output=node, param_attr=attr) kernel="fluid.layers.pad2d",
input = node inputs={"input": transpose_name},
attr = {"paddings": new_padding} outputs=[node.name],
node.fluid_code.add_layer( paddings=new_padding)
"pad2d", inputs=input, output=node, param_attr=attr) program.add_layer(
if input.tf_data_format == "NHWC": kernel="fluid.layers.transpose",
attr = {"perm": [0, 2, 3, 1]} inputs={"x": node.name},
node.fluid_code.add_layer( outputs=[node.name],
"transpose", inputs=node, output=node, param_attr=attr) perm=[0, 2, 3, 1])
return return
attr = {"paddings": paddings} program.add_layer(
node.fluid_code.add_layer( kernel="fluid.layers.pad",
"pad", inputs=input, output=node, param_attr=attr) inputs={"input": input.name},
outputs=[node.name],
def Range(self, node): paddings=paddings)
start = self.graph.get_node(node.layer.input[0], copy=True)
limit = self.graph.get_node(node.layer.input[1], copy=True)
delta = self.graph.get_node(node.layer.input[2], copy=True)
if start.layer_type == "Const":
self.add_omit_nodes(start.layer_name, node.layer_name)
start = start.value
if limit.layer_type == "Const":
self.add_omit_nodes(limit.layer_name, node.layer_name)
limit = limit.value
if delta.layer_type == "Const":
self.add_omit_nodes(delta.layer_name, node.layer_name)
delta = delta.value
dtype = node.dtype def Squeeze(self, node):
inputs = { input = self.graph.get_node(node.layer.input[0])
"start": start, squeeze_dims = node.get_attr('squeeze_dims')
"end": limit, program.add_layer(
"step": delta, kernel="fluid.layers.squeeze",
} inputs={"input": input.name},
attr = {"dtype": string(node.dtype)} outputs=[node.name],
node.fluid_code.add_layer( axes=squeeze_dims)
"range", inputs=inputs, output=node, param_attr=attr)
def Mean(self, node): def Softmax(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True) input = self.graph.get_node(node.layer.input[0])
reduce_idx = self.graph.get_node(node.layer.input[1], copy=True) axis = node.get_attr("axis")
assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]" program.add_layer(
dims = reduce_idx.value.tolist() kernel="fluid.layers.softmax",
keep_dims = node.get_attr("keep_dims") inputs={"input": input.name},
outputs=[node.name],
axis=axis)
def Shape(self, node):
input = self.graph.get_node(node.layer.input[0])
program.add_layer(
kernel="fluid.layers.shape",
inputs={"input": input.name},
outputs=[node.name])
attr = {"dim": dims, "keep_dim": keep_dims} def ArgMax(self, node):
node.fluid_code.add_layer( input = self.graph.get_node(node.layer.input[0])
"reduce_mean", inputs=input, output=node, param_attr=attr) axis = self.graph.get_node(node.layer.input[1])
assert axis.layer_type == "Const", "ArgMax only support Const parameter"
axis = axis.value
program.add_layer(
kernel="fluid.layers.argmax",
inputs={"x": input.name},
outputs=[node.name],
axis=axis)
def MatMul(self, node): def MatMul(self, node):
x = self.graph.get_node(node.layer.input[0], copy=True) x = self.graph.get_node(node.layer.input[0])
y = self.graph.get_node(node.layer.input[1], copy=True) y = self.graph.get_node(node.layer.input[1])
transpose_a = node.get_attr('transpose_a') transpose_a = node.get_attr('transpose_a')
transpose_b = node.get_attr('transpose_b') transpose_b = node.get_attr('transpose_b')
inputs = {"x": x, "y": y}
# fix paddle shape infer problem
# should be removed after paddle 1.6
if x.out_shapes[0][-1] < 0 and y.out_shapes[0][0] > 0:
shape = x.out_shapes[0]
shape[-1] = y.out_shapes[0][0]
attr = {"shape": shape}
node.fluid_code.add_layer(
"reshape", inputs=x, output=x, param_attr=attr)
if transpose_a is None: if transpose_a is None:
transpose_a = node.get_attr('adj_x') transpose_a = node.get_attr('adj_x')
if transpose_b is None: if transpose_b is None:
transpose_b = node.get_attr('adj_y') transpose_b = node.get_attr('adj_y')
attr = {"transpose_x": transpose_a, "transpose_y": transpose_b} program.add_layer(
node.fluid_code.add_layer( kernel="fluid.layers.matmul",
"matmul", inputs=inputs, output=node, param_attr=attr) inputs={"x": x.name,
"y": y.name},
outputs=[node.name],
transpose_x=transpose_a,
transpose_y=transpose_b)
def DepthwiseConv2dNative(self, node):
input = self.graph.get_node(node.layer.input[0])
kernel = self.graph.get_node(node.layer.input[1])
assert kernel.layer_type == "Const", "Kernel of DepthwiseConv2DNative should be Const"
def BatchMatMul(self, node): in_shape = input.out_shapes[0]
return self.MatMul(node) k_size = kernel.out_shapes[0]
strides = node.get_attr("strides")
dilations = node.get_attr("dilations")
data_format = node.get_attr("data_format").decode()
pad_mode = node.get_attr("padding").decode()
def BatchMatMulV2(self, node): program.parameters[kernel.layer_name.replace(
return self.MatMul(node) '/', '_')] = numpy.transpose(kernel.value, (2, 3, 0, 1))
def ArgMax(self, node): input_name = input.name
if data_format == "NHWC":
in_shape = [in_shape[i] for i in [0, 3, 1, 2]]
strides = [strides[i] for i in [0, 3, 1, 2]]
dilations = [dilations[i] for i in [0, 3, 1, 2]]
transpose_name = gen_name('depthwise_conv2d', 'transpose')
program.add_layer(
kernel="fluid.layers.transpose",
inputs={"x": input.name},
outputs=[transpose_name],
perm=[0, 3, 1, 2])
input_name = transpose_name
program.add_layer(
kernel="fluid.layers.conv2d",
inputs={"input": input_name},
outputs=[node.name],
num_filters=in_shape[1],
filter_size=k_size[0:2],
stride=strides[2:4],
dilation=dilations[2:4],
groups=k_size[3] * in_shape[1],
padding=string(pad_mode),
param_attr=string(kernel.layer_name),
bias_attr=False)
if data_format == "NHWC":
program.add_layer(
kernel="fluid.layers.transpose",
inputs={"x": node.name},
outputs=[node.name],
perm=[0, 2, 3, 1])
def AvgPool(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True) input = self.graph.get_node(node.layer.input[0], copy=True)
axis = self.graph.get_node(node.layer.input[1], copy=True)
assert axis.layer_type == "Const", "ArgMax only support Const parameter" k_size = node.get_attr("ksize")
self.add_omit_nodes(axis.layer_name, node.layer_name) strides = node.get_attr("strides")
data_format = node.get_attr("data_format").decode()
pad_mode = node.get_attr("padding").decode()
input_name = input.name
if data_format == "NHWC":
transpose_name = gen_name("avg_pool", "transpose")
program.add_layer(
kernel="fluid.layers.transpose",
inputs={"x": input.name},
outputs=[transpose_name],
perm=[0, 3, 1, 2])
strides = [strides[i] for i in [0, 3, 1, 2]]
k_size = [k_size[i] for i in [0, 3, 1, 2]]
input_name = transpose_name
program.add_layer(
kernel="fluid.layers.pool2d",
inputs={"input": input_name},
outputs=[node.name],
pool_size=k_size[2:4],
pool_type=string("avg"),
pool_stride=strides[2:4],
pool_padding=string(pad_mode))
if data_format == "NHWC":
program.add_layer(
kernel="fluid.layers.transpose",
inputs={"x": node.name},
outputs=[node.name],
perm=[0, 2, 3, 1])
def Pack(self, node):
inputs = [self.graph.get_node(name) for name in node.layer.input]
axis = node.get_attr("axis")
program.add_layer(
kernel="fluid.layers.stack",
inputs={"x": [i.name for i in inputs]},
outputs=[node.name],
axis=axis)
def ConcatV2(self, node):
inputs = [self.graph.get_node(name) for name in node.layer.input[:-1]]
axis = self.graph.get_node(node.layer.input[-1])
assert axis.layer_type == "Const", "axis for ConcatV2 must be type Const"
axis = axis.value axis = axis.value
attr = {"axis": axis} if axis < 0:
node.fluid_code.add_layer( axis += len(inputs[0].out_shapes[0])
"argmax", inputs=input, output=node, param_attr=attr) program.add_layer(
kernel="fluid.layers.concat",
inputs={"input": [i.name for i in inputs]},
outputs=[node.name],
axis=axis)
def StridedSlice(self, node): def StridedSlice(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True) input = self.graph.get_node(node.layer.input[0])
begin = self.graph.get_node(node.layer.input[1], copy=True) begin = self.graph.get_node(node.layer.input[1])
end = self.graph.get_node(node.layer.input[2], copy=True) end = self.graph.get_node(node.layer.input[2])
strides = self.graph.get_node(node.layer.input[3], copy=True) strides = self.graph.get_node(node.layer.input[3])
assert begin.layer_type == "Const" assert begin.layer_type == "Const"
assert end.layer_type == "Const" assert end.layer_type == "Const"
assert strides.layer_type == "Const" assert strides.layer_type == "Const"
self.add_omit_nodes(begin.layer_name, node.layer_name)
self.add_omit_nodes(end.layer_name, node.layer_name)
self.add_omit_nodes(strides.layer_name, node.layer_name)
strides = strides.value.tolist() strides = strides.value.tolist()
assert len(set(strides)) == 1 and strides[ assert len(set(strides)) == 1 and strides[
0] == 1, "Only support strides be 1 in StridedSlice OP" 0] == 1, "Only support strides be 1 in StridedSlice OP"
...@@ -721,373 +691,278 @@ class TFOpMapperNHWC(OpMapper): ...@@ -721,373 +691,278 @@ class TFOpMapperNHWC(OpMapper):
else: else:
new_end.append(end[i]) new_end.append(end[i])
attr = { program.add_layer(
"axes": [i for i in range(len(new_begin))], kernel="fluid.layers.slice",
"starts": new_begin, inputs={"input": input.name},
"ends": new_end outputs=[node.name],
} axes=[i for i in range(len(new_begin))],
node.fluid_code.add_layer( starts=new_begin,
"slice", inputs=input, output=node, param_attr=attr) ends=new_end)
if len(new_axes) > 0: if len(new_axes) > 0:
attr = {"axes": new_axes} program.add_layer(
node.fluid_code.add_layer( kernel="fluid.layers.unsqueeze",
"unsqueeze", inputs=node, output=node, param_attr=attr) inputs={"x": node.name},
outputs=[node.name],
axes=new_axes)
if len(shrink_axes) > 0: if len(shrink_axes) > 0:
if len(input.out_shapes[0]) + len(new_axes) <= 1: if len(input.out_shapes[0]) + len(new_axes) <= 1:
pass pass
else: else:
attr = {"axes": shrink_axes} program.add_layer(
node.fluid_code.add_layer( kernel="fluid.layers.unsqueeze",
"squeeze", inputs=node, output=node, param_attr=attr) inputs={"x": node.name},
outputs=[node.name],
axes=new_axes)
def Split(self, node):
dim = self.graph.get_node(node.layer.input[0])
input = self.graph.get_node(node.layer.input[1])
assert dim.layer_type == "Const"
num_split = node.get_attr('num_split')
dim = dim.value
program.add_layer(
kernel="fluid.layers.split",
inputs={"input": input.name},
outputs=[
"{}_p{}".format(node.layer_name, i) for i in range(num_split)
],
num_or_sections=num_split,
dim=dim)
def Slice(self, node): def Slice(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True) input = self.graph.get_node(node.layer.input[0])
begin = self.graph.get_node(node.layer.input[1], copy=True) begin = self.graph.get_node(node.layer.input[1])
size = self.graph.get_node(node.layer.input[2], copy=True) size = self.graph.get_node(node.layer.input[2])
inputs = {"x": input.name}
attrs = {}
if begin.layer_type == "Const": if begin.layer_type == "Const":
self.add_omit_nodes(begin.layer_name, node.layer_name)
begin = begin.value.tolist() begin = begin.value.tolist()
attrs['offsets'] = begin
else: else:
begin = begin
shape = begin.out_shapes[0] shape = begin.out_shapes[0]
attr = {"shape": shape} reshape_name = gen_name("slice", "reshape")
node.fluid_code.add_layer( program.add_layer(
"reshape", inputs=begin, output=begin, param_attr=attr) kernel="fluid.layers.reshape",
inputs={"x": begin.name},
outputs=[reshape_name],
shape=shape)
inputs['offsets'] = reshape_name
if size.layer_type == "Const": if size.layer_type == "Const":
self.add_omit_nodes(size.layer_name, node.layer_name)
size = size.value.tolist() size = size.value.tolist()
attrs['shape'] = size
else: else:
size = size
shape = size.out_shapes[0] shape = size.out_shapes[0]
attr = {"shape": shape} reshape_name = gen_name("slice", "reshape")
node.fluid_code.add_layer( program.add_layer(
"reshape", inputs=size, output=size, param_attr=attr) kernel="fluid.layers.reshape",
inputs = {"x": input, "offsets": begin, "shape": size} inputs={"x": size.name},
node.fluid_code.add_layer( outputs=[reshape_name],
"crop_tensor", inputs=inputs, output=node, param_attr=None) shape=shape)
inputs['shape'] = reshape_name
def Conv2DBackpropInput(self, node): program.add_layer(
out_shape = self.graph.get_node(node.layer.input[0], copy=True) kernel="fluid.layers.crop_tensor",
kernel = self.graph.get_node(node.layer.input[1], copy=True) inputs=inputs,
input = self.graph.get_node(node.layer.input[2], copy=True) outputs=[node.name],
**attrs)
assert kernel.layer_type == "Const", "Kernel of Conv2DBackpropInput should be Const" def ResizeNearestNeighbor(self, node):
input = self.graph.get_node(node.layer.input[0])
self.add_omit_nodes(kernel.layer_name, node.layer_name) resize_shape = self.graph.get_node(node.layer.input[1])
self.add_omit_nodes(out_shape.layer_name, node.layer_name) data_format = "NHWC"
inputs = {"input": input.name}
attrs = {"align_corners": node.get_attr("align_corners")}
if out_shape.layer_type == "Const": if resize_shape.layer_type == "Const":
out_shape = out_shape.value.tolist() resize_shape = resize_shape.value.tolist()
attrs["out_shape"] = resize_shape
else: else:
out_shape = self.decoder.infer_shape_tensor(out_shape, shape = resize_shape.out_shapes[0]
node.out_shapes[0]) reshape_name = gen_name("resize_nearest", "reshape")
program.add_layer(
kernel="fluid.layers.reshape",
inputs={"x": resize_shape.name},
outputs=[reshape_name],
shape=shape)
inputs["out_shape"] = reshape_name
in_shape = input.out_shapes[0] if data_format == "NHWC":
if in_shape.count(-1) > 2: transpose_name = gen_name("resize_nearest", "reshape")
in_shape = self.decoder.infer_tensor(input).shape program.add_layer(
k_size = kernel.out_shapes[0] kernel="fluid.layers.transpose",
if k_size.count(-1) > 2: inputs={"x": input.name},
k_size = self.decoder.infer_tensor(kernel).shape outputs=[transpose_name],
perm=[0, 3, 1, 2])
inputs["input"] = transpose_name
program.add_layer(
kernel="fluid.layers.resize_nearest",
inputs=inputs,
outputs=[node.name],
**attrs)
pad_mode = node.get_attr("padding").decode() if data_format == "NHWC":
strides = node.get_attr("strides") program.add_layer(
dilations = node.get_attr("dilations") kernel="fluid.layers.transpose",
data_format = node.get_attr("data_format").decode() inputs={"x": node.name},
channel_first = data_format == "NCHW" outputs=[node.name],
perm=[0, 2, 3, 1])
self.weights[kernel.layer_name.replace('/', '_')] = numpy.transpose( def ResizeBilinear(self, node):
kernel.value, (3, 2, 0, 1)) input = self.graph.get_node(node.layer.input[0])
if not channel_first: resize_shape = self.graph.get_node(node.layer.input[1])
in_shape = [in_shape[i] for i in [0, 3, 1, 2]] data_format = "NHWC"
strides = [strides[i] for i in [0, 3, 1, 2]] inputs = {"input": input.name}
dilations = [dilations[i] for i in [0, 3, 1, 2]] attrs = {"align_corners": node.get_attr("align_corners")}
attr = {"perm": [0, 3, 1, 2]}
node.fluid_code.add_layer( if resize_shape.layer_type == "Const":
"transpose", inputs=input, output=node, param_attr=attr) resize_shape = resize_shape.value.tolist()
input = node attrs["out_shape"] = resize_shape
else: else:
self.graph.data_format_propagation(node) shape = resize_shape.out_shapes[0]
reshape_name = gen_name("resize_bilinear", "reshape")
attr = { program.add_layer(
"bias_attr": False, kernel="fluid.layers.reshape",
"param_attr": string(kernel.layer_name), inputs={"x": resize_shape.name},
"num_filters": k_size[2], outputs=[reshape_name],
"filter_size": k_size[0:2], shape=shape)
"stride": strides[2:4], inputs["out_shape"] = reshape_name
"dilation": dilations[2:4],
"padding": string(pad_mode),
"output_size": out_shape[1:3]
}
node.fluid_code.add_layer(
"conv2d_transpose", inputs=input, output=node, param_attr=attr)
if not channel_first: if data_format == "NHWC":
attr = {"perm": [0, 2, 3, 1]} transpose_name = gen_name("resize_bilinear", "reshape")
node.fluid_code.add_layer( program.add_layer(
"transpose", inputs=node, output=node, param_attr=attr) kernel="fluid.layers.transpose",
inputs={"x": input.name},
outputs=[transpose_name],
perm=[0, 3, 1, 2])
inputs["input"] = transpose_name
program.add_layer(
kernel="fluid.layers.resize_bilinear",
inputs=inputs,
outputs=[node.name],
**attrs)
def Max(self, node): if data_format == "NHWC":
input = self.graph.get_node(node.layer.input[0], copy=True) program.add_layer(
reduce_idx = self.graph.get_node(node.layer.input[1], copy=True) kernel="fluid.layers.transpose",
assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]" inputs={"x": node.name},
keep_dims = node.get_attr("keep_dims") outputs=[node.name],
dim = reduce_idx.value.tolist() perm=[0, 2, 3, 1])
attr = {"dim": dim, "keep_dim": keep_dims} def Cast(self, node):
node.fluid_code.add_layer( input = self.graph.get_node(node.layer.input[0])
"reduce_max", inputs=input, output=node, param_attr=attr) dtype = node.dtype
program.add_layer(
kernel="fluid.layers.cast",
inputs={"x": input.name},
outputs=[node.name],
dtype=string(dtype))
def Sum(self, node): def Sum(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True) input = self.graph.get_node(node.layer.input[0])
reduce_idx = self.graph.get_node(node.layer.input[1], copy=True) reduce_idx = self.graph.get_node(node.layer.input[1])
assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]" assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]"
keep_dims = node.get_attr("keep_dims") keep_dims = node.get_attr("keep_dims")
dim = reduce_idx.value.tolist() dim = reduce_idx.value.tolist()
attr = {"dim": dim, "keep_dim": keep_dims} program.add_layer(
node.fluid_code.add_layer( kernel="fluid.layers.reduce_sum",
"reduce_sum", inputs=input, output=node, param_attr=attr) inputs={"input": input.name},
outputs=[node.name],
def Cast(self, node): dim=dim,
input = self.graph.get_node(node.layer.input[0], copy=True) keep_dim=keep_dims)
dtype = node.dtype_map[node.get_attr('DstT')]
attr = {"dtype": string(dtype)}
node.fluid_code.add_layer(
"cast", inputs=input, output=node, param_attr=attr)
def Split(self, node):
dim = self.graph.get_node(node.layer.input[0], copy=True)
input = self.graph.get_node(node.layer.input[1], copy=True)
assert dim.layer_type == "Const"
self.add_omit_nodes(dim.layer_name, node.layer_name)
num_split = node.get_attr('num_split')
dim = dim.value
attr = {"num_or_sections": num_split, "dim": dim}
node.fluid_code.add_layer(
"split", inputs=input, output=node, param_attr=attr)
def Squeeze(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True)
squeeze_dims = node.get_attr('squeeze_dims')
attr = {"axes": squeeze_dims}
node.fluid_code.add_layer(
"squeeze", inputs=input, output=node, param_attr=attr)
def Softmax(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True)
axis = node.get_attr("axis")
attr = {"axis": axis}
node.fluid_code.add_layer(
"softmax", 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)
if resize_shape.layer_type == "Const":
self.add_omit_nodes(resize_shape.layer_name, node.layer_name)
resize_shape = resize_shape.value.tolist()
else:
resize_shape = resize_shape
shape = resize_shape.out_shapes[0]
attr = {"shape": shape}
node.fluid_code.add_layer(
"reshape",
inputs=resize_shape,
output=resize_shape,
param_attr=attr)
align_corners = node.get_attr("align_corners")
attr = {"perm": [0, 3, 1, 2]}
node.fluid_code.add_layer(
"transpose", inputs=input, output=node, param_attr=attr)
inputs = {"input": node, "out_shape": resize_shape}
attr = {"align_corners": align_corners}
node.fluid_code.add_layer(
"resize_nearest", inputs=inputs, output=node, param_attr=attr)
attr = {"perm": [0, 2, 3, 1]}
node.fluid_code.add_layer(
"transpose", inputs=node, output=node, param_attr=attr)
def ResizeBilinear(self, node): def Max(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True) input = self.graph.get_node(node.layer.input[0])
resize_shape = self.graph.get_node(node.layer.input[1], copy=True) reduce_idx = self.graph.get_node(node.layer.input[1])
if resize_shape.layer_type == "Const": assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]"
self.add_omit_nodes(resize_shape.layer_name, node.layer_name) keep_dims = node.get_attr("keep_dims")
resize_shape = resize_shape.value.tolist() dim = reduce_idx.value.tolist()
else: program.add_layer(
shape = resize_shape.out_shapes[0] kernel="fluid.layers.reduce_max",
attr = {"shape": shape} inputs={"input": input.name},
node.fluid_code.add_layer( outputs=[node.name],
"reshape", dim=dim,
inputs=resize_shape, keep_dim=keep_dims)
output=resize_shape,
param_attr=attr)
align_corners = node.get_attr("align_corners")
attr = {"perm": [0, 3, 1, 2]}
node.fluid_code.add_layer(
"transpose", inputs=input, output=node, param_attr=attr)
inputs = {"input": node, "out_shape": resize_shape}
attr = {
#"out_shape": resize_shape,
"align_corners": align_corners,
"align_mode": 1
}
node.fluid_code.add_layer(
"resize_bilinear", inputs=inputs, output=node, param_attr=attr)
attr = {"perm": [0, 2, 3, 1]}
node.fluid_code.add_layer(
"transpose", inputs=node, output=node, param_attr=attr)
def GreaterEqual(self, node):
x = self.graph.get_node(node.layer.input[0], copy=True)
y = self.graph.get_node(node.layer.input[1], copy=True)
inputs = {"x": x, "y": y}
node.fluid_code.add_layer(
"greater_equal", inputs=inputs, output=node, param_attr=None)
def RandomUniform(self, node): def RandomUniform(self, node):
shape = self.graph.get_node(node.layer.input[0], copy=True) shape = self.graph.get_node(node.layer.input[0], copy=True)
if shape.layer_type == "Const": if shape.layer_type == "Const":
self.add_omit_nodes(shape.layer_name, node.layer_name)
shape = shape.value.tolist() shape = shape.value.tolist()
program.add_layer(
kernel="fluid.layers.uniform_random",
inputs={},
outputs=[node.name],
shape=shape,
min=0.0,
max=0.9999)
else: else:
shape = shape program.add_layer(
attr = {"min": 0.0, "max": 0.9999} kernel="fluid.layers.uniform_random",
inputs={'shape': shape.name},
node.fluid_code.add_layer( outputs=[node.name],
"uniform_random", inputs=shape, output=node, param_attr=attr) min=0.0,
max=0.9999)
def SquaredDifference(self, node):
x = self.graph.get_node(node.layer.input[0], copy=True)
y = self.graph.get_node(node.layer.input[1], copy=True)
inputs = {"x": x, "y": y}
node.fluid_code.add_layer(
"elementwise_sub", inputs=inputs, output=node, param_attr=None)
inputs = {"x": node, "y": node}
node.fluid_code.add_layer(
"elementwise_mul", inputs=inputs, output=node, param_attr=None)
def ExpandDims(self, node):
x = self.graph.get_node(node.layer.input[0], copy=True)
y = self.graph.get_node(node.layer.input[1], copy=True)
if y.layer_type == 'Const':
self.add_omit_nodes(y.layer_name, node.layer_name)
dim = y.value.tolist()
if not isinstance(dim, list):
dim = [dim]
attr = {'axes': dim}
else:
attr = {'axes': y}
node.fluid_code.add_layer(
"unsqueeze", inputs=x, output=node, param_attr=attr)
def BatchToSpaceND(self, node):
x = self.graph.get_node(node.layer.input[0], copy=True)
y = self.graph.get_node(node.layer.input[1], copy=True)
if hasattr(node, 'skip') and node.skip:
node.fluid_code.add_layer(
"=", inputs=x, output=node, param_attr=None)
else:
raise Exception("BatchToSpaceND is not supported")
def SpaceToBatchND(self, node):
x = self.graph.get_node(node.layer.input[0], copy=True)
y = self.graph.get_node(node.layer.input[1], copy=True)
if hasattr(node, 'skip') and node.skip:
node.fluid_code.add_layer(
"=", inputs=x, output=node, param_attr=None)
else:
raise Exception("SpaceToBatchND is not supported")
def OneHot(self, node): def Conv2DBackpropInput(self, node):
input = self.graph.get_node(node.layer.input[0], copy=True) out_shape = self.graph.get_node(node.layer.input[0])
depth = self.graph.get_node(node.layer.input[1], copy=True) kernel = self.graph.get_node(node.layer.input[1])
on_value = self.graph.get_node(node.layer.input[2], copy=True) input = self.graph.get_node(node.layer.input[2])
off_value = self.graph.get_node(node.layer.input[3], copy=True)
assert depth.layer_type == 'Const', 'Parameter depth should be Const in OneHot' assert kernel.layer_type == "Const", "Kernel of Conv2DBackpropInput should be Const"
assert on_value.layer_type == 'Const', 'Parameter on_value should be Const in OneHot'
assert off_value.layer_type == 'Const', 'Parameter off_value should be Const in OneHot' if out_shape.layer_type == "Const":
self.add_omit_nodes(depth.layer_name, node.layer_name) out_shape = out_shape.value.tolist()
self.add_omit_nodes(on_value.layer_name, node.layer_name)
self.add_omit_nodes(off_value.layer_name, node.layer_name)
depth = depth.value
on_value = on_value.value
off_value = off_value.value
assert math.fabs(on_value -
1.0) < 1e-06, "on_value should be 1 in OneHot"
assert math.fabs(off_value -
0.0) < 1e-06, "off_value should be 0 in OneHot"
attr = {'depth': depth}
node.fluid_code.add_layer(
"one_hot",
inputs=input,
output=node,
param_attr=attr,
use_fluid=True)
def Pow(self, node):
x = self.graph.get_node(node.layer.input[0], copy=True)
factor = self.graph.get_node(node.layer.input[1], copy=True)
self.add_omit_nodes(factor.layer_name, node.layer_name)
if factor.layer_type == 'Const':
factor = factor.value.tolist()
else: else:
factor = self.decoder.infer_tensor(factor) out_shape = self.decoder.infer_shape_tensor(out_shape,
attr = {'factor': factor} node.out_shapes[0])
node.fluid_code.add_layer("pow", inputs=x, output=node, param_attr=attr)
def All(self, node): in_shape = input.out_shapes[0]
input = self.graph.get_node(node.layer.input[0], copy=True) if in_shape.count(-1) > 2:
reduce_idx = self.graph.get_node(node.layer.input[1], copy=True) in_shape = self.decoder.infer_tensor(input).shape
self.add_omit_nodes(reduce_idx.layer_name, node.layer_name) k_size = kernel.out_shapes[0]
assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]" if k_size.count(-1) > 2:
dims = reduce_idx.value.tolist() k_size = self.decoder.infer_tensor(kernel).shape
keep_dims = node.get_attr("keep_dims")
attr = {"dim": dims, "keep_dim": keep_dims} pad_mode = node.get_attr("padding").decode()
node.fluid_code.add_layer( strides = node.get_attr("strides")
"reduce_all", inputs=input, output=node, param_attr=attr) dilations = node.get_attr("dilations")
data_format = node.get_attr("data_format").decode()
def GatherV2(self, node):
embeddings = self.graph.get_node(node.layer.input[0], copy=True) program.parameters[kernel.layer_name.replace(
index = self.graph.get_node(node.layer.input[1], copy=True) '/', '_')] = numpy.transpose(kernel.value, (3, 2, 0, 1))
axis = self.graph.get_node(node.layer.input[2], copy=True)
self.add_omit_nodes(axis.layer_name, node.layer_name) input_name = input.name
assert axis.layer_type == 'Const', "Only support Const parameter[axis]" if data_format == "NHWC":
axis = axis.value.tolist() in_shape = [in_shape[i] for i in [0, 3, 1, 2]]
assert axis == 0, "Only support axis=0 in GatherV2 OP" strides = [strides[i] for i in [0, 3, 1, 2]]
attr = {'overwrite': False} dilations = [dilations[i] for i in [0, 3, 1, 2]]
if len(index.out_shapes[0]) != 1: transpose_name = gen_name("conv2dbackpropinput", "transpose")
reshape_attr = {"shape": [-1]} program.add_layer(
node.fluid_code.add_layer( kernel="fluid.layers.transpose",
"reshape", inputs=index, output=index, param_attr=reshape_attr) inputs={"x": input.name},
inputs = {'input': embeddings, 'index': index} outputs=[transpose_name],
node.fluid_code.add_layer( perm=[0, 3, 1, 2])
"gather", inputs=inputs, output=node, param_attr=attr) input_name = transpose_name
def OneShotIterator(self, node): program.add_layer(
return self.Placeholder(node) kernel="fluid.layers.conv2d_transpose",
inputs={"input": input_name},
def IteratorV2(self, node): outputs=[node.name],
dtype_map = { bias_attr=False,
1: "float32", param_attr=string(kernel.layer_name),
3: "int32", num_filters=k_size[2],
4: "uint8", filter_size=k_size[0:2],
9: "int64", stride=strides[2:4],
10: "bool" dilation=dilations[2:4],
} padding=string(pad_mode),
shapes = node.out_shapes output_size=out_shape[1:3])
dtypes = node.layer.attr['output_types'].list.type
node.fluid_code.add_note("{} = [0] * {}".format(node.layer_name, if data_format == "NHWC":
len(shapes))) program.add_layer(
for i, shape in enumerate(shapes): kernel="fluid.layers.transpose",
attr = { inputs={"x": node.name},
'dtype': string(dtype_map[dtypes[i]]), outputs=[node.name],
'shape': shape, perm=[0, 2, 3, 1])
'name': string("{}_{}".format(node.layer_name, i)),
'append_batch_size': False
}
output = "{}[{}]".format(node.layer_name, i)
node.fluid_code.add_layer(
"data", inputs=None, output=output, param_attr=attr)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册