You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GPflow 2:使用多输出核的VGP与GPR模型触发维度不匹配错误

GPflow 2.5.2中VGP/GPR搭配SharedIndependent核的维度不匹配问题解决

问题背景

参考GPflow 2.5.2文档的多输出核示例Notebook,因数据量较小无需稀疏特性,尝试将SVGP模型替换为VGP或GPR并使用SharedIndependent多输出核,但两种模型均触发矩阵乘法维度不匹配的ValueError。沿用SVGP的数据集格式,且按建议调整VGP的q_mu和q_sqrt参数后仍无效。

错误信息

VGP模型报错

ValueError: Dimensions must be equal, but are 2 and 100 for '{{node MatMul}} = BatchMatMulV2[T=DT_DOUBLE, adj_x=false, adj_y=false](Cholesky, MatMul/identity_CONSTRUCTED_AT_top_level/forward/ReadVariableOp)' with input shapes: [100,2,2], [100,2].

GPR模型报错

ValueError: Dimensions must be equal, but are 2 and 100 for '{{node triangular_solve/MatrixTriangularSolve}} = MatrixTriangularSolve[T=DT_DOUBLE, adjoint=false, lower=true](Cholesky, sub)' with input shapes: [100,2,2], [100,2].

尝试过的无效代码

m.q_mu = np.zeros((len(x_train)*len(y_train.T), 1), dtype=gpflow.config.default_float())
m.q_sqrt = np.expand_dims(np.identity(len(x_train)*len(y_train.T), dtype=gpflow.config.default_float()), axis=0)

完整复现代码

import gpflow as gpf    
import numpy as np

def generate_data(N=100):
    X1 = np.random.rand(N, 1)

    Y1 = np.sin(6 * X1) + np.random.randn(*X1.shape) * 0.03 + 2
    Y2 = np.sin(5 * X1 + 0.7) + np.random.randn(*X1.shape) * 0.1 + 0.5

    return X1, np.concatenate((Y1, Y2), axis=1)

N=100
M=15
P=2

data = (X, Y) = generate_data(N)

# 创建多输出核
kernel = gpf.kernels.SharedIndependent(
    gpf.kernels.Matern52(active_dims=list(range(X.shape[1]))), output_dim=P
)

# SVGP模型(可正常运行)
Zinit = np.linspace(0, 1, M)[:, None]
Z = Zinit.copy()
iv = gpf.inducing_variables.SharedIndependentInducingVariables(
    gpf.inducing_variables.InducingPoints(Z)
)

m = gpf.models.SVGP(kernel, gpf.likelihoods.Gaussian(), inducing_variable=iv, num_latent_gps=P)

optimizer = gpf.optimizers.Scipy()
optimizer.minimize(
    m.training_loss_closure(data),
    variables=m.trainable_variables,
    method="l-bfgs-b",
    options={"iprint": 0, "maxiter": 2000},
)

# 尝试VGP(报错)
m = gpf.models.VGP(data, kernel, gpf.likelihoods.Gaussian(), num_latent_gps=P)
optimizer = gpf.optimizers.Scipy()
optimizer.minimize(
    m.training_loss,
    variables=m.trainable_variables,
    method="l-bfgs-b",
    options={"iprint": 0, "maxiter": 2000},
)

# 尝试GPR(报错)
m = gpf.models.GPR(data, kernel)
optimizer = gpf.optimizers.Scipy()
optimizer.minimize(
    m.training_loss,
    variables=m.trainable_variables,
    method="l-bfgs-b",
    options={"iprint": 0, "maxiter": 2000},
)

问题根源与解决方法

SharedIndependent核针对独立多输出场景设计,但VGP/GPR与SVGP对多输出数据的格式要求不同:

  • SVGP支持直接输入形状为[N, P]的Y(N为样本数,P为输出维度);
  • VGP/GPR则要求数据转换为长格式(long format):将每个输出维度的样本拆分为单独行,同时在输入X中添加输出维度标识。

具体修改步骤

  1. 转换数据集格式

    • 将输入X从[N, D]扩展为[N*P, D+1],新增列标记样本所属的输出维度(0到P-1);
    • 将输出Y从[N, P]展平为[N*P, 1]。
  2. 调整核的定义

    • 指定active_dims为原始输入的维度索引,确保核仅作用于原始输入特征,输出维度标识由模型自动处理。

修改后可运行代码

# 转换为长格式数据
X_long = np.repeat(X, P, axis=0)
output_indices = np.tile(np.arange(P)[:, None], (N, 1))
X_long = np.concatenate([X_long, output_indices], axis=1)
Y_long = Y.flatten()[:, None]

# 重新定义核
kernel = gpf.kernels.SharedIndependent(
    gpf.kernels.Matern52(active_dims=[0]), output_dim=P
)

# VGP模型
m_vgp = gpf.models.VGP((X_long, Y_long), kernel, gpf.likelihoods.Gaussian(), num_latent_gps=P)
optimizer = gpf.optimizers.Scipy()
optimizer.minimize(
    m_vgp.training_loss,
    variables=m_vgp.trainable_variables,
    method="l-bfgs-b",
    options={"iprint": 0, "maxiter": 2000},
)

# GPR模型
m_gpr = gpf.models.GPR((X_long, Y_long), kernel)
optimizer = gpf.optimizers.Scipy()
optimizer.minimize(
    m_gpr.training_loss,
    variables=m_gpr.trainable_variables,
    method="l-bfgs-b",
    options={"iprint": 0, "maxiter": 2000},
)

补充说明

之前调整q_mu和q_sqrt无效的核心原因是数据格式不匹配,VGP的q_mu形状应为[N*P, P],但只有先修正数据格式,参数调整才有意义。

内容的提问来源于stack exchange,提问作者tamara d

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 11:05:19