Skip to content

Commit

Permalink
fix cntk padding.
Browse files Browse the repository at this point in the history
  • Loading branch information
kitstar committed Dec 6, 2017
1 parent 86e834e commit 52c0386
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 35 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Models | Caffe | Keras | Tensorflow
[Inception V1](http://arxiv.org/abs/1409.4842v1) | √ | √ | √ | √ | √ | x (No LRN)
[Inception V3](http://arxiv.org/abs/1512.00567) | × | √ | √ | √ | √ | √
[ResNet V1 50](https://arxiv.org/abs/1512.03385) | × | √ | √ | o | √ | √
[ResNet V2 152](https://arxiv.org/abs/1603.05027) | × | √ | √ | √ | √ | √
[ResNet V2 152](https://arxiv.org/abs/1603.05027) | | √ | √ | √ | √ | √
[VGG 19](http://arxiv.org/abs/1409.1556.pdf) | √ | √ | √ | √ | √ | √
[MobileNet_v1](https://arxiv.org/pdf/1704.04861.pdf)| × | √ | √ | × (No Relu6) | × | ×
[Xception](https://arxiv.org/pdf/1610.02357.pdf) | × | √ | √ | × | × | ×
Expand Down
9 changes: 5 additions & 4 deletions mmdnn/conversion/caffe/transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def __init__(self, def_path, data_path):
# A list containing (layer name, parameters) tuples
self.params = None
# Load the parameters
self.caffemodel = None
self.caffemodel = None
if has_pycaffe() and self.def_path:
self.load_using_caffe()
else:
Expand Down Expand Up @@ -322,7 +322,8 @@ def __init__(self, def_path, data_path, target_toolkit, input_shape=None, phase=
}),
ParameterNamer() # Convert parameters to dictionaries
])
self.graph = NodeRenamer()(graph)
self.graph = graph
# self.graph = NodeRenamer()(graph)
print_stderr(self.graph)

def gen_prototxt_from_caffemodel(self, data_path, input_shape):
Expand Down Expand Up @@ -354,7 +355,7 @@ def transform_graph(self):
name = get_upper_case(get_lower_case(self.graph.name))
return Graph(name, ret)
#return Graph(name, [self.map_node(node) for node in self.graph.nodes])

def get_handler(self, node_kind, prefix):
name = get_handler_name(node_kind)
name = '_'.join((prefix, name))
Expand Down Expand Up @@ -382,7 +383,7 @@ def map_node(self, node):
cur_node.output.extend([node.name + '_' + str(idx + 1)])

self.layer_name_map[node.name] = node.name + '_' + str(len(mapped_node) - 1)
ret.append(cur_node)
ret.append(cur_node)
return ret

else:
Expand Down
78 changes: 60 additions & 18 deletions mmdnn/conversion/cntk/cntk_emitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import os

import cntk
from mmdnn.conversion.common.IR.IR_graph import IRGraph, IRGraphNode
import mmdnn.conversion.common.IR.graph_pb2 as graph_pb2
from mmdnn.conversion.common.IR.graph_pb2 import NodeDef, GraphDef, DataType
Expand Down Expand Up @@ -97,12 +98,43 @@ def _shapeToStr(shapes):
new_shape = filter(lambda x:x >- 1, [dim.size for dim in shapes.dim])
return ', '.join('%s' % i for i in new_shape)

@staticmethod
def is_valid_padding(auto_pad, pads):
"""
different from utils.is_valid_padding
"""
if auto_pad:
if auto_pad == 'VALID':
return True
elif auto_pad.startswith('SAME'):
return False
else:
raise ValueError("Unknown padding type{}.".format(auto_pad))

else:
lens = len(pads)
assert lens % 2 == 0
for i in range(0, lens // 2):
if pads[i] != 0:
return False
return True

@staticmethod
def is_ceil_mode(pads):
lens = len(pads)
for i in range(lens // 2 + 1, lens - 1):
if pads[i] == pads[i - lens // 2]:
return False
else:
return True


def emit_Conv(self, IR_node):
if self.weight_loaded:
self.used_layers.add(IR_node.type)
dim = len(IR_node.get_attr('strides')) - 2
padding = [False] + [IR_node.get_attr('auto_pad') != 'VALID'] * dim
padding = not self.is_valid_padding(IR_node.get_attr('auto_pad'), IR_node.get_attr('pads'))
padding = [False] + [padding] * dim
self.add_body(1, "{:<15} = convolution({}, strides={}, auto_padding={}, dilation={}, groups={}, name='{}')".format(
IR_node.variable_name,
self.parent_variable_name(IR_node),
Expand Down Expand Up @@ -137,23 +169,33 @@ def emit_Pool(self, IR_node):
for e in IR_node.get_attr('dilations', []):
assert e == 1

pool_size = ', '.join('%s' % id for id in IR_node.get_attr('kernel_shape')[1:-1])
strides = ', '.join('%s' % id for id in IR_node.get_attr('strides')[1:-1])
padding = IR_node.get_attr('auto_pad') != 'VALID'
dim = len(IR_node.get_attr('kernel_shape')) - 2
padding = not self.is_valid_padding(IR_node.get_attr('auto_pad'), IR_node.get_attr('pads'))
padding = [False] + [padding] * dim
ceil_out_dim = self.is_ceil_mode(IR_node.get_attr('pads'))

pooling_type = IR_node.get_attr('pooling_type')
if pooling_type == 'MAX':
pooling_type = cntk.MAX_POOLING
elif pooling_type == 'AVG':
pooling_type = cntk.AVG_POOLING
else:
raise ValueError

if self.weight_loaded:
self.used_layers.add(IR_node.type)
self.add_body(1, "{:<15} = pooling({}, '{}', filter_shape = ({}), strides = ({}), pad = {}, name = '{}')".format(
self.add_body(1, "{:<15} = pooling({}, pooling_type={}, pooling_window_shape={}, strides={}, auto_padding={}, ceil_out_dim={})".format(
IR_node.variable_name,
input_node,
IR_node.get_attr('pooling_type'),
pool_size,
strides,
pooling_type,
tuple(IR_node.get_attr('kernel_shape')[1:-1]),
tuple(IR_node.get_attr('strides')[1:-1]),
padding,
IR_node.name))
ceil_out_dim
))

else:
raise NotImplementedError("")
raise NotImplementedError


def emit_UNKNOWN(self, IR_node):
Expand Down Expand Up @@ -253,7 +295,7 @@ def emit_GRU(self, IR_node):

def emit_Add(self, IR_node):
if len(IR_node.in_edges) > 1:
inputs = '+ '.join(self.IR_graph.get_node(i).real_variable_name for i in IR_node.in_edges)
inputs = ' +'.join(self.IR_graph.get_node(i).real_variable_name for i in IR_node.in_edges)
self.add_body(1, "{:<15} = {}".format(
IR_node.variable_name,
inputs))
Expand All @@ -270,7 +312,7 @@ def emit_Concat(self, IR_node):

def emit_BatchNorm(self, IR_node):
self.used_layers.add(IR_node.type)
self.add_body(1, "{:<15} = batch_normalization({}, epsilon = {}, name = '{}')".format(
self.add_body(1, "{:<15} = batch_normalization({}, epsilon={}, name='{}')".format(
IR_node.variable_name,
self.parent_variable_name(IR_node),
IR_node.get_attr('epsilon'),
Expand All @@ -290,7 +332,7 @@ def emit_Pad(self, IR_node):
padding = IR_node.get_attr('pads')
padding = convert_onnx_pad_to_tf(padding)[1:]

self.add_body(1, "{:<15} = ops.pad({}, pattern = {}, {})".format(
self.add_body(1, "{:<15} = ops.pad({}, pattern={}, {})".format(
IR_node.variable_name,
self.parent_variable_name(IR_node),
padding,
Expand Down Expand Up @@ -336,7 +378,7 @@ def _layer_FullyConnected(self):
def dense(input, name, **kwargs):
w = __weights_dict[name]['weights']
b = __weights_dict[name]['bias'] if 'bias' in __weights_dict[name] else None
return BlockApiSetup.linear(output_shape = w.shape[1], input_shape = w.shape[0], scale_init = w, bias_init = b, name = name, **kwargs)(input)
return BlockApiSetup.linear(output_shape=w.shape[1], input_shape=w.shape[0], scale_init=w, bias_init=b, name=name, **kwargs)(input)
""")


Expand All @@ -346,14 +388,14 @@ def convolution(input, name, **kwargs):
dim = __weights_dict[name]['weights'].ndim
weight = np.transpose(__weights_dict[name]['weights'], [dim - 1, dim - 2] + list(range(0, dim - 2)))
w = cntk.Parameter(init = weight, name = name + '_weight')
w = cntk.Parameter(init=weight, name=name + '_weight')
input = cntk.transpose(input, [dim - 2] + list(range(0, dim - 2)))
layer = ops.convolution(w, input, **kwargs)
if 'bias' in __weights_dict[name]:
bias = np.reshape(__weights_dict[name]['bias'], [-1] + [1] * (dim - 2))
b = cntk.Parameter(init = bias, name = name + '_bias')
b = cntk.Parameter(init=bias, name=name + '_bias')
layer = layer + b
layer = cntk.transpose(layer, list(range(1, dim - 1)) + [0])
return layer
Expand All @@ -362,10 +404,10 @@ def convolution(input, name, **kwargs):

def _layer_Pool(self):
self.add_body(0, """
def pooling(input, type, name, **kwargs):
def pooling(input, **kwargs):
dim = len(input.output.shape)
input = cntk.transpose(input, [dim - 1] + list(range(0, dim - 1)))
layer = layers.MaxPooling(**kwargs)(input) if type == 'MAX' else layers.AveragePooling(**kwargs)(input)
layer = ops.pooling(input, **kwargs)
layer = cntk.transpose(layer, list(range(1, dim)) + [0])
return layer
""")
Expand Down
22 changes: 11 additions & 11 deletions mmdnn/conversion/examples/cntk/imagenet_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,35 @@ class TestCNTK(TestKit):

def __init__(self):
super(TestCNTK, self).__init__()

self.truth['keras']['resnet'] = [(144, 0.77398175), (23, 0.10650793), (21, 0.081077583), (146, 0.0092755388), (562, 0.0089645367)]
self.truth['tensorflow']['resnet'] = [(22, 13.589937), (147, 8.9272985), (90, 5.7173862), (24, 5.7097111), (88, 4.77315)]
self.truth['tensorflow']['resnet'] = [(22, 13.370872), (147, 8.8040094), (24, 5.6983061), (90, 5.6143088), (95, 4.8060427)]

self.model = self.MainModel.KitModel(self.args.w)
# self.model, self.testop = self.MainModel.KitModel(self.args.w)


def preprocess(self, image_path):
self.data = super(TestCNTK, self).preprocess(image_path)
self.data = super(TestCNTK, self).preprocess(image_path)


def print_result(self):
predict = self.model.eval({self.model.arguments[0]:[self.data]})
super(TestCNTK, self).print_result(predict)


def print_intermediate_result(self, layer_name, if_transpose = False):
test_arr = self.testop.eval({self.testop.arguments[0]:[self.data]})
super(TestCNTK, self).print_intermediate_result(test_arr, if_transpose)


def inference(self, image_path):
self.preprocess(image_path)

# self.print_intermediate_result(None, False)

self.print_result()

self.test_truth()

def dump(self, path = None):
Expand All @@ -53,7 +53,7 @@ def dump(self, path = None):
path, self.args.n, self.args.w))


if __name__=='__main__':
if __name__=='__main__':
tester = TestCNTK()
if tester.args.dump:
tester.dump()
Expand Down
2 changes: 1 addition & 1 deletion mmdnn/conversion/tensorflow/tensorflow_emitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def emit_Pool(self, IR_node):
pooling_type = IR_node.get_attr('pooling_type')
if pooling_type == 'MAX':
op = 'max_pool'
padding_const = ", constant_value=float('-Inf')"
padding_const = ", constant_values=float('-Inf')"
elif pooling_type == 'AVG':
op = 'avg_pool'
padding_const = ""
Expand Down

0 comments on commit 52c0386

Please sign in to comment.