0

我有一个SGPR模型:

import numpy as np
import gpflow

X, Y = np.random.randn(50, 2), np.random.randn(50, 1)
Z1 = np.random.randn(13, 2)

k = gpflow.kernels.SquaredExponential()
m = gpflow.models.SGPR(data=(X, Y), kernel=k, inducing_variable=Z1)

而且我想分配诱导变量但具有不同的形状,例如:

Z2 = np.random.randn(29, 2)
m.inducing_variable.Z.assign(Z2)

但如果我这样做,我得到:

ValueError: Shapes (13, 2) and (29, 2) are incompatible

有没有办法在不重新定义模型的情况下重新分配诱导变量?

背景:我不想用诱导变量优化模型,而是在不优化诱导变量的情况下优化模型,在优化的每一步手动重新分配诱导变量。

4

1 回答 1

0

更新:此问题已由https://github.com/GPflow/GPflow/pull/1594解决,它将成为下一个 GPflow 补丁版本 (2.1.4) 的一部分。

通过该修复,您不需要自定义类。您需要做的就是None沿第一个维度显式设置静态形状:

inducing_variable = gpflow.inducing_variables.InducingPoints(
    tf.Variable(
        Z1,  # initial value
        trainable=False,  # True does not work - see Note below
        shape=(None, Z1.shape[1]),  # or even tf.TensorShape(None)
        dtype=gpflow.default_float(),  # required due to tf's 32bit default
    )
)
m = gpflow.models.SGPR(data=(X, Y), kernel=k, inducing_variable=inducing_variable)

然后m.inducing_variable.Z.assign(Z2)应该可以正常工作。

请注意,在这种情况下Z 无法训练,因为 TensorFlow 优化器需要在构建时知道形状并且不支持动态形状。


现在(从 GPflow 2.1.2 开始)没有内置方法可以改变 的诱导变量的形状SGPR,尽管原则上是可行的。你可以用你自己的诱导变量类得到你想要的东西:

class VariableInducingPoints(gpflow.inducing_variables.InducingPoints):
     def __init__(self, Z, name=None):
         super().__init__(Z, name=name)
         # overwrite with Variable with None as first element in shape so
         # we can assign arrays with arbitrary length along this dimension:
         self.Z = tf.Variable(Z, dtype=gpflow.default_float(),
             shape=(None, Z.shape[1])
         )

     def __len__(self):
         return tf.shape(self.Z)[0]  # dynamic shape
         # instead of the static shape returned by the InducingPoints parent class

然后做

m = gpflow.models.SGPR(
    data=(X, Y), kernel=k, inducing_variable=VariableInducingPoints(Z1)
)

反而。然后你m.inducing_variable.Z.assign()应该随心所欲地工作。

(对于SVGP,诱导变量的大小和由q_mu和定义的分布q_sqrt必须匹配,并且在构造时就知道了,所以在这种情况下,改变诱导变量的数量就不那么简单了。)

于 2020-09-30T22:09:11.170 回答