TowardsDataScience 博客中文翻译 2020(五百一十七)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

基于混合规则的机器学习

原文:https://towardsdatascience.com/hybrid-rule-based-machine-learning-b15abc7d7bbe?source=collection_archive---------52-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由 You X Ventures 在 Unsplash 上提供

混合基于规则的机器学习和 scikit-learn

卢卡斯·哈斯 — 10 分钟读完

TL;scikit-learn 博士不允许您将硬编码的规则添加到您的机器学习模型中,但对于许多用例来说,您应该这样做!本文探讨了如何利用领域知识和面向对象编程(OOP)在 scikit-learn 之上构建基于混合规则的机器学习模型。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片来自 Pexels 的 fauxels

揭开魔法:解读机器学习黑盒模型

Fabricio Pretto — 15 分钟读取

在使用黑盒模型时,预测能力和可解释性之间的权衡是一个常见的问题,尤其是在必须向非技术受众解释结果的业务环境中。可解释性对于质疑、理解和信任人工智能和人工智能系统至关重要。它还为数据科学家和工程师提供了更好的方法来调试模型,并确保它们按预期工作。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Kyle Glenn 在 Unsplash 上拍摄

生产中的深度强化学习第 2 部分:个性化用户通知

迈赫迪·本·阿耶德帕特里克·哈琳娜

在这篇文章中,我们将讨论如何使用 RL 来个性化通知,并提高 Words with Friends Instant 的点击率。它作为一个例子来说明构建 RL 应用程序需要什么,以及为什么 RL 如此强大。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来自 NeONBRAND 的 Unsplash

理解转置卷积

宽尾 — 11 分钟读完

生成对抗网络(GAN)是用于新数据生成的最先进的人工神经网络之一。它广泛应用于照片生成、照片编辑、人脸老化等领域。GAN 的核心是发生器和鉴别器。

基于混合规则的机器学习与 scikit-learn

原文:https://towardsdatascience.com/hybrid-rule-based-machine-learning-with-scikit-learn-9cb9841bebf2?source=collection_archive---------9-----------------------

使用领域知识,通过硬编码的规则来扩充您的 scikit-learn 模型

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由 You X VenturesUnsplash

TL;DRscikit-learn不允许你将硬编码的规则添加到你的机器学习模型中,但是对于很多用例来说,你应该!本文探讨了如何利用领域知识和面向对象编程(OOP)在 scikit-learn 之上构建基于混合规则的机器学习模型。

介绍

有监督的机器学习模型非常适合在不确定的情况下进行预测;他们从过去的数据中提取模式,并将其准确地推断到未来。机器学习已经推动了一些领域的发展,在这些领域中,确定最可能的结果(无论是类还是特定值)一直具有挑战性,容易出错,或者在规模上过于耗时或昂贵。

然而,在许多领域中,所有可能的结果都不是模糊的,而是根据定义确定的。您可能会遇到嵌入在特定于业务的流程或法规中的规则。在这样的环境中,让 ML 模型使用隐式学习来渐进地猜测预先制定的规则似乎是低效的。相反,我们希望模型关注所有不存在预定义规则的情况。

在本文中,您将了解到将预定义的领域规则合并到机器学习模型中有许多好处。为了获得更多的实际操作,我们将为 scikit-learn 估算器构建一个简单的包装器类,它考虑了显式规则,并让模型来解决困难的情况。

如果您不能等待,请跳到 Python 中的完整文档实现。

领域知识的重要性

任何好的机器学习项目都是从领域知识的聚合开始的——收集关于业务问题的相关信息和专业知识的过程。通常,我们与行业从业者交谈,在线研究,并进行数据探索,以揭示有助于机器学习模型构建的特定趋势、模式或提示。

领域知识非常有用,原因有很多:它帮助我们平衡涉众的需求,理解我们的目标受众,但最重要的是,它给了我们关于特性工程的重要线索。虽然在试图识别照片中的猫时,这些线索是不言自明的,但在许多行业领域,如法律、保险或医疗诊断,特征工程远非直观。

为了说明这一点,假设您的目标是为一家电信公司建立一个 ML 模型来预测客户流失(计划取消率)。在设计和迭代可能的功能之前,收集该领域专家关于影响流失因素的意见当然会有所帮助——保留部门是一个合理的起点。保留部门甚至可以用数据来支持他们的观点,使用客户调查来揭示具体的痛点。在任何情况下,数据和行业从业者都可以为您指出正确的方向,节省时间,并可能揭示以前未考虑的数据源和功能组合。

如何从领域知识中获取规则

在许多工业领域中,您可以从已经存在的过程中推导出简单的确定性规则。例如,在特定的法律诉讼中,名誉损害索赔可能永远不会被批准,因为法律只是这样规定。同样,保险公司可能不会支付低于 1,000 美元的损失索赔,因为根据与被保险人的合同,他们没有责任这样做。如果我们想预测诉讼结果或保险损失,这种简单的规则可以直接构建到机器学习模型中,以提高性能。

由于机器学习在解决模糊和具有挑战性的情况方面非常出色,因此只有在确定性规则适用于每种情况并且不太多也不太复杂的情况下,将确定性规则纳入模型才有意义。然而,还存在其他用例,所以我整理了一个完整的列表,列出了您何时可能想要考虑部署混合的、基于规则的模型:

  • 预测过程的确定性规则已经存在 如前所述,根据您试图预测的内容,评估过程的确定性规则可能已经存在。如果规则很简单,适用于所有情况,并且总体上没有太多规则,将它硬编码到机器学习模型中可以保证你已经可以非常准确地预测一部分情况。
  • 缺少特定类型预测案例的数据 在某些类型预测案例的数据稀疏的情况下,您的模型可能很难开发出正确的隐式规则来正确分类或估计数据点。如果模型不能仅从其他特征准确推断目标变量,通常会出现这种情况。在上面的法律示例中,可能有不常见的索赔类别,如费用报销,对于这些类别,只存在少数数据点。由于索赔类别对于确定诉讼结果至关重要,因此在没有进一步了解报销索赔的情况下,该模型不可能正确预测诉讼结果。在这种情况下,通过简单地预测该类别所有实例的平均目标变量,例如所有费用报销的平均成功率,可以提高性能。
  • 高特征基数
    高特征基数(一个特征可能值的数量)是几乎所有机器学习模型的问题。特别是对于需要编码的分类数据,大量的唯一可能值会影响模型性能。因此,如果存在适当的经验法则或统计参数,逼近目标变量可能会产生有吸引力的折衷,因为它会使剩余数据具有较低的基数以帮助模型训练。
  • 积极对抗数据中的偏差 机器学习预测天生就有偏差,因为我们的训练数据中反映了真实世界的模式。在某些情况下,我们可以通过自己处理问题和硬编码覆盖模型行为的规则来防止有偏见的预测。

如何将确定性规则硬编码为逻辑公式

如前所述,机器学习模型隐式地学习规则。这种学习的集大成者是基于决策树的算法,如 scikit-learn决策树分类器GradientBoostingRegressor,后者是决策树的集合

基于决策树的算法试图通过学习从提供的数据推断出的决策规则来预测目标变量。决策规则本身非常简单;它们是只使用基本逻辑操作符=、、≤、≥对数据进行的一系列分割。然而,所有的分割只是近似任何明确的规则,因此可能不准确。

我们可以使用相同的方法来构建简单的确定性规则作为逻辑公式,这样我们就可以将其翻译成代码。例如,让我们再次假设我们想要设计一个预测模型来估计一家保险公司的总损失,并且我们知道该公司拒绝小于或等于 1.000 美元的索赔。对该规则进行硬编码的一种方式是:

if claim_amount <= 1000:
   # reject claimelse:
   # use machine learning model

让我们开始编码吧

有许多方法可以将确定性规则集成到我们的机器学习管道中。作为数据预处理步骤逐步添加规则可能看起来很直观,但这不符合我们的目标。优选地,我们的目标是通过采用面向对象编程(OOP)来利用抽象的概念,以生成一个新颖的 ML 模型类。这个混合模型将包含所有确定性规则,使我们能够像其他任何机器学习模型一样训练它。

方便的是, scikit-learn 提供了一个base estimator类,我们可以继承它来自己构建 scikit-learn 模型,而不需要太多的努力。构建新估计器的优势在于,我们可以将规则直接与模型逻辑相结合,同时利用底层机器学习模型来处理规则不适用的所有数据。

让我们从构建新的混合模型类开始,并向它添加一个 init 方法。作为底层模型,我们将使用 scikit-learn 实现一个GradientBoostingClassifier我们称之为基础模型*。*

*import pandas as pd
from typing import Dict, Tuple
from sklearn.base import BaseEstimatorclass RuleAugmentedGBC(BaseEstimator):

  **def __init__(self, base_model: BaseEstimator, rules: Dict, **base_params):**

    self.rules = rules
    self.base_model = base_model
    self.base_model.set_params(**base_params)*

我们创建了继承自 BaseEstimatorRuleAugmentedGBC 类。我们的类还没有完成,仍然缺少一些基本的方法,但是从技术上来说,它现在是一个 scikit-learn 估计器。 init 方法利用一个 base_model 和一个规则字典初始化我们的估计器。我们可以在 init 方法中设置额外的参数,然后直接传递给底层的 base_model 。在我们的例子中,我们将使用一个GradientBoostingClassifier作为 base_model

规则的通用格式

在本文的实现中,我们将以以下格式为模型提供规则:

*{"House Price": [
    ("<", 1000.0, 0.0),
    (">=", 500000.0, 1.0)
],
 "...": [
    ...
    ...
]}*

如上所示,我们将规则格式化为一个 Python 字典。字典键代表我们想要应用规则的特性列名。字典的值是元组列表,每个元组代表一个唯一的规则。元组的第一个元素是规则的逻辑操作符,第二个是拆分标准,最后一个对象是模型在规则适用时应该返回的值。

例如,上面示例中的第一条规则表明,如果房价特征列中的任何值小于 1000.0,模型应该返回值 0.0。

该拟合方法

我们继续编写一个 fit 方法(在我们的 RuleAugmentedGBC 类中),以允许我们的模型对数据进行训练。这里需要注意的是,我们希望尽可能使用确定性规则,并且只在不受规则影响的数据上训练 base_model 。我们将通过制定一个名为 _get_base_model_data 的私有助手方法来分解这个步骤,以过滤出训练我们的 base_model 所必需的数据。

***def fit(self, X: pd.DataFrame, y: pd.Series, **kwargs):** train_x, train_y = self._get_base_model_data(X, y)
  self.base_model.fit(train_x, train_y, **kwargs)*

fit 方法非常简单:它首先应用要编码的 _get_base_model_data 方法来提取我们底层 base_model 的训练特征和标签,然后将模型拟合到数据。与之前类似,我们可以设置附加参数,随后将这些参数传递给 base_model 的 fit 方法。现在让我们实现 _get_base_model_data 方法:

***def _get_base_model_data(self, X: pd.DataFrame, y: pd.Series) -> Tuple[pd.DataFrame, pd.Series]:** train_x = X

  for category, rules in self.rules.items(): if category not in train_x.columns.values: continue
    for rule in rules: if rule[0] == "=":
        train_x = train_x.loc[train_x[category] != rule[1]] elif rule[0] == "<":
        train_x = train_x.loc[train_x[category] >= rule[1]] elif rule[0] == ">":
        train_x = train_x.loc[train_x[category] <= rule[1]] elif rule[0] == "<=":
        train_x = train_x.loc[train_x[category] > rule[1]] elif rule[0] == ">=":
        train_x = train_x.loc[train_x[category] < rule[1]] else:
        print("Invalid rule detected: {}".format(rule)) indices = train_x.index.values
  train_y = y.iloc[indices]
  train_x = train_x.reset_index(drop=True)
  train_y = train_y.reset_index(drop=True) return train_x, train_y*

我们的私有 _get_base_model_data 方法遍历规则字典键,最后遍历每个唯一的规则。在每个规则中,根据逻辑操作符,它缩小了 train_x pandas 数据帧的范围,只包括不受规则影响的数据点。一旦我们应用了所有规则,我们通过索引匹配相应的标签,并返回 base_model 的剩余数据。

该预测方法

**预测方法的工作方式类似于拟合方法。只要有可能,就应该适用规则;如果没有适用的规则,基本模型应该产生一个预测。

***def predict(self, X: pd.DataFrame) -> np.array:**

  p_X = X.copy()
  p_X['prediction'] = np.nan for category, rules in self.rules.items(): if category not in p_X.columns.values: continue
    for rule in rules: if rule[0] == "=":
        p_X.loc[p_X[category] == rule[1], 'prediction'] = rule[2] elif rule[0] == "<":
        p_X.loc[p_X[category] < rule[1], 'prediction'] = rule[2] elif rule[0] == ">":
        p_X.loc[p_X[category] > rule[1], 'prediction'] = rule[2] elif rule[0] == "<=":
        p_X.loc[p_X[category] <= rule[1], 'prediction'] = rule[2] elif rule[0] == ">=":
        p_X.loc[p_X[category] >= rule[1], 'prediction'] = rule[2] else:
        print("Invalid rule detected: {}".format(rule)) if len(p_X.loc[p_X['prediction'].isna()].index != 0): base_X = p_X.loc[p_X['prediction'].isna()].copy()
    base_X.drop('prediction', axis=1, inplace=True)
    p_X.loc[p_X['prediction'].isna(), 'prediction'] = self.base_model.predict(base_X) return p_X['prediction'].values*

predict 方法复制我们的输入 pandas 数据帧,以便不改变输入数据。然后我们添加一个预测列,在其中我们收集了所有混合模型的预测。就像在 _get_base_model_data 方法中一样,我们遍历所有规则,并在适用的情况下,在预测列中记录相应的返回值。一旦我们应用了所有的规则,我们检查是否有任何预测仍然丢失。如果是这种情况,我们返回到我们的基础模型来生成剩余的预测。

其他要求的方法

为了获得从 BaseEstimator 类继承的工作模型,我们需要实现两个更简单的方法——get _ paramsset_params 。这些允许我们设置和读取新模型的参数。由于这两种方法不是本文主题的组成部分,如果您想了解更多,请查看下面完整记录的实现。**

完整记录的实施

下面,您将找到我们在本文中构建的 scikit-learn 包装器类的完整代码,以及完整的文档。您可能会发现它对您的一个用例很有用。

基于混合规则的模型使用示例

这里有一小段代码来说明如何利用 RuleAugmentedEstimator 包装类向GradientBoostingClassifier添加规则。本例假设您已经初始化了变量规则*、 train_Xtrain_ytest_X 。请参考 一节规则的通用格式 来检查应该如何使用任何规则。*

*gbc = GradientBoostingClassifier(n_estimators=50)
**hybrid_model = RuleAugmentedEstimator(gbc, rules)****hybrid_model.fit(train_X, train_y)** predictions = **hybrid_model.predict(test_X)***

结论

恭喜你走到这一步!我希望这篇文章能够帮助您利用领域知识和面向对象编程(OOP)来构建基于混合规则的机器学习模型。正如您所看到的,抽象的概念对于直接将规则合并到 ML 模型中,同时保持您的数据管道的整洁非常有帮助。

写这篇文章有助于我深入探索这个主题及其应用。当我试图检查我的工作中的错误时,如果你发现任何错误,请让我知道。

我总是很高兴得到反馈,并对数据科学、机器学习和一般技术领域的话题讨论持开放态度。我很想收到你的来信,所以请随时通过LinkedIn与我联系。

Tableau 中的混合可视化

原文:https://towardsdatascience.com/hybrid-visualizations-in-tableau-cd031c76a107?source=collection_archive---------46-----------------------

结合可视化技术从数据中提取更深层的含义——用三个循序渐进的例子!

简短的画面概述

Tableau 对于数据科学家和数据分析师来说是一个非常强大的工具,可以让他们理解数据并产生可视化效果,简称为 “viz”

简单回顾一下——在 Tableau 中,我们使用显示为蓝色的分类数据**(维度),以及显示为绿色的可以聚合的数值数据(度量)。通过尺寸和测量的独特组合,以及“标记”卡(颜色、尺寸、标签和细节)**上的选项,我们可以生成非常健壮的图!

混合可视化

使用数据的全部意义(除了它很棒这一事实之外)是为了回答问题以得出一些结论。这些结论可以通过分析 KPI、识别趋势和提取其他有意义的见解来找到。根据这些结论,我们经常采取行动来影响未来的结果。

有时候,见解很容易从数据中提取出来。我们可以简单地用传统的方法来表示这些发现,如柱状图、线图或散点图。但其他时候,我们想要从数据中提取的见解更加细致入微,这些标准情节本身不足以有效而简洁地讲述故事。

当这种情况出现时,我会使用一种混合的可视化方式。我所说的“混合”是指两种或两种以上技术的结合,在多个层次上处理数据,所有这些都在一个层次上进行,即。

例如,我们将使用 Tableau 的**“全球超市”**数据集来处理三种不同的场景。该数据集的 Excel 文件可以在这里找到

混合 Viz 1:树形图+条形图

创建一个显示每年每季度总销售额和利润的 viz。我们希望将其分为 3 个层次:首先是地区,然后是产品类别,最后是产品子类别。

哇哦。那是一口。显然,这不能通过简单的条形图来解释。我们必须创造一个比标准更高的 viz。所以让我们一口一口地解决这个问题。

首先,让我们确定需要处理的数据类别。“品类”、“子品类”、“区域”、“下单日期”是我们的维度,而“销售额”、“利润”是我们的衡量标准。

Tableau 允许我们创建一个名为 tree-map 的 viz,这本质上是一种使用矩形显示嵌套数据的方式,其中树的每个“分支”都有一个大矩形,这个大矩形被分成更小的矩形,这些矩形就是“叶子”。在我们的例子中,我们最大的分支是“区域”,较小的分支是“类别”,我们的“叶子”是“子类别”。每个枝叶的大小是由“销量”决定的。

为了将“利润”形象化,我们可以分配一个发散的调色板来轻松识别高利润产品和低利润产品。所以,这个树形图照顾到了一切,除了时间方面。“订单日期”呢?

这就是我们混合树形图和柱状图的地方。在构建了树形图之后,如果我们将“订单日期”分配给“行”,那么 Tableau 将为数据集中的每一年创建一个树形图。每个树形图变成一个条形图,其总大小代表该特定年份所有产品类别和所有地区的总销售额。我们还可以按季度进一步细分。

现在,让我们来看看如何在 Tableau 中创建它。

第一步:

首先选择销售、利润和地区,然后使用 Tableau 右上角的“演示”工具,我们制作了一个树形图,其中每个矩形代表一个不同的地区。每个矩形的大小代表每个地区的销售额。每个矩形的颜色代表每个地区的利润。深橙色利润较低,深蓝色利润较高。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第二步:

接下来,我们将“类别”维度添加到标记卡上的“标签”中。现在,我们的树形图显示了每个地区,按产品类别细分。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第三步:

现在,我们将“子类别”维度添加到标记卡的“标签”中。结果显示每个地区的销售额,首先按产品类别细分,然后再按产品子类别细分。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第四步:

