我正在尝试从.h5文件中加载经过训练的Keras模型,然后在其周围包裹几个TensorFlow层并另存为ProtoBuf。保存工作正常,但是当我导入图形def时,出现错误:
ValueError:节点batch_normalization_24_1 / cond / ReadVariableOp / Switch_1的输入0传递了来自batch_normalization_24 / gamma_1:0的浮点数,与预期资源不兼容。
以下是此错误的最小可重现示例:
import tensorflow as tf
import keras
import keras.backend.tensorflow_backend as K
import base64
def bitstring_to_float32_tensor(input_bytes, image_size):
""" Transforms image bitstring to float32 tensor.
Args:
input_bytes: A bitstring representative of an input image.
image_size: The input image size (e.g., 512).
Returns:
A batched float32 tensor representative of the input image.
"""
input_bytes = tf.reshape(input_bytes, [])
# Transforms bitstring to uint8 tensor
input_tensor = tf.image.decode_png(input_bytes, channels=3)
# Converts to float32 tensor
input_tensor = tf.image.convert_image_dtype(input_tensor,
dtype=tf.float32)
input_tensor = input_tensor / 127.5 - 1.0
# Ensures tensor has correct shape
input_tensor = tf.reshape(input_tensor, [image_size, image_size, 3])
# Expands the single tensor into a batch of 1
input_tensor = tf.expand_dims(input_tensor, 0)
return input_tensor
def float32_tensor_to_bitstring(output_tensor):
""" Transforms float32 tensor to list of image bitstrings.
Args:
output_tensor: A float32 tensor representative of
an inferred image.
Returns:
output_node_names: A list containing the name of the output
node in the graph.
"""
# Converts to uint8 tensor
output_tensor = (output_tensor + 1.0) / 2.0
output_tensor = tf.image.convert_image_dtype(output_tensor, tf.uint8)
output_tensor = tf.squeeze(output_tensor)
# Transforms uint8 tensor to bitstring
output_bytes = tf.image.encode_png(output_tensor)
output_bytes = tf.identity(output_bytes, name="output_bytes")
# Adds output node name to list
output_node_names = ["output_bytes"]
# Returns output list and image boolean
return output_node_names
# Sets model phase to inference
K.set_learning_phase(0)
# Loads model from hdf5 file
model = tf.keras.models.load_model("model.h5")
# Instantiates placeholder for image bitstring
input_bytes = tf.placeholder(tf.string,
shape=[],
name="input_bytes")
# Converts image bitstring to float32 tensor
input_tensor = bitstring_to_float32_tensor(input_bytes, image_size=512)
# Performs inference on tensor, returning a float32 tensor
output_tensor = model.call(input_tensor)
# Converts float32 tensor to image bitstring
output_node_names = float32_tensor_to_bitstring(output_tensor)
# Starts a TensorFlow session
with K.get_session() as sess:
# Initializes variables
sess.run(tf.global_variables_initializer())
# Exports graph to ProtoBuf
output_graph_def = tf.graph_util.convert_variables_to_constants(
sess, sess.graph.as_graph_def(), output_node_names)
# Saves ProtoBuf to disk
tf.train.write_graph(output_graph_def,
"./",
"test.pb",
as_text=False)
# Reads data from ProtoBuf
with tf.gfile.GFile("test.pb", "rb") as protobuf_file:
graph_def = tf.GraphDef()
graph_def.ParseFromString(protobuf_file.read())
# Sets tensor names to extract from graph
tensor_names = ["input_bytes:0", "output_bytes:0"]
# Imports graph and returns extracted tensors
io_tensors = tf.import_graph_def(graph_def,
name="",
return_elements=tensor_names)
我正在使用TensorFlow和TensorFlow-GPU 1.9版和Keras 2.2版。
答案 0 :(得分:2)
我已经成功地解决了几乎相同的问题。 如my answer中关于另一个问题所述,此问题可能与
有关keras.backend.set_learning_phase(0)
应放置在模型加载之前。
import tensorflow as tf
from tensorflow.python.framework import graph_io
from tensorflow.keras.applications.inception_v3 import InceptionV3
def freeze_graph(graph, session, output):
with graph.as_default():
graphdef_inf = tf.graph_util.remove_training_nodes(graph.as_graph_def())
graphdef_frozen = tf.graph_util.convert_variables_to_constants(session, graphdef_inf, output)
graph_io.write_graph(graphdef_frozen, ".", "frozen_model.pb", as_text=False)
tf.keras.backend.set_learning_phase(0) # this line
base_model = InceptionV3()
session = tf.keras.backend.get_session()
INPUT_NODE = base_model.inputs[0].op.name
OUTPUT_NODE = base_model.outputs[0].op.name
freeze_graph(session.graph, session, [out.op.name for out in base_model.outputs])
答案 1 :(得分:1)
我不只是包装TensorFlow图层,而是将它们封装在Keras Lambda layers中以与导入的模型兼容,然后构建了一个新的Keras模型。我最终将其保存为SavedModel而不是ProtoBuf,后者仍可与TensorFlow-Serving一起使用。
工作代码如下:
import tensorflow as tf
from keras.engine.input_layer import Input
from keras.models import Model, load_model
from keras.layers import Lambda
import keras.backend.tensorflow_backend as K
import base64
def bitstring_to_float32_tensor(input_bytes):
""" Transforms image bitstring to float32 tensor.
Args:
input_bytes: A bitstring representative of an input image.
Returns:
A batched float32 tensor representative of the input image.
"""
input_bytes = tf.reshape(input_bytes, [])
input_bytes = tf.cast(input_bytes, tf.string)
# Transforms bitstring to uint8 tensor
input_tensor = tf.image.decode_png(input_bytes, channels=3)
# Converts to float32 tensor
input_tensor = tf.image.convert_image_dtype(input_tensor,
dtype=tf.float32)
input_tensor = input_tensor / 127.5 - 1.0
# Ensures tensor has correct shape
input_tensor = tf.reshape(input_tensor, [512, 512, 3])
# Expands the single tensor into a batch of 1
input_tensor = tf.expand_dims(input_tensor, 0)
return input_tensor
def float32_tensor_to_bitstring(output_tensor):
""" Transforms float32 tensor to list of image bitstrings.
Args:
output_tensor: A float32 tensor representative of
an inferred image.
Returns:
output_node_names: A list containing the name of the output
node in the graph.
"""
# Converts to uint8 tensor
output_tensor = (output_tensor + 1.0) / 2.0
output_tensor = tf.image.convert_image_dtype(output_tensor, tf.uint8)
output_tensor = tf.squeeze(output_tensor)
# Transforms uint8 tensor to bitstring
output_bytes = tf.image.encode_png(output_tensor)
output_bytes = tf.identity(output_bytes, name="output_bytes")
# Expands the single tensor into a batch of 1
output_bytes = tf.expand_dims(output_bytes, 0)
# Returns output tensor
return output_bytes
# Sets model phase to inference
K.set_learning_phase(0)
# Loads model from hdf5 file
model = load_model("model.h5")
# Instantiates placeholder for image bitstring
input_bytes = Input(shape=[], dtype=tf.string)
# Converts image bitstring to float32 tensor
input_tensor = Lambda(bitstring_to_float32_tensor)(input_bytes)
# Performs inference on tensor, returning a float32 tensor
output_tensor = sat_net(input_tensor)
# Converts float32 tensor to image bitstring
output_bytes = Lambda(float32_tensor_to_bitstring)(output_tensor)
# Builds new Model
sat_net = Model(input_bytes, output_bytes)
sat_net.summary()
# Creates signature for prediction
signature_definition = tf.saved_model.signature_def_utils.predict_signature_def(
{"input_bytes": sat_net.input},
{"output_bytes": sat_net.output})
# Instantiates a SavedModelBuilder
builder = tf.saved_model.builder.SavedModelBuilder("serve/1")
with tf.Session() as sess:
# Initializes model and variables
sess.run(tf.global_variables_initializer())
# Adds meta-information
builder.add_meta_graph_and_variables(
sess, [tf.saved_model.tag_constants.SERVING],
signature_def_map={
tf.saved_model.signature_constants.
DEFAULT_SERVING_SIGNATURE_DEF_KEY: signature_definition
})
# Saves the model
builder.save()