• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 // See docs in ../ops/nn_ops.cc.
17 
18 #define USE_EIGEN_TENSOR
19 #define EIGEN_USE_THREADS
20 
21 #include "tensorflow/core/kernels/conv_grad_ops.h"
22 
23 #include <algorithm>
24 #include <vector>
25 
26 #include "tensorflow/core/framework/common_shape_fns.h"
27 #include "tensorflow/core/framework/numeric_op.h"
28 #include "tensorflow/core/framework/op_kernel.h"
29 #include "tensorflow/core/framework/register_types.h"
30 #include "tensorflow/core/framework/tensor.h"
31 #include "tensorflow/core/framework/tensor_shape.h"
32 #include "tensorflow/core/framework/tensor_slice.h"
33 #include "tensorflow/core/kernels/conv_2d.h"
34 #include "tensorflow/core/kernels/ops_util.h"
35 #include "tensorflow/core/lib/core/errors.h"
36 #include "tensorflow/core/platform/logging.h"
37 #include "tensorflow/core/platform/macros.h"
38 #include "tensorflow/core/util/padding.h"
39 #include "tensorflow/core/util/tensor_format.h"
40 #include "tensorflow/core/util/use_cudnn.h"
41 
42 namespace tensorflow {
43 
44 // Compute padding for the given spatial dimension.
SpatialPadding(const Padding & padding,int dim) const45 int ConvBackpropDimensions::SpatialPadding(const Padding& padding,
46                                            int dim) const {
47   return (padding == VALID)
48              ? 0
49              : std::max<int>(
50                    0, static_cast<int>((output_size(dim) - 1) * stride(dim) +
51                                        (filter_size(dim) - 1) * dilation(dim) +
52                                        1 - input_size(dim)));
53 }
54 
55 namespace {
56 
ConvBackpropExtractAndVerifyDimension(StringPiece label,const TensorShape & input_shape,const TensorShape & filter_shape,const TensorShape & output_shape,const gtl::ArraySlice<int32> & dilations,const std::vector<int32> & strides,Padding padding,int64 padding_before,int64 padding_after,int spatial_dim,int filter_spatial_dim,ConvBackpropSpatialDimension * dim)57 Status ConvBackpropExtractAndVerifyDimension(
58     StringPiece label, const TensorShape& input_shape,
59     const TensorShape& filter_shape, const TensorShape& output_shape,
60     const gtl::ArraySlice<int32>& dilations, const std::vector<int32>& strides,
61     Padding padding, int64 padding_before, int64 padding_after, int spatial_dim,
62     int filter_spatial_dim, ConvBackpropSpatialDimension* dim) {
63   dim->input_size = input_shape.dim_size(spatial_dim);
64   dim->filter_size = filter_shape.dim_size(filter_spatial_dim);
65   dim->output_size = output_shape.dim_size(spatial_dim);
66   dim->stride = strides[spatial_dim];
67   dim->dilation = dilations[spatial_dim];
68   int64 out_size = 0;
69   TF_RETURN_IF_ERROR(GetWindowedOutputSizeVerboseV2(
70       dim->input_size, dim->filter_size, dim->dilation, dim->stride, padding,
71       &out_size, &padding_before, &padding_after));
72   if (dim->output_size != out_size) {
73     return errors::InvalidArgument(
74         label, ": Size of out_backprop doesn't match computed: ", "actual = ",
75         dim->output_size, ", computed = ", out_size,
76         " spatial_dim: ", spatial_dim, " input: ", dim->input_size,
77         " filter: ", dim->filter_size, " output: ", dim->output_size,
78         " stride: ", dim->stride, " dilation: ", dim->dilation);
79   }
80 
81   int64 effective_filter_size = (dim->filter_size - 1) * dim->dilation + 1;
82   dim->expanded_output_size = (dim->output_size - 1) * dim->stride + 1;
83   const auto padded_out_size = dim->input_size + effective_filter_size - 1;
84   dim->pad_before = effective_filter_size - 1 - padding_before;
85   dim->pad_after =
86       padded_out_size - dim->expanded_output_size - dim->pad_before;
87   VLOG(2) << label << ": expanded_out = " << dim->expanded_output_size
88           << ", effective_filter_size = " << effective_filter_size
89           << ", padded_out = " << padded_out_size
90           << ", pad_before = " << dim->pad_before
91           << ", pad_after = " << dim->pad_after
92           << ", dilation = " << dim->dilation << ", strides = " << dim->stride;
93   return Status::OK();
94 }
95 
96 }  // namespace
97 
ConvBackpropComputeDimensionsV2(StringPiece label,int num_spatial_dims,const TensorShape & input_shape,const TensorShape & filter_shape,const TensorShape & out_backprop_shape,const gtl::ArraySlice<int32> & dilations,const std::vector<int32> & strides,Padding padding,absl::Span<const int64> explicit_paddings,TensorFormat data_format,ConvBackpropDimensions * dims)98 Status ConvBackpropComputeDimensionsV2(
99     StringPiece label, int num_spatial_dims, const TensorShape& input_shape,
100     const TensorShape& filter_shape, const TensorShape& out_backprop_shape,
101     const gtl::ArraySlice<int32>& dilations, const std::vector<int32>& strides,
102     Padding padding, absl::Span<const int64> explicit_paddings,
103     TensorFormat data_format, ConvBackpropDimensions* dims) {
104   // The + 2 in the following line is for the batch and feature dimensions.
105   const int num_dims = num_spatial_dims + 2;
106   if (input_shape.dims() != num_dims) {
107     return errors::InvalidArgument(label, ": input must be ", num_dims,
108                                    "-dimensional");
109   }
110   if (filter_shape.dims() != num_dims) {
111     return errors::InvalidArgument(label, ": filter must be ", num_dims,
112                                    "-dimensional");
113   }
114   if (out_backprop_shape.dims() != num_dims) {
115     return errors::InvalidArgument(label, ": out_backprop must be ", num_dims,
116                                    "-dimensional");
117   }
118   int batch_dim = GetTensorBatchDimIndex(num_dims, data_format);
119   dims->batch_size = input_shape.dim_size(batch_dim);
120   if (dims->batch_size != out_backprop_shape.dim_size(batch_dim)) {
121     return errors::InvalidArgument(
122         label, ": input and out_backprop must have the same batch size",
123         "input batch: ", dims->batch_size,
124         "outbackprop batch: ", out_backprop_shape.dim_size(batch_dim),
125         " batch_dim: ", batch_dim);
126   }
127 
128   int feature_dim = GetTensorFeatureDimIndex(num_dims, data_format);
129   dims->in_depth = input_shape.dim_size(feature_dim);
130   // The input and output feature dimensions are the second last and last
131   // dimensions of the filter Tensor.
132   VLOG(2) << "input vs filter_in depth " << dims->in_depth << " "
133           << filter_shape.dim_size(num_dims - 2);
134   if (dims->in_depth % filter_shape.dim_size(num_dims - 2)) {
135     return errors::InvalidArgument(
136         label, ": input depth must be evenly divisible by filter depth");
137   }
138   dims->out_depth = filter_shape.dim_size(num_dims - 1);
139   if (dims->out_depth != out_backprop_shape.dim_size(feature_dim)) {
140     return errors::InvalidArgument(
141         label, ": filter and out_backprop must have the same out_depth");
142   }
143   dims->spatial_dims.resize(num_spatial_dims);
144   for (int i = 0; i < num_spatial_dims; ++i) {
145     int image_dim = GetTensorSpatialDimIndex(num_dims, data_format, i);
146     int64 padding_before = -1, padding_after = -1;
147     if (padding == EXPLICIT) {
148       padding_before = explicit_paddings[2 * image_dim];
149       padding_after = explicit_paddings[2 * image_dim + 1];
150     }
151     TF_RETURN_IF_ERROR(ConvBackpropExtractAndVerifyDimension(
152         label, input_shape, filter_shape, out_backprop_shape, dilations,
153         strides, padding, padding_before, padding_after, image_dim, i,
154         &dims->spatial_dims[i]));
155   }
156   return Status::OK();
157 }
158 
ConvBackpropComputeDimensions(StringPiece label,int num_spatial_dims,const TensorShape & input_shape,const TensorShape & filter_shape,const TensorShape & out_backprop_shape,const std::vector<int32> & strides,Padding padding,TensorFormat data_format,ConvBackpropDimensions * dims)159 Status ConvBackpropComputeDimensions(StringPiece label, int num_spatial_dims,
160                                      const TensorShape& input_shape,
161                                      const TensorShape& filter_shape,
162                                      const TensorShape& out_backprop_shape,
163                                      const std::vector<int32>& strides,
164                                      Padding padding, TensorFormat data_format,
165                                      ConvBackpropDimensions* dims) {
166   static constexpr std::array<int32, 5> one_dilations = {{1, 1, 1, 1, 1}};
167   return ConvBackpropComputeDimensionsV2(
168       label, num_spatial_dims, input_shape, filter_shape, out_backprop_shape,
169       one_dilations, strides, padding, /*explicit_paddings=*/{}, data_format,
170       dims);
171 }
172 
173 }  // namespace tensorflow
174