Skip to content

Commit

Permalink
Merge pull request opencv#20494 from rogday:onnx_diagnostic_fix
Browse files Browse the repository at this point in the history
fix ONNXImporter diagnostic mode layer registration issue

* fix layer registration, thread unsafe access and align the behavior of DNN_DIAGNOSTICS_RUN between onnx and tf importers

* move skipModelInput

* print all missing layers

* address TF issue
  • Loading branch information
rogday authored Aug 20, 2021
1 parent bb5f33d commit 6801dd0
Show file tree
Hide file tree
Showing 9 changed files with 321 additions and 273 deletions.
2 changes: 2 additions & 0 deletions apps/model-diagnostics/model_diagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
**************************************************/
#include <opencv2/dnn.hpp>
#include <opencv2/core/utils/filesystem.hpp>
#include <opencv2/dnn/utils/debug_utils.hpp>

#include <iostream>

Expand Down Expand Up @@ -57,6 +58,7 @@ int main( int argc, const char** argv )
CV_Assert(!model.empty());

enableModelDiagnostics(true);
skipModelImport(true);
redirectError(diagnosticsErrorCallback, NULL);

Net ocvNet = readNet(model, config, frameworkId);
Expand Down
8 changes: 7 additions & 1 deletion modules/dnn/include/opencv2/dnn/layer_reg.private.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@ CV__DNN_INLINE_NS_BEGIN
//! @addtogroup dnn
//! @{

//! Register layer types of DNN model.
typedef std::map<std::string, std::vector<LayerFactory::Constructor> > LayerFactory_Impl;

//! Register layer types of DNN model.
//!
//! @note In order to thread-safely access the factory, see getLayerFactoryMutex() function.
LayerFactory_Impl& getLayerFactoryImpl();

//! Get the mutex guarding @ref LayerFactory_Impl, see getLayerFactoryImpl() function.
Mutex& getLayerFactoryMutex();

//! @}
CV__DNN_INLINE_NS_END
}
Expand Down
24 changes: 24 additions & 0 deletions modules/dnn/include/opencv2/dnn/utils/debug_utils.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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_UTILS_DEBUG_UTILS_HPP
#define OPENCV_DNN_UTILS_DEBUG_UTILS_HPP

#include "../dnn.hpp"

namespace cv { namespace dnn {
CV__DNN_INLINE_NS_BEGIN

/**
* @brief Skip model import after diagnostic run in readNet() functions.
* @param[in] skip Indicates whether to skip the import.
*
* This is an internal OpenCV function not intended for users.
*/
CV_EXPORTS void skipModelImport(bool skip);

CV__DNN_INLINE_NS_END
}} // namespace

#endif // OPENCV_DNN_UTILS_DEBUG_UTILS_HPP
91 changes: 91 additions & 0 deletions modules/dnn/src/debug_utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// 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.

#include "precomp.hpp"

#include <sstream>

#include <opencv2/dnn/layer_reg.private.hpp>
#include <opencv2/dnn/utils/debug_utils.hpp>
#include <opencv2/core/utils/logger.hpp>

