Skip to content

Commit bcc669f

Browse files
committed
TensorFlow weights dequantization
1 parent 047ad4f commit bcc669f

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

modules/dnn/src/tensorflow/tf_importer.cpp

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ static Mat getTensorContent(const tensorflow::TensorProto &tensor)
138138
convertFp16(halfsSigned, floats);
139139
return floats;
140140
}
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+
}
141146
default:
142147
CV_Error(Error::StsError, "Tensor's data type is not supported");
143148
break;
@@ -588,7 +593,7 @@ const tensorflow::TensorProto& TFImporter::getConstBlob(const tensorflow::NodeDe
588593
}
589594
}
590595

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,
592597
std::set<String>& layers_to_ignore)
593598
{
594599
for (int li = 0; li < net.node_size(); li++)
@@ -597,7 +602,52 @@ static void addConstNodes(const tensorflow::GraphDef& net, std::map<String, int>
597602
String name = layer.name();
598603
String type = layer.op();
599604

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")
601651
continue; // only Const parameters are supported
602652

603653
if (layer.attr().find("value") != layer.attr().end())

modules/dnn/test/test_tf_importer.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ TEST(Test_TensorFlow, fp16)
188188
runTensorFlowNet("fp16_padding_same", false, l1, lInf);
189189
}
190190

191+
TEST(Test_TensorFlow, quantized)
192+
{
193+
runTensorFlowNet("uint8_single_conv");
194+
}
195+
191196
TEST(Test_TensorFlow, MobileNet_SSD)
192197
{
193198
std::string netPath = findDataFile("dnn/ssd_mobilenet_v1_coco.pb", false);

0 commit comments

Comments
 (0)