I'm trying to load a simple four-layer convolutional neural network from an ONNX file in C++ with OpenCV. The ONNX file was created from a TensorFlow model using the tf2onnx
library in Python. I saved the model with the following piece of code.
(onnx_model_proto, storage) = tf2onnx.convert.from_keras(model, opset=8)
with open(os.path.join("models", 'upscaleModelData.onnx'), "wb") as f:
f.write(onnx_model_proto.SerializeToString())
When reading via cv::dnn::Net net = cv::dnn::readNetFromONNX("model.onnx");
in C++, I get the following error.
[ INFO:0] global ####\master_winpack-build-win64-vc15\opencv\modules\dnn\src\onnx\onnx_importer.cpp (429) cv::dnn::dnn4_v20210608::ONNXImporter::populateNet DNN/ONNX: loading ONNX v4 model produced by 'tf2onnx':1.10.0. Number of nodes = 13, inputs = 1, outputs = 1
OpenCV(4.5.3) Error: Unspecified error (Can't create layer "model/tf.nn.depth_to_space/DepthToSpace:0" of type "DepthToSpace") in cv::dnn::dnn4_v20210608::LayerData::getLayerInstance, file ####\opencv\modules\dnn\src\dnn.cpp, line 621
[ERROR:0] global ####\opencv\modules\dnn\src\onnx\onnx_importer.cpp (2127) cv::dnn::dnn4_v20210608::ONNXImporter::handleNode DNN/ONNX: ERROR during processing node with 1 inputs and 1 outputs: [DepthToSpace]:(model/tf.nn.depth_to_space/DepthToSpace:0)
[ INFO:0] global ####\opencv\modules\dnn\src\onnx\onnx_importer.cpp (2131) cv::dnn::dnn4_v20210608::ONNXImporter::handleNode Input[0] = 'model/conv2d_3/Relu:0'
[ INFO:0] global ####\opencv\modules\dnn\src\onnx\onnx_importer.cpp (2135) cv::dnn::dnn4_v20210608::ONNXImporter::handleNode Output[0] = 'model/tf.nn.depth_to_space/DepthToSpace:0'
OpenCV(4.5.3) Error: Unspecified error (> Node [DepthToSpace]:(model/tf.nn.depth_to_space/DepthToSpace:0) parse error: OpenCV(4.5.3) ####\opencv\modules\dnn\src\dnn.cpp:621: error: (-2:Unspecified error) Can't create layer "model/tf.nn.depth_to_space/DepthToSpace:0" of type "DepthToSpace" in function 'cv::dnn::dnn4_v20210608::LayerData::getLayerInstance'
> ) in cv::dnn::dnn4_v20210608::ONNXImporter::handleNode, file ####\opencv\modules\dnn\src\onnx\onnx_importer.cpp, line 2146
OpenCV(4.5.3) ####\opencv\modules\dnn\src\onnx\onnx_importer.cpp:2146: error: (-2:Unspecified error) in function 'cv::dnn::dnn4_v20210608::ONNXImporter::handleNode'
> Node [DepthToSpace]:(model/tf.nn.depth_to_space/DepthToSpace:0) parse error: OpenCV(4.5.3) ####\opencv\modules\dnn\src\dnn.cpp:621: error: (-2:Unspecified error) Can't create layer "model/tf.nn.depth_to_space/DepthToSpace:0" of type "DepthToSpace" in function 'cv::dnn::dnn4_v20210608::LayerData::getLayerInstance'
I'm using OpenCV on Windows and Visual C++.
This might be a similar issue to this: EMGU - EDSR : Can't create layer DepthToSpace.
I tried reading the same network from TensorFlow PB and H5 file, but I get a similar result.
For reading a PB file, created with cv::dnn::readNetFromTensorflow("model.pb")
I get:
OpenCV(4.5.3) Error: Unspecified error (FAILED: fs.is_open(). Can't open "model.pb") in cv::dnn::ReadProtoFromBinaryFile, file ####\opencv\modules\dnn\src\caffe\caffe_io.cpp, line 1133
OpenCV(4.5.3) ####\opencv\modules\dnn\src\caffe\caffe_io.cpp:1133: error: (-2:Unspecified error) FAILED: fs.is_open(). Can't open "model.pb" in function 'cv::dnn::ReadProtoFromBinaryFile'
For reading a H5 file created with cv::dnn::readNetFromTensorflow("upscaleModelData.h5");
I get:
OpenCV(4.5.3) Error: Unspecified error (Cannot determine an origin framework of files: model.h5) in cv::dnn::dnn4_v20210608::readNet, file ####\opencv\modules\dnn\src\dnn.cpp, line 5461
OpenCV(4.5.3) ####\opencv\modules\dnn\src\dnn.cpp:5461: error: (-2:Unspecified error) Cannot determine an origin framework of files: model.h5 in function 'cv::dnn::dnn4_v20210608::readNet'
Does this mean I should make modifications to the model's layers so that it can be read by OpenCV? Is this a compatibility issue? Any feedback, workarounds or alternative approaches (e.g. TensorFlow C++ API solutions) are welcome.
Edit 1: Implementing a layer-type workaround
I reimplemented the depth_to_space
layer manually in Python, using the following piece of code, based on these links: onnx-tensorflow, depth_to_space, keras-subpixel-conv.
x_shape = tf.shape(x)
n, h, w, c = x_shape[0], x_shape[1], x_shape[2], x_shape[3]
y = tf.reshape(x, (n, h, w, bs, bs, c // (bs ** 2)))
y = tf.transpose(y, (0, 1, 3, 2, 4, 5))
outputs = tf.reshape(y, (n, h * bs, w * bs, c // (bs ** 2)))
Now, when I run the same C++ code, I get the following error.
[ INFO:0] global ####\opencv\modules\dnn\src\onnx\onnx_importer.cpp (429) cv::dnn::dnn4_v20210608::ONNXImporter::populateNet DNN/ONNX: loading ONNX v4 model produced by 'tf2onnx':1.10.0. Number of nodes = 38, inputs = 14, outputs = 1
OpenCV(4.5.3) Error: Assertion failed (indexMat.total() == 1) in cv::dnn::dnn4_v20210608::ONNXImporter::handleNode, file ####\opencv\modules\dnn\src\onnx\onnx_importer.cpp, line 1842
[ERROR:0] global ####\opencv\modules\dnn\src\onnx\onnx_importer.cpp (2127) cv::dnn::dnn4_v20210608::ONNXImporter::handleNode DNN/ONNX: ERROR during processing node with 2 inputs and 1 outputs: [Gather]:(model/tf.compat.v1.shape/Shape:0)
[ INFO:0] global ####\opencv\modules\dnn\src\onnx\onnx_importer.cpp (2131) cv::dnn::dnn4_v20210608::ONNXImporter::handleNode Input[0] = 'Shape__72:0'
[ INFO:0] global ####\opencv\modules\dnn\src\onnx\onnx_importer.cpp (2131) cv::dnn::dnn4_v20210608::ONNXImporter::handleNode Input[1] = 'Const__76'
[ INFO:0] global ####\opencv\modules\dnn\src\onnx\onnx_importer.cpp (2135) cv::dnn::dnn4_v20210608::ONNXImporter::handleNode Output[0] = 'model/tf.compat.v1.shape/Shape:0'
OpenCV(4.5.3) Error: Unspecified error (> Node [Gather]:(model/tf.compat.v1.shape/Shape:0) parse error: OpenCV(4.5.3) ####\opencv\modules\dnn\src\onnx\onnx_importer.cpp:1842: error: (-215:Assertion failed) indexMat.total() == 1 in function 'cv::dnn::dnn4_v20210608::ONNXImporter::handleNode'
> ) in cv::dnn::dnn4_v20210608::ONNXImporter::handleNode, file ####\opencv\modules\dnn\src\onnx\onnx_importer.cpp, line 2146
OpenCV(4.5.3) ####\opencv\modules\dnn\src\onnx\onnx_importer.cpp:2146: error: (-2:Unspecified error) in function 'cv::dnn::dnn4_v20210608::ONNXImporter::handleNode'
> Node [Gather]:(model/tf.compat.v1.shape/Shape:0) parse error: OpenCV(4.5.3) ####\opencv\modules\dnn\src\onnx\onnx_importer.cpp:1842: error: (-215:Assertion failed) indexMat.total() == 1 in function 'cv::dnn::dnn4_v20210608::ONNXImporter::handleNode'