mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
343 lines
10 KiB
343 lines
10 KiB
// 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. |
|
|
|
#ifndef __OPENCV_DNN_SRC_LAYER_INTERNALS_HPP__ |
|
#define __OPENCV_DNN_SRC_LAYER_INTERNALS_HPP__ |
|
|
|
namespace cv { namespace dnn { |
|
CV__DNN_INLINE_NS_BEGIN |
|
inline namespace detail { |
|
|
|
struct LayerPin |
|
{ |
|
int lid; |
|
int oid; |
|
|
|
LayerPin(int layerId = -1, int outputId = -1) |
|
: lid(layerId) |
|
, oid(outputId) |
|
{} |
|
|
|
bool valid() const |
|
{ |
|
return (lid >= 0 && oid >= 0); |
|
} |
|
|
|
bool equal(const LayerPin& r) const |
|
{ |
|
return (lid == r.lid && oid == r.oid); |
|
} |
|
|
|
bool operator<(const LayerPin& r) const |
|
{ |
|
return lid < r.lid || (lid == r.lid && oid < r.oid); |
|
} |
|
|
|
bool operator==(const LayerPin& r) const |
|
{ |
|
return lid == r.lid && oid == r.oid; |
|
} |
|
}; |
|
|
|
struct LayerData |
|
{ |
|
LayerData() |
|
: id(-1) |
|
, dtype(CV_32F) |
|
, skip(false) |
|
, flag(0) |
|
{} |
|
LayerData(int _id, const String& _name, const String& _type, const int& _dtype, LayerParams& _params) |
|
: id(_id) |
|
, name(_name) |
|
, type(_type) |
|
, dtype(_dtype) |
|
, params(_params) |
|
, skip(false) |
|
, flag(0) |
|
{ |
|
CV_TRACE_FUNCTION(); |
|
|
|
// add logging info |
|
params.name = name; |
|
params.type = type; |
|
} |
|
|
|
int id; |
|
String name; |
|
String type; |
|
int dtype; // Datatype of output blobs. |
|
LayerParams params; |
|
|
|
std::vector<LayerPin> inputBlobsId; |
|
std::set<int> inputLayersId; |
|
std::set<int> requiredOutputs; |
|
std::vector<LayerPin> consumers; |
|
std::vector<Ptr<BackendWrapper>> outputBlobsWrappers; |
|
std::vector<Ptr<BackendWrapper>> inputBlobsWrappers; |
|
std::vector<Ptr<BackendWrapper>> internalBlobsWrappers; |
|
|
|
#ifdef HAVE_CUDA |
|
/* output ids which must be transferred to the host in the background |
|
* after the completion of the forward pass of the layer |
|
*/ |
|
std::vector<int> cudaD2HBackgroundTransfers; |
|
#endif |
|
|
|
Ptr<Layer> layerInstance; |
|
std::vector<Mat> outputBlobs; |
|
std::vector<Mat*> inputBlobs; |
|
std::vector<Mat> internals; |
|
// Computation nodes of implemented backends (except DEFAULT). |
|
std::map<int, Ptr<BackendNode>> backendNodes; |
|
// Flag for skip layer computation for specific backend. |
|
bool skip; |
|
|
|
int flag; |
|
|
|
|
|
void resetAllocation() |
|
{ |
|
if (id == 0) |
|
return; // skip "input" layer (assertion in Net::Impl::allocateLayers) |
|
|
|
layerInstance.release(); |
|
outputBlobs.clear(); |
|
inputBlobs.clear(); |
|
internals.clear(); |
|
|
|
outputBlobsWrappers.clear(); |
|
inputBlobsWrappers.clear(); |
|
internalBlobsWrappers.clear(); |
|
|
|
backendNodes.clear(); |
|
|
|
skip = false; |
|
flag = 0; |
|
|
|
#ifdef HAVE_CUDA |
|
cudaD2HBackgroundTransfers.clear(); |
|
#endif |
|
} |
|
}; |
|
|
|
|
|
// fake layer containing network input blobs |
|
struct DataLayer : public Layer |
|
{ |
|
DataLayer() |
|
: Layer() |
|
{ |
|
skip = false; |
|
} |
|
|
|
virtual bool supportBackend(int backendId) CV_OVERRIDE |
|
{ |
|
return backendId == DNN_BACKEND_OPENCV; |
|
} |
|
|
|
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()); |
|
|
|
// FIXIT: add wrapper without exception suppression |
|
CV_OCL_RUN(IS_DNN_OPENCL_TARGET(preferableTarget), |
|
forward_ocl(inputs_arr, outputs_arr, internals_arr)) |
|
|
|
bool isFP16 = outputs_arr.depth() == CV_16F; |
|
|
|
std::vector<Mat> outputs, internals; |
|
outputs_arr.getMatVector(outputs); |
|
internals_arr.getMatVector(internals); |
|
|
|
for (int i = 0; i < inputsData.size(); ++i) |
|
{ |
|
double scale = scaleFactors[i]; |
|
Scalar& mean = means[i]; |
|
|
|
CV_Assert(mean == Scalar() || inputsData[i].size[1] <= 4); |
|
if (isFP16) |
|
CV_CheckTypeEQ(outputs[i].type(), CV_16FC1, ""); |
|
else |
|
CV_CheckTypeEQ(outputs[i].type(), CV_32FC1, ""); |
|
|
|
bool singleMean = true; |
|
for (int j = 1; j < std::min(4, inputsData[i].size[1]) && singleMean; ++j) |
|
{ |
|
singleMean = mean[j] == mean[j - 1]; |
|
} |
|
|
|
if (singleMean) |
|
{ |
|
if (isFP16) |
|
{ |
|
Mat input_f32; |
|
inputsData[i].convertTo(input_f32, CV_32F, scale, -mean[0] * scale); |
|
input_f32.convertTo(outputs[i], CV_16F); |
|
} |
|
else |
|
{ |
|
inputsData[i].convertTo(outputs[i], CV_32F, scale, -mean[0] * scale); |
|
} |
|
} |
|
else |
|
{ |
|
for (int n = 0; n < inputsData[i].size[0]; ++n) |
|
{ |
|
for (int c = 0; c < inputsData[i].size[1]; ++c) |
|
{ |
|
Mat inp = getPlane(inputsData[i], n, c); |
|
Mat out = getPlane(outputs[i], n, c); |
|
if (isFP16) |
|
{ |
|
Mat input_f32; |
|
inp.convertTo(input_f32, CV_32F, scale, -mean[c] * scale); |
|
input_f32.convertTo(out, CV_16F); |
|
} |
|
else |
|
{ |
|
inp.convertTo(out, CV_32F, scale, -mean[c] * scale); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
#ifdef HAVE_OPENCL |
|
bool forward_ocl(InputArrayOfArrays, OutputArrayOfArrays outputs_, OutputArrayOfArrays internals_) |
|
{ |
|
bool isFP16 = outputs_.depth() == CV_16F; |
|
|
|
std::vector<UMat> outputs; |
|
outputs_.getUMatVector(outputs); |
|
|
|
for (int i = 0; i < inputsData.size(); ++i) |
|
{ |
|
Mat inputData = inputsData[i]; |
|
|
|
double scale = scaleFactors[i]; |
|
Scalar& mean = means[i]; |
|
|
|
CV_Assert(mean == Scalar() || inputData.size[1] <= 4); |
|
if (isFP16) |
|
CV_CheckTypeEQ(outputs[i].type(), CV_16FC1, ""); |
|
else |
|
CV_CheckTypeEQ(outputs[i].type(), CV_32FC1, ""); |
|
|
|
bool singleMean = true; |
|
for (int j = 1; j < std::min(4, inputData.size[1]) && singleMean; ++j) |
|
{ |
|
singleMean = mean[j] == mean[j - 1]; |
|
} |
|
|
|
if (singleMean) |
|
{ |
|
if (isFP16) |
|
{ |
|
UMat input_i; |
|
inputData.convertTo(input_i, CV_32F, scale, -mean[0] * scale); |
|
input_i.convertTo(outputs[i], CV_16F); |
|
} |
|
else |
|
{ |
|
inputData.convertTo(outputs[i], CV_32F, scale, -mean[0] * scale); |
|
} |
|
} |
|
else |
|
{ |
|
for (int n = 0; n < inputData.size[0]; ++n) |
|
{ |
|
for (int c = 0; c < inputData.size[1]; ++c) |
|
{ |
|
Mat inp = getPlane(inputData, n, c); |
|
|
|
std::vector<cv::Range> plane(4, Range::all()); |
|
plane[0] = Range(n, n + 1); |
|
plane[1] = Range(c, c + 1); |
|
UMat out = outputs[i](plane).reshape(1, inp.dims, inp.size); |
|
|
|
if (isFP16) |
|
{ |
|
UMat input_i; |
|
inp.convertTo(input_i, CV_32F, scale, -mean[c] * scale); |
|
input_i.convertTo(out, CV_16F); |
|
} |
|
else |
|
{ |
|
inp.convertTo(out, CV_32F, scale, -mean[c] * scale); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
return true; |
|
} |
|
#endif |
|
|
|
int outputNameToIndex(const String& tgtName) CV_OVERRIDE |
|
{ |
|
int idx = (int)(std::find(outNames.begin(), outNames.end(), tgtName) - outNames.begin()); |
|
return (idx < (int)outNames.size()) ? idx : -1; |
|
} |
|
|
|
void setNames(const std::vector<String>& names) |
|
{ |
|
outNames.assign(names.begin(), names.end()); |
|
shapes.clear(); |
|
shapes.resize(outNames.size()); |
|
} |
|
|
|
void setInputShape(const String& tgtName, const MatShape& shape) |
|
{ |
|
std::vector<String>::const_iterator it = std::find(outNames.begin(), outNames.end(), tgtName); |
|
CV_Check(tgtName, it != outNames.end(), "Unknown input"); |
|
int idx = (int)(it - outNames.begin()); |
|
|
|
CV_Assert(idx < (int)shapes.size()); |
|
CV_Check(tgtName, shapes[idx].empty(), "Input shape redefinition is not allowed"); |
|
shapes[idx] = shape; |
|
} |
|
|
|
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() == requiredOutputs); |
|
outputs.assign(inputs.begin(), inputs.end()); |
|
return false; |
|
} |
|
|
|
virtual void finalize(InputArrayOfArrays, OutputArrayOfArrays outputs_arr) CV_OVERRIDE |
|
{ |
|
std::vector<Mat> outputs; |
|
outputs_arr.getMatVector(outputs); |
|
|
|
CV_Assert_N(outputs.size() == scaleFactors.size(), outputs.size() == means.size(), |
|
inputsData.size() == outputs.size()); |
|
skip = true; |
|
for (int i = 0; skip && i < inputsData.size(); ++i) |
|
{ |
|
if (inputsData[i].data != outputs[i].data || scaleFactors[i] != 1.0 || means[i] != Scalar()) |
|
skip = false; |
|
} |
|
} |
|
|
|
|
|
std::vector<String> outNames; |
|
std::vector<MatShape> shapes; |
|
// Preprocessing parameters for each network's input. |
|
std::vector<double> scaleFactors; |
|
std::vector<Scalar> means; |
|
std::vector<Mat> inputsData; |
|
bool skip; |
|
}; // DataLayer |
|
|
|
|
|
} // namespace detail |
|
CV__DNN_INLINE_NS_END |
|
}} // namespace cv::dnn |
|
#endif // __OPENCV_DNN_SRC_LAYER_INTERNALS_HPP__
|
|
|