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