Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Tong ZHAN 2018-05-17 15:23:44 +08:00
Родитель 5e3f4ffa98 72635b9e53
Коммит 79b061ee2e
5 изменённых файлов: 182 добавлений и 68 удалений

Просмотреть файл

@ -1,6 +1,21 @@
# CoreML README
Currently we only implemented the CoreML emitter (IR -> CoreML) part. Any contribution to CoreML model parser (CoreML -> IR) part or emitter part is welcome.
We tested the [Awesome-CoreML-Models](https://github.com/likedan/Awesome-CoreML-Models) and the parser works. Any contribution is welcome.
Models | Caffe | CoreML | CNTK | Keras | MXNet | PyTorch | TensorFlow
:-----------------------:|:-----:|:------:|:----:|:-----:|:-----:|:-------:|:------:|
Vgg16 | √ | √ | | √ | √ | √ | √
Inception_v3 | √ | √ | | √ | √ | √ | √
ResNet 50 | √ | √ | | √ | √ | √ | √
MobileNet V1 | √ | √ | | √ | √ | √ | √
Tiny-yolo | | √ | | √ | √ | √ | √
**√** - Correctness tested
**o** - Some difference after conversion
**space** - not tested
---
@ -90,7 +105,7 @@ The inference result is slightly different from the original keras model. Curren
## Develop version
macOS High Sierra 10.13.2 (17C205)
macOS High Sierra 10.13.3 (17C205)
@ 2018/01/10

Просмотреть файл

@ -490,47 +490,6 @@ class CoremlParser(Parser):
def _convert_pooling(self, source_node, dim, pooling_type, is_global):
source_node_layer = source_node.layer
IR_node = self.IR_graph.node.add()
# name, op
CoremlParser._copy_and_repo(resource_node, IR_node, "Pool")
# input edge
self.convert_inedge(source_node, IR_node)
kwargs = {}
kwargs['pooling_type'] = pooling_type
if is_global:
kwargs['global_pooling'] = True
kwargs['strides'] = [1] * (dim + 2)
else:
# padding
self._convert_padding(source_node, IR_node)
# strides
# [1, sd, sh, sw, 1]
kwargs['strides'] = [1, 1] + list(source_node) + [1]
# window_shape
# [1, pd, ph, pw, 1]
kwagrs['kernel_shape'] = [1,1] + list(source_node_layer.kernelSize) + [1]
assign_IRnode_values(IR_node, kwargs)
if is_global:
flatten_node = self.IR_graph.node.add()
flatten_node.name = source_node_layer.name + "_flatten"
flatten_node.op = 'Flatten'
flatten_node.input.append(source_node_layer.name)
CoremlParser._set_output_shape(source_node, flatten_node)
source_node.real_name = flatten_node_layer.name
def _convert_merge(self, source_node, new_name = None):
IR_node = self.IR_graph.node.add()
@ -865,6 +824,7 @@ class CoremlParser(Parser):
# [1, sd, sh, sw, 1]
kwargs['strides'] = [1] + list(coreml_node_pool.stride) + [1]
# window_shape
# [1, pd, ph, pw, 1]
kwargs['kernel_shape'] = [1] + list(coreml_node_pool.kernelSize) + [1]

Просмотреть файл

@ -34,7 +34,7 @@ def _main():
type=_text_type, help='Test Image Path')
parser.add_argument('-o', '--output_dir', default='./',
type=_text_type, help='Caffe Checkpoint file name')
type=_text_type, help='CNTK Checkpoint file name')
args = parser.parse_args()

Просмотреть файл

