OpenCV读取含UpSampling2D层的TensorFlow冻结图报错求解决方案
问题:OpenCV读取含UpSampling2D层的TensorFlow冻结图报错
调用cv2.dnn.readNetFromTensorflow('./frozen.pb')读取包含UpSampling2D层的TensorFlow冻结图时,出现如下错误:
cv_model = cv2.dnn.readNetFromTensorflow('./frozen.pb') cv2.error: OpenCV(4.6.0) /io/opencv/modules/dnn/src/tensorflow/tf_importer.cpp:2824: error: (-2:Unspecified error) More than one input is Const op in function 'getConstBlob'
可复现问题的Python代码如下(错误出现在最后一行):
import cv2 import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2 # Create model model = keras.Sequential([ layers.Input((10, 10, 3)), layers.Conv2D(8, 3, activation='elu', padding='same'), layers.UpSampling2D(size=(2, 2)), ]) model.compile(optimizer='adam', loss='mse') model.summary() # Freeze model full_model = tf.function(lambda x: model(x)) full_model = full_model.get_concrete_function( tf.TensorSpec(model.inputs[0].shape, model.inputs[0].dtype)) frozen_func = convert_variables_to_constants_v2(full_model) frozen_func.graph.as_graph_def() tf.io.write_graph(frozen_func.graph, './', 'frozen.pb', False) # read frozen graph with opencv cv_model = cv2.dnn.readNetFromTensorflow('./frozen.pb') # Error here
注释掉UpSampling2D层后,生成的冻结图可被OpenCV正常读取。已在Windows 10、Ubuntu 22.04系统,多个版本OpenCV和TensorFlow(含最新版),以及C++中使用OpenCV 4.5.5加载模型,均出现相同错误。
解决办法
方案1:替换UpSampling2D为Conv2DTranspose
OpenCV的DNN模块对UpSampling2D的TensorFlow实现支持存在问题,可将模型中的UpSampling2D替换为Conv2DTranspose,功能近似且能被OpenCV正常解析:
# 修改后的模型定义 model = keras.Sequential([ layers.Input((10, 10, 3)), layers.Conv2D(8, 3, activation='elu', padding='same'), # 用Conv2DTranspose替代UpSampling2D,参数对应2倍上采样 layers.Conv2DTranspose(8, 3, strides=(2,2), padding='same', activation='elu'), ])
注:Conv2DTranspose会引入可训练参数,若不需要额外训练,可将其权重固定为上采样的等效值(比如核权重设置为单位矩阵相关值)。
方案2:通过ONNX格式中转
先将TensorFlow模型转换为ONNX格式,再用OpenCV读取ONNX模型,绕开TensorFlow冻结图的解析问题:
- 安装ONNX转换工具:
pip install tf2onnx onnx
- 修改模型导出代码,转为ONNX:
# 替换原冻结图导出代码,改为导出ONNX import tf2onnx spec = tf.TensorSpec(model.inputs[0].shape, model.inputs[0].dtype, name="input") output_path = "./model.onnx" tf2onnx.convert.from_keras(model, input_signature=[spec], output_path=output_path) # 用OpenCV读取ONNX模型 cv_model = cv2.dnn.readNetFromONNX(output_path)
方案3:手动修改冻结图的节点结构
如果必须保留UpSampling2D层,可手动编辑冻结图,合并或调整导致错误的Const节点:
- 用TensorFlow加载冻结图,查看节点结构:
import tensorflow as tf graph_def = tf.compat.v1.GraphDef() with open('./frozen.pb', 'rb') as f: graph_def.ParseFromString(f.read()) # 打印所有Const节点 for node in graph_def.node: if node.op == 'Const': print(node.name)
- 找到UpSampling2D相关的多个Const节点,尝试将其合并为单个输入(需熟悉TensorFlow图结构),重新保存冻结图后再用OpenCV读取。
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

