我最近一直在试验TensorFlow(TF),我遇到了这个问题:说我想计算函数的值和梯度
其中x的索引不同,但都引用相同的向量而J是随机常量(在物理学中这是一个旋转玻璃模型)。然后,渐变wrt 就是
因此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上)的相关示例进行的一些分析显示
(这个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
答案 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。 $$