// Tencent is pleased to support the open source community by making ncnn available. // // Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. // // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // https://opensource.org/licenses/BSD-3-Clause // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #include "reduction.h" #include #include #include #include #include namespace ncnn { DEFINE_LAYER_CREATOR(Reduction) Reduction::Reduction() { one_blob_only = true; support_inplace = false; } int Reduction::load_param(const ParamDict& pd) { operation = pd.get(0, 0); dim = pd.get(1, 0); coeff = pd.get(2, 1.f); return 0; } template static int reduction_op(const Mat& a, Mat& b, float v0, int dim, float coeff, const Option& opt) { Op op; Op2 op2; int w = a.w; int h = a.h; int channels = a.c; size_t elemsize = a.elemsize; int size = w * h; if (dim == 0) { // w h c -> X X X b.create(1, elemsize, opt.blob_allocator); } else if (dim == 1) { // w h c -> X X c b.create(channels, elemsize, opt.blob_allocator); } else if (dim == 2) { // w h c -> X h c b.create(h, channels, elemsize, opt.blob_allocator); } else if (dim == -1) { // w h c -> w X X b.create(w, elemsize, opt.blob_allocator); } else if (dim == -2) { // w h c -> w h X b.create(w, h, elemsize, opt.blob_allocator); } if (b.empty()) return -100; if (dim == 0) { Mat sums(channels, elemsize, opt.workspace_allocator); if (sums.empty()) return -100; #pragma omp parallel for num_threads(opt.num_threads) for (int q=0; q struct reduction_op_asum : std::binary_function { T operator() (const T& x, const T& y) const { return x + fabs(y); } }; template struct reduction_op_sumsq : std::binary_function { T operator() (const T& x, const T& y) const { return x + y * y; } }; template struct reduction_op_max : std::binary_function { T operator() (const T& x, const T& y) const { return std::max(x, y); } }; template struct reduction_op_min : std::binary_function { T operator() (const T& x, const T& y) const { return std::min(x, y); } }; int Reduction::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const { if (operation == ReductionOp_SUM) return reduction_op< std::plus, std::plus >(bottom_blob, top_blob, 0.f, dim, coeff, opt); if (operation == ReductionOp_ASUM) return reduction_op< reduction_op_asum, std::plus >(bottom_blob, top_blob, 0.f, dim, coeff, opt); if (operation == ReductionOp_SUMSQ) return reduction_op< reduction_op_sumsq, std::plus >(bottom_blob, top_blob, 0.f, dim, coeff, opt); if (operation == ReductionOp_MEAN) { int ret = reduction_op< std::plus, std::plus >(bottom_blob, top_blob, 0.f, dim, coeff, opt); if (ret != 0) return -100; int w = bottom_blob.w; int h = bottom_blob.h; int channels = bottom_blob.c; int size = w * h; if (dim == 0) { top_blob[0] /= channels * size; } else if (dim == 1) { for (int q=0; q, reduction_op_max >(bottom_blob, top_blob, -FLT_MAX, dim, coeff, opt); if (operation == ReductionOp_MIN) return reduction_op< reduction_op_min, reduction_op_min >(bottom_blob, top_blob, FLT_MAX, dim, coeff, opt); if (operation == ReductionOp_PROD) return reduction_op< std::multiplies, std::multiplies >(bottom_blob, top_blob, 1.f, dim, coeff, opt); return 0; } } // namespace ncnn