替换 tensorflow v2 的占位符
Replacing placeholder for tensorflow v2
对于我的项目,我需要将有向图转换为该图的张量流实现,就好像它是一个神经网络一样。在 tensorflow 版本 1 中,我可以将所有输入定义为占位符,然后使用图的广度优先搜索为输出生成数据流图。然后我会使用 feed_dict 输入我的输入。但是,在 TensorFlow v2.0 中,他们决定完全取消占位符。
如何在不使用占位符的情况下为每个接受可变输入量和 returns 可变输出量的图表制作 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 的预期方式,因为他们似乎强烈反对在此新版本中使用占位符。
关键是我只需要对图进行一次预处理,因为它 returns 是一个独立于 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,您必须稍微重构一下您的代码。
我建议您 return 不是 return 使用 TF 1.0 调用的张量列表,而是 return
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
到 return
- 使用值元组(不再是字典)调用您的模型
这是代码的输出。
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)
对于我的项目,我需要将有向图转换为该图的张量流实现,就好像它是一个神经网络一样。在 tensorflow 版本 1 中,我可以将所有输入定义为占位符,然后使用图的广度优先搜索为输出生成数据流图。然后我会使用 feed_dict 输入我的输入。但是,在 TensorFlow v2.0 中,他们决定完全取消占位符。
如何在不使用占位符的情况下为每个接受可变输入量和 returns 可变输出量的图表制作 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 的预期方式,因为他们似乎强烈反对在此新版本中使用占位符。
关键是我只需要对图进行一次预处理,因为它 returns 是一个独立于 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,您必须稍微重构一下您的代码。
我建议您 return 不是 return 使用 TF 1.0 调用的张量列表,而是 return
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
到 return - 使用值元组(不再是字典)调用您的模型
这是代码的输出。
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)