这些功能是否等效?

Are these functions equivalent?

我正在构建一个利用 T-distribution noise. I am using functions defined in the numpy library np.random.standard_t and the one defined in tensorflow tf.distributions.StudentT. The link to the documentation of the first function is here and that to the second function is here 的神经网络。我正在使用如下所述的功能:

a = np.random.standard_t(df=3, size=10000)  # numpy's function

t_dist = tf.distributions.StudentT(df=3.0, loc=0.0, scale=1.0)
sess = tf.Session()
b = sess.run(t_dist.sample(10000))

在为 Tensorflow 实现提供的文档中,有一个名为 scale 的参数,其描述为

The scaling factor(s) for the distribution(s). Note that scale is not technically the standard deviation of this distribution but has semantics more similar to standard deviation than variance.

我已将 scale 设置为 1.0,但我无法确定它们是否指的是同一分布。


谁能帮我验证一下?谢谢

我会说它们是,因为在这两种情况下,它们的采样定义方式几乎完全相同。 tf.distributions.StudentT 的采样是这样定义的:

def _sample_n(self, n, seed=None):
  # The sampling method comes from the fact that if:
  #   X ~ Normal(0, 1)
  #   Z ~ Chi2(df)
  #   Y = X / sqrt(Z / df)
  # then:
  #   Y ~ StudentT(df).
  seed = seed_stream.SeedStream(seed, "student_t")
  shape = tf.concat([[n], self.batch_shape_tensor()], 0)
  normal_sample = tf.random.normal(shape, dtype=self.dtype, seed=seed())
  df = self.df * tf.ones(self.batch_shape_tensor(), dtype=self.dtype)
  gamma_sample = tf.random.gamma([n],
                                 0.5 * df,
                                 beta=0.5,
                                 dtype=self.dtype,
                                 seed=seed())
  samples = normal_sample * tf.math.rsqrt(gamma_sample / df)
  return samples * self.scale + self.loc  # Abs(scale) not wanted.

所以它是一个标准正态样本除以参数为df的卡方样本除以df的平方根。将卡方样本作为参数0.5 * df、率0.5的gamma样本,是等价的(卡方是gamma的特例)。 scale 值与 loc 一样,仅在最后一行发挥作用,作为 "relocate" 分布样本在某个点和规模的一种方式。当 scale 为一且 loc 为零时,它们什么都不做。

下面是 np.random.standard_t 的实现:

double legacy_standard_t(aug_bitgen_t *aug_state, double df) {
  double num, denom;

  num = legacy_gauss(aug_state);
  denom = legacy_standard_gamma(aug_state, df / 2);
  return sqrt(df / 2) * num / sqrt(denom);
})

本质上是一样的,只是措辞稍有改动。这里我们也有一个形状为 df / 2 的伽玛,但它是标准的(率一)。但是,缺失的 0.5 现在分子为 sqrt 中的 / 2。所以它只是移动数字。不过,这里没有 scaleloc

事实上,区别在于 TensorFlow 的分布确实是 noncentral t-distributionloc=0.0scale=1.0 相同的一个简单的经验证明是绘制两个分布的直方图,看看它们看起来有多接近。

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
np.random.seed(0)
t_np = np.random.standard_t(df=3, size=10000)
with tf.Graph().as_default(), tf.Session() as sess:
    tf.random.set_random_seed(0)
    t_dist = tf.distributions.StudentT(df=3.0, loc=0.0, scale=1.0)
    t_tf = sess.run(t_dist.sample(10000))
plt.hist((t_np, t_tf), np.linspace(-10, 10, 20), label=['NumPy', 'TensorFlow'])
plt.legend()
plt.tight_layout()
plt.show()

输出:

看起来很接近。显然,从统计样本的角度来看,这不是任何一种证明。如果您仍然不相信,可以使用一些统计工具来测试一个样本是来自某个分布还是两个样本来自同一分布。