1 | /* Copyright 2017 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 | #ifndef TENSORFLOW_LITE_KERNELS_PADDING_H_ |
16 | #define TENSORFLOW_LITE_KERNELS_PADDING_H_ |
17 | |
18 | #include "tensorflow/lite/c/builtin_op_data.h" |
19 | #include "tensorflow/lite/kernels/internal/types.h" |
20 | |
21 | namespace tflite { |
22 | |
23 | inline int ComputePadding(int stride, int dilation_rate, int in_size, |
24 | int filter_size, int out_size) { |
25 | int effective_filter_size = (filter_size - 1) * dilation_rate + 1; |
26 | int padding = ((out_size - 1) * stride + effective_filter_size - in_size) / 2; |
27 | return padding > 0 ? padding : 0; |
28 | } |
29 | |
30 | // It's not guaranteed that padding is symmetric. It's important to keep |
31 | // offset for algorithms need all paddings. |
32 | inline int ComputePaddingWithOffset(int stride, int dilation_rate, int in_size, |
33 | int filter_size, int out_size, |
34 | int* offset) { |
35 | int effective_filter_size = (filter_size - 1) * dilation_rate + 1; |
36 | int total_padding = |
37 | ((out_size - 1) * stride + effective_filter_size - in_size); |
38 | total_padding = total_padding > 0 ? total_padding : 0; |
39 | *offset = total_padding % 2; |
40 | return total_padding / 2; |
41 | } |
42 | |
43 | // Matching GetWindowedOutputSize in TensorFlow. |
44 | inline int ComputeOutSize(TfLitePadding padding, int image_size, |
45 | int filter_size, int stride, int dilation_rate = 1) { |
46 | int effective_filter_size = (filter_size - 1) * dilation_rate + 1; |
47 | |
48 | // TODO(b/186448822): This uses 0 since the function has no other way to |
49 | // report error case |
50 | if (stride == 0) return 0; |
51 | |
52 | switch (padding) { |
53 | case kTfLitePaddingSame: |
54 | return (image_size + stride - 1) / stride; |
55 | case kTfLitePaddingValid: |
56 | return (image_size + stride - effective_filter_size) / stride; |
57 | default: |
58 | return 0; |
59 | } |
60 | } |
61 | |
62 | inline TfLitePaddingValues ComputePaddingHeightWidth( |
63 | int stride_height, int stride_width, int dilation_rate_height, |
64 | int dilation_rate_width, int in_height, int in_width, int filter_height, |
65 | int filter_width, TfLitePadding padding, int* out_height, int* out_width) { |
66 | *out_width = ComputeOutSize(padding, in_width, filter_width, stride_width, |
67 | dilation_rate_width); |
68 | *out_height = ComputeOutSize(padding, in_height, filter_height, stride_height, |
69 | dilation_rate_height); |
70 | |
71 | TfLitePaddingValues padding_values; |
72 | int offset = 0; |
73 | padding_values.height = |
74 | ComputePaddingWithOffset(stride_height, dilation_rate_height, in_height, |
75 | filter_height, *out_height, &offset); |
76 | padding_values.height_offset = offset; |
77 | padding_values.width = |
78 | ComputePaddingWithOffset(stride_width, dilation_rate_width, in_width, |
79 | filter_width, *out_width, &offset); |
80 | padding_values.width_offset = offset; |
81 | return padding_values; |
82 | } |
83 | |
84 | inline Padding3DValues ComputePadding3DValues( |
85 | int stride_height, int stride_width, int stride_depth, |
86 | int dilation_rate_height, int dilation_rate_width, int dilation_rate_depth, |
87 | int in_height, int in_width, int in_depth, int filter_height, |
88 | int filter_width, int filter_depth, TfLitePadding padding, int* out_height, |
89 | int* out_width, int* out_depth) { |
90 | *out_width = ComputeOutSize(padding, in_width, filter_width, stride_width, |
91 | dilation_rate_width); |
92 | *out_height = ComputeOutSize(padding, in_height, filter_height, stride_height, |
93 | dilation_rate_height); |
94 | *out_depth = ComputeOutSize(padding, in_depth, filter_depth, stride_depth, |
95 | dilation_rate_depth); |
96 | |
97 | Padding3DValues padding_values; |
98 | int offset = 0; |
99 | padding_values.depth = |
100 | ComputePaddingWithOffset(stride_depth, dilation_rate_depth, in_depth, |
101 | filter_depth, *out_depth, &offset); |
102 | padding_values.depth_offset = offset; |
103 | padding_values.height = |
104 | ComputePaddingWithOffset(stride_height, dilation_rate_height, in_height, |
105 | filter_height, *out_height, &offset); |
106 | padding_values.height_offset = offset; |
107 | padding_values.width = |
108 | ComputePaddingWithOffset(stride_width, dilation_rate_width, in_width, |
109 | filter_width, *out_width, &offset); |
110 | padding_values.width_offset = offset; |
111 | return padding_values; |
112 | } |
113 | } // namespace tflite |
114 | |
115 | #endif // TENSORFLOW_LITE_KERNELS_PADDING_H_ |
116 | |