tf.placeholder 和 tf.Variable 有啥区别?

Posted

技术标签:

【中文标题】tf.placeholder 和 tf.Variable 有啥区别?【英文标题】:What's the difference between tf.placeholder and tf.Variable?tf.placeholder 和 tf.Variable 有什么区别? 【发布时间】:2016-08-10 04:14:42 【问题描述】:

我是 TensorFlow 的新手。我对tf.placeholdertf.Variable 之间的区别感到困惑。在我看来,tf.placeholder 用于输入数据,tf.Variable 用于存储数据的状态。这就是我所知道的。

谁能更详细地向我解释他们之间的差异?特别是什么时候用tf.Variable,什么时候用tf.placeholder

【问题讨论】:

直观地说,您需要相对于Variables 的渐变,而不是placeholders(必须始终提供其值)。 像cs231n.stanford.edu 这样的课程可以帮助那些困惑的人。我很喜欢!显然还有其他的 【参考方案1】:

简而言之,您可以将tf.Variable 用于模型的可训练变量,例如权重 (W) 和偏差 (B)。

weights = tf.Variable(
    tf.truncated_normal([IMAGE_PIXELS, hidden1_units],
                    stddev=1.0 / math.sqrt(float(IMAGE_PIXELS))), name='weights')

biases = tf.Variable(tf.zeros([hidden1_units]), name='biases')

tf.placeholder 用于提供实际的训练示例。

images_placeholder = tf.placeholder(tf.float32, shape=(batch_size, IMAGE_PIXELS))
labels_placeholder = tf.placeholder(tf.int32, shape=(batch_size))

这是您在训练期间提供训练示例的方式:

for step in xrange(FLAGS.max_steps):
    feed_dict = 
       images_placeholder: images_feed,
       labels_placeholder: labels_feed,
     
    _, loss_value = sess.run([train_op, loss], feed_dict=feed_dict)

您的tf.variables 将作为此次培训的结果接受培训(修改)。

在https://www.tensorflow.org/versions/r0.7/tutorials/mnist/tf/index.html 上查看更多信息。 (示例来自网页。)

【讨论】:

如果我想在输入图像之前对其进行预处理怎么办? (例如,重新调整对比度)。我现在需要一个变量吗?如果是这样,它对内存或速度有影响吗? 您所做的任何预处理都将在将数据输入到 Tensorflow 图(即网络)之前进行,因此从技术上讲,这项工作不需要任何来自 Tensorflow 的代码工具。例如,一个变量是不必要的 1. 因为它是输入数据,它通过图形中的 tf.placeholders(不是变量)传递 2. 预处理发生在它被加载到当前通过网络的占位符之前. 只是想说明我多么欣赏这个答案。对这个答案的赞成票比对这个问题的赞成票要少得多,这一事实表明人们可以即时满足,以及tensorflowdeep learningAI 等时尚标签的流行程度。 所以这意味着,tf.Variable => 反向传播时更新; tf.placeholder => 反向传播时不更新。对吗?【参考方案2】:

不同之处在于tf.Variable 在声明它时必须提供一个初始值。使用tf.placeholder,您不必提供初始值,您可以在运行时使用feed_dict 参数在Session.run 中指定它

【讨论】:

-1。虽然是真的,但这没有抓住重点。更重要的区别是它们在 TensorFlow 中的角色。变量会随着时间的推移进行训练,占位符是不会随着模型训练而改变的输入数据(如输入图像和这些图像的类标签)。就像 Sung Kim 的回答所说,您在模型中使用变量来表示权重和偏差(尽管不限于此 - 对于风格转移,您会随着时间的推移优化图像)。 @ChrisAnderson 我们可以说这个插图是错误的吗?! youtu.be/MotG3XI2qSs?t=136 @ChrisAnderson 为什么它的用途很重要,如果差异只是需要一个初始值? @Goldname 这不是它的“本意”用途——它是可能的和不可能的。它们是完全不同的对象。它们不可互换,并且差异不仅仅是“需要一个初始值”。【参考方案3】:

由于张量计算由graphs 组成,因此最好用图形来解释这两者。

以简单的线性回归为例

WX+B=Y

其中WB 代表权重和偏差,X 代表观察的输入,Y 代表观察的输出。

