2d19cb21eff7bd4a5e5c8ac50a7f72c97975b4e9
[platform/core/ml/nnfw.git] / tools / kbenchmark / kernels / acl_neon / Convolution.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 Conv2D benchmark with various algorithms (draft version)
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 using namespace arm_compute;
32
33 //
34 // Helpers
35 //
36 namespace
37 {
38
39 enum Layout
40 {
41   NCHW,
42   NHWC
43 };
44
45 TensorInfo make_info(uint32_t N)
46 {
47   TensorShape shape{N};
48   return TensorInfo{shape, 1, DataType::F32};
49 }
50
51 template <enum Layout> TensorInfo make_info(uint32_t N, uint32_t C, uint32_t H, uint32_t W);
52
53 template <> TensorInfo make_info<NCHW>(uint32_t N, uint32_t C, uint32_t H, uint32_t W)
54 {
55   TensorShape shape{W, H, C, N};
56   TensorInfo info{shape, 1, DataType::F32};
57   info.set_data_layout(DataLayout::NCHW);
58   return info;
59 }
60
61 template <> TensorInfo make_info<NHWC>(uint32_t N, uint32_t C, uint32_t H, uint32_t W)
62 {
63   TensorShape shape{C, W, H, N};
64   TensorInfo info{shape, 1, DataType::F32};
65   info.set_data_layout(DataLayout::NHWC);
66   return info;
67 }
68
69 inline void check(const Status &status)
70 {
71   if (!status)
72   {
73     std::cerr << status.error_description() << std::endl;
74     throw std::runtime_error{"ERROR"};
75   }
76 }
77
78 inline bool is_odd(uint32_t n) { return (n % 2 != 0) ? true : false; }
79
80 } // namespace
81
82 //
83 // Benchmark Parameters
84 //
85 NONIUS_PARAM(BATCH, 1);
86
87 NONIUS_PARAM(IFM_C, 3);
88 NONIUS_PARAM(IFM_H, 244);
89 NONIUS_PARAM(IFM_W, 244);
90
91 NONIUS_PARAM(OFM_C, 3);
92 NONIUS_PARAM(OFM_H, 244);
93 NONIUS_PARAM(OFM_W, 244);
94
95 NONIUS_PARAM(KER_H, 3);
96 NONIUS_PARAM(KER_W, 3);
97
98 NONIUS_PARAM(STRIDE_H, 1);
99 NONIUS_PARAM(STRIDE_W, 1);
100
101 NONIUS_PARAM(PADDING, std::string{"SAME"})
102 NONIUS_PARAM(FUSED_ACT, std::string{"RELU"})
103
104 //
105 // Configuration Helpers
106 //
107 namespace
108 {
109
110 struct Configuration
111 {
112   uint32_t ifm_N;
113   uint32_t ifm_C;
114   uint32_t ifm_H;
115   uint32_t ifm_W;
116
117   uint32_t ofm_N;
118   uint32_t ofm_C;
119   uint32_t ofm_H;
120   uint32_t ofm_W;
121
122   uint32_t ker_N;
123   uint32_t ker_C;
124   uint32_t ker_H;
125   uint32_t ker_W;
126
127   uint32_t vertical_stride;
128   uint32_t horizontal_stride;
129
130   std::string padding;
131   std::string fused_act;
132
133   uint32_t top_padding;
134   uint32_t bottom_padding;
135   uint32_t left_padding;
136   uint32_t right_padding;
137
138   Configuration(nonius::chronometer meter)
139   {
140     ifm_N = meter.param<BATCH>();
141     ifm_C = meter.param<IFM_C>();
142     ifm_H = meter.param<IFM_H>();
143     ifm_W = meter.param<IFM_W>();
144
145     ofm_N = meter.param<BATCH>();
146     ofm_C = meter.param<OFM_C>();
147     ofm_H = meter.param<OFM_H>();
148     ofm_W = meter.param<OFM_W>();
149
150     ker_N = meter.param<OFM_C>();
151     ker_C = meter.param<IFM_C>();
152     ker_H = meter.param<KER_H>();
153     ker_W = meter.param<KER_W>();
154
155     vertical_stride = meter.param<STRIDE_H>();
156     horizontal_stride = meter.param<STRIDE_W>();
157
158     padding = meter.param<PADDING>();
159     fused_act = meter.param<FUSED_ACT>();
160
161     assert((ifm_H - ker_H) % vertical_stride == 0);
162     assert((ifm_W - ker_H) % horizontal_stride == 0);
163
164     uint32_t const effective_ofm_H = (ifm_H - ker_H) / vertical_stride + 1;
165     uint32_t const effective_ofm_W = (ifm_W - ker_H) / horizontal_stride + 1;
166
167     assert(ofm_H >= effective_ofm_H);
168     assert(ofm_W >= effective_ofm_W);
169
170     uint32_t const pad_H = ofm_H - effective_ofm_H;
171     uint32_t const pad_W = ofm_W - effective_ofm_W;
172
173     top_padding = pad_H / 2;
174     bottom_padding = pad_H / 2;
175     left_padding = pad_W / 2;
176     right_padding = pad_W / 2;
177
178     if (is_odd(pad_H))
179       top_padding += 1;
180     if (is_odd(pad_W))
181       left_padding += 1;
182   }
183
184   template <Layout L> TensorInfo src_info() const
185   {
186     return make_info<L>(ifm_N, ifm_C, ifm_H, ifm_W);
187   }
188   template <Layout L> TensorInfo dst_info() const
189   {
190     return make_info<L>(ofm_N, ofm_C, ofm_H, ofm_W);
191   }
192   template <Layout L> TensorInfo ker_info() const
193   {
194     return make_info<L>(ker_N, ker_C, ker_H, ker_W);
195   }
196   TensorInfo bias_info(void) const { return make_info(ker_N); }
197
198   PadStrideInfo pad_stride_info(void) const
199   {
200     return PadStrideInfo{horizontal_stride,
201                          vertical_stride,
202                          left_padding,
203                          right_padding,
204                          top_padding,
205                          bottom_padding,
206                          DimensionRoundingType::FLOOR};
207   }
208 };
209
210 } // namespace
211
212 //
213 // Benchmark Implementations
214 //
215 namespace
216 {
217
218 inline nonius::benchmark_registry &local_benchmark_registry()
219 {
220   static nonius::benchmark_registry registry;
221   return registry;
222 }
223
224 } // namespace
225
226 #define NONIUS_LOCAL_BENCHMARK(name, ...)                                              \
227   namespace                                                                            \
228   {                                                                                    \
229   static ::nonius::benchmark_registrar                                                 \
230       NONIUS_DETAIL_UNIQUE_NAME(benchmark_registrar)(local_benchmark_registry(), name, \
231                                                      __VA_ARGS__);                     \
232   }
233
234 NONIUS_LOCAL_BENCHMARK("NEDirectConvolutionLayer_NCHW", [](nonius::chronometer meter) {
235   NEDirectConvolutionLayer conv;
236
237   // Configure
238   Configuration p{meter};
239
240   Tensor src_tensor{};
241   Tensor dst_tensor{};
242   Tensor ker_tensor{};
243   Tensor bias_tensor{};
244
245   src_tensor.allocator()->init(p.src_info<NCHW>());
246   dst_tensor.allocator()->init(p.dst_info<NCHW>());
247   ker_tensor.allocator()->init(p.ker_info<NCHW>());
248   bias_tensor.allocator()->init(p.bias_info());
249
250   try
251   {
252     check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
253                         p.pad_stride_info()));
254   }
255   catch (...)
256   {
257     meter.measure([&](int) {
258       // DO NOTHING
259       volatile int x = 0;
260       return x;
261     });
262     return;
263   }
264
265   conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
266
267   src_tensor.allocator()->allocate();
268   ker_tensor.allocator()->allocate();
269   bias_tensor.allocator()->allocate();
270   dst_tensor.allocator()->allocate();
271
272   // Run!
273   meter.measure([&](int) { conv.run(); });
274 })
275
276 NONIUS_LOCAL_BENCHMARK("NEDirectConvolutionLayer_NHWC", [](nonius::chronometer meter) {
277   NEDirectConvolutionLayer conv;
278
279   // Configure
280   Configuration p{meter};
281
282   Tensor src_tensor{};
283   Tensor dst_tensor{};
284   Tensor ker_tensor{};
285   Tensor bias_tensor{};
286
287   src_tensor.allocator()->init(p.src_info<NHWC>());
288   dst_tensor.allocator()->init(p.dst_info<NHWC>());
289   ker_tensor.allocator()->init(p.ker_info<NHWC>());
290   bias_tensor.allocator()->init(p.bias_info());
291
292   try
293   {
294     check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
295                         p.pad_stride_info()));
296   }
297   catch (...)
298   {
299     meter.measure([&](int) {
300       // DO NOTHING
301       volatile int x = 0;
302       return x;
303     });
304     return;
305   }
306
307   conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
308
309   src_tensor.allocator()->allocate();
310   ker_tensor.allocator()->allocate();
311   bias_tensor.allocator()->allocate();
312   dst_tensor.allocator()->allocate();
313
314   // Run!
315   meter.measure([&](int) { conv.run(); });
316 })
317
318 NONIUS_LOCAL_BENCHMARK("NEGEMMConvolutionLayer_NCHW", [](nonius::chronometer meter) {
319   NEGEMMConvolutionLayer conv;
320
321   // Configure
322   Configuration p{meter};
323
324   Tensor src_tensor{};
325   Tensor dst_tensor{};
326   Tensor ker_tensor{};
327   Tensor bias_tensor{};
328
329   src_tensor.allocator()->init(p.src_info<NCHW>());
330   dst_tensor.allocator()->init(p.dst_info<NCHW>());
331   ker_tensor.allocator()->init(p.ker_info<NCHW>());
332   bias_tensor.allocator()->init(p.bias_info());
333
334   try
335   {
336     check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
337                         p.pad_stride_info()));
338   }
339   catch (...)
340   {
341     meter.measure([&](int) {
342       // DO NOTHING
343       volatile int x = 0;
344       return x;
345     });
346     return;
347   }
348
349   conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
350
351   src_tensor.allocator()->allocate();
352   ker_tensor.allocator()->allocate();
353   bias_tensor.allocator()->allocate();
354   dst_tensor.allocator()->allocate();
355
356   // Run
357   meter.measure([&](int) { conv.run(); });
358 })
359
360 NONIUS_LOCAL_BENCHMARK("NEGEMMConvolutionLayer_NHWC", [](nonius::chronometer meter) {
361   NEGEMMConvolutionLayer conv;
362
363   // Configure
364   Configuration p{meter};
365
366   Tensor src_tensor{};
367   Tensor dst_tensor{};
368   Tensor ker_tensor{};
369   Tensor bias_tensor{};
370
371   src_tensor.allocator()->init(p.src_info<NHWC>());
372   dst_tensor.allocator()->init(p.dst_info<NHWC>());
373   ker_tensor.allocator()->init(p.ker_info<NHWC>());
374   bias_tensor.allocator()->init(p.bias_info());
375
376   try
377   {
378     check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
379                         p.pad_stride_info()));
380   }
381   catch (...)
382   {
383     meter.measure([&](int) {
384       // DO NOTHING
385       volatile int x = 0;
386       return x;
387     });
388     return;
389   }
390
391   conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
392
393   src_tensor.allocator()->allocate();
394   ker_tensor.allocator()->allocate();
395   bias_tensor.allocator()->allocate();
396   dst_tensor.allocator()->allocate();
397
398   // Run
399   meter.measure([&](int) { conv.run(); });
400 })
401
402 NONIUS_LOCAL_BENCHMARK("NEWinogradConvolutionLayer_NCHW", [](nonius::chronometer meter) {
403   NEWinogradConvolutionLayer conv;
404
405   // Configure
406   Configuration p{meter};
407
408   Tensor src_tensor{};
409   Tensor dst_tensor{};
410   Tensor ker_tensor{};
411   Tensor bias_tensor{};
412
413   src_tensor.allocator()->init(p.src_info<NCHW>());
414   dst_tensor.allocator()->init(p.dst_info<NCHW>());
415   ker_tensor.allocator()->init(p.ker_info<NCHW>());
416   bias_tensor.allocator()->init(p.bias_info());
417
418   try
419   {
420     check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
421                         p.pad_stride_info()));
422   }
423   catch (...)
424   {
425     meter.measure([&](int) {
426       // DO NOTHING
427       volatile int x = 0;
428       return x;
429     });
430     return;
431   }
432
433   conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
434
435   src_tensor.allocator()->allocate();
436   ker_tensor.allocator()->allocate();
437   bias_tensor.allocator()->allocate();
438   dst_tensor.allocator()->allocate();
439
440   // Run
441   meter.measure([&](int) { conv.run(); });
442 })
443
444 NONIUS_LOCAL_BENCHMARK("NEWinogradConvolutionLayer_NHWC", [](nonius::chronometer meter) {
445   NEWinogradConvolutionLayer conv;
446
447   // Configure
448   Configuration p{meter};
449
450   Tensor src_tensor{};
451   Tensor dst_tensor{};
452   Tensor ker_tensor{};
453   Tensor bias_tensor{};
454
455   src_tensor.allocator()->init(p.src_info<NHWC>());
456   dst_tensor.allocator()->init(p.dst_info<NHWC>());
457   ker_tensor.allocator()->init(p.ker_info<NHWC>());
458   bias_tensor.allocator()->init(p.bias_info());
459
460   try
461   {
462     check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
463                         p.pad_stride_info()));
464   }
465   catch (...)
466   {
467     meter.measure([&](int) {
468       // DO NOTHING
469       volatile int x = 0;
470       return x;
471     });
472     return;
473   }
474
475   conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
476
477   src_tensor.allocator()->allocate();
478   ker_tensor.allocator()->allocate();
479   bias_tensor.allocator()->allocate();
480   dst_tensor.allocator()->allocate();
481
482   // Run
483   meter.measure([&](int) { conv.run(); });
484 })
485
486 extern "C" nonius::benchmark_registry &benchmark_functions(void)
487 {
488   return local_benchmark_registry();
489 }