2 * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @file Conv2D benchmark with various algorithms (draft version)
21 #include <nonius/nonius.h++>
23 #include <arm_compute/core/Types.h>
24 #include <arm_compute/runtime/CL/CLScheduler.h>
25 #include <arm_compute/runtime/CL/CLFunctions.h>
31 using namespace arm_compute;
47 Initializer() { CLScheduler::get().default_init(); }
50 Initializer initializer;
52 TensorInfo make_info(uint32_t N)
55 return TensorInfo{shape, 1, DataType::F32};
58 template <enum Layout> TensorInfo make_info(uint32_t N, uint32_t C, uint32_t H, uint32_t W);
60 template <> TensorInfo make_info<NCHW>(uint32_t N, uint32_t C, uint32_t H, uint32_t W)
62 TensorShape shape{W, H, C, N};
63 TensorInfo info{shape, 1, DataType::F32};
64 info.set_data_layout(DataLayout::NCHW);
68 template <> TensorInfo make_info<NHWC>(uint32_t N, uint32_t C, uint32_t H, uint32_t W)
70 TensorShape shape{C, W, H, N};
71 TensorInfo info{shape, 1, DataType::F32};
72 info.set_data_layout(DataLayout::NHWC);
76 inline void check(const Status &status)
80 std::cerr << status.error_description() << std::endl;
81 throw std::runtime_error{"ERROR"};
85 inline bool is_odd(uint32_t n) { return (n % 2 != 0) ? true : false; }
90 // Benchmark Parameters
92 NONIUS_PARAM(BATCH, 1);
94 NONIUS_PARAM(IFM_C, 3);
95 NONIUS_PARAM(IFM_H, 244);
96 NONIUS_PARAM(IFM_W, 244);
98 NONIUS_PARAM(OFM_C, 3);
99 NONIUS_PARAM(OFM_H, 244);
100 NONIUS_PARAM(OFM_W, 244);
102 NONIUS_PARAM(KER_H, 3);
103 NONIUS_PARAM(KER_W, 3);
105 NONIUS_PARAM(STRIDE_H, 1);
106 NONIUS_PARAM(STRIDE_W, 1);
108 NONIUS_PARAM(PADDING, std::string{"SAME"})
109 NONIUS_PARAM(FUSED_ACT, std::string{"RELU"})
112 // Configuration Helpers
134 uint32_t vertical_stride;
135 uint32_t horizontal_stride;
138 std::string fused_act;
140 uint32_t top_padding;
141 uint32_t bottom_padding;
142 uint32_t left_padding;
143 uint32_t right_padding;
145 Configuration(nonius::chronometer meter)
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>();
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>();
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>();
162 vertical_stride = meter.param<STRIDE_H>();
163 horizontal_stride = meter.param<STRIDE_W>();
165 padding = meter.param<PADDING>();
166 fused_act = meter.param<FUSED_ACT>();
168 assert((ifm_H - ker_H) % vertical_stride == 0);
169 assert((ifm_W - ker_H) % horizontal_stride == 0);
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;
174 assert(ofm_H >= effective_ofm_H);
175 assert(ofm_W >= effective_ofm_W);
177 uint32_t const pad_H = ofm_H - effective_ofm_H;
178 uint32_t const pad_W = ofm_W - effective_ofm_W;
180 top_padding = pad_H / 2;
181 bottom_padding = pad_H / 2;
182 left_padding = pad_W / 2;
183 right_padding = pad_W / 2;
191 template <Layout L> TensorInfo src_info() const
193 return make_info<L>(ifm_N, ifm_C, ifm_H, ifm_W);
195 template <Layout L> TensorInfo dst_info() const
197 return make_info<L>(ofm_N, ofm_C, ofm_H, ofm_W);
199 template <Layout L> TensorInfo ker_info() const
201 return make_info<L>(ker_N, ker_C, ker_H, ker_W);
203 TensorInfo bias_info(void) const { return make_info(ker_N); }
205 PadStrideInfo pad_stride_info(void) const
207 return PadStrideInfo{horizontal_stride,
213 DimensionRoundingType::FLOOR};
220 // Benchmark Implementations
225 inline nonius::benchmark_registry &local_benchmark_registry()
227 static nonius::benchmark_registry registry;
233 #define NONIUS_LOCAL_BENCHMARK(name, ...) \
236 static ::nonius::benchmark_registrar \
237 NONIUS_DETAIL_UNIQUE_NAME(benchmark_registrar)(local_benchmark_registry(), name, \
241 NONIUS_LOCAL_BENCHMARK("CLDirectConvolutionLayer_NCHW", [](nonius::chronometer meter) {
242 CLDirectConvolutionLayer conv;
245 Configuration p{meter};
247 CLTensor src_tensor{};
248 CLTensor dst_tensor{};
249 CLTensor ker_tensor{};
250 CLTensor bias_tensor{};
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());
259 check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
260 p.pad_stride_info()));
264 meter.measure([&](int) {
272 conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
274 src_tensor.allocator()->allocate();
275 ker_tensor.allocator()->allocate();
276 bias_tensor.allocator()->allocate();
277 dst_tensor.allocator()->allocate();
280 meter.measure([&](int) {
282 CLScheduler::get().sync();
286 NONIUS_LOCAL_BENCHMARK("CLDirectConvolutionLayer_NHWC", [](nonius::chronometer meter) {
287 CLDirectConvolutionLayer conv;
290 Configuration p{meter};
292 CLTensor src_tensor{};
293 CLTensor dst_tensor{};
294 CLTensor ker_tensor{};
295 CLTensor bias_tensor{};
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());
304 check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
305 p.pad_stride_info()));
309 meter.measure([&](int) {
317 conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
319 src_tensor.allocator()->allocate();
320 ker_tensor.allocator()->allocate();
321 bias_tensor.allocator()->allocate();
322 dst_tensor.allocator()->allocate();
325 meter.measure([&](int) {
327 CLScheduler::get().sync();
331 NONIUS_LOCAL_BENCHMARK("CLGEMMConvolutionLayer_NCHW", [](nonius::chronometer meter) {
332 CLGEMMConvolutionLayer conv;
335 Configuration p{meter};
337 CLTensor src_tensor{};
338 CLTensor dst_tensor{};
339 CLTensor ker_tensor{};
340 CLTensor bias_tensor{};
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());
349 check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
350 p.pad_stride_info()));
354 meter.measure([&](int) {
362 conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
364 src_tensor.allocator()->allocate();
365 ker_tensor.allocator()->allocate();
366 bias_tensor.allocator()->allocate();
367 dst_tensor.allocator()->allocate();
370 meter.measure([&](int) {
372 CLScheduler::get().sync();
376 NONIUS_LOCAL_BENCHMARK("CLGEMMConvolutionLayer_NHWC", [](nonius::chronometer meter) {
377 CLGEMMConvolutionLayer conv;
380 Configuration p{meter};
382 CLTensor src_tensor{};
383 CLTensor dst_tensor{};
384 CLTensor ker_tensor{};
385 CLTensor bias_tensor{};
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());
394 check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
395 p.pad_stride_info()));
399 meter.measure([&](int) {
407 conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
409 src_tensor.allocator()->allocate();
410 ker_tensor.allocator()->allocate();
411 bias_tensor.allocator()->allocate();
412 dst_tensor.allocator()->allocate();
415 meter.measure([&](int) {
417 CLScheduler::get().sync();
421 NONIUS_LOCAL_BENCHMARK("CLWinogradConvolutionLayer_NCHW", [](nonius::chronometer meter) {
422 CLWinogradConvolutionLayer conv;
425 Configuration p{meter};
427 CLTensor src_tensor{};
428 CLTensor dst_tensor{};
429 CLTensor ker_tensor{};
430 CLTensor bias_tensor{};
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());
439 check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
440 p.pad_stride_info()));
444 meter.measure([&](int) {
452 conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
454 src_tensor.allocator()->allocate();
455 ker_tensor.allocator()->allocate();
456 bias_tensor.allocator()->allocate();
457 dst_tensor.allocator()->allocate();
460 meter.measure([&](int) {
462 CLScheduler::get().sync();
466 NONIUS_LOCAL_BENCHMARK("CLWinogradConvolutionLayer_NHWC", [](nonius::chronometer meter) {
467 CLWinogradConvolutionLayer conv;
470 Configuration p{meter};
472 CLTensor src_tensor{};
473 CLTensor dst_tensor{};
474 CLTensor ker_tensor{};
475 CLTensor bias_tensor{};
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());
484 check(conv.validate(src_tensor.info(), ker_tensor.info(), bias_tensor.info(), dst_tensor.info(),
485 p.pad_stride_info()));
489 meter.measure([&](int) {
497 conv.configure(&src_tensor, &ker_tensor, &bias_tensor, &dst_tensor, p.pad_stride_info());
499 src_tensor.allocator()->allocate();
500 ker_tensor.allocator()->allocate();
501 bias_tensor.allocator()->allocate();
502 dst_tensor.allocator()->allocate();
505 meter.measure([&](int) {
507 CLScheduler::get().sync();
511 extern "C" nonius::benchmark_registry &benchmark_functions(void)
513 return local_benchmark_registry();