@ -201,25 +201,50 @@ class KitModel(nn.Module):
))
else:
for e in IR_node.get_attr('dilations', []):
assert e == 1
pool_size = IR_node.get_attr('kernel_shape')[1:-1]
strides = IR_node.get_attr('strides')[1:-1]
if IR_node.get_attr('pooling_type') == "MAX":
# Change to padding defuse
input_node = self._defuse_padding(IR_node,", value=float('-inf')")
for e in IR_node.get_attr('dilations', []):
assert e == 1
padding = IR_node.get_attr('pads')[1:dim]
ceil_mode = self.is_ceil_mode(IR_node.get_attr('pads'))
pool_size = IR_node.get_attr('kernel_shape')[1:-1]
strides = IR_node.get_attr('strides')[1:-1]
# input_node = self._defuse_padding(IR_node, exstr)
self.add_body(2, "{:<15} = F.{}({}, kernel_size={}, stride={}, padding={}, ceil_mode={})".format(
IR_node.variable_name,
pool_name,
self.parent_variable_name(IR_node),
tuple(pool_size),
tuple(strides),
tuple(padding),
ceil_mode
))
self.add_body(2, "{:<15} = F.{}({}, kernel_size={}, stride={}, padding={}, ceil_mode={})".format(
IR_node.variable_name,
pool_name,
input_node,
tuple(pool_size),
tuple(strides),
0,
False
))
elif IR_node.get_attr('pooling_type') == "AVG":
for e in IR_node.get_attr('dilations', []):
assert e == 1
pool_size = IR_node.get_attr('kernel_shape')[1:-1]
strides = IR_node.get_attr('strides')[1:-1]
padding = IR_node.get_attr('pads')[1:dim]
ceil_mode = self.is_ceil_mode(IR_node.get_attr('pads'))
# input_node = self._defuse_padding(IR_node, exstr)
self.add_body(2, "{:<15} = F.{}({}, kernel_size={}, stride={}, padding={}, ceil_mode={})".format(
IR_node.variable_name,
pool_name,
self.parent_variable_name(IR_node),
tuple(pool_size),
tuple(strides),
tuple(padding),
ceil_mode
))
else:
raise ValueError()
def emit_UNKNOWN(self, IR_node):
@ -306,6 +331,14 @@ class KitModel(nn.Module):
self.IR_graph.get_parent(IR_node.name, [0]).real_variable_name))
def emit_LeakyRelu(self, IR_node):
self.add_body(2, "{:<15} = F.leaky_relu({}, negative_slope={})".format(
IR_node.variable_name,
self.IR_graph.get_parent(IR_node.name, [0]).real_variable_name,
IR_node.get_attr('alpha')))
def emit_Relu6(self, IR_node):
self.add_body(2, "{:<15} = F.relu6({})".format(
IR_node.variable_name,
@ -432,6 +465,23 @@ class KitModel(nn.Module):
self.parent_variable_name(IR_node)
))
def emit_Scale(self, IR_node):
self.used_layers.add(IR_node.type)
dim = len(IR_node.layer.attr['_output_shapes'].list.shape[0].dim) - 2
self.add_init(2, "self.{} = self.__scale({}, '{}', num_features={})".format(
IR_node.variable_name,
dim,
IR_node.name,
IR_node.layer.attr['_output_shapes'].list.shape[0].dim[-1].size
))
self.add_body(2, "{:<15} = self.{}({})".format(
IR_node.variable_name,
IR_node.variable_name,
self.parent_variable_name(IR_node)
))
def emit_Squeeze(self, IR_node):
self.add_body(2, "{:<15} = torch.squeeze({})".format(
@ -450,11 +500,11 @@ class KitModel(nn.Module):
def emit_Pad(self, IR_node):
if IR_node.get_attr('mode') == 'constant':
if IR_node.get_attr('mode').lower() == 'constant':
mode = "mode = 'constant', value = {}".format(0)
elif IR_node.get_attr('mode') == 'reflect':
elif IR_node.get_attr('mode').lower() == 'reflect':
mode = "mode = 'reflect'"
elif IR_node.get_attr('mode') == 'SYMMETRIC':
elif IR_node.get_attr('mode').upper() == 'SYMMETRIC':
mode = "mode = 'replicate'"
else:
assert False
@ -565,6 +615,95 @@ class KitModel(nn.Module):
return layer""")
def _layer_Scale(self):
self.add_body(0, """
# from torch.nn.parameter import Parameter
class _Scale(nn.Module):
def __init__(self, num_features, affine=True):
super(KitModel._Scale, self).__init__()
self.num_features = num_features
self.affine = affine
self.running_mean = torch.zeros(num_features)
self.running_var = torch.ones(num_features)
self.training = False
self.eps = 1e-5
if self.affine:
self.weight = nn.Parameter(torch.Tensor(num_features))
self.bias = nn.Parameter(torch.Tensor(num_features))
else:
self.register_parameter('weight', None)
self.register_parameter('bias', None)
self.reset_parameters()
def reset_parameters(self):
if self.affine:
self.weight.data.uniform_()
self.bias.data.zero_()
def _check_input_dim(self, input):
raise NotImplementedError
def forward(self, input):
self._check_input_dim(input)
return F.batch_norm(
input, self.running_mean, self.running_var, self.weight, self.bias,
self.training,
0 , self.eps)
class Scale1d(_Scale):
def _check_input_dim(self, input):
if input.dim() != 2 and input.dim() != 3:
raise ValueError('expected 2D or 3D input (got {}D input)'
.format(input.dim()))
class Scale2d(_Scale):
def _check_input_dim(self, input):
if input.dim() != 4:
raise ValueError('expected 4D input (got {}D input)'
.format(input.dim()))
class Scale3d(_Scale):
def _check_input_dim(self, input):
if input.dim() != 5:
raise ValueError('expected 5D input (got {}D input)'
.format(input.dim()))
@staticmethod
def __scale(dim, name, **kwargs):
if dim == 1: layer = KitModel.Scale1d(**kwargs)
elif dim == 2: layer = KitModel.Scale2d(**kwargs)
elif dim == 3: layer = KitModel.Scale3d(**kwargs)
else: raise NotImplementedError()
if 'scale' in __weights_dict[name]:
layer.state_dict()['weight'].copy_(torch.from_numpy(__weights_dict[name]['scale']))
else:
layer.weight.data.fill_(1)
if 'bias' in __weights_dict[name]:
layer.state_dict()['bias'].copy_(torch.from_numpy(__weights_dict[name]['bias']))
else:
layer.bias.data.fill_(0)
return layer""")
def _layer_LRN(self):
self.add_body(0, """
class LRN(nn.Module):

Просмотреть файл

@ -736,11 +736,11 @@ class TestModels(CorrectnessTest):
},
'coreml' : {
'inception_v3' : [CaffeEmit, CoreMLEmit, KerasEmit, MXNetEmit, TensorflowEmit],
'mobilenet' : [CaffeEmit, CoreMLEmit, KerasEmit, MXNetEmit, TensorflowEmit],
'resnet50' : [CaffeEmit, CoreMLEmit, KerasEmit, MXNetEmit, TensorflowEmit],
'tinyyolo' : [CoreMLEmit, KerasEmit, MXNetEmit, TensorflowEmit],
'vgg16' : [CaffeEmit, CoreMLEmit, KerasEmit, MXNetEmit, TensorflowEmit],
'inception_v3' : [CaffeEmit, CoreMLEmit, KerasEmit, MXNetEmit, PytorchEmit, TensorflowEmit],
'mobilenet' : [CaffeEmit, CoreMLEmit, KerasEmit, MXNetEmit, PytorchEmit, TensorflowEmit],
'resnet50' : [CaffeEmit, CoreMLEmit, KerasEmit, MXNetEmit, PytorchEmit, TensorflowEmit],
'tinyyolo' : [CoreMLEmit, KerasEmit, MXNetEmit, PytorchEmit, TensorflowEmit],
'vgg16' : [CaffeEmit, CoreMLEmit, KerasEmit, MXNetEmit, PytorchEmit, TensorflowEmit],
},
'darknet' : {