在 GPflow 2.0 中使用 Tensorflow 双射链进行边界超参数优化
Bounding hyperparameter optimization with Tensorflow bijector chain in GPflow 2.0
在 GPflow 2.0 中做 GP 回归时,我想在 lengthscale 上设置硬边界(即限制 lengthscale 优化范围)。在这个线程 () 之后,我构建了一个 TensorFlow Bijector 链(参见下面的 bounded_lengthscale
函数)。但是,下面的双射链并不会阻止模型在假定范围之外进行优化。我需要更改什么才能使 bounded_lengthscale
函数对优化设置严格限制?
下面是MRE:
import gpflow
import numpy as np
from gpflow.utilities import print_summary
import tensorflow as tf
from tensorflow_probability import bijectors as tfb
# Noisy training data
noise = 0.3
X = np.arange(-3, 4, 1).reshape(-1, 1).astype('float64')
Y = (np.sin(X) + noise * np.random.randn(*X.shape)).reshape(-1,1)
def bounded_lengthscale(low, high, lengthscale):
"""Returns lengthscale Parameter with optimization bounds."""
affine = tfb.AffineScalar(shift=low, scale=high-low)
sigmoid = tfb.Sigmoid()
logistic = tfb.Chain([affine, sigmoid])
parameter = gpflow.Parameter(lengthscale, transform=logistic, dtype=tf.float32)
parameter = tf.cast(parameter, dtype=tf.float64)
return parameter
# build GPR model
k = gpflow.kernels.Matern52()
m = gpflow.models.GPR(data=(X, Y), kernel=k)
m.kernel.lengthscale.assign(bounded_lengthscale(0, 1, 0.5))
print_summary(m)
# train model
@tf.function(autograph=False)
def objective_closure():
return - m.log_marginal_likelihood()
opt = gpflow.optimizers.Scipy()
opt_logs = opt.minimize(objective_closure,
m.trainable_variables)
print_summary(m)
谢谢!
在 MWE 中,您 assign
一个新的 值 到一个 Parameter
已经存在(并且没有逻辑转换)。该值是使用逻辑变换构造的参数具有的约束-space 值,但不会保留该变换。相反,您需要 将不带逻辑变换的参数替换为 具有所需变换的参数:m.kernel.lengthscale = bounded_lengthscale(0,1,0.5)
.
请注意,您分配给 kernel.lengthscale
属性的对象 必须 是一个 Parameter
实例;如果你像在 MWE 中一样分配 tf.cast(parameter)
的 return 值,这相当于一个常量,它实际上不会被优化!
由于 float32/float64 不匹配,简单地移动此问题中 MWE 中的 tf.cast 不会立即起作用。要修复它,AffineScalar 双射器需要在 float64 中;它没有 dtype
参数,而是将 shift=
和 scale=
的参数转换为所需的类型:
def bounded_lengthscale(low, high, lengthscale):
"""Make lengthscale tfp Parameter with optimization bounds."""
affine = tfb.AffineScalar(shift=tf.cast(low, tf.float64),
scale=tf.cast(high-low, tf.float64))
sigmoid = tfb.Sigmoid()
logistic = tfb.Chain([affine, sigmoid])
parameter = gpflow.Parameter(lengthscale, transform=logistic, dtype=tf.float64)
return parameter
m.kernel.lengthscale = bounded_lengthscale(0, 1, 0.5)
(GPflow 可能应该包含这样的辅助函数,以使有界参数转换更易于使用 - GPflow 始终感谢人们提供帮助,因此如果您想将其转换为拉取请求,请这样做!)
tfb.Sigmoid
现在接受 low
和 high
参数,正如@Brian Patton 在评论中预测的那样。
因此,代码可以简化为:
from tensorflow_probability import bijectors as tfb
def bounded_lengthscale(low, high, lengthscale):
"""Make lengthscale tfp Parameter with optimization bounds."""
sigmoid = tfb.Sigmoid(low, high)
parameter = gpflow.Parameter(lengthscale, transform=sigmoid, dtype='float32')
return parameter
m.kernel.lengthscale = bounded_lengthscale(0, 1, 0.5)
在 GPflow 2.0 中做 GP 回归时,我想在 lengthscale 上设置硬边界(即限制 lengthscale 优化范围)。在这个线程 (bounded_lengthscale
函数)。但是,下面的双射链并不会阻止模型在假定范围之外进行优化。我需要更改什么才能使 bounded_lengthscale
函数对优化设置严格限制?
下面是MRE:
import gpflow
import numpy as np
from gpflow.utilities import print_summary
import tensorflow as tf
from tensorflow_probability import bijectors as tfb
# Noisy training data
noise = 0.3
X = np.arange(-3, 4, 1).reshape(-1, 1).astype('float64')
Y = (np.sin(X) + noise * np.random.randn(*X.shape)).reshape(-1,1)
def bounded_lengthscale(low, high, lengthscale):
"""Returns lengthscale Parameter with optimization bounds."""
affine = tfb.AffineScalar(shift=low, scale=high-low)
sigmoid = tfb.Sigmoid()
logistic = tfb.Chain([affine, sigmoid])
parameter = gpflow.Parameter(lengthscale, transform=logistic, dtype=tf.float32)
parameter = tf.cast(parameter, dtype=tf.float64)
return parameter
# build GPR model
k = gpflow.kernels.Matern52()
m = gpflow.models.GPR(data=(X, Y), kernel=k)
m.kernel.lengthscale.assign(bounded_lengthscale(0, 1, 0.5))
print_summary(m)
# train model
@tf.function(autograph=False)
def objective_closure():
return - m.log_marginal_likelihood()
opt = gpflow.optimizers.Scipy()
opt_logs = opt.minimize(objective_closure,
m.trainable_variables)
print_summary(m)
谢谢!
在 MWE 中,您 assign
一个新的 值 到一个 Parameter
已经存在(并且没有逻辑转换)。该值是使用逻辑变换构造的参数具有的约束-space 值,但不会保留该变换。相反,您需要 将不带逻辑变换的参数替换为 具有所需变换的参数:m.kernel.lengthscale = bounded_lengthscale(0,1,0.5)
.
请注意,您分配给 kernel.lengthscale
属性的对象 必须 是一个 Parameter
实例;如果你像在 MWE 中一样分配 tf.cast(parameter)
的 return 值,这相当于一个常量,它实际上不会被优化!
由于 float32/float64 不匹配,简单地移动此问题中 MWE 中的 tf.cast 不会立即起作用。要修复它,AffineScalar 双射器需要在 float64 中;它没有 dtype
参数,而是将 shift=
和 scale=
的参数转换为所需的类型:
def bounded_lengthscale(low, high, lengthscale):
"""Make lengthscale tfp Parameter with optimization bounds."""
affine = tfb.AffineScalar(shift=tf.cast(low, tf.float64),
scale=tf.cast(high-low, tf.float64))
sigmoid = tfb.Sigmoid()
logistic = tfb.Chain([affine, sigmoid])
parameter = gpflow.Parameter(lengthscale, transform=logistic, dtype=tf.float64)
return parameter
m.kernel.lengthscale = bounded_lengthscale(0, 1, 0.5)
(GPflow 可能应该包含这样的辅助函数,以使有界参数转换更易于使用 - GPflow 始终感谢人们提供帮助,因此如果您想将其转换为拉取请求,请这样做!)
tfb.Sigmoid
现在接受 low
和 high
参数,正如@Brian Patton 在评论中预测的那样。
因此,代码可以简化为:
from tensorflow_probability import bijectors as tfb
def bounded_lengthscale(low, high, lengthscale):
"""Make lengthscale tfp Parameter with optimization bounds."""
sigmoid = tfb.Sigmoid(low, high)
parameter = gpflow.Parameter(lengthscale, transform=sigmoid, dtype='float32')
return parameter
m.kernel.lengthscale = bounded_lengthscale(0, 1, 0.5)