Не удается импортировать замороженный график после добавления слоев в модель Keras

1

Я пытаюсь загрузить обученную модель Keras из файла.h5, а затем обернуть пару слоев TensorFlow вокруг нее и сохранить как ProtoBuf. Сохранение работает просто отлично, но когда я импортирую график def, я получаю сообщение об ошибке:

ValueError: вход 0 узла batch_normalization_24_1/cond/ReadVariableOp/Switch_1 передан float из 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.

Теги:
tensorflow
keras

2 ответа

0
Лучший ответ

Вместо того, чтобы просто обертывать слои TensorFlow, я инкапсулировал их в слои Keras Lambda, чтобы они были совместимы с импортированной моделью, а затем построили новую модель 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()
0

Я просто успешно справился с почти той же проблемой. Как указано в моем ответе по другому вопросу, этот вопрос, вероятно, связан с

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])

Ещё вопросы

Сообщество Overcoder
Наверх
Меню