【问题标题】:Caching a computed value as a constant in TensorFlow在 TensorFlow 中将计算值缓存为常量
【发布时间】:2016-02-24 20:03:31
【问题描述】:

假设我想在 TensorFlow 中使用封闭式解决方案计算最小二乘系数。通常,我会这样做,

beta_hat = tf.matmul(
           tf.matmul(tf.matrix_inverse(tf.matmul(tf.transpose(X), X)), tf.transpose(X)), y
)

其中Xy 分别是对应于协变量和目标变量的TensorFlow 占位符。

如果我想执行预测,我会做类似的事情,

y_pred = tf.matmul(X, beta_hat)

如果我要执行,

sess.run(y_pred, feed_dict={X: data_X})

我当然会收到一个错误,即我没有为占位符y 提供必要的值。我希望在计算 beta_hat 后灵活地将其视为常量(这样我就不需要为新的协变量矩阵定义新的占位符来进行预测)。实现此目的的一种方法是,

# Make it constant.
beta_hat = sess.run(beta_hat, feed_dict={X: data_X, y: data_y})
y_pred = tf.matmul(X, beta_hat)

我想知道是否有更优雅的方式将张量视为常量,这样我既不需要执行会话并获取常量,也不需要为传入数据创建单独的占位符以用于预测。

这里有一些示例代码来演示我所描述的情况。

import numpy as np
import tensorflow as tf


n, k = 100, 5
X = tf.placeholder(dtype=tf.float32, shape=[None, k])
y = tf.placeholder(dtype=tf.float32, shape=[None, 1])

beta = np.random.normal(size=(k, ))
data_X = np.random.normal(size=(n, k))

data_y = data_X.dot(beta)
data_y += np.random.normal(size=data_y.shape) / 3.0
data_y = np.atleast_2d(data_y).T

# Convert to 32-bit precision.
data_X, data_y = np.float32(data_X), np.float32(data_y)

# Compute the least squares solution.
beta_hat = tf.matmul(
    tf.matmul(tf.matrix_inverse(tf.matmul(tf.transpose(X), X)),
              tf.transpose(X)), y
)

# Launch the graph
sess = tf.Session()
sess.run(tf.initialize_all_variables())

print "True beta: {}".format(beta)
print "Est. beta: {}".format(
    sess.run(beta_hat, feed_dict={X: data_X, y: data_y}).ravel()
)

# # This would error.
# y_pred = tf.matmul(X, beta_hat)
# print "Predictions:"
# print sess.run(y_pred, feed_dict={X: data_X})

# Make it constant.
beta_hat = sess.run(beta_hat, feed_dict={X: data_X, y: data_y})

# This will no longer error.
y_pred = tf.matmul(X, beta_hat)
print "Predictions:"
print sess.run(y_pred, feed_dict={X: data_X})

