Imported Upstream version 1.12.0
[platform/core/ml/nnfw.git] / tools / kbenchmark / kernels / acl_neon / TransposeConv.cpp
1 /*
2  * Copyright (c) 2019 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 /**
18  * @file TransposeConv benchmark with various algorithms
19  */
20
21 #include <nonius/nonius.h++>
22
23 #include <arm_compute/core/Types.h>
24 #include <arm_compute/runtime/NEON/NEScheduler.h>
25 #include <arm_compute/runtime/NEON/NEFunctions.h>
26
27 #include <cstdint>
28 #include <cassert>
29 #include <stdexcept>
30
31 #include "acl_common/Utils.h"
32
33 using namespace arm_compute;
34 using namespace kbenchmark::kernels::acl_common;
35
36 //
37 // Helpers
38 //
39 namespace
40 {
41
42 enum Layout
43 {
44   NCHW,
45   NHWC
46 };
47
48 TensorInfo make_info(uint32_t N)
49 {
50   TensorShape shape{N};
51   return TensorInfo{shape, 1, DataType::F32};
52 }
53
54 template <enum Layout> TensorInfo make_info(uint32_t N, uint32_t C, uint32_t H, uint32_t W);
55
56 template <> TensorInfo make_info<NCHW>(uint32_t N, uint32_t C, uint32_t H, uint32_t W)
57 {
58   TensorShape shape{W, H, C, N};
59   TensorInfo info{shape, 1, DataType::F32};
60   info.set_data_layout(DataLayout::NCHW);
61   return info;
62 }
63
64 template <> TensorInfo make_info<NHWC>(uint32_t N, uint32_t C, uint32_t H, uint32_t W)
65 {
66   TensorShape shape{C, W, H, N};
67   TensorInfo info{shape, 1, DataType::F32};
68   info.set_data_layout(DataLayout::NHWC);
69   return info;
70 }
71
72 inline void check(const Status &status)
73 {
74   if (!status)
75   {
76     std::cerr << status.error_description() << std::endl;
77     throw std::runtime_error{"ERROR"};
78   }
79 }
80
81 inline bool is_odd(uint32_t n) { return (n % 2 != 0) ? true : false; }
82
83 } // namespace
84
85 //
86 // Benchmark Parameters
87 //
88 NONIUS_PARAM(BATCH, 1);
89
90 NONIUS_PARAM(IFM_C, 3);
91 NONIUS_PARAM(IFM_H, 244);
92 NONIUS_PARAM(IFM_W, 244);
93
94 NONIUS_PARAM(OFM_C, 3);
95 NONIUS_PARAM(OFM_H, 244);
96 NONIUS_PARAM(OFM_W, 244);
97
98 NONIUS_PARAM(KER_H, 3);
99 NONIUS_PARAM(KER_W, 3);
100
101 NONIUS_PARAM(STRIDE_H, 1);
102 NONIUS_PARAM(STRIDE_W, 1);
103
104 NONIUS_PARAM(PADDING, std::string{"SAME"})
105
106 //
107 // Configuration Helpers
108 //
109 namespace
110 {
111
112 struct Configuration
113 {
114   uint32_t ifm_N;
115   uint32_t ifm_C;
116   uint32_t ifm_H;
117   uint32_t ifm_W;
118
119   uint32_t ofm_N;
120   uint32_t ofm_C;
121   uint32_t ofm_H;
122   uint32_t ofm_W;
123
124   uint32_t ker_N;
125   uint32_t ker_C;
126   uint32_t ker_H;
127   uint32_t ker_W;
128
129   uint32_t vertical_stride;
130   uint32_t horizontal_stride;
131
132   PadStrideInfo deconv_info;
133
134   uint32_t inner_border_right;
135   uint32_t inner_border_top;
136
137   Configuration(nonius::chronometer meter)
138   {
139     ifm_N = meter.param<BATCH>();
140     ifm_C = meter.param<IFM_C>();
141     ifm_H = meter.param<IFM_H>();
142     ifm_W = meter.param<IFM_W>();
143
144     ofm_N = meter.param<BATCH>();
145     ofm_C = meter.param<OFM_C>();
146     ofm_H = meter.param<OFM_H>();
147     ofm_W = meter.param<OFM_W>();
148
149     ker_N = meter.param<OFM_C>();
150     ker_C = meter.param<IFM_C>();
151     ker_H = meter.param<KER_H>();
152     ker_W = meter.param<KER_W>();
153
154     vertical_stride = meter.param<STRIDE_H>();
155     horizontal_stride = meter.param<STRIDE_W>();
156
157     // NOTE The padding calculation formula of TransposeConv is opposite to Conv.
158     //      So the location of ifm and ofm is changed.
159     auto padding_info = calculatePadding(meter.param<PADDING>(), ofm_H, ofm_W, ifm_H, ifm_W,
160                                          vertical_stride, horizontal_stride, ker_H, ker_W);
161
162     inner_border_right = padding_info.right - padding_info.left;
163     inner_border_top = padding_info.bottom - padding_info.top;
164
165     padding_info.left = padding_info.right;
166     padding_info.top = padding_info.bottom;
167
168     deconv_info = asPadStrideInfo(padding_info, vertical_stride, horizontal_stride);
169   }
170
171   template <Layout L> TensorInfo src_info() const
172   {
173     return make_info<L>(ifm_N, ifm_C, ifm_H, ifm_W);
174   }
175   template <Layout L> TensorInfo dst_info() const
176   {
177     return make_info<L>(ofm_N, ofm_C, ofm_H, ofm_W);
178   }
179   template <Layout L> TensorInfo ker_info() const
180   {
181     return make_info<L>(ker_N, ker_C, ker_H, ker_W);
182   }
183   TensorInfo bias_info(void) const { return make_info(ker_N); }
184 };
185
186 } // namespace
187
188 //
189 // Benchmark Implementations
190 //
191 namespace
192 {
193
194 inline nonius::benchmark_registry &local_benchmark_registry()
195 {
196   static nonius::benchmark_registry registry;
197   return registry;
198 }
199
200 } // namespace
201
202 #define NONIUS_LOCAL_BENCHMARK(name, ...)                                                          \
203   namespace                                                                                        \
204   {                                                                                                \
205   static ::nonius::benchmark_registrar                                                             \
206     NONIUS_DETAIL_UNIQUE_NAME(benchmark_registrar)(local_benchmark_registry(), name, __VA_ARGS__); \
207   }
208
209 NONIUS_LOCAL_BENCHMARK("NEDeconvolutionLayer_NCHW", [](nonius::chronometer meter) {
210   NEDeconvolutionLayer deconv;
211
212   // Configure
213   Configuration p{meter};
214
215   Tensor src_tensor{};
216   Tensor dst_tensor{};
217   Tensor ker_tensor{};
218
219   src_tensor.allocator()->init(p.src_info<NCHW>());
220   dst_tensor.allocator()->init(p.dst_info<NCHW>());
221   ker_tensor.allocator()->init(p.ker_info<NCHW>());
222
223   try
224   {
225     check(deconv.validate(src_tensor.info(), ker_tensor.info(), nullptr, dst_tensor.info(),
226                           p.deconv_info, p.inner_border_right, p.inner_border_top));
227   }
228   catch (...)
229   {
230     meter.measure([&](int) {
231       // DO NOTHING
232       volatile int x = 0;
233       return x;
234     });
235     return;
236   }
237
238   deconv.configure(&src_tensor, &ker_tensor, nullptr, &dst_tensor, p.deconv_info,
239                    p.inner_border_right, p.inner_border_top);
240
241   src_tensor.allocator()->allocate();
242   ker_tensor.allocator()->allocate();
243   dst_tensor.allocator()->allocate();
244
245   // Run!
246   meter.measure([&](int) { deconv.run(); });
247 })
248
249 NONIUS_LOCAL_BENCHMARK("NEDeconvolutionLayer_NHWC", [](nonius::chronometer meter) {
250   NEDeconvolutionLayer deconv;
251
252   // Configure
253   Configuration p{meter};
254
255   Tensor src_tensor{};
256   Tensor dst_tensor{};
257   Tensor ker_tensor{};
258
259   src_tensor.allocator()->init(p.src_info<NHWC>());
260   dst_tensor.allocator()->init(p.dst_info<NHWC>());
261   ker_tensor.allocator()->init(p.ker_info<NHWC>());
262
263   try
264   {
265     check(deconv.validate(src_tensor.info(), ker_tensor.info(), nullptr, dst_tensor.info(),
266                           p.deconv_info, p.inner_border_right, p.inner_border_top));
267   }
268   catch (...)
269   {
270     meter.measure([&](int) {
271       // DO NOTHING
272       volatile int x = 0;
273       return x;
274     });
275     return;
276   }
277
278   deconv.configure(&src_tensor, &ker_tensor, nullptr, &dst_tensor, p.deconv_info,
279                    p.inner_border_right, p.inner_border_top);
280
281   src_tensor.allocator()->allocate();
282   ker_tensor.allocator()->allocate();
283   dst_tensor.allocator()->allocate();
284
285   // Run!
286   meter.measure([&](int) { deconv.run(); });
287 })
288
289 extern "C" nonius::benchmark_registry &benchmark_functions(void)
290 {
291   return local_benchmark_registry();
292 }