微信号:deep_intelligence(欢迎关注!)

weixin.qq.com/r/ry7r8xz (二维码自动识别)

您是否厌倦了babysittin您的DL模型?如果是这样,你就来对地方了。在这篇文章中,我们讨论了有效搜索任何深度学习模型的最佳超参数集的动机和策略。我们将演示如何在FloydHub上完成这项工作。当您阅读完这篇文章后,您会学到一个有用的工具 ,使您尽可能自动地为深度学习任务找到最佳配置。

与机器学习模型不同,深度学习模型实际上充满了超参数。当然,并非所有这些变数都以相同的方式对模型的学习过程做出贡献,但是,鉴于这种额外的复杂性,很明显在这样一个高维空间中找到这些变数的最佳配置并不是一个微不足道的挑战。幸运的是,我们有不同的策略和工具来解决搜索问题。

我们的目标

如何?

我们希望找到超参数的最佳配置,为感兴趣的度量实现验证/测试集的最佳分数

为什么?

在给定可用资源的情况下,每个科学家和研究人员都希望获得最佳模型:??,??和?(又名计算金钱时间)。有效的超参数搜索是这个难题的缺失部分,将帮助我们实现这一目标。

什么时候?

  • 研究人员和业余爱好者在最后的开发阶段尝试其中一种搜索策略是很常见的。
  • 超参数搜索作为半/全自动深度学习流程中的阶段或组件也很常见。显然,这在公司的数据科学团队中更为常见。

等等,但究竟什么是超参数?

让我们从最简单的定义开始,

超参数是您在构建机器/深度学习模型时可以转动的旋钮。

或者:

超参数是在开始训练前需要预先确定和手动设置的训练变数。

我们可能会同意学习率和丢弃率(dropout)是超参数,但模型的设计变数呢?例如嵌入,层数,激活函数等。我们应该将这些变数视为超参数吗?

为简单起见,是的 - 我们也可以将模型设计组件视为超参数集的一部分。

那么,从训练过程中获得的参数—— 从数据中学习的变数是超参数吗?这些权重称为模型参数。但我们会将它们从超参数集中排除。

好的,让我们尝试一个真实的例子。请看下面的图片,说明深度学习模型中变数的不同分类。

我们的下一个问题:搜索费用很高

现在我们知道我们想要搜索超参数的最佳配置,我们面临的挑战是搜索超参数是一个????constra约束的迭代过程

一切都以有前途的配置的猜测(步骤1)开始,然后我们将需要等到完全训练(步骤2)以获得对感兴趣的度量的实际评估(步骤3)。我们将跟踪搜索过程的进度(步骤4),然后根据我们的搜索策略,我们将选择一个新的猜测(步骤1)。

我们将继续这样做,直到我们达到终止条件(例如用完???)。

我们来谈谈策略

我们有四种主要策略可用于搜索最佳配置。

  • Babysitting (或 Trial & Error)
  • 网格搜索 Grid Search
  • 随机搜索 Random Search
  • 贝叶斯优化 Bayesian Optimization

Babysitting

Babysitting在学术领域也被称为Grad Student DescentGrad Student Descent。这种方法是100%手动,是研究人员,学生和业余爱好者最广泛采用的方法。

端到端的工作流程非常简单:学生设计了一个新的实验,她通过学习过程的所有步骤(从数据收集到特征图可视化),然后她将按顺序迭代超参数直到她运行时间结束(通常是由于截止日期)。

如果您已经注册了deeplearning.ai课程,那么您就熟悉这种方法 - 这是由Andrew Ng教授描述的Panda工作流程【1】。

这种方法非常有教育意义,但它不能在团队或公司内部扩展,因为数据科学家的时间非常宝贵。

因此,我们的问题是:

「有不那么费时的更好的方法吗

当然!我们可以通过定义超参数搜索的自动策略来优化您的时间!

网格搜索

网格搜索 ——简单地尝试各种可能的配置的幼稚的做法。它的工作流程如下:

  • n维上定义网格,其中每个都为超参数映射。例如n =(learning_rate,dropout_rate,batch_size)
  • 对于每个维度,定义可能值的范围:例如batch_size = [4,8,16,32,64,128,256]
  • 搜索所有可能的配置并等待结果建立最佳配置:例如C1 =(0.1,0.3,4) - > acc = 92%,C2 =(0.1,0.35,4) - > acc = 92.3%,等等...

下图显示了Dropout和学习速率在两个维度上的简单网格搜索。

这种策略的并行很尴尬,因为它没有考虑计算历史。但它的意思是,你的可用计算资源??越多,那么你可以在同一时间尝试越多的猜测!

这种方法的真正痛点被称为维度的诅咒。这意味著我们添加的维度越多,搜索在时间复杂度(通常是指数级别的)的爆炸越多,最终使这个策略变得不可行!

