1
// Tencent is pleased to support the open source community by making ncnn available.
3
// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
5
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
6
// in compliance with the License. You may obtain a copy of the License at
8
// https://opensource.org/licenses/BSD-3-Clause
10
// Unless required by applicable law or agreed to in writing, software distributed
11
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13
// specific language governing permissions and limitations under the License.
17
#include "layer_type.h"
26
support_inplace = false;
29
int Pooling1D::load_param(const ParamDict& pd)
31
pooling_type = pd.get(0, 0);
32
kernel_w = pd.get(1, 0);
33
stride_w = pd.get(2, 1);
34
pad_left = pd.get(3, 0);
35
pad_right = pd.get(14, pad_left);
36
global_pooling = pd.get(4, 0);
37
pad_mode = pd.get(5, 0);
38
avgpool_count_include_pad = pd.get(6, 0);
39
adaptive_pooling = pd.get(7, 0);
45
int Pooling1D::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
47
int w = bottom_blob.w;
48
int h = bottom_blob.h;
49
size_t elemsize = bottom_blob.elemsize;
51
// NCNN_LOGE("Pooling1D input %d x %d pad = %d %d ksize=%d stride=%d", w, h, pad_left, pad_right, kernel_w, stride_w);
54
top_blob.create(h, elemsize, opt.blob_allocator);
58
if (pooling_type == PoolMethod_MAX)
60
#pragma omp parallel for num_threads(opt.num_threads)
61
for (int q = 0; q < h; q++)
63
const float* ptr = bottom_blob.row(q);
66
for (int i = 0; i < w; i++)
68
max = std::max(max, ptr[i]);
74
else if (pooling_type == PoolMethod_AVE)
76
#pragma omp parallel for num_threads(opt.num_threads)
77
for (int q = 0; q < h; q++)
79
const float* ptr = bottom_blob.row(q);
82
for (int i = 0; i < w; i++)
87
top_blob[q] = sum / w;
96
top_blob.create(out_w, h, elemsize, opt.blob_allocator);
100
if (pooling_type == PoolMethod_MAX)
102
#pragma omp parallel for num_threads(opt.num_threads)
103
for (int q = 0; q < h; q++)
105
const float* inptr = bottom_blob.row(q);
106
float* outptr = top_blob.row(q);
108
for (int j = 0; j < out_w; j++)
111
const int iw0 = w * j / out_w;
113
const int iw1 = (w * (j + 1) + out_w - 1) / out_w;
115
float max = inptr[iw0];
116
for (int iw = iw0; iw < iw1; iw++)
118
max = std::max(max, inptr[iw]);
125
else if (pooling_type == PoolMethod_AVE)
127
#pragma omp parallel for num_threads(opt.num_threads)
128
for (int q = 0; q < h; q++)
130
const float* inptr = bottom_blob.row(q);
131
float* outptr = top_blob.row(q);
133
for (int j = 0; j < out_w; j++)
136
const int iw0 = w * j / out_w;
138
const int iw1 = (w * (j + 1) + out_w - 1) / out_w;
139
const int wk = iw1 - iw0;
142
for (int iw = iw0; iw < iw1; iw++)
147
outptr[j] = sum / wk;
155
Mat bottom_blob_bordered;
156
make_padding(bottom_blob, bottom_blob_bordered, opt);
157
if (bottom_blob_bordered.empty())
160
w = bottom_blob_bordered.w;
161
h = bottom_blob_bordered.h;
163
int outw = (w - kernel_w) / stride_w + 1;
165
top_blob.create(outw, h, elemsize, opt.blob_allocator);
166
if (top_blob.empty())
169
if (pooling_type == PoolMethod_MAX)
171
#pragma omp parallel for num_threads(opt.num_threads)
172
for (int q = 0; q < h; q++)
174
const float* ptr = bottom_blob_bordered.row(q);
175
float* outptr = top_blob.row(q);
177
for (int j = 0; j < outw; j++)
179
const float* sptr = ptr + j * stride_w;
183
for (int k = 0; k < kernel_w; k++)
186
max = std::max(max, val);
193
else if (pooling_type == PoolMethod_AVE)
195
if (avgpool_count_include_pad == 0)
199
if (pad_mode == 0) // full padding
201
wtailpad = bottom_blob_bordered.w - bottom_blob.w - pad_left - pad_right;
204
#pragma omp parallel for num_threads(opt.num_threads)
205
for (int q = 0; q < h; q++)
207
const float* ptr = bottom_blob_bordered.row(q);
208
float* outptr = top_blob.row(q);
210
for (int j = 0; j < outw; j++)
212
int sx0 = j * stride_w;
217
for (int kj = 0; kj < kernel_w; kj++)
224
if (sx >= w - pad_right - wtailpad)
232
outptr[j] = sum / area;
236
else // if (avgpool_count_include_pad == 1)
238
#pragma omp parallel for num_threads(opt.num_threads)
239
for (int q = 0; q < h; q++)
241
const float* ptr = bottom_blob_bordered.row(q);
242
float* outptr = top_blob.row(q);
244
for (int j = 0; j < outw; j++)
246
const float* sptr = ptr + j * stride_w;
250
for (int k = 0; k < kernel_w; k++)
256
outptr[j] = sum / kernel_w;
265
void Pooling1D::make_padding(const Mat& bottom_blob, Mat& bottom_blob_bordered, const Option& opt) const
267
int w = bottom_blob.w;
269
bottom_blob_bordered = bottom_blob;
271
float pad_value = 0.f;
272
if (pooling_type == PoolMethod_MAX)
274
pad_value = bottom_blob.elemsize == 1 ? -128.f : -FLT_MAX;
276
else if (pooling_type == PoolMethod_AVE)
283
if (pad_mode == 0) // full padding
285
int wtail = (w + pad_left + pad_right - kernel_w) % stride_w;
288
wtailpad = stride_w - wtail;
291
opt_b.blob_allocator = opt.workspace_allocator;
292
copy_make_border(bottom_blob, bottom_blob_bordered, 0, 0, pad_left, pad_right + wtailpad, BORDER_CONSTANT, pad_value, opt_b);
294
else if (pad_mode == 1) // valid padding
297
opt_b.blob_allocator = opt.workspace_allocator;
298
copy_make_border(bottom_blob, bottom_blob_bordered, 0, 0, pad_left, pad_right, BORDER_CONSTANT, pad_value, opt_b);
300
else if (pad_mode == 2) // tensorflow padding=SAME or onnx padding=SAME_UPPER
302
int wpad = kernel_w + (w - 1) / stride_w * stride_w - w;
306
opt_b.blob_allocator = opt.workspace_allocator;
307
copy_make_border(bottom_blob, bottom_blob_bordered, 0, 0, wpad / 2, wpad - wpad / 2, BORDER_CONSTANT, pad_value, opt_b);
310
else if (pad_mode == 3) // onnx padding=SAME_LOWER
312
int wpad = kernel_w + (w - 1) / stride_w * stride_w - w;
316
opt_b.blob_allocator = opt.workspace_allocator;
317
copy_make_border(bottom_blob, bottom_blob_bordered, 0, 0, wpad - wpad / 2, wpad / 2, BORDER_CONSTANT, pad_value, opt_b);