显然XY 具有相同的性质(显式变量),不同于WB(潜在变量)的性质。 XY 是样本(观察值)的值,因此需要填充位置,而 WB 是权重和偏差,变量(前面的值会影响后面的值)应该使用不同的 XY 对进行训练。我们将不同的样本放置到 Placeholders 以训练 Variables

我们只需要保存或恢复 变量(在检查点处)即可使用代码保存或重建图表。

占位符主要是不同数据集(例如训练数据或测试数据)的持有者。但是,变量在特定任务的训练过程中被训练,即预测输入的结果或将输入映射到所需的标签。在您使用不同或相同的样本重新训练或微调模型以经常通过 dict 填充 Placeholders 之前,它们保持不变。例如:

 session.run(a_graph, dict = a_placeholder_name : sample_values) 

占位符 也作为参数传递给设置模型。

如果您在训练过程中更改模型的占位符(添加、删除、更改形状等),您仍然可以重新加载检查点而无需进行任何其他修改。但是如果保存的模型的变量发生了变化,您应该相应地调整检查点以重新加载它并继续训练(图中定义的所有变量都应该在检查点中可用)。

总而言之,如果这些值来自样本(您已经拥有的观察结果),您可以安全地制作一个占位符来保存它们,而如果您需要一个参数来进行训练,则使用 变量(简单地说将 Variables 设置为您想要使用 TF 自动获取的值)。

在一些有趣的模型中,例如a style transfer model,输入像素将被优化并且通常称为模型变量是固定的,然后我们应该将输入(通常随机初始化)作为该链接中实现的变量.

更多信息请参考此simple and illustrating doc。

【讨论】:

【参考方案4】:

TL;DR

变量

用于学习的参数 值可以从训练中获得 需要初始值(通常是随机的)

占位符

为数据分配的存储空间(例如在馈送期间用于图像像素数据) 初始值不是必需的(但可以设置,参见tf.placeholder_with_default

【讨论】:

【参考方案5】:

tf.Variable 和tf.placeholder 最明显的区别在于


您使用变量来保存和更新参数。变量是 包含张量的内存缓冲区。它们必须明确 初始化,可以在训练期间和训练后保存到磁盘。你 以后可以恢复保存的值来练习或分析模型。

变量的初始化是使用sess.run(tf.global_variables_initializer()) 完成的。此外,在创建变量时,您需要将张量作为其初始值传递给 Variable() 构造函数,并且当您创建变量时,您始终知道它的形状。


另一方面,您无法更新占位符。它们也不应该被初始化,但因为它们承诺有一个张量,所以你需要将值输入它们sess.run(<op>, a: <some_val>)。最后,与变量相比,占位符可能不知道形状。您可以提供部分尺寸,也可以什么都不提供。


还有其他区别:

变量内的值可以在优化期间更新 变量可以是shared,也可以是non-trainable 变量内的值可以在训练后存储 创建变量时,3 ops are added to a graph(变量操作,初始化操作,初始值操作) placeholder is a function, Variable is a class(因此是大写) 当您在分布式环境中使用 TF 时,变量存储在一个特殊的位置 (parameter server) 并在工作人员之间共享。

有趣的部分是不仅可以输入占位符。您可以将值提供给变量,甚至提供给常量。

【讨论】:

【参考方案6】:

添加到其他人的答案中,他们也在 Tensoflow 网站上的 MNIST tutorial 中很好地解释了这一点:

我们通过操纵符号来描述这些交互操作 变量。让我们创建一个:

x = tf.placeholder(tf.float32, [None, 784]),

x 不是特定值。它是一个占位符,当我们要求 TensorFlow 运行计算。我们希望能够输入任意数量的 MNIST 图像,每个都被展平成一个 784 维的向量。我们代表 这是浮点数的二维张量,形状为 [None, 784]。 (这里的 None 表示维度可以是任意长度。)

我们还需要模型的权重和偏差。我们可以想象 将这些视为额外的输入,但 TensorFlow 有一个偶数 更好的处理方法:VariableVariable 是一个可修改的张量 它存在于 TensorFlow 的交互操作图中。有可能 被计算使用甚至修改。用于机器学习 应用中,模型参数一般为Variables。

W = tf.Variable(tf.zeros([784, 10]))

b = tf.Variable(tf.zeros([10]))

我们通过赋予tf.Variable 的初始值来创建这些Variables Variable:在这种情况下,我们将 Wb 都初始化为满张量 的零。既然我们要学习Wb,那就无所谓了 和它们最初的样子差不多。

【讨论】:

您好,谢谢您的回答!在您给出的示例中,我们有 x 形状为 [batch size, features] ,权重从输入到大小为 [features, hidden units] 的第一层和偏差 [hidden units]。所以我的问题是:我们如何将它们相乘?如果我们做tf.matmul(x, w),那么我们将得到[batch size, hidden units],我们不能b,因为它的形状是[hidden units] M.Gorner 在他的幻灯片“学习 TensorFlow 和深度学习,无需博士学位”中解释了这一切。比我在此评论中所做的更好。所以,请允许我参考这张幻灯片:docs.google.com/presentation/d/…【参考方案7】:

Tensorflow 使用三种类型的容器来存储/执行流程

    常量:常量保存典型数据。

    变量:数据值会随着cost_function等函数发生变化。

    占位符:训练/测试数据将传入图表。

【讨论】:

【参考方案8】:

示例 sn-p:

import numpy as np
import tensorflow as tf

### Model parameters ###
W = tf.Variable([.3], tf.float32)
b = tf.Variable([-.3], tf.float32)

### Model input and output ###
x = tf.placeholder(tf.float32)
linear_model = W * x + b
y = tf.placeholder(tf.float32)

### loss ###
loss = tf.reduce_sum(tf.square(linear_model - y)) # sum of the squares

### optimizer ###
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)

