// This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. #include "../precomp.hpp" #include "layers_common.hpp" #include #include #include namespace cv { namespace dnn { class ReduceLayerInt8Impl CV_FINAL : public ReduceLayerInt8 { public: ReduceLayerInt8Impl(const LayerParams& params) { // Set reduce type CV_Assert(params.has("reduce")); String typeString = toLowerCase(params.get("reduce")); if (typeString == "max") reduceType = MAX; else if (typeString == "min") reduceType = MIN; else CV_Error(Error::StsBadArg, "Unknown reduce type \"" + typeString + "\""); // Set deleted dims CV_Assert(params.has("deleted_dims")); DictValue tempDims = params.get("deleted_dims"); int i, n = tempDims.size(); reduceDims.resize(n); for (i = 0; i < n; i++) { reduceDims[i] = tempDims.get(i); } } virtual bool supportBackend(int backendId) CV_OVERRIDE { if (backendId == DNN_BACKEND_OPENCV) { return true; } return false; } // reduceType == MIN struct ReduceOpMIN { int8_t apply(const int8_t* first, const int8_t* last) { return std::accumulate(first, last, *first, [](int8_t a, int8_t b) { return std::min(a, b); }); } }; // reduceType == MAX struct ReduceOpMAX { int8_t apply(const int8_t* first, const int8_t* last) { return std::accumulate(first, last, *first, [](int8_t a, int8_t b) { return std::max(a, b); }); } }; template class ReduceInvoker : public ParallelLoopBody { public: const Mat* src; Mat *dst; std::vector reduceDims; int nstripes; int reduceType; Ptr func; ReduceInvoker() : src(0), dst(0), nstripes(0), reduceType(MAX), func(makePtr()) {} static void run(const Mat& src, Mat& dst, std::vector reduceDims, int reduceType, int nstripes) { CV_Assert_N(src.isContinuous(), dst.isContinuous(), src.type() == CV_8S, src.type() == dst.type()); ReduceInvoker p; p.src = &src; p.dst = &dst; p.reduceDims = reduceDims; p.nstripes = nstripes; p.reduceType = reduceType; parallel_for_(Range(0, nstripes), p, nstripes); } void operator()(const Range& r) const CV_OVERRIDE { size_t total = dst->total(); size_t stripeSize = (total + nstripes - 1)/nstripes; size_t stripeStart = r.start*stripeSize; size_t stripeEnd = std::min(r.end*stripeSize, total); size_t totalDeleted = std::accumulate(reduceDims.begin(), reduceDims.end(), 1, std::multiplies()); int8_t *dstData = (int8_t *)dst->data; int8_t *srcData = (int8_t *)src->data; for (size_t ofs = stripeStart; ofs < stripeEnd;) { const int8_t* first = srcData + ofs * totalDeleted; const int8_t* last = srcData + (ofs + 1) * totalDeleted; dstData[ofs] = func->apply(first, last); ofs += 1; } } }; void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE { CV_TRACE_FUNCTION(); CV_TRACE_ARG_VALUE(name, "name", name.c_str()); std::vector inputs, outputs; inputs_arr.getMatVector(inputs); outputs_arr.getMatVector(outputs); CV_Assert(inputs.size() == 1); const int nstripes = getNumThreads(); switch (reduceType) { case MIN: { ReduceInvoker::run(inputs[0], outputs[0], reduceDims, reduceType, nstripes); break; } case MAX: { ReduceInvoker::run(inputs[0], outputs[0], reduceDims, reduceType, nstripes); break; } default: CV_Error(Error::StsNotImplemented, "Not implemented"); break; } } bool getMemoryShapes(const std::vector &inputs, const int requiredOutputs, std::vector &outputs, std::vector &internals) const CV_OVERRIDE { CV_Assert(inputs.size() > 0); CV_Assert(reduceDims.size() != 0 && inputs[0].size() >= reduceDims.size()); std::vector outShape; if (inputs[0].size() == reduceDims.size()) outShape.push_back(1); else { for (int i = 0; i < inputs[0].size() - reduceDims.size(); i++) { outShape.push_back(inputs[0][i]); } } outputs.assign(1, outShape); return false; } virtual bool tryQuantize(const std::vector > &scales, const std::vector > &zeropoints, LayerParams& params) CV_OVERRIDE { return false; } virtual int64 getFLOPS(const std::vector &inputs, const std::vector &outputs) const CV_OVERRIDE { CV_UNUSED(inputs); // suppress unused variable warning long flops = 0; size_t totalDeleted = std::accumulate(reduceDims.begin(), reduceDims.end(), 1, std::multiplies()); for (int i = 0; i < outputs.size(); i++) { flops += total(outputs[i])*(totalDeleted); } return flops; } private: enum Type { MAX, MIN }; }; Ptr ReduceLayerInt8::create(const LayerParams& params) { return Ptr(new ReduceLayerInt8Impl(params)); } } }