【问题讨论】:

    标签: python numpy constants linear-regression tensorflow


    【解决方案1】:

    也许与直觉相反,在后续步骤中重用beta_hat 作为常量的最简单方法是将其分配给tf.Variable

    n, k = 100, 5
    X = tf.placeholder(dtype=tf.float32, shape=[None, k])
    y = tf.placeholder(dtype=tf.float32, shape=[None, 1])
    
    beta = np.random.normal(size=(k, ))
    data_X = np.random.normal(size=(n, k))
    
    data_y = data_X.dot(beta)
    data_y += np.random.normal(size=data_y.shape) / 3.0
    data_y = np.atleast_2d(data_y).T
    
    # Convert to 32-bit precision.
    data_X, data_y = np.float32(data_X), np.float32(data_y)
    
    # Compute the least squares solution.
    beta_hat = tf.matmul(
        tf.matmul(tf.matrix_inverse(tf.matmul(tf.transpose(X), X)),
                  tf.transpose(X)), y
    )
    
    beta_hat_cached = tf.Variable(beta_hat)
    
    # Launch the graph
    sess = tf.Session()
    
    print "True beta: {}".format(beta)
    # Run the initializer, which computes `beta_hat` once:
    sess.run(beta_hat_cached.initializer, feed_dict={X: data_X, y: data_y})
    # To access the value of `beta_hat`, "run" the variable to read its contents.
    print "Est. beta: {}".format(beta_hat_cached.ravel())
    
    # Use the cached version to compute predictions.
    y_pred = tf.matmul(X, beta_hat_cached)
    print "Predictions:"
    print sess.run(y_pred, feed_dict={X: data_X})
    

    【讨论】:

    • ravel == 评估? (或者这个函数有记录吗?)
    【解决方案2】:

    mrry 确实提出了一个优雅的解决方案。如果这确实是您想要的,您应该考虑将他的答案标记为正确。

    但是,我认为这是一个很好的地方,可以澄清我认为对占位符造成混淆的原因...这不一定针对提出问题的人,但我相信它会相关对于很多偶然发现这个问题的初学者......


    占位符应该被视为函数输入。所以首先,让我们回顾一下它在 Python 中是如何工作的,然后我将在 Tensorflow 中展示等价形式......

    如果我想要一个函数来计算给定各种输入 xy 的输出,那么我可以这样做......

    def f(x,y):
        # For example... 
        return x * y 
    

    具体来说,我可以使用 xy 的各种值调用此函数:

    f(1,3) = 3
    f(1,4) = 4
    f(2,3) = 6
    f(2,4) = 8
    

    但是,在我的特定情况下,我可能有一个固定值y。所以就我而言,将y 作为参数传递是没有意义的。相反,我想将我的y 值烘焙到函数中,并改变x。为此,我可以简单地捕获y 的外部值:

    y = 3
    def g(x):
        return x * y
    

    现在每当我调用g 时,y 都会有固定值 3:

    g(1) = 3
    g(2) = 6
    

    同样,如果我也知道x 是固定的,我可以捕获x 的外部值:

    x = 2
    def h():
       return g(x)
    

    现在,当我调用h 时,我隐含地调用h()=g(2)=f(2,3)

    很好,但问题是每次我调用h,它都会重做乘法,因为它相当于调用f(2,3)。因此,为了提高性能,我可以评估表达式,然后有一个函数只返回这个预先计算的值:

    val = h()
    def h23():
        return val
    

    无论我调用多少次h23,乘法只执行一次(在val = h() 行上)。

    Tensorflow 有类似的概念。

    如果您想要一个可以改变两个输入的函数,那么您应该为两个实例创建占位符对象,并在会话中运行时将值传递给提要字典中的函数:

    dtype = tf.float64
    shape = ()
    x = tf.placeholder( dtype, shape )
    y = tf.placeholder( dtype, shape )
    fxy = f(x,y)
    with tf.Session() as sess: 
        print( sess.run( fxy, {x:1,y:3} ) )
        print( sess.run( fxy, {x:1,y:4} ) )
        print( sess.run( fxy, {x:2,y:3} ) )
        print( sess.run( fxy, {x:2,y:4} ) )
    

    但是,如果我的某个值没有改变,那么我可以直接将其初始化为常量,并使用“烘焙到其中”的值创建一个新函数:

    y = tf.constant( 3 )
    gx = f( x, y )
    with tf.Session() as sess: 
        print( sess.run( gx, {x:1} ) )
        print( sess.run( gx, {x:2} ) )
    

    关键是现在我不需要在我的提要字典中传递y 的值。它是常量并在表达式 gx 中捕获。
    同样,如果x 也是一个常量,那么我应该这样声明:

    x = tf.constant(2)
    h = f(x,y)
    with tf.Session() as sess: 
        print( sess.run( h ) )
    

    如您所见,由于我的所有变量都是常量,因此我根本不需要提要字典。这是 Tensorflow 等效于调用不带参数的函数,例如 h()

    但是,和以前一样,当我调用h 时,它可能每次都需要重新评估图表。所以我有两个选择。

    1. 我可以在 numpy 中计算结果,然后用 tensorflow 常量包装该值。
    2. 我可以在 tensorflow 中计算输出,在会话中运行它以获取 numpy 值,然后将其包装在一个常量中。

    在第一个选项中,我会做这样的事情

    fxy = tf.constant( f(2,3) ) 
    

    现在我已经在 Tensorflow 之外预先计算了函数的值,然后将该值包装为常量,以便我可以在其他 tensorflow 函数中使用它。

    相反,如果您的函数使用一些复杂的 Tensorflow 内在函数,或者如果您的函数需要很长时间运行并且您认为在 Tensorflow 中计算机会更快,您只会考虑选项 2:

    with tf.Session() as sess: 
        fxy = tf.constant( sess.run( h ) )
    

    要了解这里发生了什么,请回想一下

    h = f( tf.constant(1), tf.constant(3) )
    

    所以我不需要传递提要字典。 sn-p sess.run( h ) 在 tensorflow 中运行该乘法并将其作为 Numpy 数组返回。最后,我用 tf.constant 包装该值,以便可以在其他 Tensorflow 函数中使用它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-05
      相关资源
      最近更新 更多