Skip to main content
 首页 » 编程设计

python之在 Tensorflow 中计算梯度

2024年12月31日29haluo1

最近,我正在尝试在学习领域做一些实验。但是,我发现 Tensorflow 中有两个函数可以帮助我计算梯度。有时他们可以给我相同的答案,但有时却不能。我不知道这种情况的原因。

以下是我的函数,它有一个明确的等式。

def function_1(x): 
    return tf.sin(x) * x + tf.cos(x) * tf.exp(x) 

然后,我使用以下两个函数来计算梯度并获得相同的结果。

x = tf.Variables(2.0, name='x') 
gradient_1 = tf.gradients(function_1(x), [x]) 
gradient_2 = tf.train.AdamOptimizer().compute_gradients(function_1(x), var_list=[x]) 

但是,当我尝试使用它们来计算没有显式方程的函数的梯度时,它们提供了我不同的答案。例如,我从高斯过程中采样函数,详细信息如下。

def expectation(x): 
    point = np.reshape(np.linspace(-5.0, 5.0, 300), (300, 1)) 
    kernel_matrix_np = np.exp(-(point - np.transpose(point))**2 / (2 * 1.5**2)) 
 
    def reference_point(): 
        covariance = kernel_matrix_np 
        np.random.seed(100) 
        sampled_funcs = np.random.multivariate_normal(np.ones(len(point)), covariance) 
        return sampled_funcs 
    ref_point = tf.transpose(tf.convert_to_tensor(reference_point(), dtype=tf.float32)) 
    point = tf.reshape(tf.linspace(-5.0, 5.0, 300), (300, 1)) 
    kernel_matrix_tf = tf.exp(-(point - tf.transpose(point))**2 / (2 * 1.5**2)) 
    inverse_kernel_matrix = tf.matrix_inverse(kernel_matrix_tf) 
    kernel_vector = tf.exp(-(x - tf.transpose(point))**2 / (2 * 1.5**2)) 
    mu = tf.matmul(kernel_vector, inverse_kernel_matrix) 
    ref_point = tf.expand_dims(ref_point, axis=1) 
    mu = tf.matmul(mu, ref_point) 
    return mu 
 
x = tf.Variable(2.0, name='x') 
gradients_1 = tf.train.AdamOptimizer().compute_gradients(expectation(x), var_list=[x]) 
graidents_2 = tf.gradients(expectation(x), [x]) 
 
with tf.Session() as sess: 
    sess.run(tf.global_variables_initializer()) 
    print('The gradient one is', sess.run(gradients_1)) 
    print('The gradient two is', sess.run(graidents_2)) 

结果如下。

The gradient one is [(-24.727448, 2.0)] 
The gradient two is [-27.727448] 

我不确定问题出在哪里以及这两个功能如何工作。非常感谢!

请您参考如下方法:

梯度的计算方式完全相同。您有精度问题,可能是因为您的求幂 + 矩阵求逆。

这里是使用 float64 而不是 float32 的版本,其梯度确实相同:

def expectation(x): 
    point = np.reshape(np.linspace(-5.0, 5.0, 300), (300, 1)) 
    kernel_matrix_np = np.exp(-(point - np.transpose(point))**2 / (2 * 1.5**2)) 
 
    def reference_point(): 
        covariance = kernel_matrix_np 
        np.random.seed(100) 
        sampled_funcs = np.random.multivariate_normal(np.ones(len(point)), covariance) 
        return sampled_funcs 
    ref_point = tf.transpose(tf.convert_to_tensor(reference_point(), dtype=tf.float64))  # <--- 
    five64 = tf.convert_to_tensor(5.0, dtype=tf.float64)  # <--- 
    point = tf.reshape(tf.linspace(-five64, 5.0, 300), (300, 1))  # <--- 
    kernel_matrix_tf = tf.exp(-(point - tf.transpose(point))**2 / (2 * 1.5**2)) 
    inverse_kernel_matrix = tf.matrix_inverse(kernel_matrix_tf) 
    kernel_vector = tf.exp(-(x - tf.transpose(point))**2 / (2 * 1.5**2)) 
    mu = tf.matmul(kernel_vector, inverse_kernel_matrix) 
    ref_point = tf.expand_dims(ref_point, axis=1) 
    mu = tf.matmul(mu, ref_point) 
    return mu 
 
x = tf.Variable(2.0, dtype=tf.float64, name='x')  # <--- 
gradients_1 = tf.train.AdamOptimizer().compute_gradients(expectation(x), var_list=[x]) 
graidents_2 = tf.gradients(expectation(x), [x]) 
 
with tf.Session() as sess: 
    sess.run(tf.global_variables_initializer()) 
    print('The gradient one is', sess.run(gradients_1)) 
    print('The gradient two is', sess.run(graidents_2)) 

(我修改过的行标有花哨的箭头注释)

我的输出:

>>> The gradient one is [(-21.5, 2.0)] 
>>> The gradient two is [-21.5] 

请注意,优化器的 compute_gradients 也会返回 x 本身的值。这就是为什么你有一个元组而不是只有梯度(第一个值)。