You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Keras模型转为TensorFlow的.pb/.pbtxt并解决OpenCV加载报错问题

Fixing Keras-to-TensorFlow PB/PBTXT Conversion for OpenCV DNN

Hey there! Let's tackle your liveness detection model conversion issues step by step. I've run into similar compatibility quirks between Keras models and OpenCV's DNN module before, so here's what you need to know:

First: Why Some Use .pb Alone, Others Use .pb + .pbtxt?

  • The .pb file is a binary TensorFlow graph definition that includes both the model structure and trained weights. OpenCV can parse this alone if it can correctly interpret all layers.
  • The .pbtxt is a text-based version of the graph structure (no weights). It's sometimes used as a fallback if OpenCV struggles to parse the graph from the binary .pb file, or to explicitly define input/output nodes. However, if the .pbtxt doesn't exactly match the graph in the .pb, you'll get errors like your first assertion failure.

The Root Cause of Your Errors

Your second error ("Can't create layer 'flatten_1/Shape'") is the key issue: Keras' default Flatten() layer is implemented using TensorFlow's Shape and StridedSlice operations under the hood, and OpenCV's DNN module doesn't support the Shape layer (at least in older versions like 4.1.0).

The first assertion error happens because your manually generated .pb and .pbtxt files have mismatched graph structures (often due to how the freeze_session function prunes or modifies nodes).

Step-by-Step Solution

1. Fix the Flatten Layer in Your Keras Model

Replace any Flatten() layers with a Reshape() layer that achieves the same result. This avoids the unsupported Shape node entirely:

# Instead of:
x = Flatten()(previous_layer)

# Use this (automatically infers the flattened shape):
x = Reshape((-1,))(previous_layer)

If you already have a trained model, you can load it, modify the layer, and re-save it:

import tensorflow as tf
from tensorflow.keras.models import load_model
from tensorflow.keras.layers import Reshape

model = load_model("liveness2.model")

# Find and replace the Flatten layer
new_layers = []
for layer in model.layers:
    if isinstance(layer, tf.keras.layers.Flatten):
        # Add a Reshape layer instead
        new_layers.append(Reshape((-1,), name=f"reshape_{layer.name.split('_')[1]}"))
    else:
        new_layers.append(layer)

# Rebuild the model
new_model = tf.keras.Sequential(new_layers)
new_model.set_weights(model.get_weights())
new_model.save("liveness_fixed.model")

2. Convert the Fixed Model to PB/PBTXT Correctly

Forget the old freeze_session function—use TensorFlow's native tools to generate compatible files. This ensures the .pb and .pbtxt are perfectly matched:

import tensorflow as tf

# Load the fixed model
model = load_model("liveness_fixed.model")

# Set learning phase to test mode (disables training-only layers like dropout)
tf.keras.backend.set_learning_phase(0)

# Save as TensorFlow SavedModel (cleaner graph structure)
tf.saved_model.save(model, "./saved_model")

# Freeze the graph and save PB/PBTXT
graph = tf.compat.v1.get_default_graph()
with tf.compat.v1.Session(graph=graph) as sess:
    # Load the SavedModel
    tf.compat.v1.saved_model.loader.load(sess, [tf.saved_model.tag_constants.SERVING], "./saved_model")
    
    # Get input/output node names (verify these match your model's inputs/outputs)
    input_names = [t.name.split(':')[0] for t in model.inputs]
    output_names = [t.name.split(':')[0] for t in model.outputs]
    
    # Freeze the graph (convert variables to constants)
    frozen_graph = tf.compat.v1.graph_util.convert_variables_to_constants(
        sess,
        graph.as_graph_def(),
        output_names=output_names
    )
    
    # Save the files
    tf.io.write_graph(frozen_graph, "./model", "tf_model.pb", as_text=False)
    tf.io.write_graph(frozen_graph, "./model", "tf_model.pbtxt", as_text=True)

3. Test with OpenCV

Now you should be able to load both files without errors, or just the .pb if you prefer:

import cv2

# Load with both files (recommended for better compatibility)
net = cv2.dnn.readNetFromTensorflow("./model/tf_model.pb", "./model/tf_model.pbtxt")

# Prepare your input blob (match the model's input shape and preprocessing)
face = ...  # Your detected face image
blob = cv2.dnn.blobFromImage(cv2.resize(face, (32, 32)), scalefactor=1.0, size=(32,32), swapRB=True)
net.setInput(blob)
detections = net.forward()

# Interpret the output (matches your model's output layer)
print("Liveness prediction:", detections)

Why This Works

  • Replacing Flatten() with Reshape() eliminates the unsupported Shape layer that was crashing OpenCV's forward pass.
  • Using TensorFlow's native SavedModel and graph freezing tools ensures the .pb and .pbtxt have identical graph structures, fixing the first assertion error.

内容的提问来源于stack exchange,提问作者gwenmaupile14

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:02:02