tensorflow_probability:向后传播正态分布样本的log_prob时,梯度始终为零

时间:2019-04-22 12:37:38

标签: python tensorflow tensorflow-probability

作为项目的一部分,我在使用带有tensorflow_probability的正态分布的梯度时遇到了麻烦。为此,我创建了一个正态分布并绘制了样本。然后,将这个样本的log_prob馈入优化器以更新网络的权重。

如果我得到某个常数的log_prob,我总是会得到非零梯度。不幸的是,我在教程或类似的帮助来源中没有找到任何相关的帮助。

def get_log_prob(mu, std)
   extracted_location = tf.squeeze(extracted_location)
   normal = tfd.Normal(mu, scale=std)
   samples = normal.sample(sample_shape=(1))
   log_prob = normal.log_prob(samples)
   return log_prob

const = tf.constant([0.1], dtype=np.float32)

log_prob = get_log_prob(const, 0.01)
grads = tf.gradients(log_prob, const)

with tf.Session() as sess:
   gradients = sess.run([grads])


print('gradients', gradients)

输出:渐变[array([0。],dtype = float32)]

如果计算样品的梯度,我希望得到非零梯度。而是输出始终为“ 0”。

1 个答案:

答案 0 :(得分:0)

这是TensorFlow概率实现重新参数化梯度(又称为“重新参数化技巧”)的结果,实际上在某些情况下是正确的答案。让我向您展示0.答案的产生方式。

从具有一定位置和规模的正态分布生成样本的一种方法是,首先从标准正态分布生成样本(这通常是某些库提供的函数,例如TensorFlow中的tf.random.normal),然后进行平移并扩大规模。例如。假设tf.random.normal的输出为z。要从正态分布中的位置为x并缩放为loc的样本scale,您可以这样做:x = z * scale + loc

现在,如何计算正态分布下数字的概率密度值?一种方法是逆转该转换,以便您现在处理标准正态分布,然后在那里计算对数概率密度。即log_prob(x) = log_prob_std_normal((x - loc) / scale) + f(scale)f(scale)这个术语来自于转换所涉及的变量的变化,这种解释的形式无关紧要。)

您现在可以将第一个表达式插入第二个表达式,您将得到log_prob(x) = log_prob_std_normal(z) + f(scale),即loc被完全取消了!结果,log_prob相对于loc的梯度为0.。这也解释了为什么如果以常数评估对数概率却没有得到0.的原因:它将丢失用于创建样本的正向变换,并且会得到(通常)非零值渐变。

那么,这何时是正确的行为?当您根据分布下函数的期望值计算分布参数的梯度时,重新参数化梯度是正确的。一种计算这种期望值的方法是进行蒙特卡洛近似,如:tf.reduce_mean(g(dist.sample(N), axis=0)。听起来这就是您正在做的事情(您的g()log_prob()),因此看起来渐变是正确的。