提交 932508e3 编写于 作者: 李滨

Merge branch 'quantize' into 'master'

Add convolution filter transpose to quantized models

See merge request !722
...@@ -33,6 +33,7 @@ class FilterFormat(Enum): ...@@ -33,6 +33,7 @@ class FilterFormat(Enum):
HWIO = 0 HWIO = 0
OIHW = 1 OIHW = 1
HWOI = 2 HWOI = 2
OHWI = 3
class PaddingMode(Enum): class PaddingMode(Enum):
...@@ -325,50 +326,41 @@ class ConverterOption(object): ...@@ -325,50 +326,41 @@ class ConverterOption(object):
self._transformer_option = [TransformerRule[transformer] self._transformer_option = [TransformerRule[transformer]
for transformer in self._transformer_option] # noqa for transformer in self._transformer_option] # noqa
else: else:
if not self._quantize: self._transformer_option = [
self._transformer_option = [ # Model structure related transformation
TransformerRule.REMOVE_IDENTITY_OP, TransformerRule.REMOVE_IDENTITY_OP,
TransformerRule.TRANSFORM_GLOBAL_POOLING, TransformerRule.TRANSFORM_GLOBAL_POOLING,
TransformerRule.FOLD_RESHAPE, TransformerRule.FOLD_RESHAPE,
TransformerRule.TRANSFORM_MATMUL_TO_FC, TransformerRule.TRANSFORM_MATMUL_TO_FC,
TransformerRule.FOLD_BATCHNORM, TransformerRule.FOLD_BATCHNORM,
TransformerRule.FOLD_CONV_AND_BN, TransformerRule.FOLD_CONV_AND_BN,
TransformerRule.FOLD_DEPTHWISE_CONV_AND_BN, TransformerRule.FOLD_DEPTHWISE_CONV_AND_BN,
TransformerRule.TRANSFORM_GPU_WINOGRAD, TransformerRule.TRANSFORM_GPU_WINOGRAD,
TransformerRule.TRANSFORM_ADD_TO_BIASADD, TransformerRule.TRANSFORM_ADD_TO_BIASADD,
TransformerRule.FOLD_BIASADD, TransformerRule.FOLD_BIASADD,
TransformerRule.FLATTEN_ATROUS_CONV, TransformerRule.FLATTEN_ATROUS_CONV,
TransformerRule.FOLD_ACTIVATION, TransformerRule.FOLD_ACTIVATION,
TransformerRule.TRANSPOSE_FILTERS, TransformerRule.TRANSFORM_GLOBAL_CONV_TO_FC,
TransformerRule.TRANSPOSE_DATA_FORMAT, TransformerRule.RESHAPE_FC_WEIGHT,
TransformerRule.ADD_IN_OUT_TENSOR_INFO, # Model data format related transformation
TransformerRule.TRANSFORM_GLOBAL_CONV_TO_FC, TransformerRule.TRANSPOSE_FILTERS,
TransformerRule.RESHAPE_FC_WEIGHT, TransformerRule.TRANSPOSE_DATA_FORMAT,
TransformerRule.TRANSFORM_BUFFER_IMAGE, # Mace model structure related transformation
TransformerRule.ADD_DEVICE, TransformerRule.ADD_IN_OUT_TENSOR_INFO,
TransformerRule.UPDATE_FLOAT_OP_DATA_TYPE, # Device related transformation
TransformerRule.ADD_MACE_INPUT_AND_OUTPUT_NODES, TransformerRule.TRANSFORM_BUFFER_IMAGE,
TransformerRule.SORT_BY_EXECUTION, TransformerRule.ADD_DEVICE,
] # Data type related transformation
else: TransformerRule.UPDATE_FLOAT_OP_DATA_TYPE,
self._transformer_option = [ # Transform finalization
TransformerRule.REMOVE_IDENTITY_OP, TransformerRule.ADD_MACE_INPUT_AND_OUTPUT_NODES,
TransformerRule.TRANSFORM_GLOBAL_POOLING, TransformerRule.SORT_BY_EXECUTION,
TransformerRule.FOLD_RESHAPE, ]
TransformerRule.TRANSFORM_MATMUL_TO_FC, if self._quantize:
TransformerRule.FOLD_BATCHNORM, self._transformer_option = self._transformer_option[:-1] + [
TransformerRule.FOLD_CONV_AND_BN,
TransformerRule.FOLD_DEPTHWISE_CONV_AND_BN,
TransformerRule.TRANSFORM_GPU_WINOGRAD,
TransformerRule.TRANSFORM_ADD_TO_BIASADD,
TransformerRule.FOLD_BIASADD,
TransformerRule.FLATTEN_ATROUS_CONV,
TransformerRule.FOLD_ACTIVATION,
TransformerRule.ADD_IN_OUT_TENSOR_INFO,
TransformerRule.QUANTIZE_NODES, TransformerRule.QUANTIZE_NODES,
TransformerRule.ADD_QUANTIZE_TENSOR_RANGE, TransformerRule.ADD_QUANTIZE_TENSOR_RANGE,
TransformerRule.QUANTIZE_WEIGHTS, TransformerRule.QUANTIZE_WEIGHTS,
TransformerRule.ADD_DEVICE,
TransformerRule.SORT_BY_EXECUTION, TransformerRule.SORT_BY_EXECUTION,
] ]
......
...@@ -102,7 +102,8 @@ class Transformer(base_converter.ConverterInterface): ...@@ -102,7 +102,8 @@ class Transformer(base_converter.ConverterInterface):
self._quantize_activation_info = {} self._quantize_activation_info = {}
self._quantized_tensor = set() self._quantized_tensor = set()
if self._option.device == DeviceType.CPU.value: if self._option.device == DeviceType.CPU.value and \
not self._option.quantize:
self._target_data_format = DataFormat.NCHW self._target_data_format = DataFormat.NCHW
def run(self): def run(self):
...@@ -710,6 +711,66 @@ class Transformer(base_converter.ConverterInterface): ...@@ -710,6 +711,66 @@ class Transformer(base_converter.ConverterInterface):
return False return False
def transform_global_conv_to_fc(self):
"""Transform global conv to fc should be placed after transposing
input/output and filter"""
if self._option.quantize:
return
net = self._model
for op in net.op:
if op.type == MaceOp.Conv2D.name:
producer = self._producer[op.input[0]]
input_shape = producer.output_shape[0].dims
batch, height, width, channels = self.sort_feature_map_shape(
input_shape, ConverterUtil.data_format(producer))
filter = self._consts[op.input[1]]
filter_shape = filter.dims
filter_height, filter_width, in_channels, out_channels = \
self.sort_filter_shape(filter_shape, self.filter_format())
zero_padding = True
padding_arg = ConverterUtil.get_arg(op,
MaceKeyword.mace_padding_str) # noqa
if padding_arg is not None:
if padding_arg.i != PaddingMode.VALID.value:
zero_padding = False
else:
padding_value_arg = ConverterUtil.get_arg(op,
MaceKeyword.mace_padding_values_str) # noqa
if padding_value_arg is not None:
if not all(v == 0 for v in padding_value_arg.ints):
zero_padding = False
if height == filter_height and width == filter_width \
and zero_padding:
print("transform global conv to fc %s(%s)"
% (op.name, op.type))
op.type = MaceOp.FullyConnected.name
return False
def reshape_fc_weight(self):
print("Reshape fully connected weight shape")
net = self._model
filter_format = self.filter_format()
for op in net.op:
if op.type == MaceOp.FullyConnected.name:
weight = self._consts[op.input[1]]
if len(weight.dims) == 2:
input_op = self._producer[op.input[0]]
input_shape = list(input_op.output_shape[0].dims)
weight.dims[:] = [weight.dims[0]] + input_shape[1:]
if len(input_shape) == 2:
if filter_format == FilterFormat.HWIO:
weight.dims[:] = [1, 1] + weight.dims[:]
elif filter_format == FilterFormat.OIHW:
weight.dims[:] = weight.dims[:] + [1, 1]
else:
mace_check("FC does not support filter format %s",
filter_format.name)
return False
def transpose_data_format(self): def transpose_data_format(self):
net = self._model net = self._model
...@@ -896,64 +957,67 @@ class Transformer(base_converter.ConverterInterface): ...@@ -896,64 +957,67 @@ class Transformer(base_converter.ConverterInterface):
net = self._model net = self._model
filter_format = self.filter_format() filter_format = self.filter_format()
print("Transpose filters to OIHW") if self._option.quantize:
# transpose filter to OIHW/MIHW for tensorflow (HWIO/HWIM) print("Transpose filters to OHWI")
if filter_format == FilterFormat.HWIO: if filter_format == FilterFormat.HWIO:
transpose_order = [3, 0, 1, 2]
elif filter_format == FilterFormat.OIHW:
transpose_order = [0, 2, 3, 1]
else:
mace_check("Quantize model does not support conv "
"filter format: %s" % filter_format.name)
for op in net.op: for op in net.op:
if op.type == MaceOp.Conv2D.name \ if op.type == MaceOp.Conv2D.name \
or op.type == MaceOp.Deconv2D.name \ or op.type == MaceOp.Deconv2D.name:
or op.type == MaceOp.DepthwiseConv2d.name:
filter = self._consts[op.input[1]] filter = self._consts[op.input[1]]
filter_data = np.array(filter.float_data).reshape( filter_data = np.array(filter.float_data).reshape(
filter.dims) filter.dims)
filter_data = filter_data.transpose(3, 2, 0, 1) filter_data = filter_data.transpose(transpose_order)
filter.float_data[:] = filter_data.flat filter.float_data[:] = filter_data.flat
filter.dims[:] = filter_data.shape filter.dims[:] = filter_data.shape
if (op.type == MaceOp.MatMul.name and
ConverterUtil.get_arg(op, MaceKeyword.mace_winograd_filter_transformed) is not None): # noqa self.set_filter_format(FilterFormat.OHWI)
filter = self._consts[op.input[0]] else:
print("Transpose filters to OIHW/MIHW")
# transpose filter to OIHW/MIHW for tensorflow (HWIO/HWIM)
if filter_format == FilterFormat.HWIO:
for op in net.op:
if op.type == MaceOp.Conv2D.name \
or op.type == MaceOp.Deconv2D.name \
or op.type == MaceOp.DepthwiseConv2d.name:
filter = self._consts[op.input[1]]
filter_data = np.array(filter.float_data).reshape(
filter.dims)
filter_data = filter_data.transpose(3, 2, 0, 1)
filter.float_data[:] = filter_data.flat
filter.dims[:] = filter_data.shape
if (op.type == MaceOp.MatMul.name and
ConverterUtil.get_arg(op, MaceKeyword.mace_winograd_filter_transformed) is not None): # noqa
filter = self._consts[op.input[0]]
filter_data = np.array(filter.float_data).reshape(
filter.dims)
filter_data = filter_data.transpose(3, 2, 0, 1)
filter.float_data[:] = filter_data.flat
filter.dims[:] = filter_data.shape
if op.type == MaceOp.FullyConnected.name:
weight = self._consts[op.input[1]]
if len(weight.dims) == 4:
weight_data = np.array(weight.float_data).reshape(
weight.dims)
weight_data = weight_data.transpose(3, 2, 0, 1)
weight.float_data[:] = weight_data.flat
weight.dims[:] = weight_data.shape
self.set_filter_format(FilterFormat.OIHW)
for op in net.op:
if op.type == MaceOp.Deconv2D.name:
filter = self._consts[op.input[1]]
filter_data = np.array(filter.float_data).reshape( filter_data = np.array(filter.float_data).reshape(
filter.dims) filter.dims)
filter_data = filter_data.transpose(3, 2, 0, 1) filter_data = filter_data.transpose(1, 0, 2, 3)
filter.float_data[:] = filter_data.flat filter.float_data[:] = filter_data.flat
filter.dims[:] = filter_data.shape filter.dims[:] = filter_data.shape
if op.type == MaceOp.FullyConnected.name:
weight = self._consts[op.input[1]]
if len(weight.dims) == 4:
weight_data = np.array(weight.float_data).reshape(
weight.dims)
weight_data = weight_data.transpose(3, 2, 0, 1)
weight.float_data[:] = weight_data.flat
weight.dims[:] = weight_data.shape
self.set_filter_format(FilterFormat.OIHW)
for op in net.op:
if op.type == MaceOp.Deconv2D.name:
filter = self._consts[op.input[1]]
filter_data = np.array(filter.float_data).reshape(
filter.dims)
filter_data = filter_data.transpose(1, 0, 2, 3)
filter.float_data[:] = filter_data.flat
filter.dims[:] = filter_data.shape
return False
def reshape_fc_weight(self):
print("Reshape fully connected weight shape")
net = self._model
for op in net.op:
if op.type == MaceOp.FullyConnected.name:
weight = self._consts[op.input[1]]
if len(weight.dims) == 2:
input_op = self._producer[op.input[0]]
input_shape = list(input_op.output_shape[0].dims)
input_data_format = ConverterUtil.data_format(input_op)
weight.dims[:] = [weight.dims[0]] + input_shape[1:]
if len(input_shape) == 2:
weight.dims[:] = weight.dims[:] + [1, 1]
if input_data_format == DataFormat.NHWC and \
len(input_shape) == 4:
self.transpose_shape(weight.dims, [0, 3, 1, 2])
return False return False
...@@ -1199,42 +1263,6 @@ class Transformer(base_converter.ConverterInterface): ...@@ -1199,42 +1263,6 @@ class Transformer(base_converter.ConverterInterface):
return False return False
def transform_global_conv_to_fc(self):
"""Transform global conv to fc should be placed after transposing
input/output and filter"""
# if self._option.device == DeviceType.GPU.value:
# return False
net = self._model
for op in net.op:
if op.type == MaceOp.Conv2D.name:
producer = self._producer[op.input[0]]
input_shape = producer.output_shape[0].dims
batch, height, width, channels = self.sort_feature_map_shape(
input_shape, ConverterUtil.data_format(producer))
filter = self._consts[op.input[1]]
filter_shape = filter.dims
filter_height, filter_width, in_channels, out_channels = \
self.sort_filter_shape(filter_shape, self.filter_format())
zero_padding = True
padding_arg = ConverterUtil.get_arg(op,
MaceKeyword.mace_padding_str) # noqa
if padding_arg is not None:
if padding_arg.i != PaddingMode.VALID.value:
zero_padding = False
else:
padding_value_arg = ConverterUtil.get_arg(op,
MaceKeyword.mace_padding_values_str) # noqa
if padding_value_arg is not None:
if not all(v == 0 for v in padding_value_arg.ints):
zero_padding = False
if height == filter_height and width == filter_width \
and zero_padding:
print("transform global conv to fc %s(%s)"
% (op.name, op.type))
op.type = MaceOp.FullyConnected.name
def add_device(self): def add_device(self):
# TODO(liuqi) add device definition in OperatorDef # TODO(liuqi) add device definition in OperatorDef
net = self._model net = self._model
...@@ -1246,6 +1274,9 @@ class Transformer(base_converter.ConverterInterface): ...@@ -1246,6 +1274,9 @@ class Transformer(base_converter.ConverterInterface):
return False return False
def update_float_op_data_type(self): def update_float_op_data_type(self):
if self._option.quantize:
return
print("update op with float data type") print("update op with float data type")
net = self._model net = self._model
for op in net.op: for op in net.op:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册