现在我们介绍时间方面。通过将“订单日期”维度拖动到 Tableau 中的“行”中,我们现在可以看到每个地区的销售额,按产品类别细分,再按产品子类别细分,并拆分为每年一个树形图。我们可以看到,每年我们的整体销售额都在增长!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们介绍时间方面。通过将“订单日期”维度拖动到 Tableau 中的“行”中,我们现在可以看到每个地区的销售额,按产品类别细分,再按产品子类别细分,并拆分为每年一个树形图。我们可以看到,每年我们的整体销售额都在增长!

第五步:

最后,我们可以扩展“订单日期”层次结构,以显示每年每个季度的树形图。我们的树形图已经变成了柱状图——最长的柱状图显示的是销售额最高的季度,最短的柱状图显示的是销售额最低的季度。使用发散调色板,利润最高的产品子类别显示为深蓝色,而利润最低的子类别显示为深橙色。似乎有一个明显的趋势,即 Q1 的销售额最低,每个季度都在增长,其中第四季度的销售额最高。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

混合 Viz 2:双轴条形图+线图

创建一个显示每年每月全球总销售额的 viz,并叠加显示每年每月的总利润。提供一年的销售和利润预测。

好吧,让我们概括一下这个任务。还是那句话,我们感兴趣的是“销量”和“利润”。但是这一次,我们没有用几个分类维度来分解它。我们不需要超精细的可视化。我们只想了解我们的全球超市销售额和利润是如何随时间变化的。

直观传达每月销售额的一种简单方法是使用条形图,x 轴表示“月/年”,y 轴表示“销售额”。但是利润呢?为了从图形上区分“利润”和“销售额”,我们可以在条形图的顶部叠加一个显示一段时间内的利润数据的线图。

除了天气预报,其他的都考虑到了。我们可以提供一年的额外棒线来预测“销售”,并提供一条额外的线来预测“利润”,置信区间为 95%。

让我们开始在 Tableau 中构建第二个混合模型。

第一步:

首先,我们为销售数据创建一个简单的条形图。我们在“行”中指定了“销售额”,在“列”中指定了“订单日期”。我们对每年每月的销售额和利润感兴趣,所以我们将“订单日期”从离散改为连续,其颜色从蓝色改为绿色。我给我们的条形图分配了深灰色,以保持 viz 中性,因为我们将在这些条形图的顶部覆盖利润数据。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第二步:

接下来,我们需要合并我们的利润数据。这将表示为销售条形图顶部的线形图。要做到这一点,我们将按 SUM 聚合的“利润”拖到“行”中,然后单击“利润”药丸上的下拉菜单,并选择“双轴”。这在 viz 的右侧创建了一个新的轴,标记为“利润”。为了使我们的“利润”比例与“销售”比例保持一致,我们右键单击新轴,并选择“同步轴”。现在,这些值在我们的 y 轴上对齐,这使得阅读更加直观。我选择了一条浅蓝色的利润线,与深灰色的销售柱状图形成对比。(注意:我们不想用绿色或红色作为盈利线,因为这些颜色与财务收益和损失相关联。)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第三步:

最后,我们建立预测。在左上角的“分析”选项卡中,我们将“预测”拖放到视图中。在顶部的功能区中,在“分析”—“预测”—“预测选项”下,我们可以定义我们希望准确预测 1 年,并使用触须显示 95%的置信区间。我们将预测的条形图和线条用不同的颜色表示,以表明这些是预测,而不是实际数据。Tableau 默认情况下会自动为您选择一个指数平滑预测模型。简而言之,“指数平滑”是指时间序列数据:数据越老,数据的权重越小,而较新的数据被认为更重要,被赋予更大的权重。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

混合 Viz 3:抖动图+盒须图

创建一个显示每份订单利润的 viz,它还显示按地区细分的每份订单的利润分布。过滤以排除异常数据(仅当每份订单的利润介于 0 美元到 1,000 美元之间时)。

现在我们只关心一个衡量标准:“利润”。我们只关心一个维度:“区域”。没什么可分解的。这里的挑战是以图形方式显示成千上万的订单,过滤数据,并用分布信息覆盖这些数据。这可以通过使用带有盒须图叠加的抖动图来实现。

抖动图随机排列 x 轴上的值,以分散数据,从而更清楚地了解分布情况。在这种情况下,这对我们特别有帮助,因为我们有数千个数据点显示每个地区每个订单的利润。

盒须图叠加为我们提供了关于每份订单利润分布的更具体的分析。它显示了数据的核心所在。“方框”显示了中间的百分之五十的值,即第一个到第三个四分位数,中间有一条线。这被称为“四分位距”或“ IQR ”。“胡须”要么延伸到最小值/最大值,要么延伸到 1.5 倍 IQR,这是确定数据中异常值的常用规则。

让我们设计这最后一个场景吧!

第一步:

首先,我们需要生成盒须图。我们选择“订单 ID”、“区域”和“利润”,并在“演示”下拉列表中选择盒须图。这显示了在每个地区下单的每个订单的数据点。在标记卡的“颜色”选项卡中,我们可以降低数据点的不透明度,以获得更好的订单密度图形感。我们可以看到我们的盒须图非常紧凑,因为我们有广泛的利润值。显然,我们订单利润值的很大一部分在一个非常窄的范围内。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第二步:

接下来,我们要过滤数据。我们被告知排除 0 到 1000 美元之间的利润数据。因此,我们将汇总的“利润”拖到过滤器卡上,并相应地调整范围。我们的盒须图会自动更新为过滤值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第三步:

为了使区域更容易相互区分,我们可以将“色调圆”调色板分配给“区域”。区域是绝对的。当我们处理类别时,我们希望为每个类别使用不同的颜色。我们不想在这里使用单一的颜色或分散的调色板。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第四步:

最后,我们可以沿着每个地区的 x 轴“抖动”我们的数据点,以图形方式查看我们每份订单的利润密度。我们可以通过右键单击“数据”选项卡,然后单击“创建计算字段”来完成此操作。我们将这个新字段命名为“Jitter”,并通过键入“INDEX()%20”来创建这个字段的计算。

这里的 INDEX()函数本质上是在每个区域内创建“抖动列”,我们的数据点被随机分配到这些区域中,以便将它们水平分布,而不是都在一行中。“%20”指定我们想要制作的抖动列的数量。最后,在将新的“Jitter”字段拖到列中后,我们单击“Jitter”字段的下拉菜单,并选择“Compute Using”—即“Order ID”。结果就是你下面看到的!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结论

我希望这篇教程能激发出更健壮、更有效的方法来可视化数据!如果有一点创造力,了解什么是可能的,并花一些时间练习和使用它,数据是一种强大的资源!本博客中的所有这些可视化内容都可以在 Tableau Public 这里 看到并与之互动。

数据很美!

超参数调谐—教程

原文:https://towardsdatascience.com/hyper-parameter-tuning-a-tutorial-70dc6c552c54?source=collection_archive---------25-----------------------

不使用代码或数学的超级参数调整方法的简单高级概述

在本教程中,我们将介绍 5 种超参数优化方法:

  1. 网格搜索
  2. 随机搜索
  3. 贝叶斯优化
  4. 连续减半
  5. 超波段

网格搜索

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从这篇遗传算法论文

网格搜索背后的思想非常直观。递增移动一个超参数,同时保持其他参数不变,并记录结果。基本上对所有你怀疑可以优化的超参数都这样做。这是一种非常昂贵和麻烦的优化和调整超参数的方法,今天被认为是进行超参数搜索的效率较低的方法之一。让我们看看如何做得更好。

随机搜索

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自的随机搜索论文

虽然你可能一开始没有想到,但随机选择所有超参数的值实际上是一种更有效的超参数调整方法。在这种情况下,我们不是保持所有超参数不变并以迭代方式调整其中一个,而是在每次试验中随机初始化所有超参数值。这更好,因为事实证明,一些超参数对优化来说比其他的更重要,如果我们不能区分重要的超参数和不重要的超参数,我们能做的下一个最好的事情是在每次试验中随机选择所有的超参数值。这将为重要的超参数提供更高的采样率,因此我们的优化将更加高效。随机搜索与网格搜索的优势在这篇文章中有所探讨。

贝叶斯优化

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自贝叶斯优化回购

实际上,高层次的概念非常简单,我们试图用贝叶斯优化做同样的事情,我们总是试图在 ML 中做,那是估计函数,函数太复杂而无法公式化。但是现在我们试图逼近的函数是我们的 ML 算法。在这种情况下,我们可能会使用深度学习或其他形式的 ML,我们只能运行有限数量的试验来测试超参数的不同组合。如果我们能够在选择下一个超参数配置之前智能地近似我们的 ML 算法的结果,我们可能会节省大量的时间和金钱。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自 TPE 论文

有几个贝叶斯优化函数,但其关键思想是使用贝叶斯方法来估计一个更好的超参数配置给定以前的一组配置及其结果。在上图中,我们使用了一种叫做 TPE 的算法,其基本概念是将我们的试验根据其表现分成两组,即得到较好结果的组和得到较差结果的组。然后,我们基于其属于好分布而不是坏分布的概率来挑选下一组超参数。

连续减半

在连续减半中,我们开始训练少量时期的大量试验,超参数配置是随机的。然后,我们丢弃表现最差的试验,并且仅继续训练表现最好的试验,我们这样做,直到保留单个超参数配置。

超波段

超带是逐次减半算法的扩展。连续减半的问题是,我们通常无法知道试验次数与时期数之间的正确权衡。在某些情况下,一些超参数配置可能需要更长时间才能收敛,因此开始时进行大量试验,但少量的历元并不理想,在其他情况下,收敛速度很快,试验次数是瓶颈。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

摘自超频论文

这就是超级波段的用武之地。Hyperband 本质上只是对最优分配策略的网格搜索。所以在每个单独的试验中,超参数组是随机选择的。

在图像中,您可以看到 hyperband 算法将在 5 次资源分配中连续减半。s=4 以 81 个试验开始其第一轮,为每个试验提供单个历元,然后迭代地丢弃 2/3 的试验,直到剩下一个试验,并训练 81 个历元。在 s=0 时,Hyperband 算法基本上运行一个随机搜索,进行 5 次试验,每次试验都根据最大历元数进行训练。

扎祖姆尔

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ZazuML 开源项目

ZazuML 是我和一些朋友一直在做的一个开源 AutoML 项目。它混合了几种搜索算法,包括前面提到的超波段和随机搜索。

请查看我们的 Github

超参数优化

原文:https://towardsdatascience.com/hyper-parameters-optimization-c2f888515d8f?source=collection_archive---------28-----------------------

了解如何让您的深度学习模型更上一层楼!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

https://unsplash.com/photos/Kl1gC0ve620

介绍

本文的目的是学习如何通过选择最佳超参数来优化神经网络。具体来说,我们将探索:

  • 网格搜索
  • 远视
  • 遗传算法

网格搜索

网格搜索是在一组参数中寻找最佳参数的最简单方法。本质上是蛮力。让我们看一个简单的例子:

假设我们有一个网格,我们想看看哪些参数是最好的。我们有:

  • 下降:可以从 0 到 0.5 变化,间隔为 0.1
  • 学习率:可以在 0.1 到 0.001 之间变化,间隔为 x10
  • 过滤器数量:从 64 到 256 不等,间隔为 64
  • 过滤器尺寸:从 3 到 7 英寸不等(总是方形过滤器)

嗯,网格搜索会做的如下:

**# grid definition**
dropouts = [0, 0.1, 0.2, 0.3, 0.4, 0.5]
learning_rates = [0.1, 0.01, 0.001, 0.0001]
n_filters = [64, 128, 192, 256]
filter_sizes = [3, 5, 7]**# variable creation to store the values**
log_accuracies = []from random import uniform
def dummy_net(d, lr, nf, fs):
  print('Executing network with d={}, lr={}, nf={}, fs={}'.format(d, lr, nf, fs))
  return uniform(0,1)**# counter**
i = 1**# grid search**
for d in dropouts:
  for lr in learning_rates:
    for nf in n_filters:
      for fs in filter_sizes:
        result_net = dummy_net(d, lr, nf, fs)
        print('[{}] Resultado: {}'.format(i, result_net))
        log_accuracies.append(result_net)
        i += 1

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最好的结果是:

import numpy as np
idx_max = np.nonzero(log_accuracies==np.max(log_accuracies))
print(idx_max)print('Best execution: {}. Accuracy: {}'.format(idx_max[0][0], log_accuracies[idx_max[0][0]]))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这就是我们如何评估网络配置的最佳结果。

这种方法的问题是我们在网络中有 6×4×4×3 次执行,总共有 288 次执行。如果每次执行最少需要 10 分钟,那么总时间加起来就是 48 小时。

让我们用一个非常简单的网来做一个测试:

**# We import the necessary libraries**
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K
from keras.utils import to_categorical
from keras.optimizers import Adam**# To load the data and convert from vectors to images**
img_rows, img_cols = 28, 28
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
input_shape = (img_rows, img_cols, 1)**# to normalize the data**
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255**# convert class vectors to binary class matrices**
num_classes = 10
y_train = to_categorical(y_train, num_classes)
y_test = to_categorical(y_test, num_classes)def net(do, lr, nf, fs):model = Sequential()
  model.add(Conv2D(nf, kernel_size=fs, activation='relu', input_shape=input_shape))
  model.add(Conv2D(nf, fs, activation='relu'))
  model.add(MaxPooling2D(pool_size=(2, 2)))
  model.add(Dropout(do))
  model.add(Flatten())
  model.add(Dense(128, activation='relu'))
  model.add(Dropout(do))
  model.add(Dense(10, activation='softmax'))model.compile(loss='categorical_crossentropy', optimizer=Adam(lr=lr), metrics=['accuracy'])model.fit(x_train, y_train,
            batch_size=1024,
            epochs=1,
            verbose=0,
            validation_data=(x_test, y_test))score = model.evaluate(x_test, y_test, verbose=0)

  print('Red con d={}, lr={}, nf={}, fs={}. Loss: {}. Acc: {}.'.format(d, lr, nf, fs, score[0], score[1]))      
  return score[1] # accuracy

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

**# grid definition**
dropouts = [0, 0.3]
learning_rates = [0.1, 0.01]
n_filters = [32, 64]
filter_sizes = [3, 5]**# variable creation to store the values**
log_accuracies = []**# counter**
i = 1**# grid search**
for d in dropouts:
  for lr in learning_rates:
    for nf in n_filters:
      for fs in filter_sizes:
        result_net = net(d, lr, nf, fs)
        print('[{}] Resultado: {}'.format(i, result_net))
        log_accuracies.append(result_net)
        i += 1

**# the best result will be:**
import numpy as np
idx_max = np.nonzero(log_accuracies==np.max(log_accuracies))
print(idx_max)print('Best execution: {}. Accuracy: {}'.format(idx_max[0][0], log_accuracies[idx_max[0][0]]))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

**# grid definition with the best values**
dropouts = [0, 0.3]
learning_rates = [0.01]
n_filters = [32, 64, 128]
filter_sizes = [5, 7]**# variable creation to store the values**
log_accuracies = []**# counter**
i = 1**# grid search**
for d in dropouts:
  for lr in learning_rates:
    for nf in n_filters:
      for fs in filter_sizes:
        result_net = net(d, lr, nf, fs)
        print('[{}] Resultado: {}'.format(i, result_net))
        log_accuracies.append(result_net)
        i += 1

**# the best result will be:**
import numpy as np
idx_max = np.nonzero(log_accuracies==np.max(log_accuracies))
print(idx_max)
print('Best execution: {}. Accuracy: {}'.format(idx_max[0][0], log_accuracies[idx_max[0][0]]))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是一个相当好的结果。虽然用更快的方法或者一些启发式的方法会很棒,而不是蛮力。你很幸运,因为有各种各样的方法:

  • 留兰香(蟒蛇皮)
  • BayesOpt(带有 Python 和 Matlab/Octave 接口的 C++)
  • 远视(蟒蛇皮)
  • SMAC(爪哇)
  • 伦博(Matlab)
  • MOE (C++/Python)

接下来我们将探索超级选项!

超级选项

Hyperopt 是一个用 Python 编写的库,它允许您通过更多地关注最有可能提供良好解决方案的值来快速优化函数。

你可以在这里找到完整的方法:分布式异步超参数优化,【https://github.com/hyperopt/hyperopt】T2。

它目前实现了两种算法来做到这一点:

  • 随机搜索
  • Parzen 估计树(TPE)

此外,利用 MongoDB,它们可以串行或并行运行。

让我们看一个如何使用它的例子。

让我们找出 x 的最小值:

from hyperopt import fmin, tpe, hp**# with 10 iterations**
best = fmin(fn=lambda x: x ** 2,
            space=hp.uniform('x', -10, 10),
            algo=tpe.suggest,
            max_evals=10)print(best)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

from hyperopt import fmin, tpe, hp**# with 100 iterations**
best = fmin(fn=lambda x: x ** 2,
            space=hp.uniform('x', -10, 10),
            algo=tpe.suggest,
            max_evals=100)print(best)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

from hyperopt import fmin, tpe, hp**# with 1000 iterations**
best = fmin(fn=lambda x: x ** 2,
            space=hp.uniform('x', -10, 10),
            algo=tpe.suggest,
            max_evals=1000)print(best)

现在让我们尝试一个更复杂的神经网络:

**# we install the necessary packages**
!pip install networkx==1.11 # para instala hyperopt correctamente, si no, da errores
!pip install hyperopt**# necessary imports**
import sys
import time
import numpy as np
from hyperopt import fmin, tpe, hp, STATUS_OK, Trials
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.constraints import max_norm
from keras.optimizers import Adam
from sklearn.model_selection import train_test_split
from keras.utils import to_categorical
from keras.callbacks import EarlyStopping
from keras.datasets import cifar10SEED = 42(X_train, y_train), (X_test, y_test) = cifar10.load_data()
validation_split = 0.1
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=validation_split, random_state=SEED)**# Let's convert the data to float and then divide it by 255 to normalize it
# Due to image characteristics they can only get values from 0 to 255**
X_train = X_train.astype('float32') / 255.
X_val = X_val.astype('float32') / 255.
X_test = X_test.astype('float32') / 255.**# let's convert the labels with one-hot encoding**
n_classes = 10
y_train = to_categorical(y_train, n_classes)
y_val = to_categorical(y_val, n_classes)
y_test = to_categorical(y_test, n_classes)**# we define the search space
# we'll vary:
# - the number of filters in our conv layers
# - the dropout percentage
# - the number of neurons in the dense layer**
space = {
    'n_filters_conv': hp.choice('n_filters_conv', [32, 64, 128]),
    'dropout': hp.uniform('dropout', 0.0, 0.5),
    'neurons_dense': hp.choice('neurons_dense', [256, 512, 1024]), 
}def get_callbacks(pars):
  callbacks = [EarlyStopping(monitor='val_loss', min_delta=0.0001, patience=2, verbose=0, mode='auto')]
  return callbacksdef mi_cnn(pars):
  print ('Parameters: ', pars)
  model = Sequential()

 **# First convolutional block**
  model.add(Conv2D(pars['n_filters_conv'], kernel_size=(3, 3), activation='relu', input_shape=(32, 32, 3)))
  model.add(MaxPooling2D(pool_size=(2, 2)))
  model.add(Dropout(pars['dropout']))**# second convolutional block**
  model.add(Conv2D(pars['n_filters_conv'], kernel_size=(3, 3), activation='relu'))
  model.add(MaxPooling2D(pool_size=(2, 2)))
  model.add(Dropout(pars['dropout']))**# third convolutional block**
  model.add(Conv2D(pars['n_filters_conv'], kernel_size=(3, 3), activation='relu'))
  model.add(MaxPooling2D(pool_size=(2, 2)))
  model.add(Dropout(pars['dropout']))**# Classifier block**
  model.add(Flatten())
  model.add(Dense(pars['neurons_dense'], activation='relu', kernel_constraint=max_norm(3.)))
  model.add(Dropout(pars['dropout']))
  model.add(Dense(10, activation='softmax'))**# We compile the model**
  model.compile(loss='categorical_crossentropy',
                optimizer=Adam(lr=0.0001, decay=1e-6),
                metrics=['accuracy'])**# We train the model**
  history = model.fit(X_train, 
                      y_train,
                      batch_size=128,
                      shuffle=True,
                      epochs=5,
                      validation_data=(X_val, y_val),
                      verbose = 0,
                      callbacks = get_callbacks(pars))best_epoch_loss = np.argmin(history.history['val_loss'])
  best_val_loss = np.min(history.history['val_loss'])
  best_val_acc = np.max(history.history['val_acc'])

  print('Epoch {} - val acc: {} - val loss: {}'.format(best_epoch_loss, best_val_acc, best_val_loss))
  sys.stdout.flush()

  return {'loss': best_val_loss, 'best_epoch': best_epoch_loss, 'eval_time': time.time(), 'status': STATUS_OK, 'model': model, 'history': history}trials = Trials()
best = fmin(mi_cnn, space, algo=tpe.suggest, max_evals=10, trials=trials)
print(best)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

trials.results

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

trials.losses()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这样,您可以离开您的配置,去做一些比改变参数更有用的事情,直到您找到正确的配置。

但是我们不一定要呆在这里,如果我们想要剩余连接,我们也可以改变层数或设置。是的,这意味着我们也可以改变架构!

这里有一个非常完整的例子:【https://github.com/Vooban/Hyperopt-Keras-CNN-CIFAR-100】T4

还有一个你可能会感兴趣的。

遗传算法

本质上,遗传算法是一种受自然进化启发的元启发式研究方法。它们属于进化算法,特别是导向随机搜索算法(进化算法)。

这听起来可能很复杂,但实际上非常简单。让我们用一个例子来理解它们:

想象一下,我们有一个拼图,我们只剩下一块拼图可以拼了。问题是这个谜题非常特别,因为它让我们能够完成我们的作品。为此,我们有几种机制:

  • 组合部分片段(交叉或重组)
  • 修改那些部分的某些部分(突变)
  • 选择我们所做的最好的作品,从新的和更好的作品中建立(选择)

然后,假设我们决定切割 10 块纸板,这是我们最初的 10 块纸板,我们将用它们来测试是否有任何一个完全符合。我们都试过了,在这 10 个中,有 5 个或多或少合适。因此,我们选择了这 5 个,并使用上面解释的机制从中制作了新的:

  • 从选择的五个中,我们通过随机选择的方式将最初的五个中的两个部分组合起来,再取五个。
  • 在最初的 5 个和我们创造的新的 5 个中,我们通过稍微修改作品的一个尖端,再去掉 5 个

现在我们有 15 个棋子,我们总是想要 10 个,因为如果不是在第 5 次我们这样做了,我们会有很多棋子,所以:

  • 我们试了 15 件,找到最合适的,然后随机选择 9 件。

让我们看看如何在实践中应用这个例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按作者分列的数字

如你所见:

  • 我们这组片段(群体)中的每一个片段都是一条染色体
  • 我们的每一部分都是一个基因,所以我们的染色体有 4 个基因
  • 每个基因可能具有的值或设置被称为等位基因。

这和生物学中的一样,因为这些算法是受自然进化的启发?

好的,让我们把这些单词和我们的例子联系起来:

  • 我们需要为我们的拼图洞找到合适的一块
  • 我们有一组初始的片段(群体),我们不知道它们是否合适
  • 我们检查这些部分配合得有多好(使用适应度函数)
  • 如果没有一个片段符合我们的要求,我们就修改这些片段(使用操作符:交叉和变异)
  • 我们检查新创建的片段在一起的吻合程度(适应度函数)
  • 我们选择我们想要为下一次迭代(选择)保留的片段
  • 我们重新开始。直到我们找到一个符合我们要求精度的零件

我们来看看伪算法:

开始

  • 生成初始群体
  • 计算适合度

重复

  • 选择
  • 交叉
  • 变化
  • 计算适合度

直到种群已经收敛

停止

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

但是它们是如何工作的呢?

我们必须理解几个概念:

  • 我们的人口如何初始化
  • 交叉是如何工作的
  • 变异是如何发生的
  • 选择是如何工作的
  • 我们如何定义我们的适应度函数

首先要明白的是,当我们在现实世界中遇到问题,想要在计算机上解决时,我们需要对它进行编码,以便计算机能够理解它。

比如说:

在现实世界中,染色体是拼图的一部分。在计算机中,染色体是一个有 4 个值的向量(一个表示每个尖端的大小,其中正表示尖端,负表示片上的洞)
这就是所谓的编码。

一旦我们知道了这一点,我们将看到操作符是如何工作的。首先,你应该知道有许多类型的交叉、变异和选择,但是这里我们将只从时间的角度来看最简单的那些。

如果你有兴趣了解更多,网上有很多资料。可以从这里开始:https://www.tutorialspoint.com/genetic_algorithms/index.htm

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按作者分列的数字

单点交叉

我们的染色体是拼图,它有你在图片中看到的 4 个基因。因此,简单的交叉只是从 4 个基因中随机选择一个点,并将这些部分组合成新的染色体,如图所示。

理解这一点很重要,因为我们有原始的和重组的染色体。

均匀突变

统一的突变是,对于每个染色体,我们抛硬币。如果很贵,我们就修改随机选择的基因。我们赋予它什么价值?在基因允许的范围内随机选择一个。

选择

对于选择,通常使用染色体适应度(也称为可能的解决方案)。在这种情况下,我们将研究随机通用采样,它包括构建一个饼形图,其中每个染色体占据一个与其适应度相对应的空间。然后,我们在“蛋糕”周围建立 N 个固定点,其中 N 是我们要选择的染色体数目。然后,我们“旋转蛋糕”,仿佛是运气轮盘,定点指向的染色体就是被选中的,继续下一次迭代。

你看看,染色体不是从适应度最高到最低排序的。

这一点很重要,因为否则,选择一个高适应性染色体和另一个低适应性染色体的机会将高于选择两个高适应性染色体的机会。毕竟,由于选择点在彼此的前面,选择两条适应度相似的染色体会非常复杂。

这个运算符有几种工作方式。继续我们的 10 染色体群体的例子:

  • 我们选择 N=10 条染色体,也就是说,我们用一个完全新的群体替换先前的群体
  • 我们选择 N=n 条染色体,其中 N<10. In other words, we replace only a part of the old chromosomes.

Okay, so if we select all 10 it’s clear, but if we select n, how do we choose which ones to remove?

Well, the two most common ways are:

  • We remove the oldest chromosomes
  • We remove the chromosomes with the worst fitness

Finally, there are times when we select the best chromosome (or the k best) to pass if or when the next iteration, that is, there is elitism. We have to be careful with this, because although a priori it seems that elitism is the best and that we should only stay with the best if we did we would be killing one of the greatest virtues of genetics: that they can escape to local minimums!

Look, here you can see a geneticist in action trying to decide which is the best configuration for a two-wheeled vehicle: http://rednuht.org/genetic_cars_2/

让我们自己实现几个例子?

**# example of a GA where we have to find N numbers that add up to X
#** [**https://lethain.com/genetic-algorithms-cool-name-damn-simple**](https://lethain.com/genetic-algorithms-cool-name-damn-simple)from random import randint, random
from operator import add
from functools import reduce
import numpy as npdef individual(length, min, max):
 **# we create an individual**
    return [ randint(min,max) for x in range(length) ]def population(count, length, min, max):   
    **# we create our population**
 **# count: number of individuals of each population
    # length: number of values per individual
    # min: minimum allowed for each individual's value
    # max: maximum allowed for each individual's value**return [ individual(length, min, max) for x in range(count) ]def fitness(individual, target):
    **# we compute the fitness of each individual, the smaller the better**

    sum = reduce(add, individual, 0)
    return abs(target-sum)def grade(pop, target):
    **# we compute the average of the entire population**
    summed = reduce(add, (fitness(x, target) for x in pop))
    return summed / (len(pop) * 1.0)

def find_best_solution(pop, target):
 **# we find the best solution in the current population and prints it**
    res = [fitness(x, target) for x in pop]
    res_min = np.min(res)
    res_min_idx = np.where(res == res_min)[0]
    for n in res_min_idx:
        print('Individual: ', n, 'Valores: ', *pop[n], ' Result: ', np.sum(pop[n]), 'Target; ', target)
    return res_mindef evolve(pop, target, retain=0.2, random_select=0.05, mutate=0.01):
    graded = [ (fitness(x, target), x) for x in pop]
    graded = [ x[1] for x in sorted(graded)]
    retain_length = int(len(graded)*retain)
    parents = graded[:retain_length]

 **# we add individuals randomnly to promote genetic diversity**
    for individual in graded[retain_length:]:
        if random_select > random():
            parents.append(individual)

 **# we mute some**
    for individual in parents:
        if mutate > random():
            pos_to_mutate = randint(0, len(individual)-1)
            individual[pos_to_mutate] = randint(i_min, i_max)

 **# we reproduce (crossover) our chromossomes (individuals, solutions)**
    parents_length = len(parents)
    desired_length = len(pop) - parents_length
    children = []
    while len(children) < desired_length:
        male = randint(0, parents_length-1)
        female = randint(0, parents_length-1)
        if male != female:
            male = parents[male]
            female = parents[female]
            half = round(len(male) / 2)
            child = male[:half] + female[half:]
            children.append(child)        
    parents.extend(children)
    return parents**# exectute the GA**
