人人都能懂的机器学习——用Keras搭建人工神经网络09

微调神经网络超参数

神经网络的灵活性其实也是它的缺点:有太多的超参数需要调整。神经网络的灵活性可以让我们使用任何想象中的网络架构,但是即使一个简单的MLP,我们也要考虑层的数量,每层神经元的数量,每层使用的激活函数的类型,权重初始化逻辑等等。那么我们要怎么知道那种超参数组合最适合解决问题呢?

一个解决方式就是尝试各种超参数组合方式然后看那种组合在验证集上的表现最好(或者使用K-fold交叉验证)。为此,我们可以使用网格搜索或者随机搜索方法,探索超参数空间。我们需要将Keras模型打包成一个对象,就像一般的Scikit-Learn回归器一样。第一步我们需要创建一个函数,用于创建和编译Keras模型,然后输入一系列超参数:

def build_model(n_hidden=1, n_neurons=30, learning_rate=3e-3, input_shape=[8]):
    model = keras.models.Sequential()
    model.add(keras.layers.InputLayer(input_shape=input_shape))
    for layer in range(n_hidden):
        model.add(keras.layers.Dense(n_neurons, activation="relu"))
    model.add(keras.layers.Dense(1))
    optimizer = keras.optimizers.SGD(lr=learning_rate)
    model.compile(loss="mse", optimizer=optimizer)
    return model

这个函数创建了一个简单的单变量回归Sequential模型,并向其传递了输入形状,层数和每层的神经元数,然后用SGD优化器编译并设置了学习率。代码中向模型提供了尽可能多的超参数默认值,这通常是比较好的做法。

接下来,我们创建一个基于上面的build_model()函数的KerasRegressor:

keras_reg = keras.wrappers.scikit_learn.KerasRegressor(build_model)

KerasRegressor对象是使用build_model()构建的Keras模型的一个简单包装。因为我们在创建它时没有指定任何超参数,所以它将使用我们在build_model()中定义的默认超参数值。现在我们可以像使用常规的Scikit-Learn回归器一样使用这个对象:我们可以使用fit()方法来训练它,然后使用score()方法来评估,并使用predict()方法进行预测。具体操作如下所示:

keras_reg.fit(X_train, y_train, epochs=100,
              validation_data=(X_valid, y_valid),
              callbacks=[keras.callbacks.EarlyStopping(patience=10)])
mse_test = keras_reg.score(X_test, y_test)
y_pred = keras_reg.predict(X_new)

注意,传递给fit()方法的任何额外的参数都将传递给底层的Keras模型。另外,score()方法的结果与MSE的相反,因为Scikit-Learn的理念是计算分数,而不是损失(即得分越高越好)

当然我们的目的并不是训练和评估一个模型,而是训练成百上千的超参数组合然后看哪种超参数组合在验证集上的表现最好。那么既然有那么多超参数需要调整,选用随机搜索的方法比网格搜索更佳。让我们尝试探索一下隐藏层和神经元的数量以及学习率:

from scipy.stats import reciprocal
from sklearn.model_selection import RandomizedSearchCV
param_distribs = {
    "n_hidden": [0, 1, 2, 3],
    "n_neurons": np.arange(1, 100),
    "learning_rate": reciprocal(3e-4, 3e-2),
}
rnd_search_cv = RandomizedSearchCV(keras_reg, param_distribs, n_iter=10, cv=3)
rnd_search_cv.fit(X_train, y_train, epochs=100,
                  validation_data=(X_valid, y_valid),
                  callbacks=[keras.callbacks.EarlyStopping(patience=10)])

我们将额外的参数传递给fit()方法,并将它们传递给底层的Keras模型。注意RandomizedSearchCV使用K-fold交叉验证,因此它不使用X_valid和y_valid,这两个值只用于早停。

超参数的探索可能需要几个小时,具体取决于硬件,数据量,模型复杂度,n_itercv的值。在运行结束之后,你就会得到最佳的超参数,得分,以及训练好的Keras模型:

>>> rnd_search_cv.best_params_
{'learning_rate': 0.0033625641252688094, 'n_hidden': 2, 'n_neurons': 42}
>>> rnd_search_cv.best_score_
-0.3189529188278931
>>> model = rnd_search_cv.best_estimator_.model

现在你就可以保存这个模型,在测试集上进行评估,如果你对这个结果比较满意,那么就可以部署生产了。使用随机搜索并不难,并且对于许多简单的问题表现得很好。但当训练速度很慢的时候(比如问题很复杂,数据量又很大),这个方法只能探索很小范围的超参数空间。我们可以手动帮助这个探索过程,让它稍微有所改善:首先使用大范围的超参数空间,快速运行一次随机搜索,然后在第一次的运行结果中找出最佳的超参数值,再在这个超参数值附近更小的空间运行一次随机搜索。这种方法可以手动缩小至一组较好的超参数。但是,这个方法仍然非常花时间,而且也不是最值得花时间的地方。

非常幸运的是,现在已经有很多技术可以帮助我们更高效地探索超参数空间了。这些技术的核心思路也很简单:当一个区域的超参数空间的结果不错,那么应该对这个区域进行更多的探索。这些技术帮助我们处理了缩小搜索空间的事情,并且用更少的时间得出更好的解决方案。下面列出了一下可以用来调参的python库:

  • Hyperopt:用于优化各种复杂的搜索空间的Python库(比如学习率,离散值,隐藏层数)
  • Hyperas,kopt,Talos:为Keras模型优化超参数而开发的库(前两个是基于Hyperopt)
  • Keras Tuner:谷歌为Keras开发的很容易使用的超参数优化库,并且带有可视化和分析托管服务
  • Scikit-Optimize(skopt):是一个通用的优化库。BayesSearchCV类执行贝叶斯优化,并且其接口与GridSearchCV十分相似
  • Spearmint:一个贝叶斯优化库
  • Hyperband:基于Lisha Li等人的论文《Hyperband: A Novel Bandit-Based Approach to Hyperparameter Optimization》开发的快速超参数调优库
  • Sklearn-Deap:一个基于进化算法的超参数优化库,其接口也与GridSearchCV十分相似

另外,许多公司还提供超参数优化服务。我们在未来的文章中将讨论谷歌云AI平台的超参数调优服务。还有公司会提供超参数优化的API,比如Arimo,SifOpt和Oscar等。

超参数调优仍然是一个活跃的研究领域。进化算法最近又卷土重来了。比如,DeepMind在2017年发表了一篇优秀的论文:《Population Based Training of Neural Networks》,在论文中作者综合优化了一些模型以及它们的超参数。谷歌还使用了一种进化方法,不仅用于搜索超参数,还用于寻找解决问题的最佳神经网络体系结构。这个进化方法被称为AutoML,并已经可以在云端使用。也许这个技术会是人工构建神经网络的终结?有兴趣的朋友可以看谷歌关于这个项目的文章:

https://ai.googleblog.com/2018/03/using-evolutionary-automl-to-discover.html

实际上,进化算法已经替代无处不在的梯度下降法成功用于训练单个神经网络了。Uber就于2017年在官网上发表了一篇介绍他们深度神经进化技术的文章。

虽然我们有了这些令人兴奋的技术发展,还有各种工具和服务,但是了解每个超参数的合理范围仍然是有帮助的。这样我们就可以构建一个快速的原型并限制超参数搜索空间。

下一篇文章将讲述如何在MLP中选择隐藏层和神经元数量,以及选择其他重要超参数合适的值。

敬请期待啦!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容