Skip to main content
 首页 » 编程设计

python之替换 tensorflow v2 的占位符

2024年09月03日28grandyang

对于我的项目,我需要将有向图转换为该图的 tensorflow 实现,就好像它是一个神经网络一样。在 tensorflow 版本 1 中,我可以将所有输入定义为占位符,然后使用图的广度优先搜索为输出生成数据流图。然后我会使用 feed_dict 输入我的输入。但是,在 TensorFlow v2.0 中,他们决定完全取消占位符。

如何在不使用占位符的情况下为每个接受可变数量输入并返回可变数量输出的图创建一个 tf.function?

我想生成一个适用于任意非循环有向图的 tf.function,这样我就可以利用 tensorflow GPU 支持在生成图形后连续运行图形前馈几千次。


编辑代码示例:

我的图被定义为字典。每个键代表一个节点,并具有另一个字典的对应值,该字典指定带有权重的传入和传出链接。

{ 
    "A": { 
        "incoming": [("B", 2), ("C", -1)], 
        "outgoing": [("D", 3)] 
    } 
} 

为简洁起见,我省略了 B、C 和 D 的条目。 这是我在 tensorflow v1.0 中构建我想要的代码的方式,其中输入只是严格输入到图形的键值列表

def construct_graph(graph_dict, inputs, outputs): 
    queue = inputs[:] 
    make_dict = {} 
    for key, val in graph_dict.items(): 
        if key in inputs: 
            make_dict[key] = tf.placeholder(tf.float32, name=key) 
        else: 
            make_dict[key] = None 
    # Breadth-First search of graph starting from inputs 
    while len(queue) != 0: 
        cur = graph_dict[queue[0]] 
        for outg in cur["outgoing"]: 
            if make_dict[outg[0]]: # If discovered node, do add/multiply operation 
                make_dict[outg[0]] = tf.add(make_dict[outg[0]], tf.multiply(outg[1], make_dict[queue[0]])) 
            else: # If undiscovered node, input is just coming in multiplied and add outgoing to queue 
                make_dict[outg[0]] = tf.multiply(make_dict[queue[0]], outg[1]) 
                for outgo in graph_dict[outg[0]]["outgoing"]: 
                    queue.append(outgo[0]) 
        queue.pop(0) 
    # Returns one data graph for each output 
    return [make_dict[x] for x in outputs] 

然后我将能够多次运行输出,因为它们只是带有占位符的图形,我会为其提供 feed_dict。

显然,这不是 TensorFlow v2.0 的预期方式,因为他们似乎强烈反对在这个新版本中使用占位符。

关键是我只需要对图形进行一次预处理,因为它返回一个独立于 graph_dict 定义的数据图。

请您参考如下方法:

让您的代码与 TF 2.0 一起工作

以下是您可以与 TF 2.0 一起使用的示例代码。 它依赖于 compatibility API 可以作为 tensorflow.compat.v1 访问,并且需要 disable v2 behaviors . 我不知道它的行为是否如你所料。 如果没有,请向我们提供更多关于您尝试实现的目标的解释。

import tensorflow.compat.v1 as tf 
tf.disable_v2_behavior() 
 
@tf.function 
def construct_graph(graph_dict, inputs, outputs): 
    queue = inputs[:] 
    make_dict = {} 
    for key, val in graph_dict.items(): 
        if key in inputs: 
            make_dict[key] = tf.placeholder(tf.float32, name=key) 
        else: 
            make_dict[key] = None 
    # Breadth-First search of graph starting from inputs 
    while len(queue) != 0: 
        cur = graph_dict[queue[0]] 
        for outg in cur["outgoing"]: 
            if make_dict[outg[0]]: # If discovered node, do add/multiply operation 
                make_dict[outg[0]] = tf.add(make_dict[outg[0]], tf.multiply(outg[1], make_dict[queue[0]])) 
            else: # If undiscovered node, input is just coming in multiplied and add outgoing to queue 
                make_dict[outg[0]] = tf.multiply(make_dict[queue[0]], outg[1]) 
                for outgo in graph_dict[outg[0]]["outgoing"]: 
                    queue.append(outgo[0]) 
        queue.pop(0) 
    # Returns one data graph for each output 
    return [make_dict[x] for x in outputs] 
 
def main(): 
    graph_def = { 
        "B": { 
            "incoming": [], 
            "outgoing": [("A", 1.0)] 
        }, 
        "C": { 
            "incoming": [], 
            "outgoing": [("A", 1.0)] 
        }, 
        "A": { 
            "incoming": [("B", 2.0), ("C", -1.0)], 
            "outgoing": [("D", 3.0)] 
        }, 
        "D": { 
            "incoming": [("A", 2.0)], 
            "outgoing": [] 
        } 
    } 
    outputs = construct_graph(graph_def, ["B", "C"], ["A"]) 
    print(outputs) 
 
