Add explicit padding to depthwise conv2d.

Explicit padding is supported with CPUs, GPUs, and XLA. No XLA code needed to be changed as the existing codepaths already worked with explicit padding. Little CPU and GPU code needed to be changed as well, as the algorithms already had to take into account padding to support SAME padding.

PiperOrigin-RevId: 301302951
Change-Id: I1217b62e3cf2cf50c10ee1ae03695e28f895ce38
This commit is contained in:
A. Unique TensorFlower 2020-03-16 21:53:02 -07:00 committed by TensorFlower Gardener
parent 29690922c7
commit 092ae742c3
17 changed files with 91 additions and 637 deletions

View File

@ -1,4 +1,8 @@
op { op {
graph_op_name: "DepthwiseConv2dNative" graph_op_name: "DepthwiseConv2dNative"
visibility: HIDDEN deprecation_message: "Use nn.depthwise_conv2d instead"
endpoint {
name: "nn.depthwise_conv2d_native"
deprecation_version: 2
}
} }

View File

@ -1,4 +1,11 @@
op { op {
graph_op_name: "DepthwiseConv2dNativeBackpropFilter" graph_op_name: "DepthwiseConv2dNativeBackpropFilter"
visibility: HIDDEN endpoint {
name: "nn.depthwise_conv2d_native_backprop_filter"
deprecated: true
deprecation_version: 2
}
endpoint {
name: "nn.depthwise_conv2d_backprop_filter"
}
} }

View File

@ -1,4 +1,11 @@
op { op {
graph_op_name: "DepthwiseConv2dNativeBackpropInput" graph_op_name: "DepthwiseConv2dNativeBackpropInput"
visibility: HIDDEN endpoint {
name: "nn.depthwise_conv2d_native_backprop_input"
deprecated: true
deprecation_version: 2
}
endpoint {
name: "nn.depthwise_conv2d_backprop_input"
}
} }

View File

