作为项目的一部分,我在使用带有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”。
最佳答案
这是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()
),因此看起来渐变是正确的。
关于python - tensorflow_probability:向后传播正态分布样本的log_prob时,梯度始终为零,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55794542/