深度学习超参数搜索实用指南

摘要: 在本文中,咱们将讨论为深度学习模型搜索最佳超参数集合的动机和策略,并演示如何在FloydHub上来完成任务。学习本文以后,这将会在深度学习工做中为你自动化寻找最佳配置的过程。

与机器学习模型不一样,深度学习模型里面充满了各类超参数。并且,并不是全部参数都能对模型的学习过程产生一样的贡献。考虑到这种额外的复杂性,在一个多维空间中找到合适的参数变量成为了挑战。幸运的是,咱们有不一样的策略和工具能够解决搜索问题。python

每一位研究人员都但愿在现有的资源条件下,找到最佳的模型。一般状况下,他们会在开发的最后阶段尝试一种搜索策略,这可能会有助于改进他们辛辛苦训练出来的模型。算法

此外,在半自动/全自动深度学习过程当中,超参数搜索也是的一个很是重要的阶段。网络

超参数究竟是什么?框架

让咱们从最简单的定义开始,超参数是在构建机器/深度学习模型时能够转动的旋钮。或者这样解释,超参数是开始训练以前,用预先肯定的值来手动设置的全部训练变量。dom

咱们应该都会承认Learning Rate和Dropout Rate是超参数。可是模型设计的变量呢?这些变量包括嵌入值、网络层数、激活函数等等,咱们应该把这些变量视为超参数吗?curl

clipboard.png
模型设计变量+超参数→模型参数机器学习

那么,从训练过程当中得到的参数,以及从数据中得到的变量应该如何考虑呢?这被称为模型参数,咱们将把它们排除在超参数集以外。函数

请看下图,举例说明在深度学习模型中变量的分类。工具

clipboard.png
变量分类实例布局

下一个问题: 搜索代价巨大

寻找超参数的最佳配置,面临的挑战是寻找超参数是一个消耗巨大的工做。

clipboard.png
超参数搜索周期

咱们从配置的猜想开始,须要等到一个完整的训练结束,来得到对相关指标的实际评估,以后是跟踪搜索过程的进度,最后根据搜索策略,选择新的猜想。

策略讨论

咱们有四种主要的策略用于寻找最佳配置。

  • 试错法(Babysitting)
  • 网格搜索(Grid Search)
  • 随机搜索(Random Search)
  • 贝叶斯优化(Bayesian Optimization)

Babysitting

在研究领域,Babysitting也被称为“试错法”。100%手工操做,被你们普遍采用。

流程很是简单:好比学生设计了一个实验后,遵循学习过程的全部步骤(从数据收集到特征图映射的可视化),而后在超参数上依次迭代直到时间终止。

clipboard.png

若是你学习过deeplearning.ai的课程,那么你确定对吴恩达教授的熊猫工做流程很熟悉。

这种方法很是有教育意义。可是,在一个团队或者一个公司里,这种方法并不适用,由于数据科学家的时间是很是宝贵的。

这就给咱们提出了一个问题:“有没有更好的方法来利用咱们的时间?”

固然有,咱们能够经过定义超参数搜索的自动策略来优化时间!

网格搜索

网格搜索,是一种简单尝试全部可能配置的方法。

它的工做流程是这样的:

  • 定义一个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 Rate和Learning Rate。

clipboard.png
并行执行两个变量的网格搜索

这种策略没有考虑到计算背景,但这意味着可用的计算资源越多,那么同时能够尝试的猜想就会越多。它的痛点被称为维度灾难,意思是咱们增长的维度越多,搜索就会变得越困难,最终致使策略失败。

当维度小于或等于4时,经常使用这种方法。可是在实践中,即便保证最后找到最佳配置,它仍然不可取,而是应该使用随机搜索。

你可使用FloydHub的Workspace在配置完整的云主机上运行下面的代码(使用Scikit-learn和Keras进行网格搜索):

# Load the dataset
x, y = load_dataset()
# Create model for KerasClassifier
defcreate_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发表了一篇论文,论证了网格搜索的效率低下。

网格搜索和随机搜索之间惟一的区别在于策略周期的第一步:随机搜索在配置空间上随机选择点。

请看下图:

clipboard.png
网格搜索vs随机搜索

经过在两个超参数空间上搜索最佳配置来对比这两种方法,并假定一个参数比另外一个参数更重要。深度学习模型,如前面所说,实际上包含许多超参数,一般研究者知道哪些对训练影响最大。

在网格搜索中,即便咱们已经训练了9个模型,但给每一个变量只使用了3个值,然而,在随机搜索中,屡次选择相同变量的可能性微乎其微。若是用第二种方法,那么就会给每一个变量使用9个不一样的值来训练9个模型。

上图中,从每一个布局顶部的空间搜索能够看出,使用随机搜索更普遍地研究了超参数空间,这将帮助咱们在较少的迭代中找到最佳配置。

总之,若是搜索空间包含3到4个维度,则不要使用网格搜索。相反,使用随机搜索,则会为每一个搜索任务提供了一个很是好的基线。

clipboard.png
网格搜索与随机搜索的利弊

你可使FloydHub的Workspace在配置完整的云主机上运行下面的代码:

# Load the dataset X, Y = load_dataset() # Create model for KerasClassifier defcreate_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))

另外,当你为每一个维度设置空间时,为每一个变量设定正确的尺度是很是重要的。

clipboard.png

批量大小和Learning Rate的通用比例空间

例如,使用批量大小的值做为2的幂指数,而且在日志中对Learning Rate进行抽样是很常见的。

clipboard.png

放大

另外一个很常见的作法是,在必定次数的迭代中,从上面的一个布局开始,而后经过在每一个变量范围内进行更密集的采样,甚至使用相同或不一样的搜索策略开始新的搜索,从而放大到一个子空间。