generations = 20
target = 108
p_count = 20
i_length = 5
i_min = 0
i_max = 100
error_accepted = 1
print('We intiate the population with 20 individuals.')
p = population(p_count, i_length, i_min, i_max)
print('We compute the fitness of those 20 individuals.')
fitness_history = [grade(p, target),]
print('The best individual of the initial population is:')
find_best_solution(p, target)for i in range(generations):
    p = evolve(p, target, retain=0.2, random_select=0.2, mutate=0.4)
    res = grade(p, target)
    fitness_history.append(res)

    res_min = find_best_solution(p, target)
    print('Generation: ', i, ' Average fitness of the population's individuals:', res)

    if res_min < error_accepted:
      break

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在让我们通过使用 Github 上可用的实现将它应用于神经网络:【https://github.com/jliphard/DeepEvolve

让我们克隆一个 git 存储库,它已经实现了 GA 来进化神经网络的超参数和架构:

!rm -rf DeepEvolve
!git clone [https://github.com/jliphard/DeepEvolve.git](https://github.com/jliphard/DeepEvolve.git)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

!ls

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

!pip install tqdm

看一看正在进行搜索以找到最佳组合的参数:

if dataset == 'mnist_cnn':
        generations = 8 # Number of times to evolve the population.
        all_possible_genes = {
            'nb_neurons': [16, 32, 64, 128],
            'nb_layers':  [1, 2, 3, 4 ,5],
            'activation': ['relu', 'elu', 'tanh', 'sigmoid', 'hard_sigmoid','softplus','linear'],
            'optimizer':  ['rmsprop', 'adam', 'sgd', 'adagrad','adadelta', 'adamax', 'nadam']
        }

现在我们将执行 GA:

!python DeepEvolve/main.py

最后的话

一如既往,我希望你喜欢这个帖子,并且你获得了关于如何优化你的神经网络参数的直觉!

如果你喜欢这篇文章,那么你可以看看我关于数据科学和机器学习的其他文章 这里

如果你想了解更多关于机器学习、数据科学和人工智能的知识 请关注我的 Medium ,敬请关注我的下一篇帖子!

人工智能设计的“超级食物”可能有助于预防癌症

原文:https://towardsdatascience.com/hyperfoods-9582e5d9a8e4?source=collection_archive---------17-----------------------

让食物成为你的良药

我们吃的食物含有成千上万的生物活性分子,其中一些类似于抗癌药物。现代机器学习技术可以发现这种成分,并帮助设计营养,让我们活得更长更健康。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

插图:比安卡·达盖蒂。

本文与Kirill Veselkov和 Gabriella Sbordone 合著,基于《自然》杂志科学报告上发表的TEDx Lugano 2019 talk 论文

我们现在比以往任何时候都活得长。然而,我们并不一定生活得更健康:随着人口的快速老龄化,人们正在经历癌症、代谢、神经和心脏疾病等慢性疾病的持续增长。这使得医疗费用飞涨,给公共卫生系统带来了巨大压力[1]。

很大一部分问题在于糟糕的饮食选择。不健康的饮食杀死的不仅仅是香烟,而且是全球五分之一死亡的原因——2018 年,这相当于近 1100 万条生命。除了明显的罪魁祸首——不健康的高度加工食品——一个不太明显的杀手是健康食品的低摄入量,如全谷物、蔬菜、水果、坚果、种子和豆类[2]。

以癌症为例:正当地考虑现代社会的困境,它将在他们一生中的某一点上影响这篇文章的每一个读者。尽管前景似乎很悲观,但好消息是,仅通过饮食和生活方式的改变,就可以预防近 40%的肿瘤疾病[3]——这一发现鼓励我们更仔细地审视我们所吃的东西,因为饮食可能是癌症最重要的可变风险因素。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

暗物质

在过去的几十年里,营养科学在分析影响人类健康和疾病的六大营养类别方面取得了卓越的进展:蛋白质、碳水化合物、脂肪、矿物质、维生素和水。国家营养数据库跟踪这些类别中的大约 150 种成分,它们出现在每个食品包装上。

然而,越来越多的证据表明,来自各种化学类别的数千种其他分子——如多酚类黄酮萜类化合物吲哚——可能有助于预防和对抗疾病,这些分子在植物中大量存在,通常是它们的颜色、味道和气味的天然原因[4]。这些化合物中的大多数仍然基本上没有被专家探索,没有被监管机构跟踪,也不为公众所知,因此名副其实地被称为“营养的暗物质”[5]。

每吃一口食物,我们都会把数百种这样的生物活性化合物放进嘴里。这些分子在我们吞下它们的那一刻就相互作用,随着食物被消化和代谢,还会与我们体内的其他生物分子和我们肠道中的数万亿细菌发生反应。

植物性食物中发现的许多化合物与药物属于同一类化学物质。因此,几乎一半被批准用于抗癌治疗的小分子来自天然产物就不足为奇了。这些药物通常耐受性更好,对健康细胞的毒性更小[6]。

药物和食物

传统药物分子旨在结合与特定疾病过程相关的生物分子靶标,其中最重要的涉及蛋白质[7]。经典药物治疗遵循“一种疾病-一种药物-一个靶点”的范式,试图确定一种与疾病相关的“可用药”蛋白质,该蛋白质可以被药物靶向。事实上,药物很少如此具有选择性[8],蛋白质之间复杂的相互作用网络(或“图形”)产生了一种“网络效应”,可以干扰多种生物过程——就像一张倒下的多米诺骨牌撞掉一整排。

蛋白质-蛋白质相互作用(PPIs) [9]被认为是下一代治疗靶点,大多数制药行业现在已经将其药物发现计划扩展到 PPIs [10]。为了利用现代高通量技术产生的大量分子相互作用数据,机器学习(ML)变得越来越重要。然而,与图像和音频信号不同的是,ML 在过去十年中取得了突破性的成果,网络结构化数据需要一种不同类型的方法,称为“图形 ML”。

Graph ML,也称为“图形表示学习”或“几何深度学习”,是机器学习领域最近的一个热门话题,我在我的走向数据科学博客中对此进行了广泛的介绍。典型的图形 ML 架构,称为图形神经网络在图形上实现某种形式的消息传递,允许不同的节点交换信息。在最简单的公式中,消息传递采取线性扩散或图中“随机漫步”的形式[11]。

在去年发表在《自然科学报告》杂志上的一篇论文中,我们应用 graph ML 利用蛋白质-蛋白质和药物-蛋白质相互作用图来寻找食物中的抗癌分子【12】。药物与蛋白质的相互作用被表示为 PPI 图上的信号,一个可学习的扩散过程被用于模拟药物的网络效应。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一种药物通常会影响多个蛋白质靶点(显示为红色)。作为蛋白质相互作用的结果,药物效应波及到生物网络的其他部分(显示在橙色阴影中)。

我们使用了一个由近 2000 种临床批准的药物组成的训练集,其中约有 10%被标记为抗癌药物,以便训练一个分类器,通过新分子与 PPI 图的相互作用来预测新分子的抗癌药物相似性。然后,我们将大约 8000 种已知蛋白质相互作用的基于食物的分子输入训练好的分类器。我们的模型确定了一百多种抗癌药物样候选物,我们称之为“抗癌分子”。使用 ML 方法的主要优势在于,可以利用大量公开可用的数据集自动发现这些分子。

然后,我们再次求助于机器学习,使用自然语言处理(NLP)技术从医学文献中挖掘已识别分子抗癌效果的实验证据[13]。我们还必须排除毒性过大的化合物。这是依赖于已报道的体外体内实验的第一个验证步骤。

好东西

关于食物基化合物的现有文献的一个关键限制是它集中于特定的化合物,例如抗氧化剂孤立的。你肯定见过被誉为富含抗氧化剂的食物,并且经常以“超级食物”的标签销售。然而,尽管经常食用这类食物可以降低癌症形成的风险(“致癌”),但其中所含的抗增殖剂在单独作用时似乎并不能始终如一地提供相同水平的益处[14]。

这种现象类似于在医疗实践中同时使用多种药物(技术上称为“多种药物”),这通常会导致不良副作用以及比每种药物单独使用更强的协同作用[15]。因此,某些食物的抗癌效果是生物活性物质组合的结果,并由它们的拮抗和协同作用以及它们同时作用于不同致癌生物机制的方式决定。

茶和柑橘类水果是满足这两个条件的食物的例子:首先,它们含有多种由我们的 ML 模型确定并从医学文献中证实的抗癌药物样化合物,其次,这些化合物发挥互补的抗癌作用[16]。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

食物地图:每个节点是一种食物,它的大小代表抗癌分子的数量。两个节点之间的联系反映了这些食物分子特征的相似性,使我们能够根据它们的分子组成对食物进行分类。图来自[12]。

有了这种认识,我们构建了超过 250 种不同食物成分的抗癌分子图谱,突出了我们称为“超食物”的突出冠军。除了前面提到的茶和柑橘,卷心菜、芹菜和鼠尾草都是相当常见、便宜和容易买到的超级食物。从某种意义上来说,这并不奇怪,因为营养专家提倡这些食物是健康的选择,而且有大量证据表明它们对健康有益。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

姜黄香料热巧克力由厨师约瑟夫·优素福根据他的新 超食物食谱 设计。图片来源:厨房理论。

然而,读完这篇文章后,不要急着做卷心菜奶昔,因为你可能会失望——大多数情况下,它会很难吃。我们仍然缺少最后一步,将超食物成分整合到味道和外观都很棒的食谱中。这就是我们利用 Jozef Youssef 的帮助的地方,他是厨房理论【17】的创始人和主厨赞助人,他用我们的 hyperfood 原料创造了简单、实惠、美味的食谱。事实上,超级食物不仅仅是米其林餐厅的常客和高级美食的粉丝的专利:许多简单、传统的日常食谱已经包含了抗癌成分。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

核桃酱黑麦面包含有许多超食物成分。这道菜是我们在卢加诺 TEDx talk 上展示的意大利-瑞士 hyperfood 菜单的一部分。菜肴和图片来源:加布里埃拉·斯博多内。

后续步骤

我们还需要记住,食物烹饪涉及物理和化学过程,可能会改变其分子内容。例如,如果我们在高温下油炸我们的原料,许多抗癌分子可能会消失。我们可以将食物制备表示为一个计算图,烹饪转换建模为边,并通过选择以最佳方式保留抗癌分子成分的操作来优化它。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第二,除了抗癌分子,食物还含有赋予食物味道、气味和独特风味的分子[18]。许多食物都有多种这样的成分:例如,你会惊讶地发现大蒜和茶有一百多种共同的味道分子。食物搭配的秘诀是将具有相似或互补风味分子特征的成分组合在一起[19]。被认为是顶级厨师的某种“黑魔法”现在可以自动化了——我们可以潜在地使用 graph ML 来生成食谱,在健康、味道甚至美学之间取得最佳平衡。有一天,我们电脑生成的食谱甚至会挑战米其林星级厨师,这并非不可能。

最后但并非最不重要的一点是,当谈到品味时,唯一共同的真理是,正如拉丁谚语所说的那样。食谱设计必须高度个性化,考虑到个人的口味偏好,以及许多其他参数,如饮食限制、遗传、病史和肠道微生物群。我们设想未来每个人都将拥有一个存储个人营养数据的数字“食物护照”,这样当你在网上订餐或外出就餐时,你的膳食将根据你的健康和食物状况进行优化。

最后的想法

Hyperfoods 首次尝试应用基于图形的 ML 方法,通过模拟食品中生物活性分子与我们体内生物分子相互作用的“网络效应”来预测其对健康的影响。graph ML 方法的使用使我们能够确定哪些食物中含有的成分可能与医学药物的作用方式相似,并有可能预防或战胜疾病。虽然癌症是一类重要的疾病,但同样的方法可以用于发现有助于预防神经退行性疾病、心血管疾病或病毒性疾病的食物[21]。

从更长远的角度来看,我们的目标是在如何“规定”、设计和准备我们的食物方面提供一个巨大的飞跃——让我们所有人过上更健康、更幸福、更美好的生活。

[1] M. J. Prince 等人,《老年人的疾病负担及其对健康政策和实践的影响》( 2015 年),《柳叶刀》385:549–562。

[2] GBD 2017 饮食合作者,195 个国家饮食风险的健康影响 (2019),Lancet 393:1958–1972 发现,1100 万例死亡可归因于饮食风险因素,其中 300 万例是由于全谷物摄入量低,200 万例是由于水果摄入量低。相比之下,T2 世卫组织估计烟草每年杀死 800 万人。

[3] M. S. Donaldson,营养与癌症:抗癌饮食证据综述 (2004),营养杂志 3,估计 30%-40%的癌症可以仅通过生活方式和饮食措施来预防,并建议坚持建议的饮食指南(包括十字花科蔬菜、亚麻籽和水果的推荐摄入量)可能导致乳腺癌、结肠直肠癌和前列腺癌减少 60%-70%,肺癌减少 40%-50%,以及类似的减少

[4]实验研究表明,这些分子参与多种机制,有助于预防或治疗各种癌症,包括调节炎症介质和生长因子的活性,抑制癌细胞存活、增殖和侵袭,以及血管生成和转移。例如,参见 A. K. Singh 等人,膳食植物化学物质在对抗癌症中的新兴重要性:在靶向癌症干细胞中的作用(2017),食品科学和营养学评论 57:3449-3463 或 R. Baena Ruiz 和 P. Salinas Hernandez,膳食植物化学物质的癌症化学预防:流行病学证据(2016),Maturitas 94:13-19。

[5]这种与物理学中的“暗物质的类比出现在 R. R. da Silva 等人的《代谢组学中的暗物质》(2015),PNAS 112(41):12549–12550 以及 A.-L. Barabási 等人的《我们饮食中未映射的化学复杂性》(2019),《自然食品》1:33–37 中。

[6]许多药物来源于植物,这常常反映在它们的名称中:例如,麻黄素得名于植物属麻黄,阿托品取自颠茄属植物颠茄,乙酰水杨酸,俗称阿司匹林,取自柳树皮白柳,其药性自古就为人所知。在肿瘤医学中,突出的例子是天然化合物喜树碱的类似物,它是从喜树中提取的,在传统医学中也是众所周知的。四种这样的分子——拓扑替康、伊立替康、贝洛替康和曲妥珠单抗 deruxtecan——被广泛用于癌症化疗。D. J. Newman 和 G. M. Cragg,1981 年至 2014 年(2016 年)天然产物作为新药的来源,《天然产物杂志》79(3):629–661 报道,几乎一半的抗癌疗法源自天然产物。

[7]蛋白质是活细胞的动力源泉,从字面上看是“生命分子”,因为我们目前还不知道任何不是以蛋白质为基础的生命形式。在我们的身体中,蛋白质负责催化化学反应(酶),为组织提供结构(胶原蛋白),运输氧气(血红蛋白),保护我们免受病原体(抗体)的侵害,等等。蛋白质是在细胞中通过一种特殊的化学机制合成的,这种机制读出遗传密码并将其翻译成氨基酸序列:称为“密码子的 DNA 核苷酸短序列编码 20 种蛋白质氨基酸。我们的基因组中编码了大约 20,000 种蛋白质,这些蛋白质相互作用,并与其他分子相互作用。由于蛋白质在生物化学过程中的关键作用,它们被用作药物靶标:典型的药物是小分子,其设计方式使得它们可以化学附着(“结合”)到特定的蛋白质上。

[8]据估计,一个药物分子可以结合近 50 种蛋白质,参见 B. Srinivasan 等人对八种蛋白质的 FINDSITE(comb)虚拟配体筛选结果的实验验证产生了新的纳摩尔和微摩尔结合物 (2014),Cheminformatics 6:16,因此一种药物-一个靶标的假设与现实相差甚远。

[9]蛋白质-蛋白质相互作用是“网络医学”中利用的图表的一个例子,该术语由 A.-L. Barabási 在《网络医学——从肥胖到“疾病体”(2007),新英格兰医学杂志 357:404–407 中创造并普及。

[10] A. Mullard,蛋白质-蛋白质相互作用抑制剂进入凹槽(2012)。自然评论药物发现 11(3):173–175 称 PPI 目标为“未开采的黄金储备”。大环是药物样小分子的一个例子,它破坏蛋白质-蛋白质相互作用并加速癌细胞死亡。尽管它们的治疗相关性和未开发的丰富性,但它们的采用受到技术障碍的阻碍,参见 T. L. Nero 等人,致癌蛋白质界面:小分子,大挑战(2014),自然评论癌症 14(4):248-262 和 D. E. Scott 等人,小分子,大目标:药物发现面临蛋白质-蛋白质相互作用的挑战(2016),自然评论药物发现 15:533-550。

[11]参见 M. M. Bronstein 等人的几何深度学习:超越欧几里德数据 (2017),IEEE Signal Processing Magazine 34(4):18–42 和我的关于这个主题的博文

[12] K. Veselkov 等人, HyperFoods:食品中抗癌分子的机器智能图谱 (2019),科学报告 9。

[13]关于癌症的科学文献数量巨大,平均每 3 到 4 分钟就有一篇论文发表,即使是最勤奋的人类科学家也无法消化。我们使用了 D. Galea 等人早期开发的用于命名实体识别的 NLP 系统,开发和评估用于监督生物医学命名实体识别的多源数据 (2018),生物信息学 34(14):2474–2482。我们论文的补充材料提供了在食物中发现的化合物的详细列表以及它们抗癌作用的实验证据。

[14]苹果是一个很好的例子,说明为什么人们必须考虑多种化合物的拮抗或协同作用:苹果提取物含有生物活性化合物,已被证明在体外抑制肿瘤细胞生长*。然而,这种效果因苹果皮是否保存而有很大差异:带皮的苹果抑制结肠癌细胞增殖达 43%,而不带皮的苹果仅抑制 29%,参见 M. V. Eberhardt 等人的《新鲜苹果的抗氧化活性》( 2000 年), Nature 405:903–904。*

[15] M. Zitnik 等人,用图卷积网络对多药副作用建模 (2018),生物信息学 34(13):457–466,将图 ML 应用于蛋白质-蛋白质和蛋白质-药物相互作用图,以预测多药的副作用

[16]茶是儿茶素(表没食子儿茶素没食子酸酯)、萜类化合物(羽扇豆醇)和单宁(原花青素)的丰富来源,它们分别通过保护活性氧化物质诱导的 DNA 损伤、抑制炎症、诱导凋亡和癌细胞周期停滞而发挥强大的互补抗癌作用。最近的几项荟萃分析表明,饮用绿茶可延迟癌症发作,降低治疗后癌症复发率,并增加长期癌症缓解率,参见 V. Gianfredi 等人绿茶饮用与乳腺癌和复发风险-观察性研究的系统综述和荟萃分析 (2018),营养素 10,以及 Y. Guo 等人:绿茶与前列腺癌风险: (2017),医学 96(13)。第二个例子是甜橙,这是一种柑橘类水果,含有化合物 dydimin(柑橘类黄酮)、obacunone(柠檬苦素样葡萄糖)和β-榄香烯,以其强抗氧化、促凋亡和化学敏化作用而闻名。S. Cirmi 等人的《柑橘类果汁及其提取物的抗癌潜力:临床前和临床研究的系统综述》 (2017),药理学前沿 8。

[17]我第一次见到基里尔是在 2015 年的世界经济论坛会议上。我们很快成为朋友,部分是因为我们共同的俄罗斯背景,然后在我 2018 年加入帝国理工学院时成为同事。基里尔是在 2018 年计算与食品未来的会议上认识乔泽夫的。Jozef 是厨房理论(Kitchen theory)的主厨赞助人,这是一家看起来像化学实验室的高端餐厅,客人们被邀请参加心理物理实验,比如一边听着嘎吱嘎吱的声音一边吃水母(这改变了对食物味道的感知)。

[18] FlavorDB 是一个在线资源,允许我们探索近 1000 种食物中超过 25000 种风味分子的含量。

[19] Y.-Y. Ahn 等,风味网络与食物搭配原则 (2011)。科学报告 1 通过分析共享风味分子图显示,西方烹饪倾向于使用具有共同风味化合物的配料对,而东亚烹饪倾向于避免共享化合物的配料。

[20]我们并不是第一个致力于自动菜谱生成的人:已经做了多次尝试,最著名的是 IBM 认知烹饪项目。然而,据我所知,我们是第一个超越味道并试图解释生物活性分子的人。

[21]graph ML 的使用在针对新疾病重新调整现有药物的用途方面似乎非常有前途(药物重新定位),这可以显著降低开发新疗法的成本和时间。作为药物和冠状病毒项目的一部分,我们目前正在使用沃达丰分布式计算平台寻找食品和现有药物组合中的抗病毒化合物,这些化合物可能对癌症和新冠肺炎有治疗作用。我还担任医药创业公司 Relation Therapeutic 的科学顾问,该公司与 Mila盖茨基金会合作,将 graph ML 与主动学习技术相结合,寻找针对新冠肺炎的组合疗法。

非常感谢费比诺·弗拉斯卡、卢卡·斯博多内和大卫·西尔弗对这篇文章的校对。Hyperfoods 是帝国理工学院的一个项目,由 Kirill Veselkov 领导,与沃达丰基金会和厨房理论合作。这篇文章无意作为医学建议:食物和疾病之间的关系仍然是一个新兴的研究领域,仍然缺乏系统的临床验证。厨师 Jozef Youssef 的食谱可在第一本 Hyperfoods 食谱 中在线获得。关于图形深度学习的其他文章,请参见我的 博客 关于走向数据科学, 订阅 我的帖子,获取 中等会员 ,或者关注我的Twitter。**

用于视网膜 OCT 图像分类的超参数分析

原文:https://towardsdatascience.com/hyperparameter-analysis-for-classification-of-retinal-oct-images-94254f67d914?source=collection_archive---------50-----------------------

通过使用 Monk,一个低代码深度学习工具和计算机视觉的统一包装器,使您的分类模型更好

超参数是在系统的训练过程之前指定的预定义参数。这些参数通常包括时期数、学习率和优化器等。它们识别机器学习模型的整体属性,并且可以被调整以控制机器学习算法的行为。

因此很容易猜测,设置最佳超参数意味着从您的模型中获得最大收益。通常,超参数优化涉及独立的过程,如 GridSearchCV 和 RandomizedSearchCV。在这里,我将向您展示优化超参数的最简单方法,使用 Monk 库中的内置函数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

CNV 受影响的眼睛的十月

视网膜光学相干断层扫描(OCT)是一种用于捕捉活着的患者的视网膜的高分辨率横截面的成像技术,并且这些图像的分析和解释占用了大量时间。我们的工作是将这些 OCT 图像分类为正常或 3 种疾病类型之一,即玻璃疣、CNV 或 DME。

目录

  1. 安装
  2. 建立模型
  3. 超参数分析
  4. 验证和推理

装置

安装 Monk,一个低代码深度学习工具,也是计算机视觉的统一包装器。

注意 : 我将在 Kaggle 上运行我的笔记本,我将使用的数据集是https://www.kaggle.com/paultimothymooney/kermany2018因此我将安装来自 Monk 的 Kaggle 需求。如果您希望在启用 CUDA 的系统上运行它,那么您应该安装 cu9 需求或 cu10 需求

*# Cloning the monk repository*
$ git clone [https://github.com/Tessellate-Imaging/monk_v1.git](https://github.com/Tessellate-Imaging/monk_v1.git)*# Installing the dependencies for Kaggle required by Monk*
$ pip install -r monk_v1/installation/Misc/requirements_kaggle.txt

如果您想在自己的系统上运行它,请将第二行替换为,

*# Installing the dependencies for CUDA 9 required by Monk*
$ pip install -r monk_v1/installation/Linux/requirements_cu9.txt*# Installing the dependencies for CUDA 10 required by Monk*
$ pip install -r monk_v1/installation/Linux/requirements_cu10.txt

建立模型

首先,我们将为我们的模型选择后端,在这种情况下,我将使用 MXNet 后端,

$ from gluon_prototype import prototype

然后,我们继续为我们的培训、测试和验证数据集定义路径。在我的例子中,它们在我的 Kaggle 工作目录中,在你的例子中,只需将路径粘贴到数据集中相应的文件夹中。

现在我们需要初始化我们的 Monk 原型,它将为项目建立一个工作目录

$ gtf = prototype(verbose=1)
$ gtf.Prototype("Retina-OCT", "Hyperparameter-Analyser")

现在可以用期望的基本模型、时期数和训练数据的位置来设置原型

$ gtf.Default(dataset_path=train_path,
           model_name="densenet121",
           freeze_base_network=False,
           num_epochs=5)

总之,设置的代码应该如下所示

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正常眼的 OCT 对比 DME 患眼的 OCT

超参数分析

转到主要焦点,优化我们模型的超参数。调整超参数对模型的性能有明显的影响,因此优化是必要的。

我们将使用 Monk 的内置超参数分析仪,这使我们的工作变得非常容易。首先,给分析项目起一个名字,并定义您想要分析的所有超参数。

在 Monk 的内置超参数分析器中,您可以选择分析以下超参数:

  1. 学习率 : 控制模型适应问题的速度
  2. 批量 : 指训练的一次迭代中抽取的样本数
  3. 优化器 : 更新权重参数以最小化损失函数

您还可以分析历元数、输入大小和基础模型。

# Analysis Project Name$ analysis_name = "analyse_hyperparameters"
$ lrs = [0.1, 0.05, 0.01, 0.005, 0.0001] # learning rates
$ batch_sizes = [2, 4, 8, 12] # Batch sizes
$ models = [["densenet121", False, True], ["densenet169", False, True], ["densenet201", False, True]] # models
$ optimizers = ["sgd", "adam", "adagrad"] # optimizers
$ epochs=10 # number of epochs
$ percent_data=5 # percent of data to use

要分析每个超参数,使用内置函数开始分析,并输入与该超参数对应的列表。因此,如果您从学习率的分析开始,输入将是学习率列表 lrs

*# Analysis of learning rates*
$ analysis = gtf.Analyse_Learning_Rates(analysis_name,lrs,
           percent_data,num_epochs=epochs, state="keep_none")

所以为了分析所有的超参数

验证和推理

现在我们的模型已经完全优化了,我们可以用它来验证和推断我们的验证和测试数据集。

当然,在这之前,我们需要训练我们的模型。Monk 中的训练过程再简单不过了,它只是一行代码。

$ gtf.Train()

在等待该培训完成后,我们可以继续获取该模型的准确性。因此,我们再次初始化我们的原型,但是这次用 infer-eval 标志为真,这样模型就处于预测模式。

# Set flag eval_infer as True 
$ gtf = prototype(verbose=1)
$ gtf.Prototype("Retina-OCT","Hyperparameter-Analyser", 
              eval_infer = True)

加载验证数据集,对整个数据集运行预测并显示结果

# Load the validation dataset 
$ gtf.Dataset_Params(dataset_path=val_path)
$ gtf.Dataset()# Run validation
$ accuracy, class_based_accuracy = gtf.Evaluate()

现在,我们将对测试图像运行一个样本推断,然后对整个测试数据集进行预测

# Running sample inference$ img_name = test_path +"/DRUSEN/DRUSEN-1786810-3.jpeg"
$ predictions = gtf.Infer(img_name=img_name)#Display 
$ from IPython.display import Image
$ Image(filename=img_name)# Load the test dataset
$ gtf.Dataset_Params(dataset_path=test_path)
$ gtf.Dataset()# Run inference on test data
$ accuracy, class_based_accuracy = gtf.Evaluate()

推断和验证的完整代码看起来有点像这样

结果

优化后的模型给出了惊人的结果,在验证数据集上的准确率为 100%

Result
        class based accuracies
            0\. CNV - 100.0 %
            1\. DME - 100.0 %
            2\. DRUSEN - 100.0 %
            3\. NORMAL - 100.0 %
        total images:            32
        num correct predictions: 32
        Average accuracy (%):    100.0

这是一个关于测试图像的示例推断,

Prediction
    Image name:         ../input/kermany2018/OCT2017 /test/DRUSEN/DRUSEN-1786810-3.jpeg
    Predicted class:      DRUSEN
    Predicted score:      5.612982273101807

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

玻璃疣受累眼的 OCT

在测试数据集上给出了 99.17% 的准确率。

你可以在 Kaggle 上找到完整的笔记本

如果有任何问题,可以联系 AbhishekAkash 。请随意联系他们。

我是 Monk Libraries 的开源贡献者。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Unsplash 上的 v2osk 拍摄的照片

最佳变压器模型的超参数优化

原文:https://towardsdatascience.com/hyperparameter-optimization-for-optimum-transformer-models-b95a32b70949?source=collection_archive---------15-----------------------

如何使用简单的转换器调整超参数,以实现更好的自然语言处理。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

格伦·汉森在 Unsplash 拍摄的照片

任何深度学习模型的目标都是接受输入并生成正确的输出。这些输入和输出的性质在不同的应用程序之间有很大的不同,这取决于模型应该执行的特定工作。例如,狗品种分类模型可以将图像作为其输入,并生成狗品种的名称(或对应于该品种的数字标签)作为输出。另一个模型可能接受一条狗的文本描述作为其输入,并生成狗的品种名称作为其输出。第一个模型是计算机视觉模型的一个例子,而后者是自然语言处理(NLP) 模型的一个例子。

参数与超参数

这两个模型的内部都将包含许多花哨的部分(卷积层、注意力机制等)。),每个都是为他们的特定任务量身定制的。从高层次的角度来看,所有这些组件构成了一组参数(或权重),它们决定了任何给定输入的输出。训练深度学习模型是为这些参数寻找一组值的过程,这些值在给定的任务中产生最佳结果。

相比之下,超参数是控制训练过程本身的因素。学习速率、训练时期/迭代次数和批量是常见超参数的一些例子。为超参数选择的值对学习到的参数有重大影响,并进而影响模型的性能。

简而言之,参数是模型学习的内容,超参数决定了模型学习的好坏。

超参数优化

就像我们有各种技术来训练模型参数,我们也有方法找到最佳超参数值。寻找最佳超参数值的过程是超参数优化,该过程使模型能够发现执行给定任务的最佳参数组

作为一个松散的类比,考虑超频一个 CPU。通过优化电压、温度、时钟频率等。(超参数),你可以在不改变 CPU 架构*(型号),或者 CPU 的组件(型号的参数)*的情况下,让 CPU 以更高的速度运行。

知道了什么是超参数优化,您可能想知道在训练模型时是否需要它。毕竟,我们中的许多人都不会考虑超频我们的 CPU,因为它们通常开箱即用。就像现代的 CPU 一样,最先进的深度学习模型即使没有超参数优化,通常也能表现良好。只要你坚持明智的默认,SOTA 预训练模型结合迁移学习的力量足以产生一个性能令人满意的模型。

但是,当您认为“足够好”还不够好时,超参数优化是您工具箱中的一个重要工具,可以帮助您的模型走得更远。

简单变压器的超参数优化

Simple Transformers 是一个库,旨在使变压器模型的训练和使用尽可能简单。根据这一想法,它通过 W & B 扫描特性为超参数优化提供了本机支持。

简单的变形金刚是建立在令人难以置信的变形金刚库之上的,拥抱脸为 NLP 的普及做出了巨大的贡献!

本文将重点关注使用简单的 Transformers 库,以及 W&B 扫描,对识别 SuperGLUE [2】基准的文本蕴涵 [1】任务执行超参数优化。任务是对句子对进行二元分类,如下所述。

文本蕴涵 识别最近被提出作为一种通用任务,其捕获许多 NLP 应用的主要语义推理需求,例如问题回答信息检索信息提取文本摘要。这个任务需要识别,给定两个文本片段,一个文本的含义是否是从另一个文本中推导出来的。

识别文本蕴涵

在本指南中,我们将执行三项主要任务来强调超参数优化的价值,并了解如何定制优化流程。

  1. 合理的默认值训练一个模型。
  2. 进行扫描以优化基本超参数
  3. 进行扫描以获得更多高级超参数优化

对于每项任务,我们将在 RTE 数据集上训练 RoBERTa-Large [3]模型。让我们设置好开发环境并下载数据集,这样我们就可以开始培训了!

设置

  1. 这里安装 Anaconda 或 Miniconda 包管理器。
  2. 创建新的虚拟环境并安装软件包。
    conda create -n simpletransformers python pandas tqdm wandb
    conda activate simpletransformers
    conda install pytorch cudatoolkit=10.2 -c pytorch 注意:选择您系统上安装的 Cuda 工具包版本。
  3. 如果您使用 fp16 培训,请安装 Apex。请遵循此处的说明
  4. 安装简单的变压器。
    pip install simpletransformers

数据准备

  1. 这里下载数据。
  2. 将档案文件解压到data/。(应包含 3 个文件,train.jsonlval.jsonltest.jsonl)

下面给出的函数可用于读取这些jsonl文件,并将数据转换成简单的变压器输入格式(带有三列text_a, text_b, labels的熊猫数据帧)。

因为我们将在许多地方使用这个函数,所以将它添加到项目根目录下的文件utils.py中,这样就可以根据需要导入它。

RTE 数据集包含三个子数据集。

  1. 训练集(带标签)-用于训练模型。
  2. 验证集(已标记)—用于验证(超参数优化、交叉验证等)。)
  3. 测试集(未标记)-可以提交对该集进行的预测进行评分。

为了避免提交预测来测试我们的最终模型,我们将把验证集分成两个随机部分,一个用于验证(eval_df),另一个用于测试(test_df)。

运行上面显示的data_prep.py文件将创建eval_dftest_df,我们将使用它们来验证和测试我们的模型。

用合理的默认值训练模型

有了经验,大多数人倾向于对重要的超参数以及哪些值对那些超参数有效产生直觉。根据我的经验,在 NLP 任务中训练 Transformer 模型时要考虑的两个最重要的超参数是学习速率训练时期数。

训练太多的历元或使用太高的学习率通常会导致灾难性遗忘,模型通常会对任何给定的输入生成相同的输出/标签。另一方面,训练历元数量不足或太低的学习率会导致低于标准的模型。

我对这两个超参数的定位值通常是5e-52学习率3训练时段(我增加了较小数据集的训练时段数量)。

然而,当我在 RTE 数据集上应用这些值训练模型时,我发现我的直觉让我失望了。该模型最终预测所有输入的标签相同,这表明学习率过高。将学习率降低到1e-5足以避免这个问题。

下面的脚本展示了如何用合理的默认值训练一个模型。

关于 *model_args* 属性的详细信息,可以根据需要参考变形金刚的简单文档( 此处 此处 )。

由于 RTE 任务使用准确性作为 SuperGLUE 基准测试中的度量,我们也将这样做。

使用可感知的默认超参数值,该模型达到了 0.8116 的精度。模型的混淆矩阵如下所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用合理的默认值训练的模型的混淆矩阵

您还可以在这里 看到完整的训练进度以及其他指标

还不错,不过还是看看超参数优化能做什么吧。

基本超参数优化

简单变压器中的 W&B Sweeps [4]集成简化了超参数优化过程。

可以通过 Python 字典定义扫描配置,该字典指定要优化的度量、要使用的搜索策略和要优化的超参数。

我强烈推荐浏览 文档 了解更多关于如何配置扫描的信息。

对于我们的基本超参数优化,我们将关注与前面部分相同的两个超参数,即学习率训练时期数

扫描配置可定义如下。

注意:你可以使用简单变压器模型的 配置选项 中的任何一个作为扫描时要优化的参数。

这里,我们使用bayes(贝叶斯优化)搜索策略来优化超参数。

贝叶斯优化使用高斯过程来模拟函数,然后选择参数来优化改进的概率。

W & B 文档

我们想要优化的指标是accuracy,目标显然是最大化它。请注意,要优化的指标必须记录到 W & B 中。

需要优化的参数是learning_ratenum_train_epochs。这里,学习率可以取从04e-4的任何值,而训练时期的数量可以是从140的任何整数。

W&B 扫描还可以通过终止任何表现不佳的运行来加速超参数优化(early_terminate)。这使用了超波段算法,如这里的所解释的

扫描的最后一个要求是一个函数,可以调用该函数用一组给定的超参数值来训练模型。

该函数将初始化wandb运行,建立简单的 Transformers 模型,训练模型,最后同步结果。

当前运行的一组超参数值包含在wandb.config中,可以传递给一个简单的变压器模型。所有简单的变形金刚模型都接受一个sweep_config关键字参数,并将根据传递给sweep_configwandb.config自动更新model_args

我们还确保在训练模型时,在验证集(eval_df)上计算accuracy指标。简单转换器中的所有eval_model()train_model()方法都接受由指标名和指标函数名组成的关键字参数。这里用来计算eval_df上的accuracy(更多信息在 文档 )

将所有这些放在一个 Python 文件中,我们得到了下面的脚本。

现在我们让它跑吧!

W&B 仪表板提供了许多图表和可视化效果,其中包含了大量有价值的信息。下图描绘了在扫描过程中(48 次运行约 13 小时)每个模型获得的精度。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

准确度 vs 创造的

根据达到的精度对这 48 次运行进行细分,我们得到以下结果:

  • 10 次运行获得的准确度大于 0.8
  • 23 次运行达到了精确到0.5507 的精度
  • 15 次运行达到的精度为精确到0.4493

这些结果可能看起来有点奇怪(使用精确的相同的准确度分数进行多次运行),直到您考虑到这样一个事实,即当使用错误的超参数值进行训练时,变压器模型可能会完全崩溃。这导致模型对任何输入预测相同的标签,解释具有相同准确度分数的模型(由于测试集中不平衡的标签,有两种可能的准确度)。

这个假设在参数重要性可视化中得到证实。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

基本超参数优化的参数重要性

这里,我们有两个超参数对最终精度的影响。learning_rate与准确度有很高的负相关性,因为高学习率导致模型预测所有输入的标签相同。

下面的平行坐标图证实了同样的理论。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

基本超参数优化的平行坐标图

专注于准确度高于 0.8 的运行进一步强化了这一想法。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

基本超参数优化的平行坐标图(精度> 0.8)

有趣的是,当在这个范围内使用学习率值时,训练时期的数量也开始发挥更重要的作用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

基本超参数优化的参数重要性(精确度> 0.8)

在这里随意挖掘扫描结果

现在,让我们看看用这些超参数训练的模型在测试集上的表现。

提醒:模型在训练集上训练,扫描在验证集( *eval_df* )上评估,最终模型(使用最佳超参数值)将在测试集( *test_df* )上评估。

该脚本使用扫描过程中在eval_df上产生最佳精度的超参数值。

learning_rate = 0.00003173
num_train_epochs = 40

用这些超参数值训练的模型获得了 0.8768 的精度,比敏感默认值模型( 0.8116 )有了显著提高。

查看测试集预测的混淆矩阵:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用基本超参数优化训练的模型的混淆矩阵

显然,我们的超参数优化取得了成效!

您还可以在这里 看到完整的训练进度以及其他指标

高级超参数优化

在上一节中,我们看到了学习率在一个经过训练的模型的性能中起着至关重要的作用。具有太高的学习率会导致模型损坏,而训练具有太低的学习率的模型会导致模型拟合不足或模型陷入局部最小值。

这个难题的一个潜在解决方案依赖于这样一个事实,即学习率似乎并不平等地影响模型的所有部分。例如,添加在 Transformer 模型层之上的分类层在更高的学习速率下更不容易被破坏。这可能是因为分类层在微调预训练模型时被随机初始化。即分类层不是预训练层,因此没有任何获得的知识会因灾难性遗忘而丢失。另一方面,分类层更有可能陷入局部最小值(具有低学习率),这正是因为它是随机初始化的。

当比较学习速率对早期层和后期层的影响时,可以观察到相同的现象,尽管程度较低(且一致性较低)。早期层比最终层更容易发生灾难性遗忘。

对于简单的变压器,我们可以为变压器模型中每个名为参数定义不同的学习速率。方便的是,我们还可以为模型中的任何给定层设置学习速率(RoBERTa-LARGE 为 24 层)。让我们看看是否可以将这一特性与我们对学习率的影响的了解结合起来,以推动我们的模型达到更好的性能。**

虽然我们可以尝试分别优化每一层的学习速率*,但我选择将这些层捆绑成四个相等的组,每个组包含六个连续的层。这将使我们更容易看到扫描结果,也可能使扫描更容易优化超参数,因为变量更少。*

RoBERTa 模型的分类层有四个命名的参数*,每个参数将被单独优化。或者,这些也可以组合成一个组(这可能是更合理的选择),但是出于演示的目的,我将它们分开。*

提示:所有简单的变形金刚模型都有一个 *get_named_parameters()* 方法,该方法返回模型中所有参数名称的列表。

同样,我们将从设置扫描配置开始。

我们正在使用从基本超参数优化中获得的见解,为变压器模型层的学习率设置一个较小的最大值,同时为分类层参数提供更多的余地。

关于使用自定义参数组和改编自文档的简单变压器的快速补充说明:

简单变形金刚模型的model_args(在本例中是一个ClassificationArgs对象)有三个与配置自定义参数组相关的属性。

  1. custom_layer_parameters
  2. custom_parameter_groups
  3. train_custom_parameters_only

自定义图层参数

custom_layer_parameters为给定层或层组设置(PyTorch)优化器选项更加方便。这应该是一个 Python 字典列表,其中每个字典包含一个layer键和任何其他与优化器接受的关键字参数匹配的可选键(例如lrweight_decay)。layer键的值应为指定层的int(必须是数字)(如0111)。

例如:

自定义参数组

custom_parameter_groups提供最精细的配置选项。这应该是一个 Python 字典列表,其中每个字典包含一个params键和任何其他与优化器接受的关键字参数匹配的可选键(例如lrweight_decay)。params键的值应该是一个命名参数列表(例如["classifier.weight", "bert.encoder.layer.10.output.dense.weight"])。

例如:

仅训练自定义参数

train_custom_parameters_only选项仅用于方便特定参数的训练。如果train_custom_parameters_only设置为True,则只训练custom_parameter_groupscustom_layer_parameters中指定的参数。

返回超参数优化:

虽然您可以使用简单变压器模型中可用的任何配置选项作为要优化的超参数,但 W&B Sweeps 目前不支持具有嵌套参数的配置。这意味着配置选项中预期的数据类型是集合(字典、列表等。)不能在扫描配置中直接配置。但是,我们自己可以轻松处理这个逻辑。

查看我们之前定义的sweep_config,我们可以观察到没有一个参数是嵌套的,尽管我们想要具有相同学习速率的多个层。**

扫描将为配置中定义的每个参数提供一个值(每次运行)。我们将在扫描的train()函数中把它转换成简单转换器所期望的格式。

选择sweep_config中的参数名称是为了使转换相对简单。

  • 层组的名称格式为layer_<start_layer>-<end_layer>
  • 参数组(分类器参数)的名称格式为params_<parameter name>

基于这个命名约定,让我们看看如何解析sweep_config来提取适当的超参数值。

首先,我们获取分配给当前运行的超参数值。这些可以通过 Sweep 的train()方法中的wandb.config对象来访问。幸运的是,我们可以将wandb.config转换成易于解析的 Python 字典。

我们还移除了_wandb键,并将其他字典条目重新排列成从参数名称到其当前值的直接映射。

接下来,我们遍历字典中的每一项,并以简单转换器所期望的格式构建一个字典。最后,我们用字典值更新model_args(一个ClassificationArgs对象)。

将所有这些整合到一个 Python 脚本中,我们就可以开始比赛了!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

精确度与为高级超参数优化创建的

在高级超参数优化扫描中,四十(40)次运行中有三十八(38)次达到了高于 0.8 的精度(相比之下,基本优化中为 48 次运行中的 10 次)。

当我们包括所有运行时,平行坐标图有点难以可视化,但我们可以专注于单个组以获得更清晰的图片。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

高级超参数优化的平行坐标图

我推荐你亲自去看看平行图(这里),因为它有许多互动功能,比单独的图像更好地可视化扫描。

第 0 层至第 6 层

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

0–6 层的平行坐标图

第 6 至 12 层

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第 6-12 层的平行坐标图

第 12 至 18 层

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

12-18 层的平行坐标图

第 18 至 24 层

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

18-24 层的平行坐标图

精确度> 0.8 的运行的第 0-24 层

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对于精度> 0.8 的运行,0-24 层的平行坐标图

虽然这个图确实有点嘈杂,但我们仍然可以看到,较好的模型(浅绿色)在 24 层的前半部分确实具有较低的学习率*,而在另一半部分具有较高的学习率。*

精确度> 0.8 的运行的分类层

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

准确度> 0.8 的运行分类层的平行坐标图

**分类层的平行坐标图似乎比变压器模型层的图更嘈杂。这可能表明分类层相对更健壮,并且只要学习率足够高以避免陷入局部最小值,就可以学习良好的权重。

最后,让我们看看用从高级扫描中找到的最佳超参数训练的模型将如何在测试集上执行。

要下载包含最佳运行超参数的 CSV 文件,请转到 W&B 仪表板中的扫描表,搜索deep-sweep(最佳运行的名称),然后单击下载按钮(右上角)。创建一个目录sweep_results并将 CSV 文件保存为sweep_results/deep-sweep.csv

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从最佳运行下载超参数值

下面的脚本将训练模型并根据测试集对其进行评估。

deep-sweep.csv提取的超参数值如下所示。

该模型在测试集上的最终精度得分为 0.8913

查看测试集预测的混淆矩阵:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用高级超参数优化训练的模型的混淆矩阵

与从基本超参数优化* vs 敏感默认值(0.8768vs0.8116】)获得的精度增益相比,从高级超参数优化 vs 基本超参数优化(0.8913vs**0.8768】*获得的精度增益要小得多。然而,这仍然是对基本超参数优化的显著改进。

结果

准确(性)

混淆矩阵

总结

  • 超参数优化可用于训练具有显著更好性能的模型。
  • **学习速率训练时期数是训练变压器模型时要考虑的两个最关键的超参数。
  • 通过对模型的不同层使用(并优化)不同的学习速率*,可以进一步提高性能增益。*
  • 在任务复杂且模型难以学习的情况下,高级超参数优化可能会更加出色。
  • 超参数调谐可用于找到临界超参数的良好值范围,然后可用于寻找更好的值。
  • 如果您想阅读更多关于超参数调整和相关算法的内容,这篇文章非常值得一读!

参考文献

[1]詹皮科洛博士、马尼尼博士、达甘博士和多兰博士,2007 年。第三个帕斯卡认识到文本蕴涵的挑战。在ACL-PASCAL 关于文本蕴涵和释义的研讨会会议录*(第 1-9 页)。*

[2]王敬实、亚大·普鲁克萨奇昆、尼基塔·南吉亚、阿曼普里特·辛格、朱利安·迈克尔、菲利克斯·希尔、奥梅尔·利维和塞缪尔·鲍曼 2019。强力胶:通用语言理解系统的一个更棘手的基准。 arXiv 预印本 1905.00537

[3]刘,y .,奥特,m .,戈亚尔,n .,杜,j .,乔希,m .,陈,d .,列维,o .,刘易斯,m .,泽特勒莫耶,l .和斯托扬诺夫,v .,2019。Roberta:稳健优化的 bert 预训练方法。 arXiv 预印本 arXiv:1907.11692

https://docs.wandb.com/sweeps

利用 Scikit-Learn、Scikit-Opt 和 Keras 优化超参数

原文:https://towardsdatascience.com/hyperparameter-optimization-with-scikit-learn-scikit-opt-and-keras-f13367f3e796?source=collection_archive---------10-----------------------

探索使用网格搜索、随机搜索和贝叶斯优化来优化模型超参数的实用方法。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

超参数优化通常是数据科学项目的最后步骤之一。一旦你有了一个有前途的模型的候选名单,你会想要微调它们,使它们在你的特定数据集上表现得更好。

在本文中,我们将介绍三种用于寻找最佳超参数的技术,并举例说明如何在 Scikit-Learn 中的模型上实现这些技术,最后介绍 Keras 中的神经网络。我们将讨论的三种技术如下:

  • 网格搜索
  • 随机搜索
  • 贝叶斯优化

你可以在这里查看 jupyter 笔记本。

网格搜索

一种选择是手动调整超参数,直到找到优化性能指标的超参数值的最佳组合。这将是非常乏味的工作,你可能没有时间探索许多组合。

相反,你应该让 Scikit-Learn 的GridSearchCV为你做这件事。你要做的就是告诉它你要试验哪些超参数,要试验哪些值,它会用交叉验证来评估超参数值的所有可能组合。

让我们来看一个例子,在这个例子中,我们使用GridSearchCV为使用流行的 MNIST 数据集训练的 RandomForestClassifier 搜索超参数值的最佳组合。

为了让您对分类任务的复杂性有所了解,下图显示了 MNIST 数据集中的一些影像:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为了实现GridSearchCV,我们需要定义一些东西。首先是我们想要试验的超参数和我们想要尝试的值。下面我们在一本名为param_grid的字典中对此进行详细说明。

param_grid告诉 Scikit-Learn 评估指定的bootstrapmax_depthmax_featuresmin_samples_leafmin_samples_splitn_estimators超参数的 1 x 2 x 2 x 2 x 2 x 2 = 32 种组合。网格搜索将探索 RandomForestClassifier 的超参数值的 32 种组合,并且它将训练每个模型 5 次(因为我们正在使用五重交叉验证)。也就是说,总而言之,会有 32 x 5 = 160 轮的训练!这可能需要很长时间,但完成后,您可以获得如下超参数的最佳组合:

forest_grid_search.best_params_

由于 n_estimators=350 和 max_depth=10 是评估的最大值,您可能应该尝试用更高的值再次搜索;分数可能会继续提高。

你也可以直接得到最佳估计量:

forest_grid_search.best_estimator_

当然,评估分数也是可用的:

forest_grid_search.best_score_

我们在这里的最好成绩是 94.59%的准确率,这对于这样一个小参数网格来说已经不错了。

随机搜索

当您探索相对较少的组合时,网格搜索方法很好,就像前面的例子一样,但是当超参数空间很大时,通常最好使用RandomizedSearchCV来代替。这个类的使用方式与GridSearchCV类非常相似,但是它不是尝试所有可能的组合,而是通过在每次迭代中为每个超参数选择一个随机值来评估给定数量的随机组合。这种方法有两个主要好处:

  • 如果让随机搜索运行 1000 次迭代,这种方法将为每个超参数探索 1000 个不同的值(而不是网格搜索方法中每个超参数只有几个值)。
  • 只需设置迭代次数,您就可以更好地控制分配给超参数搜索的计算预算。

让我们像以前一样浏览同一个例子,但是使用RandomizedSearchCV。由于我们使用了RandomizedSearchCV,我们可以搜索比使用GridSearchCV更大的参数空间:

同上,我们可以看到探索的最佳超参数:

forest_rand_search.best_params_

也是最好的评估者:

forest_rand_search.best_estimator_

并查看最佳分数:

forest_rand_search.best_score_

我们最好的表现是 96.21%的准确率,比GridSearchCV高出 1.5%。如你所见,RandomizedSearchCV允许我们在相对相同的时间内探索更大的超参数空间,并且通常比GridSearchCV输出更好的结果。

现在,您可以保存这个模型,在测试集上对它进行评估,如果您对它的性能满意,就可以将它部署到生产环境中。使用随机搜索并不太难,对于许多相当简单的问题来说,它工作得很好。

然而,当训练很慢时(例如,对于具有较大数据集的更复杂的问题),这种方法将只探索超参数空间的很小一部分。您可以通过手动协助搜索过程来部分缓解这个问题:首先,使用大范围的超参数值运行快速随机搜索,然后使用以第一次运行中找到的最佳值为中心的较小范围的值运行另一次搜索,以此类推。这种方法有望放大一组好的超参数。然而,这非常耗费时间,而且可能不是对时间的最佳利用。

贝叶斯优化

幸运的是,有许多技术可以比随机更有效地探索搜索空间。他们的核心思想很简单:当空间的一个区域被证明是好的,它应该被更多地探索。这种技术为您处理“缩放”过程,并在更短的时间内产生更好的解决方案。

其中一种技术叫做贝叶斯优化,我们将使用 Scikit-Optimize(Skopt)https://scikit-optimize.github.io/来执行贝叶斯优化。Skopt 是一个通用优化库,它使用一个类似于GridSearchCV的接口,用它的类BayesSearchCV执行贝叶斯优化。

如果您还没有安装 Skopt,请在您的虚拟环境中运行下面一行代码:

! pip install scikit-optimize

使用 Skopt 的BayesSearchCV进行贝叶斯优化有两个主要区别。首先,在创建你的搜索空间时,你需要把每个超参数的空间做成一个概率分布,而不是使用像GridSearchCV这样的列表。Skopt 通过他们的库 skopt.space 使这一点变得简单,它允许我们导入实数、整数和分类数来创建概率分布。

  • :连续超参数空间。
  • 整数:离散超参数空间。
  • 分类:分类超参数空间。

下面你可以看到使用分类函数和整数函数的例子。对于分类空间,只需在函数中输入一个列表。对于整数空间,输入您希望BayesSearchCV探索的最小值和最大值。

函数on_step允许我们实现一种提前停止的形式,并在每次迭代后打印出分数。在这里,我们指定在每次迭代之后,我们要打印最好的分数,如果最好的分数大于 98%的准确度,就不再需要训练。

就像在 Scikit-Learn 中一样,我们可以查看最佳参数:

forest_bayes_search.best_params_

最好的估计是:

forest_bayes_search.best_estimator_

最好的成绩是:

forest_bayes_search.best_score_

贝叶斯优化让我们在与随机搜索相同的迭代次数下,将准确率提高了整整一个百分点。我希望这能说服你使用GridSearchCVRandomizedSearchCV离开你的舒适区,尝试在你的下一个项目中实现像BayesSearchCV这样的新事物。超参数搜索可能会很繁琐,但是有一些工具可以为您完成这项繁琐的工作。

微调神经网络超参数

神经网络的灵活性也是其主要缺点之一:有许多超参数需要调整。您不仅可以使用任何可以想象的网络架构,而且即使在一个简单的 MLP 中,您也可以更改层数、每层神经元的数量、每层中使用的激活函数的类型、权重初始化逻辑等等。很难知道什么样的超参数组合最适合您的任务。

一种选择是简单地尝试超参数的许多组合,看看哪一个在验证集上效果最好(或者使用 K-fold 交叉验证)。例如,我们可以使用GridSearchCVRandomizedSearchCV来探索超参数空间。为此,我们需要将 Keras 模型包装在模仿常规 Scikit-Learn 分类器的对象中。第一步是在给定一组超参数的情况下,创建一个将构建和编译 Keras 模型的函数:

此函数使用给定的输入形状和给定的隐藏层和神经元数量为多类分类创建一个简单的顺序模型,并使用配置了指定学习速率的 SGD 优化器对其进行编译。

接下来,让我们基于这个build_model()函数创建一个 KerasClassifier:

keras_clf = keras.wrappers.scikit_learn.KerasClassifier(build_model)

KerasClassifier对象是使用build_model()构建的 Keras 模型的一个薄薄的包装器。这将允许我们像使用常规 Scikit-Learn 分类器一样使用这个对象:我们可以使用它的fit()方法训练它,然后使用它的score()方法评估它,并使用它的predict()方法进行预测。

我们不想像这样训练和评估单个模型,我们想训练数百个变体,看看哪一个在验证集上表现最好。由于有许多超参数,最好使用随机搜索而不是网格搜索。让我们尝试探索隐藏层的数量、神经元的数量和学习率:

现在,我们可以像在 Scikit-Learn 中一样访问最佳参数、估计值和分数:

keras_rand_search.best_params_
keras_rand_search.best_score_

我们的准确率又提高了 0.5%!最后一步是观察每个模型在测试集上的表现(见下文)。

结论

超参数调整仍然是一个活跃的研究领域,目前正在产生不同的算法。但是在你的口袋里有基本的算法可以减轻许多寻找最佳超参数的繁琐工作。

请记住,随机搜索几乎总是比网格搜索更可取,除非您需要探索的超参数非常少。如果您在使用更大的数据集时遇到了更复杂的问题,您可能希望求助于一种更有效地探索搜索空间的技术,如贝叶斯优化。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一如既往,非常感谢任何反馈和建设性的批评。

如果您想查看演示幻灯片或 jupyter 笔记本,并在此处查看完整的代码和描述,请随意查看 Github 资源库。

额外资源

[## scikit-optimize:Python-scikit-optimize 0 . 7 . 3 中基于顺序模型的优化…

编辑描述

scikit-optimize.github.io](https://scikit-optimize.github.io/stable/)

这篇文章涵盖了两个不同的能够执行贝叶斯优化的库,绝对值得一看:

[## Optuna vs Hyperopt:应该选择哪个超参数优化库?-海王星,我

思考应该选择哪个库进行超参数优化?使用远视有一段时间了,感觉像…

海王星. ai](https://neptune.ai/blog/optuna-vs-hyperopt) [## 机器学习的贝叶斯超参数优化的概念解释

使用贝叶斯优化的高效超参数调整背后的概念

towardsdatascience.com](/a-conceptual-explanation-of-bayesian-model-based-hyperparameter-optimization-for-machine-learning-b8172278050f)

迭代扫描超参数搜索

原文:https://towardsdatascience.com/hyperparameter-search-with-iterative-sweeps-3799df1a4d45?source=collection_archive---------42-----------------------

如何在深度学习模型上运行有效的超参数搜索,使用来自 Weights & Biases 的特定可视示例

我花了几年时间来复制和优化各种深度学习模型,主要是针对计算机视觉和 NLP,通常有极短的期限。我提炼的超参数搜索的高级策略是有界探索(用更少的变量尝试更大范围的值)和更快的迭代(更多的探索阶段建立在彼此之上)。我希望这个超参数搜索的概述可以帮助你更快地调整深度学习模型,不管你使用的是什么框架或工具。

什么是超参数搜索?

超参数搜索——或调整,或优化——是为学习算法寻找最佳超参数的任务。这种调整可以完全手动完成:运行一个受控实验(保持所有超参数不变,只有一个除外),分析单个值变化的影响,基于此决定接下来要改变哪个超参数,运行下一个实验,并重复。当然,对于卷积或递归神经网络等深度学习算法来说,这将是非常缓慢的:每个实验(超参数值的一个组合)都需要端到端地训练模型。我们可以通过在手动搜索中使用 meta 来使这个过程更易于管理。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个示例在权重和偏差 UI 中扫描工作空间。图片作者。

方法:手动、网格、随机

算法或自动化超参数调优的核心承诺是更明智地选择下一个实验。如果我们无论如何都需要为一系列不同的超参数尝试一系列不同的值,我们如何才能最佳地选择下一个组合——并运行更少的实验,浪费更少的计算资源,甚至更快地获得结果?这方面的标准方法是网格随机和贝叶斯或贝叶斯(尽管您会听到这个领域中其他术语和策略的长尾效应,尤其是基于模型的优化)。网格搜索会尝试所有可能的组合——可以把它想象成一个嵌套的 for 循环,其中实验的总数大约是超参数的数量乘以每个超参数的可能值的数量。如果您的搜索空间很小,并且希望确保找到最佳选项,这将非常有用。随机搜索通常更快,如果你有更大的搜索空间,特别推荐使用随机搜索,因为它会对更大范围的组合进行采样,并比网格搜索更快地给你一种可能性的感觉。但是,不能保证找到最佳组合。

贝叶斯

贝叶斯优化建立了一个概率模型,或有根据的猜测,从您的超参数选择到您的性能的目标测量,通常是验证准确性的函数映射。您正在训练的实际模型的贝叶斯模型基于迄今为止看到的所有值和结果,预测接下来要尝试什么值。该过程旨在平衡探索-利用的权衡,根据预设的目标,尝试它不确定获得关于空间的更多信息的值和它期望接近最优的值。在实践中,贝叶斯优化比网格和随机更快,因为它运行的“坏”实验更少。贝叶斯确实需要目标度量来优化,这可以默认为模型的验证损失。你可以点击阅读关于贝叶斯优化的更详细的介绍。

其他方法的长尾效应

其他方法包括基于梯度的优化,以明确地计算关于某些超参数的梯度,早期停止以避免在没有希望的运行上浪费时间,以及应用于连续的所选超参数集的进化优化。还有基于群体的训练,其中多个独立的过程同时学习超参数值和网络权重。这里有很多选项——包括算法细节和黑盒优化服务——我无法一一介绍。一旦你研究了这些细节和权衡,我会问自己,我是否已经考虑了我正在调优的特定模型和我正在解决的特定问题,并得出结论说我没有其他聪明的办法可以做——我只想用 GPU 来完成这项任务?如果是的话,我会建议使用一些优化,比如贝叶斯,因为这很可能会更快地工作,并去考虑其他事情。但是以我的经验来看,更有趣、更有挑战性、更有回报的超参数调整工作发生在这个阶段之前,我们还没有很好的算法来解决这个问题——这就是为什么我们中的许多人仍然从事机器学习的工作。因此,让我们深入了解这一部分!

超参数编码谱

在您开始尝试不同的超参数之前,您需要决定什么是超参数。在网络的常规参数和超参数之间有一个重要的区别,常规参数如模型权重和偏差,它们本身是学习的,或者在训练过程中反复改进,而超参数在训练过程之外配置,并且通常在其持续时间内是固定的(尽管有些可以是自适应的,如学习速率)。对于给定的网络,这些可以包括训练时期的数量、学习优化器类型、批量大小、权重衰减等等。网络架构本身可能是一个超参数:我是从像 Inception 或 ResNet 这样的知名基础网络开始的吗?相对于微调,我冻结了多少层?如果我正在从头开始设计一个网络,那么层的数量、大小、类型和连接模式,以及卷积中滑动窗口的维度,都可以是超参数。要决定给定的超参数是固定的还是可变的,您可能需要考虑如何提前预测它的影响,以及它将如何影响搜索的整体运行时间和复杂性。

纪元

epochs——或通过整个训练数据的次数——是一个非常好理解的超参数。当我运行重复的实验时,我希望将这个值设置得足够高,以看到明确的改进,但又不要高到在非常缓慢收敛的曲线上浪费时间。我通常尝试 10 次左右,如果我能逃脱的话——只要我能看到损失减少并开始渐近。看到验证损失的改善对于确保模型不仅仅是记忆训练数据是特别重要的。

资料组

你的训练数据的大小,以及你用多少例子来验证你的训练,是另一个被充分探索的超参数。假设您的数据和分割是有代表性的无偏样本,数据集越大,性能越好-当然,每个假设的测试时间也越长。我遵循 80/10/10 分割的传统智慧,在所有训练和调优完成之前保留 10%的数据,以获得模型泛化能力的最佳感觉。在手动模式下,我训练 80%,在每个时期后验证 10%。在实践中,每次 80%的实验训练和 10%的验证对于超参数搜索来说太慢了。我降低了这些要求,将每次分割的 20-50%作为每次实验的标准。我试图将一个实验的运行时间缩短到几分钟。

在每组实验运行之后——它们一起形成一个扫描— ,您可以使用完整的训练和验证集进行测试。希望观察到的模式保持不变,甚至可能略有增加。如果添加更多的数据没有帮助或伤害,我可能会适得其反,可能需要增加每次扫描所用数据的百分比。验证数据在这里尤其棘手,因为小得多的样本可能噪声太大,不具有代表性。一个解决方案是每次随机选择一个验证子集,记住,如果有的话,你正在解决一个更难的问题。

迭代扫描

对于超参数搜索过程来说,这是一个很好的框架:迭代扫描,或者在一个小的子集上重复调优阶段,然后在完整的训练和验证集上进行测试。在每一次扫描中,您可能隐含地决定,哪些超参数在代码中保持固定,哪些将通过改变它们来测试。因此,您的首要选择之一是一次改变多少:如果您对每个可能的设置进行扫描,或者如果您对一个超参数测试了太多的值,您需要等待几天才能得到结果。

可管理的探索

一般的策略是,尤其是在时间紧迫的情况下,从简单的架构或现有的最佳解决方案开始。运行一些手动测试来选择一个好的历元计数和训练/验证大小。尝试对一小组超参数(比如 3-10)进行探索性扫描。开始的超参数越多,这个阶段就越长。对于每个超参数,在更宽的范围内采样更少的值——即使一些运行失败,您也会对搜索空间有更好的感觉。在这一点上,我不会进入非常精确或不寻常的值——常见的默认值是好的,例如,批量大小为 2 的幂,并且每个超参数也不要太多——我可以在后面的扫描中缩小我的关注范围。

调音的第一人选

我发现,探索训练动态——网络学习的快慢——是一个可靠的第一关:在这里,你可以通过落入正确的范围来轻松获胜。例如,通过学习速率和批量大小,我可以只对几个值进行采样,以获得关于网络对该超参数的敏感度的大部分信息。获得正确的学习率数量级:比如说,0.01 比 0.001 比 0.0001,通常比获得 0.0001 比 0.00015 的完美值更有影响力。优化器将与学习速度和批量大小高度相关,但它们也会对收敛产生巨大影响,并且值得探索(例如,Adam 对于许多应用程序来说都很棒,但我见过 SGD 大大优于 Adam 的项目)。

调整的下一个候选对象

一旦我在训练动力学中为更容易的候选者设置了一些范围,我就挑选一些更高级的细节,比如层大小或过滤器的数量。总体网络架构很适合在这里探索,但我会避免一次进行太多的更改或一次尝试太多详细的假设,因为这样会产生更多的案例需要测试。例如,我会构建两个或更多的架构来捕捉我的想法之间的一般差异——比方说,一个常规的 RNN 和一个鸟瞰 RNN,或者一个具有最大与平均池的 CNN,并使用这些作为分类变量。另一种方法是参数化卷积块的数量。但是,如果一个超参数是卷积块的数量,另一个是每个卷积层中的滤波器数量,另一个是最大或平均池,我会遇到组合爆炸,我试图通过将这些扫描限制在紧凑、可管理的迭代来避免这种爆炸。在这一点上,辍学可以很好地测试,但通常是在我已经学得很好之后——当我在探索过程中过早地增加辍学时,我的跑步中有很大一部分根本没有学到很多东西。你可以在这里加入其他细节,比如体重衰减、学习率时间表、训练阶段、冻结层数等等。可能性是无穷无尽的,我的主要建议是,不要试图太快捕捉太多——首先坚持比你可能想要的更简单的扫描,然后看看你能学到什么。

保姆和被完成

你如何判断你的清扫表现如何,何时停止?我经常着迷地刷新我的终端输出,以查看缓慢运行的统计数据。有了像权重&偏差这样的工具,这部分就更令人愉快了,因为我可以看到我的损耗和精度的实时图。尽管如此,这并不是对人类超参数调节能力的有效利用。对于我运行超参数扫描的任何模型,我已经验证了训练和验证损失通常会减少,并且训练和验证准确性(或任何其他性能指标)通常会增加。一旦您调试了代码,并且确定扫描运行正确,并且在某个地方记录了结果,我强烈建议不要刷新它,如果您能够抵制改进指标的诱惑的话。与手动探索模式不同,实验 B 不再以查看实验 a 中的假设如何实现为条件。相反,我们让自动超参数调整为我们工作。假设单次运行可以限制在几分钟内,一个小时或几个小时通常足够进行一次扫描。有了权重&偏差,缩放扫描也很容易。在另一台机器上运行相同的启动命令,管理超参数的下一个选择的逻辑将在两台机器或代理上并行化。这使您可以在尽可能多的 GPU 上运行一次扫描,而没有跟踪哪个实验在哪个机器上的认知开销。

设置约束

提前设定一个限制是有用的,比如我想尝试的实验总数,或者我想花费的计算量或时间,这既是为了效率,也是为了我自己的理智。我已经浪费了比我愿意承认的更多的时间来观看清扫,希望有一个神奇的组合就在眼前。真的没有最优答案——我的启发是这样的,如果结果的模式看起来没有变化或者不会很快产生任何令人惊讶的东西,就停止。在最坏的情况下,如果我已经跑了两倍的时间来获得最后的最佳值,我就会停下来。

了解您的结果

现在进行分析。这一阶段至关重要——深入研究结果,最好以书面形式总结任何模式,尤其是你观察到的关系。例如,降低学习率会增加验证的准确性吗?增加辍学有帮助吗,但只有在至少有三层的情况下?考虑哪些实验会证实或反驳你的观察,以及你下一步想做什么。我做的笔记越具体,我就越容易有意识,未来的自己——更不用说队友或更广泛的观众——就越容易理解过去的自己到底在做什么,为什么。

平行坐标图

可视化所有超参数如何与目标指标交互非常有帮助。重量和偏差平行坐标图是一种特别方便的方法。最右边的一列绘制了一次扫描中每次运行的结果指标(如认证准确度、认证损失)。一条波浪线将该结果与该特定实验的所有相应超参数值联系起来:这些是波浪线与其他每条垂直数字线的交叉点(例如,学习率、批量、辍学率)。因此,每条波浪线代表一个实验,并根据结果进行着色(例如,准确度越低,紫色越多,准确度越高,黄色越多)。这让你一眼就能看出相关性。在下面的示例中,动量的中间值更好,将学习率和动量都设置得较高会导致验证准确度较低。你可以在这里阅读更多关于和互动探索这个图,以及在这个关于在超参数搜索中量化显著性的更长报告中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可视化 138 CNNs 时尚培训-MNIST。图片作者。

参数重要性面板

权重和偏差参数重要性面板使这些视觉相关性更加具体。它在你的扫描过程中运行一个随机森林(即哪些超参数值导致了哪些结果),以计算每个超参数对结果度量的重要性和相关性。额外的好处是,这个指标不一定是您在扫描中试图优化的指标。下面,我展示了在 Fastai 中训练的用于驾驶场景语义分割的 UNet 的平行坐标图和两个参数重要性面板(将每个像素识别为属于汽车、人、自行车、建筑物、人行道等,总共 20 个类别)。我的性能指标是 IOU:所有类的交集/并集平均值,当我的模型的预测区域与地面实况标注完全重叠时,该值最高,当我的预测区域与地面实况不匹配时,该值较低。第一个图清楚地表明,ResNets 是比 Alexnet 更好的编码器来增加 IOU,而学习率的效果是不确定的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

学习速度的影响很难理清。图片作者。

当我参考参数重要性面板关于所有班级的 IOU 时,我发现学习率有很强的负相关性:我应该将学习率设置得更低,以增加平均 IOU。然而,如果我查询相对于人类 IOU 的参数重要性——仅针对人类类别的 IOU——我发现使用 Alexnet 作为编码器要重要得多,如果我的目标是检测人类,这是最佳选择。你可以阅读这份报告了解更多细节:基本上,Alexnet 倾向于预测更大的误报区域,改善了像人类这样的罕见类别的 IOU,但削弱了整体性能。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

相对于总体平均 IOU(左)和仅人类 IOU(右)的超参数重要性。作者图片。

扫过,想象,重复

一旦您分析了您的扫描,记录了您的发现,并制定了下一步的计划,您就可以运行更多的手动测试或尝试另一次扫描。我建议在推荐的方向上扩大窗口(例如,如果较低的学习率增加了验证准确性,则尝试更低的值)或在更有成效的超参数上增加精度(在最佳值附近更紧密地采样)。如果任何超参数设置明显很好,请注意并考虑将它们提升为常量:保持这些已经调好的值不变,也许可以在代码中添加注释来解释原因。另一方面,如果有任何设置由于异常值而破坏了脚本(例如,过大的批处理大小导致 OOM 错误),请缩小未来运行的范围。您还可以添加一些新的超参数来探索,并且您已经准备好重复这个过程了!在 Weights & Biases 中,你甚至可以从现有跑步中开始一次清扫:从你刚刚完成的清扫中标记出一些你最好的跑步,作为你下一次清扫配置的灵感或草稿。创建扫描时会考虑它们,并且在运行下一次扫描时不会重复它们的配置。

我希望这个概述可以帮助您更快地调整深度学习模型,而不管您使用的是什么框架或工具。在高层次上,我推荐有约束的探索(用更少的超参数获得更大范围的值)和尽可能收紧你的反馈回路(更短的实验,更小的扫描,在更多的迭代中完成)。这里有更多资源来开始使用权重&偏差扫描。我很想听听你的意见,我们如何让 W & B 扫描更好地为你的用例服务。

超参数调谐:实用指南和模板

原文:https://towardsdatascience.com/hyperparameter-tuning-a-practical-guide-and-template-b3bf0504f095?source=collection_archive---------18-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

FreeImages.com哈蒙·德夫的照片

Y 你已经煞费苦心地完成了你的探索性数据分析,数据处理和最后😎,该造型了!但是你很快意识到,你有相当多的超参数需要调整,你可能要花上一千年的时间在这个巨大的超参数空间中搜索最优设置。

生命短暂,因此,懒惰的我决定编写不止一个,而是两个代码模板,以自动化和加快机器学习和深度学习模型的超参数调整过程。点击此处获取代码链接(或滚动至底部),但请继续阅读,了解更多关于超参数调整的信息,并理解代码的作用。

超参数调谐的情况有哪些

在我们深入研究这两个代码模板之前,有必要首先列出我们可能面临的超参数调优的背景。

本质上有两种情况:

  1. 试验次数>超参数次数;和
  2. 试验次数

其中每个试验都是对一组超参数的评估。

情况 1 通常(但不总是)适用于机器学习。训练时间不是特别长,因此我们可以进行大量试验来覆盖超参数空间(即,探索超参数的许多可能组合)。面临的挑战是,如果超参数空间很大,我们可能仍然需要大量的试验和很长时间才能达到最佳设置。因此,如果算法能够智能地操纵超参数空间,将有助于加快优化。

然而,在深度学习中,训练时间通常要长得多;可能几天甚至几周。因此,我们没有能力进行多次试验,这就是情况 2。在这种情况下,我们需要通过并行运行许多试验来提高我们的能力,而不是针对全部数量的时期训练所有试验,该算法应该在训练期间尽早淘汰最没有希望的试验候选,以将计算资源重新分配给其他更有希望的试验。

考虑到上述情况,我们现在来看看各种超参数调整算法以及为我们的目的而选择的算法。

超参数调整算法

下表显示了超参数调整算法的高级概述。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们不会详细讨论每一个算法,但是如果你有兴趣了解更多,下面有其他资源的链接供你参考。

网格搜索和随机搜索

网格搜索系统地评估网格中指定的每个超参数组合的模型,而随机搜索从可能参数值的分布中对每个超参数集进行采样。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:伯格斯特拉等人(2012 年)

在上面由 James Bergstra 和 Yoshua Bengio 在他们的 2012 年论文中的著名图表中,我们看到左边的网格搜索和右边的随机搜索,都有九个试验(黑点)和两个参数。每个方块上方的绿色区域显示了通过改变重要参数值的函数增益,每个方块左侧的黄色区域显示了由不重要参数引起的增益。该图说明了随机搜索可能更彻底地探索参数空间,并导致发现更优的设置。

贝叶斯优化(Parzen 估计器树)

虽然随机搜索比网格搜索好,但还是有可能做得更好。

请注意,在超参数空间中,同一区域中的点往往会返回相似的性能。贝叶斯优化利用了这一事实,并以较高的可能性对性能较好的点的区域进行采样。Parzen 估计树(TPE)是采用贝叶斯优化方法的算法之一。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

上图说明了贝叶斯优化搜索超参数空间的方式。假设红色区域是最佳损失发生的地方,每个白色圆圈是一次尝试,数字代表搜索的顺序。最初,超参数搜索类似于随机搜索,但随着贝叶斯优化算法用过去试验提供的信息更新自身,搜索逐渐开始向红色区域移动。这本质上是贝叶斯优化优于随机搜索的直觉。

在 T4 的一篇论文中,作者也是 James Bergstra 等人,TPE 算法被证明能够找到比随机搜索更好的超参数配置。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:伯格斯特拉等人(2013 年)

上图中的灰点表示使用随机搜索的 n 次试验中的最低误差,而绿点是 TPE 算法对于相应的 n 次试验的最低误差。因此,该论文在他们的实验中显示,TPE 通常发现超参数配置,这些配置返回比随机搜索更低的验证错误。

异步连续减半算法(ASHA)

然而,以并行的方式运行贝叶斯优化是很重要的。在深度学习中,模型训练通常需要很长时间,并行计算尤其重要,ASHA 利用了这一点。

为了理解 ASHA 是如何工作的,我们需要介绍两个组件。第一,连续减半算法(SHA ),第二,异步方面。

***【SHA】***逐次减半算法

假设有 64 个超参数配置需要评估,SHA 将以如下方式制定策略。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对于每个梯级,将剩余 1/配置缩减系数

参考上表,SHA 将首先评估所有 64 个超参数配置,每个配置 1 个历元。这 64 项试验的性能将相互比较,试验的前 1/缩减系数将被“提升”。在我们的示例中,我们任意将缩减因子设置为 4,因此 1/4 * 64 = 16 次试验将被“提升”到下一个梯级,在那里将运行另外 3 个时期。在每个下一个梯级进行类似的比较,直到只剩下 1 次试验。

来自 SHA 的关键见解是,我们不需要完全评估全部 64 个时期的所有试验来选择最佳超参数配置。通常情况下,最没有希望的试验可以在几个时期后确定,我们可以提前停止这些试验,将我们的资源重新分配给其他更有希望的试验。

异步算法

不幸的是,由于 SHA 需要等待一个梯级中的所有试验完成后才能继续下一个梯级,因此在存在掉队者(即运行速度比其他试验慢的试验)的情况下,很难实现最佳并行化。并且假设我们有 10 个计算节点,并且每次试验分配一个计算节点,SHA 也将导致越来越多的剩余计算节点没有被利用,因为对于更高的梯级,试验的数量减少(例如,梯级 3 处的 6 个空闲节点)。

因此,ASHA 通过尽可能提升配置来调整 SHA 算法,而不是等待所有试验都在一个梯级中完成。参考上表中的相同示例,ASHA 将每评估 4 次试验,就将一次试验提升至下一级。

根据本文的研究,与其他可以在并行环境中运行的现有算法相比,ASHA 的性能通常不亚于甚至更好。

我从论文中得到的直觉是,ASHA 可能会表现得更好,因为它能够充分利用并行计算来评估给定时间范围内尽可能多的配置。对于其他算法,它们可能无法在掉队的情况下充分利用并行计算。

进化算法

其他类型的算法包括基于进化的算法,如基于群体的训练。欲知详情,请参考 DeepMind 的博文

我们的代码模板

在回顾了关于超参数调优算法的现有文献并回忆了我们的两种情况后,我决定为每种情况使用两个单独的代码模板。

第一个代码模板适合更简单的情况 1,我们不需要并行计算,所以我写了一些可以在 Google Colab 中轻松运行的东西。第二个代码模板将迎合情况 2,利用 Google 云平台进行分布式试验。

在算法方面,第一个代码使用贝叶斯优化,而第二个代码使用 ASHA。

情况 1 的代码模板

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Hyperopt 是一个超参数优化库,实现了贝叶斯优化的 TPE。远视的主要贡献者之一是詹姆斯·伯格斯特拉。

我们的代码模板使用 Hyperopt 库,可以很容易地在 Google Colab 中运行,有两个主要部分。

**1。车型配置探究

在本节中,我们将设置我们想要研究的模型的配置。例如,下面的代码块为 XGBoost 分类器设置超参数空间。

# XGB Classifier parametersmodel_params = {
'learning_rate': hp.choice('xgbc.learning_rate', np.arange(0.05, 0.31, 0.05)),'max_depth': hp.choice('xgbc.max_depth', np.arange(5, 16, 1, dtype=int)),'min_child_weight': hp.choice('xgbc.min_child_weight', np.arange(1, 8, 1, dtype=int)),'colsample_bytree': hp.choice('xgbc.colsample_bytree', np.arange(0.3, 0.8, 0.1)),'subsample': hp.uniform('xgbc.subsample', 0.8, 1),'n_estimators': 100,
}

为了方便起见,我们为 3 个主要模型设置了模板,每个模型都有一个分类器和回归器:

  • XGBoost
  • LightGBM
  • 随机森林

要根据您的目的修改代码模板,只需相应地修改相关的代码块。

2。远视类对象

这一部分包含我们的主要代码。

要执行超参数优化,只需实例化 HyperOpt 类对象并调用 optimize 方法。此外,您还可以通过在 experiment_space 字典中包含其他模型来执行模型搜索。

# set dictionary containing hyperparameter space defined
experiment_space = {'model_type': hp.choice('model_type',[rf_clf_params, xgb_clf_params, lgbm_clf_params])}# Perform optimal model search
param_search = HyperOpt(X, y, cv=5)
param_search.optimize(space=experiment_space, max_evals=2)

例如,在上面的代码中,我们已经将 max_evals 设置为 2,但是您也可以将其设置为其他的试验次数。或者,将其设置为*‘auto’*,让代码搜索最佳设置,直到损失度量在预定义的试验次数内没有改善。

情况 2 的代码模板

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Ray Tune 是一个 Python 库,用于任何规模的超参数调谐,允许我们轻松地执行多节点分布式计算,以同时评估各种超参数配置。

我们的代码参考了 Ray Tune 的 GitHub,由两个文件组成,可以在这里下载

  1. cluster_config_cpu.yml (分布式集群的配置)
  2. tune_cifar10.py (超参数调整脚本)

我们将利用谷歌云进行分布式计算,并以 CIFAR-10 为例。请注意,谷歌云为新客户提供了免费试用

在我们的 CIFAR-10 示例中,我们能够在一个小时内使用 40 个 CPU 评估 100 个配置,而这通常需要一天的时间。所有这些都是在创建谷歌云账户后通过 5 个主要步骤实现的。

1.设置 Google 云端认证

2.启用以下 API:

3.将项目 ID 复制粘贴到 cluster_config_cpu.yml 配置文件中的 project_id

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在配置文件的 project_id 下填写您的项目 ID

4.通过在终端中运行来启动集群:

ray up -y cluster_config_cpu.yml

5.通过在终端中执行以下命令开始超参数调整试验:

ray submit cluster_config_cpu.yml tune_cifar10.py# To trial run scripts, add argument smoke-test
# ray submit cluster_config_cpu.yml tune_cifar10.py --smoke-test

在超参数调整过程中,您将在终端中看到状态更新,如下图所示。每次迭代( iter )后,将为每次试验报告指标( acc,总时间)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在我们的示例中,我们调整了三个超参数:

  • 丢弃层将元素设置为零的概率( dropout_p )
  • 第二全连接层中的节点数( dense2_nodes
  • 第二卷积层输出的通道数(输出通道)

超参数空间可以在脚本顶部的 tune_cifar10.py 中与其他主要配置一起设置。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

要在 tune_cifar10.py 中设置的主要配置

为了使代码适合您的目的,您可能希望修改 ConvNet 类(用于模型架构)和 get_data_loaders 函数(用于数据集加载)。

要设置使用的 cpu 类型和数量,请修改 cluster_config_cpu.yml 中的 head_nodeworker_nodesmax_workers 。或者,要启动 gpu,请参见 cluster_config_gpu.yml

在超参数调优过程结束时,将报告最佳配置,并且可以从 Google 云集群的头节点下载相应的模型检查点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

每个试验的最佳模型将作为 model_xxx.pth 保存在头群集节点的/home/Ubuntu/ray _ results/train model 下的每个试验文件夹中

快速提示:

  • 如果您正在启动大量的 CPU,请确保您的 head 节点是足够强大的机器类型。
  • 默认情况下,Google Cloud 对您可以启动的 CPU 和 GPU 数量有配额限制。但是您可以编辑您的配额

通过上面的插图,我们希望展示如何为机器学习和深度学习模型执行超参数调整。

如果您错过了代码模板链接,它们也在这里:

感谢阅读,我希望代码和文章是有用的。如果您有任何问题或建议,请随时发表评论。

参考

机器学习模型的超参数调整

原文:https://towardsdatascience.com/hyperparameter-tuning-for-machine-learning-models-1b80d783b946?source=collection_archive---------3-----------------------

使用随机搜索、网格搜索和超点优化方法提高机器学习模型的准确性

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由乔·凯恩Unsplash 拍摄

简介

本文介绍了使用 Sci-kit learn 和 HyperOpt 库对机器学习模型的超参数调整进行随机搜索、网格搜索和贝叶斯优化方法的比较和实现。超参数调整至关重要,因为它们控制机器学习模型的整体行为。每个机器学习模型都有不同的可以设置的超参数。

超参数是在学习过程开始之前设置其值的参数。

我将使用来自 Kaggle 的 Titanic 数据集进行比较。本文的目的是探索随机森林模型的性能和计算时间如何随着各种超参数调整方法而变化。毕竟,机器学习就是要在计算时间和模型性能之间找到正确的平衡。

具有默认参数的基线模型:

random_forest = RandomForestClassifier(random_state=1).fit(X_train, y_train)
random_forest.score(X_test,y_test)

当在测试装置上使用时,该模型的精度为 81.56

我们可以使用命令获取用于模型的默认参数。**randomforest.get_params()**

**The default parameters are:** {'bootstrap': True, 'ccp_alpha': 0.0,  'class_weight': None,  'criterion': 'gini',  'max_depth': None,  'max_features': 'auto',  'max_leaf_nodes': None,  'max_samples': None,  'min_impurity_decrease': 0.0,  'min_impurity_split': None,  'min_samples_leaf': 1,  'min_samples_split': 2,  'min_weight_fraction_leaf': 0.0,  'n_estimators': 100,  'n_jobs': None,  'oob_score': False,  'random_state': 1,  'verbose': 0,  'warm_start': False}

如果您不知道这些参数以及它们的使用方法,也不必担心。通常,关于所有参数的信息可以在模型的 Scikit 文档中找到。

随机森林中的一些重要参数:

  1. max_depth: int,default=None 该选项用于选择你希望森林中每棵树的深度。树越深,它就有越多的分支,它就能获取更多的数据信息。
  2. 判据 :{“Gini “,” entropy”},default=" Gini": 衡量每个拆分的质量。“基尼系数”使用基尼系数杂质,而“熵”则根据信息增益进行分割。
  3. max_features: {“auto “,” sqrt “,” log2”},int 或 float,default=" auto": 这表示在寻找最佳分割时,在分割前级别上考虑的特征数量。这提高了模型的性能,因为每个树节点现在都在考虑更多的选项。
  4. min _ samples _ leaf:int 或 float,default=1: 该参数帮助确定在随机森林中的每个决策树节点的末端对其进行拆分所需的最小观察次数。
  5. min_samples_split :
  6. n_estimators : int,default=100: 这可能是最重要的参数。这表示在计算预测值之前,要在随机森林中构建的树的数量。通常,数字越高越好,但是这在计算上更昂贵。

关于其他参数的更多信息可以在随机森林分类器模型文档中找到。

网格搜索

执行超参数调整的一种传统且流行的方法是使用 Scikit learn 的穷举网格搜索。该方法尝试每组超参数的每种可能的组合。使用这种方法,我们可以在参数搜索空间中找到最佳的一组值。这通常使用更多的计算能力,并需要很长时间来运行,因为这种方法需要尝试网格大小中的每个组合。

参数网格大小将是所有参数的乘积。即,对于我们模型中的以下参数,网格大小将是 102453*5 = 12000

parameters ={'max_depth': [10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
     'criterion' : ['gini', 'entropy'],
     'max_features': [0.3,0.5,0.7,0.9],
     'min_samples_leaf': [3,5,7,10,15],
     'min_samples_split': [2,5,10],
     'n_estimators': [50,100,200,400,600]}**from** sklearn.model_selection **import** ParameterGrid
param_size = ParameterGrid(parameters)
len(param_size)**Output:
12000**

使用 sklearn 的GridSearchCV,我们可以搜索我们的网格,然后运行网格搜索。

%%time**from** sklearn.model_selection **import** GridSearchCV
grid_search = RandomForestClassifier()grid_search = GridSearchCV(
    grid_search, 
    parameters, 
    cv=5,
    scoring='accuracy',n_jobs=-1)

grid_result= grid_search.fit(X_train, y_train)
**print**('Best Params: ', grid_result.best_params_)
**print**('Best Score: ', grid_result.best_score_)

输出

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

与基线模型相比,网格搜索 CV 模型的交叉验证分数从 81.56%提高到 84.12%。这是 3.3%的改进。计算时间几乎是 5 小时,这对于这样一个简单的问题是不可行的。

关于实现 Gridsearch 的不同方法的更多信息可以在这里找到。

随机搜索

与 GridCV 相比,RandomizedSearch CV 的主要区别在于,它不是尝试每个可能的组合,而是从网格空间中随机选择超参数样本组合。因为这个原因,不能保证我们会像网格搜索一样找到最好的结果。但是,这种搜索在实践中非常有效,因为计算时间非常少。

计算时间和模型执行主要取决于n_iter值。因为该值指定了模型应该搜索参数的次数。如果这个值很高,就有更好的机会获得更高的精度,但这也带来了更多的计算能力。

我们可以通过使用 sklearn 的库来实现RandomizedSearchCV

%%time
**from** sklearn.model_selection **import** RandomizedSearchCV
random_search=RandomizedSearchCV(estimator = RandomForestClassifier(), param_distributions=parameters,verbose=1, n_jobs=-1,
                            n_iter=200)
random_result = random_search.fit(X_train, y_train)
print('Best Score: ', random_result.best_score_*100)
print('Best Params: ', random_result.best_params_)

输出

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

与基线模型相比,使用随机搜索 CV 模型,我们的交叉验证分数从 81.56%提高到 83.57%。这是 2.5%的改进,比 Grid CV 少 0.8%。但计算时间不到 5 分钟,几乎快了 60 倍。对于大多数简单的问题,这种随机搜索将是超参数调整的最可行的选择。

更多关于实现随机搜索的不同方法的信息可以在这里找到。

使用 HyperOpt 的贝叶斯模型优化

为了在 Hyperopt 中公式化优化问题,我们需要一个目标函数,该函数接受一个输入并返回一个损失以最小化模型。以及一个域空间对于超参数类似于网格搜索,我们要用输入值的范围创建一个参数空间来评估。

函数可以简单到 f(x) = sin(x),也可以复杂到深度神经网络的误差。该模型根据前面的步骤选择超参数。

这个模型的工作过程很简单:

  1. 创建目标函数的替代概率模型。
  2. 找到在代理模型上表现最好的超参数。
  3. 在真实模型上使用这些值来返回目标函数并更新代理模型。
  4. 重复步骤 2 和 3,直到达到最大评估值。

简单来说,如果我们想找到精度最高的超参数。计算精度的函数称为目标函数

%%time
import **numpy** as **np**
from **hyperopt** import **hp**, **tpe**, **fmin**,**STATUS_OK**,**Trials****def** accuracy_model(params):
   clf = RandomForestClassifier(**params)
   **return** cross_val_score(clf, X_train, y_train).mean()param_space = {'max_depth': hp.choice('max_depth', range(10,100)),
'max_features': hp.uniform('max_features', 0.1,1),
'n_estimators': hp.choice('n_estimators', range(50,500)),
'min_samples_leaf': hp.choice('min_samples_leaf',range(3,5)),
'min_samples_split': hp.choice('min_samples_split',range(2,10)),
'criterion': hp.choice('criterion', ["gini", "entropy"])}best = 0
**def** f(params):
    global best
    acc = accuracy_model(params)
    if acc > best:
       best = acc
    **return** {'loss': -acc, 'status': STATUS_OK}Trials = Trials()
best_params = fmin(f, param_space , algo=tpe.suggest,max_evals=500, trials= Trials)**print**('New best:', best, best_params)
**print**(best_params)

输出

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们使用贝叶斯优化的交叉验证交叉为 84.44%,优于随机搜索和网格搜索。计算时间为 20 分钟,考虑到这种方法的性能最好,这是合理的。

使用贝叶斯优化模型的另一个好处是不同于随机搜索或网格搜索;我们可以跟踪用于形成概率模型的所有过去的评估模型,该概率模型将超参数映射到目标函数的得分概率。

关于安装和实现 Hyperopt 库的更多信息可以在这里找到。

结论

超参数调整对于提高机器学习模型的准确性非常有利。在我们的例子中,随机森林模型在预测存活率方面已经很好了,所以使用超参数调整方法在准确性方面没有太大的提高。

总之,使用网格搜索选择最佳超参数可能非常耗时。随机搜索速度快但不可靠。然而,即使这些方法也比贝叶斯优化效率低,因为它们不基于先前的结果选择下一个超参数来评估。由于这个原因,这些方法消耗更多的时间来评估无用的参数。

额外资源

除了随机搜索、网格搜索和贝叶斯优化,还有一些高级方法,如超波段和 BOHB,它们结合了超波段和贝叶斯优化,更适合超参数调整。关于它们的详细解释在 n eptune.ai 的精彩博客中有所涉及,可以在这里找到

完整的数据和代码可以在我的 Github 库中找到。

希望那有用!非常感谢你读到这里。如果你对这篇文章有任何问题,或者想要联系和交谈,请随时在 LinkedIn 上直接给我发消息。我非常乐意和你聊天,并尽我所能提供帮助。

支持向量机的超参数调整— C 和 Gamma 参数

原文:https://towardsdatascience.com/hyperparameter-tuning-for-support-vector-machines-c-and-gamma-parameters-6a5097416167?source=collection_archive---------2-----------------------

理解支持向量机的超参数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Unsplash 上的 Aziz Acharki 拍摄

支持向量机(SVM)是一种广泛使用的监督机器学习算法。它主要用于分类任务,但也适用于回归任务。在这篇文章中,我们将深入探讨支持向量机的两个重要参数:T4 C 和伽马。所以我假设你对算法有一个基本的了解,并关注这些参数。

大多数机器学习和深度学习算法都有一些可以调整的参数,称为超参数。我们需要在训练模型之前设置超参数。超参数在构建稳健而精确的模型时非常关键。它们帮助我们找到偏差和方差之间的平衡,从而防止模型过拟合或欠拟合。为了能够调整超参数,我们需要理解它们的含义以及它们如何改变模型。随机尝试一堆超参数值将是一项单调乏味且永无止境的任务。

我们强调了超参数的重要性。让我们开始讨论 C伽马。SVM 创建了一个决策边界来区分两个或更多的类。如何绘制或确定决策边界是 SVM 算法中最关键的部分。当不同类中的数据点是线性可分的时,就很容易画出决策边界。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

线性可分数据点

然而,真实数据是有噪声的,并且在大多数情况下不是线性可分的。一个标准的 SVM 试图将所有的正面和负面例子(即两个不同的类)分开,不允许任何点被错误分类。这导致过度拟合模型,或者在某些情况下,无法使用标准 SVM 找到决策边界。

考虑以下二维空间中的数据点:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

标准 SVM

标准的 SVM 会使用黑色曲线作为判定边界来区分蓝色和红色等级。然而,这是一个过于具体的分类,很可能以过度拟合而告终。过度拟合的 SVM 在训练集上取得了很高的精度,但在新的、以前未见过的样本上表现不佳。该模型对噪声非常敏感,即使数据点值中非常小的变化也可能改变分类结果。使用这条黑线作为决策边界的 SVM 不适用于该数据集。

为了解决这个问题,1995 年,Cortes 和 Vapnik 提出了“软余量”SVM 的概念,它允许一些例子被错误分类或位于决策边界的错误一侧。软边际 SVM 通常会产生更好通用模型。在我们的示例中,软利润 SVM 的决策边界可能看起来像黑色直线,如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

软利润 SVM

有一些错误的分类点,但我们最终有一个更一般化的模型。当确定决策边界时,软裕度 SVM 试图解决具有以下目标的优化问题:

  • 增加决策边界到类别(或支持向量)的距离
  • 最大化训练集中正确分类的点数

这两个目标之间显然有所取舍。决策边界可能必须非常接近一个特定类,才能正确标记训练集中的所有数据点。然而,在这种情况下,测试数据集的准确性可能会较低,因为决策边界对噪声和独立变量的微小变化过于敏感。另一方面,决策边界可能被放置在尽可能远的每个类,代价是一些错误分类的异常。这种权衡由 c 参数控制。

C 参数为每个错误分类的数据点增加一个惩罚。如果 c 很小,则对误分类点的惩罚也很低,因此以更大数量的误分类为代价选择了具有大余量的决策边界。如果 c 很大,SVM 试图最小化由于高惩罚导致的错误分类的例子的数量,这导致了具有较小裕度的决策边界。对于所有错误分类的例子,惩罚是不同的。它与到决策边界的距离成正比。

在介绍 gamma 参数之前,我们需要先说一下内核的诀窍。在某些情况下,不可线性分离的数据点会使用核函数进行变换,以便它们变得可线性分离。核函数是一种相似性度量。输入是原始特征,输出是新特征空间中的相似性度量。这里的相似性是指接近的程度。将数据点实际转换到高维特征空间是一个代价很高的操作。该算法实际上并不将数据点转换到新的高维特征空间。内核化 SVM 根据高维特征空间中的相似性度量来计算决策边界,而不实际进行变换。我想这就是为什么它也被称为内核把戏的原因。

常用的核函数之一是径向基函数(RBF)。RBF 的 Gamma 参数控制单个训练点的影响距离。低 gamma 值表示较大的相似性半径,这将导致更多的点被组合在一起。对于高 gamma 值,这些点需要彼此非常接近,才能被视为在同一组(或类)中。因此,gamma 值非常大的模型往往会过度拟合。以下可视化更好地解释了这个概念:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第一幅图像代表低伽马值的情况。相似性半径很大,因此彩色区域中的所有点都被认为属于同一类。例如,如果我们有一个点的右下角,它被归类为“绿色”类。另一方面,第二个图像是具有大伽马的情况。对于要分组到同一类中的数据点,它们必须落在紧有界区域中。因此,一个小的噪声可能导致数据点脱离类别。大的伽玛值可能会导致过度拟合。

随着灰度系数的降低,分隔不同类别的区域变得更加一般化。非常大的 gamma 值会导致太特定的类别区域(过度拟合)。

伽马与 C 参数

对于线性核,我们只需要优化 c 参数。然而,如果我们想要使用 RBF 核,则需要同时优化 c 和γ参数。如果γ很大,c 的影响可以忽略不计。如果 gamma 很小,c 会像影响线性模型一样影响模型。c 和γ的典型值如下。然而,根据应用可能存在特定的最佳值:

0.0001

0.1 < c < 100

对于 SVM 来说,记住输入数据需要进行归一化以使要素具有相同的比例和兼容性是非常重要的。

感谢您的阅读。如果您有任何反馈,请告诉我。

超参数调整减少过度拟合— LightGBM

原文:https://towardsdatascience.com/hyperparameter-tuning-to-reduce-overfitting-lightgbm-5eb81a0b464e?source=collection_archive---------7-----------------------

用例子演示

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

安德烈斯·达利蒙提在 Unsplash 上的照片

对大量数据的轻松访问和高计算能力使得设计复杂的机器学习算法成为可能。随着模型复杂性的增加,训练模型所需的数据量也会增加。

数据不是模型性能的唯一因素。复杂模型有许多超参数,需要正确地调整或调整,以便充分利用它们。

例如,XGBoost 和 LightGBM 的性能高度依赖于超参数调优。这就像以每小时 50 英里的速度驾驶法拉利,在不仔细调整超参数的情况下实现这些算法。

在本帖中,我们将实验 LightGBM 的性能如何根据超参数值而变化。重点是有助于推广模型的参数,从而降低过度拟合的风险。

让我们从导入库开始。

import pandas as pd
from sklearn.model_selection import train_test_split
import lightgbm as lgb

数据集包含 60 k 个观测值、99 个数字特征和一个目标变量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者提供)

目标变量包含 9 个值,这使其成为多类分类任务。

我们的重点是超参数调优,因此我们将跳过数据争论部分。下面的代码块将数据集分为训练和测试子集,并将它们转换为适合 LightGBM 的格式。

X = df.drop('target', axis=1)
y = df['target']X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.33, random_state=42)lgb_train = lgb.Dataset(X_train, y_train)
lgb_test = lgb.Dataset(X_test, y_test)

我们将从一组新的基本超参数开始,并逐步引入新的超参数。

params = {
'boosting_type': 'gbdt',
'objective': 'multiclass',
'metric': 'multi_logloss',
'num_class':9
}

我们现在可以训练模型,并根据指定的评估指标查看结果。

gbm = lgb.train(
params,
lgb_train,
num_boost_round=500,
valid_sets=[lgb_train, lgb_test],
early_stopping_rounds=10
)

评价标准是多级测井曲线损失。这是训练集和验证集的结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者提供)

助推轮数设置为 500,但出现了提前停止。如果在指定的回合数内成绩没有提高,early_stopping_rounds 将停止训练。

因为在训练集和验证集的损失之间存在显著的差异,所以该模型似乎高度过度适合训练集。

min_data_in_leaf 参数是一种减少过度拟合的方法。它要求每片叶子都有指定数量的观察值,这样模型才不会变得太具体。

'min_data_in_leaf':300 #added to params dict

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者提供)

验证损失几乎相同,但差异变小,这意味着过度拟合的程度降低。

防止模型过于具体的另一个参数是 feature_fraction ,它表示在每次迭代中随机选择的特征的比率。

'feature_fraction':0.8 #added to params dict

现在模型在每次迭代中使用 80%的特性。这是结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者提供)

过度拟合进一步减少。

Bagging_fraction 允许在每次迭代中使用随机选择的行样本。它类似于 feature_fraction,但用于行。bagging_freq 指定更新所选行的迭代频率。

#added to params dict
'bagging_fraction':0.8,
'bagging_freq':10

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者提供)

