Tensorflow:在同一操作中共享两个不同变量的值

时间:2016-01-12 15:47:30

标签: python tensorflow

我最近一直在试验TensorFlow(TF),我遇到了这个问题:说我想计算函数的值和梯度

f(x) = \sum_{ijk} x_i x_j x_k

其中x的索引不同,但都引用相同的向量bold x而J是随机常量(在物理学中这是一个旋转玻璃模型)。然后,渐变wrt x_k就是

grad_k(x) = sum_ij x_i*x_j

因此f对N ^ 3项求和,gradf求和N ^ 2项N次。我已经通过生成总和的所有项来实现f作为秩3张量并且减少了所有条目的总和。然后区分我申请

tf.gradients(f, xk)[0]

其中f是损失函数,xk是变量。这是一个MWE,假设所有的J都是1

import numpy as np
import tensorflow as tf

#first I define the variable                                                                                                                                                                  
n=10 #size of x                                                                                                                                                                               
x1 = tf.Variable(tf.zeros([n], dtype='float64'))
x2 = tf.placeholder(tf.float64, shape=[n])

#here I define the cost function                                                                                                                                                              
f_tensor = tf.mul(tf.mul(tf.reshape(x1, [n]),
                         tf.reshape(x2, [n,1])),
                  tf.reshape(x2, [n,1,1]))
f = tf.reduce_sum(f_tensor)

session = tf.Session()
init = tf.initialize_all_variables()
session.run(init)

#run on test array                                                                                                                                                                            
xtest = np.ones(n)
res = session.run([f, tf.gradients(f, x1)[0]],
                  feed_dict={x1 : xtest,
                             x2 : xtest})

assert res[0] == 1000
assert all(res[1] == np.array([100 for _ in xrange(n)]))

我需要独立调用run多次,我想将变量赋值的数量减少到只有一个,因为x1,x2指的是同一个向量。

n=200(在GeForce GTX 650上)的相关示例进行的一些分析显示

  • cuMemcpyDtoHAsync需要63%的时间
  • cuMemcpyHtoDAsync 18%和
  • cuEventRecord 18%。

(这个mwe的结果相似)

因此,在GPU上执行计算时,赋值是最昂贵的操作。显然,增加n会增加开销,从而部分抵消使用GPU的好处。

关于我如何能够通过仅传输x一次来减少开销的任何建议?

关于如何减少任何其他开销的任何其他建议都将受到极大的赞赏。

修改

要显示问题,我将按照 mrry 的建议进行操作。 如果我用x1替换x2的所有实例,那么MWE将如下所示

#first I define the variable                                                                                                                                                                  
n=10 #size of x                                                                                                                                                                               
x1 = tf.Variable(tf.zeros([n], dtype='float64'))

#here I define the cost function                                                                                                                                                              
f_tensor = tf.mul(tf.mul(tf.reshape(x1, [n]),
                         tf.reshape(x1, [n,1])),
                  tf.reshape(x1, [n,1,1]))
f = tf.reduce_sum(f_tensor)

session = tf.Session()
init = tf.initialize_all_variables()
session.run(init)

#run on test array                                                                                                                                                                            
xtest = np.ones(n)
session.run(x1.assign(xtest))
res = session.run([f, tf.gradients(f, x1)[0]])

assert res[0] == 1000
for g in res[1]:
    assert g == 100

并且第二个断言将失败,因为渐变的每个条目将是300而不是100,因为它应该是。原因是虽然xi,xj,xk都指向相同的向量,但它们在符号上是不同的:用相同的变量替换所有x将导致x ^ 3的导数,即3 * x ^ 2,因此结果第二个MWE。

P.S。为清晰起见,我还明确指定了x1

2 个答案:

答案 0 :(得分:2)

实现所需结果的一种方法是使用tf.stop_gradient()操作来制作变量x1的有效副本,而不会影响渐变:

import numpy as np
import tensorflow as tf

# First define the variable.
n = 10 # size of x                                                                                                                                                                               
x1 = tf.Variable(tf.zeros([n], dtype=tf.float64))
x2 = tf.stop_gradient(x1)

# Now define the cost function                                                                                                                                                              
f_tensor = tf.mul(tf.mul(tf.reshape(x1, [n]),
                         tf.reshape(x2, [n,1])),
                  tf.reshape(x2, [n,1,1]))
f = tf.reduce_sum(f_tensor)

session = tf.Session()
init = tf.initialize_all_variables()
session.run(init)

# Run on test array                                                                                                                                                                            
xtest = np.ones(n)
res = session.run([f, tf.gradients(f, x1)[0]],
                  feed_dict={x1 : xtest})

assert res[0] == 1000
for g in res[1]:
    assert g == 100

答案 1 :(得分:1)

我无法在上面发表评论(声誉不够),但请注意分析梯度应为

$$ \ frac {\ partial f} {\ partial x_k} = \ sum_ {ij} J_ {ijk} x_i x_j + \ sum_ {ij} J_ {ikj} x_i x_j + \ sum_ {ij} J_ {kij} x_i x_j。 $$