还有一个问题:独立猜想。

不幸的是,网格搜索和随机搜索有一个共同的缺点:“每一个新的猜想都独立于以前的运行!”

相比之下,Babysitting的优点就显现出来了。Babysitting之因此有效,是由于研究者有能力利用过去的猜想,将其做为改进下一步工做的资源,来有效地推进搜索和实验。

贝叶斯优化

贝叶斯策略创建了一个代理模型,试图从超参数配置中预测咱们所关注的度量指标。在每一次的迭代中,咱们对代理会变得愈来愈有信心,新的猜想会带来新的改进,就像其它搜索策略同样,它也会等到耗尽资源的时候终止。

clipboard.png
贝叶斯优化工做流程

高斯过程

咱们能够将高斯过程定义为学习从超参数配置到度量映射的替代过程。它不只产生一个预测值,并且还会给咱们一个不肯定性的范围。

clipboard.png
2个点的高斯过程

在上图中,咱们在单个变量上(在横轴上)遵循高斯过程优化的第一步,在这个例子中,能够表明Learning Rate或Dropout Rate。在纵轴上,咱们将某个度量指标绘制成单个超参数的函数。因为咱们正在寻找尽量低的值,因此能够把它看做是损失函数。

图中黑线表明了训练出来的模型,红线是真实值,也就是咱们正在试图学习的函数。黑线表明咱们对真实值函数假设的平均值,而灰色区域代表空间中相关的不肯定性或方差。正如咱们看到的,点周围的不肯定性减小了,由于咱们对这些点周围的结果很是有信心,由于咱们已经在这里训练了模型。而在信息较少的区域,不肯定性会增长。

如今已经定义了起点,咱们准备好选择下一个变量来训练模型。为此,须要定义一个采集函数,它会告诉咱们在哪里采样下一个配置。

在这个例子中,若是咱们使用不肯定性区域中的配置,则函数将寻找尽量低的值。上图中的蓝点显示了下一次训练所选择的点。

clipboard.png
3个点的高斯过程

咱们训练的模型越多,代理对下一个采样的点就越有信心。下图是8次训练后的模型:

clipboard.png
8个点的高斯过程

高斯过程属于一类称为基于序列模型的优化(SMBO)的算法。正如刚刚看到的,这些算法为搜索最佳超参数配置提供了很是好的基准。可是,就像每种工具同样,它们都有缺点:

  • 按照定义,这个过程是按部就班的;
  • 它只能处理数字参数;
  • 若是训练表现不佳,它不提供任何机制来中止训练;

你可使用FloydHub的Workspace在配置完整的云主机上运行下面的代码:

def data():
    """
    Data providing function:
    This function is separated from model() so that hyperopt
won't reload data for each evaluation run.
    """
    # Load / Cleaning / Preprocessing
    ...
returnx_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)

下图总结了咱们所涉及的内容,了解每一个策略的优缺点:

clipboard.png

总结

只要资源没有限制,贝叶斯SMBO多是最好的选择,但还应该考虑创建一个随机搜索的基准。

若是你还处于学习或者初级阶段,那么选择Babysitting。即便从空间搜索的角度来看不切实际,也是一种可行的方法。

若是训练表现不佳,这些策略都不会提供节省资源的机制,只能等到计算结束。

早停的力量

clipboard.png

“早停”不只是一种规则化技术,并且在训练方向不正确时,它会提供防止资源浪费的机制。

下图是最经常使用的中止标准:

clipboard.png

中止标准

前三个标准不用多说,因此你们集中看最后一个标准。

一般状况下,根据实验类别来限定训练时长,这能够对团队内部的资源进行优化。经过这种方式,咱们可以分配更多的资源给最有但愿的实验。

这些标准能够在Babysitting过程当中手动应用,或者经过在最多见框架中提供的钩子/回调组件将这些规则集成到实验中:

  • Keras提供了一个很好的“早停”功能,甚至更好的回调组件。因为Keras最近被集成在Tensorflow中,你能在Tensorflow代码中使用回调组件;
  • Tensorflow提供了训练钩子,可能不像Keras回调(或tf.keras API)那么直观,可是它们提供了对执行状态的更多控制;
  • 目前,Pytorch尚未提供回调组件,可是这个功能可能会随着新版本一块儿发布;
  • fast.ai库也提供了回调功能,不过目前还没提供任何类型的文档;
  • Ignite(Pytorch的高级库)提供相似于keras的回调,虽然还在开发阶段;

在FloydHub上管理实验

FloydHub的最大特性之一是,当使用不一样的超参数集时可以比较正在训练的模型。

下图显示了FloydHub项目中的任务列表。能够看到,该用户正在使用任务消息,突出显示在这些任务中使用的超参数。

另外,还能够看到每一个任务的训练度量指标,并提供了一个快速浏览,以帮助你了解哪些任务表现的最好,以及使用的机器类型和总的训练时间。

clipboard.png

FloydHub的dashboard为你提供了一种简便的方式来比较在超参数搜索中的训练任务,并且是实时更新的。咱们的建议是为每个任务建立一个不一样的FloydHub项目,这样,你就能够更容易地组织工做和团队合做。

训练度量指标

如上所述,你能够轻松地在FloydHub上发布与工做相关的训练度量指标。当你在FloydHub的dashboard上查看任务时,能够很容易地为每一个指标找到相应的实时图表。这个特性并非要取代Tensorboard,而是由所选择的超参数配置来突出训练的状态。

例如,若是你正在Babysitting训练的过程当中,那么训练度量指标确定会帮你肯定和应用中止标准。

clipboard.png
训练度量指标

本文做者:【方向】

阅读原文

本文为云栖社区原创内容,未经容许不得转载。

相关文章
相关标签/搜索