@ -48,6 +48,8 @@ CV__DNN_INLINE_NS_BEGIN
extern bool DNN_DIAGNOSTICS_RUN ;
extern bool DNN_DIAGNOSTICS_RUN ;
class ONNXLayerHandler ;
class ONNXImporter
class ONNXImporter
{
{
opencv_onnx : : ModelProto model_proto ;
opencv_onnx : : ModelProto model_proto ;
@ -80,7 +82,7 @@ public:
void populateNet ( ) ;
void populateNet ( ) ;
protected :
protected :
std : : unique_ptr < detail : : LayerHandler > missingL ayerHandler;
std : : unique_ptr < ONNXLayerHandler > l ayerHandler;
Net & dstNet ;
Net & dstNet ;
opencv_onnx : : GraphProto graph_proto ;
opencv_onnx : : GraphProto graph_proto ;
@ -98,11 +100,14 @@ protected:
void handleNode ( const opencv_onnx : : NodeProto & node_proto ) ;
void handleNode ( const opencv_onnx : : NodeProto & node_proto ) ;
private :
private :
friend class ONNXLayerHandler ;
typedef void ( ONNXImporter : : * ONNXImporterNodeParser ) ( LayerParams & layerParams , const opencv_onnx : : NodeProto & node_proto ) ;
typedef void ( ONNXImporter : : * ONNXImporterNodeParser ) ( LayerParams & layerParams , const opencv_onnx : : NodeProto & node_proto ) ;
typedef std : : map < std : : string , ONNXImporterNodeParser > DispatchMap ;
typedef std : : map < std : : string , ONNXImporterNodeParser > DispatchMap ;
typedef std : : map < std : : string , DispatchMap > DomainDispatchMap ;
typedef std : : map < std : : string , DispatchMap > DomainDispatchMap ;
DomainDispatchMap domain_dispatch_map ;
DomainDispatchMap domain_dispatch_map ;
std : : string getLayerTypeDomain ( const opencv_onnx : : NodeProto & node_proto ) ;
const DispatchMap & getDispatchMap ( const opencv_onnx : : NodeProto & node_proto ) ;
void buildDispatchMap_ONNX_AI ( int opset_version ) ;
void buildDispatchMap_ONNX_AI ( int opset_version ) ;
void buildDispatchMap_COM_MICROSOFT ( int opset_version ) ;
void buildDispatchMap_COM_MICROSOFT ( int opset_version ) ;
@ -156,6 +161,7 @@ private:
void parseSoftMax ( LayerParams & layerParams , const opencv_onnx : : NodeProto & node_proto ) ;
void parseSoftMax ( LayerParams & layerParams , const opencv_onnx : : NodeProto & node_proto ) ;
void parseDetectionOutput ( LayerParams & layerParams , const opencv_onnx : : NodeProto & node_proto ) ;
void parseDetectionOutput ( LayerParams & layerParams , const opencv_onnx : : NodeProto & node_proto ) ;
void parseCumSum ( LayerParams & layerParams , const opencv_onnx : : NodeProto & node_proto ) ;
void parseCumSum ( LayerParams & layerParams , const opencv_onnx : : NodeProto & node_proto ) ;
void parseSimpleLayers ( LayerParams & layerParams , const opencv_onnx : : NodeProto & node_proto ) ;
// Domain: com.microsoft
// Domain: com.microsoft
// URL: https://github.com/microsoft/onnxruntime/blob/master/docs/ContribOperators.md
// URL: https://github.com/microsoft/onnxruntime/blob/master/docs/ContribOperators.md
@ -178,9 +184,38 @@ private:
const std : : string str_domain_ai_onnx = " ai.onnx " ;
const std : : string str_domain_ai_onnx = " ai.onnx " ;
} ;
} ;
class ONNXLayerHandler : public detail : : LayerHandler
{
public :
explicit ONNXLayerHandler ( ONNXImporter * importer_ ) ;
void fillRegistry ( const opencv_onnx : : GraphProto & net ) ;
protected :
ONNXImporter * importer ;
} ;
ONNXLayerHandler : : ONNXLayerHandler ( ONNXImporter * importer_ ) : importer ( importer_ ) { }
void ONNXLayerHandler : : fillRegistry ( const opencv_onnx : : GraphProto & net )
{
int layersSize = net . node_size ( ) ;
for ( int li = 0 ; li < layersSize ; li + + ) {
const opencv_onnx : : NodeProto & node_proto = net . node ( li ) ;
const std : : string & name = node_proto . output ( 0 ) ;
const std : : string & type = node_proto . op_type ( ) ;
const std : : string & layer_type_domain = importer - > getLayerTypeDomain ( node_proto ) ;
const auto & dispatch = importer - > getDispatchMap ( node_proto ) ;
if ( dispatch . find ( type ) = = dispatch . end ( ) )
{
addMissing ( name , cv : : format ( " %s.%s " , layer_type_domain . c_str ( ) , type . c_str ( ) ) ) ;
}
}
printMissing ( ) ;
}
ONNXImporter : : ONNXImporter ( Net & net , const char * onnxFile )
ONNXImporter : : ONNXImporter ( Net & net , const char * onnxFile )
: missingLayerHandler ( DNN_DIAGNOSTICS_RUN ? new detail : : LayerHandler ( ) : nullptr )
: l ayerHandler( DNN_DIAGNOSTICS_RUN ? new ONNXLayerHandler ( this ) : nullptr )
, dstNet ( net )
, dstNet ( net )
, onnx_opset ( 0 )
, onnx_opset ( 0 )
{
{
@ -203,7 +238,7 @@ ONNXImporter::ONNXImporter(Net& net, const char *onnxFile)
}
}
ONNXImporter : : ONNXImporter ( Net & net , const char * buffer , size_t sizeBuffer )
ONNXImporter : : ONNXImporter ( Net & net , const char * buffer , size_t sizeBuffer )
: missingL ayerHandler( DNN_DIAGNOSTICS_RUN ? new detail : : LayerHandler ( ) : nullptr )
: l ayerHandler( DNN_DIAGNOSTICS_RUN ? new ONNXLayerHandler ( this ) : nullptr )
, dstNet ( net )
, dstNet ( net )
, onnx_opset ( 0 )
, onnx_opset ( 0 )
{
{
@ -795,6 +830,7 @@ void ONNXImporter::populateNet()
if ( DNN_DIAGNOSTICS_RUN ) {
if ( DNN_DIAGNOSTICS_RUN ) {
CV_LOG_INFO ( NULL , " DNN/ONNX: start diagnostic run! " ) ;
CV_LOG_INFO ( NULL , " DNN/ONNX: start diagnostic run! " ) ;
layerHandler - > fillRegistry ( graph_proto ) ;
}
}
for ( int li = 0 ; li < layersSize ; li + + )
for ( int li = 0 ; li < layersSize ; li + + )
@ -806,54 +842,48 @@ void ONNXImporter::populateNet()
CV_LOG_DEBUG ( NULL , ( DNN_DIAGNOSTICS_RUN ? " DNN/ONNX: diagnostic run completed! " : " DNN/ONNX: import completed! " ) ) ;
CV_LOG_DEBUG ( NULL , ( DNN_DIAGNOSTICS_RUN ? " DNN/ONNX: diagnostic run completed! " : " DNN/ONNX: import completed! " ) ) ;
}
}
std : : string ONNXImporter : : getLayerTypeDomain ( const opencv_onnx : : NodeProto & node_proto )
{
if ( ! node_proto . has_domain ( ) )
return str_domain_ai_onnx ;
const std : : string & domain = node_proto . domain ( ) ;
if ( domain . empty ( ) )
return str_domain_ai_onnx ;
return domain ;
}
const ONNXImporter : : DispatchMap & ONNXImporter : : getDispatchMap ( const opencv_onnx : : NodeProto & node_proto )
{
static DispatchMap empty_map ;
const std : : string & layer_type_domain = getLayerTypeDomain ( node_proto ) ;
auto it = domain_dispatch_map . find ( layer_type_domain ) ;
if ( it = = domain_dispatch_map . end ( ) )
{
return empty_map ;
}
return it - > second ;
}
void ONNXImporter : : handleNode ( const opencv_onnx : : NodeProto & node_proto )
void ONNXImporter : : handleNode ( const opencv_onnx : : NodeProto & node_proto )
{
{
CV_Assert ( node_proto . output_size ( ) > = 1 ) ;
CV_Assert ( node_proto . output_size ( ) > = 1 ) ;
const std : : string & name = node_proto . output ( 0 ) ;
const std : : string & name = node_proto . output ( 0 ) ;
const std : : string & layer_type = node_proto . op_type ( ) ;
const std : : string & layer_type = node_proto . op_type ( ) ;
const std : : string & layer_type_domain = [ & ] ( )
const std : : string & layer_type_domain = getLayerTypeDomain ( node_proto ) ;
{
const auto & dispatch = getDispatchMap ( node_proto ) ;
if ( ! node_proto . has_domain ( ) )
return str_domain_ai_onnx ;
CV_LOG_DEBUG ( NULL , " DNN/ONNX: processing node with " < < node_proto . input_size ( ) < < " inputs and "
const std : : string & domain = node_proto . domain ( ) ;
< < node_proto . output_size ( ) < < " outputs: "
if ( domain . empty ( ) )
< < cv : : format ( " [%s]:(%s) " , layer_type . c_str ( ) , name . c_str ( ) )
return str_domain_ai_onnx ;
< < cv : : format ( " from %sdomain=' " , onnx_opset_map . count ( layer_type_domain ) = = 1 ? " " : " undeclared " )
return domain ;
< < layer_type_domain < < " ' "
} ( ) ;
) ;
const auto & dispatch = [ & ] ( )
if ( dispatch . empty ( ) )
{
{
if ( layer_type_domain ! = str_domain_ai_onnx )
CV_LOG_WARNING ( NULL , " DNN/ONNX: missing dispatch map for domain=' " < < layer_type_domain < < " ' " ) ;
{
}
if ( onnx_opset_map . find ( layer_type_domain ) = = onnx_opset_map . end ( ) )
{
CV_LOG_WARNING ( NULL , " DNN/ONNX: processing node with " < < node_proto . input_size ( ) < < " inputs and " < < node_proto . output_size ( ) < < " outputs: "
< < cv : : format ( " [%s]:(%s) " , layer_type . c_str ( ) , name . c_str ( ) )
< < " from undeclared domain=' " < < layer_type_domain < < " ' "
) ;
}
else
{
CV_LOG_DEBUG ( NULL , " DNN/ONNX: processing node with " < < node_proto . input_size ( ) < < " inputs and " < < node_proto . output_size ( ) < < " outputs: "
< < cv : : format ( " [%s]:(%s) " , layer_type . c_str ( ) , name . c_str ( ) )
< < " from domain=' " < < layer_type_domain < < " ' "
) ;
}
auto it = domain_dispatch_map . find ( layer_type_domain ) ;
if ( it = = domain_dispatch_map . end ( ) )
{
CV_LOG_WARNING ( NULL , " DNN/ONNX: missing dispatch map for domain=' " < < layer_type_domain < < " ' " ) ;
return DispatchMap ( ) ;
}
return it - > second ;
}
else
{
CV_LOG_DEBUG ( NULL , " DNN/ONNX: processing node with " < < node_proto . input_size ( ) < < " inputs and " < < node_proto . output_size ( ) < < " outputs: "
< < cv : : format ( " [%s]:(%s) " , layer_type . c_str ( ) , name . c_str ( ) )
) ;
return domain_dispatch_map [ str_domain_ai_onnx ] ;
}
} ( ) ;
LayerParams layerParams ;
LayerParams layerParams ;
try
try
@ -2871,6 +2901,15 @@ void ONNXImporter::parseCumSum(LayerParams& layerParams, const opencv_onnx::Node
addLayer ( layerParams , node_proto ) ;
addLayer ( layerParams , node_proto ) ;
}
}
void ONNXImporter : : parseSimpleLayers ( LayerParams & layerParams , const opencv_onnx : : NodeProto & node_proto )
{
for ( int j = 0 ; j < node_proto . input_size ( ) ; j + + ) {
if ( layer_id . find ( node_proto . input ( j ) ) = = layer_id . end ( ) )
layerParams . blobs . push_back ( getBlob ( node_proto , j ) ) ;
}
addLayer ( layerParams , node_proto ) ;
}
void ONNXImporter : : parseCustomLayer ( LayerParams & layerParams , const opencv_onnx : : NodeProto & node_proto )
void ONNXImporter : : parseCustomLayer ( LayerParams & layerParams , const opencv_onnx : : NodeProto & node_proto )
{
{
const std : : string & name = layerParams . name ;
const std : : string & name = layerParams . name ;
@ -2886,20 +2925,11 @@ void ONNXImporter::parseCustomLayer(LayerParams& layerParams, const opencv_onnx:
}
}
}
}
CV_LOG_INFO ( NULL , " DNN/ONNX: unknown node type, try using custom handler for node with " < < node_proto . input_size ( ) < < " inputs and " < < node_proto . output_size ( ) < < " outputs: "
CV_LOG_IF_I NFO ( NULL , ! LayerFactory : : isLayerRegistered ( layer_type ) , " DNN/ONNX: unknown node type, try using custom handler for node with " < < node_proto . input_size ( ) < < " inputs and " < < node_proto . output_size ( ) < < " outputs: "
< < cv : : format ( " [%s]:(%s) " , layer_type . c_str ( ) , name . c_str ( ) )
< < cv : : format ( " [%s]:(%s) " , layer_type . c_str ( ) , name . c_str ( ) )
) ;
) ;
if ( missingLayerHandler )
parseSimpleLayers ( layerParams , node_proto ) ;
{
missingLayerHandler - > addMissing ( layerParams . name , layerParams . type ) ;
}
for ( int j = 0 ; j < node_proto . input_size ( ) ; j + + ) {
if ( layer_id . find ( node_proto . input ( j ) ) = = layer_id . end ( ) )
layerParams . blobs . push_back ( getBlob ( node_proto , j ) ) ;
}
addLayer ( layerParams , node_proto ) ;
}
}
void ONNXImporter : : parseQuantDequant ( LayerParams & layerParams , const opencv_onnx : : NodeProto & node_proto )
void ONNXImporter : : parseQuantDequant ( LayerParams & layerParams , const opencv_onnx : : NodeProto & node_proto )
@ -3349,6 +3379,15 @@ void ONNXImporter::buildDispatchMap_ONNX_AI(int opset_version)
dispatch [ " DetectionOutput " ] = & ONNXImporter : : parseDetectionOutput ;
dispatch [ " DetectionOutput " ] = & ONNXImporter : : parseDetectionOutput ;
dispatch [ " CumSum " ] = & ONNXImporter : : parseCumSum ;
dispatch [ " CumSum " ] = & ONNXImporter : : parseCumSum ;
std : : vector < std : : string > simpleLayers { " Acos " , " Acosh " , " Asin " , " Asinh " , " Atan " , " Atanh " , " Ceil " , " Celu " , " Cos " ,
" Cosh " , " Dropout " , " Erf " , " Exp " , " Floor " , " HardSigmoid " , " HardSwish " ,
" Identity " , " Log " , " Round " , " Selu " , " Sigmoid " , " Sin " , " Sinh " , " Softmax " ,
" Softplus " , " Softsign " , " Sqrt " , " Tan " , " ThresholdedRelu " } ;
for ( const auto & name : simpleLayers )
{
dispatch [ name ] = & ONNXImporter : : parseSimpleLayers ;
}
// ai.onnx: opset 10+
// ai.onnx: opset 10+
dispatch [ " QuantizeLinear " ] = dispatch [ " DequantizeLinear " ] = & ONNXImporter : : parseQuantDequant ;
dispatch [ " QuantizeLinear " ] = dispatch [ " DequantizeLinear " ] = & ONNXImporter : : parseQuantDequant ;
dispatch [ " QLinearConv " ] = & ONNXImporter : : parseQConv ;
dispatch [ " QLinearConv " ] = & ONNXImporter : : parseQConv ;