@ -29,9 +29,9 @@ namespace tensorflow {
namespace shape_inference { namespace shape_inference {
// The V2 version computes windowed output size with arbitrary dilation_rate and // The V2 version computes windowed output size with arbitrary dilation_rate,
// explicit padding, while the original version only handles the cases where // while the original version only handles the cases where dilation_rates equal
// dilation_rates equal to 1 and the padding is SAME or VALID. // to 1.
Status GetWindowedOutputSizeFromDimsV2( Status GetWindowedOutputSizeFromDimsV2(
shape_inference::InferenceContext* c, shape_inference::InferenceContext* c,
shape_inference::DimensionHandle input_size, shape_inference::DimensionHandle input_size,
@ -822,10 +822,7 @@ Status Conv3DShape(shape_inference::InferenceContext* c) {
return Status::OK(); return Status::OK();
} }
namespace { Status DepthwiseConv2DNativeShape(shape_inference::InferenceContext* c) {
Status DepthwiseConv2DNativeShapeImpl(shape_inference::InferenceContext* c,
bool supports_explicit_padding) {
ShapeHandle input_shape; ShapeHandle input_shape;
TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input_shape)); TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input_shape));
ShapeHandle filter_shape; ShapeHandle filter_shape;
@ -853,17 +850,13 @@ Status DepthwiseConv2DNativeShapeImpl(shape_inference::InferenceContext* c,
dilations.size()); dilations.size());
} }
string data_format_str; string data_format;
Status s = c->GetAttr("data_format", &data_format_str); Status s = c->GetAttr("data_format", &data_format);
TensorFormat data_format;
if (!s.ok() || !FormatFromString(data_format_str, &data_format)) {
data_format = FORMAT_NHWC;
}
int32 stride_rows; int32 stride_rows;
int32 stride_cols; int32 stride_cols;
int32 dilation_rows; int32 dilation_rows;
int32 dilation_cols; int32 dilation_cols;
if (data_format == FORMAT_NCHW) { if (s.ok() && data_format == "NCHW") {
// Canonicalize input shape to NHWC so the shape inference code below can // Canonicalize input shape to NHWC so the shape inference code below can
// process it. // process it.
input_shape = input_shape =
@ -899,41 +892,20 @@ Status DepthwiseConv2DNativeShapeImpl(shape_inference::InferenceContext* c,
Padding padding; Padding padding;
TF_RETURN_IF_ERROR(c->GetAttr("padding", &padding)); TF_RETURN_IF_ERROR(c->GetAttr("padding", &padding));
std::vector<int64> explicit_paddings;
if (supports_explicit_padding) {
Status status = c->GetAttr("explicit_paddings", &explicit_paddings);
// Use the default value, which is an empty list, if the attribute is not
// found. Otherwise return the error to the caller.
if (!status.ok() && !errors::IsNotFound(status)) {
return status;
}
TF_RETURN_IF_ERROR(CheckValidPadding(padding, explicit_paddings,
/*num_dims=*/4, data_format));
} else {
DCHECK(padding != Padding::EXPLICIT);
}
// TODO(mrry,shlens): Raise an error if the stride would cause // TODO(mrry,shlens): Raise an error if the stride would cause
// information in the input to be ignored. This will require a change // information in the input to be ignored. This will require a change
// in the kernel implementation. // in the kernel implementation.
DimensionHandle output_rows, output_cols; DimensionHandle output_rows, output_cols;
int64 pad_rows_before = -1, pad_rows_after = -1;
int64 pad_cols_before = -1, pad_cols_after = -1;
if (padding == Padding::EXPLICIT) {
GetExplicitPaddingForDim(explicit_paddings, data_format, 'H',
&pad_rows_before, &pad_rows_after);
GetExplicitPaddingForDim(explicit_paddings, data_format, 'W',
&pad_cols_before, &pad_cols_after);
}
TF_RETURN_IF_ERROR(GetWindowedOutputSizeFromDimsV2( TF_RETURN_IF_ERROR(GetWindowedOutputSizeFromDimsV2(
c, in_rows_dim, filter_rows_dim, dilation_rows, stride_rows, padding, c, in_rows_dim, filter_rows_dim, dilation_rows, stride_rows, padding, -1,
pad_rows_before, pad_rows_after, &output_rows)); -1, &output_rows));
TF_RETURN_IF_ERROR(GetWindowedOutputSizeFromDimsV2( TF_RETURN_IF_ERROR(GetWindowedOutputSizeFromDimsV2(
c, in_cols_dim, filter_cols_dim, dilation_cols, stride_cols, padding, c, in_cols_dim, filter_cols_dim, dilation_cols, stride_cols, padding, -1,
pad_cols_before, pad_cols_after, &output_cols)); -1, &output_cols));
ShapeHandle output_shape; ShapeHandle output_shape;
if (data_format == FORMAT_NCHW) { if (data_format == "NCHW") {
output_shape = output_shape =
c->MakeShape({batch_size_dim, output_depth, output_rows, output_cols}); c->MakeShape({batch_size_dim, output_depth, output_rows, output_cols});
} else { } else {
@ -944,17 +916,6 @@ Status DepthwiseConv2DNativeShapeImpl(shape_inference::InferenceContext* c,
return Status::OK(); return Status::OK();
} }
}; // namespace
Status DepthwiseConv2DNativeShape(shape_inference::InferenceContext* c) {
return DepthwiseConv2DNativeShapeImpl(c, false);
}
Status DepthwiseConv2DNativeShapeWithExplicitPadding(
shape_inference::InferenceContext* c) {
return DepthwiseConv2DNativeShapeImpl(c, true);
}
Status AvgPoolShape(shape_inference::InferenceContext* c) { Status AvgPoolShape(shape_inference::InferenceContext* c) {
string data_format_str; string data_format_str;
TensorFormat data_format; TensorFormat data_format;

View File

@ -129,13 +129,7 @@ Status Conv2DShape(shape_inference::InferenceContext* c);
// Shape function for Conv3D-like operations. // Shape function for Conv3D-like operations.
Status Conv3DShape(shape_inference::InferenceContext* c); Status Conv3DShape(shape_inference::InferenceContext* c);
// Shape function for DepthwiseConv2D-like operations that support explicit // Shape function for DepthwiseConv2D-like operations.
// padding.
Status DepthwiseConv2DNativeShapeWithExplicitPadding(
shape_inference::InferenceContext* c);
// Shape function for DepthwiseConv2D-like operations that do not support
// explicit padding.
Status DepthwiseConv2DNativeShape(shape_inference::InferenceContext* c); Status DepthwiseConv2DNativeShape(shape_inference::InferenceContext* c);
// Shape function for AvgPool-like operations. // Shape function for AvgPool-like operations.

View File

@ -116,20 +116,13 @@ typedef Eigen::GpuDevice GPUDevice;
errors::InvalidArgument( \ errors::InvalidArgument( \
label, ": depth_multiplier * in_depth not equal to out_depth")); \ label, ": depth_multiplier * in_depth not equal to out_depth")); \
const auto stride = stride_; \ const auto stride = stride_; \
int64 out_rows = 0, out_cols = 0, pad_top = 0, pad_bottom = 0, pad_left = 0, \ int64 out_rows = 0, out_cols = 0, pad_rows = 0, pad_cols = 0; \
pad_right = 0; \ OP_REQUIRES_OK(context, \
if (padding_ == Padding::EXPLICIT) { \ GetWindowedOutputSize(input_rows, filter_rows, stride, \
GetExplicitPaddingForDim(explicit_paddings_, data_format_, 'H', &pad_top, \ padding_, &out_rows, &pad_rows)); \
&pad_bottom); \ OP_REQUIRES_OK(context, \
GetExplicitPaddingForDim(explicit_paddings_, data_format_, 'W', &pad_left, \ GetWindowedOutputSize(input_cols, filter_cols, stride, \
&pad_right); \ padding_, &out_cols, &pad_cols)); \
} \
OP_REQUIRES_OK(context, GetWindowedOutputSizeVerbose( \
input_rows, filter_rows, stride_, padding_, \
&out_rows, &pad_top, &pad_bottom)); \
OP_REQUIRES_OK(context, GetWindowedOutputSizeVerbose( \
input_cols, filter_cols, stride_, padding_, \
&out_cols, &pad_left, &pad_right)); \
OP_REQUIRES( \ OP_REQUIRES( \
context, output_rows == out_rows, \ context, output_rows == out_rows, \
errors::InvalidArgument( \ errors::InvalidArgument( \
@ -149,8 +142,8 @@ typedef Eigen::GpuDevice GPUDevice;
args.filter_cols = filter_cols; \ args.filter_cols = filter_cols; \
args.depth_multiplier = depth_multiplier; \ args.depth_multiplier = depth_multiplier; \
args.stride = stride; \ args.stride = stride; \
args.pad_rows = pad_top; \ args.pad_rows = pad_rows; \
args.pad_cols = pad_left; \ args.pad_cols = pad_cols; \
args.out_rows = out_rows; \ args.out_rows = out_rows; \
args.out_cols = out_cols; \ args.out_cols = out_cols; \
args.out_depth = out_depth; \ args.out_depth = out_depth; \
@ -158,7 +151,7 @@ typedef Eigen::GpuDevice GPUDevice;
<< input_rows << ", " << input_cols << ", " << in_depth \ << input_rows << ", " << input_cols << ", " << in_depth \
<< "]; Filter: [" << filter_rows << ", " << filter_cols << ", " \ << "]; Filter: [" << filter_rows << ", " << filter_cols << ", " \
<< in_depth << ", " << depth_multiplier << "]; stride = " << stride \ << in_depth << ", " << depth_multiplier << "]; stride = " << stride \
<< ", pad_rows = " << pad_top << ", pad_cols = " << pad_left \ << ", pad_rows = " << pad_rows << ", pad_cols = " << pad_cols \
<< ", output: [" << batch << ", " << out_rows << ", " << out_cols \ << ", output: [" << batch << ", " << out_rows << ", " << out_cols \
<< ", " << out_depth << "]"; << ", " << out_depth << "]";
@ -573,10 +566,6 @@ class DepthwiseConv2dNativeBackpropInputOp : public OpKernel {
errors::InvalidArgument("Current implementation does not yet support " errors::InvalidArgument("Current implementation does not yet support "
"strides in the batch and depth dimensions.")); "strides in the batch and depth dimensions."));
OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_));
OP_REQUIRES_OK(context,
context->GetAttr("explicit_paddings", &explicit_paddings_));
OP_REQUIRES_OK(context, CheckValidPadding(padding_, explicit_paddings_,
/*num_dims=*/4, data_format_));
// For in_depth == 1 and grouped convolutions. // For in_depth == 1 and grouped convolutions.
use_cudnn_ = CanUseCudnn() && std::is_same<Device, GPUDevice>::value; use_cudnn_ = CanUseCudnn() && std::is_same<Device, GPUDevice>::value;
@ -639,7 +628,7 @@ class DepthwiseConv2dNativeBackpropInputOp : public OpKernel {
<< filter_cols << ", " << in_depth << ", " << depth_multiplier << filter_cols << ", " << in_depth << ", " << depth_multiplier
<< "]; Output: [" << batch << ", " << out_rows << ", " << out_cols << "]; Output: [" << batch << ", " << out_rows << ", " << out_cols
<< ", " << out_depth << "], stride = " << stride_ << ", " << out_depth << "], stride = " << stride_
<< ", pad_rows = " << pad_top << ", pad_cols = " << pad_left << ", pad_rows = " << pad_rows << ", pad_cols = " << pad_cols
<< ", Use cuDNN: " << use_cudnn; << ", Use cuDNN: " << use_cudnn;
if (use_cudnn) { if (use_cudnn) {
@ -663,8 +652,8 @@ class DepthwiseConv2dNativeBackpropInputOp : public OpKernel {
// conv is supported. // conv is supported.
launcher_(context, use_cudnn_, cudnn_use_autotune_, out_backprop, launcher_(context, use_cudnn_, cudnn_use_autotune_, out_backprop,
reshaped_filter, /*row_dilation=*/1, /*col_dilation=*/1, reshaped_filter, /*row_dilation=*/1, /*col_dilation=*/1,
stride_, stride_, padding_, explicit_paddings_, in_backprop, stride_, stride_, padding_, /*explicit_paddings=*/{},
data_format_); in_backprop, data_format_);
return; return;
} }
@ -682,7 +671,6 @@ class DepthwiseConv2dNativeBackpropInputOp : public OpKernel {
private: private:
std::vector<int32> strides_; std::vector<int32> strides_;
Padding padding_; Padding padding_;
std::vector<int64> explicit_paddings_;
TensorFormat data_format_; TensorFormat data_format_;
int64 stride_; int64 stride_;
@ -1067,10 +1055,6 @@ class DepthwiseConv2dNativeBackpropFilterOp : public OpKernel {
errors::InvalidArgument("Current implementation does not yet support " errors::InvalidArgument("Current implementation does not yet support "
"strides in the batch and depth dimensions.")); "strides in the batch and depth dimensions."));
OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_));
OP_REQUIRES_OK(context,
context->GetAttr("explicit_paddings", &explicit_paddings_));
OP_REQUIRES_OK(context, CheckValidPadding(padding_, explicit_paddings_,
/*num_dims=*/4, data_format_));
// For in_depth == 1 and grouped convolutions. // For in_depth == 1 and grouped convolutions.
use_cudnn_ = CanUseCudnn() && std::is_same<Device, GPUDevice>::value; use_cudnn_ = CanUseCudnn() && std::is_same<Device, GPUDevice>::value;
@ -1139,7 +1123,7 @@ class DepthwiseConv2dNativeBackpropFilterOp : public OpKernel {
<< filter_cols << ", " << in_depth << ", " << depth_multiplier << filter_cols << ", " << in_depth << ", " << depth_multiplier
<< "]; Output: [" << batch << ", " << out_rows << ", " << out_cols << "]; Output: [" << batch << ", " << out_rows << ", " << out_cols
<< ", " << out_depth << "], stride = " << stride_ << ", " << out_depth << "], stride = " << stride_
<< ", pad_rows = " << pad_top << ", pad_cols = " << pad_left << ", pad_rows = " << pad_rows << ", pad_cols = " << pad_cols
<< ", Use cuDNN: " << use_cudnn; << ", Use cuDNN: " << use_cudnn;
if (use_cudnn) { if (use_cudnn) {
@ -1164,7 +1148,8 @@ class DepthwiseConv2dNativeBackpropFilterOp : public OpKernel {
// conv is supported. // conv is supported.
launcher_(context, use_cudnn_, cudnn_use_autotune_, out_backprop, input, launcher_(context, use_cudnn_, cudnn_use_autotune_, out_backprop, input,
/*row_dilation=*/1, /*col_dilation=*/1, stride_, stride_, /*row_dilation=*/1, /*col_dilation=*/1, stride_, stride_,
padding_, explicit_paddings_, &reshaped_filter, data_format_); padding_, /*explicit_paddings=*/{}, &reshaped_filter,
data_format_);
return; return;
} }
@ -1182,7 +1167,6 @@ class DepthwiseConv2dNativeBackpropFilterOp : public OpKernel {
private: private:
std::vector<int32> strides_; std::vector<int32> strides_;
Padding padding_; Padding padding_;
std::vector<int64> explicit_paddings_;
TensorFormat data_format_; TensorFormat data_format_;
int64 stride_; int64 stride_;

View File

@ -293,10 +293,6 @@ class DepthwiseConv2dNativeOp : public BinaryOp<T> {
errors::InvalidArgument("Current implementation does not yet support " errors::InvalidArgument("Current implementation does not yet support "
"strides in the batch and depth dimensions.")); "strides in the batch and depth dimensions."));
OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_));
OP_REQUIRES_OK(context,
context->GetAttr("explicit_paddings", &explicit_paddings_));
OP_REQUIRES_OK(context, CheckValidPadding(padding_, explicit_paddings_,
/*num_dims=*/4, data_format_));
// For in_depth == 1 and grouped convolutions. // For in_depth == 1 and grouped convolutions.
use_cudnn_ = CanUseCudnn() && std::is_same<Device, GPUDevice>::value; use_cudnn_ = CanUseCudnn() && std::is_same<Device, GPUDevice>::value;
@ -361,20 +357,13 @@ class DepthwiseConv2dNativeOp : public BinaryOp<T> {
// The first dimension for input is batch. // The first dimension for input is batch.
const int32 batch = input.dim_size(0); const int32 batch = input.dim_size(0);
int64 out_rows = 0, out_cols = 0, pad_top = 0, pad_bottom = 0, pad_left = 0, int64 out_rows = 0, out_cols = 0, pad_rows = 0, pad_cols = 0;
pad_right = 0; OP_REQUIRES_OK(context,
if (padding_ == Padding::EXPLICIT) { GetWindowedOutputSize(input_rows, filter_rows, stride_,
GetExplicitPaddingForDim(explicit_paddings_, data_format_, 'H', &pad_top, padding_, &out_rows, &pad_rows));
&pad_bottom); OP_REQUIRES_OK(context,
GetExplicitPaddingForDim(explicit_paddings_, data_format_, 'W', &pad_left, GetWindowedOutputSize(input_cols, filter_cols, stride_,
&pad_right); padding_, &out_cols, &pad_cols));
}
OP_REQUIRES_OK(context, GetWindowedOutputSizeVerbose(
input_rows, filter_rows, stride_, padding_,
&out_rows, &pad_top, &pad_bottom));
OP_REQUIRES_OK(context, GetWindowedOutputSizeVerbose(
input_cols, filter_cols, stride_, padding_,
&out_cols, &pad_left, &pad_right));
TensorShape out_shape = TensorShape out_shape =
ShapeFromFormat(data_format_, batch, out_rows, out_cols, out_depth); ShapeFromFormat(data_format_, batch, out_rows, out_cols, out_depth);
OP_REQUIRES( OP_REQUIRES(
@ -409,7 +398,7 @@ class DepthwiseConv2dNativeOp : public BinaryOp<T> {
<< filter_cols << ", " << in_depth << ", " << depth_multiplier << filter_cols << ", " << in_depth << ", " << depth_multiplier
<< "]; Output: [" << batch << ", " << out_rows << ", " << out_cols << "]; Output: [" << batch << ", " << out_rows << ", " << out_cols
<< ", " << out_depth << "], stride = " << stride_ << ", " << out_depth << "], stride = " << stride_
<< ", pad_top = " << pad_top << ", pad_left = " << pad_left << ", pad_rows = " << pad_rows << ", pad_cols = " << pad_cols
<< ", Use cuDNN: " << use_cudnn; << ", Use cuDNN: " << use_cudnn;
if (use_cudnn) { if (use_cudnn) {
@ -433,7 +422,7 @@ class DepthwiseConv2dNativeOp : public BinaryOp<T> {
// conv is supported. // conv is supported.
launcher_(context, use_cudnn_, cudnn_use_autotune_, input, launcher_(context, use_cudnn_, cudnn_use_autotune_, input,
reshaped_filter, /*row_dilation=*/1, /*col_dilation=*/1, reshaped_filter, /*row_dilation=*/1, /*col_dilation=*/1,
stride_, stride_, padding_, explicit_paddings_, output, stride_, stride_, padding_, /*explicit_paddings=*/{}, output,
data_format_); data_format_);
return; return;
} }
@ -447,8 +436,8 @@ class DepthwiseConv2dNativeOp : public BinaryOp<T> {
args.filter_cols = filter_cols; args.filter_cols = filter_cols;
args.depth_multiplier = depth_multiplier; args.depth_multiplier = depth_multiplier;
args.stride = stride_; args.stride = stride_;
args.pad_rows = pad_top; args.pad_rows = pad_rows;
args.pad_cols = pad_left; args.pad_cols = pad_cols;
args.out_rows = out_rows; args.out_rows = out_rows;
args.out_cols = out_cols; args.out_cols = out_cols;
args.out_depth = out_depth; args.out_depth = out_depth;
@ -466,7 +455,6 @@ class DepthwiseConv2dNativeOp : public BinaryOp<T> {
private: private:
std::vector<int32> strides_; std::vector<int32> strides_;
Padding padding_; Padding padding_;
std::vector<int64> explicit_paddings_;
TensorFormat data_format_; TensorFormat data_format_;
int64 stride_; // in height/width dimension. int64 stride_; // in height/width dimension.

View File

@ -32,8 +32,8 @@ struct DepthwiseArgs {
int filter_cols; int filter_cols;
int depth_multiplier; int depth_multiplier;
int stride; int stride;
int pad_rows; // Amount of padding to the top of the input int pad_rows;
int pad_cols; // Amount of padding to the left of the input int pad_cols;
// Output layer dimensions // Output layer dimensions
int out_rows; int out_rows;

View File

@ -558,11 +558,10 @@ REGISTER_OP("DepthwiseConv2dNative")
.Output("output: T") .Output("output: T")
.Attr("T: {half, bfloat16, float, double}") .Attr("T: {half, bfloat16, float, double}")
.Attr("strides: list(int)") .Attr("strides: list(int)")
.Attr(GetPaddingAttrStringWithExplicit()) .Attr(GetPaddingAttrString())
.Attr(GetExplicitPaddingsAttrString())
.Attr(GetConvnetDataFormatAttrString()) .Attr(GetConvnetDataFormatAttrString())
.Attr("dilations: list(int) = [1, 1, 1, 1]") .Attr("dilations: list(int) = [1, 1, 1, 1]")
.SetShapeFn(shape_inference::DepthwiseConv2DNativeShapeWithExplicitPadding); .SetShapeFn(shape_inference::DepthwiseConv2DNativeShape);
REGISTER_OP("DepthwiseConv2dNativeBackpropInput") REGISTER_OP("DepthwiseConv2dNativeBackpropInput")
.Input("input_sizes: int32") .Input("input_sizes: int32")
@ -571,8 +570,7 @@ REGISTER_OP("DepthwiseConv2dNativeBackpropInput")
.Output("output: T") .Output("output: T")
.Attr("T: {half, bfloat16, float, double}") .Attr("T: {half, bfloat16, float, double}")
.Attr("strides: list(int)") .Attr("strides: list(int)")
.Attr(GetPaddingAttrStringWithExplicit()) .Attr(GetPaddingAttrString())
.Attr(GetExplicitPaddingsAttrString())
.Attr(GetConvnetDataFormatAttrString()) .Attr(GetConvnetDataFormatAttrString())
.Attr("dilations: list(int) = [1, 1, 1, 1]") .Attr("dilations: list(int) = [1, 1, 1, 1]")
.SetShapeFn([](InferenceContext* c) { .SetShapeFn([](InferenceContext* c) {
@ -590,8 +588,7 @@ REGISTER_OP("DepthwiseConv2dNativeBackpropFilter")
.Output("output: T") .Output("output: T")
.Attr("T: {half, bfloat16, float, double}") .Attr("T: {half, bfloat16, float, double}")
.Attr("strides: list(int)") .Attr("strides: list(int)")
.Attr(GetPaddingAttrStringWithExplicit()) .Attr(GetPaddingAttrString())
.Attr(GetExplicitPaddingsAttrString())
.Attr(GetConvnetDataFormatAttrString()) .Attr(GetConvnetDataFormatAttrString())
.Attr("dilations: list(int) = [1, 1, 1, 1]") .Attr("dilations: list(int) = [1, 1, 1, 1]")
.SetShapeFn([](InferenceContext* c) { .SetShapeFn([](InferenceContext* c) {

View File

@ -31,12 +31,12 @@ class NodeDef;
// Padding: the padding we apply to the input tensor along the rows and columns // Padding: the padding we apply to the input tensor along the rows and columns
// dimensions. This is usually used to make sure that the spatial dimensions do // dimensions. This is usually used to make sure that the spatial dimensions do
// not shrink when we progress with convolutions. Three types of padding are // not shrink when we progress with convolutions. Two types of padding are
// supported: // supported:
// VALID: No padding is carried out. // VALID: No padding is carried out.
// SAME: The pad value is computed so that the output will have the same // SAME: The pad value is computed so that the output will have the same
// dimensions as the input. // dimensions as the input.
// EXPLICIT: The user specifies the pad values in the explicit_paddings // EXPLICIT: The user specifies the pad values in the explicit_padding
// attribute. // attribute.
// The padded area is zero-filled. // The padded area is zero-filled.
enum Padding { enum Padding {

View File

@ -2941,7 +2941,6 @@ cuda_py_test(
size = "medium", # http://b/30603882 size = "medium", # http://b/30603882
timeout = "long", timeout = "long",
srcs = ["depthwise_conv_op_test.py"], srcs = ["depthwise_conv_op_test.py"],
shard_count = 2,
# TODO(b/118842098): Re-enable this test in Kokoro. # TODO(b/118842098): Re-enable this test in Kokoro.
tags = ["no_oss"], tags = ["no_oss"],
deps = [ deps = [

View File

@ -166,43 +166,6 @@ def ConfigsToTest():
] ]
def ConfigsToTestExplicit():
"""Iterator for different convolution shapes, strides and explicit paddings.
Returns:
List of tuples (input_size, filter_size, out_size, stride, padding,
dilations), the depthwise convolution parameters.
"""
def Config(input_size, filter_size, out_size, stride=1, padding=None,
dilations=None):
return input_size, filter_size, out_size, stride, padding, dilations
return [
Config([4, 5, 5, 48], [1, 1, 48, 2], [4, 8, 12, 96],
padding=[[1, 2], [3, 4]]),
Config([4, 1, 1, 3], [3, 3, 3, 2], [4, 29, 39, 6],
padding=[[10, 20], [15, 25]]),
Config([4, 9, 27, 8], [3, 3, 8, 1], [4, 14, 31, 8],
padding=[[3, 4], [4, 2]]),
Config([4, 31, 31, 7], [3, 3, 7, 1], [4, 29, 29, 7],
padding=[[0, 0], [0, 0]]),
Config([3, 299, 299, 3], [3, 2, 3, 8], [3, 150, 153, 24], 2,
padding=[[1, 2], [3, 5]]),
Config([5, 183, 183, 1], [5, 5, 1, 2], [5, 62, 60, 2], 3,
padding=[[3, 2], [1, 0]]),
Config([5, 29, 31, 1], [5, 4, 1, 2], [5, 26, 23, 2],
padding=[[3, 2], [1, 0]], dilations=[2, 3]),
# These cases test the kernels in depthwise_conv_op_gpu.h which are used
# if the input size is small.
Config([4, 5, 5, 48], [3, 3, 48, 1], [4, 5, 5, 48],
padding=[[0, 2], [0, 2]]),
Config([1, 8, 7, 2], [8, 7, 2, 1], [1, 8, 7, 2],
padding=[[0, 7], [3, 3]]),
Config([2, 4, 3, 2], [3, 2, 2, 1], [2, 4, 3, 2],
padding=[[2, 0], [1, 0]]),
]
def CheckGradConfigsToTest(): def CheckGradConfigsToTest():
"""Iterator for different convolution shapes, strides and paddings. """Iterator for different convolution shapes, strides and paddings.
@ -231,39 +194,6 @@ def CheckGradConfigsToTest():
] ]
def CheckGradConfigsToTestExplicit():
"""Iterator for different convolution shapes, strides and explicit paddings.
compute_gradient_error() is very expensive. So the configs should be
relatively small.
Returns:
List of tuples (input_size, filter_size, out_size, stride, padding,
dilations), the depthwise convolution parameters.
"""
def Config(input_size, filter_size, out_size, stride=1, padding=None,
dilations=None):
return input_size, filter_size, out_size, stride, padding, dilations
return [
Config([2, 5, 8, 1], [4, 4, 1, 2], [2, 3, 10, 2],
padding=[[0, 1], [2, 3]]),
Config([4, 5, 5, 1], [2, 2, 1, 2], [4, 4, 5, 2], 2,
padding=[[3, 1], [5, 0]]),
Config([2, 4, 4, 2], [3, 1, 2, 2], [2, 7, 11, 4],
padding=[[4, 1], [3, 4]]),
Config([1, 15, 15, 2], [1, 3, 2, 1], [1, 18, 23, 2],
padding=[[3, 0], [2, 8]]),
Config([2, 15, 16, 1], [3, 3, 1, 2], [2, 5, 8, 2], 3,
padding=[[0, 0], [10, 0]]),
Config([2, 5, 8, 1], [3, 4, 1, 2], [2, 5, 10, 2],
padding=[[3, 1], [2, 3]], dilations=[2, 1]),
# These cases test the kernels in depthwise_conv_op_gpu.h which are used
# if the input size is small.
Config([2, 4, 3, 2], [3, 2, 2, 1], [2, 4, 3, 2],
padding=[[2, 0], [1, 0]]),
]
class DepthwiseConv2DTest(test.TestCase): class DepthwiseConv2DTest(test.TestCase):
# This tests depthwise_conv2d and depthwise_conv2d_native # This tests depthwise_conv2d and depthwise_conv2d_native
@ -305,8 +235,6 @@ class DepthwiseConv2DTest(test.TestCase):
x2 = np.array(x2).reshape(filter_in_sizes) x2 = np.array(x2).reshape(filter_in_sizes)
# Compute reference result # Compute reference result
strides = [1, stride, stride, 1] strides = [1, stride, stride, 1]
if isinstance(padding, list):
padding = [(0, 0)] + padding + [(0, 0)]
np_result = _DepthwiseConv2dNumpy(x1, x2, strides, padding, "NHWC", np_result = _DepthwiseConv2dNumpy(x1, x2, strides, padding, "NHWC",
dilations) dilations)
@ -327,8 +255,6 @@ class DepthwiseConv2DTest(test.TestCase):
# Ex. [4, 5, 5, 48] to [4, 48, 5, 5] # Ex. [4, 5, 5, 48] to [4, 48, 5, 5]
t1 = array_ops.transpose(t1, [0, 3, 1, 2]) t1 = array_ops.transpose(t1, [0, 3, 1, 2])
strides = [1, 1, stride, stride] strides = [1, 1, stride, stride]
if isinstance(padding, list):
padding = [padding[0], padding[3], padding[1], padding[2]]
# depthwise_conv2d_native does not support dilations except on TPUs. # depthwise_conv2d_native does not support dilations except on TPUs.
if dilations is None: if dilations is None:
@ -458,23 +384,6 @@ class DepthwiseConv2DTest(test.TestCase):
data_format="NCHW", data_format="NCHW",
dilations=dilations) dilations=dilations)
@test_util.run_v1_only("b/120545219")
def testDepthwiseConv2DExplicit(self):
for index, (input_size, filter_size, _, stride,
padding, dilations) in enumerate(ConfigsToTestExplicit()):
tf_logging.info(
"Testing DepthwiseConv2D, %dth config: %r * %r, stride: %d, padding: "
"%s", index, input_size, filter_size, stride, padding)
# double datatype is currently not supported for convolution ops
# on the ROCm platform
optional_float64 = [] if test.is_built_with_rocm() else [dtypes.float64]
data_formats = ["NHWC", "NCHW"] if test.is_gpu_available() else ["NHWC"]
for data_type in [dtypes.float16, dtypes.float32] + optional_float64:
for data_format in data_formats:
self._VerifyValues(
input_size, filter_size, stride, padding, data_type, use_gpu=True,
data_format=data_format, dilations=dilations)
# This is testing against hand calculated results. # This is testing against hand calculated results.
def _VerifyHandValues(self, tensor_in_sizes, filter_in_sizes, stride, padding, def _VerifyHandValues(self, tensor_in_sizes, filter_in_sizes, stride, padding,
@ -621,8 +530,6 @@ class DepthwiseConv2DTest(test.TestCase):
native_input = input_tensor native_input = input_tensor
strides = [1, stride, stride, 1] strides = [1, stride, stride, 1]
if isinstance(padding, list):
padding = [(0, 0)] + padding + [(0, 0)]
if data_format == "NCHW": if data_format == "NCHW":
# Transpose from NHWC input to NCHW # Transpose from NHWC input to NCHW
# Ex. [4, 5, 5, 48] to [4, 48, 5, 5] # Ex. [4, 5, 5, 48] to [4, 48, 5, 5]
@ -634,8 +541,6 @@ class DepthwiseConv2DTest(test.TestCase):
output_shape[0], output_shape[3], output_shape[1], output_shape[2] output_shape[0], output_shape[3], output_shape[1], output_shape[2]
] ]
strides = [1, 1, stride, stride] strides = [1, 1, stride, stride]
if isinstance(padding, list):
padding = [padding[0], padding[3], padding[1], padding[2]]
with sess.graph._kernel_label_map({ with sess.graph._kernel_label_map({
"DepthwiseConv2dNative": "cudnn_grouped_convolution", "DepthwiseConv2dNative": "cudnn_grouped_convolution",
@ -761,32 +666,6 @@ class DepthwiseConv2DTest(test.TestCase):
data_format="NCHW", data_format="NCHW",
dilations=dilations) dilations=dilations)
@test_util.run_v1_only("b/120545219")
def testDepthwiseConv2DInputGradExplicit(self):
for index, (input_size, filter_size, output_size, stride, padding,
dilations) in enumerate(CheckGradConfigsToTestExplicit()):
tf_logging.info(
"Testing DepthwiseConv2DInputGradExplicit, %dth config: %r * %r, "
"stride: %d, padding: %s", index, input_size, filter_size, stride,
padding)
# double datatype is currently not supported for convolution ops
# on the ROCm platform
optional_float64 = [] if test.is_built_with_rocm() else [dtypes.float64]
data_formats = ["NHWC", "NCHW"] if test.is_gpu_available() else ["NHWC"]
for data_type in [dtypes.float16, dtypes.float32] + optional_float64:
for data_format in data_formats:
self._ConstructAndTestGradient(
input_size,
filter_size,
output_size,
stride,
padding,
data_type,
test_input=True,
use_gpu=True,
data_format=data_format,
dilations=dilations)
@test_util.run_v1_only("b/120545219") @test_util.run_v1_only("b/120545219")
@test_util.run_cuda_only @test_util.run_cuda_only
def testDepthwiseConv2DFilterGradCudnn(self): def testDepthwiseConv2DFilterGradCudnn(self):
@ -871,38 +750,10 @@ class DepthwiseConv2DTest(test.TestCase):
data_format="NCHW", data_format="NCHW",
dilations=dilations) dilations=dilations)
@test_util.run_v1_only("b/120545219")
def testDepthwiseConv2DFilterGradExplicit(self):
for index, (input_size, filter_size, output_size, stride, padding,
dilations) in enumerate(CheckGradConfigsToTestExplicit()):
tf_logging.info(
"Testing DepthwiseConv2DFilterGradExplicit, %dth config: %r * %r, "
"stride: %d, padding: %s", index, input_size, filter_size, stride,
padding)
# double datatype is currently not supported for convolution ops
# on the ROCm platform
optional_float64 = [] if test.is_built_with_rocm() else [dtypes.float64]
data_formats = ["NHWC", "NCHW"] if test.is_gpu_available() else ["NHWC"]
for data_type in [dtypes.float16, dtypes.float32] + optional_float64:
for data_format in data_formats:
self._ConstructAndTestGradient(
input_size,
filter_size,
output_size,
stride,
padding,
data_type,
test_input=False,
use_gpu=True,
data_format=data_format,
dilations=dilations)
def _CompareBackpropInput(self, input_sizes, filter_sizes, output_sizes, def _CompareBackpropInput(self, input_sizes, filter_sizes, output_sizes,
stride, padding, dtype): stride, padding, dtype):
x1 = np.random.rand(*filter_sizes).astype(dtype) x1 = np.random.rand(*filter_sizes).astype(dtype)
x2 = np.random.rand(*output_sizes).astype(dtype) x2 = np.random.rand(*output_sizes).astype(dtype)
if isinstance(padding, list):
padding = [(0, 0)] + padding + [(0, 0)]
def _GetVal(use_gpu): def _GetVal(use_gpu):
with self.cached_session(use_gpu=use_gpu): with self.cached_session(use_gpu=use_gpu):
@ -937,30 +788,10 @@ class DepthwiseConv2DTest(test.TestCase):
self._CompareBackpropInput(input_size, filter_size, output_size, stride, self._CompareBackpropInput(input_size, filter_size, output_size, stride,
padding, "float64") padding, "float64")
def testDepthwiseConv2DInputGradExplicitCompare(self):
for index, (input_size, filter_size, output_size, stride,
padding, dilations) in enumerate(ConfigsToTestExplicit()):
if dilations:
continue
tf_logging.info(
"Testing DepthwiseConv2DInputGradCompare, %dth config: %r * %r, "
"stride: %d, padding: %s", index, input_size, filter_size, stride,
padding)
self._CompareBackpropInput(input_size, filter_size, output_size, stride,
padding, "float32")
# double datatype is currently not supported for convolution ops
# on the ROCm platform
if test.is_built_with_rocm():
continue
self._CompareBackpropInput(input_size, filter_size, output_size, stride,
padding, "float64")
def _CompareBackpropFilter(self, input_sizes, filter_sizes, output_sizes, def _CompareBackpropFilter(self, input_sizes, filter_sizes, output_sizes,
stride, padding, dtype): stride, padding, dtype):
x0 = np.random.rand(*input_sizes).astype(dtype) x0 = np.random.rand(*input_sizes).astype(dtype)
x2 = np.random.rand(*output_sizes).astype(dtype) x2 = np.random.rand(*output_sizes).astype(dtype)
if isinstance(padding, list):
padding = [(0, 0)] + padding + [(0, 0)]
def _GetVal(use_gpu): def _GetVal(use_gpu):
with self.cached_session(use_gpu=use_gpu): with self.cached_session(use_gpu=use_gpu):
@ -995,24 +826,6 @@ class DepthwiseConv2DTest(test.TestCase):
self._CompareBackpropFilter(input_size, filter_size, output_size, stride, self._CompareBackpropFilter(input_size, filter_size, output_size, stride,
padding, "float64") padding, "float64")
def testDepthwiseConv2DFilterGradExplicitCompare(self):
for index, (input_size, filter_size, output_size, stride,
padding, dilations) in enumerate(ConfigsToTestExplicit()):
if dilations:
continue
tf_logging.info(
"Testing DepthwiseConv2DFilterGradCompare, %dth config: %r * %r, "
"stride: %d, padding: %s", index, input_size, filter_size, stride,
padding)
self._CompareBackpropFilter(input_size, filter_size, output_size, stride,
padding, "float32")
# double datatype is currently not supported for convolution ops
# on the ROCm platform
if test.is_built_with_rocm():
continue
self._CompareBackpropFilter(input_size, filter_size, output_size, stride,
padding, "float64")
if __name__ == "__main__": if __name__ == "__main__":
test.main() test.main()

View File

@ -104,22 +104,20 @@ def _DepthwiseConv2dNativeBackpropInputGrad(op, grad):
""" """
return [ return [
None, None,
gen_nn_ops.depthwise_conv2d_native_backprop_filter( nn_ops.depthwise_conv2d_native_backprop_filter(
grad, grad,
array_ops.shape(op.inputs[1]), array_ops.shape(op.inputs[1]),
op.inputs[2], op.inputs[2],
dilations=op.get_attr("dilations"), dilations=op.get_attr("dilations"),
strides=op.get_attr("strides"), strides=op.get_attr("strides"),
padding=op.get_attr("padding"), padding=op.get_attr("padding"),
explicit_paddings=op.get_attr("explicit_paddings"),
data_format=op.get_attr("data_format")), data_format=op.get_attr("data_format")),
gen_nn_ops.depthwise_conv2d_native( nn_ops.depthwise_conv2d_native(
grad, grad,
op.inputs[1], op.inputs[1],
dilations=op.get_attr("dilations"), dilations=op.get_attr("dilations"),
strides=op.get_attr("strides"), strides=op.get_attr("strides"),
padding=op.get_attr("padding"), padding=op.get_attr("padding"),
explicit_paddings=op.get_attr("explicit_paddings"),
data_format=op.get_attr("data_format")) data_format=op.get_attr("data_format"))
] ]
@ -127,22 +125,20 @@ def _DepthwiseConv2dNativeBackpropInputGrad(op, grad):
@ops.RegisterGradient("DepthwiseConv2dNativeBackpropFilter") @ops.RegisterGradient("DepthwiseConv2dNativeBackpropFilter")
def _DepthwiseConv2dNativeBackpropFilterGrad(op, grad): def _DepthwiseConv2dNativeBackpropFilterGrad(op, grad):
return [ return [
gen_nn_ops.depthwise_conv2d_native_backprop_input( nn_ops.depthwise_conv2d_native_backprop_input(
array_ops.shape(op.inputs[0]), array_ops.shape(op.inputs[0]),
grad, grad,
op.inputs[2], op.inputs[2],
dilations=op.get_attr("dilations"), dilations=op.get_attr("dilations"),
strides=op.get_attr("strides"), strides=op.get_attr("strides"),
padding=op.get_attr("padding"), padding=op.get_attr("padding"),
explicit_paddings=op.get_attr("explicit_paddings"),
data_format=op.get_attr("data_format")), None, data_format=op.get_attr("data_format")), None,
gen_nn_ops.depthwise_conv2d_native( nn_ops.depthwise_conv2d_native(
op.inputs[0], op.inputs[0],
grad, grad,
dilations=op.get_attr("dilations"), dilations=op.get_attr("dilations"),
strides=op.get_attr("strides"), strides=op.get_attr("strides"),
padding=op.get_attr("padding"), padding=op.get_attr("padding"),
explicit_paddings=op.get_attr("explicit_paddings"),
data_format=op.get_attr("data_format")) data_format=op.get_attr("data_format"))
] ]
@ -610,23 +606,21 @@ def _Conv2DGrad(op, grad):
@ops.RegisterGradient("DepthwiseConv2dNative") @ops.RegisterGradient("DepthwiseConv2dNative")
def _DepthwiseConv2dNativeGrad(op, grad): def _DepthwiseConv2dNativeGrad(op, grad):
return [ return [
gen_nn_ops.depthwise_conv2d_native_backprop_input( nn_ops.depthwise_conv2d_native_backprop_input(
array_ops.shape(op.inputs[0]), array_ops.shape(op.inputs[0]),
op.inputs[1], op.inputs[1],
grad, grad,
dilations=op.get_attr("dilations"), dilations=op.get_attr("dilations"),
strides=op.get_attr("strides"), strides=op.get_attr("strides"),
padding=op.get_attr("padding"), padding=op.get_attr("padding"),
explicit_paddings=op.get_attr("explicit_paddings"),
data_format=op.get_attr("data_format")), data_format=op.get_attr("data_format")),
gen_nn_ops.depthwise_conv2d_native_backprop_filter( nn_ops.depthwise_conv2d_native_backprop_filter(
op.inputs[0], op.inputs[0],
array_ops.shape(op.inputs[1]), array_ops.shape(op.inputs[1]),
grad, grad,
dilations=op.get_attr("dilations"), dilations=op.get_attr("dilations"),
strides=op.get_attr("strides"), strides=op.get_attr("strides"),
padding=op.get_attr("padding"), padding=op.get_attr("padding"),
explicit_paddings=op.get_attr("explicit_paddings"),
data_format=op.get_attr("data_format")) data_format=op.get_attr("data_format"))
] ]

View File

@ -740,50 +740,14 @@ def depthwise_conv2d(input,
convolution, in which case all values in the `strides` tensor must be equal convolution, in which case all values in the `strides` tensor must be equal
to 1. to 1.
Usage Example:
>>> x = np.array([
... [1., 2.],
... [3., 4.],
... [5., 6.]
... ], dtype=np.float32).reshape((1, 3, 2, 1))
>>> kernel = np.array([
... [1., 2.],
... [3., 4]
... ], dtype=np.float32).reshape((2, 1, 1, 2))
>>> tf.compat.v1.nn.depthwise_conv2d(x, kernel, strides=[1, 1, 1, 1],
... padding='VALID').numpy()
array([[[[10., 14.],
[14., 20.]],
[[18., 26.],
[22., 32.]]]], dtype=float32)
>>> tf.compat.v1.nn.depthwise_conv2d(x, kernel, strides=[1, 1, 1, 1],
... padding=[[0, 0], [1, 0], [1, 0], [0, 0]]
... ).numpy()
array([[[[ 0., 0.],
[ 3., 4.],
[ 6., 8.]],
[[ 0., 0.],
[10., 14.],
[14., 20.]],
[[ 0., 0.],
[18., 26.],
[22., 32.]]]], dtype=float32)
Args: Args:
input: 4-D with shape according to `data_format`. input: 4-D with shape according to `data_format`.
filter: 4-D with shape filter: 4-D with shape
`[filter_height, filter_width, in_channels, channel_multiplier]`. `[filter_height, filter_width, in_channels, channel_multiplier]`.
strides: 1-D of size 4. The stride of the sliding window for each strides: 1-D of size 4. The stride of the sliding window for each
dimension of `input`. dimension of `input`.
padding: Controls how to pad the image before applying the convolution. Can padding: A string, either `'VALID'` or `'SAME'`. The padding algorithm.
be the string `"SAME"` or `"VALID"` indicating the type of padding See the "returns" section of `tf.nn.convolution` for details.
algorithm to use, or a list indicating the explicit paddings at the start
and end of each dimension. When explicit padding is used and data_format
is `"NHWC"`, this should be in the form `[[0, 0], [pad_top, pad_bottom],
[pad_left, pad_right], [0, 0]]`. When explicit padding used and
data_format is `"NCHW"`, this should be in the form `[[0, 0], [0, 0],
[pad_top, pad_bottom], [pad_left, pad_right]]`.
rate: 1-D of size 2. The dilation rate in which we sample input values rate: 1-D of size 2. The dilation rate in which we sample input values
across the `height` and `width` dimensions in atrous convolution. If it is across the `height` and `width` dimensions in atrous convolution. If it is
greater than 1, then all values of strides must be 1. greater than 1, then all values of strides must be 1.
@ -866,49 +830,14 @@ def depthwise_conv2d_v2(input,
convolution, in which case all values in the `strides` tensor must be equal convolution, in which case all values in the `strides` tensor must be equal
to 1. to 1.
Usage Example:
>>> x = np.array([
... [1., 2.],
... [3., 4.],
... [5., 6.]
... ], dtype=np.float32).reshape((1, 3, 2, 1))
>>> kernel = np.array([
... [1., 2.],
... [3., 4]
... ], dtype=np.float32).reshape((2, 1, 1, 2))
>>> tf.nn.depthwise_conv2d(x, kernel, strides=[1, 1, 1, 1],
... padding='VALID').numpy()
array([[[[10., 14.],
[14., 20.]],
[[18., 26.],
[22., 32.]]]], dtype=float32)
>>> tf.nn.depthwise_conv2d(x, kernel, strides=[1, 1, 1, 1],
... padding=[[0, 0], [1, 0], [1, 0], [0, 0]]).numpy()
array([[[[ 0., 0.],
[ 3., 4.],
[ 6., 8.]],
[[ 0., 0.],
[10., 14.],
[14., 20.]],
[[ 0., 0.],
[18., 26.],
[22., 32.]]]], dtype=float32)
Args: Args:
input: 4-D with shape according to `data_format`. input: 4-D with shape according to `data_format`.
filter: 4-D with shape filter: 4-D with shape
`[filter_height, filter_width, in_channels, channel_multiplier]`. `[filter_height, filter_width, in_channels, channel_multiplier]`.
strides: 1-D of size 4. The stride of the sliding window for each strides: 1-D of size 4. The stride of the sliding window for each
dimension of `input`. dimension of `input`.
padding: Controls how to pad the image before applying the convolution. Can padding: A string, either `'VALID'` or `'SAME'`. The padding algorithm.
be the string `"SAME"` or `"VALID"` indicating the type of padding See the "returns" section of `tf.nn.convolution` for details.
algorithm to use, or a list indicating the explicit paddings at the start
and end of each dimension. When explicit padding is used and data_format
is `"NHWC"`, this should be in the form `[[0, 0], [pad_top, pad_bottom],
[pad_left, pad_right], [0, 0]]`. When explicit padding used and
data_format is `"NCHW"`, this should be in the form `[[0, 0], [0, 0],
[pad_top, pad_bottom], [pad_left, pad_right]]`.
data_format: The data format for input. Either "NHWC" (default) or "NCHW". data_format: The data format for input. Either "NHWC" (default) or "NCHW".
dilations: 1-D of size 2. The dilation rate in which we sample input values dilations: 1-D of size 2. The dilation rate in which we sample input values
across the `height` and `width` dimensions in atrous convolution. If it is across the `height` and `width` dimensions in atrous convolution. If it is

View File

@ -557,8 +557,6 @@ class _WithSpaceToBatch(object):
self.call = build_op(num_spatial_dims, padding) self.call = build_op(num_spatial_dims, padding)
return return
padding, explicit_paddings = convert_padding(padding)
# We have two padding contributions. The first is used for converting "SAME" # We have two padding contributions. The first is used for converting "SAME"
# to "VALID". The second is required so that the height and width of the # to "VALID". The second is required so that the height and width of the
# zero-padded value tensor are multiples of rate. # zero-padded value tensor are multiples of rate.
@ -579,14 +577,6 @@ class _WithSpaceToBatch(object):
self.base_paddings = None self.base_paddings = None
elif padding == "VALID": elif padding == "VALID":
self.base_paddings = np.zeros([num_spatial_dims, 2], np.int32) self.base_paddings = np.zeros([num_spatial_dims, 2], np.int32)
elif padding == "EXPLICIT":
base_paddings = (np.array(explicit_paddings)
.reshape([num_spatial_dims + 2, 2]))
# Remove batch and channel dimensions
if data_format is not None and data_format.startswith("NC"):
self.base_paddings = base_paddings[2:]
else:
self.base_paddings = base_paddings[1:-1]
else: else:
raise ValueError("Invalid padding method %r" % padding) raise ValueError("Invalid padding method %r" % padding)
@ -1538,7 +1528,7 @@ def atrous_conv2d(value, filters, rate, padding, name=None):
name=name) name=name)
def convert_padding(padding): def _convert_padding(padding):
"""Converts Python padding to C++ padding for ops which take EXPLICIT padding. """Converts Python padding to C++ padding for ops which take EXPLICIT padding.
Args: Args:
@ -1867,7 +1857,7 @@ def conv2d_v2(input, # pylint: disable=redefined-builtin
... [[1], [3], [2], [2], [3]], ... [[1], [3], [2], [2], [3]],
... [[1], [1], [3], [3], [0]], ... [[1], [1], [3], [3], [0]],
... [[2], [2], [0], [1], [1]], ... [[2], [2], [0], [1], [1]],
... [[0], [0], [3], [1], [2]], ]]) ... [[0], [0], [3], [1], [2]], ]])
>>> kernel_in = np.array([ >>> kernel_in = np.array([
... [ [[2, 0.1]], [[3, 0.2]] ], ... [ [[2, 0.1]], [[3, 0.2]] ],
... [ [[0, 0.3]],[[1, 0.4]] ], ]) ... [ [[0, 0.3]],[[1, 0.4]] ], ])
@ -2006,7 +1996,7 @@ def conv2d( # pylint: disable=redefined-builtin,dangerous-default-value
""" """
filter = deprecation.deprecated_argument_lookup( filter = deprecation.deprecated_argument_lookup(
"filters", filters, "filter", filter) "filters", filters, "filter", filter)
padding, explicit_paddings = convert_padding(padding) padding, explicit_paddings = _convert_padding(padding)
if data_format is None: if data_format is None:
data_format = "NHWC" data_format = "NHWC"
channel_index = 1 if data_format.startswith("NC") else 3 channel_index = 1 if data_format.startswith("NC") else 3
@ -2078,7 +2068,7 @@ def conv2d_backprop_filter( # pylint: disable=redefined-builtin,dangerous-defau
Returns: Returns:
A `Tensor`. Has the same type as `input`. A `Tensor`. Has the same type as `input`.
""" """
padding, explicit_paddings = convert_padding(padding) padding, explicit_paddings = _convert_padding(padding)
return gen_nn_ops.conv2d_backprop_filter( return gen_nn_ops.conv2d_backprop_filter(
input, filter_sizes, out_backprop, strides, padding, use_cudnn_on_gpu, input, filter_sizes, out_backprop, strides, padding, use_cudnn_on_gpu,
explicit_paddings, data_format, dilations, name) explicit_paddings, data_format, dilations, name)
@ -2142,7 +2132,7 @@ def conv2d_backprop_input( # pylint: disable=redefined-builtin,dangerous-defaul
""" """
filter = deprecation.deprecated_argument_lookup( filter = deprecation.deprecated_argument_lookup(
"filters", filters, "filter", filter) "filters", filters, "filter", filter)
padding, explicit_paddings = convert_padding(padding) padding, explicit_paddings = _convert_padding(padding)
return gen_nn_ops.conv2d_backprop_input( return gen_nn_ops.conv2d_backprop_input(
input_sizes, filter, out_backprop, strides, padding, use_cudnn_on_gpu, input_sizes, filter, out_backprop, strides, padding, use_cudnn_on_gpu,
explicit_paddings, data_format, dilations, name) explicit_paddings, data_format, dilations, name)
@ -2459,219 +2449,6 @@ def atrous_conv2d_transpose(value,
input=value, crops=batch_to_space_crop, block_size=rate) input=value, crops=batch_to_space_crop, block_size=rate)
@tf_export(v1=["nn.depthwise_conv2d_native"])
@deprecation.deprecated_endpoints("nn.depthwise_conv2d_native")
def depthwise_conv2d_native( # pylint: disable=redefined-builtin,dangerous-default-value
input,
filter,
strides,
padding,
data_format="NHWC",
dilations=[1, 1, 1, 1],
name=None):
r"""Computes a 2-D depthwise convolution.
Given an input tensor of shape `[batch, in_height, in_width, in_channels]`
and a filter / kernel tensor of shape
`[filter_height, filter_width, in_channels, channel_multiplier]`, containing
`in_channels` convolutional filters of depth 1, `depthwise_conv2d` applies
a different filter to each input channel (expanding from 1 channel to
`channel_multiplier` channels for each), then concatenates the results
together. Thus, the output has `in_channels * channel_multiplier` channels.
```
for k in 0..in_channels-1
for q in 0..channel_multiplier-1
output[b, i, j, k * channel_multiplier + q] =
sum_{di, dj} input[b, strides[1] * i + di, strides[2] * j + dj, k] *
filter[di, dj, k, q]
```
Must have `strides[0] = strides[3] = 1`. For the most common case of the same
horizontal and vertices strides, `strides = [1, stride, stride, 1]`.
Args:
input: A `Tensor`. Must be one of the following types: `half`, `bfloat16`,
`float32`, `float64`.
filter: A `Tensor`. Must have the same type as `input`.
strides: A list of `ints`. 1-D of length 4. The stride of the sliding
window for each dimension of `input`.
padding: Controls how to pad the image before applying the convolution. Can
be the string `"SAME"` or `"VALID"` indicating the type of padding
algorithm to use, or a list indicating the explicit paddings at the start
and end of each dimension. When explicit padding is used and data_format
is `"NHWC"`, this should be in the form `[[0, 0], [pad_top, pad_bottom],
[pad_left, pad_right], [0, 0]]`. When explicit padding used and
data_format is `"NCHW"`, this should be in the form `[[0, 0], [0, 0],
[pad_top, pad_bottom], [pad_left, pad_right]]`.
data_format: An optional `string` from: `"NHWC", "NCHW"`. Defaults to
`"NHWC"`. Specify the data format of the input and output data. With the
default format "NHWC", the data is stored in the order of: [batch, height,
width, channels].
Alternatively, the format could be "NCHW", the data storage order of:
[batch, channels, height, width].
dilations: An optional list of `ints`. Defaults to `[1, 1, 1, 1]`. 1-D
tensor of length 4. The dilation factor for each dimension of `input`. If
set to k > 1, there will be k-1 skipped cells between each filter element
on that dimension. The dimension order is determined by the value of
`data_format`, see above for details. Dilations in the batch and depth
dimensions must be 1.
name: A name for the operation (optional).
Returns:
A `Tensor`. Has the same type as `input`.
"""
padding, explicit_paddings = convert_padding(padding)
return gen_nn_ops.depthwise_conv2d_native(
input,
filter,
strides,
padding,
explicit_paddings=explicit_paddings,
data_format=data_format,
dilations=dilations,
name=name)
@tf_export(
"nn.depthwise_conv2d_backprop_input",
v1=[
"nn.depthwise_conv2d_native_backprop_input",
"nn.depthwise_conv2d_backprop_input"
])
@deprecation.deprecated_endpoints("nn.depthwise_conv2d_native_backprop_input")
def depthwise_conv2d_native_backprop_input( # pylint: disable=redefined-builtin,dangerous-default-value
input_sizes,
filter,
out_backprop,
strides,
padding,
data_format="NHWC",
dilations=[1, 1, 1, 1],
name=None):
r"""Computes the gradients of depthwise convolution with respect to the input.
Args:
input_sizes: A `Tensor` of type `int32`. An integer vector representing the
shape of `input`, based on `data_format`. For example, if `data_format`
is 'NHWC' then `input` is a 4-D `[batch, height, width, channels]` tensor.
filter: A `Tensor`. Must be one of the following types: `half`, `bfloat16`,
`float32`, `float64`. 4-D with shape `[filter_height, filter_width,
in_channels, depthwise_multiplier]`.
out_backprop: A `Tensor`. Must have the same type as `filter`. 4-D with
shape based on `data_format`. For example, if `data_format` is 'NHWC'
then out_backprop shape is `[batch, out_height, out_width, out_channels]`.
Gradients w.r.t. the output of the convolution.
strides: A list of `ints`. The stride of the sliding window for each
dimension of the input of the convolution.
padding: Controls how to pad the image before applying the convolution. Can
be the string `"SAME"` or `"VALID"` indicating the type of padding
algorithm to use, or a list indicating the explicit paddings at the start
and end of each dimension. When explicit padding is used and data_format
is `"NHWC"`, this should be in the form `[[0, 0], [pad_top, pad_bottom],
[pad_left, pad_right], [0, 0]]`. When explicit padding used and
data_format is `"NCHW"`, this should be in the form `[[0, 0], [0, 0],
[pad_top, pad_bottom], [pad_left, pad_right]]`.
data_format: An optional `string` from: `"NHWC", "NCHW"`. Defaults to
`"NHWC"`. Specify the data format of the input and output data. With the
default format "NHWC", the data is stored in the order of: [batch, height,
width, channels].
Alternatively, the format could be "NCHW", the data storage order of:
[batch, channels, height, width].
dilations: An optional list of `ints`. Defaults to `[1, 1, 1, 1]`. 1-D
tensor of length 4. The dilation factor for each dimension of `input`. If
set to k > 1, there will be k-1 skipped cells between each filter element
on that dimension. The dimension order is determined by the value of
`data_format`, see above for details. Dilations in the batch and depth
dimensions must be 1.
name: A name for the operation (optional).
Returns:
A `Tensor`. Has the same type as `filter`.
"""
padding, explicit_paddings = convert_padding(padding)
return gen_nn_ops.depthwise_conv2d_native_backprop_input(
input_sizes,
filter,
out_backprop,
strides,
padding,
explicit_paddings=explicit_paddings,
data_format=data_format,
dilations=dilations,
name=name)
@tf_export(
"nn.depthwise_conv2d_backprop_filter",
v1=[
"nn.depthwise_conv2d_native_backprop_filter",
"nn.depthwise_conv2d_backprop_filter"
])
@deprecation.deprecated_endpoints("nn.depthwise_conv2d_native_backprop_filter")
def depthwise_conv2d_native_backprop_filter( # pylint: disable=redefined-builtin,dangerous-default-value
input,
filter_sizes,
out_backprop,
strides,
padding,
data_format="NHWC",
dilations=[1, 1, 1, 1],
name=None):
r"""Computes the gradients of depthwise convolution with respect to the filter.
Args:
input: A `Tensor`. Must be one of the following types: `half`, `bfloat16`,
`float32`, `float64`. 4-D with shape based on `data_format`. For example,
if `data_format` is 'NHWC' then `input` is a 4-D `[batch, in_height,
in_width, in_channels]` tensor.
filter_sizes: A `Tensor` of type `int32`. An integer vector representing the
tensor shape of `filter`, where `filter` is a 4-D `[filter_height,
filter_width, in_channels, depthwise_multiplier]` tensor.
out_backprop: A `Tensor`. Must have the same type as `input`. 4-D with shape
based on `data_format`. For example, if `data_format` is 'NHWC' then
out_backprop shape is `[batch, out_height, out_width, out_channels]`.
Gradients w.r.t. the output of the convolution.
strides: A list of `ints`. The stride of the sliding window for each
dimension of the input of the convolution.
padding: Controls how to pad the image before applying the convolution. Can
be the string `"SAME"` or `"VALID"` indicating the type of padding
algorithm to use, or a list indicating the explicit paddings at the start
and end of each dimension. When explicit padding is used and data_format
is `"NHWC"`, this should be in the form `[[0, 0], [pad_top, pad_bottom],
[pad_left, pad_right], [0, 0]]`. When explicit padding used and
data_format is `"NCHW"`, this should be in the form `[[0, 0], [0, 0],
[pad_top, pad_bottom], [pad_left, pad_right]]`.
data_format: An optional `string` from: `"NHWC", "NCHW"`. Defaults to
`"NHWC"`. Specify the data format of the input and output data. With the
default format "NHWC", the data is stored in the order of: [batch, height,
width, channels].
Alternatively, the format could be "NCHW", the data storage order of:
[batch, channels, height, width].
dilations: An optional list of `ints`. Defaults to `[1, 1, 1, 1]`. 1-D
tensor of length 4. The dilation factor for each dimension of `input`. If
set to k > 1, there will be k-1 skipped cells between each filter element
on that dimension. The dimension order is determined by the value of
`data_format`, see above for details. Dilations in the batch and depth
dimensions must be 1.
name: A name for the operation (optional).
Returns:
A `Tensor`. Has the same type as `input`.
"""
padding, explicit_paddings = convert_padding(padding)
return gen_nn_ops.depthwise_conv2d_native_backprop_filter(
input,
filter_sizes,
out_backprop,
strides,
padding,
explicit_paddings=explicit_paddings,
data_format=data_format,
dilations=dilations,
name=name)
@tf_export("nn.conv3d", v1=[]) @tf_export("nn.conv3d", v1=[])
def conv3d_v2(input, # pylint: disable=redefined-builtin,missing-docstring def conv3d_v2(input, # pylint: disable=redefined-builtin,missing-docstring
filters, filters,

View File

@ -1090,15 +1090,15 @@ tf_module {
} }
member_method { member_method {
name: "DepthwiseConv2dNative" name: "DepthwiseConv2dNative"
argspec: "args=[\'input\', \'filter\', \'strides\', \'padding\', \'explicit_paddings\', \'data_format\', \'dilations\', \'name\'], varargs=None, keywords=None, defaults=[\'[]\', \'NHWC\', \'[1, 1, 1, 1]\', \'None\'], " argspec: "args=[\'input\', \'filter\', \'strides\', \'padding\', \'data_format\', \'dilations\', \'name\'], varargs=None, keywords=None, defaults=[\'NHWC\', \'[1, 1, 1, 1]\', \'None\'], "
} }
member_method { member_method {
name: "DepthwiseConv2dNativeBackpropFilter" name: "DepthwiseConv2dNativeBackpropFilter"
argspec: "args=[\'input\', \'filter_sizes\', \'out_backprop\', \'strides\', \'padding\', \'explicit_paddings\', \'data_format\', \'dilations\', \'name\'], varargs=None, keywords=None, defaults=[\'[]\', \'NHWC\', \'[1, 1, 1, 1]\', \'None\'], " argspec: "args=[\'input\', \'filter_sizes\', \'out_backprop\', \'strides\', \'padding\', \'data_format\', \'dilations\', \'name\'], varargs=None, keywords=None, defaults=[\'NHWC\', \'[1, 1, 1, 1]\', \'None\'], "
} }
member_method { member_method {
name: "DepthwiseConv2dNativeBackpropInput" name: "DepthwiseConv2dNativeBackpropInput"
argspec: "args=[\'input_sizes\', \'filter\', \'out_backprop\', \'strides\', \'padding\', \'explicit_paddings\', \'data_format\', \'dilations\', \'name\'], varargs=None, keywords=None, defaults=[\'[]\', \'NHWC\', \'[1, 1, 1, 1]\', \'None\'], " argspec: "args=[\'input_sizes\', \'filter\', \'out_backprop\', \'strides\', \'padding\', \'data_format\', \'dilations\', \'name\'], varargs=None, keywords=None, defaults=[\'NHWC\', \'[1, 1, 1, 1]\', \'None\'], "
} }
member_method { member_method {
name: "Dequantize" name: "Dequantize"

View File

@ -1090,15 +1090,15 @@ tf_module {
} }
member_method { member_method {
name: "DepthwiseConv2dNative" name: "DepthwiseConv2dNative"
argspec: "args=[\'input\', \'filter\', \'strides\', \'padding\', \'explicit_paddings\', \'data_format\', \'dilations\', \'name\'], varargs=None, keywords=None, defaults=[\'[]\', \'NHWC\', \'[1, 1, 1, 1]\', \'None\'], " argspec: "args=[\'input\', \'filter\', \'strides\', \'padding\', \'data_format\', \'dilations\', \'name\'], varargs=None, keywords=None, defaults=[\'NHWC\', \'[1, 1, 1, 1]\', \'None\'], "
} }
member_method { member_method {
name: "DepthwiseConv2dNativeBackpropFilter" name: "DepthwiseConv2dNativeBackpropFilter"
argspec: "args=[\'input\', \'filter_sizes\', \'out_backprop\', \'strides\', \'padding\', \'explicit_paddings\', \'data_format\', \'dilations\', \'name\'], varargs=None, keywords=None, defaults=[\'[]\', \'NHWC\', \'[1, 1, 1, 1]\', \'None\'], " argspec: "args=[\'input\', \'filter_sizes\', \'out_backprop\', \'strides\', \'padding\', \'data_format\', \'dilations\', \'name\'], varargs=None, keywords=None, defaults=[\'NHWC\', \'[1, 1, 1, 1]\', \'None\'], "
} }
member_method { member_method {
name: "DepthwiseConv2dNativeBackpropInput" name: "DepthwiseConv2dNativeBackpropInput"
argspec: "args=[\'input_sizes\', \'filter\', \'out_backprop\', \'strides\', \'padding\', \'explicit_paddings\', \'data_format\', \'dilations\', \'name\'], varargs=None, keywords=None, defaults=[\'[]\', \'NHWC\', \'[1, 1, 1, 1]\', \'None\'], " argspec: "args=[\'input_sizes\', \'filter\', \'out_backprop\', \'strides\', \'padding\', \'data_format\', \'dilations\', \'name\'], varargs=None, keywords=None, defaults=[\'NHWC\', \'[1, 1, 1, 1]\', \'None\'], "
} }
member_method { member_method {
name: "Dequantize" name: "Dequantize"