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