1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-31 08:13:04 +04:00

cuda support and Layer Split + per-op executors

This commit is contained in:
Abhishek Gola
2026-06-08 18:06:28 +05:30
parent a5e4c04903
commit 72ffdfc170
32 changed files with 995 additions and 328 deletions
+87 -105
View File
@@ -262,23 +262,93 @@ CV__DNN_INLINE_NS_BEGIN
class CV_EXPORTS Graph;
class CV_EXPORTS ActivationLayer;
/** @brief This interface class allows to build new Layers - are building blocks of networks.
/** @brief Backend-independent description of a graph operation (node).
*
* Each class, derived from Layer, must implement forward() method to compute outputs.
* Also before using the new layer into networks you must register your layer by using one of @ref dnnLayerFactory "LayerFactory" macros.
* %OpData carries everything needed to reason about an operation *without* executing it:
* its parameters (#blobs and type-specific fields of derived classes), graph wiring
* (#inputs / #outputs as Arg indices) and shape/type/layout inference. The new DNN graph
* engine stores a topologically sorted sequence of %OpData nodes (see Graph::prog());
* executable, backend-specific instances (Layer subclasses) are constructed from an
* %OpData during Net::finalizeNet().
*
* Each operation type registers a `static Ptr<OpData> create(const LayerParams&)` factory
* via @ref CV_DNN_REGISTER_OP_CLASS_STATIC.
*/
class CV_EXPORTS_W Layer : public Algorithm
class CV_EXPORTS_W OpData : public Algorithm
{
public:
OpData();
explicit OpData(const LayerParams& params);
virtual ~OpData();
void setParamsFrom(const LayerParams& params);
//! List of learned parameters must be stored here to allow read them by using Net::getParam().
CV_PROP_RW std::vector<Mat> blobs;
std::vector<Arg> inputs;
std::vector<Arg> outputs;
void* netimpl;
void* netimpl = nullptr;
CV_PROP String name;
CV_PROP String type;
virtual std::vector<Ptr<Graph> >* subgraphs() const;
virtual int inputNameToIndex(String inputName); // FIXIT const
CV_WRAP virtual int outputNameToIndex(const String& outputName); // FIXIT const
virtual bool getMemoryShapes(const std::vector<MatShape> &inputs,
const int requiredOutputs,
std::vector<MatShape> &outputs,
std::vector<MatShape> &internals) const;
virtual void getTypes(const std::vector<MatType>& inputs,
const int requiredOutputs,
const int requiredInternals,
std::vector<MatType>&outputs,
std::vector<MatType>&internals) const;
virtual int getLayouts(const std::vector<DataLayout>& actualInputs,
std::vector<DataLayout>& desiredInputs,
const int requiredOutputs,
std::vector<DataLayout>& outputs) const;
virtual int64 getFLOPS(const std::vector<MatShape> &inputs,
const std::vector<MatShape> &outputs) const;
virtual bool updateMemoryShapes(const std::vector<MatShape> &inputs);
virtual bool alwaysSupportInplace() const;
virtual bool dynamicOutputShapes() const;
virtual bool isDataShuffling() const;
virtual void getScaleShift(Mat& scale, Mat& shift) const;
virtual void getScaleZeropoint(float& scale, int& zeropoint) const;
virtual std::ostream& dumpAttrs(std::ostream& strm, int indent) const;
virtual std::ostream& dump(std::ostream& strm, int indent, bool comma) const;
};
/** @brief This interface class allows to build new Layers - are building blocks of networks.
*
* A %Layer is the *executable*, backend-specific counterpart of an OpData node: it
* implements forward() (and finalize()) for a particular backend/target. In the new graph
* engine a %Layer is created from an OpData (held in #data) by Net::finalizeNet(); its
* inference methods (getMemoryShapes() etc., inherited from OpData) delegate to #data.
*
* Each class, derived from Layer, must implement forward() method to compute outputs.
* Also before using the new layer into networks you must register your layer by using one of @ref dnnLayerFactory "LayerFactory" macros.
*/
class CV_EXPORTS_W Layer : public OpData
{
public:
Ptr<OpData> data;
/** @brief Computes and sets internal parameters according to inputs, outputs and blobs.
* @deprecated Use Layer::finalize(InputArrayOfArrays, OutputArrayOfArrays) instead
* @param[in] input vector of already allocated input blobs
@@ -341,18 +411,6 @@ CV__DNN_INLINE_NS_BEGIN
CV_DEPRECATED CV_WRAP void run(const std::vector<Mat> &inputs, CV_OUT std::vector<Mat> &outputs,
CV_IN_OUT std::vector<Mat> &internals);
/** @brief Returns index of input blob into the input array.
* @param inputName label of input blob
*
* Each layer input and output can be labeled to easily identify them using "%<layer_name%>[.output_name]" notation.
* This method maps label of input blob to its index into input vector.
*/
virtual int inputNameToIndex(String inputName); // FIXIT const
/** @brief Returns index of output blob in output array.
* @see inputNameToIndex()
*/
CV_WRAP virtual int outputNameToIndex(const String& outputName); // FIXIT const
/**
* @brief Ask layer if it support specific backend for doing computations.
* @param[in] backendId computation backend identifier.
@@ -419,102 +477,25 @@ CV__DNN_INLINE_NS_BEGIN
virtual bool tryFuse(Ptr<Layer>& top);
/**
* @brief Returns parameters of layers with channel-wise multiplication and addition.
* @param[out] scale Channel-wise multipliers. Total number of values should
* be equal to number of channels.
* @param[out] shift Channel-wise offsets. Total number of values should
* be equal to number of channels.
* @brief Executes the operation on the CUDA backend (new graph engine).
*
* Some layers can fuse their transformations with further layers.
* In example, convolution + batch normalization. This way base layer
* use weights from layer after it. Fused layer is skipped.
* By default, @p scale and @p shift are empty that means layer has no
* element-wise multiplications or additions.
* Called by the engine for nodes assigned to DNN_BACKEND_CUDA. The default
* implementation raises an error. @p workspace is an opaque pointer to a
* cuda4dnn::csl::Workspace (kept void* to avoid leaking internal CUDA types).
*/
virtual void getScaleShift(Mat& scale, Mat& shift) const;
/**
* @brief Returns scale and zeropoint of layers
* @param[out] scale Output scale
* @param[out] zeropoint Output zeropoint
*
* By default, @p scale is 1 and @p zeropoint is 0.
*/
virtual void getScaleZeropoint(float& scale, int& zeropoint) const;
virtual void forwardCUDA(const std::vector<Ptr<BackendWrapper> >& inputs,
const std::vector<Ptr<BackendWrapper> >& outputs,
void* workspace);
/**
* @brief "Detaches" all the layers, attached to particular layer.
*/
virtual void unsetAttached();
virtual bool getMemoryShapes(const std::vector<MatShape> &inputs,
const int requiredOutputs,
std::vector<MatShape> &outputs,
std::vector<MatShape> &internals) const;
virtual void getTypes(const std::vector<MatType>& inputs,
const int requiredOutputs,
const int requiredInternals,
std::vector<MatType>&outputs,
std::vector<MatType>&internals) const;
// this is the method for Layer to express its attitude to the block layout
// or any other special form of layout. It takes
// layouts of the inputs and should return the desired layouts of
// inputs, as well as layouts of the outputs.
// By default, no mater what the actual inputs' layouts are,
// the desired inputs as well as outputs will get 'Unknown' layout values.
// It means that the layer can only handle non-block layout
// (depending on the model format, e.g. NCHW for ONNX or NHWC for TFLite)
// and will return tensors with non-block layout as well.
// Some layers could override this default behaviour:
// a) if they _can_ process block-layout data, like element-wise operations, or
// b) if they _need_ block-layout data, like convolution
virtual int getLayouts(const std::vector<DataLayout>& actualInputs,
std::vector<DataLayout>& desiredInputs,
const int requiredOutputs,
std::vector<DataLayout>& outputs) const;
virtual int64 getFLOPS(const std::vector<MatShape> &inputs,
const std::vector<MatShape> &outputs) const;
virtual bool updateMemoryShapes(const std::vector<MatShape> &inputs);
// returns true if the operation takes a single input and can always be performed in-place,
// assuming that the input is contiguous.
// Examples of such operations are: Reshape, Flatten, Squeeze, Unsqueeze,
// as well many unary element-wise operations (ReLU, Tanh, ...)
virtual bool alwaysSupportInplace() const;
// returns false if the shape of Layer outputs is defined only by the shapes of inputs.
// Sometimes the shape depends on the content of the input(s), then the method should return true.
// In such a rare case forward() method should take care of proper allocation of the output tensors.
// On the other hand, when this method returns false, the engine takes care of proper allocation of the outputs,
// so that forward() can assume that the outputs are already allocated.
virtual bool dynamicOutputShapes() const;
// returns true if the layer only rearranges data without changing values.
// Examples: Flatten, Reshape, Transpose, Permute, Squeeze, Unsqueeze,
// Concat, Split, Slice, Tile, MaxPool.
// Used by QDQ fusion to elide redundant dequantize-quantize pairs
// when the scale and zero point are the same.
virtual bool isDataShuffling() const;
// dumps attributes of the layer (e.g. strides, dilations in Convolution, MaxPool)
virtual std::ostream& dumpAttrs(std::ostream& strm, int indent) const;
// dumps information about the layer. The default implementation is usually good enough,
// just override dumpAttrs().
virtual std::ostream& dump(std::ostream& strm, int indent, bool comma) const;
CV_PROP String name; //!< Name of the layer instance, can be used for logging or other internal purposes.
CV_PROP String type; //!< Type name which was used for creating layer by layer factory.
CV_PROP int preferableTarget; //!< prefer target for layer forwarding
Layer();
explicit Layer(const LayerParams &params); //!< Initializes only #name, #type and #blobs fields.
void setParamsFrom(const LayerParams &params); //!< Initializes only #name, #type and #blobs fields.
virtual ~Layer();
};
@@ -533,15 +514,16 @@ CV__DNN_INLINE_NS_BEGIN
virtual bool empty() const = 0;
virtual void clear() = 0;
virtual std::string name() const = 0;
virtual const std::vector<Arg>& append(Ptr<Layer>& layer,
virtual const std::vector<Arg>& append(Ptr<OpData>& op,
const std::vector<std::string>& outnames=std::vector<std::string>()) = 0;
virtual Arg append(Ptr<Layer>& layer, const std::string& outname=std::string()) = 0;
virtual Arg append(Ptr<OpData>& op, const std::string& outname=std::string()) = 0;
virtual std::ostream& dump(std::ostream& strm, int indent, bool comma) = 0;
virtual const std::vector<Arg>& inputs() const = 0;
virtual const std::vector<Arg>& outputs() const = 0;
virtual void setOutputs(const std::vector<Arg>& outputs) = 0;
virtual const std::vector<Ptr<Layer> >& prog() const = 0;
virtual void setProg(const std::vector<Ptr<Layer> >& newprog) = 0;
virtual const std::vector<Ptr<OpData> >& prog() const = 0;
virtual void setProg(const std::vector<Ptr<OpData> >& newprog) = 0;
https://github.com/opencv/opencv/pull/29018 virtual int opBackend(int opidx) const = 0;
};
/** @brief This class allows to create and manipulate comprehensive artificial neural networks.
@@ -45,6 +45,24 @@ Ptr<Layer> __LayerStaticRegisterer_func_##type(LayerParams &params) \
{ return Ptr<Layer>(new class(params)); } \
static cv::dnn::details::_LayerStaticRegisterer __LayerStaticRegisterer_##type(#type, __LayerStaticRegisterer_func_##type);
/** @brief Registers an OpData (metadata node) class for the new graph engine.
* @param type string, containing the operation type name.
* @param class C++ class derived from OpData, providing `static Ptr<OpData> create(const LayerParams&)`.
* @details This macro must be placed inside the function code (e.g. initializeLayerFactory()).
*/
#define CV_DNN_REGISTER_OP_CLASS(type, class) \
cv::dnn::LayerFactory::registerOp(#type, cv::dnn::details::_opDynamicRegisterer<class>);
/** @brief Registers a backend executor class for the new graph engine.
* @param type string, containing the operation type name.
* @param backendId backend id the executor targets (e.g. DNN_BACKEND_OPENCV, DNN_BACKEND_CUDA).
* @param class C++ class derived from Layer, providing
* `static Ptr<Layer> create(const Ptr<OpData>&, void* backendCtx)` (null Ptr if unsupported).
* @details This macro must be placed inside the function code.
*/
#define CV_DNN_REGISTER_EXEC_CLASS(type, backendId, class) \
cv::dnn::LayerFactory::registerExec(#type, backendId, cv::dnn::details::_execDynamicRegisterer<class>);
namespace details {
template<typename LayerClass>
@@ -53,6 +71,18 @@ Ptr<Layer> _layerDynamicRegisterer(LayerParams &params)
return Ptr<Layer>(LayerClass::create(params));
}
template<typename OpClass>
Ptr<OpData> _opDynamicRegisterer(const LayerParams &params)
{
return Ptr<OpData>(OpClass::create(params));
}
template<typename ExecClass>
Ptr<Layer> _execDynamicRegisterer(const Ptr<OpData>& data, void* backendCtx)
{
return Ptr<Layer>(ExecClass::create(data, backendCtx));
}
//allows automatically register created layer on module load time
class _LayerStaticRegisterer
{
+13
View File
@@ -76,6 +76,19 @@ public:
*/
static Ptr<Layer> createLayerInstance(const String &type, LayerParams& params);
// Builds the abstract (metadata) node for an operation type.
typedef Ptr<OpData>(*OpConstructor)(const LayerParams& params);
//! Builds a backend-specific executor from an OpData; returns null Ptr if unsupported.
typedef Ptr<Layer>(*ExecConstructor)(const Ptr<OpData>& data, void* backendCtx);
static void registerOp(const String& type, OpConstructor constructor);
static Ptr<OpData> createOp(const String& type, const LayerParams& params);
static void registerExec(const String& type, int backendId, ExecConstructor constructor);
static Ptr<Layer> createExec(const String& type, int backendId,
const Ptr<OpData>& data, void* backendCtx);
private:
LayerFactory();
};