GPflow 2:使用多输出核的VGP与GPR模型触发维度不匹配错误
问题背景
参考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中添加输出维度标识。
具体修改步骤
转换数据集格式
- 将输入X从
[N, D]扩展为[N*P, D+1],新增列标记样本所属的输出维度(0到P-1); - 将输出Y从
[N, P]展平为[N*P, 1]。
- 将输入X从
调整核的定义
- 指定
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
相关产品推荐
相关产品推荐

