1

作为项目的一部分,我在使用 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”。

4

1 回答 1

2

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

从具有某些位置和比例的正态分布生成样本的一种方法是首先从标准正态分布生成样本(这通常是一些库提供的函数,例如tf.random.normal在 TensorFlow 中),然后对其进行移位和缩放。例如,假设 is 的tf.random.normal输出z。要从具有 location和 scalex的正态分布中获取样本,您可以:locscalex = 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相对于的梯度loc0.。这也解释了为什么如果您以常数评估对数概率,您不会得到 a 0.:它将丢失用于创建样本的正向变换,并且您将获得一些(通常)非零梯度。

那么,什么时候是正确的行为呢?当您计算分布参数相对于该分布下函数的期望的梯度时,重新参数化梯度是正确的。计算这种期望的一种方法是进行蒙特卡罗近似,如下所示tf.reduce_mean(g(dist.sample(N), axis=0):听起来这就是你正在做的事情(你在哪里g()log_prob(),所以看起来渐变是正确的。

于 2019-04-22T22:18:12.290 回答