提交 a5b69c1c 编写于 作者: S SunAhong1993

add the custom layer

上级 7ba875b4
......@@ -23,11 +23,11 @@ def arg_parser():
type=_text_type,
default=None,
help="model file path")
parser.add_argument("--proto",
parser.add_argument("--prototxt",
"-p",
type=_text_type,
default=None,
help="proto file of caffe model")
help="prototxt file of caffe model")
parser.add_argument("--weight",
"-w",
type=_text_type,
......@@ -43,6 +43,11 @@ def arg_parser():
type=_text_type,
default=None,
help="define which deeplearning framework")
parser.add_argument("--caffe_proto",
"-c",
type=_text_type,
default=None,
help="caffe proto file of caffe model")
return parser
......@@ -57,12 +62,12 @@ def tf2paddle(model_path, save_dir):
mapper.save_python_model(save_dir)
def caffe2paddle(proto, weight, save_dir):
def caffe2paddle(proto, weight, save_dir, caffe_proto):
from x2paddle.decoder.caffe_decoder import CaffeDecoder
from x2paddle.op_mapper.caffe_op_mapper import CaffeOpMapper
print("Now translating model from caffe to paddle.")
model = CaffeDecoder(proto, weight)
model = CaffeDecoder(proto, weight, caffe_proto)
mapper = CaffeOpMapper(model)
mapper.run()
mapper.save_python_model(save_dir)
......@@ -80,8 +85,9 @@ def main():
tf2paddle(args.model, args.save_dir)
elif args.framework == "caffe":
assert args.proto is not None, "--proto and --weight should be defined while translating caffe model"
caffe2paddle(args.proto, args.weight, args.save_dir)
assert args.prototxt is not None and args.weight is not None, "--prototxt and --weight should be defined while translating caffe model"
caffe2paddle(args.prototxt, args.weight, args.save_dir,
args.caffe_proto)
else:
raise Exception("--framework only support tensorflow/caffe now")
......
......@@ -13,7 +13,6 @@
# limitations under the License.
from x2paddle.core.graph import GraphNode
import collections
class Layer(object):
......@@ -22,6 +21,7 @@ class Layer(object):
self.param_attr = dict()
self.inputs = dict()
self.output = None
self.is_new = False
def get_code(self):
layer_code = ""
......@@ -36,34 +36,25 @@ class Layer(object):
if isinstance(self.inputs, list):
in_list = "["
for input in self.inputs:
if isinstance(input, GraphNode):
if hasattr(input, "index"):
in_list += (input.layer_name +
"[{}]".format(input.index) + ", ")
else:
in_list += (input.layer_name + ", ")
elif isinstance(input, str):
in_list += (input + ", ")
assert isinstance(
input, GraphNode), "Type of input should be GraphNode"
if hasattr(input, "index"):
in_list += (input.layer_name + "[{}]".format(input.index) +
", ")
else:
raise Exception(
"Element of inputs should GraphNode or String")
in_list += (input.layer_name + ", ")
in_list = in_list.strip(", ") + "], "
layer_code += in_list
elif isinstance(self.inputs, dict):
inputs = collections.OrderedDict(self.inputs)
for key, input in inputs.items():
if isinstance(input, GraphNode):
if hasattr(input, "index"):
layer_code = layer_code + key + "={}, ".format(
input.layer_name + "[{}]".format(input.index))
else:
layer_code = layer_code + key + "={}, ".format(
input.layer_name)
elif isinstance(input, str):
layer_code = layer_code + key + "={}, ".format(input)
for key, input in self.inputs.items():
assert isinstance(
input, GraphNode), "Type of input should be GraphNode"
if hasattr(input, "index"):
layer_code = layer_code + key + "={}, ".format(
input.layer_name + "[{}]".format(input.index))
else:
raise Exception(
"Element of inputs should GraphNode or String")
layer_code = layer_code + key + "={}, ".format(
input.layer_name)
elif isinstance(self.inputs, GraphNode):
if hasattr(self.inputs, "index"):
layer_code += (self.inputs.layer_name +
......@@ -75,8 +66,38 @@ class Layer(object):
else:
raise Exception("Unknown type of inputs.")
param_attr = collections.OrderedDict(self.param_attr)
for key, value in param_attr.items():
for key, value in self.param_attr.items():
layer_code = layer_code + key + "={}, ".format(value)
layer_code = layer_code.strip(", ")
return layer_code + ")"
def get_custom_code(self):
layer_code = ""
if self.output is not None:
if isinstance(self.output, str):
layer_code = self.output + " = "
else:
layer_code = self.output.layer_name + " = "
layer_code = layer_code + self.op + "("
if isinstance(self.inputs, list):
in_list = "["
for input in self.inputs:
assert isinstance(
input, GraphNode), "Type of input should be GraphNode"
if hasattr(input, "index"):
in_list += (input.layer_name + "[{}]".format(input.index) +
", ")
else:
in_list += (input.layer_name + ", ")
in_list = in_list.strip(", ") + "], "
layer_code += in_list
else:
raise Exception("Unknown type of inputs.")
for key, value in self.param_attr.items():
layer_code = layer_code + key + "={}, ".format(value)
layer_code = layer_code.strip(", ")
......@@ -87,9 +108,15 @@ class FluidCode(object):
def __init__(self):
self.layers = list()
def add_layer(self, op, inputs, output, param_attr=None):
def add_layer(self,
op,
inputs,
output,
param_attr=None,
is_custom_layer=False):
layer = Layer()
layer.op = op
layer.is_custom_layer = is_custom_layer
if inputs is not None:
layer.inputs = inputs
layer.output = output
......@@ -108,7 +135,10 @@ class FluidCode(object):
codes = list()
for layer in self.layers:
if isinstance(layer, Layer):
codes.append(layer.get_code())
if layer.is_custom_layer:
codes.append(layer.get_custom_code())
else:
codes.append(layer.get_code())
elif isinstance(layer, str):
codes.append(layer)
return codes
......@@ -18,19 +18,20 @@ from google.protobuf import text_format
import numpy as np
from x2paddle.core.graph import GraphNode, Graph
from x2paddle.core.fluid_code import FluidCode
from x2paddle.decoder import caffe_shape
from x2paddle.op_mapper import caffe_shape
class CaffeResolver(object):
def __init__(self, use_default=True):
self.use_default = use_default
def __init__(self, caffe_proto_folder=None):
self.proto_path = caffe_proto_folder
if self.proto_path == None:
self.use_default = True
else:
self.use_default = False
self.import_caffe()
def import_caffepb(self):
p = os.path.realpath(__file__)
p = os.path.dirname(p)
p = os.path.join(p, './proto')
sys.path.insert(0, p)
sys.path.append(self.proto_path)
import caffe_pb2
return caffe_pb2
......@@ -60,11 +61,13 @@ class CaffeResolver(object):
class CaffeGraphNode(GraphNode):
def __init__(self, layer, layer_name=None):
if layer_name is None:
super(CaffeGraphNode, self).__init__(layer,
layer.name.replace('/', '_'))
super(CaffeGraphNode,
self).__init__(layer,
layer.name.replace('/', '_').replace('-', '_'))
else:
super(CaffeGraphNode, self).__init__(layer,
layer_name.replace('/', '_'))
super(CaffeGraphNode,
self).__init__(layer,
layer_name.replace('/', '_').replace('-', '_'))
self.layer_type = layer.type
self.fluid_code = FluidCode()
self.data = None
......@@ -72,10 +75,13 @@ class CaffeGraphNode(GraphNode):
def set_params(self, params):
self.data = params
def set_output_shape(self, input_shape):
def set_output_shape(self, input_shape, is_input=True):
func_name = 'shape_' + self.layer_type.lower()
self.output_shape = getattr(caffe_shape, func_name)(self.layer,
input_shape)
if is_input:
self.output_shape = getattr(caffe_shape, func_name)(self.layer,
input_shape)
else:
self.output_shape = input_shape
def set_input_shape(self, input_shape):
self.input_shape = input_shape
......@@ -135,7 +141,7 @@ class CaffeGraph(Graph):
]))).to_proto().layer[0])
except:
raise ImportError(
'You must install the caffe first when you use old style prototxt.'
'The .proto file does not work for the old style prototxt. You must install the caffe or modify the old style to new style in .protottx file.'
)
data.name = self.model.input[i]
data.top[0] = self.model.input[i]
......@@ -151,7 +157,7 @@ class CaffeGraph(Graph):
]))).to_proto().layer[0])
except:
raise ImportError(
'You must install the caffe first when you use old style prototxt.'
'The .proto file does not work for the old style prototxt. You must install the caffe or modify the old style to new style in .protottx file.'
)
data.name = self.model.input[i]
data.top[0] = self.model.input[i]
......@@ -180,19 +186,6 @@ class CaffeGraph(Graph):
else:
notice('Ignoring parameters for non-existent layer: %s' % \
layer_name)
for layer_name in self.node_map:
node = self.node_map[layer_name]
inputs = node.inputs
i = 0
input_shape = []
for nm in inputs:
last_node = self.get_node(nm)
tmp = node.layer.bottom[i]
i = i + 1
idx = list(last_node.layer.top).index(tmp)
input_shape.append(last_node.output_shape[idx])
node.set_output_shape(input_shape)
node.set_input_shape(input_shape)
super(CaffeGraph, self).build()
......@@ -210,11 +203,11 @@ class CaffeGraph(Graph):
class CaffeDecoder(object):
def __init__(self, proto_path, model_path, use_caffe=True):
def __init__(self, proto_path, model_path, caffe_proto_folder=None):
self.proto_path = proto_path
self.model_path = model_path
self.resolver = CaffeResolver(use_default=use_caffe)
self.resolver = CaffeResolver(caffe_proto_folder=caffe_proto_folder)
self.net = self.resolver.NetParameter()
with open(proto_path, 'rb') as proto_file:
proto_str = proto_file.read()
......
from .register import get_registered_layers
#custom layer import begins
# from . import roipooling
# from . import priorbox
# from . import permute
# from . import detection_out
# from . import normalize
# from . import select
from . import convolutiondepthwise
#custom layer import ends
custom_layers = get_registered_layers()
def set_args(f, params):
""" set args for function 'f' using the parameters in node.layer.param
Args:
f (function): a python function object
params (object): a object contains attributes needed by f's arguments
Returns:
arg_names (list): a list of argument names
kwargs (dict): a dict contains needed arguments
"""
argc = f.__code__.co_argcount
arg_list = f.__code__.co_varnames[0:argc]
kwargs = {}
for arg_name in arg_list:
if hasattr(params, arg_name) and params is not None:
kwargs[arg_name] = getattr(params, arg_name)
return arg_list, kwargs
def has_layer(layer_type):
""" test whether this layer exists in custom layer
"""
return layer_type in custom_layers
def get_params(layer, layer_type):
if layer_type.lower() == "deconvolution" or layer_type.lower(
) == "convolutiondepthwise":
param_name = '_'.join(('convolution', 'param'))
elif layer_type.lower() == "normalize":
param_name = '_'.join(('norm', 'param'))
else:
param_name = '_'.join((layer_type.lower(), 'param'))
return getattr(layer, param_name, None)
def compute_output_shape(node):
""" compute the output shape of custom layer
"""
layer_type = node.layer_type
assert layer_type in custom_layers, "layer[%s] not exist in custom layers" % (
layer_type)
shape_func = custom_layers[layer_type]['shape']
layer = node.layer
params = get_params(layer, layer_type)
arg_names, kwargs = set_args(shape_func, params)
input_shape = node.input_shape
return shape_func(input_shape, **kwargs)
def make_custom_layer(node):
""" get the code which implement the custom layer function
"""
layer_type = node.layer_type
assert layer_type in custom_layers, "layer[%s] not exist in custom layers" % (
layer_type)
layer_func = custom_layers[layer_type]['layer']
import inspect
return inspect.getsource(layer_func), layer_func
def deal_weights(node, data=None):
""" deal the weights of the custom layer
"""
layer_type = node.layer_type
weights_func = custom_layers[layer_type]['weights']
name = node.layer_name
return weights_func(name, data)
from .register import register
from x2paddle.core.util import *
import numbers
def convolutiondepthwise_shape(input_shape,
num_output=None,
pad=None,
kernel_size=None,
stride=None,
dilation=None,
pad_h=None,
pad_w=None,
kernel_h=None,
kernel_w=None,
stride_h=None,
stride_w=None):
[k_h, k_w] = [1, 1]
if isinstance(kernel_size, numbers.Number):
[k_h, k_w] = [kernel_size] * 2
elif isinstance(kernel_size, list):
k_h = kernel_h if kernel_h else kernel_size[0]
k_w = kernel_w if kernel_w else kernel_size[len(kernel_size) - 1]
[s_h, s_w] = [1, 1]
if isinstance(stride, numbers.Number):
[s_h, s_w] = [stride] * 2
elif isinstance(stride, list):
s_h = stride_h if stride_h else stride[0]
s_w = stride_w if stride_w else stride[len(stride) - 1]
[p_h, p_w] = [0, 0]
if isinstance(pad, numbers.Number):
[p_h, p_w] = [pad] * 2
elif isinstance(pad, list):
p_h = pad_h if pad_h else pad[0]
p_w = pad_w if pad_w else pad[len(pad) - 1]
dila_len = len(dilation)
dila_h = 1
dila_w = 1
if dila_len == 2:
dila_h = dilation[0]
dila_w = dilation[1]
elif dila_len == 1:
dila_h = dila_w = dilation[0]
else:
assert dila_len == 0, "invalid length[%s] of dilation in convolution" % (
dila_len)
i_w = input_shape[0][2]
i_h = input_shape[0][3]
o_h = (i_h + 2 * p_h - (dila_h * (k_h - 1) + 1)) / float(s_h) + 1
o_w = (i_w + 2 * p_w - (dila_w * (k_w - 1) + 1)) / float(s_w) + 1
import math
o_h = int(math.floor(o_h))
o_w = int(math.floor(o_w))
c = num_output if num_output is not None else input_shape[0][1]
return [[input_shape[0][0], c, o_h, o_w]]
def convolutiondepthwise_layer(inputs,
num_output=None,
pad=None,
kernel_size=None,
stride=None,
dilation=None,
pad_h=None,
pad_w=None,
kernel_h=None,
kernel_w=None,
stride_h=None,
stride_w=None,
input_shape=[],
name=None):
[k_h, k_w] = [1, 1]
if isinstance(kernel_size, numbers.Number):
[k_h, k_w] = [kernel_size] * 2
elif isinstance(kernel_size, list):
k_h = kernel_h if kernel_h else kernel_size[0]
k_w = kernel_w if kernel_w else kernel_size[len(kernel_size) - 1]
[s_h, s_w] = [1, 1]
if isinstance(stride, numbers.Number):
[s_h, s_w] = [stride] * 2
elif isinstance(stride, list):
s_h = stride_h if stride_h else stride[0]
s_w = stride_w if stride_w else stride[len(stride) - 1]
[p_h, p_w] = [0, 0]
if isinstance(pad, numbers.Number):
[p_h, p_w] = [pad] * 2
elif isinstance(pad, list):
p_h = pad_h if pad_h else pad[0]
p_w = pad_w if pad_w else pad[len(pad) - 1]
input = inputs[0]
dila_len = len(dilation)
dila_h = 1
dila_w = 1
if dila_len == 2:
dila_h = dilation[0]
dila_w = dilation[1]
elif dila_len == 1:
dila_h = dila_w = dilation[0]
else:
assert dila_len == 0, "invalid length[%s] of dilation in convolution" % (
dila_len)
c_in = input_shape[0][1]
c_out = num_output if num_output is not None else input_shape[0][1]
group = int(c_in / (c_in / c_out)) if c_in > c_out else int(c_in /
(c_out / c_in))
out = fluid.layers.conv2d(input,
dilation=[dila_h, dila_w],
filter_size=[k_h, k_w],
stride=[s_h, s_w],
padding=[p_h, p_w],
groups=group,
num_filters=c_out,
param_attr=name + '_weights',
bias_attr=name + '_bias',
name=name)
return out
def convolutiondepthwise_weights(name, data=None):
weights_name = []
weights_name.append(name + '_weights')
weights_name.append(name + '_bias')
return weights_name
register(kind='ConvolutionDepthwise',
shape=convolutiondepthwise_shape,
layer=convolutiondepthwise_layer,
weights=convolutiondepthwise_weights)
""" this module provides 'register' for registering customized layers
"""
g_custom_layers = {}
def register(kind, shape, layer, weights):
""" register a custom layer or a list of custom layers
Args:
@kind (str or list): type name of the layer
@shape (function): a function to generate the shape of layer's output
@layer (function): a function to generate the paddle code of layer
@weights (function): a function to deal with weights data
Returns:
None
"""
assert type(shape).__name__ == 'function', 'shape should be a function'
assert type(layer).__name__ == 'function', 'layer should be a function'
if type(kind) is str:
kind = [kind]
else:
assert type(
kind
) is list, 'invalid param "kind" for register, not a list or str'
for k in kind:
assert type(
k) is str, 'invalid param "kind" for register, not a list of str'
assert k not in g_custom_layers, 'this type[%s] has already been registered' % (
k)
print('register layer[%s]' % (k))
g_custom_layers[k] = {
'shape': shape,
'layer': layer,
'weights': weights
}
def get_registered_layers():
return g_custom_layers
......@@ -17,6 +17,7 @@ import numpy as np
from x2paddle.decoder.caffe_decoder import CaffeGraph
from x2paddle.core.op_mapper import OpMapper
from x2paddle.core.util import *
from x2paddle.op_mapper.caffe_custom_layer import *
class CaffeOpMapper(OpMapper):
......@@ -25,34 +26,72 @@ class CaffeOpMapper(OpMapper):
self.graph = decoder.caffe_graph
self.weights = dict()
resolver = decoder.resolver
self.mylayers = {}
if resolver.has_pycaffe():
self.did_use_pb = False
else:
self.did_use_pb = True
def op_checker(self):
unsupported_ops = set()
for node_name in self.graph.topo_sort:
node = self.graph.get_node(node_name)
op = node.layer_type
if not hasattr(self, op) and op not in custom_layers:
unsupported_ops.add(op)
if len(unsupported_ops) == 0:
return True
else:
print("There are {} ops not supported yet, list as below".format(
len(unsupported_ops)))
for op in unsupported_ops:
print(op)
return False
def run(self):
print("Total nodes: {}".format(len(self.graph.topo_sort)))
# check if ops in model are all supported
if not self.op_checker():
raise Exception("Model are not supported yet.")
for node_name in self.graph.topo_sort:
node = self.graph.get_node(node_name)
op = node.layer_type
if hasattr(self, op):
self.set_shape(node)
func = getattr(self, op)
func(node)
elif op in custom_layers:
self.set_shape(node, is_fluid_op=False)
self.deal_custom_layer(node)
else:
raise Exception("Model are not supported yet.")
for key in self.mylayers:
self.net_code.append(self.mylayers[key])
for i in range(len(self.graph.topo_sort)):
node_name = self.graph.topo_sort[i]
node = self.graph.get_node(node_name)
self.net_code += node.fluid_code.gen_codes()
def adjust_parameters(self, node, data):
def set_shape(self, node, is_fluid_op=True):
inputs = node.inputs
input_shape = []
for i, nm in enumerate(inputs):
last_node = self.graph.get_node(nm)
tmp = node.layer.bottom[i]
idx = list(last_node.layer.top).index(tmp)
input_shape.append(last_node.output_shape[idx])
node.set_input_shape(input_shape)
if is_fluid_op:
node.set_output_shape(input_shape)
else:
node.set_output_shape(compute_output_shape(node),
is_input=is_fluid_op)
def adjust_parameters(self, node):
data = node.data
if not self.did_use_pb:
return data
# When using the protobuf-backend, each parameter initially has four dimensions.
# In certain cases (like FC layers), we want to eliminate the singleton dimensions.
# This implementation takes care of the common cases. However, it does leave the
......@@ -61,7 +100,7 @@ class CaffeOpMapper(OpMapper):
data = list(data)
squeeze_indices = [1] # Squeeze biases.
if node.kind == NodeKind.InnerProduct:
if node.layer_type == 'InnerProduct':
squeeze_indices.append(0) # Squeeze FC.
for idx in squeeze_indices:
......@@ -85,55 +124,44 @@ class CaffeOpMapper(OpMapper):
data[idx] = np.squeeze(d, axis=sq_axis)
shape_new = data[idx].shape
print('shape-old' + str(shape_old))
print('shape-new' + str(shape_new))
if len(shape_old) != shape_new:
debug('squeeze idx:%d, with kind:%s,name:%s' % \
(idx, node.kind, node.name))
print('squeeze idx:%d, with kind:%s,name:%s' % \
(idx, node.layer_type, node.layer.name))
return data
@staticmethod
def get_kernel_value(scalar, repeated, idx, default=None):
if scalar:
return scalar
if repeated:
if isinstance(repeated, numbers.Number):
return repeated
if len(repeated) == 1:
# Same value applies to all spatial dimensions
return int(repeated[0])
assert idx < len(repeated)
# Extract the value for the given spatial dimension
return repeated[idx]
if default is None:
raise ValueError('Unable to determine kernel parameter!')
return default
def get_kernel_parameters(self, kind, params):
assert kind in ['Convolution', 'Pooling', 'Deconvolution']
k_h = self.get_kernel_value(params.kernel_h,
params.kernel_size,
0,
default=1)
k_w = self.get_kernel_value(params.kernel_w,
params.kernel_size,
1,
default=1)
s_h = self.get_kernel_value(params.stride_h,
params.stride,
0,
default=1)
s_w = self.get_kernel_value(params.stride_w,
params.stride,
1,
default=1)
p_h = self.get_kernel_value(params.pad_h, params.pad, 0, default=0)
p_w = self.get_kernel_value(params.pad_w, params.pad, 1, default=0)
assert kind in [
'Convolution', 'Pooling', 'Deconvolution', 'ConvolutionDepthwise'
]
[k_h, k_w] = [1, 1]
print(params.kernel_size)
if isinstance(params.kernel_size, numbers.Number):
[k_h, k_w] = [params.kernel_size] * 2
else:
k_h = params.kernel_h if params.kernel_h else params.kernel_size[0]
k_w = params.kernel_w if params.kernel_w else params.kernel_size[
len(params.kernel_size) - 1]
[s_h, s_w] = [1, 1]
if isinstance(params.stride, numbers.Number):
[s_h, s_w] = [params.stride] * 2
else:
s_h = params.stride_h if params.stride_h else params.stride[0]
s_w = params.stride_w if params.stride_w else params.stride[
len(params.stride) - 1]
[p_h, p_w] = [0, 0]
if isinstance(params.pad, numbers.Number):
[p_h, p_w] = [params.pad] * 2
else:
p_h = params.pad_h if params.pad_h else params.pad[0]
p_w = params.pad_w if params.pad_w else params.pad[len(params.pad) -
1]
dila_h = dila_w = 1
group = 1
c_o = 1
if kind in ['Convolution', 'Deconvolution']:
if kind in ['Convolution', 'Deconvolution', 'ConvolutionDepthwise']:
c_o = params.num_output
group = params.group
dila_len = len(params.dilation)
if dila_len == 2:
dila_h = params.dilation[0]
......@@ -143,12 +171,12 @@ class CaffeOpMapper(OpMapper):
else:
assert dila_len == 0, "invalid length[%s] of dilation in convolution" % (
dila_len)
if kind in ['Convolution', 'Deconvolution']:
group = params.group
kernel = [k_h, k_w]
stride = [s_h, s_w]
pad = [p_h, p_w]
dilation = [dila_h, dila_w]
return c_o, kernel, stride, pad, dilation, group
def get_input_name(self, node):
......@@ -180,7 +208,7 @@ class CaffeOpMapper(OpMapper):
data = node.data
assert data is not None, 'The parameter of {} (type is {}) is not set. You need to use python package of caffe to set the default value.'.format(
node.layer_name, node.layer_type)
data = self.adjust_parameters(node, data)
data = self.adjust_parameters(node)
self.weights[node.layer_name + '_weights'] = data[0]
if len(data) == 2:
self.weights[node.layer_name + '_bias'] = data[1]
......@@ -224,7 +252,7 @@ class CaffeOpMapper(OpMapper):
data = node.data
assert data is not None, 'The parameter of {} (type is {}) is not set. You need to use python package of caffe to set the default value.'.format(
node.layer_name, node.layer_type)
data = self.adjust_parameters(node, data)
data = self.adjust_parameters(node)
self.weights[node.layer_name + '_weights'] = data[0]
if len(data) == 2:
self.weights[node.layer_name + '_bias'] = data[1]
......@@ -343,7 +371,7 @@ class CaffeOpMapper(OpMapper):
data = node.data
assert data is not None, 'The parameter of {} (type is {}) is not set. You need to use python package of caffe to set the default value.'.format(
node.layer_name, node.layer_type)
data = self.adjust_parameters(node, data)
data = self.adjust_parameters(node)
# Reshape the parameters to Paddle's ordering
transpose_order = (1, 0)
w = data[0]
......@@ -396,40 +424,11 @@ class CaffeOpMapper(OpMapper):
shape = node.input_shape[0]
dims = len(shape)
axis = axis + dims if axis < 0 else axis
need_transpose = False
if axis + 1 != dims:
need_transpose = True
if need_transpose:
in_order = list(range(dims))
in_order.remove(axis)
in_order.append(axis)
attr = {
'perm': in_order,
'name': string(node.layer_name + '_transpose_in')
}
node.fluid_code.add_layer("transpose",
inputs=input,
output=node,
param_attr=attr)
attr = {'name': string(node.layer_name + '_softmax')}
attr = {'axis': axis, 'name': string(node.layer_name + '_softmax')}
node.fluid_code.add_layer("softmax",
inputs=node if need_transpose else input,
inputs=input,
output=node,
param_attr=attr)
if need_transpose:
out_order = [
0,
] * dims
for id, v in enumerate(in_order):
out_order[v] = id
attr = {
'perm': out_order,
'name': string(node.layer_name + '_transpose_out')
}
node.fluid_code.add_layer("transpose",
inputs=node,
output=node,
param_attr=attr)
def Slice(self, node):
assert len(
......@@ -451,13 +450,11 @@ class CaffeOpMapper(OpMapper):
attr = {
'axes': [axis],
'starts': [points[i]],
'ends': [points[i + 1]],
'name': string(node.layer_name + '_' + str(i))
'ends': [points[i + 1]]
}
node.fluid_code.add_layer("slice",
inputs=input,
output=string(node.layer_name + '_' +
str(i)),
output=node.layer_name + '_' + str(i),
param_attr=attr)
node.fluid_code.add_note('{}.append({})'.format(
node.layer_name, node.layer_name + '_' + str(i)))
......@@ -503,7 +500,7 @@ class CaffeOpMapper(OpMapper):
node.layer_name, node.layer_type)
self.weights[node.layer_name + '_weights'] = data[0]
attr = {
'mode': mode,
'mode': string(mode),
'param_attr': string(node.layer_name + '_weights'),
'name': string(node.layer_name)
}
......@@ -731,7 +728,7 @@ class CaffeOpMapper(OpMapper):
def Scale(self, node):
assert len(
node.outputs) == 1, 'The count of Scale node\'s output is not 1.'
node.inputs) == 1, 'The count of Scale node\'s input is not 1.'
if len(node.inputs) == 1 and self.graph.get_node(
node.inputs[0]).layer_type == 'BatchNorm':
return
......@@ -1058,7 +1055,9 @@ class CaffeOpMapper(OpMapper):
param_attr=attr)
input_name = self.get_input_name(input)
data = node.data
data = self.adjust_parameters(node, data)
assert data is not None, 'The parameter of {} (type is {}) is not set. You need to use python package of caffe to set the default value.'.format(
node.layer_name, node.layer_type)
data = self.adjust_parameters(node)
self.weights[node.layer_name + '_scale'] = data[0]
node.fluid_code.add_note(
'{}_scale_attr = ParamAttr(name=\'{}\')'.format(
......@@ -1297,7 +1296,7 @@ class CaffeOpMapper(OpMapper):
def Select(self, node):
assert len(
node.inputs) == 1, 'The count of Select node\'s input is not 2.'
node.inputs) == 1, 'The count of Select node\'s input is not 1.'
input = self.graph.get_bottom_node(node, idx=0, copy=True)
if self.is_Scale(input):
tmp = self.graph.get_bottom_node(input, idx=0, copy=True)
......@@ -1327,3 +1326,49 @@ class CaffeOpMapper(OpMapper):
node.layer_name, node.layer_name + '_' + str(i)))
if i == len(slice_point) - 2:
break
def ShuffleChannel(self, node):
assert len(node.inputs
) == 1, 'The count of ShuffleChannel node\'s input is not 1.'
params = node.layer.shuffle_channel_param
group = params.group
input = self.graph.get_bottom_node(node, idx=0, copy=True)
if self.is_Scale(input):
tmp = self.graph.get_bottom_node(input, idx=0, copy=True)
if self.is_BN(tmp):
input = tmp
attr = {'group': group, 'name': string(node.layer_name)}
node.fluid_code.add_layer("shuffle_channel",
inputs=input,
output=node,
param_attr=attr)
def deal_custom_layer(self, node):
op = node.layer_type
custom_code, func = make_custom_layer(node)
params = get_params(node.layer, node.layer_type)
arg_names, kwargs = set_args(func, params)
kwargs['name'] = string(node.layer_name)
kwargs['input_shape'] = node.input_shape
data = node.data
assert data is not None, 'The parameter of {} (type is {}) is not set. You need to use python package of caffe to set the default value.'.format(
node.layer_name, node.layer_type)
data = self.adjust_parameters(node)
weights_name = deal_weights(node)
for i in range(len(data)):
self.weights[weights_name[i]] = data[i]
inputs_node = []
for i in range(len(node.inputs)):
input = self.graph.get_bottom_node(node, idx=i, copy=True)
if self.is_Scale(input):
tmp = self.graph.get_bottom_node(input, idx=0, copy=True)
if self.is_BN(tmp):
input = tmp
inputs_node.append(input)
node.fluid_code.add_layer(func.__code__.co_name,
inputs=inputs_node,
output=node,
param_attr=kwargs,
is_custom_layer=True)
if op not in self.mylayers:
self.mylayers[op] = custom_code
......@@ -453,3 +453,12 @@ def shape_select(layer, input_shape):
output_shape = input_shape
output_shape[axis] = end - start
return [output_shape]
def shape_shufflechannel(layer, input_shape):
return input_shape
# def shape_convolutiondepthwise(layer, input_shape):
# params = layer.convolution_param
# return get_strided_kernel_output_shape(params, input_shape[0], math.floor)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册