-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a python operator for DepthwiseConvolution #99
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,6 +74,66 @@ def compute_output_dim(input_dim, weight_dim, stride, padding): | |
output_tensors_dims=[output_tensor_dims], | ||
output_tensor_layout=output_layout, params=params)[0] | ||
|
||
def depthwise_convolution( | ||
input_tensor, filter_tensor, stride, padding, activation=None, | ||
activation_params=None, name="depthwise_conv"): | ||
"""Compute a 3D depthwise Convolution given 4D `input_tensor` and `filter_tensor`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Drop the "3D" here. A 4D tensor + 4D filter produces a 4D output tensor. |
||
|
||
Args: | ||
input_tensor: A 4D `Tensor`. | ||
filter_tensor: A 4D `Tensor`. | ||
stride: A list of two integers: [row_stride, col_stride]. | ||
padding: A string from: `same`, `valid`. The zero padding options. | ||
activation: A string representing the activation function (optional). | ||
activation_params: kwargs for the activation function (optional). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. kwargs should be the last argument in the signature |
||
name: Operator name (optional). | ||
""" | ||
def compute_output_dim(input_dim, weight_dim, stride, padding): | ||
pad = 0 | ||
if to_padding_type(padding) == types_pb2.SamePadding: | ||
pad = weight_dim - 1 | ||
return (input_dim - weight_dim + pad) // stride + 1 | ||
|
||
input_tensor, filter_tensor = array_ops.check_and_add_layout_transform( | ||
name=name, op=types_pb2.ConvolutionDepthwise, | ||
input_tensors=[input_tensor, filter_tensor]) | ||
|
||
row_idx = 2 if input_tensor.shape.layout == types_pb2.NCHW else 1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You need to check that the input tensor shape is either NCHW or NHWC (and same for all the other tensors). Prefer raising a ValueError over |
||
col_idx = 3 if input_tensor.shape.layout == types_pb2.NCHW else 2 | ||
chan_idx = 1 if input_tensor.shape.layout == types_pb2.NCHW else 3 | ||
assert input_tensor.dims(chan_idx) == filter_tensor.dims(chan_idx), ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. raise a |
||
"The weights must have the same number of channels as the inputs.") | ||
output_rows = compute_output_dim(input_tensor.shape.dims[row_idx], | ||
filter_tensor.shape.dims[row_idx], stride[0], | ||
padding) | ||
output_cols = compute_output_dim(input_tensor.shape.dims[col_idx], | ||
filter_tensor.shape.dims[col_idx], stride[1], | ||
padding) | ||
output_layout = input_tensor.shape.layout | ||
if output_layout == types_pb2.NCHW: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check should happen before any work is done. |
||
output_tensor_dims = [ | ||
input_tensor.shape.dims[0], input_tensor.shape.dims[chan_idx], output_rows, | ||
output_cols | ||
] | ||
elif output_layout == types_pb2.NHWC: | ||
output_tensor_dims = [ | ||
input_tensor.shape.dims[0], output_rows, output_cols, | ||
input_tensor.shape.dims[chan_idx] | ||
] | ||
else: | ||
assert False, "Unsupported output layout!" | ||
params = node_pb2.Params() | ||
params.conv_params.padding = to_padding_type(padding) | ||
params.conv_params.stride.extend(stride) | ||
if activation is not None: | ||
params.act_params.CopyFrom( | ||
activation_ops.to_proto(activation, activation_params)) | ||
return common.add_node( | ||
name=name, op=types_pb2.ConvolutionDepthwise, | ||
input_tensors=[input_tensor, filter_tensor], | ||
output_tensors_dims=[output_tensor_dims], | ||
output_tensor_layout=output_layout, params=params)[0] | ||
|
||
def batch_norm( | ||
input_tensor, mean_tensor, var_tensor, gamma_tensor, beta_tensor, | ||
activation=None, activation_params=None, name="batch_norm"): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer that this is only enabled for the Reference backend, not for SMV (unless we properly implement an accelerated kernel for it). Can you first do a check for the backend? You can get this with
get_graph().backend()
(don't forget to check forgraph == None
too).