当尺寸小于或等于4时,通常使用这种方法。但是,实际上,即使它保证在最后找到最佳配置,它仍然不是优选的。相反,最好使用随机搜索 - 我们将在下面讨论

使用FloyHub进行网格搜索!

可在FloydHub上打开工作区【2】。您可以使用工作区在完全配置的云计算机上运行以下代码(使用Scikit-learn和Keras进行网格搜索)。

# Load the dataset
x, y = load_dataset()

# Create model for KerasClassifier
def create_model(hparams1=dvalue,
hparams2=dvalue,
...
hparamsn=dvalue):
# Model definition
...

model = KerasClassifier(build_fn=create_model)

# Define the range
hparams1 = [2, 4, ...]
hparams2 = [elu, relu, ...]
...
hparamsn = [1, 2, 3, 4, ...]

# Prepare the Grid
param_grid = dict(hparams1=hparams1,
hparams2=hparams2,
...
hparamsn=hparamsn)

# GridSearch in action
grid = GridSearchCV(estimator=model,
param_grid=param_grid,
n_jobs=,
cv=,
verbose=)
grid_result = grid.fit(x, y)

# Show the results
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
means = grid_result.cv_results_[mean_test_score]
stds = grid_result.cv_results_[std_test_score]
params = grid_result.cv_results_[params]
for mean, stdev, param in zip(means, stds, params):
print("%f (%f) with: %r" % (mean, stdev, param))

随机搜索

几年前,Bergstra和Bengio发表了一篇惊人的论文【3】,他们证明了网格搜索的低效率。网格搜索和随机搜索之间唯一真正的区别在于策略周期的第1步 - 随机搜索从配置空间中随机选取点。让我们使用下面的图片(在论文中提供)来显示研究人员报告的声明。

网格搜索VS随机搜索

图像中,通过在两个超参数空间上搜索最佳配置来比较两种方法。它还假设一个参数比另一个参数更重要。这是一个安全的假设,因为开头提到的深度学习模型确实充满了超参数,并且通常研究人员/科学家/学生知道哪些对训练影响最大。

在网格搜索中,很容易注意到,即使我们已经训练了9个模型,我们每个变数只使用了3个值!然而,使用随机搜索,我们不太可能多次选择相同的变数。最后,通过第二种方法,我们将使用9个不同的值为每个变数训练9个模型。

从图像中每个布局顶部的空间探索可以看出,我们使用随机搜索更广泛地探索了超参数空间(特别是对于更重要的变数)。这将有助于我们在更少的迭代中找到最佳配置。

总结:如果搜索空间包含3到4个以上的维度,请不要使用网格搜索。相反,使用随机搜索,它为每个搜索任务提供了非常好的基线。

使用FloydHub进行随机搜索!

在这里(floydhub.com/run?)可在FloydHub上打开工作区。您可以使用工作区在配置完整的云计算机上运行以下代码(使用Scikit-learn和Keras进行随机搜索。)。

# Load the dataset
X, Y = load_dataset()

# Create model for KerasClassifier
def create_model(hparams1=dvalue,
hparams2=dvalue,
...
hparamsn=dvalue):
# Model definition
...

model = KerasClassifier(build_fn=create_model)

# Specify parameters and distributions to sample from
hparams1 = randint(1, 100)
hparams2 = [elu, relu, ...]
...
hparamsn = uniform(0, 1)

# Prepare the Dict for the Search
param_dist = dict(hparams1=hparams1,
hparams2=hparams2,
...
hparamsn=hparamsn)

# Search in action!
n_iter_search = 16 # Number of parameter settings that are sampled.
random_search = RandomizedSearchCV(estimator=model,
param_distributions=param_dist,
n_iter=n_iter_search,
n_jobs=,
cv=,
verbose=)
random_search.fit(X, Y)

# Show the results
print("Best: %f using %s" % (random_search.best_score_, random_search.best_params_))
means = random_search.cv_results_[mean_test_score]
stds = random_search.cv_results_[std_test_score]
params = random_search.cv_results_[params]
for mean, stdev, param in zip(means, stds, params):
print("%f (%f) with: %r" % (mean, stdev, param))

退后一步,前进两步

另外,当您需要为每个维度设置空间时,为每个变数使用正确的比例非常重要。

例如,通常使用批量大小的值作为2的幂,并在对数标度中对学习率进行采样。

从上面的一个布局开始进行一定数量的迭代也是很常见的,然后通过在每个变数范围内更密集地采样来放大到有希望的子空间,甚至用相同或不同的搜索策略开始新的搜索。

还有一个问题:独立猜测!

不幸的是,网格和随机搜索都有共同的缺点:

「每一个新猜测都独立于之前的运行!」

