mirror of
https://github.com/opencv/opencv.git
synced 2025-06-22 03:22:10 +08:00

CUDA backend for the DNN module * stub cuda4dnn design * minor fixes for tests and doxygen * add csl public api directory to module headers * add low-level CSL components * add high-level CSL components * integrate csl::Tensor into backbone code * switch to CPU iff unsupported; otherwise, fail on error * add fully connected layer * add softmax layer * add activation layers * support arbitary rank TensorDescriptor * pass input wrappers to `initCUDA()` * add 1d/2d/3d-convolution * add pooling layer * reorganize and refactor code * fixes for gcc, clang and doxygen; remove cxx14/17 code * add blank_layer * add LRN layer * add rounding modes for pooling layer * split tensor.hpp into tensor.hpp and tensor_ops.hpp * add concat layer * add scale layer * add batch normalization layer * split math.cu into activations.cu and math.hpp * add eltwise layer * add flatten layer * add tensor transform api * add asymmetric padding support for convolution layer * add reshape layer * fix rebase issues * add permute layer * add padding support for concat layer * refactor and reorganize code * add normalize layer * optimize bias addition in scale layer * add prior box layer * fix and optimize normalize layer * add asymmetric padding support for pooling layer * add event API * improve pooling performance for some padding scenarios * avoid over-allocation of compute resources to kernels * improve prior box performance * enable layer fusion * add const layer * add resize layer * add slice layer * add padding layer * add deconvolution layer * fix channelwise ReLU initialization * add vector traits * add vectorized versions of relu, clipped_relu, power * add vectorized concat kernels * improve concat_with_offsets performance * vectorize scale and bias kernels * add support for multi-billion element tensors * vectorize prior box kernels * fix address alignment check * improve bias addition performance of conv/deconv/fc layers * restructure code for supporting multiple targets * add DNN_TARGET_CUDA_FP64 * add DNN_TARGET_FP16 * improve vectorization * add region layer * improve tensor API, add dynamic ranks 1. use ManagedPtr instead of a Tensor in backend wrapper 2. add new methods to tensor classes - size_range: computes the combined size of for a given axis range - tensor span/view can be constructed from a raw pointer and shape 3. the tensor classes can change their rank at runtime (previously rank was fixed at compile-time) 4. remove device code from tensor classes (as they are unused) 5. enforce strict conditions on tensor class APIs to improve debugging ability * fix parametric relu activation * add squeeze/unsqueeze tensor API * add reorg layer * optimize permute and enable 2d permute * enable 1d and 2d slice * add split layer * add shuffle channel layer * allow tensors of different ranks in reshape primitive * patch SliceOp to allow Crop Layer * allow extra shape inputs in reshape layer * use `std::move_backward` instead of `std::move` for insert in resizable_static_array * improve workspace management * add spatial LRN * add nms (cpu) to region layer * add max pooling with argmax ( and a fix to limits.hpp) * add max unpooling layer * rename DNN_TARGET_CUDA_FP32 to DNN_TARGET_CUDA * update supportBackend to be more rigorous * remove stray include from preventing non-cuda build * include op_cuda.hpp outside condition #if * refactoring, fixes and many optimizations * drop DNN_TARGET_CUDA_FP64 * fix gcc errors * increase max. tensor rank limit to six * add Interp layer * drop custom layers; use BackendNode * vectorize activation kernels * fixes for gcc * remove wrong assertion * fix broken assertion in unpooling primitive * fix build errors in non-CUDA build * completely remove workspace from public API * fix permute layer * enable accuracy and perf. tests for DNN_TARGET_CUDA * add asynchronous forward * vectorize eltwise ops * vectorize fill kernel * fixes for gcc * remove CSL headers from public API * remove csl header source group from cmake * update min. cudnn version in cmake * add numerically stable FP32 log1pexp * refactor code * add FP16 specialization to cudnn based tensor addition * vectorize scale1 and bias1 + minor refactoring * fix doxygen build * fix invalid alignment assertion * clear backend wrappers before allocateLayers * ignore memory lock failures * do not allocate internal blobs * integrate NVTX * add numerically stable half precision log1pexp * fix indentation, following coding style, improve docs * remove accidental modification of IE code * Revert "add asynchronous forward" This reverts commit 1154b9da9da07e9b52f8a81bdcea48cf31c56f70. * [cmake] throw error for unsupported CC versions * fix rebase issues * add more docs, refactor code, fix bugs * minor refactoring and fixes * resolve warnings/errors from clang * remove haveCUDA() checks from supportBackend() * remove NVTX integration * changes based on review comments * avoid exception when no CUDA device is present * add color code for CUDA in Net::dump
253 lines
9.1 KiB
C++
253 lines
9.1 KiB
C++
// 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.
|
|
|
|
// Copyright (C) 2017, Intel Corporation, all rights reserved.
|
|
// Third party copyrights are property of their respective owners.
|
|
|
|
/*
|
|
Implementation of padding layer, which adds paddings to input blob.
|
|
*/
|
|
|
|
#include "../precomp.hpp"
|
|
#include "layers_common.hpp"
|
|
#include "../op_cuda.hpp"
|
|
#include "../op_halide.hpp"
|
|
#include "../op_inf_engine.hpp"
|
|
#include <vector>
|
|
|
|
#ifdef HAVE_CUDA
|
|
#include "../cuda4dnn/primitives/padding.hpp"
|
|
using namespace cv::dnn::cuda4dnn;
|
|
#endif
|
|
|
|
namespace cv
|
|
{
|
|
namespace dnn
|
|
{
|
|
|
|
class PaddingLayerImpl CV_FINAL : public PaddingLayer
|
|
{
|
|
public:
|
|
PaddingLayerImpl(const LayerParams ¶ms)
|
|
{
|
|
setParamsFrom(params);
|
|
paddingValue = params.get<float>("value", 0);
|
|
inputDims = params.get<int>("input_dims", -1);
|
|
paddingType = params.get<String>("type", "constant");
|
|
|
|
CV_Assert(params.has("paddings"));
|
|
const DictValue& paddingsParam = params.get("paddings");
|
|
CV_Assert((paddingsParam.size() & 1) == 0);
|
|
|
|
paddings.resize(paddingsParam.size() / 2);
|
|
for (int i = 0; i < paddings.size(); ++i)
|
|
{
|
|
paddings[i].first = paddingsParam.get<int>(i * 2); // Pad before.
|
|
paddings[i].second = paddingsParam.get<int>(i * 2 + 1); // Pad after.
|
|
CV_Assert_N(paddings[i].first >= 0, paddings[i].second >= 0);
|
|
}
|
|
}
|
|
|
|
bool getMemoryShapes(const std::vector<MatShape> &inputs,
|
|
const int requiredOutputs,
|
|
std::vector<MatShape> &outputs,
|
|
std::vector<MatShape> &internals) const CV_OVERRIDE
|
|
{
|
|
CV_Assert(inputs.size() == 1);
|
|
const MatShape& inpShape = inputs[0];
|
|
CV_Assert(inpShape.size() >= paddings.size());
|
|
CV_Assert(inputDims == -1 || inpShape.size() == inputDims || inpShape.size() > paddings.size());
|
|
|
|
outputs.resize(1, inpShape);
|
|
int offset = (inputDims == -1 ? 0 : (inpShape.size() > inputDims ? 1 : 0));
|
|
for (int i = 0; i < paddings.size(); ++i)
|
|
{
|
|
outputs[0][offset + i] = inpShape[offset + i] + paddings[i].first + paddings[i].second;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays) CV_OVERRIDE
|
|
{
|
|
std::vector<Mat> inputs;
|
|
inputs_arr.getMatVector(inputs);
|
|
|
|
// Compute dstRanges.
|
|
const MatSize& inpShape = inputs[0].size;
|
|
|
|
if (inputDims != -1 && inputs[0].dims != inputDims)
|
|
{
|
|
paddings.insert(paddings.begin(), std::make_pair(0, 0));
|
|
}
|
|
|
|
dstRanges.resize(paddings.size());
|
|
for (int i = 0; i < paddings.size(); ++i)
|
|
{
|
|
dstRanges[i].start = paddings[i].first;
|
|
dstRanges[i].end = paddings[i].first + inpShape[i];
|
|
}
|
|
|
|
// Add the rest of dimensions.
|
|
for (int i = dstRanges.size(); i < inputs[0].dims; ++i)
|
|
{
|
|
dstRanges.push_back(Range::all());
|
|
paddings.push_back(std::make_pair(0, 0));
|
|
}
|
|
inputDims = -1; // Next time paddings are filled for all the dimensions.
|
|
}
|
|
|
|
virtual bool supportBackend(int backendId) CV_OVERRIDE
|
|
{
|
|
#ifdef HAVE_INF_ENGINE
|
|
if (backendId == DNN_BACKEND_INFERENCE_ENGINE)
|
|
return INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2019R1) &&
|
|
(preferableTarget != DNN_TARGET_MYRIAD ||
|
|
(dstRanges.size() == 4 && paddings[0].first == 0 && paddings[0].second == 0));
|
|
#endif
|
|
return backendId == DNN_BACKEND_OPENCV ||
|
|
backendId == DNN_BACKEND_CUDA ||
|
|
(backendId == DNN_BACKEND_HALIDE && haveHalide() && dstRanges.size() == 4);
|
|
}
|
|
|
|
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<Mat> inputs, outputs;
|
|
inputs_arr.getMatVector(inputs);
|
|
outputs_arr.getMatVector(outputs);
|
|
|
|
if (paddingType == "constant")
|
|
{
|
|
if (inputs_arr.depth() == CV_16S)
|
|
{
|
|
std::vector<float> paddingValue_fp32(1, paddingValue);
|
|
std::vector<int16_t> paddingValue_fp16(1);
|
|
cv::convertFp16(paddingValue_fp32, paddingValue_fp16);
|
|
outputs[0].setTo(paddingValue_fp16[0]);
|
|
}
|
|
else
|
|
outputs[0].setTo(paddingValue);
|
|
inputs[0].copyTo(outputs[0](dstRanges));
|
|
}
|
|
else if (paddingType == "reflect")
|
|
{
|
|
CV_Assert(inputs.size() == 1);
|
|
CV_Assert(outputs.size() == 1);
|
|
CV_Assert(inputs[0].dims == 4);
|
|
CV_Assert(outputs[0].dims == 4);
|
|
|
|
if (inputs[0].size[0] != outputs[0].size[0] || inputs[0].size[1] != outputs[0].size[1])
|
|
CV_Error(Error::StsNotImplemented, "Only spatial reflection padding is supported.");
|
|
|
|
const int inpHeight = inputs[0].size[2];
|
|
const int inpWidth = inputs[0].size[3];
|
|
const int outHeight = outputs[0].size[2];
|
|
const int outWidth = outputs[0].size[3];
|
|
const int padTop = dstRanges[2].start;
|
|
const int padBottom = outHeight - dstRanges[2].end;
|
|
const int padLeft = dstRanges[3].start;
|
|
const int padRight = outWidth - dstRanges[3].end;
|
|
CV_CheckLT(padTop, inpHeight, ""); CV_CheckLT(padBottom, inpHeight, "");
|
|
CV_CheckLT(padLeft, inpWidth, ""); CV_CheckLT(padRight, inpWidth, "");
|
|
|
|
for (size_t n = 0; n < inputs[0].size[0]; ++n)
|
|
{
|
|
for (size_t ch = 0; ch < inputs[0].size[1]; ++ch)
|
|
{
|
|
copyMakeBorder(getPlane(inputs[0], n, ch),
|
|
getPlane(outputs[0], n, ch),
|
|
padTop, padBottom, padLeft, padRight,
|
|
BORDER_REFLECT_101);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
CV_Error(Error::StsNotImplemented, "Unknown padding type: " + paddingType);
|
|
}
|
|
|
|
#ifdef HAVE_CUDA
|
|
Ptr<BackendNode> initCUDA(
|
|
void *context_,
|
|
const std::vector<Ptr<BackendWrapper>>& inputs,
|
|
const std::vector<Ptr<BackendWrapper>>& outputs
|
|
) override
|
|
{
|
|
auto context = reinterpret_cast<csl::CSLContext*>(context_);
|
|
|
|
cuda4dnn::PaddingType ptype;
|
|
if (paddingType == "constant")
|
|
ptype = PaddingType::CONSTANT;
|
|
else if (paddingType == "reflect")
|
|
ptype = PaddingType::REFLECTION101;
|
|
else
|
|
CV_Error(Error::StsNotImplemented, "Unsupported padding mode");
|
|
|
|
return make_cuda_node<cuda4dnn::PaddingOp>(preferableTarget, std::move(context->stream), ptype, paddingValue, dstRanges);
|
|
}
|
|
#endif
|
|
|
|
virtual Ptr<BackendNode> initHalide(const std::vector<Ptr<BackendWrapper> > &inputs) CV_OVERRIDE
|
|
{
|
|
#ifdef HAVE_HALIDE
|
|
int inW, inH, inC, inN;
|
|
int minN = std::max(dstRanges[0].start, 0);
|
|
int minC = std::max(dstRanges[1].start, 0);
|
|
int minY = std::max(dstRanges[2].start, 0);
|
|
int minX = std::max(dstRanges[3].start, 0);
|
|
Halide::Buffer<float> inputBuffer = halideBuffer(inputs[0]);
|
|
getCanonicalSize(inputBuffer, &inW, &inH, &inC, &inN);
|
|
|
|
Halide::Var x("x"), y("y"), c("c"), n("n");
|
|
Halide::Func top = (name.empty() ? Halide::Func() : Halide::Func(name));
|
|
Halide::Func padded =
|
|
Halide::BoundaryConditions::constant_exterior(inputBuffer, paddingValue);
|
|
top(x, y, c, n) = padded(x - minX, y - minY, c - minC, n - minN);
|
|
return Ptr<BackendNode>(new HalideBackendNode(top));
|
|
#endif // HAVE_HALIDE
|
|
return Ptr<BackendNode>();
|
|
}
|
|
|
|
#ifdef HAVE_INF_ENGINE
|
|
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&) CV_OVERRIDE
|
|
{
|
|
InferenceEngine::Builder::Layer ieLayer(name);
|
|
ieLayer.setName(name);
|
|
ieLayer.setType("Pad");
|
|
|
|
std::vector<int> begins(paddings.size(), 0), ends(paddings.size(), 0);
|
|
for (int i = 0; i < paddings.size(); ++i)
|
|
{
|
|
begins[i] = paddings[i].first;
|
|
ends[i] = paddings[i].second;
|
|
}
|
|
ieLayer.getParameters()["pads_begin"] = begins;
|
|
ieLayer.getParameters()["pads_end"] = ends;
|
|
ieLayer.getParameters()["pad_mode"] = paddingType;
|
|
if (paddingType == "constant")
|
|
ieLayer.getParameters()["pad_value"] = paddingValue;
|
|
|
|
ieLayer.setInputPorts(std::vector<InferenceEngine::Port>(1));
|
|
ieLayer.setOutputPorts(std::vector<InferenceEngine::Port>(1));
|
|
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
|
|
}
|
|
#endif
|
|
|
|
private:
|
|
std::vector<std::pair<int, int> > paddings; // Pairs pad before, pad after.
|
|
std::vector<Range> dstRanges;
|
|
int inputDims;
|
|
float paddingValue;
|
|
std::string paddingType;
|
|
};
|
|
|
|
Ptr<PaddingLayer> PaddingLayer::create(const LayerParams ¶ms)
|
|
{
|
|
return Ptr<PaddingLayer>(new PaddingLayerImpl(params));
|
|
}
|
|
|
|
}
|
|
}
|