How to convert TensorFlow 2 saved model to be used with OpenCV dnn.readNet

2k views Asked by At

I am struggling to find a way to convert my trained network using TensorFlow 2 Object detection API to be used with OpenCV for deployment purposes. I tried two methods for that but without success. Could someone help me resolve this issue or propose the best and easy deep learning framework to convert my model to OpenCV (OpenCV friendly)? I really appreciate any help you can provide.

This is my information system

OS Platform: Windows 10 64 bits

Tensorflow Version: 2.8

Python version: 3.9.7

OpenCV version: 4.5.5

1st Method: Using tf2onnx

I used the following code since I am using TensorFlow 2

python -m tf2onnx.convert --saved-model tensorflow-model-path --output model.onnx --opset 15

The conversion process generates the model.onnx successfully and returns the following: enter image description here

However, when I try to read the converted model, I get the following error:

File "C:\Tensorflow\testcovertedTF2ToONNX.py", line 10, in <module> net = cv2.dnn.readNetFromONNX('C:/Tensorflow/model.onnx') cv2.error: Unknown C++ exception from OpenCV code

The code used to read the converted network is simple.

import cv2
import numpy as np
 
image = cv2.imread("img002500.jpg")
if image is None:
    print("image emplty")
image_height, image_width, _ = image.shape
net = cv2.dnn.readNetFromONNX('model.onnx')
image = image.astype(np.float32)

input_blob = cv2.dnn.blobFromImage(image, 1, (640,640), 0, swapRB=False, crop=False)
net.setInput(input_blob)
output = net.forward()

2nd Method: Trying to get Frozen graph from saved model

I tried to get frozen_graph.pb from my saved_model using the script below, found in
https://github.com/opencv/opencv/issues/16879#issuecomment-603815872

import tensorflow as tf
print(tf.__version__)

from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2

loaded = tf.saved_model.load('models/mnist_test')
infer = loaded.signatures['serving_default']

f = tf.function(infer).get_concrete_function(input_tensor=tf.TensorSpec(shape=[None, 640, 640, 3], dtype=tf.float32))
f2 = convert_variables_to_constants_v2(f)
graph_def = f2.graph.as_graph_def()

# Export frozen graph
with tf.io.gfile.GFile('frozen_graph.pb', 'wb') as f:
   f.write(graph_def.SerializeToString())

Then, I tried to generate the text graph representation (graph.pbtxt) using tf_text_graph_ssd.py found in https://github.com/opencv/opencv/wiki/TensorFlow-Object-Detection-API

python tf_text_graph_ssd.py --input path2frozen_graph.pb --config path2pipeline.config --output outputgraph.pbtxt

The execution of this script returns the following error:

cv.dnn.writeTextGraph(modelPath, outputPath)
cv2.error: OpenCV(4.5.5) D:\a\opencv-python\opencv-python\opencv\modules\dnn\src\tensorflow\tf_graph_simplifier.cpp:1052: error: (-215:Assertion failed) permIds.size() == net.node_size() in function 'cv::dnn::dnn4_v20211220::sortByExecutionOrder'

During the handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Tensorflow\generatepBtxtgraph\tf_text_graph_ssd.py", line 413, in <module>
    createSSDGraph(args.input, args.config, args.output)
  File "C:\Tensorflow\generatepBtxtgraph\tf_text_graph_ssd.py", line 127, in createSSDGraph
    writeTextGraph(modelPath, outputPath, outNames)
  File "C:\Tensorflow\generatepBtxtgraph\tf_text_graph_common.py", line 320, in writeTextGraph
    from tensorflow.tools.graph_transforms import TransformGraph
ModuleNotFoundError: No module named 'tensorflow.tools.graph_transforms'

Trying to read the generated frozen model without a graph.pb using dnn.readNet the code below:

import cv2
import numpy as np
 
image = cv2.imread("img002500.jpg")
if image is None:
    print("image emplty")
image_height, image_width, _ = image.shape
net = cv2.dnn.readNet('frozen_graph_centernet.pb')
image = image.astype(np.float32)
# create blob from image (opencv dnn way of pre-processing)
input_blob = cv2.dnn.blobFromImage(image, 1, (1024,1024), 0, swapRB=False, crop=False)
net.setInput(input_blob)
output = net.forward()

returns the following error

Traceback (most recent call last):
  File "C:\Tensorflow\testFrozengraphTF2.py", line 14, in <module>
    output = net.forward()
cv2.error: OpenCV(4.5.5) D:\a\opencv-python\opencv-python\opencv\modules\dnn\src\dnn.cpp:621: error: (-2:Unspecified error) Can't create layer "StatefulPartitionedCall" of type "StatefulPartitionedCall" in function 'cv::dnn::dnn4_v20211220::LayerData::getLayerInstance'

I understand that OpenCV doesn't import models with StatefulPartitionedCall (TF Eager mode). Unfortunately, this means the script found to export my saved model to frozen_graph did not work.

saved model

you can get my saved model from the link below

https://www.dropbox.com/s/liw5ff87rz7v5n5/my_model.zip?dl=0

#note: the exported model works well with the TensorFlow script

1

There are 1 answers

0
Hogi Kim On

2nd Method: Trying to get Frozen graph from saved model

make_FB

https://medium.com/@sebastingarcaacosta/how-to-export-a-tensorflow-2-x-keras-model-to-a-frozen-and-optimized-graph-39740846d9eb

use pyopencv

model = cv.dnn.readNetFromTensorflow('./frozen_graph2.pb')