// 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 inputBlobsId; std::set inputLayersId; std::set requiredOutputs; std::vector consumers; std::vector> outputBlobsWrappers; std::vector> inputBlobsWrappers; std::vector> 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 cudaD2HBackgroundTransfers; #endif Ptr layerInstance; std::vector outputBlobs; std::vector inputBlobs; std::vector internals; // Computation nodes of implemented backends (except DEFAULT). std::map> 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 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 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 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& names) { outNames.assign(names.begin(), names.end()); shapes.clear(); shapes.resize(outNames.size()); } void setInputShape(const String& tgtName, const MatShape& shape) { std::vector::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& inputs, const int requiredOutputs, std::vector& outputs, std::vector& 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 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 outNames; std::vector shapes; // Preprocessing parameters for each network's input. std::vector scaleFactors; std::vector means; std::vector inputsData; bool skip; }; // DataLayer } // namespace detail CV__DNN_INLINE_NS_END }} // namespace cv::dnn #endif // __OPENCV_DNN_SRC_LAYER_INTERNALS_HPP__