Expression Templates Library (ETL)
prob_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 namespace etl::impl::standard {
11 
22 template <typename T>
23 inline void pmp_h_kernel_2x2(etl::dyn_matrix<T, 2>& exp_sub, etl::dyn_matrix<T, 2>& base) {
24  const size_t M = etl::dim<0>(exp_sub);
25  const size_t N = etl::dim<1>(exp_sub);
26 
27  for (size_t m = 0; m < M; ++m) {
28  const auto start_mm = (m >> 1) << 1;
29 
30  for (size_t n = 0; n < N; ++n) {
31  const auto start_nn = (n >> 1) << 1;
32 
33  base(m, n) = exp_sub(start_mm + 0, start_nn + 0) + exp_sub(start_mm + 0, start_nn + 1) + exp_sub(start_mm + 1, start_nn + 0)
34  + exp_sub(start_mm + 1, start_nn + 1);
35  }
36  }
37 }
38 
46 template <size_t C1, size_t C2, typename T>
47 inline void pmp_h_kernel(etl::dyn_matrix<T, 2>& exp_sub, etl::dyn_matrix<T, 2>& base) {
48  const size_t M = etl::dim<0>(exp_sub);
49  const size_t N = etl::dim<1>(exp_sub);
50 
51  for (size_t m = 0; m < M; ++m) {
52  const auto start_mm = (m / C1) * C1;
53 
54  for (size_t n = 0; n < N; ++n) {
55  const auto start_nn = (n / C2) * C2;
56 
57  auto p = T(0);
58 
59  for (size_t mm = start_mm; mm < start_mm + C1; ++mm) {
60  for (size_t nn = start_nn; nn < start_nn + C2; ++nn) {
61  p += exp_sub(mm, nn);
62  }
63  }
64 
65  base(m, n) = p;
66  }
67  }
68 }
69 
77 template <typename T>
78 inline void pmp_h_kernel(etl::dyn_matrix<T, 2>& exp_sub, etl::dyn_matrix<T, 2>& base, size_t c1, size_t c2) {
79  const size_t M = etl::dim<0>(exp_sub);
80  const size_t N = etl::dim<1>(exp_sub);
81 
82  for (size_t m = 0; m < M; ++m) {
83  const auto start_mm = (m / c1) * c1;
84 
85  for (size_t n = 0; n < N; ++n) {
86  const auto start_nn = (n / c2) * c2;
87 
88  auto p = T(0);
89 
90  for (size_t mm = start_mm; mm < start_mm + c1; ++mm) {
91  for (size_t nn = start_nn; nn < start_nn + c2; ++nn) {
92  p += exp_sub(mm, nn);
93  }
94  }
95 
96  base(m, n) = p;
97  }
98  }
99 }
100 
104 struct pmp_h_impl {
109  template <typename A>
110  static constexpr bool gpu_computable = false;
111 
117  template <size_t C1, size_t C2, size_t S1, size_t S2, size_t P1, size_t P2, etl_2d A, typename C>
118  static void apply(A&& a, C&& c) {
119  static_assert(S1 == C1, "pmp_h does not support strides");
120  static_assert(S2 == C2, "pmp_h does not support strides");
121  static_assert(P1 == 0, "pmp_h does not support padding");
122  static_assert(P2 == 0, "pmp_h does not support padding");
123 
124  using T = value_t<A>;
125 
126  const size_t M = etl::dim<0>(a);
127  const size_t N = etl::dim<1>(a);
128 
129  etl::dyn_matrix<T, 2> exp_sub(M, N);
130  etl::dyn_matrix<T, 2> base(M, N);
131 
132  CPU_SECTION {
133  exp_sub = exp(a);
134 
135  if (C1 == 2 && C2 == 2) {
136  pmp_h_kernel_2x2(exp_sub, base);
137  } else {
138  pmp_h_kernel<C1, C2>(exp_sub, base);
139  }
140 
141  c = exp_sub / (1.0 + base);
142  }
143  }
144 
150  template <size_t C1, size_t C2, size_t S1, size_t S2, size_t P1, size_t P2, etl_3d A, typename C>
151  static void apply(A&& a, C&& c) {
152  static_assert(S1 == C1, "pmp_h does not support strides");
153  static_assert(S2 == C2, "pmp_h does not support strides");
154  static_assert(P1 == 0, "pmp_h does not support padding");
155  static_assert(P2 == 0, "pmp_h does not support padding");
156 
157  using T = value_t<A>;
158 
159  const size_t L = etl::dim<0>(a);
160  const size_t M = etl::dim<1>(a);
161  const size_t N = etl::dim<2>(a);
162 
163  etl::dyn_matrix<T, 2> exp_sub(M, N);
164  etl::dyn_matrix<T, 2> base(M, N);
165 
166  CPU_SECTION {
167  if (C1 == 2 && C2 == 2) {
168  for (size_t l = 0; l < L; ++l) {
169  exp_sub = exp(a(l));
170 
171  pmp_h_kernel_2x2(exp_sub, base);
172 
173  c(l) = exp_sub / (1.0 + base);
174  }
175  } else {
176  for (size_t l = 0; l < L; ++l) {
177  exp_sub = exp(a(l));
178 
179  pmp_h_kernel<C1, C2>(exp_sub, base);
180 
181  c(l) = exp_sub / (1.0 + base);
182  }
183  }
184  }
185  }
186 
192  template <size_t C1, size_t C2, size_t S1, size_t S2, size_t P1, size_t P2, etl_4d A, typename C>
193  static void apply(A&& a, C&& c) {
194  static_assert(S1 == C1, "pmp_h does not support strides");
195  static_assert(S2 == C2, "pmp_h does not support strides");
196  static_assert(P1 == 0, "pmp_h does not support padding");
197  static_assert(P2 == 0, "pmp_h does not support padding");
198 
199  using T = value_t<A>;
200 
201  const size_t K = etl::dim<0>(a);
202  const size_t L = etl::dim<1>(a);
203  const size_t M = etl::dim<2>(a);
204  const size_t N = etl::dim<3>(a);
205 
206  etl::dyn_matrix<T, 2> exp_sub(M, N);
207  etl::dyn_matrix<T, 2> base(M, N);
208 
209  CPU_SECTION {
210  if (C1 == 2 && C2 == 2) {
211  for (size_t k = 0; k < K; ++k) {
212  for (size_t l = 0; l < L; ++l) {
213  exp_sub = exp(a(k)(l));
214 
215  pmp_h_kernel_2x2(exp_sub, base);
216 
217  c(k)(l) = exp_sub / (1.0 + base);
218  }
219  }
220  } else {
221  for (size_t k = 0; k < K; ++k) {
222  for (size_t l = 0; l < L; ++l) {
223  exp_sub = exp(a(k)(l));
224 
225  pmp_h_kernel<C1, C2>(exp_sub, base);
226 
227  c(k)(l) = exp_sub / (1.0 + base);
228  }
229  }
230  }
231  }
232  }
233 };
234 
243  template <typename A>
244  static constexpr bool gpu_computable = false;
245 
251  template <etl_2d A, typename C>
252  static void apply(A&& a, C&& c, size_t c1, size_t c2, [[maybe_unused]] size_t s1, [[maybe_unused]] size_t s2, [[maybe_unused]] size_t p1, [[maybe_unused]] size_t p2) {
253  cpp_assert(s1 == c1, "pmp_p does not support strides");
254  cpp_assert(s2 == c2, "pmp_p does not support strides");
255  cpp_assert(p1 == 0, "pmp_p does not support pooling");
256  cpp_assert(p2 == 0, "pmp_p does not support pooling");
257 
258  using T = value_t<A>;
259 
260  const size_t M = etl::dim<0>(a);
261  const size_t N = etl::dim<1>(a);
262 
263  etl::dyn_matrix<T, 2> exp_sub(M, N);
264  etl::dyn_matrix<T, 2> base(M, N);
265 
266  CPU_SECTION {
267  exp_sub = exp(a);
268 
269  if (c1 == 2 && c2 == 2) {
270  pmp_h_kernel_2x2(exp_sub, base);
271  } else {
272  pmp_h_kernel(exp_sub, base, c1, c2);
273  }
274 
275  c = exp_sub / (1.0 + base);
276  }
277  }
278 
284  template <etl_3d A, typename C>
285  static void apply(A&& a, C&& c, size_t c1, size_t c2, [[maybe_unused]] size_t s1, [[maybe_unused]] size_t s2, [[maybe_unused]] size_t p1, [[maybe_unused]] size_t p2) {
286  cpp_assert(s1 == c1, "pmp_p does not support strides");
287  cpp_assert(s2 == c2, "pmp_p does not support strides");
288  cpp_assert(p1 == 0, "pmp_p does not support pooling");
289  cpp_assert(p2 == 0, "pmp_p does not support pooling");
290 
291  using T = value_t<A>;
292 
293  const size_t L = etl::dim<0>(a);
294  const size_t M = etl::dim<1>(a);
295  const size_t N = etl::dim<2>(a);
296 
297  etl::dyn_matrix<T, 2> exp_sub(M, N);
298  etl::dyn_matrix<T, 2> base(M, N);
299 
300  CPU_SECTION {
301  if (c1 == 2 && c2 == 2) {
302  for (size_t l = 0; l < L; ++l) {
303  exp_sub = exp(a(l));
304 
305  pmp_h_kernel_2x2(exp_sub, base);
306 
307  c(l) = exp_sub / (1.0 + base);
308  }
309  } else {
310  for (size_t l = 0; l < L; ++l) {
311  exp_sub = exp(a(l));
312 
313  pmp_h_kernel(exp_sub, base, c1, c2);
314 
315  c(l) = exp_sub / (1.0 + base);
316  }
317  }
318  }
319  }
320 
326  template <etl_4d A, typename C>
327  static void apply(A&& a, C&& c, size_t c1, size_t c2, [[maybe_unused]] size_t s1, [[maybe_unused]] size_t s2, [[maybe_unused]] size_t p1, [[maybe_unused]] size_t p2) {
328  cpp_assert(s1 == c1, "pmp_p does not support strides");
329  cpp_assert(s2 == c2, "pmp_p does not support strides");
330  cpp_assert(p1 == 0, "pmp_p does not support pooling");
331  cpp_assert(p2 == 0, "pmp_p does not support pooling");
332 
333  using T = value_t<A>;
334 
335  const size_t K = etl::dim<0>(a);
336  const size_t L = etl::dim<1>(a);
337  const size_t M = etl::dim<2>(a);
338  const size_t N = etl::dim<3>(a);
339 
340  etl::dyn_matrix<T, 2> exp_sub(M, N);
341  etl::dyn_matrix<T, 2> base(M, N);
342 
343  CPU_SECTION {
344  if (c1 == 2 && c2 == 2) {
345  for (size_t k = 0; k < K; ++k) {
346  for (size_t l = 0; l < L; ++l) {
347  exp_sub = exp(a(k)(l));
348 
349  pmp_h_kernel_2x2(exp_sub, base);
350 
351  c(k)(l) = exp_sub / (1.0 + base);
352  }
353  }
354  } else {
355  for (size_t k = 0; k < K; ++k) {
356  for (size_t l = 0; l < L; ++l) {
357  exp_sub = exp(a(k)(l));
358 
359  pmp_h_kernel(exp_sub, base, c1, c2);
360 
361  c(k)(l) = exp_sub / (1.0 + base);
362  }
363  }
364  }
365  }
366  }
367 };
368 
379 template <typename T>
380 inline void pmp_p_kernel_2x2(etl::dyn_matrix<T, 2>& exp_sub, etl::dyn_matrix<T, 2>& base) {
381  const size_t M = etl::dim<0>(exp_sub);
382  const size_t N = etl::dim<1>(exp_sub);
383 
384  for (size_t m = 0; m < M / 2; ++m) {
385  const auto start_mm = m * 2;
386 
387  for (size_t n = 0; n < N / 2; ++n) {
388  const auto start_nn = n * 2;
389 
390  base(m, n) = exp_sub(start_mm + 0, start_nn + 0) + exp_sub(start_mm + 0, start_nn + 1) + exp_sub(start_mm + 1, start_nn + 0)
391  + exp_sub(start_mm + 1, start_nn + 1);
392  }
393  }
394 }
395 
403 template <size_t C1, size_t C2, typename T>
404 inline void pmp_p_kernel(etl::dyn_matrix<T, 2>& exp_sub, etl::dyn_matrix<T, 2>& base) {
405  const size_t M = etl::dim<0>(exp_sub);
406  const size_t N = etl::dim<1>(exp_sub);
407 
408  for (size_t m = 0; m < M / C1; ++m) {
409  const auto start_mm = m * C1;
410 
411  for (size_t n = 0; n < N / C2; ++n) {
412  const auto start_nn = n * C2;
413 
414  auto p = T(0);
415 
416  for (size_t mm = start_mm; mm < start_mm + C1; ++mm) {
417  for (size_t nn = start_nn; nn < start_nn + C2; ++nn) {
418  p += exp_sub(mm, nn);
419  }
420  }
421 
422  base(m, n) = p;
423  }
424  }
425 }
426 
434 template <typename T>
435 inline void pmp_p_kernel(etl::dyn_matrix<T, 2>& exp_sub, etl::dyn_matrix<T, 2>& base, size_t c1, size_t c2) {
436  const size_t M = etl::dim<0>(exp_sub);
437  const size_t N = etl::dim<1>(exp_sub);
438 
439  for (size_t m = 0; m < M / c1; ++m) {
440  const auto start_mm = m * c1;
441 
442  for (size_t n = 0; n < N / c2; ++n) {
443  const auto start_nn = n * c2;
444 
445  auto p = T(0);
446 
447  for (size_t mm = start_mm; mm < start_mm + c1; ++mm) {
448  for (size_t nn = start_nn; nn < start_nn + c2; ++nn) {
449  p += exp_sub(mm, nn);
450  }
451  }
452 
453  base(m, n) = p;
454  }
455  }
456 }
457 
461 struct pmp_p_impl {
466  template <typename A>
467  static constexpr bool gpu_computable = false;
468 
474  template <size_t C1, size_t C2, size_t S1, size_t S2, size_t P1, size_t P2, etl_2d A, typename C>
475  static void apply(A&& a, C&& c) {
476  static_assert(S1 == C1, "pmp_p does not support strides");
477  static_assert(S2 == C2, "pmp_p does not support strides");
478  static_assert(P1 == 0, "pmp_p does not support padding");
479  static_assert(P2 == 0, "pmp_p does not support padding");
480 
481  using T = value_t<A>;
482 
483  const size_t M = etl::dim<0>(a);
484  const size_t N = etl::dim<1>(a);
485 
486  etl::dyn_matrix<T, 2> exp_sub(M, N);
487  etl::dyn_matrix<T, 2> base(M / C1, N / C2);
488 
489  exp_sub = exp(a);
490 
491  if (C1 == 2 && C2 == 2) {
492  pmp_p_kernel_2x2(exp_sub, base);
493  } else {
494  pmp_p_kernel<C1, C2>(exp_sub, base);
495  }
496 
497  c = 1.0 / (1.0 + base);
498  }
499 
505  template <size_t C1, size_t C2, size_t S1, size_t S2, size_t P1, size_t P2, etl_3d A, typename C>
506  static void apply(A&& a, C&& c) {
507  static_assert(S1 == C1, "pmp_p does not support strides");
508  static_assert(S2 == C2, "pmp_p does not support strides");
509  static_assert(P1 == 0, "pmp_p does not support padding");
510  static_assert(P2 == 0, "pmp_p does not support padding");
511 
512  using T = value_t<A>;
513 
514  const size_t L = etl::dim<0>(a);
515  const size_t M = etl::dim<1>(a);
516  const size_t N = etl::dim<2>(a);
517 
518  etl::dyn_matrix<T, 2> exp_sub(M, N);
519  etl::dyn_matrix<T, 2> base(M / C1, N / C2);
520 
521  if (C1 == 2 && C2 == 2) {
522  for (size_t l = 0; l < L; ++l) {
523  exp_sub = exp(a(l));
524 
525  pmp_p_kernel_2x2(exp_sub, base);
526 
527  c(l) = 1.0 / (1.0 + base);
528  }
529  } else {
530  for (size_t l = 0; l < L; ++l) {
531  exp_sub = exp(a(l));
532 
533  pmp_p_kernel<C1, C2>(exp_sub, base);
534 
535  c(l) = 1.0 / (1.0 + base);
536  }
537  }
538  }
539 
545  template <size_t C1, size_t C2, size_t S1, size_t S2, size_t P1, size_t P2, etl_4d A, typename C>
546  static void apply(A&& a, C&& c) {
547  static_assert(S1 == C1, "pmp_p does not support strides");
548  static_assert(S2 == C2, "pmp_p does not support strides");
549  static_assert(P1 == 0, "pmp_p does not support padding");
550  static_assert(P2 == 0, "pmp_p does not support padding");
551 
552  using T = value_t<A>;
553 
554  const size_t K = etl::dim<0>(a);
555  const size_t L = etl::dim<1>(a);
556  const size_t M = etl::dim<2>(a);
557  const size_t N = etl::dim<3>(a);
558 
559  etl::dyn_matrix<T, 2> exp_sub(M, N);
560  etl::dyn_matrix<T, 2> base(M / C1, N / C2);
561 
562  if (C1 == 2 && C2 == 2) {
563  for (size_t k = 0; k < K; ++k) {
564  for (size_t l = 0; l < L; ++l) {
565  exp_sub = exp(a(k)(l));
566 
567  pmp_p_kernel_2x2(exp_sub, base);
568 
569  c(k)(l) = 1.0 / (1.0 + base);
570  }
571  }
572  } else {
573  for (size_t k = 0; k < K; ++k) {
574  for (size_t l = 0; l < L; ++l) {
575  exp_sub = exp(a(k)(l));
576 
577  pmp_p_kernel<C1, C2>(exp_sub, base);
578 
579  c(k)(l) = 1.0 / (1.0 + base);
580  }
581  }
582  }
583  }
584 };
585 
594  template <typename A>
595  static constexpr bool gpu_computable = false;
596 
602  template <etl_2d A, typename C>
603  static void apply(A&& a, C&& c, size_t c1, size_t c2, [[maybe_unused]] size_t s1, [[maybe_unused]] size_t s2, [[maybe_unused]] size_t p1, [[maybe_unused]] size_t p2) {
604  cpp_assert(s1 == c1, "pmp_p does not support strides");
605  cpp_assert(s2 == c2, "pmp_p does not support strides");
606  cpp_assert(p1 == 0, "pmp_p does not support pooling");
607  cpp_assert(p2 == 0, "pmp_p does not support pooling");
608 
609  using T = value_t<A>;
610 
611  const size_t M = etl::dim<0>(a);
612  const size_t N = etl::dim<1>(a);
613 
614  etl::dyn_matrix<T, 2> exp_sub(M, N);
615  etl::dyn_matrix<T, 2> base(M / c1, N / c2);
616 
617  exp_sub = exp(a);
618 
619  if (c1 == 2 && c2 == 2) {
620  pmp_p_kernel_2x2(exp_sub, base);
621  } else {
622  pmp_p_kernel(exp_sub, base, c1, c2);
623  }
624 
625  c = 1.0 / (1.0 + base);
626  }
627 
633  template <etl_3d A, typename C>
634  static void apply(A&& a, C&& c, size_t c1, size_t c2, [[maybe_unused]] size_t s1, [[maybe_unused]] size_t s2, [[maybe_unused]] size_t p1, [[maybe_unused]] size_t p2) {
635  cpp_assert(s1 == c1, "pmp_p does not support strides");
636  cpp_assert(s2 == c2, "pmp_p does not support strides");
637  cpp_assert(p1 == 0, "pmp_p does not support pooling");
638  cpp_assert(p2 == 0, "pmp_p does not support pooling");
639 
640  using T = value_t<A>;
641 
642  const size_t L = etl::dim<0>(a);
643  const size_t M = etl::dim<1>(a);
644  const size_t N = etl::dim<2>(a);
645 
646  etl::dyn_matrix<T, 2> exp_sub(M, N);
647  etl::dyn_matrix<T, 2> base(M / c1, N / c2);
648 
649  if (c1 == 2 && c2 == 2) {
650  for (size_t l = 0; l < L; ++l) {
651  exp_sub = exp(a(l));
652 
653  pmp_p_kernel_2x2(exp_sub, base);
654 
655  c(l) = 1.0 / (1.0 + base);
656  }
657  } else {
658  for (size_t l = 0; l < L; ++l) {
659  exp_sub = exp(a(l));
660 
661  pmp_p_kernel(exp_sub, base, c1, c2);
662 
663  c(l) = 1.0 / (1.0 + base);
664  }
665  }
666  }
667 
673  template <etl_4d A, typename C>
674  static void apply(A&& a, C&& c, size_t c1, size_t c2, [[maybe_unused]] size_t s1, [[maybe_unused]] size_t s2, [[maybe_unused]] size_t p1, [[maybe_unused]] size_t p2) {
675  cpp_assert(s1 == c1, "pmp_p does not support strides");
676  cpp_assert(s2 == c2, "pmp_p does not support strides");
677  cpp_assert(p1 == 0, "pmp_p does not support pooling");
678  cpp_assert(p2 == 0, "pmp_p does not support pooling");
679 
680  using T = value_t<A>;
681 
682  const size_t K = etl::dim<0>(a);
683  const size_t L = etl::dim<1>(a);
684  const size_t M = etl::dim<2>(a);
685  const size_t N = etl::dim<3>(a);
686 
687  etl::dyn_matrix<T, 2> exp_sub(M, N);
688  etl::dyn_matrix<T, 2> base(M / c1, N / c2);
689 
690  if (c1 == 2 && c2 == 2) {
691  for (size_t k = 0; k < K; ++k) {
692  for (size_t l = 0; l < L; ++l) {
693  exp_sub = exp(a(k)(l));
694 
695  pmp_p_kernel_2x2(exp_sub, base);
696 
697  c(k)(l) = 1.0 / (1.0 + base);
698  }
699  }
700  } else {
701  for (size_t k = 0; k < K; ++k) {
702  for (size_t l = 0; l < L; ++l) {
703  exp_sub = exp(a(k)(l));
704 
705  pmp_p_kernel(exp_sub, base, c1, c2);
706 
707  c(k)(l) = 1.0 / (1.0 + base);
708  }
709  }
710  }
711  }
712 };
713 
714 } //end of namespace etl::impl::standard
Definition: prob_pooling.hpp:10
static void apply(A &&a, C &&c, size_t c1, size_t c2, [[maybe_unused]] size_t s1, [[maybe_unused]] size_t s2, [[maybe_unused]] size_t p1, [[maybe_unused]] size_t p2)
Apply the functor.
Definition: prob_pooling.hpp:603
static void apply(A &&a, C &&c)
Apply the functor.
Definition: prob_pooling.hpp:118
static constexpr bool gpu_computable
Indicates if the temporary expression can be directly evaluated using only GPU.
Definition: prob_pooling.hpp:110
Matrix with run-time fixed dimensions.
Definition: dyn.hpp:26
static void apply(A &&a, C &&c)
Apply the functor.
Definition: prob_pooling.hpp:475
auto exp(E &&value) -> detail::unary_helper< E, exp_unary_op >
Apply exponential on each value of the given expression.
Definition: function_expression_builder.hpp:154
2D Implemenetation of Probabilistic Max Pooling for hidden units
Definition: prob_pooling.hpp:104
Dynamic Implemenetation of Probabilistic Max Pooling for hidden units.
Definition: prob_pooling.hpp:238
typename decay_traits< E >::value_type value_t
Traits to extract the value type out of an ETL type.
Definition: tmp.hpp:81
Implemenetation of Probabilistic Max Pooling for pooling units.
Definition: prob_pooling.hpp:461
static void apply(A &&a, C &&c, size_t c1, size_t c2, [[maybe_unused]] size_t s1, [[maybe_unused]] size_t s2, [[maybe_unused]] size_t p1, [[maybe_unused]] size_t p2)
Apply the functor.
Definition: prob_pooling.hpp:252
Dynamic 4D Implemenetation of Probabilistic Max Pooling for pooling units.
Definition: prob_pooling.hpp:589