31969911f2349db737dac8e101ac3d627de188ef
[platform/core/ml/nnfw.git] / runtime / onert / core / src / ir / Padding.cc
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "ir/Padding.h"
18
19 #include "util/Utils.h"
20
21 #include <stdexcept>
22 #include <cassert>
23
24 namespace onert
25 {
26 namespace ir
27 {
28 namespace
29 {
30
31 inline ExplicitPadding validPadding(void)
32 {
33   //
34   // ANEURALNETWORKS_PADDING_VALID
35   //
36   // VALID padding. No padding.
37   //
38   // When the input size is not evenly divisible by the filter size,
39   // the input at the end that could not fill the whole filter tile
40   // will simply be ignored.
41   //
42   ExplicitPadding padding;
43
44   padding.top = 0;
45   padding.bottom = 0;
46   padding.left = 0;
47   padding.right = 0;
48
49   return padding;
50 }
51
52 inline ExplicitPadding samePaddingUsingIFM(const FeatureShape &ifm_shape, const Stride &stride,
53                                            uint32_t kw, uint32_t kh)
54 {
55   ExplicitPadding padding;
56
57   // ANEURALNETWORKS_PADDING_SAME (from NNAPI spec)
58   //
59   // SAME padding. Padding on both ends are the "same":
60   //
61   // padding_to_beginning = total_padding / 2
62   // padding_to_end = (total_padding + 1)/2.
63   //
64   const int32_t vertical_expected_output = (ifm_shape.H + stride.vertical - 1) / stride.vertical;
65   const int32_t horizontal_expected_output =
66       (ifm_shape.W + stride.horizontal - 1) / stride.horizontal;
67
68   const int32_t vertical_needed_input = (vertical_expected_output - 1) * stride.vertical + kh;
69   const int32_t vertical_total_padding = std::max(0, vertical_needed_input - ifm_shape.H);
70
71   const int32_t horizontal_needed_input = (horizontal_expected_output - 1) * stride.horizontal + kw;
72   const int32_t horizontal_total_padding = std::max(0, horizontal_needed_input - ifm_shape.W);
73
74   padding.top = vertical_total_padding / 2;
75   padding.bottom = (vertical_total_padding + 1) / 2;
76   padding.left = horizontal_total_padding / 2;
77   padding.right = (horizontal_total_padding + 1) / 2;
78
79   return padding;
80 }
81
82 inline ExplicitPadding samePadding(const FeatureShape &ifm_shape, const FeatureShape &ofm_shape,
83                                    const Stride &stride, uint32_t kw, uint32_t kh)
84 {
85   const int32_t vertical_expected_output = (ifm_shape.H + stride.vertical - 1) / stride.vertical;
86   const int32_t horizontal_expected_output =
87       (ifm_shape.W + stride.horizontal - 1) / stride.horizontal;
88   assert(vertical_expected_output == ofm_shape.H);
89   assert(horizontal_expected_output == ofm_shape.W);
90
91   UNUSED_RELEASE(ofm_shape);
92   UNUSED_RELEASE(vertical_expected_output);
93   UNUSED_RELEASE(horizontal_expected_output);
94
95   return samePaddingUsingIFM(ifm_shape, stride, kw, kh);
96 }
97
98 } // namespace
99
100 inline std::string to_string(const PaddingType type)
101 {
102   switch (type)
103   {
104     case PaddingType::EXPLICIT:
105       return "Padding::EXPLICIT";
106     case PaddingType::SAME:
107       return "Padding::SAME";
108     case PaddingType::VALID:
109       return "Padding::VALID";
110     default:
111       throw std::runtime_error{"Fail to convert string: wrong padding type"};
112   }
113 }
114
115 Padding::Padding(void) : type{PaddingType::EXPLICIT}, param{0, 0, 0, 0}
116 {
117   // DO NOTHING
118 }
119
120 Padding::Padding(PaddingType paddingType) : type{paddingType}, param{0, 0, 0, 0}
121 {
122   assert(paddingType != PaddingType::EXPLICIT);
123 }
124
125 Padding::Padding(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom)
126     : type{PaddingType::EXPLICIT}, param{left, right, top, bottom}
127 {
128   // DO NOTHING
129 }
130
131 const ExplicitPadding calculatePadding(const Padding &padding, const FeatureShape &ifm_shape,
132                                        const FeatureShape &ofm_shape, const Stride &stride,
133                                        uint32_t kw, uint32_t kh)
134 {
135   if (padding.type == PaddingType::EXPLICIT)
136   {
137     return padding.param;
138   }
139   else if (padding.type == PaddingType::SAME)
140   {
141     return samePadding(ifm_shape, ofm_shape, stride, kw, kh);
142   }
143   else if (padding.type == PaddingType::VALID)
144   {
145     return validPadding();
146   }
147   else
148   {
149     throw std::runtime_error{"Cannot handle padding type"};
150   }
151 }
152
153 } // namespace ir
154 } // namespace onert