From 00dd433368ec65ab8efd09f2da2cbdb28cba10ad Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 27 Jun 2017 20:34:17 +0300 Subject: [PATCH] dnn: fix LayerFactory initialization --- modules/dnn/include/opencv2/dnn/dnn.hpp | 7 -- .../dnn/include/opencv2/dnn/layer.details.hpp | 77 +++++++++++++++ modules/dnn/include/opencv2/dnn/layer.hpp | 68 +------------- modules/dnn/src/dnn.cpp | 51 +++++++--- modules/dnn/src/init.cpp | 94 +++++++++---------- modules/dnn/src/precomp.hpp | 5 + samples/dnn/caffe_googlenet.cpp | 2 - samples/dnn/fcn_semsegm.cpp | 2 - samples/dnn/squeezenet_halide.cpp | 2 - samples/dnn/ssd_object_detection.cpp | 2 - 10 files changed, 168 insertions(+), 142 deletions(-) create mode 100644 modules/dnn/include/opencv2/dnn/layer.details.hpp diff --git a/modules/dnn/include/opencv2/dnn/dnn.hpp b/modules/dnn/include/opencv2/dnn/dnn.hpp index a705731521..608c584eed 100644 --- a/modules/dnn/include/opencv2/dnn/dnn.hpp +++ b/modules/dnn/include/opencv2/dnn/dnn.hpp @@ -73,13 +73,6 @@ namespace dnn //! This namespace is used for dnn module functionlaity. DNN_TARGET_OPENCL }; - /** @brief Initialize dnn module and built-in layers. - * - * This function automatically called on most of OpenCV builds, - * but you need to call it manually on some specific configurations (iOS for example). - */ - CV_EXPORTS_W void initModule(); - /** @brief This class provides all data needed to initialize layer. * * It includes dictionary with scalar params (which can be readed by using Dict interface), diff --git a/modules/dnn/include/opencv2/dnn/layer.details.hpp b/modules/dnn/include/opencv2/dnn/layer.details.hpp new file mode 100644 index 0000000000..ca2d54cd24 --- /dev/null +++ b/modules/dnn/include/opencv2/dnn/layer.details.hpp @@ -0,0 +1,77 @@ +// 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_LAYER_DETAILS_HPP +#define OPENCV_DNN_LAYER_DETAILS_HPP + +#include + +namespace cv +{ +namespace dnn +{ + +/** @brief Registers layer constructor in runtime. +* @param type string, containing type name of the layer. +* @param constuctorFunc pointer to the function of type LayerRegister::Constuctor, which creates the layer. +* @details This macros must be placed inside the function code. +*/ +#define CV_DNN_REGISTER_LAYER_FUNC(type, constuctorFunc) \ + cv::dnn::LayerFactory::registerLayer(#type, constuctorFunc); + +/** @brief Registers layer class in runtime. + * @param type string, containing type name of the layer. + * @param class C++ class, derived from Layer. + * @details This macros must be placed inside the function code. + */ +#define CV_DNN_REGISTER_LAYER_CLASS(type, class) \ + cv::dnn::LayerFactory::registerLayer(#type, cv::dnn::details::_layerDynamicRegisterer); + +/** @brief Registers layer constructor on module load time. +* @param type string, containing type name of the layer. +* @param constuctorFunc pointer to the function of type LayerRegister::Constuctor, which creates the layer. +* @details This macros must be placed outside the function code. +*/ +#define CV_DNN_REGISTER_LAYER_FUNC_STATIC(type, constuctorFunc) \ +static cv::dnn::details::_LayerStaticRegisterer __LayerStaticRegisterer_##type(#type, constuctorFunc); + +/** @brief Registers layer class on module load time. + * @param type string, containing type name of the layer. + * @param class C++ class, derived from Layer. + * @details This macros must be placed outside the function code. + */ +#define CV_DNN_REGISTER_LAYER_CLASS_STATIC(type, class) \ +Ptr __LayerStaticRegisterer_func_##type(LayerParams ¶ms) \ + { return Ptr(new class(params)); } \ +static cv::dnn::details::_LayerStaticRegisterer __LayerStaticRegisterer_##type(#type, __LayerStaticRegisterer_func_##type); + +namespace details { + +template +Ptr _layerDynamicRegisterer(LayerParams ¶ms) +{ + return Ptr(LayerClass::create(params)); +} + +//allows automatically register created layer on module load time +class _LayerStaticRegisterer +{ + String type; +public: + + _LayerStaticRegisterer(const String &layerType, LayerFactory::Constuctor layerConstuctor) + { + this->type = layerType; + LayerFactory::registerLayer(layerType, layerConstuctor); + } + + ~_LayerStaticRegisterer() + { + LayerFactory::unregisterLayer(type); + } +}; + +}}} //namespace + +#endif diff --git a/modules/dnn/include/opencv2/dnn/layer.hpp b/modules/dnn/include/opencv2/dnn/layer.hpp index 443b67d89a..7025d5bb94 100644 --- a/modules/dnn/include/opencv2/dnn/layer.hpp +++ b/modules/dnn/include/opencv2/dnn/layer.hpp @@ -61,88 +61,26 @@ public: //! Each Layer class must provide this function to the factory typedef Ptr(*Constuctor)(LayerParams ¶ms); - //! Registers the layer class with typename @p type and specified @p constructor. + //! Registers the layer class with typename @p type and specified @p constructor. Thread-safe. static void registerLayer(const String &type, Constuctor constructor); - //! Unregisters registered layer with specified type name. + //! Unregisters registered layer with specified type name. Thread-safe. static void unregisterLayer(const String &type); /** @brief Creates instance of registered layer. * @param type type name of creating layer. * @param params parameters which will be used for layer initialization. + * @note Thread-safe. */ static Ptr createLayerInstance(const String &type, LayerParams& params); private: LayerFactory(); - - struct Impl; - static Ptr impl(); }; -/** @brief Registers layer constructor in runtime. -* @param type string, containing type name of the layer. -* @param constuctorFunc pointer to the function of type LayerRegister::Constuctor, which creates the layer. -* @details This macros must be placed inside the function code. -*/ -#define REG_RUNTIME_LAYER_FUNC(type, constuctorFunc) \ - cv::dnn::LayerFactory::registerLayer(#type, constuctorFunc); - -/** @brief Registers layer class in runtime. - * @param type string, containing type name of the layer. - * @param class C++ class, derived from Layer. - * @details This macros must be placed inside the function code. - */ -#define REG_RUNTIME_LAYER_CLASS(type, class) \ - cv::dnn::LayerFactory::registerLayer(#type, _layerDynamicRegisterer); - -/** @brief Registers layer constructor on module load time. -* @param type string, containing type name of the layer. -* @param constuctorFunc pointer to the function of type LayerRegister::Constuctor, which creates the layer. -* @details This macros must be placed outside the function code. -*/ -#define REG_STATIC_LAYER_FUNC(type, constuctorFunc) \ -static cv::dnn::_LayerStaticRegisterer __LayerStaticRegisterer_##type(#type, constuctorFunc); - -/** @brief Registers layer class on module load time. - * @param type string, containing type name of the layer. - * @param class C++ class, derived from Layer. - * @details This macros must be placed outside the function code. - */ -#define REG_STATIC_LAYER_CLASS(type, class) \ -Ptr __LayerStaticRegisterer_func_##type(LayerParams ¶ms) \ - { return Ptr(new class(params)); } \ -static _LayerStaticRegisterer __LayerStaticRegisterer_##type(#type, __LayerStaticRegisterer_func_##type); - - //! @} //! @} - -template -Ptr _layerDynamicRegisterer(LayerParams ¶ms) -{ - return Ptr(LayerClass::create(params)); -} - -//allows automatically register created layer on module load time -class _LayerStaticRegisterer -{ - String type; -public: - - _LayerStaticRegisterer(const String &layerType, LayerFactory::Constuctor layerConstuctor) - { - this->type = layerType; - LayerFactory::registerLayer(layerType, layerConstuctor); - } - - ~_LayerStaticRegisterer() - { - LayerFactory::unregisterLayer(type); - } -}; - } } #endif diff --git a/modules/dnn/src/dnn.cpp b/modules/dnn/src/dnn.cpp index 4e54808177..c34f740aa0 100644 --- a/modules/dnn/src/dnn.cpp +++ b/modules/dnn/src/dnn.cpp @@ -1931,42 +1931,69 @@ bool Layer::getMemoryShapes(const std::vector &inputs, ////////////////////////////////////////////////////////////////////////// -struct LayerFactory::Impl : public std::map +static Mutex& getLayerFactoryMutex() { -}; + static Mutex* volatile instance = NULL; + if (instance == NULL) + { + cv::AutoLock lock(getInitializationMutex()); + if (instance == NULL) + instance = new Mutex(); + } + return *instance; +} -Ptr LayerFactory::impl () +typedef std::map LayerFactory_Impl; + +static LayerFactory_Impl& getLayerFactoryImpl_() { - // allocate on first use - static Ptr impl_(new LayerFactory::Impl()); - return impl_; + static LayerFactory_Impl impl; + return impl; +} + +static LayerFactory_Impl& getLayerFactoryImpl() +{ + static LayerFactory_Impl* volatile instance = NULL; + if (instance == NULL) + { + cv::AutoLock lock(getLayerFactoryMutex()); + if (instance == NULL) + { + instance = &getLayerFactoryImpl_(); + initializeLayerFactory(); + } + } + return *instance; } void LayerFactory::registerLayer(const String &_type, Constuctor constructor) { + cv::AutoLock lock(getLayerFactoryMutex()); String type = _type.toLowerCase(); - Impl::iterator it = impl()->find(type); + LayerFactory_Impl::const_iterator it = getLayerFactoryImpl().find(type); - if (it != impl()->end() && it->second != constructor) + if (it != getLayerFactoryImpl().end() && it->second != constructor) { CV_Error(cv::Error::StsBadArg, "Layer \"" + type + "\" already was registered"); } - impl()->insert(std::make_pair(type, constructor)); + getLayerFactoryImpl().insert(std::make_pair(type, constructor)); } void LayerFactory::unregisterLayer(const String &_type) { + cv::AutoLock lock(getLayerFactoryMutex()); String type = _type.toLowerCase(); - impl()->erase(type); + getLayerFactoryImpl().erase(type); } Ptr LayerFactory::createLayerInstance(const String &_type, LayerParams& params) { + cv::AutoLock lock(getLayerFactoryMutex()); String type = _type.toLowerCase(); - Impl::const_iterator it = LayerFactory::impl()->find(type); + LayerFactory_Impl::const_iterator it = getLayerFactoryImpl().find(type); - if (it != impl()->end()) + if (it != getLayerFactoryImpl().end()) { return it->second(params); } diff --git a/modules/dnn/src/init.cpp b/modules/dnn/src/init.cpp index 5ece907b77..1fb0806090 100644 --- a/modules/dnn/src/init.cpp +++ b/modules/dnn/src/init.cpp @@ -40,68 +40,62 @@ //M*/ #include "precomp.hpp" +#include namespace cv { namespace dnn { -struct AutoInitializer +static Mutex* __initialization_mutex = NULL; +Mutex& getInitializationMutex() { - bool status; + if (__initialization_mutex == NULL) + __initialization_mutex = new Mutex(); + return *__initialization_mutex; +} +// force initialization (single-threaded environment) +Mutex* __initialization_mutex_initializer = &getInitializationMutex(); - AutoInitializer() : status(false) - { - initModule(); - } -}; -static AutoInitializer init; - -void initModule() +void initializeLayerFactory() { - if (init.status) - return; + CV_DNN_REGISTER_LAYER_CLASS(Slice, SliceLayer); + CV_DNN_REGISTER_LAYER_CLASS(Split, SplitLayer); + CV_DNN_REGISTER_LAYER_CLASS(Concat, ConcatLayer); + CV_DNN_REGISTER_LAYER_CLASS(Reshape, ReshapeLayer); + CV_DNN_REGISTER_LAYER_CLASS(Flatten, FlattenLayer); - REG_RUNTIME_LAYER_CLASS(Slice, SliceLayer); - REG_RUNTIME_LAYER_CLASS(Split, SplitLayer); - REG_RUNTIME_LAYER_CLASS(Concat, ConcatLayer); - REG_RUNTIME_LAYER_CLASS(Reshape, ReshapeLayer); - REG_RUNTIME_LAYER_CLASS(Flatten, FlattenLayer); + CV_DNN_REGISTER_LAYER_CLASS(Convolution, ConvolutionLayer); + CV_DNN_REGISTER_LAYER_CLASS(Deconvolution, DeconvolutionLayer); + CV_DNN_REGISTER_LAYER_CLASS(Pooling, PoolingLayer); + CV_DNN_REGISTER_LAYER_CLASS(LRN, LRNLayer); + CV_DNN_REGISTER_LAYER_CLASS(InnerProduct, InnerProductLayer); + CV_DNN_REGISTER_LAYER_CLASS(Softmax, SoftmaxLayer); + CV_DNN_REGISTER_LAYER_CLASS(MVN, MVNLayer); - REG_RUNTIME_LAYER_CLASS(Convolution, ConvolutionLayer); - REG_RUNTIME_LAYER_CLASS(Deconvolution, DeconvolutionLayer); - REG_RUNTIME_LAYER_CLASS(Pooling, PoolingLayer); - REG_RUNTIME_LAYER_CLASS(LRN, LRNLayer); - REG_RUNTIME_LAYER_CLASS(InnerProduct, InnerProductLayer); - REG_RUNTIME_LAYER_CLASS(Softmax, SoftmaxLayer); - REG_RUNTIME_LAYER_CLASS(MVN, MVNLayer); + CV_DNN_REGISTER_LAYER_CLASS(ReLU, ReLULayer); + CV_DNN_REGISTER_LAYER_CLASS(ChannelsPReLU, ChannelsPReLULayer); + CV_DNN_REGISTER_LAYER_CLASS(Sigmoid, SigmoidLayer); + CV_DNN_REGISTER_LAYER_CLASS(TanH, TanHLayer); + CV_DNN_REGISTER_LAYER_CLASS(BNLL, BNLLLayer); + CV_DNN_REGISTER_LAYER_CLASS(AbsVal, AbsLayer); + CV_DNN_REGISTER_LAYER_CLASS(Power, PowerLayer); + CV_DNN_REGISTER_LAYER_CLASS(BatchNorm, BatchNormLayer); + CV_DNN_REGISTER_LAYER_CLASS(MaxUnpool, MaxUnpoolLayer); + CV_DNN_REGISTER_LAYER_CLASS(Dropout, BlankLayer); + CV_DNN_REGISTER_LAYER_CLASS(Identity, BlankLayer); - REG_RUNTIME_LAYER_CLASS(ReLU, ReLULayer); - REG_RUNTIME_LAYER_CLASS(ChannelsPReLU, ChannelsPReLULayer); - REG_RUNTIME_LAYER_CLASS(Sigmoid, SigmoidLayer); - REG_RUNTIME_LAYER_CLASS(TanH, TanHLayer); - REG_RUNTIME_LAYER_CLASS(BNLL, BNLLLayer); - REG_RUNTIME_LAYER_CLASS(AbsVal, AbsLayer); - REG_RUNTIME_LAYER_CLASS(Power, PowerLayer); - REG_RUNTIME_LAYER_CLASS(BatchNorm, BatchNormLayer); - REG_RUNTIME_LAYER_CLASS(MaxUnpool, MaxUnpoolLayer); - REG_RUNTIME_LAYER_CLASS(Dropout, BlankLayer); - REG_RUNTIME_LAYER_CLASS(Identity, BlankLayer); - - REG_RUNTIME_LAYER_CLASS(Crop, CropLayer); - REG_RUNTIME_LAYER_CLASS(Eltwise, EltwiseLayer); - REG_RUNTIME_LAYER_CLASS(Permute, PermuteLayer); - REG_RUNTIME_LAYER_CLASS(PriorBox, PriorBoxLayer); - REG_RUNTIME_LAYER_CLASS(DetectionOutput, DetectionOutputLayer); - REG_RUNTIME_LAYER_CLASS(NormalizeBBox, NormalizeBBoxLayer); - REG_RUNTIME_LAYER_CLASS(Normalize, NormalizeBBoxLayer); - REG_RUNTIME_LAYER_CLASS(Shift, ShiftLayer); - REG_RUNTIME_LAYER_CLASS(Padding, PaddingLayer); - REG_RUNTIME_LAYER_CLASS(Scale, ScaleLayer); - - init.status = true; + CV_DNN_REGISTER_LAYER_CLASS(Crop, CropLayer); + CV_DNN_REGISTER_LAYER_CLASS(Eltwise, EltwiseLayer); + CV_DNN_REGISTER_LAYER_CLASS(Permute, PermuteLayer); + CV_DNN_REGISTER_LAYER_CLASS(PriorBox, PriorBoxLayer); + CV_DNN_REGISTER_LAYER_CLASS(DetectionOutput, DetectionOutputLayer); + CV_DNN_REGISTER_LAYER_CLASS(NormalizeBBox, NormalizeBBoxLayer); + CV_DNN_REGISTER_LAYER_CLASS(Normalize, NormalizeBBoxLayer); + CV_DNN_REGISTER_LAYER_CLASS(Shift, ShiftLayer); + CV_DNN_REGISTER_LAYER_CLASS(Padding, PaddingLayer); + CV_DNN_REGISTER_LAYER_CLASS(Scale, ScaleLayer); } -} -} +}} //namespace diff --git a/modules/dnn/src/precomp.hpp b/modules/dnn/src/precomp.hpp index b622e38da2..ee3e9dc784 100644 --- a/modules/dnn/src/precomp.hpp +++ b/modules/dnn/src/precomp.hpp @@ -43,3 +43,8 @@ #include "cvconfig.h" #include #include + +namespace cv { namespace dnn { +Mutex& getInitializationMutex(); +void initializeLayerFactory(); +}} // namespace diff --git a/samples/dnn/caffe_googlenet.cpp b/samples/dnn/caffe_googlenet.cpp index f7f325ba70..a3f7501a0d 100644 --- a/samples/dnn/caffe_googlenet.cpp +++ b/samples/dnn/caffe_googlenet.cpp @@ -84,8 +84,6 @@ static std::vector readClassNames(const char *filename = "synset_words.t int main(int argc, char **argv) { - cv::dnn::initModule(); //Required if OpenCV is built as static libs - String modelTxt = "bvlc_googlenet.prototxt"; String modelBin = "bvlc_googlenet.caffemodel"; String imageFile = (argc > 1) ? argv[1] : "space_shuttle.jpg"; diff --git a/samples/dnn/fcn_semsegm.cpp b/samples/dnn/fcn_semsegm.cpp index 062144af3c..e8ae04e09e 100644 --- a/samples/dnn/fcn_semsegm.cpp +++ b/samples/dnn/fcn_semsegm.cpp @@ -85,8 +85,6 @@ static void colorizeSegmentation(const Mat &score, const vector &colo int main(int argc, char **argv) { - cv::dnn::initModule(); //Required if OpenCV is built as static libs - String modelTxt = fcnType + "-heavy-pascal.prototxt"; String modelBin = fcnType + "-heavy-pascal.caffemodel"; String imageFile = (argc > 1) ? argv[1] : "rgb.jpg"; diff --git a/samples/dnn/squeezenet_halide.cpp b/samples/dnn/squeezenet_halide.cpp index ddb01ba187..ecc730c31a 100644 --- a/samples/dnn/squeezenet_halide.cpp +++ b/samples/dnn/squeezenet_halide.cpp @@ -53,8 +53,6 @@ static std::vector readClassNames(const char *filename = "synset_wo int main(int argc, char **argv) { - initModule(); // Required if OpenCV is built as static libs. - std::string modelTxt = "train_val.prototxt"; std::string modelBin = "squeezenet_v1.1.caffemodel"; std::string imageFile = (argc > 1) ? argv[1] : "space_shuttle.jpg"; diff --git a/samples/dnn/ssd_object_detection.cpp b/samples/dnn/ssd_object_detection.cpp index 2c564e056f..7a51d3dcc5 100644 --- a/samples/dnn/ssd_object_detection.cpp +++ b/samples/dnn/ssd_object_detection.cpp @@ -62,8 +62,6 @@ int main(int argc, char** argv) return 0; } - cv::dnn::initModule(); //Required if OpenCV is built as static libs - String modelConfiguration = parser.get("proto"); String modelBinary = parser.get("model");