namespace cv { namespace dnn {
CV__DNN_INLINE_NS_BEGIN

bool DNN_DIAGNOSTICS_RUN = false;
bool DNN_SKIP_REAL_IMPORT = false;

void enableModelDiagnostics(bool isDiagnosticsMode)
{
DNN_DIAGNOSTICS_RUN = isDiagnosticsMode;

if (DNN_DIAGNOSTICS_RUN)
{
detail::NotImplemented::Register();
}
else
{
detail::NotImplemented::unRegister();
}
}

void skipModelImport(bool skip)
{
DNN_SKIP_REAL_IMPORT = skip;
}

void detail::LayerHandler::addMissing(const std::string& name, const std::string& type)
{
cv::AutoLock lock(getLayerFactoryMutex());
auto& registeredLayers = getLayerFactoryImpl();

// If we didn't add it, but can create it, it's custom and not missing.
if (layers.find(type) == layers.end() && registeredLayers.find(type) != registeredLayers.end())
{
return;
}

layers[type].insert(name);
}

bool detail::LayerHandler::contains(const std::string& type) const
{
return layers.find(type) != layers.end();
}

void detail::LayerHandler::printMissing()
{
if (layers.empty())
{
return;
}

std::stringstream ss;
ss << "DNN: Not supported types:\n";
for (const auto& type_names : layers)
{
const auto& type = type_names.first;
ss << "Type='" << type << "', affected nodes:\n[";
for (const auto& name : type_names.second)
{
ss << "'" << name << "', ";
}
ss.seekp(-2, std::ios_base::end);
ss << "]\n";
}
CV_LOG_ERROR(NULL, ss.str());
}

LayerParams detail::LayerHandler::getNotImplementedParams(const std::string& name, const std::string& op)
{
LayerParams lp;
lp.name = name;
lp.type = "NotImplemented";
lp.set("type", op);

return lp;
}

CV__DNN_INLINE_NS_END
}} // namespace
18 changes: 1 addition & 17 deletions modules/dnn/src/dnn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,22 +94,6 @@ static bool DNN_CHECK_NAN_INF = utils::getConfigurationParameterBool("OPENCV_DNN
static bool DNN_CHECK_NAN_INF_DUMP = utils::getConfigurationParameterBool("OPENCV_DNN_CHECK_NAN_INF_DUMP", false);
static bool DNN_CHECK_NAN_INF_RAISE_ERROR = utils::getConfigurationParameterBool("OPENCV_DNN_CHECK_NAN_INF_RAISE_ERROR", false);

bool DNN_DIAGNOSTICS_RUN = false;

void enableModelDiagnostics(bool isDiagnosticsMode)
{
DNN_DIAGNOSTICS_RUN = isDiagnosticsMode;

if (DNN_DIAGNOSTICS_RUN)
{
detail::NotImplemented::Register();
}
else
{
detail::NotImplemented::unRegister();
}
}

using std::vector;
using std::map;
using std::make_pair;
Expand Down Expand Up @@ -5662,7 +5646,7 @@ bool Layer::updateMemoryShapes(const std::vector<MatShape> &inputs)
}
//////////////////////////////////////////////////////////////////////////

static Mutex& getLayerFactoryMutex()
Mutex& getLayerFactoryMutex()
{
static Mutex* volatile instance = NULL;
if (instance == NULL)
Expand Down
43 changes: 43 additions & 0 deletions modules/dnn/src/dnn_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#ifndef __OPENCV_DNN_COMMON_HPP__
#define __OPENCV_DNN_COMMON_HPP__

#include <unordered_set>
#include <unordered_map>

#include <opencv2/dnn.hpp>

namespace cv { namespace dnn {
Expand All @@ -13,6 +16,9 @@ CV__DNN_INLINE_NS_BEGIN
Mutex& getInitializationMutex();
void initializeLayerFactory();

extern bool DNN_DIAGNOSTICS_RUN;
extern bool DNN_SKIP_REAL_IMPORT;

namespace detail {
#define CALL_MEMBER_FN(object, ptrToMemFn) ((object).*(ptrToMemFn))

Expand All @@ -25,6 +31,43 @@ class NotImplemented : public Layer
static void unRegister();
};

template <typename Importer, typename ... Args>
Net readNet(Args&& ... args)
{
Net net;
Importer importer(net, std::forward<Args>(args)...);
return net;
}

template <typename Importer, typename ... Args>
Net readNetDiagnostic(Args&& ... args)
{
Net maybeDebugNet = readNet<Importer>(std::forward<Args>(args)...);
if (DNN_DIAGNOSTICS_RUN && !DNN_SKIP_REAL_IMPORT)
{
// if we just imported the net in diagnostic mode, disable it and import again
enableModelDiagnostics(false);
Net releaseNet = readNet<Importer>(std::forward<Args>(args)...);
enableModelDiagnostics(true);
return releaseNet;
}
return maybeDebugNet;
}

class LayerHandler
{
public:
void addMissing(const std::string& name, const std::string& type);
bool contains(const std::string& type) const;
void printMissing();

protected:
LayerParams getNotImplementedParams(const std::string& name, const std::string& op);

private:
std::unordered_map<std::string, std::unordered_set<std::string>> layers;
};

struct NetImplBase
{
const int networkId; // network global identifier
Expand Down
Loading

0 comments on commit 6801dd0

Please sign in to comment.