@@ -146,6 +146,11 @@ static Mat getTensorContent(const tensorflow::TensorProto &tensor)
146
146
convertFp16 (halfsSigned, floats);
147
147
return floats;
148
148
}
149
+ case tensorflow::DT_QUINT8:
150
+ {
151
+ CV_Assert (!content.empty ());
152
+ return Mat (1 , content.size (), CV_8UC1, (void *)content.c_str ()).clone ();
153
+ }
149
154
default :
150
155
CV_Error (Error::StsError, " Tensor's data type is not supported" );
151
156
break ;
@@ -596,7 +601,7 @@ const tensorflow::TensorProto& TFImporter::getConstBlob(const tensorflow::NodeDe
596
601
}
597
602
}
598
603
599
- static void addConstNodes (const tensorflow::GraphDef& net, std::map<String, int >& const_layers,
604
+ static void addConstNodes (tensorflow::GraphDef& net, std::map<String, int >& const_layers,
600
605
std::set<String>& layers_to_ignore)
601
606
{
602
607
for (int li = 0 ; li < net.node_size (); li++)
@@ -605,7 +610,52 @@ static void addConstNodes(const tensorflow::GraphDef& net, std::map<String, int>
605
610
String name = layer.name ();
606
611
String type = layer.op ();
607
612
608
- if (type != " Const" )
613
+ if (type == " Dequantize" )
614
+ {
615
+ // Example of Dequantize node:
616
+ // name: "conv2d_1/bias"
617
+ // op: "Dequantize"
618
+ // input: "conv2d_1/bias_quantized_const" (tensor of dtype DT_QUINT8)
619
+ // input: "conv2d_1/bias_quantized_min"
620
+ // input: "conv2d_1/bias_quantized_max"
621
+ // attr { key: "T" value { type: DT_QUINT8 } } (quantized type)
622
+ // attr { key: "mode" value { s: "MIN_FIRST" } } (quantization technique)
623
+ CV_Assert (layer.input_size () == 3 );
624
+ for (int i = 0 ; i < 3 ; ++i)
625
+ CV_Assert (const_layers.find (layer.input (i)) != const_layers.end ());
626
+ CV_Assert (hasLayerAttr (layer, " mode" ) &&
627
+ getLayerAttr (layer, " mode" ).s () == " MIN_FIRST" );
628
+
629
+ int tensorId = const_layers[layer.input (0 )];
630
+ int minId = const_layers[layer.input (1 )];
631
+ int maxId = const_layers[layer.input (2 )];
632
+
633
+ tensorflow::TensorProto* tensor = net.mutable_node (tensorId)
634
+ ->mutable_attr ()->at (" value" )
635
+ .mutable_tensor ();
636
+ CV_Assert (tensor->dtype () == tensorflow::DT_QUINT8);
637
+
638
+ Mat qMin = getTensorContent (net.node (minId).attr ().at (" value" ).tensor ());
639
+ Mat qMax = getTensorContent (net.node (maxId).attr ().at (" value" ).tensor ());
640
+ CV_Assert (qMin.total () == 1 , qMin.type () == CV_32FC1,
641
+ qMax.total () == 1 , qMax.type () == CV_32FC1);
642
+
643
+ Mat content = getTensorContent (*tensor);
644
+
645
+ float minVal = qMin.at <float >(0 );
646
+ float rangeScale = (qMax.at <float >(0 ) - minVal) / 255 ;
647
+ CV_Assert (rangeScale >= 0 );
648
+ content.convertTo (content, CV_32FC1, rangeScale,
649
+ rangeScale * cvRound (minVal / rangeScale));
650
+
651
+ tensor->set_dtype (tensorflow::DT_FLOAT);
652
+ tensor->set_tensor_content (content.data , content.total () * content.elemSize1 ());
653
+
654
+ ExcludeLayer (net, li, 0 , false );
655
+ layers_to_ignore.insert (name);
656
+ continue ;
657
+ }
658
+ else if (type != " Const" )
609
659
continue ; // only Const parameters are supported
610
660
611
661
if (layer.attr ().find (" value" ) != layer.attr ().end ())
0 commit comments