Path: blob/master/modules/dnn/src/layers/normalize_bbox_layer.cpp
16337 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2013, OpenCV Foundation, all rights reserved.13// Copyright (C) 2017, Intel Corporation, all rights reserved.14// Third party copyrights are property of their respective owners.15//16// Redistribution and use in source and binary forms, with or without modification,17// are permitted provided that the following conditions are met:18//19// * Redistribution's of source code must retain the above copyright notice,20// this list of conditions and the following disclaimer.21//22// * Redistribution's in binary form must reproduce the above copyright notice,23// this list of conditions and the following disclaimer in the documentation24// and/or other materials provided with the distribution.25//26// * The name of the copyright holders may not be used to endorse or promote products27// derived from this software without specific prior written permission.28//29// This software is provided by the copyright holders and contributors "as is" and30// any express or implied warranties, including, but not limited to, the implied31// warranties of merchantability and fitness for a particular purpose are disclaimed.32// In no event shall the Intel Corporation or contributors be liable for any direct,33// indirect, incidental, special, exemplary, or consequential damages34// (including, but not limited to, procurement of substitute goods or services;35// loss of use, data, or profits; or business interruption) however caused36// and on any theory of liability, whether in contract, strict liability,37// or tort (including negligence or otherwise) arising in any way out of38// the use of this software, even if advised of the possibility of such damage.39//40//M*/4142#include "../precomp.hpp"43#include "layers_common.hpp"44#include "../op_inf_engine.hpp"4546namespace cv { namespace dnn {4748class NormalizeBBoxLayerImpl CV_FINAL : public NormalizeBBoxLayer49{50public:51NormalizeBBoxLayerImpl(const LayerParams& params)52{53setParamsFrom(params);54pnorm = params.get<float>("p", 2);55epsilon = params.get<float>("eps", 1e-10f);56acrossSpatial = params.get<bool>("across_spatial", true);57startAxis = params.get<int>("start_axis", 1);58CV_Assert(!params.has("across_spatial") || !params.has("end_axis"));59endAxis = params.get<int>("end_axis", acrossSpatial ? -1 : startAxis);60CV_Assert(pnorm > 0);61}6263virtual bool supportBackend(int backendId) CV_OVERRIDE64{65if (backendId == DNN_BACKEND_INFERENCE_ENGINE)66{67if (pnorm != 2)68return false;69if (!blobs.empty())70return true;71if (preferableTarget == DNN_TARGET_MYRIAD)72return !acrossSpatial;73return startAxis == 1 && (!acrossSpatial || endAxis > 1);74}75else76return backendId == DNN_BACKEND_OPENCV;77}7879bool getMemoryShapes(const std::vector<MatShape> &inputs,80const int requiredOutputs,81std::vector<MatShape> &outputs,82std::vector<MatShape> &internals) const CV_OVERRIDE83{84CV_Assert(inputs.size() == 1);85Layer::getMemoryShapes(inputs, requiredOutputs, outputs, internals);86internals.resize(1, inputs[0]);87internals[0][0] = 1; // Batch size.88return true;89}9091void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays) CV_OVERRIDE92{93std::vector<Mat> inputs;94inputs_arr.getMatVector(inputs);95CV_Assert(inputs.size() == 1);96endAxis = endAxis == -1 ? (inputs[0].dims - 1) : endAxis;97startAxis = startAxis == -1 ? (inputs[0].dims - 1) : startAxis;98acrossSpatial = (startAxis == 1 && endAxis == inputs[0].dims - 1);99}100101#ifdef HAVE_OPENCL102bool forward_ocl(InputArrayOfArrays inputs_, OutputArrayOfArrays outputs_, OutputArrayOfArrays internals_)103{104std::vector<UMat> inputs;105std::vector<UMat> outputs;106std::vector<UMat> internals;107108if (inputs_.depth() == CV_16S)109return false;110111inputs_.getUMatVector(inputs);112outputs_.getUMatVector(outputs);113internals_.getUMatVector(internals);114115CV_Assert(inputs.size() == 1 && outputs.size() == 1);116CV_Assert(inputs[0].total() == outputs[0].total());117118const UMat& inp0 = inputs[0];119UMat& buffer = internals[0];120startAxis = clamp(startAxis, inp0.dims);121endAxis = clamp(endAxis, inp0.dims);122123size_t num = total(shape(inp0.size), 0, startAxis);124size_t numPlanes = total(shape(inp0.size), startAxis, endAxis + 1);125size_t planeSize = inp0.total() / (num * numPlanes);126MatShape s = shape(1, inputs[0].total());127UMat inp = inputs[0].reshape(1, s.size(), &s[0]).reshape(1, num);128UMat out = outputs[0].reshape(1, s.size(), &s[0]).reshape(1, num);129for (size_t i = 0; i < num; ++i)130{131s = shape(numPlanes, planeSize);132UMat src = inp.row(i).reshape(1, s.size(), &s[0]);133UMat dst = out.row(i).reshape(1, s.size(), &s[0]);134135UMat abs_mat;136absdiff(src, cv::Scalar::all(0), abs_mat);137pow(abs_mat, pnorm, buffer);138139if (planeSize == 1)140{141// add eps to avoid overflow142float absSum = sum(buffer)[0] + epsilon;143float norm = pow(absSum, 1.0f / pnorm);144multiply(src, 1.0f / norm, dst);145}146else147{148Mat norm;149reduce(buffer, norm, 0, REDUCE_SUM);150norm += epsilon;151152// compute inverted norm to call multiply instead divide153cv::pow(norm, -1.0f / pnorm, norm);154155repeat(norm, numPlanes, 1, buffer);156multiply(src, buffer, dst);157}158159if (!blobs.empty())160{161// scale the output162Mat scale = blobs[0];163if (scale.total() == 1)164{165// _scale: 1 x 1166multiply(dst, scale.at<float>(0, 0), dst);167}168else169{170// _scale: _channels x 1171CV_Assert(scale.total() == numPlanes);172repeat(scale, 1, dst.cols, buffer);173multiply(dst, buffer, dst);174}175}176}177return true;178}179#endif180181void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE182{183CV_TRACE_FUNCTION();184CV_TRACE_ARG_VALUE(name, "name", name.c_str());185186CV_OCL_RUN(IS_DNN_OPENCL_TARGET(preferableTarget),187forward_ocl(inputs_arr, outputs_arr, internals_arr))188189if (inputs_arr.depth() == CV_16S)190{191forward_fallback(inputs_arr, outputs_arr, internals_arr);192return;193}194195std::vector<Mat> inputs, outputs, internals;196inputs_arr.getMatVector(inputs);197outputs_arr.getMatVector(outputs);198internals_arr.getMatVector(internals);199200CV_Assert(inputs.size() == 1 && outputs.size() == 1);201CV_Assert(inputs[0].total() == outputs[0].total());202203const Mat& inp0 = inputs[0];204Mat& buffer = internals[0];205startAxis = clamp(startAxis, inp0.dims);206endAxis = clamp(endAxis, inp0.dims);207208const float* inpData = inp0.ptr<float>();209float* outData = outputs[0].ptr<float>();210211size_t num = total(shape(inp0.size), 0, startAxis);212size_t numPlanes = total(shape(inp0.size), startAxis, endAxis + 1);213CV_Assert(num * numPlanes != 0);214size_t planeSize = inp0.total() / (num * numPlanes);215for (size_t n = 0; n < num; ++n)216{217Mat src = Mat(numPlanes, planeSize, CV_32F, (void*)inpData);218Mat dst = Mat(numPlanes, planeSize, CV_32F, (void*)outData);219cv::pow(abs(src), pnorm, buffer);220221if (planeSize == 1)222{223// add eps to avoid overflow224float absSum = sum(buffer)[0] + epsilon;225float norm = pow(absSum, 1.0f / pnorm);226multiply(src, 1.0f / norm, dst);227}228else229{230Mat norm;231reduce(buffer, norm, 0, REDUCE_SUM);232norm += epsilon;233234// compute inverted norm to call multiply instead divide235cv::pow(norm, -1.0f / pnorm, norm);236237repeat(norm, numPlanes, 1, buffer);238multiply(src, buffer, dst);239}240241if (!blobs.empty())242{243// scale the output244Mat scale = blobs[0];245if (scale.total() == 1)246{247// _scale: 1 x 1248dst *= scale.at<float>(0, 0);249}250else251{252// _scale: _channels x 1253CV_Assert(scale.total() == numPlanes);254repeat(scale, 1, dst.cols, buffer);255multiply(dst, buffer, dst);256}257}258inpData += numPlanes * planeSize;259outData += numPlanes * planeSize;260}261}262263virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >& inputs) CV_OVERRIDE264{265#ifdef HAVE_INF_ENGINE266InferenceEngine::DataPtr input = infEngineDataNode(inputs[0]);267268InferenceEngine::LayerParams lp;269lp.name = name;270lp.precision = InferenceEngine::Precision::FP32;271272if (input->dims.size() == 4)273{274const int numChannels = input->dims[2]; // NOTE: input->dims are reversed (whcn)275276lp.type = "Normalize";277std::shared_ptr<InferenceEngine::CNNLayer> ieLayer(new InferenceEngine::CNNLayer(lp));278if (blobs.empty())279{280auto weights = InferenceEngine::make_shared_blob<float>(InferenceEngine::Precision::FP32,281InferenceEngine::Layout::C,282{(size_t)numChannels});283weights->allocate();284std::vector<float> ones(numChannels, 1);285weights->set(ones);286ieLayer->blobs["weights"] = weights;287ieLayer->params["channel_shared"] = "0";288}289else290{291CV_Assert(numChannels == blobs[0].total());292ieLayer->blobs["weights"] = wrapToInfEngineBlob(blobs[0], {(size_t)numChannels}, InferenceEngine::Layout::C);293ieLayer->params["channel_shared"] = blobs[0].total() == 1 ? "1" : "0";294}295ieLayer->params["eps"] = format("%f", epsilon);296ieLayer->params["across_spatial"] = acrossSpatial ? "1" : "0";297return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));298}299else300{301InferenceEngine::LayerParams lp;302lp.name = name;303lp.type = "GRN";304lp.precision = InferenceEngine::Precision::FP32;305std::shared_ptr<InferenceEngine::CNNLayer> ieLayer(new InferenceEngine::CNNLayer(lp));306ieLayer->params["bias"] = format("%f", epsilon);307return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));308}309#endif // HAVE_INF_ENGINE310return Ptr<BackendNode>();311}312313private:314int startAxis, endAxis;315};316317318Ptr<NormalizeBBoxLayer> NormalizeBBoxLayer::create(const LayerParams ¶ms)319{320return Ptr<NormalizeBBoxLayer>(new NormalizeBBoxLayerImpl(params));321}322323}324}325326327