这听起来有些奇怪和令人惊讶,但是,尽管需要大量的时间,但babysitting是科学家通过将过去的经验作??为参考来改善下一次运行来有效推动搜索和实验的能力。等一下,听起来很熟悉......如果我们尝试将超参数搜索建模为机器学习任务如何?!这就是贝叶斯优化所做的。

贝叶斯优化

此搜索策略构建了一个代理模型,该模型试图从超参数配置中预测我们关注的指标。在每次新的迭代中,代理将对哪些新的猜测可以带来改进越来越自信。就像其他搜索策略一样,它共享相同的终止条件。

高斯过程在起作用

我们可以将高斯过程定义为代理,它将学习从超参数配置到感兴趣度量的映射。它不仅会将预测产生为一个值,而且还会给我们提供不确定性的范围(均值和方差)。让我们深入研究这个教程的示例。

在上图中,我们遵循单个变数(在水平轴上)的高斯过程优化的第一步。它可以代表学习率或丢弃率等超参数。

在垂直轴上,我们把感兴趣的度量作为单个超参数的函数进行绘制。由于我们正在寻找尽可能低的值,我们可以将其视为损失函数。

黑点代表到目前为止训练的模型。红线是实际值,换句话说,就是我们正在努力学习的函数。黑线表示我们对实际函数的实际假设的平均值,灰色区域表示空间中的相关不确定性或方差。

我们可以注意到,不确定性在点周围减少,因为我们对这些点的结果非常有信心(因为我们已经在这里训练了模型)。那么,在我们拥有较少信息的区域,不确定性会增加。

现在我们已经定义了起点,我们已经准备好选择下一个有希望的变数来训练一个模型。为此,我们需要定义一个采集函数,它将告诉我们在哪里采样下一个配置。

在此示例中,我们使用预期改进(Expected Improvement):如果我们将使用来自不确定区域的建议配置,则函数旨在找到最低可能值。上面的预期改进图表中的蓝点显示了为下一次训练选择的点。

我们训练的模型越多,代理对下一个有希望的样本点的信心就越大。这是8个训练模型后的图表:

高斯过程属于称为基于顺序模型的优化(SMBO)的演算法类。正如我们刚刚看到的,这些演算法为开始搜索最佳超参数配置提供了非常好的基线。但是,就像每个工具一样,它们也有它们的缺点:

  • 根据定义,该过程是顺序的
  • 它只能处理数字参数
  • 如果训练表现不佳,它不提供任何停止训练的机制

请注意,我们只是简单地谈到了这个有趣的话题,如果您对更详细的阅读以及如何扩展SMBO感兴趣,那么请看一下这篇论文。

使用呢FloydHub进行贝叶斯优化!

单击这里(floydhub.com/run?)可在FloydHub上打开工作区。您可以使用工作区在完整配置的云计算机上运行以下代码(使用Hyperas进行贝叶斯优化(SMBO-TPE))。

def data():
"""
Data providing function:
This function is separated from model() so that hyperopt
wont reload data for each evaluation run.
"""
# Load / Cleaning / Preprocessing
...
return x_train, y_train, x_test, y_test

def model(x_train, y_train, x_test, y_test):
"""
Model providing function:
Create Keras model with double curly brackets dropped-in as needed.
Return value has to be a valid python dictionary with two customary keys:
- loss: Specify a numeric evaluation metric to be minimized
- status: Just use STATUS_OK and see hyperopt documentation if not feasible
The last one is optional, though recommended, namely:
- model: specify the model just created so that we can later use it again.
"""
# Model definition / hyperparameters space definition / fit / eval
return {loss: <metrics_to_minimize>, status: STATUS_OK, model: model}

# SMBO - TPE in action
best_run, best_model = optim.minimize(model=model,
data=data,
algo=tpe.suggest,
max_evals=,
trials=Trials())

# Show the results
x_train, y_train, x_test, y_test = data()
print("Evalutation of best performing model:")
print(best_model.evaluate(x_test, y_test))
print("Best performing model chosen hyper-parameters:")
print(best_run)

搜索策略比较

现在总结一下我们到目前为止所涵盖的内容,以了解每个提案的优缺点。

贝叶斯SMBO可能是最佳候选者,只要资源不是您或您的团队的约束,但您还应考虑使用随机搜索建立基线。

另一方面,如果你还在学习或处于开发的阶段,那么Babysitting- 即使在空间探索方面不切实际 - 也是要走的路。

就像我在SMBO部分提到的那样,如果训练表现不佳甚至更差,这些策略都没有提供保存资源的机制 - 我们必须等到计算结束。

因此,我们得出了最后一个问题:

「我们可以优化训练时间吗?」

让我们来看看。

Early Stopping

Early Stopping不仅是一种著名的正规化技术,而且它还提供了一种很好的机制,可以在训练不正确的时候防止资源浪费。这是最常采用的停止标准图:

前三个标准是不言自明的,所以让我们把注意力集中在最后一个标准上。根据研究实验室内的实验类别来限制训练时间是很常见的。此政策充当实验的渠道,并优化团队内部的资源。通过这种方式,我们将能够将更多资源分配给最有希望的实验。

floyd-cli提供了一个标志来达到这个目的:FloydHub的用户都在使用它大量规范他们的实验。

这些标准可以在照看学习过程时手动应用,或者您可以通过最常见框架中提供的钩子/回调在实验中集成这些规则来做得更好:

  • Keras提供了极强的EarlyStopping功能,是一套超级有用的回调。由于Keras最近已集成在Tensorflow中,您将能够在tensorflow代码中使用回调。
  • Tensorflow提供了训练钩子,这些可能不像Keras回调(或tf.keras API)那样直观,但它们可以让您更好地控制执行状态。
  • 目前,Pytorch尚未提供钩子或回调组件,但您可以查看TorchSample的repo和论坛。我不知道Pytorch 1.0的功能列表(团队可能会在PyTorch开发者大会上发布一些内容),但可能是这个功能将随新版本一起提供。
  • fast.ai库提供回调,即使它不提供任何形式的的文档,你可以查看教程(在这里)。或者他们有一个很棒的社区。
  • Ignite(Pytorch的高级库)提供类似于keras的回调。该库实际上正在积极开发中,但它确实看起来是一个非常有趣的选择。

这不是结束。

机器学习的子领域称为「AutoML」(自动机器学习),其目的是自动化模型选择,特征提取和/或超参数优化的方法。

这个工具是最后一个问题的答案(我保证!):

「我们可以了解整个过程吗?」

您可以将AutoML视为机器学习任务,它正在用机器学习的演算法解决另一个机器学习任务,类似于我们对Baeysian Optimiziation所做的工作。从本质上讲,这是元机器学习(Meta-Machine Learning)。

研究:AutoML和PBT

您很可能听说过Google的AutoML,这是他们对神经网路搜索的新品牌。在本文开头,我们决定将模型设计组件合并到超参数变数中。那么,Neural Architecture Search(网路架构搜索)是AutoML的子领域,旨在为给定任务找到最佳模型。关于这一主题的全面讨论需要一系列文章。幸运的是,来自fast.ai的Rachel Thomas博士做了一项了不起的工作,这里是链接。

我想与您分享来自DeepMind的另一项有趣的研究工作,他们使用Evolution Strategy(进化论)演算法的变体来执行称为基于种群的训练的超参数搜索(PTB也是DeepMind的另一项令人惊叹的研究的基础)。引用DeepMind:

PBT - 就像随机搜索 - 通过与随机超参数并行训练许多神经网路开始。但是,它不是独立地进行网路训练,而是使用来自其他种群的信息来细化超参数,并将计算资源引导到具有希望的模型。这得益于遗传演算法,其中每个种群(称为工人)可以利用其余种群的信息。例如,工作人员可以从性能更好的工作人员复制模型参数。它还可以通过随机更改当前值来探索新的超参数。

在FloydHub上管理您的实验

FloydHub的最大特点之一是能够在使用不同的超参数集时比较您正在训练的不同模型。

下图显示了FloydHub项目中的作业列表。您可以看到此用户正在使用作业的message栏位(例如floyd run --message "SGD, lr=1e-3, l1_drop=0.3" ... )来突出显示在每个作业中使用的超参数。

此外,您还可以查看每项工作的训练指标。这些提供了快速浏览,帮助您了解哪些工作表现最佳,以及使用的机器类型和总训练时间。

FloydHub dashboard为您提供了一种简单的方法来比较您在超参数搜索中所做的所有训练 - 并且实时更新。

我们的建议是为您必须解决的每个任务/问题创建一个不同的FloydHub项目。通过这种方式,您可以更轻松地组织工作并与团队协作。

训练指标

如上所述,您可以轻松地在FloydHub上发布您的训练指标。当您在FloydHub dashboard上查看作业时,您将找到您定义的每个指标的实时图表。

此功能无意替代Tensorboard(我们也提供此功能),而是旨在突出显示您已选择的超参数配置的训练行为。

例如,如果您正在监督训练过程,那么训练指标肯定会帮助您确定和应用停止标准。

FloydHub HyperSearch(即将推出!)

FloydHub目前正计划发布一些floyd-cli命令行工具的示例,工具封装这篇文章中提议的策略,以便在FloydHub上有效地运行超参数搜索。所以,请继续关注!

参考资料:

【1】coursera.org/lecture/de

【2】Workspaces on FloydHub

【3】jmlr.org/papers/volume1

本文翻译自:blog.floydhub.com/guide


推荐阅读:
相关文章