ONE - On-device Neural Engine
Loading...
Searching...
No Matches
MaxPool.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2023 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#ifndef __NNFW_CKER_TRAIN_OPERATION_MAXPOOL_H__
18#define __NNFW_CKER_TRAIN_OPERATION_MAXPOOL_H__
19
20#include "cker/Shape.h"
21#include "cker/Utils.h"
22#include "cker/eigen/Utils.h"
23
24#include <Eigen/Core>
25
26namespace nnfw
27{
28namespace cker
29{
30namespace train
31{
32
33// Most of the logic except 'arg_max_index' related is copy-paste from
34// https://github.com/Samsung/ONE/blob/a380292/compute/cker/include/cker/operation/MaxPool.h#L42-L88
35// 'arg_max_index' is to record max-arguments' index to apply gradient later.
36inline void MaxPool2D(const PoolParams &params, const Shape &input_shape, const float *input_data,
37 const Shape &output_shape, float *output_data, int *arg_max_index)
38{
39 assert(input_shape.DimensionsCount() == 4);
40 assert(output_shape.DimensionsCount() == 4);
41 assert(input_shape.Dims(0) == output_shape.Dims(0)); // MaxPool2D doesn't change batch
42 assert(input_shape.Dims(3) == output_shape.Dims(3)); // MaxPool2D doesn't change depth
43
44 const int batches = MatchingDim(input_shape, 0, output_shape, 0);
45 const int input_height = input_shape.Dims(1);
46 const int input_width = input_shape.Dims(2);
47 const int output_height = output_shape.Dims(1);
48 const int output_width = output_shape.Dims(2);
49 const int filter_height = params.filter_height;
50 const int filter_width = params.filter_width;
51 const int pad_height = params.padding_values.height;
52 const int pad_width = params.padding_values.width;
53 const int stride_height = params.stride_height;
54 const int stride_width = params.stride_width;
55
56 const auto in_mat = MapAsMatrixWithLastDimAsRows(input_data, input_shape);
57 auto out_mat = MapAsMatrixWithLastDimAsRows(output_data, output_shape);
58 auto arg_max_index_mat = MapAsMatrixWithLastDimAsRows(arg_max_index, output_shape);
59
60 // initialize output area
61 std::fill(output_data, output_data + output_shape.FlatSize(), 0.0);
62 std::fill(arg_max_index, arg_max_index + output_shape.FlatSize(), -1);
63
64 // initialize projected area with lowest float
65 const int h_start =
66 (pad_height < filter_height) ? 0 : (pad_height - filter_height) / stride_height + 1;
67 const int h_end = std::min((input_height + pad_height - 1) / stride_height + 1, output_height);
68
69 const int w_start =
70 (pad_width < filter_width) ? 0 : (pad_width - filter_width) / stride_width + 1;
71 const int w_end = std::min((input_width + pad_width - 1) / stride_width + 1, output_width);
72
73 for (int b = 0; b < batches; ++b)
74 {
75 for (int h_idx = h_start; h_idx < h_end; h_idx++)
76 {
77 for (int w_idx = w_start; w_idx < w_end; w_idx++)
78 {
79 const int offset = NodeOffset(b, h_idx, w_idx, output_height, output_width);
80 out_mat.col(offset).setConstant(std::numeric_limits<float>::lowest());
81 }
82 }
83 }
84
85 for (int b = 0; b < batches; ++b)
86 {
87 for (int h = 0; h < input_height; ++h)
88 {
89 for (int w = 0; w < input_width; ++w)
90 {
91 // (h_start, h_end) * (w_start, w_end) is the range that the input
92 // vector projects to.
93 int hpad = h + pad_height;
94 int wpad = w + pad_width;
95
96 int h_start = (hpad < filter_height) ? 0 : (hpad - filter_height) / stride_height + 1;
97 int h_end = std::min(hpad / stride_height + 1, output_height);
98
99 int w_start = (wpad < filter_width) ? 0 : (wpad - filter_width) / stride_width + 1;
100 int w_end = std::min(wpad / stride_width + 1, output_width);
101
102 // compute elementwise sum
103 for (int ph = h_start; ph < h_end; ++ph)
104 {
105 for (int pw = w_start; pw < w_end; ++pw)
106 {
107 const int out_offset = NodeOffset(b, ph, pw, output_height, output_width);
108 const int in_offset = NodeOffset(b, h, w, input_height, input_width);
109
110 const auto out_vector = out_mat.col(out_offset);
111 const auto in_vector = in_mat.col(in_offset);
112
113 // update arg_max_index_mat
114 arg_max_index_mat.col(out_offset) =
115 (out_vector.array() < in_vector.array())
116 .select(in_offset, arg_max_index_mat.col(out_offset));
117
118 // update out_mat
119 out_mat.col(out_offset) = out_vector.cwiseMax(in_vector);
120 }
121 }
122 }
123 }
124 }
125
126 out_mat = out_mat.cwiseMin(params.float_activation_max).cwiseMax(params.float_activation_min);
127}
128
129inline void MaxPool2DGrad(const Shape &incoming_shape, const float *incoming_data,
130 const int *arg_max_index, const Shape &grad_shape, float *grad_data)
131{
132 assert(grad_shape.DimensionsCount() == 4);
133 assert(incoming_shape.DimensionsCount() == 4);
134
135 // initialize grad_data
136 std::fill(grad_data, grad_data + grad_shape.FlatSize(), 0.0);
137
138 const int depth = MatchingDim(grad_shape, 3, incoming_shape, 3);
139 const auto incoming_mat = MapAsMatrixWithLastDimAsRows(incoming_data, incoming_shape);
140 auto arg_max_index_mat = MapAsMatrixWithLastDimAsRows(arg_max_index, incoming_shape);
141 auto grad_mat = MapAsMatrixWithLastDimAsRows(grad_data, grad_shape);
142
143 for (int col_index = 0; col_index < incoming_mat.cols(); col_index++)
144 {
145 auto arg_indices = arg_max_index_mat.col(col_index);
146 for (int d = 0; d < depth; d++)
147 {
148 // output value is from padding, so nothing to propagate
149 if (arg_indices(d) == -1)
150 continue;
151
152 grad_mat(d, arg_indices(d)) += incoming_mat(d, col_index);
153 }
154 }
155}
156
157} // namespace train
158} // namespace cker
159} // namespace nnfw
160
161#endif // __NNFW_CKER_TRAIN_OPERATION_MAXPOOL_H__
int32_t DimensionsCount() const
Definition Shape.h:91
int32_t Dims(int i) const
Definition Shape.h:92
int FlatSize() const
Definition Shape.h:181
__global uchar * offset(const Image *img, int x, int y)
Definition helpers.h:540
const luci_interpreter::RuntimeShape output_shape
void MaxPool2DGrad(const Shape &incoming_shape, const float *incoming_data, const int *arg_max_index, const Shape &grad_shape, float *grad_data)
Definition MaxPool.h:129
int MatchingDim(const Shape &shape1, int index1, const Shape &shape2, int index2)
Definition Shape.h:220
int NodeOffset(int b, int h, int w, int height, int width)
Definition Utils.h:147
MatrixMap< Scalar > MapAsMatrixWithLastDimAsRows(Scalar *data, const Shape &shape)
Definition Utils.h:60
Definition topk_v2.h:30
float float_activation_max
Definition Types.h:99
float float_activation_min
Definition Types.h:98
PaddingValues padding_values
Definition Types.h:89