Path: blob/master/modules/dnn/src/layers/permute_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"45#include "../op_vkcom.hpp"46#include <float.h>47#include <algorithm>4849#ifdef HAVE_OPENCL50#include "opencl_kernels_dnn.hpp"51#endif5253namespace cv54{55namespace dnn56{57class PermuteLayerImpl CV_FINAL : public PermuteLayer58{59public:60void checkNeedForPermutation()61{62_needsPermute = false;63for (size_t i = 0; i < _numAxes; ++i)64{65if (_order[i] != i)66{67_needsPermute = true;68break;69}70}71}7273PermuteLayerImpl(const LayerParams ¶ms)74: _count(0), _needsPermute(false), _numAxes(0)75{76if (!params.has("order"))77{78return;79}8081DictValue paramOrder = params.get("order");82_numAxes = paramOrder.size();8384for (size_t i = 0; i < _numAxes; i++)85{86int currentOrder = paramOrder.get<int>(i);87if (currentOrder < 0 || currentOrder > _numAxes)88{89CV_Error(Error::StsBadArg,90format("Orders of dimensions in Permute layer parameter"91"must be in [0...%zu]", _numAxes - 1));92}93if (std::find(_order.begin(), _order.end(), currentOrder) != _order.end())94{95CV_Error(Error::StsBadArg,96"Permute layer parameter contains duplicated orders.");97}98_order.push_back(currentOrder);99}100101setParamsFrom(params);102checkNeedForPermutation();103}104105virtual bool supportBackend(int backendId) CV_OVERRIDE106{107return backendId == DNN_BACKEND_OPENCV ||108backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine() ||109backendId == DNN_BACKEND_VKCOM && haveVulkan();110}111112bool getMemoryShapes(const std::vector<MatShape> &inputs,113const int requiredOutputs,114std::vector<MatShape> &outputs,115std::vector<MatShape> &internals) const CV_OVERRIDE116{117if(!_needsPermute)118{119Layer::getMemoryShapes(inputs, requiredOutputs, outputs, internals);120return true;121}122123CV_Assert(inputs.size() > 0);124CV_Assert((int)_numAxes == inputs[0].size());125126MatShape shapeBefore = inputs[0], shapeAfter;127for (size_t i = 0; i < _numAxes; i++)128{129shapeAfter.push_back(shapeBefore[_order[i]]);130}131132outputs.clear();133134for (size_t i = 0; i < inputs.size(); i++)135{136CV_Assert(total(inputs[i]) == total(shapeAfter));137outputs.push_back(shapeAfter);138}139140return false;141}142143void computeStrides(const MatShape &shapeBefore, const MatShape &shapeAfter)144{145_oldStride.resize(_numAxes);146_newStride.resize(_numAxes);147148_oldStride[_numAxes - 1] = 1;149_newStride[_numAxes - 1] = 1;150151for(int i = _numAxes - 2; i >= 0; i--)152{153_oldStride[i] = _oldStride[i + 1] * shapeBefore[i + 1];154_newStride[i] = _newStride[i + 1] * shapeAfter[i + 1];155}156157_count = _oldStride[0] * shapeBefore[0];158}159160void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr) CV_OVERRIDE161{162if(!_needsPermute)163{164return;165}166std::vector<Mat> inputs, outputs;167inputs_arr.getMatVector(inputs);168outputs_arr.getMatVector(outputs);169170CV_Assert(inputs.size() > 0);171const Mat& inp0 = inputs[0];172CV_Assert((int)_numAxes == inp0.dims);173174computeStrides(shape(inputs[0]), shape(outputs[0]));175176#ifdef HAVE_OPENCL177if (uorder.empty())178{179std::vector<int> orderVec(_order.begin(), _order.end());;180Mat morder(1, orderVec.size(), CV_32SC1, &orderVec[0]);181182std::vector<int> oldStrideVec(_oldStride.begin(), _oldStride.end());183Mat mold_stride(1, _oldStride.size(), CV_32SC1, &oldStrideVec[0]);184185std::vector<int> newStrideVec(_newStride.begin(), _newStride.end());186Mat mnew_stride(1, newStrideVec.size(), CV_32SC1, &newStrideVec[0]);187188morder.copyTo(uorder);189mold_stride.copyTo(uold_stride);190mnew_stride.copyTo(unew_stride);191}192#endif193}194195class PermuteInvoker : public ParallelLoopBody196{197public:198const Mat* inp;199Mat* out;200const std::vector<size_t>* order;201int nstripes;202203static void run(const Mat& inp, Mat& out, const std::vector<size_t>& order, int nstripes)204{205PermuteInvoker p;206p.inp = &inp;207p.out = &out;208p.order = ℴ209p.nstripes = nstripes;210211CV_Assert( out.size[0] == inp.size[order[0]] &&212out.size[1] == inp.size[order[1]] &&213out.size[2] == inp.size[order[2]] &&214out.size[3] == inp.size[order[3]]);215216parallel_for_(Range(0, nstripes), p, nstripes);217}218219PermuteInvoker() : inp(0), out(0), order(0), nstripes(0) {}220221void operator()(const Range& r) const CV_OVERRIDE222{223int n0 = out->size[0], n1 = out->size[1], n2 = out->size[2], n3 = out->size[3];224225size_t orows = (size_t)n0*n1*n2;226size_t stripeSize = (orows + nstripes - 1)/nstripes;227size_t stripeStart = r.start*stripeSize;228size_t stripeEnd = std::min(r.end*stripeSize, orows);229230const size_t esz = sizeof(float);231size_t ostep0 = out->step[0]/esz, ostep1 = out->step[1]/esz, ostep2 = out->step[2]/esz;232const size_t* ord = &order->at(0);233size_t istep0 = inp->step[ord[0]]/esz, istep1 = inp->step[ord[1]]/esz,234istep2 = inp->step[ord[2]]/esz, istep3 = inp->step[ord[3]]/esz;235236size_t val = stripeStart;237int i2 = (int)(val % n2);238val /= n2;239int i1 = (int)(val % n1);240int i0 = (int)(val / n1);241242const float* inptr_orig = inp->ptr<float>();243float* outptr_orig = out->ptr<float>();244245for( size_t ofs = stripeStart; ofs < stripeEnd; ofs++ )246{247const float* inptr = inptr_orig + i0*istep0 + i1*istep1 + i2*istep2;248float* outptr = outptr_orig + i0*ostep0 + i1*ostep1 + i2*ostep2;249250for( int i3 = 0; i3 < n3; i3++ )251outptr[i3] = inptr[i3*istep3];252253if( ++i2 >= n2 )254{255i2 = 0;256if( ++i1 >= n1 )257{258i1 = 0;259if( ++i0 >= n0 )260break;261}262}263}264}265};266267#ifdef HAVE_OPENCL268bool forward_ocl(InputArrayOfArrays inps, OutputArrayOfArrays outs, OutputArrayOfArrays internals)269{270std::vector<UMat> inputs;271std::vector<UMat> outputs;272273inps.getUMatVector(inputs);274outs.getUMatVector(outputs);275276if (!_needsPermute)277return false;278279bool use_half = (inps.depth() == CV_16S);280String opts = format("-DDtype=%s", use_half ? "half" : "float");281for (size_t i = 0; i < inputs.size(); i++)282{283ocl::Kernel kernel("permute", ocl::dnn::permute_oclsrc, opts);284285kernel.set(0, (int)_count);286kernel.set(1, ocl::KernelArg::PtrReadOnly(inputs[i]));287kernel.set(2, ocl::KernelArg::PtrReadOnly(uorder));288kernel.set(3, ocl::KernelArg::PtrReadOnly(uold_stride));289kernel.set(4, ocl::KernelArg::PtrReadOnly(unew_stride));290kernel.set(5, (int)_numAxes);291kernel.set(6, ocl::KernelArg::PtrWriteOnly(outputs[i]));292293if (!kernel.run(1, &_count, NULL, false))294return false;295}296297return true;298}299#endif300301void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE302{303CV_TRACE_FUNCTION();304CV_TRACE_ARG_VALUE(name, "name", name.c_str());305306CV_OCL_RUN(IS_DNN_OPENCL_TARGET(preferableTarget),307forward_ocl(inputs_arr, outputs_arr, internals_arr))308309if (inputs_arr.depth() == CV_16S)310{311forward_fallback(inputs_arr, outputs_arr, internals_arr);312return;313}314315std::vector<Mat> inputs, outputs;316inputs_arr.getMatVector(inputs);317outputs_arr.getMatVector(outputs);318319size_t k, ninputs = inputs.size();320if(!_needsPermute)321{322for (k = 0; k < ninputs; k++)323{324CV_Assert(outputs[k].total() == inputs[k].total());325if (outputs[k].data != inputs[k].data)326inputs[k].copyTo(outputs[k]);327}328}329else330{331size_t i, j, count = _count, numAxes = _numAxes;332const size_t* newStride = &_newStride[0];333const size_t* oldStride = &_oldStride[0];334const size_t* order = &_order[0];335336for (k = 0; k < ninputs; k++)337{338const Mat& inp = inputs[k];339Mat& out = outputs[k];340341CV_Assert(inp.dims == numAxes && inp.size == inputs[0].size);342CV_Assert(out.dims == numAxes && out.size == outputs[0].size);343344CV_Assert(inp.isContinuous() && out.isContinuous());345CV_Assert(inp.type() == CV_32F && out.type() == CV_32F);346347if( numAxes == 4 )348{349int nstripes = getNumThreads();350PermuteInvoker::run(inp, out, _order, nstripes);351}352else353{354const float *srcData = inp.ptr<float>();355float *dstData = out.ptr<float>();356357for (i = 0; i < count; ++i)358{359size_t oldPosition = 0;360size_t newPosition = i;361362for (j = 0; j < numAxes; ++j)363{364oldPosition += (newPosition / newStride[j]) * oldStride[order[j]];365newPosition %= newStride[j];366}367dstData[i] = srcData[oldPosition];368}369}370}371}372}373374virtual Ptr<BackendNode> initVkCom(const std::vector<Ptr<BackendWrapper> > &input) CV_OVERRIDE375{376#ifdef HAVE_VULKAN377CV_Assert(!_order.empty());378std::shared_ptr<vkcom::OpBase> op(new vkcom::OpPermute(_order));379return Ptr<BackendNode>(new VkComBackendNode(input, op));380#endif // HAVE_VULKAN381return Ptr<BackendNode>();382}383384virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&) CV_OVERRIDE385{386#ifdef HAVE_INF_ENGINE387InferenceEngine::LayerParams lp;388lp.name = name;389lp.type = "Permute";390lp.precision = InferenceEngine::Precision::FP32;391std::shared_ptr<InferenceEngine::CNNLayer> ieLayer(new InferenceEngine::CNNLayer(lp));392393CV_Assert(!_order.empty());394ieLayer->params["order"] = format("%zu", _order[0]);395for (int i = 1; i < _order.size(); ++i)396ieLayer->params["order"] += format(",%zu", _order[i]);397398return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));399#endif // HAVE_INF_ENGINE400return Ptr<BackendNode>();401}402403size_t _count;404std::vector<size_t> _order;405406std::vector<int> _oldDimensionSize;407std::vector<int> _newDimensionSize;408409std::vector<size_t> _oldStride;410std::vector<size_t> _newStride;411bool _needsPermute;412413#ifdef HAVE_OPENCL414UMat uorder, uold_stride, unew_stride;415#endif416417size_t _numAxes;418};419420Ptr<PermuteLayer> PermuteLayer::create(const LayerParams ¶ms)421{422return Ptr<PermuteLayer>(new PermuteLayerImpl(params));423}424425}426}427428429