Fork me on GitHub

教程

以下教程将帮助您熟悉 RoBO。您可以在 examples 文件夹中找到所有教程和额外示例的代码。

  1. 使用 RoBO 进行黑盒函数优化
  2. Bohamiann
  3. Fabolas
  4. 多任务贝叶斯优化
  5. 在 HPOLIB2 基准测试上使用 RoBO
  6. 拟合贝叶斯神经网络

使用 RoBO 进行黑盒函数优化

本教程将展示如何使用带有高斯过程和不同采集函数的标准贝叶斯优化来寻找您的(Python)函数的全局最小值。请注意,RoBO 目前只支持连续输入空间,并且无法处理多目标函数。

我们要做的第一件事是导入 numpy(用于目标函数)和 bayesian_optimization 接口

import numpy as np

from robo.fmin import bayesian_optimization

要使用 RoBO,我们必须定义一个代表我们要最小化的目标函数的函数。目标函数的接口相当简单,它接收一个 d 维向量 x 并返回相应的标量函数值。

def objective_function(x):
        y = np.sin(3 * x[0]) * 4 * (x[0] - 1) * (x[0] + 2)
        return y

在运行贝叶斯优化之前,我们首先需要定义输入搜索空间的下界和上界。在这种情况下,我们的搜索空间只包含一个维度,但贝叶斯优化不限于此,通常在高达 10 个(连续)维度时也能正常工作。

lower = np.array([0])
upper = np.array([6])

现在我们已具备所有所需,可以运行 50 次迭代的贝叶斯优化。

results = bayesian_optimization(objective_function, lower, upper, num_iterations=50)

最后我们会得到一个字典,其中包含以下条目:

  • “x_opt”:找到的最佳数据点
  • “f_opt”:对应的函数值
  • “incumbents”:每次迭代后的当前最优值(找到的最佳值)
  • “incumbent_value”:当前最优值的函数值
  • “runtime”:每次迭代后的运行时间(秒)
  • “overhead”:每次迭代的优化开销(即我们未用于评估函数的时间)
  • “X”:所有已评估的数据点
  • “y”:对应的函数评估值

默认情况下,RoBO 使用高斯过程(通过 MCMC 采样获取 GP 的超参数)和对数期望提升作为采集函数。如果您想使用不同的采集函数,例如下置信界限,您可以简单地

results = bayesian_optimization(objective_function, lower, upper, acquisition_func='lcb')

有关采集函数的不同可能选择,请参阅 API 文档。

如果您想深入了解 RoBO 在底层做了什么,可以通过在 Python 脚本顶部添加以下两行来激活 RoBO 的日志记录机制:

import logging
logging.basicConfig(level=logging.INFO)

除了标准贝叶斯优化,RoBO 还包含由 Hennig 等人提出的纯随机搜索和熵搜索的接口。这两种方法都遵循完全相同的接口。

from robo.fmin import entropy_search
from robo.fmin import random_search

results = entropy_search(objective_function, lower, upper)
results = random_search(objective_function, lower, upper)

Bohamiann

RoBO 为使用 Hamiltonian Monte Carlo 人工神经网络 (BOHAMIANN) 的贝叶斯优化提供了简单接口,该方法由 Sprigenberg 等人提出。

如果您想使用 Bohamiann,请确保已安装 Lasagne 和 Theano

pip install Lasagne
pip install theano

并且 sgmcmc 包 在您的 PYTHONPATH 中

Bohamiann 的接口与基于 GP 的贝叶斯优化接口完全相同

from robo.fmin import bohamiann

results = bohamiann(objective_function, lower, upper, num_iterations=50)

这将返回一个字典,其中包含与上述相同的元信息。

@inproceedings{springenberg-nips2016, booktitle = {Advances in Neural Information Processing Systems 29}, month = {December}, title = {Bayesian optimization with robust Bayesian neural networks}, author = {J. T. Springenberg and A. Klein and S.Falkner and F. Hutter}, year = {2016} }

Fabolas

Fabolas(Klein 等人)的思想是将训练数据集大小作为一个额外输入纳入考虑,该输入在优化过程中可以自由选择,但之后是固定的。其思想是通过仅在更便宜的子集上评估单一配置来加速优化,并推断其在完整数据集上的性能。

通过额外建模训练单一配置的成本,Fabolas 利用单位成本的信息增益来选择并在训练数据的小子集上评估配置,这些配置能够提供关于完整数据集上全局最小值的最多信息。

现在,目标函数除了配置之外,还将训练数据集大小作为额外输入。在训练数据子集上训练配置后,它返回完整验证数据集上的验证误差以及训练该配置所花费的时间。

from robo.fmin import fabolas

def objective_function(x, s):
    # Train your algorithm here with x on the dataset subset with length s
    # Estimate the validation error and the cost on the validation data set
    return validation_error, cost

此外,您必须定义配置的输入空间边界以及最小和最大数据集大小。

lower = np.array([-10, -10])
upper = np.array([10, 10])
s_min = 100
s_max = 50000