### training data ###
x_train = [1,2,3,4]
y_train = [0,-1,-2,-3]

### training loop ###
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init) # reset values to wrong
for i in range(1000):
  sess.run(train, x:x_train, y:y_train)

顾名思义,占位符是承诺稍后提供值,即

变量只是训练参数 (W(matrix), b(bias) 与您在日常编程中使用的正常变量相同,培训师会更新/修改这些变量每次运行/步骤。

虽然 placeholder 不需要任何初始值,但当您创建 xy 时,TF 不会分配任何内存,而是稍后当您在 @987654329 中提供占位符时@ 使用 feed_dict,TensorFlow 将为它们分配适当大小的内存(xy)——这种不受约束的特性允许我们提供任何大小和形状的数据。


简而言之

变量 - 是您希望训练器(即 GradientDescentOptimizer)在每一步之后更新的参数。

占位符演示 -

a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
adder_node = a + b  # + provides a shortcut for tf.add(a, b)

执行:

print(sess.run(adder_node, a: 3, b:4.5))
print(sess.run(adder_node, a: [1,3], b: [2, 4]))

导致输出

7.5
[ 3.  7.]

在第一种情况下,3 和 4.5 将分别传递给 ab,然后到 adder_node 输出 7。在第二种情况下,有一个提要列表,第一步和 2 将被添加,接下来的 3 和4(ab)。


相关阅读:

tf.placeholder 博士。 tf.Variable 博士。 Variable VS placeholder。

【讨论】:

【参考方案9】:

变量

TensorFlow 变量是表示由您的程序操作的共享、持久状态的最佳方式。变量通过 tf.Variable 类进行操作。在内部,一个 tf.Variable 存储一个持久张量。特定操作允许您读取和修改此张量的值。这些修改在多个 tf.Session 中可见,因此多个工作人员可以看到 tf.Variable 的相同值。变量必须在使用前进行初始化。

例子:

x = tf.Variable(3, name="x")
y = tf.Variable(4, name="y")
f = x*x*y + y + 2

这将创建一个计算图。变量 (x 和 y) 可以在 tensorflow 会话中初始化,函数 (f) 如下所示:

with tf.Session() as sess:
     x.initializer.run()
     y.initializer.run()
     result = f.eval()
print(result)
42

占位符

占位符是一个节点(与变量相同),其值可以在将来被初始化。这些节点基本上输出在运行时分配给它们的值。可以使用 tf.placeholder() 类分配占位符节点,您可以向该类提供参数,例如变量的类型和/或其形状。随着训练数据集不断变化,占位符被广泛用于表示机器学习模型中的训练数据集。

例子:

A = tf.placeholder(tf.float32, shape=(None, 3))
B = A + 5

注意:维度的“无”表示“任何大小”。

with tf.Session as sess:
    B_val_1 = B.eval(feed_dict=A: [[1, 2, 3]])
    B_val_2 = B.eval(feed_dict=A: [[4, 5, 6], [7, 8, 9]])

print(B_val_1)
[[6. 7. 8.]]
print(B_val_2)
[[9. 10. 11.]
 [12. 13. 14.]]

参考资料:

    https://www.tensorflow.org/guide/variables https://www.tensorflow.org/api_docs/python/tf/placeholder O'Reilly:使用 Scikit-Learn 和 Tensorflow 进行机器学习实践

【讨论】:

【参考方案10】:

将 tensorflow 中的 Variable 视为我们在编程语言中使用的普通变量。我们初始化变量,我们也可以稍后修改它。而placeholder 不需要初始值。占位符只是分配内存块以供将来使用。稍后,我们可以使用feed_dict 将数据输入placeholder。默认情况下,placeholder 具有不受约束的形状,它允许您在会话中输入不同形状的张量。您可以通过传递可选参数 -shape 来制作受约束的形状,如下所示。

x = tf.placeholder(tf.float32,(3,4))
y =  x + 2

sess = tf.Session()
print(sess.run(y)) # will cause an error

s = np.random.rand(3,4)
print(sess.run(y, feed_dict=x:s))

在执行机器学习任务时,大多数时候我们不知道行数,但(假设)我们知道特征或列的数量。在这种情况下,我们可以使用 None。

x = tf.placeholder(tf.float32, shape=(None,4))

现在,在运行时,我们可以输入任何 4 列和任意行数的矩阵。

此外,占位符用于输入数据(它们是我们用来为模型提供数据的一种变量),其中变量是我们随时间训练的权重等参数。

【讨论】:

【参考方案11】:

占位符:

    占位符只是一个变量,我们将在以后为其分配数据。它允许我们创建我们的操作并构建我们的计算图,而不需要数据。在 TensorFlow 术语中,我们然后通过这些占位符将数据输入到图表中。

    初始值不是必需的,但可以有默认值tf.placeholder_with_default)

    我们必须在运行时提供价值,例如:

    a = tf.placeholder(tf.int16) // initialize placeholder value
    b = tf.placeholder(tf.int16) // initialize placeholder value
    
    use it using session like :
    
    sess.run(add, feed_dict=a: 2, b: 3) // this value we have to assign at runtime
    

