我试图了解TensorFlow中占位符和变量之间的区别:
X = tf.placeholder("float")
W = tf.Variable(rng.randn(), name="weight")
我还阅读了下面的Stack Overflow问题。我理解它们是模型输入时的区别。
InvalidArgumentError: You must feed a value for placeholder tensor Placeholder
但是,一般来说,如果我们不构建模型,tf.placeholder()
和tf.Variable()
之间是否存在差异?
答案 0 :(得分:21)
占位符用于将外部数据输入Tensorflow计算(图表外部的内容)。这是一些文档:(https://www.tensorflow.org/versions/r0.10/how_tos/reading_data/#feeding)
TensorFlow的提要机制允许您将数据注入到任何Tensor中 计算图。因此,python计算可以直接提供数据 进入图表。
我个人会从占位符中抽取一个类比来读取标准输入。
x = raw_input()
X = tf.placeholder("float")
当您从标准输入读取时,您需要从外部源“注入数据”。与占位符相同。它允许您“注入”计算图外部的数据。
如果您正在培训学习算法,那么占位符的明确用例就是提供您的培训数据。训练数据不存储在计算图中。你打算如何进入图表?通过占位符注入它。一个占位符基本上就是你告诉图表“我还没有这个。但是当我要你跑的时候我会帮你的。”
变量用于在图表中存储状态。它需要一个初始值。一个用例可以表示神经网络的权重或类似的东西。这是文档:(https://www.tensorflow.org/api_docs/python/tf/Variable)
变量在调用run()时保持图中的状态。你添加 通过构造类的实例的图形变量 变量
Variable()构造函数需要变量的初始值, 它可以是任何类型和形状的张量。初始值定义 变量的类型和形状。施工后,类型和 变量的形状是固定的。可以使用以下值之一更改该值 分配方法。
我个人会在Tensorflow变量之间进行类比,并将Python中的变量分配给任何不依赖于外部内容的变量。例如,
# Tensorflow:
W = tf.Variable(rng.randn(), name="weight")
# Standard python:
w = 5
w = "hello"
w = [1, 2, 3, 4, 5]
W
表示计算的某种结果。就像你必须在Python中初始化所有变量一样(你不能只运行命令x
,你必须说x = ...something...
),你必须初始化Tensorflow中的所有变量对象。
在我看来,tf.Variable
和tf.placeholder
之间的相关性不大。如果需要存储状态,请使用Variable
。如果需要输入外部数据,可以使用placeholder
。
如果您没有构建模型,如果要插入在定义图形时不一定具有的外部数据,则仍应使用tf.placeholder
。如果您没有构建模型,如果要在运行图形时存储某种计算结果,则仍需要tf.Variable
。
我不是Tensorflow的专家,因此我只能推测为什么设计兼顾。
占位符和变量之间的一个巨大差异是占位符可以具有可变大小,但在构造图形时必须指定tf.Variable
的形状。
可变大小的占位符感觉:也许我现在只想输入5号培训批次,但也许我想稍后增加批量大小。也许我提前不知道我将获得多少训练样例。
可变大小的变量没有意义:tf.Variable
保存模型的学习参数,参数的数量不应改变。此外,Tensorflow扩展到分布式计算。如果你的整个计算过程中Variables
的形状发生了变化,那么要在1000台计算机中正确分配它是非常困难的。
通常,您构建模型并且所有参数都是提前知道的,因此tf.Variable
可能用于表示。 tf.placeholder
可能适用于模型(或计算图)之外的所有其他内容,因此可以更灵活。
答案 1 :(得分:4)
tf.Variable和tf.placeholder之间最明显的区别是
使用变量来保存和更新参数。变量是 包含张量的内存缓冲区。它们必须明确 初始化并可在培训期间和培训后保存到磁盘。您 以后可以恢复保存的值来锻炼或分析模型。
使用sess.run(tf.global_variables_initializer())
初始化变量。另外,在创建变量时,需要将Tensor作为其初始值传递给Variable()构造函数,并在创建变量时始终知道其形状。
另一方面,您无法更新占位符。它们也不应该被初始化,但是因为它们是承诺张量,你需要将值提供给它们sess.run(<op>, {a: <some_val>})
。最后,与变量相比,占位符可能不知道形状。您可以提供部分尺寸,也可以不提供任何内容。
还存在其他差异:
有趣的是,不仅可以喂养占位符。您可以将值提供给变量甚至是常量。