然后您可以通过以下方式调用 Fabolas:

res = fabolas(objective_function,
                  lower=lower,
                  upper=upper,
                  s_min=s_min,
                  s_max=s_max,
                  num_iterations=100)

您可以在此处找到在 MNIST 上训练支持向量机的完整示例

@article{klein-corr16, author = {A. Klein and S. Falkner and S. Bartels and P. Hennig and F. Hutter}, title = {Fast Bayesian Optimization of Machine Learning Hyperparameters on Large Datasets}, journal = corr, llvolume = {abs/1605.07079}, lurl = {http://arxiv.org/abs/1605.07079}, year = {2016} }

在 HPOLIB2 基准测试上使用 RoBO

HPOlib2 包含一套用于机器学习算法超参数优化的统一接口的基准测试。在以下示例中,我们将使用常用的合成函数 branin。请确保您已安装 HPOlib2。

首先我们加载基准测试并获取配置空间的边界

from hpolib.benchmarks.synthetic_functions import Branin
f = Branin()
info = f.get_meta_information()
bounds = np.array(info['bounds'])

然后我们只需通过以下方式运行 RoBO:

results = bayesian_optimization(f, bounds[:, 0], bounds[:, 1], num_iterations=50)

HPOlib2 允许仅在数据子集上评估单一配置,这使我们能够使用 Fabolas 或 MTBO。如果想使用 Fabolas 来优化(例如)MNIST 上的支持向量机,我们首先必须包装 HPOlib2 基准类,以便传递正确的数据集大小比例。

from hpolib.benchmarks.ml.svm_benchmark import SvmOnMnist

f = SvmOnMnist()

def objective(x, s):
    dataset_fraction = s / s_max

    res = f.objective_function(x, dataset_fraction=dataset_fraction)
    return res["function_value"], res["cost"]

然后我们只需通过以下方式运行 Fabolas:

info = f.get_meta_information()
bounds = np.array(info['bounds'])
lower = bounds[:, 0]
upper = bounds[:, 1]

results = fabolas(objective_function=objective, lower=lower, upper=upper,
                  s_min=100, s_max=s_max, n_init=10, num_iterations=80, n_hypers=20, subsets=[64., 32, 16, 8])

拟合贝叶斯神经网络

在以下教程中,我们将看到如何使用随机 MCMC 采样在我们的数据集上训练贝叶斯神经网络。请注意,RoBO 中的所有模型都实现了相同的接口,您可以轻松地用另一个模型(高斯过程、随机森林等)替换贝叶斯神经网络。

假设我们收集了 sinc 函数的一些数据点

import matplotlib.pyplot as plt
import numpy as np

from robo.models.bnn import BayesianNeuralNetwork
from robo.initial_design.init_random_uniform import init_random_uniform


def f(x):
    return np.sinc(x * 10 - 5).sum(axis=1)

X = init_random_uniform(np.zeros(1), np.ones(1), 20, rng)
y = f(X)

我们现在可以通过以下方式创建和训练神经网络:

model = BayesianNeuralNetwork(sampling_method="sghmc",
                              l_rate=np.sqrt(1e-4),
                              mdecay=0.05,
                              burn_in=3000,
                              n_iters=50000,
                              precondition=True,
                              normalize_input=True,
                              normalize_output=True)
model.train(X, y)

训练后,我们可以使用我们的模型预测任意测试点的均值和方差

x = np.linspace(0, 1, 100)[:, None]
mean_pred, var_pred = model.predict(x)

FANOVA

在以下教程中,我们将展示如何在 RoBO 中使用 FANOVA(函数方差分析)。FANOVA 是一个用于量化函数性能的框架。有关 FANOVA 的更多信息可以在此处找到。

对于此示例,让我们使用 Brannin 作为目标函数,并使用随机搜索作为优化方法。首先,我们必须导入所有必需的包。

from fanova import fANOVA
import numpy as np
from robo.fmin import random_search
from hpolib.benchmarks.synthetic_functions import Branin
import fanova.visualizer

现在我们声明目标函数并获取配置空间的边界。

objective_function = Branin()
info = objective_function.get_meta_information()
bounds = np.array(info['bounds'])
config_space = objective_function.get_configuration_space()

现在我们应用随机搜索

results = random_search(objective_function, bounds[:, 0], bounds[:, 1], num_iterations=50)

获取结果后,我们创建一个 FANOVA 对象并将结果传递给它。

X = np.array([i for i in results['X']])
Y = np.array([i for i in results['y']])
f = fANOVA(X,Y)

现在要计算第一个参数的边际,我们可以写

print(f.quantify_importance((0, )))

为了可视化单个和成对的边际,我们必须首先创建一个包含 fanova 对象、configspace 和目录的可视化器对象。

vis = fanova.visualizer.Visualizer(f, config_space, "./plots/")

然后我们可以通过以下方式绘制单个边际:

vis.plot_marginal(1)

它应该看起来像