提交 e4f6ffa1 编写于 作者: W walloollaw 提交者: qingqing01

caffe2fluid:support ssd model conversion (#1039)

上级 e7d1378f
...@@ -8,6 +8,11 @@ import axpy ...@@ -8,6 +8,11 @@ import axpy
import flatten import flatten
import argmax import argmax
import reshape import reshape
import roipooling
import priorbox
import permute
import detection_out
import normalize
#custom layer import ends #custom layer import ends
......
...@@ -4,11 +4,6 @@ ...@@ -4,11 +4,6 @@
from .register import register from .register import register
def import_fluid():
import paddle.fluid as fluid
return fluid
def flatten_shape(input_shape, axis=1, end_axis=-1): def flatten_shape(input_shape, axis=1, end_axis=-1):
""" calculate the output shape of this layer using input shape """ calculate the output shape of this layer using input shape
...@@ -28,7 +23,7 @@ def flatten_shape(input_shape, axis=1, end_axis=-1): ...@@ -28,7 +23,7 @@ def flatten_shape(input_shape, axis=1, end_axis=-1):
start_axis += len(input_shape) start_axis += len(input_shape)
if end_axis < 0: if end_axis < 0:
end_axis += len(input_shape) end_axis += len(input_shape) + 1
assert start_axis <= end_axis, 'invalid axis[%d] or end_axis[%d] params'\ assert start_axis <= end_axis, 'invalid axis[%d] or end_axis[%d] params'\
% (start_axis, end_axis) % (start_axis, end_axis)
...@@ -52,18 +47,16 @@ def flatten_layer(input, name, axis=1, end_axis=-1): ...@@ -52,18 +47,16 @@ def flatten_layer(input, name, axis=1, end_axis=-1):
Returns: Returns:
output (variable): output variable for this layer output (variable): output variable for this layer
""" """
fluid = import_fluid() import paddle.fluid as fluid
input_shape = list(input.shape) input_shape = list(input.shape)
dims = len(input_shape)
start_axis = axis if axis >= 0 else axis + dims
end_axis = end_axis if end_axis >= 0 else end_axis + dims
assert start_axis <= end_axis, 'invalid axis or end_axis params' if input_shape[0] == -1:
output_shape = input_shape[0:start_axis] input_shape[0] = 1
flat_sz = reduce(lambda a, b: a * b, input_shape[start_axis:end_axis]) output_shape = flatten_shape(input_shape, axis=axis, end_axis=end_axis)
output_shape += [flat_sz] output_shape[0] = -1
output_shape += input_shape[end_axis:-1] else:
output_shape = flatten_shape(input_shape, axis=axis, end_axis=end_axis)
output = fluid.layers.reshape(input, shape=output_shape, name=name) output = fluid.layers.reshape(input, shape=output_shape, name=name)
......
...@@ -68,15 +68,23 @@ def reshape_shape(input_sp, shape, axis=0, num_axes=-1): ...@@ -68,15 +68,23 @@ def reshape_shape(input_sp, shape, axis=0, num_axes=-1):
top_dim = shape['dim'][i] top_dim = shape['dim'][i]
if top_dim == 0: if top_dim == 0:
copy_axes.append(i) copy_axes.append(i)
copy_axis_index = start_axis + i
output_shape[copy_axis_index] = input_shape[copy_axis_index]
elif top_dim == -1: elif top_dim == -1:
assert inferred_axis == -1, "[Reshape]new shape contains multiple -1 dims" assert inferred_axis == -1, "[Reshape]new shape contains multiple -1 dims"
inferred_axis = i
else: else:
constant_count *= top_dim constant_count *= top_dim
if inferred_axis >= 0: if inferred_axis >= 0:
explicit_count = constant_count explicit_count = constant_count
explicit_count *= count(input_shape[0:start_axis]) l = input_shape[0:start_axis]
explicit_count *= count(input_shape[end_axis:]) if len(l) > 0:
explicit_count *= count(l)
l = input_shape[end_axis:]
if len(l) > 0:
explicit_count *= count(l)
for i in range(len(copy_axes)): for i in range(len(copy_axes)):
explicit_count *= output_shape[start_axis + copy_axes[i]] explicit_count *= output_shape[start_axis + copy_axes[i]]
...@@ -84,6 +92,7 @@ def reshape_shape(input_sp, shape, axis=0, num_axes=-1): ...@@ -84,6 +92,7 @@ def reshape_shape(input_sp, shape, axis=0, num_axes=-1):
assert input_count % explicit_count == 0, "[Reshape]botom count[%d] "\ assert input_count % explicit_count == 0, "[Reshape]botom count[%d] "\
"must be divisible by product of the specified dimensions[%d] "\ "must be divisible by product of the specified dimensions[%d] "\
% (input_count, explicit_count) % (input_count, explicit_count)
output_shape[start_axis + inferred_axis] = input_count / explicit_count
output_count = count(output_shape) output_count = count(output_shape)
assert output_count == input_count, "[Reshape]output count[%d] must match input count[%d]" % ( assert output_count == input_count, "[Reshape]output count[%d] must match input count[%d]" % (
...@@ -117,6 +126,7 @@ def reshape_layer(input, name, shape, axis=0, num_axes=-1): ...@@ -117,6 +126,7 @@ def reshape_layer(input, name, shape, axis=0, num_axes=-1):
output_shape = reshape_shape(input_shape, shape, axis, num_axes) output_shape = reshape_shape(input_shape, shape, axis, num_axes)
output = fluid.layers.reshape(input, shape=output_shape, name=name) output = fluid.layers.reshape(input, shape=output_shape, name=name)
return output return output
......
...@@ -179,6 +179,9 @@ class LayerAdapter(object): ...@@ -179,6 +179,9 @@ class LayerAdapter(object):
@property @property
def parameters(self): def parameters(self):
name = NodeDispatch.get_handler_name(self.kind) name = NodeDispatch.get_handler_name(self.kind)
if self.kind.lower() == "normalize":
name = "norm"
name = '_'.join((name, 'param')) name = '_'.join((name, 'param'))
try: try:
return getattr(self.layer, name) return getattr(self.layer, name)
...@@ -217,9 +220,25 @@ class LayerAdapter(object): ...@@ -217,9 +220,25 @@ class LayerAdapter(object):
params.stride_w, params.stride, 1, default=1) params.stride_w, params.stride, 1, default=1)
p_h = self.get_kernel_value(params.pad_h, params.pad, 0, default=0) 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) p_w = self.get_kernel_value(params.pad_w, params.pad, 1, default=0)
return KernelParameters(k_h, k_w, s_h, s_w, p_h, p_w)
KernelParameters = namedtuple('KernelParameters', [ dila_h = dila_w = 1
'kernel_h', 'kernel_w', 'stride_h', 'stride_w', 'pad_h', 'pad_w' if self.kind in (NodeKind.Convolution, ):
]) dila_len = len(params.dilation)
if dila_len == 2:
dila_h = params.dilation[0]
dila_w = params.dilation[1]
elif dila_len == 1:
dila_h = dila_w = params.dilation[0]
else:
assert dila_len == 0, "invalid length[%s] of dilation in convolution" % (
dila_len)
return KernelParameters(k_h, k_w, s_h, s_w, p_h, p_w, dila_h, dila_w)
KernelParameters = namedtuple(
'KernelParameters',
[
'kernel_h', 'kernel_w', 'stride_h', 'stride_w', 'pad_h', 'pad_w',
'dila_h', 'dila_w'
], )
...@@ -91,7 +91,7 @@ class Network(object): ...@@ -91,7 +91,7 @@ class Network(object):
name = '%s_%s' % (op_name, param_name) name = '%s_%s' % (op_name, param_name)
v = fluid.global_scope().find_var(name) v = fluid.global_scope().find_var(name)
w = v.get_tensor() w = v.get_tensor()
w.set(data, place) w.set(data.reshape(w.shape()), place)
except ValueError: except ValueError:
if not ignore_missing: if not ignore_missing:
raise raise
...@@ -144,6 +144,7 @@ class Network(object): ...@@ -144,6 +144,7 @@ class Network(object):
relu=True, relu=True,
relu_negative_slope=0.0, relu_negative_slope=0.0,
padding=None, padding=None,
dilation=1,
group=1, group=1,
biased=True): biased=True):
if padding is None: if padding is None:
...@@ -173,6 +174,7 @@ class Network(object): ...@@ -173,6 +174,7 @@ class Network(object):
num_filters=c_o, num_filters=c_o,
stride=[s_h, s_w], stride=[s_h, s_w],
padding=padding, padding=padding,
dilation=dilation,
groups=group, groups=group,
param_attr=fluid.ParamAttr(name=prefix + "weights"), param_attr=fluid.ParamAttr(name=prefix + "weights"),
bias_attr=fluid.ParamAttr(name=prefix + "biases"), bias_attr=fluid.ParamAttr(name=prefix + "biases"),
......
...@@ -9,21 +9,6 @@ from ..transformers import (DataInjector, DataReshaper, NodeRenamer, ...@@ -9,21 +9,6 @@ from ..transformers import (DataInjector, DataReshaper, NodeRenamer,
from . import network from . import network
def get_padding_type(kernel_params, input_shape, output_shape):
'''Translates Caffe's numeric padding to one of ('SAME', 'VALID').
Caffe supports arbitrary padding values, while Paddle only
supports 'SAME' and 'VALID' modes. So, not all Caffe paddings
can be translated to Paddle. There are some subtleties to
how the padding edge-cases are handled. These are described here:
https://github.com/Yangqing/caffe2/blob/master/caffe2/proto/caffe2_legacy.proto
'''
k_h, k_w, s_h, s_w, p_h, p_w = kernel_params
if p_h > 0 or p_w > 0:
return [p_h, p_w]
else:
return None
class PaddleNode(object): class PaddleNode(object):
'''An intermediate representation for Paddle operations.''' '''An intermediate representation for Paddle operations.'''
...@@ -78,10 +63,11 @@ class PaddleMapper(NodeMapper): ...@@ -78,10 +63,11 @@ class PaddleMapper(NodeMapper):
def get_kernel_params(self, node): def get_kernel_params(self, node):
kernel_params = node.layer.kernel_parameters kernel_params = node.layer.kernel_parameters
input_shape = node.get_only_parent().output_shape input_shape = node.get_only_parent().output_shape
padding = get_padding_type(kernel_params, input_shape, padding = [kernel_params.pad_h, kernel_params.pad_w]
node.output_shape) if padding[0] == 0 and padding[1] == 0:
# Only emit the padding if it's not the default value. padding = {}
padding = {'padding': padding} if padding is not None else {} else:
padding = {'padding': padding}
return (kernel_params, padding) return (kernel_params, padding)
def map_convolution(self, node): def map_convolution(self, node):
...@@ -95,6 +81,10 @@ class PaddleMapper(NodeMapper): ...@@ -95,6 +81,10 @@ class PaddleMapper(NodeMapper):
kwargs['group'] = group kwargs['group'] = group
if not node.parameters.bias_term: if not node.parameters.bias_term:
kwargs['biased'] = False kwargs['biased'] = False
if kernel_params.dila_h != 1 or kernel_params.dila_w != 1:
kwargs['dilation'] = (kernel_params.dila_h, kernel_params.dila_w)
assert kernel_params.kernel_h == h assert kernel_params.kernel_h == h
assert kernel_params.kernel_w == w assert kernel_params.kernel_w == w
return MaybeActivated(node)( return MaybeActivated(node)(
......
...@@ -6,6 +6,8 @@ from .errors import KaffeError ...@@ -6,6 +6,8 @@ from .errors import KaffeError
Tensor4DShape = namedtuple('Tensor4DShape', Tensor4DShape = namedtuple('Tensor4DShape',
['batch_size', 'channels', 'height', 'width']) ['batch_size', 'channels', 'height', 'width'])
Tensor3DShape = namedtuple('Tensor3DShape', ['batch_size', 'data1', 'data2'])
Tensor2DShape = namedtuple('Tensor2DShape', ['batch_size', 'data']) Tensor2DShape = namedtuple('Tensor2DShape', ['batch_size', 'data'])
ScalarShape = namedtuple('ScalarShape', ['batch_size']) ScalarShape = namedtuple('ScalarShape', ['batch_size'])
...@@ -14,6 +16,8 @@ ScalarShape = namedtuple('ScalarShape', ['batch_size']) ...@@ -14,6 +16,8 @@ ScalarShape = namedtuple('ScalarShape', ['batch_size'])
def make_tensor(batch_size, d1=None, d2=None, d3=None): def make_tensor(batch_size, d1=None, d2=None, d3=None):
if d3 is not None: if d3 is not None:
return Tensor4DShape(batch_size, d1, d2, d3) return Tensor4DShape(batch_size, d1, d2, d3)
elif d1 is not None and d2 is not None:
return Tensor3DShape(batch_size, d1, d2)
elif d1 is not None and d2 is None: elif d1 is not None and d2 is None:
return Tensor2DShape(batch_size, d1) return Tensor2DShape(batch_size, d1)
elif d1 is None and d2 is None and d3 is None: elif d1 is None and d2 is None and d3 is None:
...@@ -24,10 +28,14 @@ def make_tensor(batch_size, d1=None, d2=None, d3=None): ...@@ -24,10 +28,14 @@ def make_tensor(batch_size, d1=None, d2=None, d3=None):
def get_filter_output_shape(i_h, i_w, params, round_func): def get_filter_output_shape(i_h, i_w, params, round_func):
o_h = (i_h + 2 * params.pad_h - params.kernel_h dila_h = getattr(params, 'dila_h', 1)
) / float(params.stride_h) + 1 dila_w = getattr(params, 'dila_w', 1)
o_w = (i_w + 2 * params.pad_w - params.kernel_w
) / float(params.stride_w) + 1 o_h = (i_h + 2 * params.pad_h -
(dila_h * (params.kernel_h - 1) + 1)) / float(params.stride_h) + 1
o_w = (i_w + 2 * params.pad_w -
(dila_w * (params.kernel_w - 1) + 1)) / float(params.stride_w) + 1
return (int(round_func(o_h)), int(round_func(o_w))) return (int(round_func(o_h)), int(round_func(o_w)))
......
...@@ -337,6 +337,8 @@ class ParameterNamer(object): ...@@ -337,6 +337,8 @@ class ParameterNamer(object):
names = ('scale', ) names = ('scale', )
if getattr(node.parameters, 'bias_term', False): if getattr(node.parameters, 'bias_term', False):
names = ('scale', 'offset') names = ('scale', 'offset')
elif node.kind == "Normalize":
names = ('scale', )
else: else:
warn('Unhandled parameters when naming this it[%s]' % warn('Unhandled parameters when naming this it[%s]' %
(node.kind)) (node.kind))
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册