if __name__ == "__main__": 
    main() 
[<tf.Tensor 'PartitionedCall:0' shape=<unknown> dtype=float32>] 

将您的代码迁移到 TF 2.0

虽然上面的代码片段是有效的,但它仍然与 TF 1.0 相关联。 要将其迁移到 TF 2.0,您必须稍微重构一下您的代码。

与其返回张量列表(在 TF 1.0 中是可调用的),我建议您返回一个列表 keras.layers.Model .

下面是一个工作示例:

import tensorflow as tf 
 
def construct_graph(graph_dict, inputs, outputs): 
    queue = inputs[:] 
    make_dict = {} 
    for key, val in graph_dict.items(): 
        if key in inputs: 
            # Use keras.Input instead of placeholders 
            make_dict[key] = tf.keras.Input(name=key, shape=(), dtype=tf.dtypes.float32) 
        else: 
            make_dict[key] = None 
    # Breadth-First search of graph starting from inputs 
    while len(queue) != 0: 
        cur = graph_dict[queue[0]] 
        for outg in cur["outgoing"]: 
            if make_dict[outg[0]] is not None: # If discovered node, do add/multiply operation 
                make_dict[outg[0]] = tf.keras.layers.add([ 
                    make_dict[outg[0]], 
                    tf.keras.layers.multiply( 
                        [[outg[1]], make_dict[queue[0]]], 
                    )], 
                ) 
            else: # If undiscovered node, input is just coming in multiplied and add outgoing to queue 
                make_dict[outg[0]] = tf.keras.layers.multiply( 
                    [make_dict[queue[0]], [outg[1]]] 
                ) 
                for outgo in graph_dict[outg[0]]["outgoing"]: 
                    queue.append(outgo[0]) 
        queue.pop(0) 
    # Returns one data graph for each output 
    model_inputs = [make_dict[key] for key in inputs] 
    model_outputs = [make_dict[key] for key in outputs] 
    return [tf.keras.Model(inputs=model_inputs, outputs=o) for o in model_outputs] 
 
def main(): 
    graph_def = { 
        "B": { 
            "incoming": [], 
            "outgoing": [("A", 1.0)] 
        }, 
        "C": { 
            "incoming": [], 
            "outgoing": [("A", 1.0)] 
        }, 
        "A": { 
            "incoming": [("B", 2.0), ("C", -1.0)], 
            "outgoing": [("D", 3.0)] 
        }, 
        "D": { 
            "incoming": [("A", 2.0)], 
            "outgoing": [] 
        } 
    } 
    outputs = construct_graph(graph_def, ["B", "C"], ["A"]) 
    print("Builded models:", outputs) 
    for o in outputs: 
        o.summary(120) 
        print("Output:", o((1.0, 1.0))) 
 
if __name__ == "__main__": 
    main() 

这里要注意什么?

  • 从 placeholder 更改为 keras.Input,需要设置输入的形状。
  • 使用 keras.layers.[add|multiply] 进行计算。 这可能不是必需的,但请坚持使用一个界面。 但是,它需要将因素包装在列表中(以处理批处理)
  • 构建keras.Model返回
  • 使用值元组(不再是字典)调用您的模型

这是代码的输出。

Builded models: [<tensorflow.python.keras.engine.training.Model object at 0x7fa0b49f0f50>] 
Model: "model" 
________________________________________________________________________________________________________________________ 
Layer (type)                           Output Shape               Param #       Connected to                             
======================================================================================================================== 
B (InputLayer)                         [(None,)]                  0                                                      
________________________________________________________________________________________________________________________ 
C (InputLayer)                         [(None,)]                  0                                                      
________________________________________________________________________________________________________________________ 
tf_op_layer_mul (TensorFlowOpLayer)    [(None,)]                  0             B[0][0]                                  
________________________________________________________________________________________________________________________ 
tf_op_layer_mul_1 (TensorFlowOpLayer)  [(None,)]                  0             C[0][0]                                  
________________________________________________________________________________________________________________________ 
add (Add)                              (None,)                    0             tf_op_layer_mul[0][0]                    
                                                                                tf_op_layer_mul_1[0][0]                  
======================================================================================================================== 
Total params: 0 
Trainable params: 0 
Non-trainable params: 0 
________________________________________________________________________________________________________________________ 
Output: tf.Tensor([2.], shape=(1,), dtype=float32)