Как обернуть замороженный граф Tensoflow в слой Keras Lambda в TF2? - PullRequest
2 голосов
/ 09 июля 2020

Этот вопрос связан с этим вопросом , который предоставляет решение, которое работает в Tensorflow 1.15, но больше не работает в TF2

Я беру часть кода из этот вопрос и немного его адаптирую (удалено несколько входов замороженной модели и, вместе с этим, необходимость в nest).

Примечание : я разделяю код на блоки, но они предназначены для запуска как в файле (т.е. я не буду повторять ненужный импорт в каждом блоке)

Сначала мы генерируем замороженный график для использования в качестве фиктивной тестовой сети:

import numpy as np
import tensorflow.compat.v1 as tf

def dump_model():
    with tf.Graph().as_default() as gf:
        x = tf.placeholder(tf.float32, shape=(None, 123), name='x')
        c = tf.constant(100, dtype=tf.float32, name='C')
        y = tf.multiply(x, c, name='y')
        z = tf.add(y, x, name='z')
        with tf.gfile.GFile("tmp_net.pb", "wb") as f:
            raw = gf.as_graph_def().SerializeToString()
            print(type(raw), len(raw))
            f.write(raw)

dump_model()

Затем мы загружаем замороженную модель и оборачиваем ее в модель Keras:

persisted_sess = tf.Session()
with tf.Session().as_default() as session:
    with tf.gfile.FastGFile("./tmp_net.pb",'rb') as f:
        graph_def = tf.GraphDef()
        graph_def.ParseFromString(f.read())
        persisted_sess.graph.as_default()
        tf.import_graph_def(graph_def, name='')
        print(persisted_sess.graph.get_name_scope())
        for i, op in enumerate(persisted_sess.graph.get_operations()):
            tensor = persisted_sess.graph.get_tensor_by_name(op.name + ':0')
            print(i, '\t', op.name, op.type, tensor)
        x_tensor = persisted_sess.graph.get_tensor_by_name('x:0')
        y_tensor = persisted_sess.graph.get_tensor_by_name('y:0')
        z_tensor = persisted_sess.graph.get_tensor_by_name('z:0')

from tensorflow.compat.v1.keras.layers import Lambda, InputLayer
from tensorflow.compat.v1.keras import Model
from tensorflow.python.keras.utils import layer_utils

input_x = InputLayer(name='x', input_tensor=x_tensor)
input_x.is_placeholder = True
output_y = Lambda(lambda x: y_tensor, name='output_y')(input_x.output)
output_z = Lambda(lambda x_b: z_tensor, name='output_z')(input_x.output)

base_model_inputs = layer_utils.get_source_inputs(input_x.output)
base_model = Model(base_model_inputs, [output_y, output_z])

Наконец, мы запускаем модель на некоторых случайных данных и проверяем, что она работает без ошибок:

y_out, z_out = base_model.predict(np.ones((3, 123), dtype=np.float32))
y_out.shape, z_out.shape

В Tensorflow 1.15.3 результат выше - ((3, 123), (3, 123)), однако, если я запускаю тот же код в Tensorflow 2.1.0, первые два блока работают без проблем, но затем третий не работает с :

TypeError: An op outside of the function building code is being passed
a "Graph" tensor. It is possible to have Graph tensors
leak out of the function building context by including a
tf.init_scope in your function building code.
For example, the following function will fail:
  @tf.function
  def has_init_scope():
    my_constant = tf.constant(1.)
    with tf.init_scope():
      added = my_constant * 2
The graph tensor has name: y:0

Ошибка, похоже, связана с Tensorflow automati c "компиляция" и оптимизация функций, но я не знаю, как это интерпретировать, каков источник ошибки или как устранить.

Как правильно обернуть замороженная модель в Tensorflow 2?

Ответы [ 2 ]

1 голос
/ 09 июля 2020

Другой возможный способ сделать это:

import tensorflow as tf

input_layer = tf.keras.Input(shape=[123])
keras_graph = input_layer.graph

with keras_graph.as_default():
    with tf.io.gfile.GFile('tmp_net.pb', 'rb') as f:
        graph_def = tf.compat.v1.GraphDef()
        graph_def.ParseFromString(f.read())

    tf.graph_util.import_graph_def(graph_def, name='', input_map={'x:0': input_layer})
    
    
y_tensor = keras_graph.get_tensor_by_name('y:0')
z_tensor = keras_graph.get_tensor_by_name('z:0')

base_model = tf.keras.Model(input_layer, [y_tensor, z_tensor])

А затем

y_out, z_out = base_model.predict(tf.ones((3, 123), dtype=tf.float32))
print(y_out.shape, z_out.shape)
# (3, 123) (3, 123)
1 голос
/ 09 июля 2020
• 1000 режим графика в рамках одного и того же объекта графика.

Однако может быть проще обернуть загрузку и вычисление графика в @tf.function, что позволит избежать такого рода ошибок и сделать построение модели более прозрачным:

import tensorflow as tf
from tensorflow.core.framework.graph_pb2 import GraphDef
import numpy as np

@tf.function
def my_model(x):
    gd = GraphDef()
    with open('tmp_net.pb', 'rb') as f:
        gd.ParseFromString(f.read())
    y, z = tf.graph_util.import_graph_def(
        gd, name='', input_map={'x:0': x}, return_elements=['y:0', 'z:0'])
    return [y, z]

x = tf.keras.Input(shape=123)
y, z = tf.keras.layers.Lambda(my_model)(x)
model = tf.keras.Model(x, [y, z])
y_out, z_out = model.predict(np.ones((3, 123), dtype=np.float32))
print(y_out.shape, z_out.shape)
# (3, 123) (3, 123)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...