Skip to content

Commit 45afaa0

Browse files
author
wangqianwen0418
committed
2 parents d4786dc + 2dca0a4 commit 45afaa0

18 files changed

+900
-585
lines changed

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,28 @@ The intermediate representation will store the network structures as a protobuf
3232
- [MXNet](http://mxnet.incubator.apache.org/)
3333
- [Tensorflow](https://www.tensorflow.org/) (Experimental)
3434
- [Microsoft Cognitive Toolkit (CNTK)](http://www.microsoft.com/en-us/cognitive-toolkit) (Destination only)
35+
- [PyTorch](http://pytorch.org/) (Destination only)
3536

3637
#### Tested models
3738

3839
The model conversion between current supported frameworks is tested on some **ImageNet** models.
3940

4041
Models | Caffe | Keras | Tensorflow | CNTK | MXNet | PyTorch |
4142
:--------------------------------------------------:|:-----:|:-----:|:----------:|:----:|:-----:|:-------:|
42-
[Inception V1](http://arxiv.org/abs/1409.4842v1) | √ | √ | √ | √ | √
43-
[Inception V3](http://arxiv.org/abs/1512.00567) | × | √ | √ | √ | √
43+
[Inception V1](http://arxiv.org/abs/1409.4842v1) | √ | √ | √ | √ | √ | x (No LRN)
44+
[Inception V3](http://arxiv.org/abs/1512.00567) | × | √ | √ | √ | √ | √
4445
[ResNet V1 50](https://arxiv.org/abs/1512.03385) | × | √ | √ | o | √ | √
45-
[ResNet V2 152](https://arxiv.org/abs/1603.05027) | × | √ | √ | √ | √ |
46+
[ResNet V2 152](https://arxiv.org/abs/1603.05027) | × | √ | √ | √ | √ |
4647
[VGG 19](http://arxiv.org/abs/1409.1556.pdf) | √ | √ | √ | √ | √ | √
47-
[MobileNet_v1](https://arxiv.org/pdf/1704.04861.pdf)| × | √ | √ | × (No Relu6) | ×
48-
[Xception](https://arxiv.org/pdf/1610.02357.pdf) | × | √ | √ | × | × |
49-
[SqueezeNet](https://arxiv.org/pdf/1602.07360) | | √ | √ | √ | √ |
48+
[MobileNet_v1](https://arxiv.org/pdf/1704.04861.pdf)| × | √ | √ | × (No Relu6) | × | ×
49+
[Xception](https://arxiv.org/pdf/1610.02357.pdf) | × | √ | √ | × | × | ×
50+
[SqueezeNet](https://arxiv.org/pdf/1602.07360) | | √ | √ | √ | √ | ×
5051

5152
#### On-going frameworks
5253

5354
- [Caffe2](https://caffe2.ai/)
5455
- [CoreML](https://developer.apple.com/documentation/coreml)
55-
- [PyTorch](http://pytorch.org/)
56+
5657

5758
#### Usage
5859

mmdnn/conversion/caffe/common_graph.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
#----------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
#----------------------------------------------------------------------------------------------
5+
16
from six import string_types as _string_types
27
from mmdnn.conversion.caffe.errors import ConversionError
38
from mmdnn.conversion.common.IR.graph_pb2 import GraphDef, NodeDef, TensorShape

mmdnn/conversion/caffe/mapper.py

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ def get_handler_name(node_kind):
1414

1515

1616
class NodeMapper(object):
17-
17+
1818
@classmethod
1919
def _convert_output_shape(cls, kwargs, node):
2020
shape = TensorShape()
2121
dim = shape.dim.add()
2222
dim.size = -1
23-
23+
2424
if len(node.output_shape) > 2:
2525
for i in node.output_shape[2:]:
2626
dim = shape.dim.add()
@@ -31,22 +31,22 @@ def _convert_output_shape(cls, kwargs, node):
3131
dim = shape.dim.add()
3232
dim.size = node.output_shape[1]
3333
kwargs['_output_shapes'] = [shape]
34-
34+
3535
@classmethod
3636
def get_kernel_params(cls, node):
37-
kwargs = {}
37+
kwargs = {}
3838
if node.kernel_parameters.p_h > 0 or node.kernel_parameters.p_w > 0:
39-
padding = [0, 0, node.kernel_parameters.p_h, node.kernel_parameters.p_h, node.kernel_parameters.p_w, node.kernel_parameters.p_w, 0, 0]
39+
padding = [0, node.kernel_parameters.p_h, node.kernel_parameters.p_w, 0, 0, node.kernel_parameters.p_h, node.kernel_parameters.p_w, 0]
4040
elif node.kernel_parameters.s_h > 1 or node.kernel_parameters.s_w > 1:
41-
padding = [0, 0, (node.kernel_parameters.s_h - 1) // 2, node.kernel_parameters.s_h // 2, (node.kernel_parameters.s_w - 1) // 2, node.kernel_parameters.s_w // 2, 0, 0]
41+
padding = [0, (node.kernel_parameters.s_h - 1) // 2, (node.kernel_parameters.s_w - 1) // 2, 0, 0, node.kernel_parameters.s_h // 2, node.kernel_parameters.s_w // 2, 0]
4242
else:
4343
padding = None
44-
45-
kwargs['padding'] = 'VALID'
44+
45+
kwargs['auto_pad'] = 'VALID'
4646
kwargs['strides'] = [1, node.kernel_parameters.s_h, node.kernel_parameters.s_w, 1]
4747
cls._convert_output_shape(kwargs, node)
48-
49-
return kwargs, {'paddings' : padding, 'mode' : 'CONSTANT', 'constant_values' : 0.0}
48+
49+
return kwargs, {'pads' : padding, 'mode' : 'constant', 'constant_values' : 0.0}
5050

5151

5252
@classmethod
@@ -60,7 +60,7 @@ def map_data(cls, node):
6060
dim.size = i
6161
dim = shape.dim.add()
6262
dim.size = node.output_shape.channels
63-
63+
6464
kwargs = {'shape': shape} # Ignore the dimension of batch size
6565
cls._convert_output_shape(kwargs, node)
6666
return Node.create('DataInput', **kwargs)
@@ -74,29 +74,30 @@ def map_input(cls, node):
7474
def map_convolution(cls, node):
7575
kwargs, padding = cls.get_kernel_params(node)
7676
parent, _ = node.get_only_parent()
77-
kwargs['filter'] = [node.kernel_parameters.k_h, node.kernel_parameters.k_w, parent.output_shape.channels, node.parameters.num_output]
78-
kwargs['use_bias'] = node.parameters.bias_term
77+
kwargs['kernel_shape'] = [node.kernel_parameters.k_h, node.kernel_parameters.k_w, parent.output_shape.channels, node.parameters.num_output]
78+
kwargs['use_bias'] = node.parameters.bias_term
7979
group = node.parameters.group
8080
if group != 1:
8181
kwargs['group'] = group
82-
83-
if padding['paddings'] != None:
84-
return [Node.create('Pad', **padding), Node.create('Convolution', **kwargs)]
82+
83+
if padding['pads'] != None:
84+
return [Node.create('Pad', **padding), Node.create('Conv', **kwargs)]
8585
else:
86-
return Node.create('Convolution', **kwargs)
86+
kwargs['pads'] = [0] * 8
87+
return Node.create('Conv', **kwargs)
8788

8889

8990
@classmethod
9091
def map_deconvolution(cls, node):
9192
raise NotImplementedError()
9293
kwargs = cls.get_kernel_params(node)
9394
parent, _ = node.get_only_parent()
94-
kwargs['filter'] = [node.kernel_parameters.k_h, node.kernel_parameters.k_w, parent.output_shape.channels, node.parameters.num_output]
95+
kwargs['kernel_shape'] = [node.kernel_parameters.k_h, node.kernel_parameters.k_w, parent.output_shape.channels, node.parameters.num_output]
9596
group = node.parameters.group
9697
if group != 1:
97-
kwargs['group'] = group
98+
kwargs['group'] = group
9899
return Node.create('deconv', **kwargs)
99-
100+
100101
@classmethod
101102
def map_crop(cls, node):
102103
offset = node.parameters.offset
@@ -105,13 +106,13 @@ def map_crop(cls, node):
105106
return Node.create('crop', **kwargs)
106107
else:
107108
return Node.create('crop')
108-
109+
109110
@classmethod
110111
def map_relu(cls, node):
111112
kwargs = {}
112113
cls._convert_output_shape(kwargs, node)
113114
return Node.create('Relu', **kwargs)
114-
115+
115116
@classmethod
116117
def map_pooling(cls, node):
117118
kwargs, padding = cls.get_kernel_params(node)
@@ -122,21 +123,22 @@ def map_pooling(cls, node):
122123
else:
123124
# Stochastic pooling, for instance.
124125
raise ConversionError('Unsupported pooling type.')
125-
kwargs['window_shape'] = [1, node.kernel_parameters.k_h, node.kernel_parameters.k_w, 1]
126+
kwargs['kernel_shape'] = [1, node.kernel_parameters.k_h, node.kernel_parameters.k_w, 1]
126127
cls._convert_output_shape(kwargs, node)
127-
128-
if padding['paddings'] != None:
128+
129+
if padding['pads'] != None:
129130
return [Node.create('Pad', **padding), Node.create('Pool', **kwargs)]
130131
else:
132+
kwargs['pads'] = [0] * 8
131133
return Node.create('Pool', **kwargs)
132-
134+
133135

134136
@classmethod
135137
def _add_flatten_layer(cls, node):
136138
shape = TensorShape()
137139
dim = shape.dim.add()
138-
dim.size = -1
139-
140+
dim.size = -1
141+
140142
dim = shape.dim.add()
141143
dim.size = 1
142144
for i in node.output_shape[1:]:
@@ -149,40 +151,40 @@ def map_inner_product(cls, node):
149151
#TODO: Axis
150152
assert node.parameters.axis == 1
151153
#TODO: Unbiased
152-
kwargs = {'use_bias' : node.parameters.bias_term, 'units' : node.parameters.num_output}
153-
154+
kwargs = {'use_bias' : node.parameters.bias_term, 'units' : node.parameters.num_output}
155+
154156
# check if need the Flatten layer
155157
parent, _ = node.get_only_parent()
156158
ret = []
157159
if parent.output_shape.height > 1 or parent.output_shape.width > 1:
158160
ret.append(cls._add_flatten_layer(parent))
159161
ret.append(Node.create('FullyConnected', **kwargs))
160162
return ret
161-
163+
162164
@classmethod
163165
def map_softmax(cls, node):
164166
return Node.create('Softmax')
165-
167+
166168
@classmethod
167169
def map_lrn(cls, node):
168170
params = node.parameters
169171
assert params.local_size % 2 == 1
170172
kwargs = {'size': int((params.local_size + 1) / 2), 'alpha': params.alpha, 'beta': params.beta, 'k' : params.k}
171173
cls._convert_output_shape(kwargs, node)
172174
return Node.create('LRN', **kwargs)
173-
175+
174176
@classmethod
175177
def map_concat(cls, node):
176178
kwargs = {'axis': (2, 3, 1, 0)[node.parameters.axis]}
177179
cls._convert_output_shape(kwargs, node)
178180
return Node.create('Concat', **kwargs)
179-
181+
180182
@classmethod
181183
def map_dropout(cls, node):
182184
kwargs = {'keep_prob': node.parameters.dropout_ratio}
183185
cls._convert_output_shape(kwargs, node)
184186
return Node.create('Dropout', **kwargs)
185-
187+
186188
@classmethod
187189
def map_batch_norm(cls, node):
188190
scale_offset = len(node.data) == 4
@@ -191,12 +193,12 @@ def map_batch_norm(cls, node):
191193
kwargs['epsilon'] = epsilon
192194
cls._convert_output_shape(kwargs, node)
193195
return Node.create('batch_normalization', **kwargs)
194-
196+
195197
@classmethod
196198
def map_eltwise(cls, node):
197199
operations = {0: 'mul', 1: 'sum', 2: 'max'}
198200
op_code = node.parameters.operation
199-
try:
201+
try:
200202
return Node.create(operations[op_code])
201203
except KeyError:
202204
raise ConversionError('Unknown elementwise operation: {}'.format(op_code))

mmdnn/conversion/caffe/utils.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
#----------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
#----------------------------------------------------------------------------------------------
5+
16
import re
27

3-
48
def get_lower_case(text):
59
'''
610
Convert PascalCase name to words concatenated by '_'.
@@ -19,13 +23,3 @@ def get_upper_case(text):
1923
def get_real_name(text):
2024
text = text.strip().split(':')
2125
return ''.join(text[:-1])
22-
23-
def listToStr(data):
24-
ret = ""
25-
first = True
26-
for e in data:
27-
if first == False:
28-
ret += ", "
29-
ret += str(e)
30-
first = False
31-
return ret

0 commit comments

Comments
 (0)