首页 > 解决方案 > 为 GPflow 模型预计算张量流张量

问题描述

我想将稀疏高斯过程模型(来自 GPflow 库)包含到另一个项目中。问题是我不能一次调用多个输入的预测函数,但我必须按顺序调用它。我检查了 SGPR 类 ( https://github.com/GPflow/GPflow/blob/master/gpflow/models/sgpr.py ) 中的预测函数 predict_F ,发现我可以提前预先计算很多东西。因此,我创建了一个 SGPR 的子类并编写了一个预计算方法,修改了预测函数:

@params_as_tensors
def precompute(self):
    p_num_inducing = len(self.feature)
    p_err = self.Y - self.mean_function(self.X)
    p_Kuf = self.feature.Kuf(self.kern, self.X)
    p_Kuu = self.feature.Kuu(self.kern, jitter=settings.numerics.jitter_level)
    p_sigma = tf.sqrt(self.likelihood.variance)
    self.p_L = tf.cholesky(p_Kuu)
    p_A = tf.matrix_triangular_solve(self.p_L, p_Kuf, lower=True) / p_sigma
    p_B = tf.matmul(p_A, p_A, transpose_b=True) + tf.eye(p_num_inducing, dtype=settings.tf_float)

    self.p_LB = tf.cholesky(p_B)
    p_Aerr = tf.matmul(p_A, p_err)
    self.p_c = tf.matrix_triangular_solve(self.p_LB, p_Aerr, lower=True) / p_sigma



@params_as_tensors
def _build_predict(self, Xnew, full_cov=False):
    """
    Compute the mean and variance of the latent function at some new points
    Xnew. For a derivation of the terms in here, see the associated SGPR
    notebook.
    """
    Kus = self.feature.Kuf(self.kern, Xnew)
    tmp1 = tf.matrix_triangular_solve(self.p_L, Kus, lower=True)
    tmp2 = tf.matrix_triangular_solve(self.p_LB, tmp1, lower=True)
    mean = tf.matmul(tmp2, self.p_c, transpose_a=True)

    if full_cov:
        var = self.kern.K(Xnew) + tf.matmul(tmp2, tmp2, transpose_a=True) \
              - tf.matmul(tmp1, tmp1, transpose_a=True)
        shape = tf.stack([1, 1, tf.shape(self.Y)[1]])
        var = tf.tile(tf.expand_dims(var, 2), shape)
    else:
        var = self.kern.Kdiag(Xnew) + tf.reduce_sum(tf.square(tmp2), 0) \
              - tf.reduce_sum(tf.square(tmp1), 0)
        shape = tf.stack([1, tf.shape(self.Y)[1]])
        var = tf.tile(tf.expand_dims(var, 1), shape)
    return mean + self.mean_function(Xnew), var

但是当我运行代码时,速度没有区别。我想tensorflow只有在我调用predict_f时才会执行所有表达式,但我不知道如何显式地预先计算一些张量。希望tensorflow大师可以帮助我,在此先感谢!

标签: pythontensorflowgpflow

解决方案


我找到了一个愚蠢但直接的解决方案来解决这个问题。这是 SGPR 类的包装器,它预先计算一些常见的矩阵,然后将它们用于预测。

from gpflow.models import GPModel, SGPR
from gpflow.decors import params_as_tensors, autoflow
from gpflow import settings
from gpflow.params import Parameter, DataHolder
import tensorflow as tf

class fastSGPR(SGPR, GPModel):
    def __init__(self,X_tr, Y_tr, kernel, Zp):
        gpflow.models.SGPR.__init__(self,X_tr, Y_tr, kern=kernel, Z=Zp)
        print("Model has been initialized")

    @autoflow()
    @params_as_tensors
    def precompute(self):
        print("Precomputing required tensors...")
        p_num_inducing = len(self.feature)
        p_err = self.Y - self.mean_function(self.X)
        p_Kuf = self.feature.Kuf(self.kern, self.X)
        p_Kuu = self.feature.Kuu(self.kern, jitter=settings.numerics.jitter_level)
        p_sigma = tf.sqrt(self.likelihood.variance)
        self.p_L = tf.cholesky(p_Kuu)
        p_A = tf.matrix_triangular_solve(self.p_L, p_Kuf, lower=True) / p_sigma
        p_B = tf.matmul(p_A, p_A, transpose_b=True) + tf.eye(p_num_inducing, dtype=settings.tf_float)

        self.p_LB = tf.cholesky(p_B)
        p_Aerr = tf.matmul(p_A, p_err)
        self.p_c = tf.matrix_triangular_solve(self.p_LB, p_Aerr, lower=True) / p_sigma
        print("Tensors have been precomputed")
        return self.p_L, self.p_LB, self.p_c

    @autoflow((settings.float_type, [None, None]), (settings.float_type, [None, None]), (settings.float_type, [None, None]), (settings.float_type, [None, None]))
    def predict_f(self, Xnew, L, LB, c):
        """
        Compute the mean and variance of the latent function(s) at the points
        Xnew.
        """
        return self._build_predict(Xnew, L, LB, c)

    @params_as_tensors
    def _build_predict(self, Xnew, L, LB, c, full_cov=False):
        """
        Compute the mean and variance of the latent function at some new points
        Xnew. For a derivation of the terms in here, see the associated SGPR
        notebook.
        """
        Kus = self.feature.Kuf(self.kern, Xnew)
        tmp1 = tf.matrix_triangular_solve(L, Kus, lower=True)
        tmp2 = tf.matrix_triangular_solve(LB, tmp1, lower=True)
        mean = tf.matmul(tmp2, c, transpose_a=True)

        if full_cov:
            var = self.kern.K(Xnew) + tf.matmul(tmp2, tmp2, transpose_a=True) \
                  - tf.matmul(tmp1, tmp1, transpose_a=True)
            shape = tf.stack([1, 1, tf.shape(self.Y)[1]])
            var = tf.tile(tf.expand_dims(var, 2), shape)
        else:
            var = self.kern.Kdiag(Xnew) + tf.reduce_sum(tf.square(tmp2), 0) \
                  - tf.reduce_sum(tf.square(tmp1), 0)
            shape = tf.stack([1, tf.shape(self.Y)[1]])
            var = tf.tile(tf.expand_dims(var, 1), shape)
        return mean + self.mean_function(Xnew), var

    def assign(self, params):
        params1 = dict(params)
        params1["fastSGPR/kern/variance"] = params1.pop("SGPR/kern/variance")
        params1["fastSGPR/kern/lengthscales"] = params1.pop("SGPR/kern/lengthscales")
        params1["fastSGPR/likelihood/variance"] = params1.pop("SGPR/likelihood/variance")
        params1["fastSGPR/feature/Z"] = params1.pop("SGPR/feature/Z")
        SGPR.assign(self,params1)

推荐阅读