gpflow SVGP 的爆炸梯度

Exploding gradient for gpflow SVGP

在为大数据集优化具有泊松似然的 SVGP 时,我看到了我认为的梯度爆炸。 几个 epoch 之后,我看到 ELBO 的尖锐下降,然后在摆脱之前取得的所有进展后非常缓慢地恢复。 大约21次迭代对应一个Epoch。

这个尖峰(至少是第二个尖峰)导致参数完全改变(对于参数向量,我只是绘制了范数以查看变化):

我该如何处理?我的第一种方法是剪切渐变,但这似乎需要深入挖掘 gpflow 代码。

我的设置:

训练通过变分参数的自然梯度和其余参数的 ADAM 进行,自然梯度 Gamma 的时间表缓慢(线性)增加。

对于我的设置,批量和诱导点大小尽可能大 (均为 2^12,数据集由约 88k 个样本组成)。我包括 1e-5 抖动并用 kmeans 初始化诱导点。

我使用组合核,由 RBF、Matern52、周期核和线性核的组合组成,共有 95 个特征(其中很多是由于 one-hot 编码),都是可学习的. 长度尺度用 gpflow.transforms.

变换
    with gpflow.defer_build():
        k1 = Matern52(input_dim=len(kernel_idxs["coords"]), active_dims=kernel_idxs["coords"], ARD=False)
        k2 = Periodic(input_dim=len(kernel_idxs["wday"]), active_dims=kernel_idxs["wday"])
        k3 = Linear(input_dim=len(kernel_idxs["onehot"]), active_dims=kernel_idxs["onehot"], ARD=True)
        k4 = RBF(input_dim=len(kernel_idxs["rest"]), active_dims=kernel_idxs["rest"], ARD=True)
        #
        k1.lengthscales.transform = gpflow.transforms.Exp()
        k2.lengthscales.transform = gpflow.transforms.Exp()
        k3.variance.transform = gpflow.transforms.Exp()
        k4.lengthscales.transform = gpflow.transforms.Exp()

        m = gpflow.models.SVGP(X, Y, k1 + k2 + k3 + k4, gpflow.likelihoods.Poisson(), Z,
                               mean_function=gpflow.mean_functions.Constant(c=np.ones(1)),
                               minibatch_size=MB_SIZE, name=NAME)
        m.mean_function.set_trainable(False)

    m.compile()

更新:仅使用 ADAM 按照 Mark 的建议,我只切换到 ADAM, 这帮助我摆脱了突然的爆炸。不过我还是只用natgrad的一个epoch来初始化,貌似省了不少时间。

此外,变分参数的变化似乎不那么突然(至少就它们的标准而言)。我猜他们现在会收敛得更慢,但至少它是稳定的。

这很有趣。也许尽量不使用 natgrads 也是一个好主意。裁剪渐变确实看起来像是一种可行的技巧。是的,这需要深入研究 GPflow 代码。一个可以帮助解决这个问题的技巧是不直接使用 GPflow 优化器。 model._likelihood_tensor 包含应该优化的 TF 张量。也许使用一些手动 TensorFlow 魔法,您可以在 运行 优化器之前在此处进行梯度裁剪。

总的来说,我认为这听起来像是您偶然发现了一个实际的研究问题。通常这些大的梯度在模型中有一个很好的理由,可以通过仔细考虑来解决。某些 monte carlo 估计值是否存在差异? objective 函数是否表现不佳?

关于为什么不使用自然渐变有帮助。自然梯度使用 Fisher 矩阵作为预条件子来执行二阶优化。这样做会导致参数 space 发生相当激进的移动。在某些情况下(当有可用的共轭关系时)这些激进的举动可以使优化更快。这种具有泊松似然的情况不是存在必然有助于优化的共轭关系的情况。事实上,Fisher 预调节器通常是有害的,尤其是当变分参数不接近最佳值时。

补充一下上面 Mark 的回答,当在 non-conjugate 模型中使用 nat grads 时,可能需要进行一些调整才能获得最佳性能,并且不稳定可能是一个问题。正如 Mark 指出的那样,提供潜在更快收敛的大步长也可能导致参数在参数 space 的坏区域结束。当变分近似很好(即真实后验和近似后验很接近)时,有充分的理由期望 nat grad 会表现良好,但不幸的是,一般情况下没有灵丹妙药。请参阅 https://arxiv.org/abs/1903.02984 了解一些直觉。