【问题标题】:How to wrap tensorflow graph with placeholder in keras如何在keras中用占位符包装张量流图
【发布时间】:2020-01-12 19:15:23
【问题描述】:

我有一个带有占位符操作作为输入的张量流图(存储在一个 protobuffer 文件中)。我想将此图包装为 keras 层或模型。

这是一个例子:

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')
    with tf.gfile.GFile("test_graph/y.pb", "wb") as f:
        raw = gf.as_graph_def().SerializeToString()
        f.write(raw)

加载回张量流图:

persisted_sess = tf.Session()
with persisted_sess.as_default():
    with gfile.FastGFile("./test_graph/y.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='')
        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')

我们可以看到xy 操作和张量:

0    x Placeholder Tensor("x:0", shape=(?, 123), dtype=float32)
1    C Const Tensor("C:0", shape=(), dtype=float32)
2    y Mul Tensor("y:0", shape=(?, 123), dtype=float32)

然后我尝试使用不同的方法将其包装到 keras 模型中:

方法一:

output_layer = Lambda(lambda x: y_tensor, name='output_y')(x_tensor)
model = Model(inputs=[x_tensor], outputs=[output_layer])  # ERROR!

这已经产生错误InvalidArgumentError: You must feed a value for placeholder tensor 'x' with dtype float and shape [?,123] [[{{node x}}]]

方法二:

input_x = Input(name='x', shape=(123,), dtype='float32')
output_layer = Lambda(lambda x: y_tensor, name='output_y')(input_x)
model = Model(inputs=[input_x], outputs=[output_layer]) # OK

model.predict({'x': np.ones((3, 123), dtype=np.float32)}) # ERROR!

这会在predict 调用中导致同样的错误。

我能找到的与我的问题相关的最接近的信息是this,但它没有解决占位符的处理问题。这样做的正确方法是什么?

【问题讨论】:

    标签: tensorflow keras tf.keras


    【解决方案1】:

    我找到了方法。我们需要使用InputLayer 而不是Input

    首先是创建演示张量流图 PB 的代码:

    def dump_model(): # just to hide all vars during creation demo
        import numpy as np
        import sys
        import tensorflow as tf
        with tf.Graph().as_default() as gf:
            x = tf.placeholder(tf.float32, shape=(None, 123), name='x')
            b = tf.placeholder(tf.float32, shape=(None, 123), name='b')
            c = tf.constant(100, dtype=tf.float32, name='C')
            y = tf.multiply(x, c, name='y')
            z = tf.add(y, x, name='z')
            print(x, b, c, y, z)
            with tf.gfile.GFile("test_graph/y.pb", "wb") as f:
                raw = gf.as_graph_def().SerializeToString()
                print(type(raw), len(raw))
                f.write(raw)
    dump_model()
    

    然后导入图并找到输入/输出张量:

    import numpy as np
    import sys
    import tensorflow as tf
    
    persisted_sess = tf.Session()
    with tf.Session().as_default() as session:
        with tf.gfile.FastGFile("./test_graph/y.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')
            b_tensor = persisted_sess.graph.get_tensor_by_name('b:0')
            y_tensor = persisted_sess.graph.get_tensor_by_name('y:0')
            z_tensor = persisted_sess.graph.get_tensor_by_name('z:0')
    

    然后我们可以创建keras模型并进行推理:

    from tensorflow.keras.layers import Lambda, InputLayer
    from tensorflow.keras import Model
    from tensorflow.python.util import nest
    from tensorflow.python.keras.utils import layer_utils
    
    input_x = InputLayer(name='x', input_tensor=x_tensor)
    input_x.is_placeholder = True  # this is the critical bits
    input_b = InputLayer(name='b2', input_tensor=b_tensor) # note the keras name can be different than the tf name
    input_b.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, input_b.output])
    
    base_model_inputs = nest.flatten([layer_utils.get_source_inputs(input_x.output),
                                      layer_utils.get_source_inputs(input_b.output)])
    base_model = Model(base_model_inputs, [output_y, output_z])
    y_out, z_out = base_model.predict({'x': np.ones((3, 123), dtype=np.float32),
                                       'b2': np.full((3, 123), 100.0, dtype=np.float32)})
    y_out.shape, z_out.shape
    

    我们甚至可以从基础模型创建一个新模型:

    from tensorflow.keras.layers import Add
    derived_output = Add(name='derived')([output_y, output_z])
    derived_model = Model(base_model.inputs, [derived_output])
    
    derived_out = derived_model.predict({'x': np.ones((3, 123), dtype=np.float32),
                                                       'b2': np.full((3, 123), 100.0, dtype=np.float32)})
    derived_out.shape
    

    【讨论】:

    • 这是用什么版本的 Tensorflow 开发的?我正在尝试在 TF 2.2(使用 compat.v1 API)上重现它,但它在推理时引发错误
    猜你喜欢
    • 2019-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 2016-03-23
    • 2018-08-01
    相关资源
    最近更新 更多