Expression Templates Library (ETL)
avg_pooling.hpp
1 //=======================================================================
2 // Copyright (c) 2014-2023 Baptiste Wicht
3 // Distributed under the terms of the MIT License.
4 // (See accompanying file LICENSE or copy at
5 // http://opensource.org/licenses/MIT)
6 //=======================================================================
7 
8 #pragma once
9 
10 #include "etl/concepts.hpp"
11 namespace etl::impl::standard {
12 
16 struct avg_pool_2d {
29  template <typename A>
30  static auto pool_block_border(const A& sub, size_t j, size_t k, size_t c1, size_t c2, size_t s1, size_t s2, size_t p1, size_t p2) {
31  auto avg = value_t<A>(0);
32 
33  const auto s_j = j * s1;
34  const auto s_k = k * s2;
35 
36  for (size_t jj = 0; jj < c1; ++jj) {
37  for (size_t kk = 0; kk < c2; ++kk) {
38  if (s_j + jj >= p1 && (s_j + jj) - p1 < etl::dim<0>(sub) && s_k + kk >= p2 && (s_k + kk) - p2 < etl::dim<1>(sub)) {
39  avg += sub(s_j + jj - p1, s_k + kk - p2);
40  }
41  }
42  }
43 
44  return avg / static_cast<value_t<A>>(c1 * c2);
45  }
46 
55  template <size_t C1, size_t C2, size_t S1, size_t S2, size_t P1, size_t P2, typename A>
56  static auto pool_block_2d(const A& sub, size_t j, size_t k) {
57  const auto s_j = j * S1 - P1;
58  const auto s_k = k * S2 - P2;
59 
60  value_t<A> avg = 0;
61 
62  for (size_t jj = 0; jj < C1; ++jj) {
63  for (size_t kk = 0; kk < C2; ++kk) {
64  avg += sub(s_j + jj, s_k + kk);
65  }
66  }
67 
68  return avg / static_cast<value_t<A>>(C1 * C2);
69  }
70 
79  template <size_t C1, size_t C2, size_t S1, size_t S2, typename A>
80  static auto pool_block_3d(const A& sub, size_t n, size_t j, size_t k) {
81  const auto s_j = j * S1;
82  const auto s_k = k * S2;
83 
84  value_t<A> avg = 0;
85 
86  for (size_t jj = 0; jj < C1; ++jj) {
87  for (size_t kk = 0; kk < C2; ++kk) {
88  avg += sub(n, s_j + jj, s_k + kk);
89  }
90  }
91 
92  return avg / static_cast<value_t<A>>(C1 * C2);
93  }
94 
103  template <size_t C1, size_t C2, size_t S1, size_t S2, typename A>
104  static auto pool_block_4d(const A& sub, size_t m, size_t n, size_t j, size_t k) {
105  const auto s_j = j * S1;
106  const auto s_k = k * S2;
107 
108  value_t<A> avg = 0;
109 
110  for (size_t jj = 0; jj < C1; ++jj) {
111  for (size_t kk = 0; kk < C2; ++kk) {
112  avg += sub(m, n, s_j + jj, s_k + kk);
113  }
114  }
115 
116  return avg / static_cast<value_t<A>>(C1 * C2);
117  }
118 
126  template <size_t C1, size_t C2, size_t S1, size_t S2, size_t P1, size_t P2, etl_2d A, typename M>
127  static void apply(const A& sub, M&& m) {
128  const size_t o1 = (etl::dim<0>(sub) - C1 + 2 * P1) / S1 + 1;
129  const size_t o2 = (etl::dim<1>(sub) - C2 + 2 * P2) / S2 + 1;
130 
131  if (P1 || P2) {
132  for (size_t i = 0; i < P1; ++i) {
133  for (size_t j = 0; j < o2; ++j) {
134  m(i, j) = pool_block_border(sub, i, j, C1, C2, S1, S2, P1, P2);
135  }
136  }
137 
138  for (size_t i = o1 - P1; i < o1; ++i) {
139  for (size_t j = 0; j < o2; ++j) {
140  m(i, j) = pool_block_border(sub, i, j, C1, C2, S1, S2, P1, P2);
141  }
142  }
143 
144  for (size_t j = 0; j < P2; ++j) {
145  for (size_t i = P1; i < o1 - P1; ++i) {
146  m(i, j) = pool_block_border(sub, i, j, C1, C2, S1, S2, P1, P2);
147  }
148  }
149 
150  for (size_t j = o2 - P2; j < o2; ++j) {
151  for (size_t i = P1; i < o1 - P1; ++i) {
152  m(i, j) = pool_block_border(sub, i, j, C1, C2, S1, S2, P1, P2);
153  }
154  }
155  }
156 
157  for (size_t j = P1; j < o1 - P1; ++j) {
158  for (size_t k = P1; k < o2 - P2; ++k) {
159  m(j, k) = pool_block_2d<C1, C2, S1, S2, P1, P2>(sub, j, k);
160  }
161  }
162  }
163 
172  template <typename A>
173  static auto pool_block_2d(const A& sub, size_t j, size_t k, size_t c1, size_t c2, size_t s1, size_t s2, size_t p1, size_t p2) {
174  const auto s_j = j * s1 - p1;
175  const auto s_k = k * s2 - p2;
176 
177  value_t<A> avg = 0;
178 
179  for (size_t jj = 0; jj < c1; ++jj) {
180  for (size_t kk = 0; kk < c2; ++kk) {
181  avg += sub(s_j + jj, s_k + kk);
182  }
183  }
184 
185  return avg / static_cast<value_t<A>>(c1 * c2);
186  }
187 
196  template <typename A>
197  static auto pool_block_3d(const A& sub, size_t n, size_t j, size_t k, size_t c1, size_t c2, size_t s1, size_t s2) {
198  const auto s_j = j * s1;
199  const auto s_k = k * s2;
200 
201  value_t<A> avg = 0;
202 
203  for (size_t jj = 0; jj < c1; ++jj) {
204  for (size_t kk = 0; kk < c2; ++kk) {
205  avg += sub(n, s_j + jj, s_k + kk);
206  }
207  }
208 
209  return avg / static_cast<value_t<A>>(c1 * c2);
210  }
211 
220  template <typename A>
221  static auto pool_block_4d(const A& sub, size_t m, size_t n, size_t j, size_t k, size_t c1, size_t c2, size_t s1, size_t s2) {
222  const auto s_j = j * s1;
223  const auto s_k = k * s2;
224 
225  value_t<A> avg = 0;
226 
227  for (size_t jj = 0; jj < c1; ++jj) {
228  for (size_t kk = 0; kk < c2; ++kk) {
229  avg += sub(m, n, s_j + jj, s_k + kk);
230  }
231  }
232 
233  return avg / static_cast<value_t<A>>(c1 * c2);
234  }
235 
243  template <etl_2d A, typename M>
244  static void apply(const A& sub, M&& m, size_t c1, size_t c2, size_t s1, size_t s2, size_t p1, size_t p2) {
245  const size_t o1 = (etl::dim<0>(sub) - c1 + 2 * p1) / s1 + 1;
246  const size_t o2 = (etl::dim<1>(sub) - c2 + 2 * p2) / s2 + 1;
247 
248  if (p1 || p2) {
249  for (size_t i = 0; i < p1; ++i) {
250  for (size_t j = 0; j < o2; ++j) {
251  m(i, j) = pool_block_border(sub, i, j, c1, c2, s1, s2, p1, p2);
252  }
253  }
254 
255  for (size_t i = o1 - p1; i < o1; ++i) {
256  for (size_t j = 0; j < o2; ++j) {
257  m(i, j) = pool_block_border(sub, i, j, c1, c2, s1, s2, p1, p2);
258  }
259  }
260 
261  for (size_t j = 0; j < p2; ++j) {
262  for (size_t i = p1; i < o1 - p1; ++i) {
263  m(i, j) = pool_block_border(sub, i, j, c1, c2, s1, s2, p1, p2);
264  }
265  }
266 
267  for (size_t j = o2 - p2; j < o2; ++j) {
268  for (size_t i = p1; i < o1 - p1; ++i) {
269  m(i, j) = pool_block_border(sub, i, j, c1, c2, s1, s2, p1, p2);
270  }
271  }
272  }
273 
274  for (size_t j = p1; j < o1 - p1; ++j) {
275  for (size_t k = p2; k < o2 - p2; ++k) {
276  m(j, k) = pool_block_2d(sub, j, k, c1, c2, s1, s2, p1, p2);
277  }
278  }
279  }
280 
281  /*
282  * 3D handling
283  *
284  * This is especially optimized because this is the most common
285  * case in machine learning. Moreover, this is also easy to
286  * parallelize and optimize
287  */
288 
296  template <size_t C1, size_t C2, size_t S1, size_t S2, size_t P1, size_t P2, etl_3d A, typename M>
297  static void apply(const A& sub, M&& m) {
298  auto batch_fun_n = [&](const size_t first, const size_t last) {
299  if (last - first) {
300  if (cpp_likely(!P1 && !P2)) {
301  for (size_t n = first; n < last; ++n) {
302  for (size_t j = 0; j < etl::dim<1>(m); ++j) {
303  for (size_t k = 0; k < etl::dim<2>(m); ++k) {
304  m(n, j, k) = pool_block_3d<C1, C2, S1, S2>(sub, n, j, k);
305  }
306  }
307  }
308  } else {
309  // In the general case, we use the regular algorithm
310  for (size_t n = first; n < last; ++n) {
311  apply<C1, C2, S1, S2, P1, P2>(sub(n), m(n));
312  }
313  }
314  }
315  };
316 
317  const size_t N = etl::dim<0>(m);
318 
319  engine_dispatch_1d_serial(batch_fun_n, 0, N, 2UL);
320  }
321 
329  template <etl_3d A, typename M>
330  static void apply(const A& sub, M&& m, size_t c1, size_t c2, size_t s1, size_t s2, size_t p1, size_t p2) {
331  auto batch_fun_n = [&](const size_t first, const size_t last) {
332  if (last - first) {
333  if (cpp_likely(!p1 && !p2)) {
334  for (size_t n = first; n < last; ++n) {
335  for (size_t j = 0; j < etl::dim<1>(m); ++j) {
336  for (size_t k = 0; k < etl::dim<2>(m); ++k) {
337  m(n, j, k) = pool_block_3d(sub, n, j, k, c1, c2, s1, s2);
338  }
339  }
340  }
341  } else {
342  for (size_t n = first; n < last; ++n) {
343  apply(sub(n), m(n), c1, c2, s1, s2, p1, p2);
344  }
345  }
346  }
347  };
348 
349  const size_t N = etl::dim<0>(m);
350 
351  engine_dispatch_1d_serial(batch_fun_n, 0, N, 2UL);
352  }
353 
354  /*
355  * 4D handling
356  *
357  * This is especially optimized because this is the most common
358  * case in machine learning. Moreover, this is also easy to
359  * parallelize and optimize
360  */
361 
369  template <size_t C1, size_t C2, size_t S1, size_t S2, size_t P1, size_t P2, etl_4d A, typename M>
370  static void apply(const A& sub, M&& m) {
371  auto batch_fun_n = [&](const size_t first, const size_t last) {
372  if (last - first) {
373  if (cpp_likely(!P1 && !P2)) {
374  for (size_t mm = first; mm < last; ++mm) {
375  for (size_t n = 0; n < etl::dim<1>(m); ++n) {
376  for (size_t j = 0; j < etl::dim<2>(m); ++j) {
377  for (size_t k = 0; k < etl::dim<3>(m); ++k) {
378  m(mm, n, j, k) = pool_block_4d<C1, C2, S1, S2>(sub, mm, n, j, k);
379  }
380  }
381  }
382  }
383  } else {
384  for (size_t mm = first; mm < last; ++mm) {
385  for (size_t n = 0; n < etl::dim<1>(m); ++n) {
386  apply<C1, C2, S1, S2, P1, P2>(sub(mm)(n), m(mm)(n));
387  }
388  }
389  }
390  }
391  };
392 
393  const size_t N = etl::dim<0>(m);
394 
395  engine_dispatch_1d_serial(batch_fun_n, 0, N, 2UL);
396  }
397 
405  template <etl_4d A, typename M>
406  static void apply(const A& sub, M&& m, size_t c1, size_t c2, size_t s1, size_t s2, size_t p1, size_t p2) {
407  auto batch_fun_n = [&](const size_t first, const size_t last) {
408  if (last - first) {
409  if (cpp_likely(!p1 && !p2)) {
410  for (size_t mm = first; mm < last; ++mm) {
411  for (size_t n = 0; n < etl::dim<1>(m); ++n) {
412  for (size_t j = 0; j < etl::dim<2>(m); ++j) {
413  for (size_t k = 0; k < etl::dim<3>(m); ++k) {
414  m(mm, n, j, k) = pool_block_4d(sub, mm, n, j, k, c1, c2, s1, s2);
415  }
416  }
417  }
418  }
419  } else {
420  for (size_t mm = first; mm < last; ++mm) {
421  for (size_t n = 0; n < etl::dim<1>(m); ++n) {
422  apply(sub(mm)(n), m(mm)(n), c1, c2, s1, s2, p1, p2);
423  }
424  }
425  }
426  }
427  };
428 
429  const size_t N = etl::dim<0>(m);
430 
431  engine_dispatch_1d_serial(batch_fun_n, 0, N, 2UL);
432  }
433 
434  // Deep handling
435 
445  template <size_t C1, size_t C2, size_t S1, size_t S2, size_t P1, size_t P2, etl_5d_and_plus A, typename M>
446  static void apply(const A& sub, M&& m) {
447  for (size_t i = 0; i < etl::dim<0>(sub); ++i) {
448  apply<C1, C2, S1, S2, P1, P2>(sub(i), m(i));
449  }
450  }
451 
459  template <etl_5d_and_plus A, typename M>
460  static void apply(const A& sub, M&& m, size_t c1, size_t c2, size_t s1, size_t s2, size_t p1, size_t p2) {
461  for (size_t i = 0; i < etl::dim<0>(sub); ++i) {
462  apply(sub(i), m(i), c1, c2, s1, s2, p1, p2);
463  }
464  }
465 };
466 
470 struct avg_pool_3d {
487  template <typename A>
488  static auto pool_block_border(
489  const A& sub, size_t i, size_t j, size_t k, size_t c1, size_t c2, size_t c3, size_t s1, size_t s2, size_t s3, size_t p1, size_t p2, size_t p3) {
490  auto avg = value_t<A>(0);
491 
492  const auto s_i = i * s1;
493  const auto s_j = j * s2;
494  const auto s_k = k * s3;
495 
496  for (size_t ii = 0; ii < c1; ++ii) {
497  for (size_t jj = 0; jj < c2; ++jj) {
498  for (size_t kk = 0; kk < c3; ++kk) {
499  if (s_i + ii >= p1 && (s_i + ii) - p1 < etl::dim<0>(sub) && s_j + jj >= p2 && (s_j + jj) - p2 < etl::dim<1>(sub) && s_k + kk >= p3
500  && (s_k + kk) - p3 < etl::dim<2>(sub)) {
501  avg += sub(s_i + ii - p1, s_j + jj - p2, s_k + kk - p3);
502  }
503  }
504  }
505  }
506 
507  return avg / static_cast<value_t<A>>(c1 * c2 * c3);
508  }
509 
520  template <size_t C1, size_t C2, size_t C3, size_t S1, size_t S2, size_t S3, size_t P1, size_t P2, size_t P3, typename A>
521  static auto pool_block_3d(const A& sub, size_t i, size_t j, size_t k) {
522  const auto s_i = i * S1 - P1;
523  const auto s_j = j * S2 - P2;
524  const auto s_k = k * S3 - P3;
525 
526  value_t<A> avg = 0;
527 
528  for (size_t ii = 0; ii < C1; ++ii) {
529  for (size_t jj = 0; jj < C2; ++jj) {
530  for (size_t kk = 0; kk < C3; ++kk) {
531  avg += sub(s_i + ii, s_j + jj, s_k + kk);
532  }
533  }
534  }
535 
536  return avg / static_cast<value_t<A>>(C1 * C2 * C3);
537  }
538 
549  template <size_t C1, size_t C2, size_t C3, size_t S1, size_t S2, size_t S3, typename A>
550  static auto pool_block_4d(const A& sub, size_t n, size_t i, size_t j, size_t k) {
551  const auto s_i = i * S1;
552  const auto s_j = j * S2;
553  const auto s_k = k * S3;
554 
555  value_t<A> avg = 0;
556 
557  for (size_t ii = 0; ii < C1; ++ii) {
558  for (size_t jj = 0; jj < C2; ++jj) {
559  for (size_t kk = 0; kk < C3; ++kk) {
560  avg += sub(n, s_i + ii, s_j + jj, s_k + kk);
561  }
562  }
563  }
564 
565  return avg / static_cast<value_t<A>>(C1 * C2 * C3);
566  }
567 
576  template <size_t C1,
577  size_t C2,
578  size_t C3,
579  size_t S1,
580  size_t S2,
581  size_t S3,
582  size_t P1,
583  size_t P2,
584  size_t P3,
585  etl_3d A,
586  typename M>
587  static void apply(const A& sub, M&& m) {
588  const size_t o1 = (etl::dim<0>(sub) - C1 + 2 * P1) / S1 + 1;
589  const size_t o2 = (etl::dim<1>(sub) - C2 + 2 * P2) / S2 + 1;
590  const size_t o3 = (etl::dim<2>(sub) - C3 + 2 * P3) / S3 + 1;
591 
592  if (P1 || P2 || P3) {
593  for (size_t i = 0; i < P1; ++i) {
594  for (size_t j = 0; j < o2; ++j) {
595  for (size_t k = 0; k < o3; ++k) {
596  m(i, j, k) = pool_block_border(sub, i, j, k, C1, C2, C3, S1, S2, S3, P1, P2, P3);
597  }
598  }
599  }
600 
601  for (size_t i = o1 - P1; i < o1; ++i) {
602  for (size_t j = 0; j < o2; ++j) {
603  for (size_t k = 0; k < o3; ++k) {
604  m(i, j, k) = pool_block_border(sub, i, j, k, C1, C2, C3, S1, S2, S3, P1, P2, P3);
605  }
606  }
607  }
608 
609  for (size_t j = 0; j < P2; ++j) {
610  for (size_t i = P1; i < o1 - P1; ++i) {
611  for (size_t k = 0; k < o3; ++k) {
612  m(i, j, k) = pool_block_border(sub, i, j, k, C1, C2, C3, S1, S2, S3, P1, P2, P3);
613  }
614  }
615  }
616 
617  for (size_t j = o2 - P2; j < o2; ++j) {
618  for (size_t i = P1; i < o1 - P1; ++i) {
619  for (size_t k = 0; k < o3; ++k) {
620  m(i, j, k) = pool_block_border(sub, i, j, k, C1, C2, C3, S1, S2, S3, P1, P2, P3);
621  }
622  }
623  }
624 
625  for (size_t k = 0; k < P3; ++k) {
626  for (size_t i = P1; i < o1 - P1; ++i) {
627  for (size_t j = P2; j < o2 - P2; ++j) {
628  m(i, j, k) = pool_block_border(sub, i, j, k, C1, C2, C3, S1, S2, S3, P1, P2, P3);
629  }
630  }
631  }
632 
633  for (size_t k = o3 - P3; k < o3; ++k) {
634  for (size_t i = P1; i < o1 - P1; ++i) {
635  for (size_t j = P2; j < o2 - P2; ++j) {
636  m(i, j, k) = pool_block_border(sub, i, j, k, C1, C2, C3, S1, S2, S3, P1, P2, P3);
637  }
638  }
639  }
640  }
641 
642  for (size_t i = P1; i < o1 - P1; ++i) {
643  for (size_t j = P2; j < o2 - P2; ++j) {
644  for (size_t k = P3; k < o3 - P3; ++k) {
645  m(i, j, k) = pool_block_3d<C1, C2, C3, S1, S2, S3, P1, P2, P3>(sub, i, j, k);
646  }
647  }
648  }
649  }
650 
661  template <typename A>
662  static auto pool_block_3d(
663  const A& sub, size_t i, size_t j, size_t k, size_t c1, size_t c2, size_t c3, size_t s1, size_t s2, size_t s3, size_t p1, size_t p2, size_t p3) {
664  const auto s_i = i * s1 - p1;
665  const auto s_j = j * s2 - p2;
666  const auto s_k = k * s3 - p3;
667 
668  value_t<A> avg = 0;
669 
670  for (size_t ii = 0; ii < c1; ++ii) {
671  for (size_t jj = 0; jj < c2; ++jj) {
672  for (size_t kk = 0; kk < c3; ++kk) {
673  avg += sub(s_i + ii, s_j + jj, s_k + kk);
674  }
675  }
676  }
677 
678  return avg / static_cast<value_t<A>>(c1 * c2 * c3);
679  }
680 
691  template <typename A>
692  static auto pool_block_4d(const A& sub, size_t n, size_t i, size_t j, size_t k, size_t c1, size_t c2, size_t c3, size_t s1, size_t s2, size_t s3) {
693  const auto s_i = i * s1;
694  const auto s_j = j * s2;
695  const auto s_k = k * s3;
696 
697  value_t<A> avg = 0;
698 
699  for (size_t ii = 0; ii < c1; ++ii) {
700  for (size_t jj = 0; jj < c2; ++jj) {
701  for (size_t kk = 0; kk < c3; ++kk) {
702  avg += sub(n, s_i + ii, s_j + jj, s_k + kk);
703  }
704  }
705  }
706 
707  return avg / static_cast<value_t<A>>(c1 * c2 * c3);
708  }
709 
718  template <etl_3d A, typename M>
719  static void apply(const A& sub, M&& m, size_t c1, size_t c2, size_t c3, size_t s1, size_t s2, size_t s3, size_t p1, size_t p2, size_t p3) {
720  const size_t o1 = (etl::dim<0>(sub) - c1 + 2 * p1) / s1 + 1;
721  const size_t o2 = (etl::dim<1>(sub) - c2 + 2 * p2) / s2 + 1;
722  const size_t o3 = (etl::dim<2>(sub) - c3 + 2 * p3) / s3 + 1;
723 
724  if (p1 || p2 || p3) {
725  for (size_t i = 0; i < p1; ++i) {
726  for (size_t j = 0; j < o2; ++j) {
727  for (size_t k = 0; k < o3; ++k) {
728  m(i, j, k) = pool_block_border(sub, i, j, k, c1, c2, c3, s1, s2, s3, p1, p2, p3);
729  }
730  }
731  }
732 
733  for (size_t i = o1 - p1; i < o1; ++i) {
734  for (size_t j = 0; j < o2; ++j) {
735  for (size_t k = 0; k < o3; ++k) {
736  m(i, j, k) = pool_block_border(sub, i, j, k, c1, c2, c3, s1, s2, s3, p1, p2, p3);
737  }
738  }
739  }
740 
741  for (size_t j = 0; j < p2; ++j) {
742  for (size_t i = p1; i < o1 - p1; ++i) {
743  for (size_t k = 0; k < o3; ++k) {
744  m(i, j, k) = pool_block_border(sub, i, j, k, c1, c2, c3, s1, s2, s3, p1, p2, p3);
745  }
746  }
747  }
748 
749  for (size_t j = o2 - p2; j < o2; ++j) {
750  for (size_t i = p1; i < o1 - p1; ++i) {
751  for (size_t k = 0; k < o3; ++k) {
752  m(i, j, k) = pool_block_border(sub, i, j, k, c1, c2, c3, s1, s2, s3, p1, p2, p3);
753  }
754  }
755  }
756 
757  for (size_t k = 0; k < p3; ++k) {
758  for (size_t i = p1; i < o1 - p1; ++i) {
759  for (size_t j = p2; j < o2 - p2; ++j) {
760  m(i, j, k) = pool_block_border(sub, i, j, k, c1, c2, c3, s1, s2, s3, p1, p2, p3);
761  }
762  }
763  }
764 
765  for (size_t k = o3 - p3; k < o3; ++k) {
766  for (size_t i = p1; i < o1 - p1; ++i) {
767  for (size_t j = p2; j < o2 - p2; ++j) {
768  m(i, j, k) = pool_block_border(sub, i, j, k, c1, c2, c3, s1, s2, s3, p1, p2, p3);
769  }
770  }
771  }
772  }
773 
774  for (size_t i = p1; i < o1 - p1; ++i) {
775  for (size_t j = p2; j < o2 - p2; ++j) {
776  for (size_t k = p3; k < o3 - p3; ++k) {
777  m(i, j, k) = pool_block_3d(sub, i, j, k, c1, c2, c3, s1, s2, s3, p1, p2, p3);
778  }
779  }
780  }
781  }
782 
783  /*
784  * 4D handling
785  *
786  * This is especially optimized because this is the most common
787  * case in machine learning. Moreover, this is also easy to
788  * parallelize and optimize
789  */
790 
799  template <size_t C1,
800  size_t C2,
801  size_t C3,
802  size_t S1,
803  size_t S2,
804  size_t S3,
805  size_t P1,
806  size_t P2,
807  size_t P3,
808  etl_4d A,
809  typename M>
810  static void apply(const A& sub, M&& m) {
811  auto batch_fun_n = [&](const size_t first, const size_t last) {
812  if (last - first) {
813  if (cpp_likely(!P1 && !P2 && !P3)) {
814  for (size_t n = first; n < last; ++n) {
815  for (size_t i = 0; i < etl::dim<1>(m); ++i) {
816  for (size_t j = 0; j < etl::dim<2>(m); ++j) {
817  for (size_t k = 0; k < etl::dim<3>(m); ++k) {
818  m(n, i, j, k) = pool_block_4d<C1, C2, C3, S1, S2, S3>(sub, n, i, j, k);
819  }
820  }
821  }
822  }
823  } else {
824  // In the general case, we use the regular algorithm
825  for (size_t n = first; n < last; ++n) {
826  apply<C1, C2, C3, S1, S2, S3, P1, P2, P3>(sub(n), m(n));
827  }
828  }
829  }
830  };
831 
832  const size_t N = etl::dim<0>(m);
833 
834  engine_dispatch_1d_serial(batch_fun_n, 0, N, 2UL);
835  }
836 
845  template <etl_4d A, typename M>
846  static void apply(const A& sub, M&& m, size_t c1, size_t c2, size_t c3, size_t s1, size_t s2, size_t s3, size_t p1, size_t p2, size_t p3) {
847  auto batch_fun_n = [&](const size_t first, const size_t last) {
848  if (last - first) {
849  if (cpp_likely(!p1 && !p2 && !p3)) {
850  for (size_t n = first; n < last; ++n) {
851  for (size_t i = 0; i < etl::dim<1>(m); ++i) {
852  for (size_t j = 0; j < etl::dim<2>(m); ++j) {
853  for (size_t k = 0; k < etl::dim<3>(m); ++k) {
854  m(n, i, j, k) = pool_block_4d(sub, n, i, j, k, c1, c2, c3, s1, s2, s3);
855  }
856  }
857  }
858  }
859  } else {
860  for (size_t n = first; n < last; ++n) {
861  apply(sub(n), m(n), c1, c2, c3, s1, s2, s3, p1, p2, p3);
862  }
863  }
864  }
865  };
866 
867  const size_t N = etl::dim<0>(m);
868 
869  engine_dispatch_1d_serial(batch_fun_n, 0, N, 2UL);
870  }
871 
872  // Deep handling
873 
882  template <size_t C1,
883  size_t C2,
884  size_t C3,
885  size_t S1,
886  size_t S2,
887  size_t S3,
888  size_t P1,
889  size_t P2,
890  size_t P3,
891  etl_5d_and_plus A,
892  typename M>
893  static void apply(const A& sub, M&& m) {
894  for (size_t i = 0; i < etl::dim<0>(sub); ++i) {
895  apply<C1, C2, C3, S1, S2, S3, P1, P2, P3>(sub(i), m(i));
896  }
897  }
898 
907  template <etl_5d_and_plus A, typename M>
908  static void apply(const A& sub, M&& m, size_t c1, size_t c2, size_t c3, size_t s1, size_t s2, size_t s3, size_t p1, size_t p2, size_t p3) {
909  for (size_t i = 0; i < etl::dim<0>(sub); ++i) {
910  apply(sub(i), m(i), c1, c2, c3, s1, s2, s3, p1, p2, p3);
911  }
912  }
913 };
914 
915 } //end of namespace etl::impl::standard
Functor for 3D Average Pooling.
Definition: avg_pooling.hpp:470
static void apply(const A &sub, M &&m)
Apply the functor on sub and store the result in m.
Definition: avg_pooling.hpp:587
static auto pool_block_4d(const A &sub, size_t m, size_t n, size_t j, size_t k, size_t c1, size_t c2, size_t s1, size_t s2)
Pool a block of the sub expression.
Definition: avg_pooling.hpp:221
static auto pool_block_border(const A &sub, size_t i, size_t j, size_t k, size_t c1, size_t c2, size_t c3, size_t s1, size_t s2, size_t s3, size_t p1, size_t p2, size_t p3)
Pool a block of the sub expression.
Definition: avg_pooling.hpp:488
void engine_dispatch_1d_serial(Functor &&functor, size_t first, size_t last, size_t threshold, [[maybe_unused]] size_t n_threads=etl::threads)
Dispatch the elements of a range to a functor in a parallel manner, using the global thread engine...
Definition: parallel_support.hpp:734
static auto pool_block_2d(const A &sub, size_t j, size_t k)
Pool a block of the sub expression.
Definition: avg_pooling.hpp:56
static void apply(const A &sub, M &&m, size_t c1, size_t c2, size_t c3, size_t s1, size_t s2, size_t s3, size_t p1, size_t p2, size_t p3)
Apply the functor on sub and store the result in m.
Definition: avg_pooling.hpp:719
Definition: prob_pooling.hpp:10
static void apply(const A &sub, M &&m, size_t c1, size_t c2, size_t s1, size_t s2, size_t p1, size_t p2)
Apply the functor on sub and store the result in m.
Definition: avg_pooling.hpp:244
static auto pool_block_2d(const A &sub, size_t j, size_t k, size_t c1, size_t c2, size_t s1, size_t s2, size_t p1, size_t p2)
Pool a block of the sub expression.
Definition: avg_pooling.hpp:173
Functor for 2D Average Pooling.
Definition: avg_pooling.hpp:16
static auto pool_block_4d(const A &sub, size_t n, size_t i, size_t j, size_t k, size_t c1, size_t c2, size_t c3, size_t s1, size_t s2, size_t s3)
Pool a block of the sub expression.
Definition: avg_pooling.hpp:692
static auto pool_block_3d(const A &sub, size_t n, size_t j, size_t k, size_t c1, size_t c2, size_t s1, size_t s2)
Pool a block of the sub expression.
Definition: avg_pooling.hpp:197
static auto pool_block_4d(const A &sub, size_t m, size_t n, size_t j, size_t k)
Pool a block of the sub expression.
Definition: avg_pooling.hpp:104
static auto pool_block_3d(const A &sub, size_t i, size_t j, size_t k)
Pool a block of the sub expression.
Definition: avg_pooling.hpp:521
static auto pool_block_3d(const A &sub, size_t n, size_t j, size_t k)
Pool a block of the sub expression.
Definition: avg_pooling.hpp:80
static void apply(const A &sub, M &&m)
Apply the functor on sub and store the result in m.
Definition: avg_pooling.hpp:127
static auto pool_block_4d(const A &sub, size_t n, size_t i, size_t j, size_t k)
Pool a block of the sub expression.
Definition: avg_pooling.hpp:550
static auto pool_block_3d(const A &sub, size_t i, size_t j, size_t k, size_t c1, size_t c2, size_t c3, size_t s1, size_t s2, size_t s3, size_t p1, size_t p2, size_t p3)
Pool a block of the sub expression.
Definition: avg_pooling.hpp:662
static auto pool_block_border(const A &sub, size_t j, size_t k, size_t c1, size_t c2, size_t s1, size_t s2, size_t p1, size_t p2)
Pool a block of the sub expression around the border (with padding)
Definition: avg_pooling.hpp:30
typename decay_traits< E >::value_type value_t
Traits to extract the value type out of an ETL type.
Definition: tmp.hpp:81