训练损失和验证损失之间的差异正在减小,这表明我们在正确的轨道上。

LightGBM 是一种使用 boosting 技术组合决策树的集成方法。单个树的复杂性也是过度拟合的决定因素。它可以通过 max_depth 和 num_leaves 参数来控制。max_depth 决定了一棵树的最大深度,而 num_leaves 限制了一棵树可以拥有的最大叶子数。因为 LightGBM 适应逐叶的树生长,所以一起调整这两个参数很重要。

另一个重要的参数是 learning_rate。较小的学习速率通常更好,但它会导致模型学习更慢。

我们还可以添加一个正则项作为超参数。LightGBM 支持 L1 和 L2 正则化。

#added to params dict
'max_depth':8,
'num_leaves':70,
'learning_rate':0.04

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者提供)

我们进一步降低了训练和验证损失之间的差异,这意味着更少的过度拟合。

迭代次数也是模型训练的一个重要因素。更多的迭代导致模型学习更多,因此模型在一定数量的迭代之后开始过度拟合。

您可能需要花费大量时间来调优超参数。最终,你会创造出你自己的方法或策略来加速调整的过程。

有很多超参数。有些在准确性和速度方面更重要。其中一些主要用于防止过度拟合。

交叉验证也可以用来减少过度拟合。它允许在训练集和验证集中使用每个数据点。

我们只关注减少过度拟合。然而,如果精度或损失不令人满意,消除过拟合没有多大关系。您还可以调整超参数以在一定程度上提高精度。提高模型性能的一些方法有:

  • 特征工程
  • 特征抽出
  • 集成多个模型

感谢您的阅读。如果您有任何反馈,请告诉我。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值