变量:

    TensorFlow 变量是表示共享的最佳方式, 由您的程序操纵的持久状态。 变量通过 tf.Variable 类进行操作。一个 tf 变量 表示一个张量,其值可以通过对其运行操作来更改。

例如:tf.Variable("Welcome to tensorflow!!!")

【讨论】:

【参考方案12】:

Tensorflow 2.0 兼容答案:占位符的概念,tf.placeholder 默认在 Tensorflow 2.x (>= 2.0) 中不可用,因为默认执行模式是急切执行。

但是,如果在 Graph Mode (Disable Eager Execution) 中使用,我们可以使用它们。

2.x 版本中 TF 占位符的等效命令是 tf.compat.v1.placeholder

2.x 版本中 TF 变量的等效命令是 tf.Variable,如果要将代码从 1.x 迁移到 2.x,等效命令是

tf.compat.v2.Variable.

有关 Tensorflow 2.0 版的更多信息,请参阅Tensorflow Page。

有关从版本 1.x 迁移到 2.x 的更多信息,请参阅 Migration Guide。

【讨论】:

【参考方案13】:

想一个计算图。在这样的图表中,我们需要一个输入节点来将我们的数据传递给图表,这些节点应该在 tensorflow 中定义为占位符。

不要认为是 Python 中的通用程序。您可以编写一个 Python 程序并执行其他人在其他答案中仅通过变量解释的所有内容,但对于 tensorflow 中的计算图,要将您的数据提供给图表,您需要将这些节点定义为占位符。

【讨论】:

【参考方案14】:

对于 TF V1:

    常数是有初始值的,在计算中不会改变;

    变量是有初始值的,在计算中可以改变; (非常适合参数)

    占位符没有初始值,在计算中不会改变。 (非常适合预测实例等输入)

对于 TF V2,相同,但他们尝试隐藏占位符(不首选图形模式)。

【讨论】:

以上是关于tf.placeholder 和 tf.Variable 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

RuntimeError: tf.placeholder() 与急切执行不兼容

tensorflow中的placeholder()

tf.placeholder使用说明

任何新版本的 tf.placeholder?

TensorFlow placeholder

Tensorflow Placeholder