深度学习中的超参数调整技术
设置超参数的过程需要专业知识和大量的反复试验。没有简单易行的方法来设置超参数,特别是学习率、批量、动量和重量衰减。
深度学习模型充满了超参数,在如此高维的空间中找到这些参数的最佳配置不是一个微不足道的挑战。
在讨论寻找最优超参数的方法之前,让我们先了解这些超参数:学习率、批量、动量、权重衰减。这些超参数充当旋钮,可以在模型训练期间调整。为了让我们的模型提供最佳结果,我们需要找到这些超参数的最佳值。
梯度下降
梯度下降是一种常用于训练机器学习算法的优化技术。训练 ML 算法的主要目的是调整权重*w*
以最小化损失或成本。这个成本是我们的模型做得有多好的度量,我们用*J(w)*
来表示这个成本。因此,通过最小化成本函数,我们可以找到产生最佳模型性能的最佳参数[1]。
回归问题的典型损失函数图是碗形的,如下所示。
在梯度下降算法中,我们从随机模型参数开始,计算每次学习迭代的误差,不断更新模型参数,以更接近产生最小成本的值。详情请参考我的帖子。梯度下降算法将梯度(斜率)乘以一个称为学习速率(或步长)的标量,以确定下一个点。此参数说明了在渐变方向上移动权重的距离。
如果我们将dw
和db
表示为梯度,以更新梯度下降算法的参数W
和b
,如下所示:
如果学习率小,那么训练更可靠,但是它将花费大量时间,因为向损失函数的最小值的步骤很小。
如果学习率很高,那么训练可能不收敛,甚至发散。重量变化可能如此之大,以至于优化器超过了最小值,使损失更严重。因此,我们的目标是找到能够快速找到最小损失的最优学习速率。
对于更一般的模型,您可以将梯度下降想象为一个球在山谷中滚动。我们希望它坐落在大山的最深处,然而,很容易看出事情可能会出错。
根据球开始滚动的位置,它可能会停在谷底。但不是在最低的一个。这被称为局部最小值。我们初始化模型权重的方式可能导致它停留在局部最小值。为了避免这种情况,我们用随机分布的值初始化权重向量。
我们可以用二维表示损失面,如下所示:
红点是全局最小值,我们想要到达那个点。使用梯度下降,更新将如下所示:
随着梯度下降的每一次迭代,我们随着上下振荡向局部最优移动。如果我们使用更大的学习率,那么垂直振荡将具有更高的幅度。所以,这种垂直振荡减缓了我们的梯度下降,并阻止我们使用大得多的学习率。此外,学习率太小会使梯度下降更慢。
我们希望在垂直方向上进行较慢的学习,在水平方向上进行较快的学习,这将帮助我们更快地达到全局最小值。
为了帮助我们实现这一点,我们使用梯度下降与动量【2】。
我们从梯度下降开始:
在动量项中,我们采用 dw 和 db 的指数加权平均值,而不是对每个历元独立使用 dw 和 db。
其中,β是另一个称为动量的超参数,范围从 0 到 1。它设置以前值的平均值和当前值之间的权重,以计算新的加权平均值。
在计算指数加权平均值后,我们将更新我们的参数。
通过使用 dw 和 db 的指数加权平均值,我们倾向于使垂直方向上的振荡趋于零。然而,在水平方向上,所有的导数都指向水平方向的右边,所以水平方向上的平均值仍然很大。它允许我们的算法采取更直接的路径走向局部最优,并抑制垂直振荡。由于这个原因,该算法将通过几次迭代而在局部最优处结束。
要直观地了解这是如何工作的,可以考虑一个球滚下山的例子——vᵈʷ和 Vᵈᵇ为球提供了速度,使它运动得更快。我们不希望我们的球加速太快,以至于错过了全局最小值,因此β作为摩擦力。
梯度下降有三种方式:
批量梯度下降:
- 一次所有示例:在每次迭代中使用所有训练实例来更新模型参数。
- 随着误差梯度的精确估计而缓慢收敛。
随机梯度下降(SGD):
- 一次一个例子:在每次迭代中仅使用单个训练实例更新参数。训练实例通常是随机选择的。
- 在误差梯度的噪声估计下快速收敛。
小批量梯度下降:
- 一次 b 个样本:小批量梯度下降不是使用所有的样本,而是将训练集分成更小的规模,称为批量,用“b”表示。因此,小批量“b”用于在每次迭代中更新模型参数。
小批量梯度下降寻求在随机梯度下降的鲁棒性和批量梯度下降的效率之间找到平衡。
小批量梯度下降是深度学习领域中最常见的梯度下降实现。Mini-batch 的缺点是它为学习算法增加了一个额外的超参数“批量大小”或“b”。
寻找最佳配置的方法:网格搜索和随机搜索
网格搜索
在网格搜索[3]中,我们尝试了每个可能的参数配置。
步骤:
- 在 n 维上定义一个网格,每个网格映射一个超参数。例如 n = (learning_rate,,batch_size)
- 对于每个维度,定义可能值的范围:例如,batch_size = [4,8,16,32],learning_rate =[0.1,0.01,0.0001]
- 搜索所有可能的配置,并等待结果以建立最佳配置:例如 C1 = (0.1,4) - > acc = 92%, C2 = (0.01,4) - > acc = 92.3%,等等
正如我们看到的,维度越多,搜索的时间复杂度就越高。当维度小于或等于 4 时,通常使用这种方法。虽然它保证最终找到最佳配置,但它仍然不是首选。相反,最好使用随机搜索
随机搜索
随机搜索[4]在步骤 1 中进行随机搜索,从配置空间中随机选取一个点。它如何更好地工作的直觉是,我们可以通过随机搜索更广泛地探索超参数空间(特别是对于更重要的变量)。这将帮助我们在更少的迭代中找到最佳配置。例如,请参见下图:
在网格布局中,很容易注意到,即使我们训练了 9 个(n=3)模型,每个变量也只使用了 3 个值。然而,在随机布局中,我们不太可能多次选择相同的变量。最后,使用第二种方法,我们将为每个变量使用 9 个不同的值来训练 9 个模型。关于网格 vs 随机的详细分析,请参考这篇论文。
即使随机搜索比网格搜索执行得更好,这两种方法仍然计算量大且耗时。2018 年,Leslie N. Smith 在其经典的 论文 **中,就确定最优超参数的各种方法发表了详细的报告。**我们将快速浏览 Smith 建议的方法【5】。该方法基于通过检查训练的测试/验证损失来寻找欠拟合和过拟合的线索,从而找到欠拟合和过拟合之间的平衡,以便努力获得超参数的最优集合。
超参数调整过程是一个走钢丝的过程,目的是在欠适应和过适应之间取得平衡。
欠拟合是指机器学习模型无法减少测试集或训练集的误差。不合适的模型不足以适应数据分布的潜在复杂性。
过度拟合发生在机器学习模型强大到与训练集拟合得太好,泛化误差增大的时候。上图显示了这种欠拟合和过拟合的权衡。
方法
- 通过监控验证/测试损失观察和理解培训期间可用的线索。在培训的早期,通过几个时期的短期运行来调整您的架构和超参数。
- 测试的 欠拟合 或 过拟合 的迹象或训练过程早期的验证损失对于调整超参数是有用的。
Model complexity refers to the capacity of the machine learning model. The figure shows the optimal capacity that falls between underfitting and overfitting.
寻找最佳超参数
学习率
如果学习率(LR)太小,可能会出现过拟合。大的学习率有助于使训练规律化,但是如果学习率太大,训练就会分散。因此,对短期运行进行网格搜索以找到收敛或发散的学习率是可能的,但我们有另一种方法,称为 Leslie N. Smith 的“循环学习率(CLR) ”。
Leslie 的实验表明,在训练期间改变学习速率总体上是有益的,因此建议在一个值范围内循环地改变学习速率,而不是将其设置为固定值。这种学习率政策的本质来自于这样一种观察,即提高学习率可能会产生短期的负面影响,但却能产生长期的有益影响。这一观察引出了让学习率在一个值的范围内变化的想法,而不是采用逐步的、固定的或指数递减的值。也就是说,设置最小和最大边界,学习率在这些边界之间循环变化。
如何估计合理的最小和最大边界值?
**LR 范围测试:**在让学习率在低 LR 值和高 LR 值之间线性增加的同时,运行你的模型几个时期。每当你面对一个新的架构或数据集时,这个测试都是非常有价值的。对于浅 3 层架构,large 是 0.01,而对于 resnet,large 是 3.0,您可以尝试多个最大值。
From my previous post, using fast.ai library to do a LR test
使用 1 周期 LR 策略,通过 LR 范围测试确定最大学习率,最大学习率的十分之一的最小学习率似乎工作良好[6]。
批量
与学习率超参数(其值不影响计算时间)不同,批量大小必须结合训练的执行时间进行检查。批量大小受硬件内存的限制,而学习速率不受限制。Leslie 建议使用适合硬件内存的批处理大小,并允许使用更大的学习速率。
如果您的服务器有多个 GPU,总批处理大小是 GPU 上的批处理大小乘以 GPU 的数量。如果体系结构很小,或者您的硬件允许非常大的批量,那么您可以比较不同批量的性能。此外,请记住,小批量增加正则化,而大批量增加较少,因此在平衡正则化的适当数量时利用这一点。使用较大的批量通常更好,这样可以使用较大的学习速率。
周期性势头
动量和学习率密切相关。最佳学习速率取决于动量,动量取决于学习速率。由于学习率被认为是最重要的超参数,因此动量也很重要。像学习率一样,在不导致训练不稳定的情况下,将动量设置得尽可能大是很有价值的。
寻找学习率和动量组合的步骤
- **使用循环学习率:**最佳训练程序是一个递增的循环学习率和递减的循环动量的组合,前者初始的小学习率允许收敛开始,后者递减的动量允许学习率在训练的早期到中期变大。当学习率增加时,使用递减的循环动量提供了更快的初始收敛,并稳定了训练以允许更大的学习率。
循环动量对于以大动量开始并在学习速率增加时减小动量是有用的,因为它提高了测试精度,并使训练对大学习速率更鲁棒。
下面的图来自我的帖子典型地显示了学习率和动量在一个训练周期(一个时期)中是如何变化的。
left: learning rate one cycle, right:momentum for one cycle
- **使用恒定学习率:如果使用循环学习率,则相反方向的循环动量是有意义的,但是当学习率恒定时,最佳动量是什么?**在这里周期性的动量并不比一个好的常量值强。如果使用恒定的学习速率,那么大的恒定动量(即 0.9-0.99)将表现为伪递增的学习速率,并将加速训练。然而,使用过大的动量值会导致较差的训练结果,这在训练的早期是可见的,并且这可以被快速测试。
对于循环学习率或恒定学习率,一个好的程序是测试 0.9 到 0.99 范围内的动量值,并选择一个表现最佳的值。
重量衰减
权重衰减是正则化的一种形式,它在训练中起着重要的作用,因此需要适当地设置它的值[7]。权重衰减被定义为将每个历元的梯度下降中的每个权重乘以因子λ [0 < λ < 1】。
Leslie 的实验表明,重量衰减不同于学习速率或动量,最佳值应在训练过程中保持不变(即周期性重量衰减没有用)。
如果你不知道重量衰减的合理值,测试 1/10,1/10⁴,1/10⁵和 0。较小的数据集和架构似乎需要较大的权重衰减值,而较大的数据集和较深的架构似乎需要较小的值。我们的假设是,复杂数据提供了自己的正则化,其他正则化应该减少。
如果你用一个恒定的学习速率和使用一个学习速率范围进行搜索,最佳权重衰减是不同的。这符合我们的直觉,因为较大的学习率提供了正则化,所以较小的权重衰减值是最佳的。
主要调查结果摘要
学习率(LR):
- 执行学习率范围测试,以确定“大”学习率。
- 使用 1 循环 LR 策略,最大学习率由 LR 范围测试确定,将最小学习率设置为最大学习率的十分之一。
气势:
- 使用动量值 0.99、0.97、0.95 和 0.9 进行短期测试,以获得动量的最佳值。
- 如果使用 1 周期学习率时间表,最好使用一个循环动量(CM ),它从这个最大动量值开始,并随着学习率的增加而减少到 0.8 或 0.85。
批量:
- 使用尽可能大的批处理大小来适应您的内存,然后比较不同批处理大小的性能。
- 小批量增加正规化,而大批量增加较少,所以利用这一点,同时平衡适当数量的正规化。
- 使用较大的批量通常更好,这样可以使用较大的学习速率。
重量衰减:
- 确定适当震级的网格搜索,但通常不要求超过一个有效数字的精度。
- 更复杂的数据集需要更少的正则化,因此测试更小的权重衰减值,例如 104、105、106、0。
- 浅架构需要更多的正则化,因此测试更大的权重衰减值,如 102、103、104。
感谢您的阅读。
参考资料:
[1]https://www.jeremyjordan.me/gradient-descent/
https://engmrk.com/gradient-descent-with-momentum/
[3]https://blog . Floyd hub . com/guide-to-hyperparameters-search-for-deep-learning-models/
[4]http://www . jmlr . org/papers/volume 13/bergstra 12a/bergstra 12a . pdf
https://arxiv.org/pdf/1803.09820.pdf
[6]https://arxiv.org/pdf/1506.01186.pdf
[7]https://papers . nips . cc/paper/563-a-simple-weight-decay-can-improve-generalization . pdf
其他参考文献
利用随机网格搜索的超参数调谐
为什么随机网格搜索更好,如何使用它?
Jewel Changi Singapore — beautiful isn’t it?
随机网格搜索在为任何机器学习模型寻找接近最优的超参数时非常有用。
经验法则:无论网格大小如何,60 次迭代,95%的时间,可以找到最好的 5%的参数集。
什么是网格搜索?
网格搜索是一种寻找最优参数集的残酷搜索算法。
让我们假设我们正在构建一个二元随机森林分类模型,并将使用 AUC 来评估它。在所有的数据处理和特征工程之后,我们需要调整参数以达到最大的精度。
经过一些初步分析后,我们决定从数值范围中选择参数,例如:
Example: parameter grid
这是一个参数网格,由所有可能的参数组合组成。36 (233*2)组潜在的参数可以从这个网格中提取。
**网格搜索将计算每组参数的准确度分数,并选择产生最佳结果的一个。**在下面的例子中,网格搜索将输出集合 4,因为它产生最高的 AUC。
Example: AUC score for each parameter set in the grid
为什么网格搜索会失败?
网格搜索保证在网格中找到最佳参数集。然而,随着更多的参数或更多的参数选择添加到网格中,网格的大小呈指数级增长。
使用上面的例子,让我们用 5 个候选参数再调整一个参数“最小杂质减少”,并为所有现有参数添加一个选项。通过稍微扩大搜索区域,网格扩展到 720 (34435)个集合,比原始网格大 20 倍!如果原来的网格搜索需要 20 分钟,这个网格就需要将近 7 个小时才能完成。
因此,当我们调整具有许多参数的复杂模型时,网格搜索在许多情况下不太可行。
随机网格搜索是网格搜索的一个很好的替代品
**随机网格搜索不是穷举搜索,而是从网格中随机抽取一组参数来计算每次迭代的精确度分数。**可以调整迭代次数,所有迭代中的最佳集合将作为输出。
显然,由于控制了迭代次数,随机网格搜索消耗了更少的计算能力。但是,需要多少次迭代才能找到足够好的参数集呢?
**经验法则:**无论网格大小如何,60 次迭代,95%的时间,可以找到最好的 5%的参数集。
简单数学证明:
- 让我们将 n 表示为迭代次数。
- 经过 n 次迭代后,从网格中抽取的最佳 p 组参数中没有一组的概率是(1- p)ⁿ
- 因此,在 n 次迭代之后,从网格中抽取至少一组最佳 p %参数的概率是 1-(1- p)ⁿ
- 如果我们想要有 95%置信度的最好的 5%参数集,解上面的方程,1-(1–5%*)ⁿ=*95%,n ≈ 59
从这个证明中,我们还可以得出结论,推荐的迭代次数与网格大小无关。
随机网格搜索的迭代次数清单
为了方便读者,请参考下表,了解不同置信度和性能阈值的推荐迭代次数
Recommended number of iterations
感谢阅读!
用 Python 解释超几何分布
在数学课上的概率问题中,你需要的概率要么是给你的,要么是以一种简单明了的方式计算出来的。
Photo by Francesco Ungaro on Unsplash
但现实中并非如此。你需要根据情况自己计算概率。这就是概率分布可以发挥作用的地方。
今天,我们将通过以下方式探索超几何概率分布:
- 解释它在什么情况下有用。
- 应用此分布所需的信息。
- 使用 Python 从头开始编写一些计算代码。
- 将我们的代码应用到问题中。
我们什么时候使用超几何分布?
超几何分布是一个离散概率分布。当您想要确定在不替换特定样本量的情况下获得一定数量成功的概率时,可以使用该方法。这类似于二项式分布,但是这一次你不会得到一次成功的概率。应用这种分布的一些示例情况是:
- 扑克中一手 5 张牌中拿到 3 张黑桃的概率。
- 在万智牌一副标准的 60 张牌中,一手牌拿到 4 到 5 张非地牌的概率。
- 从特许学校招生抽签中随机抽取的混合性别组中抽出 60%男生参加新生班的概率。
超几何计算需要什么参数(信息)?
为了计算超几何分布的概率质量函数(也称为单个实例),我们需要:
a)我们从中抽取的项目总数(称为 N)。
b)N 中所需项目的总数(称为 A)。
c)我们将从 N 中抽取的次数(称为 N)。
d)在我们的 n 个项目(称为 x)的抽签中所需项目的数量。
根据教程的不同,这些变量使用不同的字母。我使用了我在下面发布的视频中使用的字母,在那里我最初了解到了超几何分布。
从头开始编写超几何 PMF、CDF 和绘图函数。
回想一下概率质量函数(PMF),它允许我们计算单一情况的概率。在我们的例子中,这是上面 x 的具体值。超几何分布 PMF 如下。
PMF for Hypergeometric Distribution
稍后,我们用其他函数为我们的计算导入numpy
。Matplotlib
将在后面创建我们的情节函数。scipy
中的comb
函数是一个内置函数,用于计算我们的 PMF 中的 3 个组合。我们为需要计算的每个组合创建一个变量,并返回 PMF 的计算结果。
累积分布函数(CDF)是计算 x 的一系列值的总概率的函数。这将允许我们用万智牌游戏解决第二个例子。另一个例子是确定在一手五张牌中最多获得 2 张黑桃的概率(也就是 2 张或更少的黑桃)。
要用最多两个黑桃回答黑桃问题,我们需要下面的 CDF:
对于万智牌游戏场景,我们可以使用上面的函数,但是它需要在 4 点开始,在 5 点结束。
PMF sum of a set of x-values.
幸运的是,使用 Python,我们可以创建一个足够灵活的函数来处理这两个问题。
最后,下面是根据您的情况绘制分布图所需的代码。一些代码和样式基于这个 scipy docs 页面的例子。
请注意,由于我们展示了从 0 到 n 的所有可能性,所以我们不需要在这个函数中为 x 创建一个参数。设置N = 52
、A = 13
和n = 5
,查看 5 手牌的超几何分布。然后,您将获得下图:
Hypergeometric Distribution plot of example 1
将我们的代码应用到问题中。
问题 1
现在来利用我们的函数。为了回答第一个问题,我们在hypergeom_pmf
中使用以下参数,因为我们想要一个单独的实例:
N = 52
因为一副牌里有 52 张牌。
因为一副牌中共有 13 张黑桃。
n = 5
既然我们抽了一手 5 开的牌。
x = 3
因为我们想在第一手牌中抽取 3 张黑桃。
计算hypergeom_pmf(52, 13, 5, 3)
我们得到的概率是 0.08154261704681873,大概是 8.1%。拿到那只手的机会不大。
问题 2
对于第二个问题,我将为您提供一些快速的背景信息。万智牌(简称魔术)是一个可收藏的交易纸牌游戏,玩家使用生物和咒语击败他们的对手。玩家从一副 60 张牌中拿出 7 张牌开始每场游戏。
Image from manaleak.com
一副牌由允许你施放法术的地牌和法术本身(非地牌)组成。根据不同的牌组,你通常希望你的起手牌中有 4-5 张非地牌,而你的牌组中有大约 23 张地牌。
假设以上,我们来计算一下拿到 4 张或者 5 张非地牌的概率。我们将使用带有以下参数的hypergeom_cdf
:
由于一副牌有 60 张牌。
A = 37
因为我们假设我们的 60 副牌中有 23 个地。
n = 7
因为我们将从一手 7 张牌开始。
t = 5
因为这是我们想要的非陆地的最大数量。
min_value = 4
因为这是我们第一手牌中非陆牌的最小数量。
计算hypergeom_cdf(60, 37, 7, 5, 4)
给我们的概率是 0.5884090217751665,大概是 59%。这意味着我们有大约 59%的机会在第一手 7 张牌中抽 4 或 5 张非地牌。还不错。你会如何改变你牌组中的地和法术的数量来增加这种概率?
问题三。
假设你经营一所特许学校,你通过抽签系统录取学生。你有 734 个申请人,其中 321 个是男生,413 个是女生。你只录取随机抽取的前 150 名学生。考虑到你的学校女生比男生多,你希望今年有更多的男生。假设你想知道你的学校录取 90 个男生的几率是多少(150 个中的 60%)。
花几秒钟计算你的答案,然后检查下面的图片。
Image from almadelmar.org
你应该使用hypergeom_pmf
,因为这是一个单实例概率。使用hypergeom_pmf(734, 321, 150, 90)
你应该得到 3.1730164380350626 e-06…少于百分之一…让我们看一下分布图,看看哪里我们有更好的机会。
Hypergeometric distribution of problem 3
看起来如果我们试着得到 65 个男孩,我们会有更好的机会,但是可能性仍然相当低。也许你应该改变你的入学程序…
哈尔滨麻将开局手的问题
现在让你练习一个你可能不熟悉的游戏。麻将是一种中国各地都玩的著名纸牌游戏,但有着相同的获胜条件。它经常是为了钱而玩的,但那不是我玩的方式。我也不鼓励你赌博…
Image from fotolia.com
我们将要讨论的麻将来自中国东北的哈尔滨。它是著名的哈尔滨冰雪节和我姻亲的家乡。
Image from mymodernmet.com
游戏有 3 种花色,编号为 1 到 9,每张牌 4 份。到目前为止总共有 108 张卡片。此外,还有 4 张钟牌(上图中竖立的红色方块),总共 112 张牌。在哈尔滨麻将中,除了获胜的一手牌之外,满足特定条件也是获胜的基础。在你的开局手牌中拿到至少 3 张钟牌,你就涵盖了几乎所有的情况。
问题是如果你不是庄家,你的开局手牌中至少有 3 张中牌的概率是多少?这意味着你的第一手牌将有 13 张。尝试使用提供的正确函数自己计算这个概率。然后把你的答案贴在下面的评论里,我会让你知道你是否回答正确。
额外资源
感谢阅读!要查看本教程的代码,你可以在我的 Github 找到。
如果你想看这里的视频教程,你可以看看下面的视频。这是我用来学习超几何分布的。
你可以在 Linkedin 和 Twitter 上关注或联系我。直接在 j.dejesus22@gmail.com 联系我。如果你喜欢这个,看看我在下面的一个叫做点双列相关的相关概念上的类似文章:
线性回归是确定数据的两个或多个连续特征之间相关性的经典技术…
towardsdatascience.com](/point-biserial-correlation-with-python-f7cd591bd3b1)
如果你喜欢在媒体上阅读,并愿意进一步支持我,你可以使用我的推荐链接注册一个媒体会员。这样做可以用你的会费的一部分在经济上支持我,我将不胜感激。
直到下一次,
约翰·德杰苏斯
Hyperledger 结构:技术概述
我是🇵🇹大学的博士研究员@ Técnico Lisboa,在那里我教授以用户为中心的设计。我是基于 Hyperledger 结构的访问控制项目的导师,该项目由 Hyperledger 和 Linux 基金会支持和资助。
Fabric 允许网络中有不同类型的参与者,这有助于链代码的分布式执行的执行-命令-验证范例。
作者认为,相对于区块链常见的订单执行模式,如比特币和以太坊,执行订单验证具有优势。
背书对等体(背书者)执行(背书)智能合同(链码)并向区块链客户端返回已提交交易的验证输出,其中包含背书对等体的签名。这个过程允许并行执行,并处理非确定性代码。
链码是结构网络中的中心元素,因为它规定了成员参与者要遵守的规则。它在 Docker 容器中运行,因此与共享分类帐隔离。
有两种类型的链码:应用链码,其执行应用逻辑并使用 gRPC 消息和系统链码与对等体通信,在配置信道上运行并用于存储生态系统的配置,例如 MSP 的定义、osn 的网络地址、关于共识的配置、订购服务参数以及关于如何改变信道配置的规则。
来源:https://hyperledger-fabric . readthedocs . io/en/release-1.4/peers/peers . html
Chaincode 可以动态部署,并且通常在网络上并发运行。它直接运行在对等体的进程上。配置信道存储 MSP 的定义、osn 的网络地址、关于共识的配置、订购服务参数以及关于如何调整信道配置的规则。
由于世界状态提供了对这些键的最新值的直接访问,Chaincode 根据世界状态数据执行事务提议。鉴于此,没有必要遍历整个事务日志并计算其值。
最终,chaincode 的目标是修改共享分类账。每个对等方包含一个分类帐组件,由存储包含事务的块的块存储和对等方事务管理器(PTM)组成。每个渠道都有不同的分类账,因为渠道会强制实施链码和数据隔离。
通道允许参与者在有权可视化交易子集的参与者子集之间建立通信路径。
例如,在同一个网络中,可能存在只能访问某类事务的对等体子集。除了通道之外,Fabric 还支持私有数据,这允许通道上组织的一个定义子集将他们的数据与其他数据隔离开来。
具体来说,具有权限的组织可以签署、提交或查询私有数据,这些数据在逻辑上与渠道分类帐数据分离。如果出现争议,可以共享私人数据。
为了进一步保护隐私,私有数据的散列通过订购者,而不是数据本身。它是点对点传播,而不是通过块。
当交易数据必须对订购服务节点保密时,使用私有数据集合而不是通道是一种解决方案。
来源:https://vital flux . com/hyperledger-fabric-channels-private-区块链-deep-dive/
Fabric 引入了混合复制模型,结合了主动和被动复制(primarybackup-replication,移植到不可信环境)。
对于主动复制或状态机复制,分类帐状态仅反映经过验证并就其排序达成一致的交易。当签署者将事务处理的结果发送到提交节点时,发生被动复制。
Fabric 包含三个围绕数据的主要元素:世界状态,对应于分布式分类帐的版本化的键值存储;交易日志,存储所有交易的历史(PTM);NoSQL 数据库,如 CouchDB,存储世界状态。
可以限制用户查看和编辑特定字段的权限,并且只授予只读权限。与 LevelDB 相比,CouchDB 支持针对整个区块链数据的复杂数据查询,这使得它成为数据分析和审计的合适解决方案。LevelDB 是存储世界状态的另一个内置选项。
这是一个简单、快速的键值存储库,提供了从字符串键到字符串值的有序映射。
虽然 Fabric 没有内置的加密货币,但可以使用 chaincode 创建一个底层令牌,它可以表示执行特定操作的资产或权利。
这些资产可以通过交易在网络参与者之间进行交换。
参与者可以拥有网络上的一个或多个对等节点。Fabric 在其模型上定义了几种对等节点:
- 提交同行。每个对等体维护分类帐当前状态的当前快照,作为键值的存储。这样的对等体不能调用链码函数。
- 背书人同行。背书者对等方安装了链码。当他们收到一个事务提议时,他们在隔离的容器上模拟事务执行。基于该模拟,这些对等方准备一个交易提议,然后发送给订购方对等方。背书者对等体的存在避免了所有对等体顺序执行事务。
- 订购者同行。订购者接收经认可的交易,并将它们组装成块。在对交易进行分组之后,订购者通过将这样的块传播给提交对等方来确保一致性,在提交对等方处,它们被验证,然后被提交到共享分类帐。订购方对等方记录有效和无效交易,而其他对等方只包含有效交易。
此外,Fabric 定义了锚点对等体和领导者对等体。
锚节点在来自其组织的节点和来自外部组织的节点之间充当中介。
领导节点负责将交易从订购者分发到提交节点。
结构解决方案的架构。
为了达成共识,并且假定在超分类帐结构网络中存在部分信任的假设,结构使用基于许可投票的方案,这实现了低延迟。
背书策略定义了对等体使用的基于投票的方案,并因此定义了每个对等体关于交易有效性的权重。
遵循执行-订单-验证范例的事务流程如下:
- 交易建议。代表组织的区块链客户创建一份交易提案,并将其发送给背书政策中定义的背书伙伴。该提议包含关于提议者的身份、交易有效载荷、随机数和交易标识符的信息。
- 执行(背书):背书是模拟交易。背书者产生一个包含密钥及其修改值的写集合和一个读集合。背书对等体还检查事务执行的正确性。背书作为建议响应发送,包含写集合、读集合、交易 ID、背书人 ID 和背书人签名。当客户机收集到足够多的背书(需要有相同的执行结果)时,它创建事务并将其发送给订购服务。认可阶段消除了任何最终的不确定性。
- 订单:背书后是订货环节,由订货人完成。订购服务检查提交交易建议的区块链客户在给定频道上是否具有适当的许可(广播和接收许可)。排序产生包含每个通道中有序序列的已签署事务的块。排序允许网络达成共识。定序器将事务的输出广播给所有对等体。
- 验证。首先,每个对等体通过检查交易是否遵循通信方背书策略来验证接收到的交易。之后,将按顺序对块中的所有事务运行读写冲突检查。对于每笔交易,它会将读取集中的密钥版本与当前分类帐中的密钥版本进行比较。它检查值是否相同。在它们不匹配的情况下,对等体丢弃该事务。最后,分类帐被更新,其中分类帐将创建的块附加到其头部。分类帐附加有效性检查的结果,包括无效的事务处理。
- 伊里·安德罗拉基、亚科夫·马涅维奇、斯里尼瓦桑·穆拉利哈兰、切特·穆尔蒂、阮平、马尼什·塞西、加里·辛格、基思·史密斯、亚历山德罗·索尼奥蒂、金苏拉·斯塔萨科普卢等。Hyperledger Fabric:许可区块链的分布式操作系统。2018 年第十三届欧洲系统会议记录
- 超级账本基金会。Hyperledger 结构文档,2018 年。https://hyperledger-fabric.readthedocs.io/en/release-1.4.网址访问时间 2018-11-12
- 马尔科·武科里奇。重新思考被允许的区块链。在 2017 年 ACM 区块链、加密货币和合同研讨会会议录第 3-7 页
超净:强大的,间接的神经网络进化
超净:强大的,间接的神经网络进化
扩展神经进化
上周,我写了一篇关于 NEAT(增强拓扑的神经进化)的文章,我们讨论了许多围绕算法的很酷的事情。我们还简要地谈到了这种旧算法可能会如何影响我们今天的网络构建方法,暗示了神经网络不需要完全手工构建的事实。
今天,我们将进入一种不同的神经进化方法,一种叫做超净的 NEAT 的扩展。你可能还记得,NEAT 的网络结构有一个直接的编码。这使得网络可以更直观地进化,一个节点接一个节点,一个连接接一个连接。HyperNEAT 放弃了这个想法,因为为了进化出像大脑(有数十亿个神经元)这样的网络,人们需要一种更快的方式来进化这种结构。
HyperNEAT 是一个概念上复杂得多的算法(至少在我看来),甚至我也在努力理解它如何工作的具体细节。今天,我们将深入了解并探索该算法的一些组件,以便我们可以更好地理解是什么使它如此强大,并在这个深度学习的时代对未来的扩展进行推理。
超净
动机
在深入研究论文和算法之前,我认为值得探索一下 HyperNEAT 背后的动机。
论文全称是“一种用于进化大规模神经网络的基于超立方体的间接编码”,相当拗口!但是,我们已经可以看到两个要点。这是一种基于超立方体的间接编码。我们稍后将讨论超立方体部分,但是我们已经知道这是从直接编码到间接编码的转变(参见我在 NEAT 上的上一篇博客,了解两者之间一些差异的更详细描述)。此外,我们还得到了它背后的主要原因:进化大型神经网络!
不仅如此,这种算法的创造者强调,如果人们观察大脑,他们会看到一个具有数十亿节点和数万亿连接的“网络”。他们看到了一个使用重复结构的网络,重复使用同一基因的图谱多次生成相同的物理结构。他们还强调,人类大脑的构造方式是为了利用世界的物理属性:对称性(拥有结构的镜子,例如两只眼睛用于输入)和局部性(结构中的节点影响它们的连接和功能)。
相比之下,我们所知道的神经网络,要么是通过进化过程建立的,要么是手工构建和训练的。这些属性中的任何一个都成立吗?当然,如果我们强迫网络具有对称性和局部性,也许…然而,即使这样,采取一个密集的前馈网络,其中一层中的所有节点都连接到下一层中的所有节点!当观察由普通算法构建的网络时?它们往往是无组织的、零星的,没有表现出任何这些良好的规律性。
以超整齐的方式进入!通过一种被称为连接性组合模式产生网络(CPPNs)的间接编码,HyperNEAT 试图利用几何属性来产生非常大的神经网络,这些网络具有我们可能希望在我们的进化网络中看到的良好特征。
什么是组合模式生产网络?
在前一篇文章中,我们讨论了编码,今天我们将深入探讨用于 HyperNEAT 的间接编码。现在,间接编码比你想象的要普遍得多。其实你自己内心也有一个!
DNA 是一种间接编码,因为表型结果(我们实际看到的)比基因型含量(DNA 中的基因)大几个数量级。如果你观察人类基因组,我们会说它有大约 30,000 个基因,编码大约 30 亿个氨基酸。大脑有 3 万亿个连接。很明显,这里面有间接的东西!
从生物学的思想中借鉴来的是一种叫做发展编码的编码方案。这是一个想法,所有的基因应该能够在发育过程中的任何时间点和在个体的任何位置重复使用。组合模式产生网络(CPPNs)是这一概念的抽象,已经表明能够在笛卡尔空间中创建重复结构的模式。请点击此处查看使用 CPPNs 生产的一些结构:
纯 CPPNs
表型可以描述为 n 维的函数,其中 n 是表型性状的数量。我们所看到的是从遗传编码到展示特征的某种转化的结果。通过组合简单的函数,复杂的模式实际上可以很容易地表示出来。像对称、重复、不对称和变异这样的东西,都很容易脱离这样的编码结构,这取决于所产生的网络类型。
我们将更深入地了解 CPPNs 在这种情况下的具体用法,但希望这能让您大致了解它们在间接编码环境中的重要性。
系在整洁的
在 HyperNEAT 中,一堆熟悉的属性重新出现在原始的 NEAT 纸上。随着时间的推移,像复杂化这样的事情是很重要的(我们将从简单开始,如果需要的话,逐渐变得复杂)。将使用历史标记,以便我们可以正确地排列任何类型的交叉编码。还将使用统一的起始群体,以便从一开始就没有通配符、不兼容的网络。
这篇文章和以前的文章在整洁程度上的主要区别是什么?HyperNEAT 没有使用 NEAT 算法直接进化神经网络,而是使用 NEAT 来进化 CPPNs。这意味着更多的“激活”函数被用于 CPPNs,因为像高斯函数产生对称性,三角函数有助于结构的重复。
该算法
既然我们已经讨论了什么是 CPPN,并且我们使用 NEAT 算法来进化和调整它们,这就引出了一个问题:在整个 HyperNEAT 环境中,这些算法实际上是如何使用的?
首先,我们需要引入基底的概念。在超净的范围内,基底仅仅是节点的几何排序。最简单的例子可能是平面或网格,其中每个离散的(x,y)点是一个节点。一个连接的 CPPN 实际上会取其中的两个点,并计算这两个节点之间的权重。我们可以把它想成下面的等式:
CPPN(x1, y1, x2, y2) = w
其中 CPPN 是一种进化的 CPPN,就像我们在前面章节中讨论的那样。我们可以看到,这样做时,每个节点之间实际上都有某种权重连接(甚至考虑到循环连接)。连接可以是正的,也可以是负的,还可以定义一个最小权重值,以便任何低于该阈值的输出都不会导致连接。
节点的几何布局必须在任何 CPPN 发展之前指定。因此,随着 CPPN 的发展,实际的连接权重和网络拓扑将导致几何模式(所有输入都基于节点的位置)。
在节点排列在某种二维平面或网格上的情况下,CPPN 是四维的函数,因此我们可以说它是在四维超立方体上发展的。这就是我们得到报纸名字的地方!
生产模式的规律性
我们之前提到的所有规则都很容易从这样的编码中脱离出来。对称可以通过在 x1 和 x2 上使用对称函数来实现。这可以是一个类似高斯函数的函数。当对称用于像 x 和 y 这样的事物时,可能会出现不完全对称,但只是相对于一个轴。
就像我们之前提到的,正弦、余弦等周期性函数也会重复。和对称性一样,通过在衬底的非重复方面引入周期性函数,可以引入相对于重复的变化。因此,所有四个主要的规律都可以从这个编码中发展出来。
衬底配置
从上面你可能已经猜到基板的配置是至关重要的。这很有道理。在生物学中,事物的结构与其功能紧密相连。因此,在我们自己的演进模式中,我们的节点结构与特定任务上可能看到的功能和性能紧密相连。
在这里,我们可以看到原始论文中特别概述的几种基板配置:
我认为查看三维立方体的配置非常重要,并注意它如何简单地将 CPPN 方程从四维调整为六维:
CPPN(x1, y1, z1, x2, y2, z2) = w
此外,通过只允许一半上的节点连接到另一半,网格可以扩展到三明治配置。这很容易被视为输入/输出配置!该论文的作者实际上使用这种配置来在输入半部上接收视觉激活,并使用它来激活输出半部上的某些节点。
圆形布局也很有趣,因为几何图形不必是配置的网格。可以使用放射状的几何图形来代替,允许从圆形所代表的独特几何图形中产生有趣的行为属性。
输入输出布局
输入和输出在 CPPNs 发展之前就已经设计好了。然而,与传统的神经网络不同,我们的超净算法知道输入和输出的几何形状,并可以学习利用和接受它的规律。通过 HyperNEAT 接收的这些额外信息,可以很容易地利用输入和输出的局部性和重复性。
基底分辨率
HyperNEAT 的另一个强大而独特的特性是能够上下缩放承印物的分辨率。那是什么意思?好吧,假设你根据一定大小的图像进化出一个超整洁的网络。在该尺寸下表现良好的基础几何图形在缩放到新尺寸时会产生相同的图案。除此之外,不需要额外的训练。它只是缩放到另一个尺寸!
算法综述
我认为有了这些关于这个算法如何工作的信息,总结一下它的步骤是值得的。
- 1.选择基板配置(节点布局和输入/输出位置)
- 2.创建一个统一的、最小的连接性 CPPNs 初始群体
- 3.重复直到解决:
- 4.对于每个 CPPN
- (a)使用 CPPN 生成神经网络的连接
- (b)评估神经网络的性能
- 5.使用 NEAT 算法再现 CPPNs
结论
我们做到了!这就是超净算法。如果你希望探索更多的细节,或者希望看看他们用该算法做的一些实验的性能,我鼓励你看看这篇论文(我特别喜欢他们的食物收集机器人实验)。
这对未来有什么影响?这也是我最近一直在思考的事情。今天,从 HyperNEAT 到训练传统的深度网络有联系吗?这是一种更好的训练深度网络的方法吗?还有另一篇关于进化基质超净的论文,其中实际的基质也在进化,这是我希望在未来探索的一篇论文!但是,在那篇论文中是否隐藏着某种东西,在超净和深度神经网络之间架起了桥梁?只有时间能证明,也只有我们能回答这个问题!
希望这篇文章是有帮助的!如果我错过了什么或者你有问题,让我知道。我自己仍在学习和探索这方面的很多东西,所以我很乐意在这里或在 Twitter 上谈论这个话题。
如果你想读更多我写的东西,也许可以看看:
HyperparameterHunter 3.0 中的特征工程优化
使用超参数猎人自动保存并优化您的特征工程步骤和超参数,使优化更加智能,并确保不会浪费任何实验
Pre-HyperparameterHunter demo of fitting feature engineering into hyperparameter optimization. Photo: Robyn Mackenzie
漫长的等待结束了。超参数猎人 3.0(阿耳忒弥斯)已经到来,增加了对特征工程的支持,并带来了礼物!
- Gift #1) 清晰且可定制的特征工程师语法:你自己的功能列表
- Gift #2) 为自动记录的建筑特色工程工作流程搭建一致的脚手架
- Gift #3) 针对特征工程步骤的优化,以及(明显地)检测过去的实验以启动优化
- 礼物#4) 你的理智和时间:停止跟踪功能工程步骤的 janky 列表,以及它们如何与你的所有其他超参数一起工作
1.特征工程背景
1.1.这是什么?
很多人对特征工程和预处理有不同的定义,那么超参数猎人是如何定义的呢?
我们对“特征工程”有一个非常宽泛的定义,因此它本身和“预处理”之间的界限是模糊的。我们认为“特征工程”是在模型拟合之前应用于数据的任何修改——无论是在实验开始时执行一次,还是在交叉验证的每个折叠中重复执行。不过,从技术上来说, HyperparameterHunter 让你为自己定义“特征工程”的细节,我们很快就会看到。以下是我们的“特征工程”的几个方面:
1) 手动特征创建, 2) 缩放/规范化/标准化,
3) 重新采样(参见我们的 [imblearn](https://github.com/HunterMcGushion/hyperparameter_hunter/blob/master/examples/feature_engineering_examples/imblearn_resampling_example.py)
示例), 4) 目标数据转换, 5) 特征选择/消除, 6) 编码(一键热码,标签等)。)、
7) 插补、 8) 二值化/宁滨/离散化
…还有许多其他东西!
1.2.我为什么要在乎?
这是一个合理的问题,因为特征工程很少成为超参数优化的话题。那么,你为什么要让超参数猎人跟踪特征工程呢?
第一,特征工程很重要。
你几乎总是需要预处理你的数据。这是一个必需的步骤。
— 机器学习掌握
第二,我们通常将特征工程步骤视为超参数——只是我们习惯于手动调整的超参数。
应该用StandardScaler
还是Normalizer
?我将对这两种算法都进行测试,并尽力记住哪一种(如果有的话)最适合每种算法。我应该将日期一次性编码成星期几,还是创建一个二进制的“is_weekend”特性?我在乎月份吗?年份?我应该把 12 个月转换成四季吗?闰年呢??
最终,我们使用的众多特征工程步骤中的每一个都只是我们应该优化的另一个超参数——但我们没有。为什么?
特征工程在普通超参数优化中的缺失实际上有一个很好的原因:很难。这并不完全像在 0.1 和 0.7 之间选择一个值,或者在 NN 层中选择使用 sigmoid 或 ReLU 变换。我们讨论的是参数化和优化一组函数,这些函数需要知道什么并返回什么,所有这些都是为了转换您的宝贵数据。
你有没有把一个脚本扔在一起做你所有的特性工程,然后拖着它到处跑——为了你的整个项目——根据需要随意地添加、删除和修改片段?你并不孤单。在项目结束时,不可能重新创建实验,因为没有为它们执行的清晰、自动的特征工程记录。此外,忽略特征工程使得超参数优化完全不可靠。当然,一定有更好的方法…而且确实有!
2.超参数亨特方法
在我们开始使用 HyperparameterHunter 之前,让我们快速浏览一下我们的数据:SKLearn 的波士顿住房回归数据集。我们将使用“DIS”列作为目标,就像 SKLearn 的目标转换示例一样。该数据集具有可管理的 506 个样本,其中 13 个特征不包括目标。
2.1.基线
因为特征工程的目标是产生更好的模型,所以让我们建立一个基线[CVExperiment](https://hyperparameter-hunter.readthedocs.io/en/latest/api_essentials.html#experiment-execution)
。和往常一样,我们将从建立一个[Environment](https://hyperparameter-hunter.readthedocs.io/en/latest/source/hyperparameter_hunter.html#hyperparameter_hunter.environment.Environment)
开始,以宽泛地定义任务以及如何评估结果。
我们将进行五次分割的交叉验证,我们将只关注中位数绝对误差。
还有,因为我们不是山顶洞人,我们会通过 SKLearn 的train_test_split
告诉[Environment](https://hyperparameter-hunter.readthedocs.io/en/latest/source/hyperparameter_hunter.html#hyperparameter_hunter.environment.Environment)
从train_dataset
预留一个holdout_dataset
。
然后,我们将使用AdaBoostRegressor
和它的默认参数运行一个简单的[CVExperiment](https://hyperparameter-hunter.readthedocs.io/en/latest/api_essentials.html#experiment-execution)
,看看没有华丽的新FeatureEngineer
我们会做些什么。
2.2.定义
已经建立了 0.51 的基线 MAE 用于折叠外预测,让我们看看我们可以采取的几个特征工程步骤来消除它。
2.2.A .手动特征创建 因为我们很有创造力,我们喜欢从特征工程中获得乐趣,所以我们将首先在输入数据中添加我们自己的特征。让我们制作一个特征,它是其他 13 个特征中的欧几里德范数,或 ℓ2 范数-范数!本着创造性的精神,让我们创造性地将我们的欧几里德范数函数命名为euclidean_norm
:
2.2.B .输入缩放 接下来,我们必须做输入缩放,因为这是最近所有酷孩子都在做的事情。说真的,扩展数据通常是个好主意。
记得fit_transform
用我们的train_inputs
,然后只transform
我们的non_train_inputs
(验证/保持数据)以避免数据泄露。
2.2.C .目标转换 我们的最后一个特征工程步骤将使用 SKLearn 的QuantileTransformer
来均匀分布我们的目标输出,从而分散最频繁出现的值,减少离群值的影响。与我们的输入缩放一样,我们必须注意fit_transform
只是我们的train_targets
,然后是transform
和non_train_targets
。
2.3.我们什么时候到达超参数猎人?
我知道你在想什么,我也在想同样的事情。别拖延了。向我展示如何在超参数搜索中完成所有这些操作。
表白时间:我可能是想偷偷摸摸的过去,没有提到我们上面清晰简洁的函数就是我们做FeatureEngineer
所需要的全部。
但是,Hunter,定义特征工程步骤的语法是如此流畅和符合逻辑!我从来没有想到 HyperparameterHunter 会期望它们采用与我已经使用的完全相同的格式!这太疯狂了。但是怎么做呢???
—你,大概是
亲爱的读者,秘密成分在上面的函数签名中,特别是输入参数。我们称这些函数为 EngineerStep 函数,因为每个函数都生成一个[EngineerStep](https://hyperparameter-hunter.readthedocs.io/en/latest/source/hyperparameter_hunter.html#hyperparameter_hunter.EngineerStep)
。那么,[FeatureEngineer](https://hyperparameter-hunter.readthedocs.io/en/latest/source/hyperparameter_hunter.html#hyperparameter_hunter.FeatureEngineer)
就是一系列EngineerStep
或函数。
回到秘密配料。EngineerStep 函数只是一个普通的函数,您可以在其中进行任何想要的数据处理。您只需要在签名的参数中告诉它您想要的数据。敏锐的读者可能已经注意到了上面 EngineerStep 函数中的模式,但是这里有一个方便的公式来记住有效的 EngineerStep 函数参数。
扣上。这个数学很高级,但是不要担心;我是专业的…
只需从第一组中取出一个字符串,将第二组中的一个字符串粘在上面,就得到一个有效的 EngineerStep 函数参数。另一个重要的部分是函数返回什么。幸运的是,这更容易记住。返回签名参数的新值。你也可以选择返回一个转换器来执行反向的目标转换,就像上面我们对quantile_transform
所做的那样。但是等等!还有呢!
我们还有两个别名来组合数据,以便于处理,我们已经在上面的函数中使用过了!让我们更新高度复杂和微妙的公式,添加额外的 EngineerStep 函数参数别名:
正如新参数的名称所暗示的,“all _ inputs”/“all _ targets”为您提供了一个包含所有数据集输入/目标的大数据框架。“non_train_inputs”和“non_train_targets”是相似的,只是它们省略了所有的训练数据。每个公式下面的注释提醒我们“test_inputs”没有 targets 对应的参数,因为我们没有通过设计来跟踪测试目标。
3.潜入水中
带着我们对如何制作自己的FeatureEngineer
步骤的新认识,让我们开始将FeatureEngineer
与[CVExperiment](https://hyperparameter-hunter.readthedocs.io/en/latest/api_essentials.html#experiment-execution)
结合使用。
我们只需要[CVExperiment](https://hyperparameter-hunter.readthedocs.io/en/latest/source/hyperparameter_hunter.html#hyperparameter_hunter.CVExperiment)
里的feature_engineer
kwarg,或者任何 OptPro 的[forge_experiment](https://hyperparameter-hunter.readthedocs.io/en/latest/source/hyperparameter_hunter.optimization.html#hyperparameter_hunter.optimization.protocol_core.BaseOptPro.forge_experiment)
方法。feature_engineer
可以是一个[FeatureEngineer](https://hyperparameter-hunter.readthedocs.io/en/latest/source/hyperparameter_hunter.html#hyperparameter_hunter.FeatureEngineer)
实例,也可以是一系列[EngineerStep](https://hyperparameter-hunter.readthedocs.io/en/latest/source/hyperparameter_hunter.html#hyperparameter_hunter.EngineerStep)
函数,就像我们上面定义的那样。
3.1.试水:实验
记住,我们的基线实验结束时,OOF 数据的中值绝对误差为 0.51。让我们用几个增强的[FeatureEngineer](https://hyperparameter-hunter.readthedocs.io/en/latest/source/hyperparameter_hunter.html#hyperparameter_hunter.FeatureEngineer)
来测试一下,看看会发生什么…
嗯,那很容易……
让我们来消化一下刚刚发生的事情。三个不同的[CVExperiment](https://hyperparameter-hunter.readthedocs.io/en/latest/api_essentials.html#experiment-execution)
s,每个都有不同的FeatureEngineer
。实验#1 的表现和我们的基线一样好。#2 好一点。然后在#3 中,我们看到误差从 0.51 下降到 0.46。或许我们可以称quantile_transform
为唯一重要的特征工程步骤,然后回家!但是我们怎么能确定呢?
3.2.面向第一:优化
对于跳过“3.1”部分的人。试水”,**我也喜欢危险地生活。**虽然在[CVExperiment](https://hyperparameter-hunter.readthedocs.io/en/latest/api_essentials.html#experiment-execution)
中使用[FeatureEngineer](https://hyperparameter-hunter.readthedocs.io/en/latest/source/hyperparameter_hunter.html#hyperparameter_hunter.FeatureEngineer)
很棒,但是让 HyperparameterHunter 的 OptPros 为我们处理测试所有不同的特征工程步骤组合会更好!
现在,你可能会担心增加优化一定会使特性工程复杂化。你可以放松了,因为我们只需要 OptPros 的[forge_experiment](https://hyperparameter-hunter.readthedocs.io/en/latest/source/hyperparameter_hunter.optimization.html#hyperparameter_hunter.optimization.protocol_core.BaseOptPro.forge_experiment)
方法,这就像初始化一个[CVExperiment](https://hyperparameter-hunter.readthedocs.io/en/latest/api_essentials.html#experiment-execution)
!
要搜索不同[EngineerStep](https://hyperparameter-hunter.readthedocs.io/en/latest/source/hyperparameter_hunter.html#hyperparameter_hunter.EngineerStep)
的空间,只需将步骤放在[Categorical](https://hyperparameter-hunter.readthedocs.io/en/latest/source/hyperparameter_hunter.html#hyperparameter_hunter.Categorical)
中,就像标准的超参数优化一样!Categorical
也有一个optional
kwarg,指的是美国疯狂的科学家都想尝试一个特别有问题的EngineerStep
。如果optional
=真(默认=假),搜索空间不仅包括显式给出的categories
,还包括当前EngineerStep
的完全省略。
在我们进行特性优化之前,我们需要更多的EngineerStep
函数来优化。也许除了standard_scale
,我们还想尝试一些其他的缩放方法,所以让我们定义一下min_max_scale
和normalize
。
这可能是足够的炒作。让我们看看功能优化的实际效果!
注意,在经典的 超参数猎人 时尚中,我们下面的 OptPro 自动计算出我们上面的四个实验与我们的搜索空间兼容,并使用它们作为学习材料来启动优化。
Blue rectangle added around scores of new Experiments conducted by OptPro
每当 OptPros 发现一个实验的分数比我们目前最好的分数高时,它会很有帮助地将分数涂成粉红色,将超参数涂成绿色。通过 16 次实验,我们的 OptPro 才刚刚起步,但quantile_transform
看起来仍然很有希望。此外,似乎搜索一些不同的缩放器可能会有所收获,因为我们新的最佳实验使用了最近添加的min_max_scale
,而不是standard_scale
。
4.回到我们的根源
Some nerd (me) + my friends, who won’t appreciate how sick this burn is
既然这是超参数搜寻者并且搜寻最佳超参数是我们的全部事情,让我们回到我们的根本。我们将把我们的新特性优化技术与一些经典的超参数优化混合在一起,因为没有人想被局部最优所困。
除了添加经典的超参数优化,让我们假装非常确信euclidean_norm
是重要的(尽管它实际上似乎并不重要),并通过移除包围它的Categorical
使它成为必需的EngineerStep
。请注意,这一变化意味着我们的 OptPro 将只从 16 个候选实验中的 8 个保存的实验中学习,因为我们限制了它的搜索空间。
quantile_transform
继续胜过无目标改造,但让我们添加一些真正的竞争与power_transform
。
我们也可以通过从BayesianOptPro
切换到RandomForestOptPro
(或者其他任何 OptPro)来获得第二种意见。纵观上面我们所有的实验,似乎normalize
做得不太好,所以我们把它去掉吧。事实上,假设我们肯定想要standard_scale
或min_max_scale
,那么我们将从组合中去掉normalize
,并在第二个EngineerStep
的末尾删除optional=True
部分。也许我们也有点过于热心地认为euclidean_norm
是件大事,所以让我们再做一次第一个EngineerStep
optional
。当然,我们还需要添加我们的新power_transform
作为我们上一个EngineerStep
的选择。
总之,下面的 OptPro 将修改上面的所有三个EngineerStep
,我们将尝试RandomForestOptPro
来改变节奏。
尽管我们改变了整个FeatureEngineer
的空间,甚至获得了一个新的 OptPro 来运行该节目,但我们从 26 个保存的候选实验中识别出 16 个匹配实验并没有问题,这些实验可用于启动优化。我要说这比从头开始好多了。
更好的是,我们有了一个新的最佳实验,大大提高了 0.37 MAE,低于我们没有任何功能工程的基线 0.51。
现在飞吧,你这只伟大的孔雀!
这些结果的神奇之处在于,它们都保存在你的本地计算机上,这意味着你可以在未来几天、几周、几年甚至几代人的时间里继续使用它们!好吧,也许不是最后一部分。
关键是,当你从这个玩具问题中抽身出来,开始构建需要数小时训练的模型时,你为什么会满足于重新运行同一个模型,或者从过去的实验中获取有价值的优化信息,或者不得不手动跟踪所有这些荒谬的超参数和特征工程步骤?
展开你的翅膀!让超参数猎人去处理所有那些烦人的事情,这样你就可以停止努力跟踪每件事,把你的时间花在真正的机器学习上。
如果你还没有足够的超参数猎人,看看我们的回购的自述快速入门,或者我们的许多例子,或者这个优秀的文章(前 HH-3.0)由 Javier Rodriguez Zaurin 关于将 ML 投入生产。
第二部分:远视。
Python 中超参数优化。
在这个博客系列中,我将比较 python HPO 库。在阅读这篇文章之前,我强烈建议你阅读 第 0 部分:简介 其中我:
- 谈论 HPO 是什么,
- 要比较的选定库,
- 选择了评估标准,
- 为 HPO 定义了一个示例问题。
这篇博文和本系列其他部分的代码可以在 github 上获得,而所有关于脚本、超参数、图表和结果(可以下载)的实验都可以在 Neptune 上获得。更多信息,请阅读这篇关于组织实验过程的文章。
好,我们开始吧。
远视
这是 HPO 空间中的经典。这个项目有超过 3300 星,600 叉和 40 个贡献者(2 个主要的)。甚至有基于它构建的项目,如:
- hyperas :远视+角膜
- 超视-sklearn :超视+ sklearn
易于设置和 API
这个 API 非常简单易用。我们需要定义一个搜索空间、目标并运行优化函数:
首先,定义搜索空间。它可以是一个常规词典,也可以是本例中的 OrderedDict:
有点尴尬的是,我必须定义这个名字两次,一次作为字典键,一次作为参数采样器中的label
。
然后,定义目标函数。记住远视最小化功能,所以如果需要,改变符号:
最后,实例化试验对象,并运行优化:
…完成了!
所有的信息、超参数、损失和其他东西都保存在trials
对象中。您可以毫无问题地访问它,也可以将其保存起来供以后使用。如果你想看完整的示例脚本,包括训练曲线、诊断图表等等,请看这个版本化的 ml 实验。
我给它的分数是 9/10 ,因为在空间搜索定义中有重复的名称,而且对于简单的问题,我宁愿不实例化trials
对象,而只是在默认情况下将它实例化为Trials()
。
分数 9/10
选项、方法和(超)超参数
搜索空间
这就是远视大放异彩的地方。有大量采样选项可供选择:
Categorical parameters-
使用 hp.choiceInteger parameters-
你可以使用 hp.randit 、 hp.quniform 、 hp.qloguniform 或 hp.qlognormal ,这给了你很多选择来为你的整数超参数空间建模Float parameters-
类似于整数参数,你真的可以选择用 hp.normal 、 hp.uniform 、 hp.lognormal 和 hp.loguniform 来解决你的问题
但事实并非如此。您可以轻松地定义嵌套空间,其中某些参数的值依赖于其他参数。以文档中的例子为例:
我们可以看到,通过将 hp.choice 与其他采样方法相结合,我们可以拥有条件搜索空间。
这在从特征预处理、模型选择方法到模型超参数的复杂空间中搜索时非常有用。
优化方法
有两种优化算法可以尝试。
*tpe.rand.suggest*
你对参数的标准随机搜索。
*tpe.suggest*
类似于在之前关于 Scikit-Optimize 的博文中所解释的,我们想要使用一个廉价的代理模型来估计昂贵的目标函数在一组参数上的性能。不同之处在于,我们想要估计尾部的密度,而不是估计实际性能(点估计)。
我喜欢 AutoML.org 弗赖堡的了不起的人们从 AutoML_Book 中摘录的以下解释。
树 Parzen 估计器对给定运行的密度函数 p(λ|y < α) and p(λ|y ≥ α). Given a percentile α (usually set to 15%), the observations are divided in good observations and bad observations and simple 1-d Parzen windows are used to model the two distributions.
By using p(λ|y < α) and p(λ|y ≥ α) one can estimate the Expected Improvement ( EI )进行建模,而不是对给定配置λ的观测值 y 的概率 p(y|λ)进行建模。
有趣的是,在优化器中没有指定 λ 参数的选项。
回调
本质上没有回调,但是您可以将回调函数放在objective
中,每次调用objective
时都会执行回调函数。
我不喜欢它,但我想我可以忍受。
总而言之,这是嵌套搜索空间的一大优势,但我不喜欢没有干净回调的事实。 TPE 没有任何(超)超参数,这一方面很好(工作量少,过拟合少),但另一方面,它不允许您调整不工作的东西。我给它 7/10。
分数 7/10
证明文件
说得好听点,它需要很多爱。
官方文档页面由维基上的托管。如果你问我的话,我觉得这更像是一次图书馆之旅,而不是正式的文档。也就是说,读完之后,你应该能够有效地使用这个库。问题是,当你想找到一个特定的东西时,你需要浏览整个维基来寻找它。
它缺少基本的例子。我找到的唯一一个(hyperopt/recipes
)是 6 岁,有错误。
绝大多数函数和 main 类方法都缺少 docstrings。不幸的是,这使得导航和回答简单的问题变得很困难,比如这个函数实际上是做什么的?
好消息是,有很多关于它的博客帖子。其中一些我认为有用的是:
- 区数据实验室的【远视参数整定】
- Vooban 撰写的《优化神经网络超参数的远视教程》
- Tanay agr awal的《关于使用 Hyperopt:高级机器学习》
- Will Koehrsen撰写的“使用 Hyperopt 在 Python 中进行贝叶斯优化的介绍性示例”
文档肯定不是这个项目的强项,但因为它是一个经典,所以有很多外部资源。我给它 3/10。
比分 3/10
注
如果你正在考虑为社区做一些有益的事情,你可以继续,添加 docstrings,一堆例子,并为这个项目创建 read-the-docs 文档。就我而言,我会很感激的。
形象化
远视有可视化模块 plotting.py 。它有三个功能:
- 它向您显示每次迭代的结果,并突出显示最好的分数。
plot_history(trials) of the best experiment
main_plot_histogram
-显示所有迭代结果的直方图。
plot_histogram(trials) of the best experiment
- 哪个…我真的不知道它是做什么的,因为我无法让它运行,也没有文档字符串或示例(同样,文档也远非完美)。
有一些基本的可视化工具,但它们不是非常有用。感觉像 3/10 。
分数 3/10
注
正如我在上一篇帖子中提到的,我喜欢 Scikit-Optimize 提供的图形,并且我实现了一组函数来帮助在不同的 HPO 库之间进行转换,以便您可以对每个库使用这些可视化。我已经把它们放在neptune-contrib
包里,你可以在这里查看如何使用。
持续/重启
你可以先处理一下trials
对象,以后再用。例如,保存部分可以读作:
pickle 会再次加载,而重新启动就像传递trials
对象(现在不为空)并将 max_evals 从 100 更改为 200 一样简单。
简单且工作没有问题: 10/10。
分数 10/10
速度和并行化
使用 hyperopt,您可以将计算分布在一组机器上。Tanay Agrawal 撰写的这篇博客文章中可以找到很好的分步指导,但简而言之,你需要:
- 启动一个装有 MongoDB 的服务器,它将使用您的工人培训脚本的结果,并发送下一个参数集进行尝试,
- 在您的训练脚本中,创建一个指向您在上一步中启动的数据库服务器的
MongoTrials
对象,而不是Trials()
, - 将您的目标函数移动到一个单独的 objective.py 脚本中,并将其重命名为函数,
- 编译您的 Python 训练脚本,
- 运行远视-蒙哥-工人
虽然它完成了任务,但感觉并不完美。您需要围绕目标函数做一些杂耍,在 CLI 中启动 MongoDB 会使事情变得更容易。
因为上面的 8/10 对我感觉很公平。
得分 8/10
实验结果
你可以在海王星探索所有版本化的 ml 实验。每个实验都有一个脚本。例如,你可以在这里看到最佳的代码。
还可以下载实验元数据给熊猫。数据帧通过运行:
我们来看看的实验结果:
只有当我们运行更多的迭代时,tpe
方法才略微胜出。在 100 次迭代的预定义预算中,random
搜索略胜tpe
。
查看 Scikit 的 plot_evaluations 图表——优化最佳 100 次迭代实验:
我们可以看到,只有对于 feature_fraction 参数,搜索实际上已经转向某个方向。否则,它基本上是随机的(这解释了为什么结果如此接近随机搜索)。
总的来说,我在 100 次迭代中得到的最高分仅仅是 0.84509,实际上比随机搜索(来自 Scikit-Optimize)的 0.8464 差了 0.001。我将把它转换成 -1 点(-0.001*100)。
分数–1
结论
hyperpt是一款经典产品,已经为社区服务多年。它有一个易于使用的 API,可以在一个机器集群上并行计算,并且对嵌套搜索空间有很好的支持。
然而,它的文档有限,只有很少的例子和文档字符串,这使得它很难使用,尤其是在黄金路径之外。Visualization suite 也非常有限,并没有带来很多价值。有点麻烦的是,对于我们的示例问题,它无法打败随机搜索。
让我们来看看所有标准的结果:
39 的分数远低于 Scikit-Optimize 的分数。最大的因素是文档、可视化和实验结果。
下一步是什么?
下次我们将仔细看看另一个用于超参数优化 Optuna 的 Tree-Parzen 估计器库。
你可以在这里查看这个系列的第三部分 Optuna vs 远视。
你也可以在我的 Python 专栏的 HPO 中阅读这个系列的其他帖子。
如果你喜欢这个,你可以在我们的 Neptune 博客上找到更多类似的帖子。
你也可以找我 发微博@Neptune_a 我或者 在 LinkedIn 上发帖 关于 ML 和数据科学的东西。
参考
@book{automl_book,
editor = {Hutter, Frank and Kotthoff, Lars and Vanschoren, Joaquin},
note = {In press, available at http://automl.org/book.},
publisher = {Springer},
title = {Automated Machine Learning: Methods, Systems, Challenges},
year = {2018}
}
超参数调谐
探索 Kaggle 的不要过度拟合 II 竞赛中超参数调整方法
卡格尔的不要过度适应 II 竞赛提出了一个有趣的问题。我们有 20,000 行连续变量,其中只有 250 行属于训练集。
挑战在于不要吃太多。
对于如此小的数据集,甚至更小的训练集,这可能是一项艰巨的任务!
在本文中,我们将探索超参数优化作为一种防止过度拟合的方法。
完整的笔记本可以在这里找到。
超参数调谐
维基百科声明“超参数调优就是为一个学习算法选择一组最优的超参数”。那么什么是超参数?
超参数是在学习过程开始之前设置其值的参数。
超参数的一些例子包括逻辑回归中的惩罚和随机梯度下降中的损失。
在 sklearn 中,超参数作为参数传递给模型类的构造函数。
调优策略
我们将探讨优化超参数的两种不同方法:
- 网格搜索
- 随机搜索
我们将从准备数据开始,用默认的超参数尝试几种不同的模型。我们将从中选择两种最佳的超参数调节方法。
然后,我们找到平均交叉验证分数和标准偏差:
Ridge
CV Mean: 0.6759762475523124
STD: 0.1170461756924883
Lasso
CV Mean: 0.5
STD: 0.0
ElasticNet
CV Mean: 0.5
STD: 0.0
LassoLars
CV Mean: 0.5
STD: 0.0
BayesianRidge
CV Mean: 0.688224616492365
STD: 0.13183095412112777
LogisticRegression
CV Mean: 0.7447916666666667
STD: 0.053735373404660246
SGDClassifier
CV Mean: 0.7333333333333333
STD: 0.03404902964480909
我们这里表现最好的模型是逻辑回归和随机梯度下降。让我们看看是否可以通过超参数优化来提高它们的性能。
网格搜索
网格搜索是执行超参数优化的传统方式。它通过彻底搜索超参数的指定子集来工作。
使用 sklearn 的GridSearchCV
,我们首先定义要搜索的参数网格,然后运行网格搜索。
Fitting 3 folds for each of 128 candidates, totalling 384 fitsBest Score: 0.7899186582809224
Best Params: {'C': 1, 'class_weight': {1: 0.6, 0: 0.4}, 'penalty': 'l1', 'solver': 'liblinear'}
我们将交叉验证分数从 0.744 提高到了 0.789!
网格搜索的好处是可以保证找到所提供参数的最佳组合。缺点是非常耗时且计算量大。
我们可以用随机搜索来解决这个问题。
随机搜索
随机搜索不同于网格搜索,主要在于它随机地而不是穷尽地搜索超参数的指定子集。主要的好处是减少了处理时间。
然而,减少处理时间是有代价的。我们不能保证找到超参数的最佳组合。
我们用 sklearn 的RandomizedSearchCV
来试试随机搜索吧。与上面的网格搜索非常相似,我们在运行搜索之前定义了要搜索的超参数。
这里需要指定的一个重要的附加参数是n_iter
。这指定了随机尝试的组合数量。
选择太低的数字会降低我们找到最佳组合的机会。选择太大的数字会增加我们的处理时间。
Fitting 3 folds for each of 1000 candidates, totalling 3000 fitsBest Score: 0.7972911250873514
Best Params: {'penalty': 'elasticnet', 'loss': 'log', 'learning_rate': 'optimal', 'eta0': 100, 'class_weight': {1: 0.7, 0: 0.3}, 'alpha': 0.1}
在这里,我们将交叉验证分数从 0.733 提高到 0.780!
结论
在这里,我们探索了两种超参数化的方法,并看到了模型性能的改善。
虽然这是建模中的一个重要步骤,但绝不是提高性能的唯一方法。
在以后的文章中,我们将探索防止过度拟合的其他方法,包括特征选择和集合。
解释了超参数调优——调优阶段、调优方法、贝叶斯优化和示例代码!
本书"赢得 KAGGLE 的数据分析技巧"
何时以及如何使用手动/网格/随机搜索和贝叶斯优化
Simple Mandala of modeling world (Validation Strategy is out of setup space because the same validation approach should be applied to any models compared for fair model selection)
超参数是 ML 模型的重要组成部分,可以使模型成为黄金或垃圾。
在这篇文章中,我将讨论:
- 随着建模的进行,调谐阶段的演变,
- 各车型的重要参数(特别是 GBDT 车型),
- 常见的四种调优方法(手动/网格搜索/随机搜索/贝叶斯优化)。
目录
- 通用超参数调整策略
- 1.1.特征工程参数调整的三个阶段
- 1.2.什么是超参数基线,哪些参数值得调整?
2。超参数调整的四种基本方法
- 2.1.人工调谐
- 2.2.网格搜索
- 2.3.随机搜索
- 2.4.贝叶斯优化
3。超参数调整和交叉验证中的 k 折叠
4。结论
这是另一篇帖子接的一本新书中介绍的技巧*数据分析技巧赢 Kaggle由三位高阶 Kaggle 作者(不包括我自己)由此可见这不是个人推广!😃 )*
关于这本书本身的完整目录,请看我的其他帖子。
1.通用超参数调整策略
1.1.特征工程参数调整的三个阶段
我们如何调整超参数不仅是关于我们使用哪种调整方法的问题,也是关于我们如何发展超参数学习阶段直到我们找到最终的和最好的。
这应该取决于任务和我们实际上通过超参数变化看到多少分数变化,但我们应该记住以下常见步骤:
- 初始阶段:开始基线参数** &基线特征工程,**
- 预热阶段:围绕手动调谐或网格搜索几个重要参数用几个搜索候选&更多特色工程,
- 激烈调优阶段 : 对更多参数进行随机搜索或贝叶斯优化 &最终特征工程
Plates are getting hotter.
1.2.什么是超参数基线,哪些参数值得调整?
然后,您会有另一个问题:“什么是超参数基线,哪些参数值得调优?”****
每个模型的参数是不同的,因此我不能在这里讨论每个模型的参数。留意参数的选择始终是数据科学家的工作。它应该从对模型算法和模型文档的理解开始。
在这篇文章中,我将只给留下一些关于 GBDT 模型、xgboost、lightbgm 和 catboost** 的资源,这些模型我曾经讨论为的入门模型。**
Laurae ++的这个网页 对于 xgboost/lightgbm 来说一直是一个很棒的起点。
- 你可以找到每个参数的描述,典型值,允许范围,变化的影响等。字面上的大量信息。
- 它们不包括 catboost(截至 2019 年 12 月 7 日)。
Laurae++, a descently-designed information-rich web site about hyperparameters of xgboost and lightgbm ( https://sites.google.com/view/lauraepp/parameters)
解析维迪亚 也提供了关于 GBDT 模型超参数的丰富内容:
- xgboost : 《使用 Python 代码在 xgboost 中进行参数调整的完整指南》
- Light GBM::Light GBM vs XGBOOST 哪个算法取冠?”
一旦你开始谷歌搜索,还有许多其他随机的网页。这是我从《数据科学》杂志上找到的一篇文章,它提供了三种主要 GBDT 车型的对比列表。
下面的图表总结了我对分级重要性中哪些参数是重要的、它们有利的基线选择和调整范围的看法。
List of important hyperparameters of three GBDT models, their baseline choice and tuning range.
(对于表格开发,我的朋友兼同事丁玉轩给了我很好的建议。谢谢大家!)
使用 Python 包建模 GBDT 的人通常使用原始函数版本(“原始 API”)或 sklearn 包装器版本(“sklearn API”),这使得函数的使用等同于其他 sklearn ML 模型 API。
**大多数情况下,你可以根据自己的喜好选择任何一个,但请记住,**除了 catboost 包,original API 和 sklearn API 可能会有不同的参数名,即使它们表示相同的参数。我在上面的总结中包含了两个参数名称。
2.超参数调整的四种基本方法
#1 手动调谐
通过手动调整,基于当前选择的参数和它们的得分,我们改变它们中的一部分,再次训练模型,并检查得分的差异,而不使用自动选择参数来改变新参数的值。
****手动调谐的优点是:
- 您可以记住超参数的行为,并在另一个项目中使用您的知识。因此,我建议至少对主要型号进行一次手动调优。
****缺点是:
- 需要手工操作。
- 你可能会过度思考乐谱的意外移动,而没有尝试很多次并检查它是否是广义的移动。
书中给出了一些手动调谐的例子:
- 当你发现有太多无用的变量输入到模型中时,你就增加正则化参数的权重。
- 当你认为变量间的相互作用在模型中没有被考虑很多时,你可以增加分裂的次数(GBDT 案例)。
一旦您了解了下面讨论的其他方法,您可能会说,如果远不是达到全局最佳参数的最佳方法,我们为什么要进行手动调整,但在实践中,这在早期阶段很好地用于了解对超参数变化的敏感度,或在最后阶段进行调整。
另外,令人惊讶的是,许多顶尖的 Kagglers 更喜欢使用手动调谐来进行网格搜索或随机搜索。
#2 网格搜索
****网格搜索是一种方法,我们从准备候选超参数集开始,为每个候选超参数集训练模型,并选择性能最佳的超参数集。
通常通过 [sklearn.model_selection](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html)
的[GridSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html)
等支持库自动完成参数设置和评估。
****这种方法的优点是:
- 您可以涵盖所有可能的预期参数集。无论你多么坚信其中一套是最可行的,谁知道,邻居可能会更成功。网格搜索不会失去这种可能性。
****缺点在于它是:
- 一个超参数集的一次运行需要一些时间。整个参数集的运行时间可能很长,因此要探索的参数数量有实际限制。
#3 随机搜索
另一方面,随机搜索是一种方法,其中我们像网格搜索一样准备候选超参数集,但是接下来从准备的超参数搜索空间中随机选择超参数集。重复随机选择、模型训练和评估指定的次数,以搜索超参数。最后,选择性能最佳的超参数集。
我们可以通过指定参数的密度函数而不是特定值来控制随机性,例如均匀分布或正态分布。
这里再次说明,设置参数和评估通常是通过 [sklearn.model_selection](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.RandomizedSearchCV.html)
的[RandomizedSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.RandomizedSearchCV.html)
等支持库自动完成的。
****使用随机搜索的优点是:
- 您不必担心运行时间,因为您可以控制参数搜索的数量。
****缺点是:
- 应该有一些妥协,最终选择的超参数集可能不是您在搜索中输入的范围之外的真正最佳值。
- 根据搜索次数和参数空间的大小,有些参数可能没有被充分研究。
The ‘world famous’ grid search vs. random search illustration by James Bergstra James, Yoshua Bengio on “Random Search for HyperParameter Optimization” ( http://www.jmlr.org/papers/volume13/bergstra12a/bergstra12a.pdf)
#4 贝叶斯优化
贝叶斯优化 的基本概念是“如果我们随机搜索一些点,并且知道其中一些点比其他点更有希望,为什么我们不在它们周围再看一看?”
在贝叶斯优化中,它从随机开始,基于贝叶斯方法缩小搜索空间。
如果你知道贝叶斯定理,你可以理解它只是通过开始随机搜索将关于可能超参数的信念的先验分布更新为后验分布。
Illustration of Bayesian optimization. Based on the Bayesian update next try will happen on star point in the bottom chart ( https://github.com/fmfn/BayesianOptimization)
贝叶斯优化方法的优势在于:
- 搜索是潜在有效的(但不一定)。
缺点是:
- 可能陷入局部最优。
做贝叶斯优化常见的有两个 python 库,[hyperopt](https://github.com/hyperopt/hyperopt)
和[optuna](https://github.com/optuna/optuna)
。还有其他名字如[gpyopt](https://github.com/SheffieldML/GPyOpt)
、[spearmint](https://github.com/JasperSnoek/spearmint)
、[scikit-optimize](https://scikit-optimize.github.io/)
。
下面是使用hyperopt
的示例代码。
Bayesian Versus Frequentist ( https://irsae.no/blog-report-international-summer-school-on-bayesian-modelling/)
3.超参数调整和交叉验证中的折叠
**在上面讨论的任何超参数调整方法中,为了避免**过拟合,首先对数据进行折叠,对训练折叠数据和非折叠数据重复训练和验证,这一点很重要。
此外,如果在交叉验证中继续使用相同的褶皱分割(以便比较模型),那么您的具有选定超参数的模型可能过度拟合褶皱,但没有机会识别它。
因此,通过更改随机数种子,将折叠分割从超参数调整更改为交叉验证非常重要。
另一种方法可能是做 嵌套交叉验证 。在嵌套交叉验证中,有两个层次交叉验证循环:外部和内部。
Nested cross-validation
嵌套交叉验证的一个巨大缺点是,它显著增加了运行时间,增加了内循环折叠的次数。我个人觉得做嵌套的交叉验证太多了,对于额外的运行时间来说好处不大,即使在 Kaggle 竞争中也不是主流。
4.结论
我们在超参数调整中采用的方法将随着建模阶段的发展而发展,首先通过手动或网格搜索从少量参数开始,随着模型随着有效特征的增加而变得更好,通过随机搜索或贝叶斯优化查看更多参数,但我们如何做没有固定的规则。
模型会有很多超参数,因此找到重要的参数及其搜索范围并不是一件容易的事情。然而,像 GBDT 家族这样受欢迎的模型是精心制作的,我们对它们知道得足够多,知道从哪里开始和去哪里。
我们必须担心数据折叠不会过度拟合模型,那么必须将折叠分割从超参数调整更改为模型选择交叉验证。
如果你发现遗漏了什么,请告诉我。它将帮助我改进这个总结,为读者提供更好的信息!
使用 Scikit-Learn 在 Google 云平台上调整超参数
谷歌云平台的 AI 平台(原 ML Engine)为你的模型提供超参数调优服务。为什么要花费额外的时间和精力去学习如何使用它,而不是仅仅在虚拟机上运行您已经拥有的代码呢?这些好处值得付出额外的时间和精力吗?
使用它的一个原因是人工智能平台提供了开箱即用的贝叶斯优化。它比网格搜索更有效,从长远来看,也比随机搜索更准确。他们还提供提前停止和恢复已完成的培训工作的能力。如果你认为你第一次没有进行足够的试验,这允许你使用过去的数据进行一些更好的试验。
所有这些都有助于加快超参数调整过程,同时比网格搜索或随机搜索更好地找到最佳匹配。当经常对大量数据进行训练或运行大量实验时,它肯定可以节省金钱和时间。
Stochastic Gradient Descent Visualized Source
和往常一样,我所有的代码都可以在我的 git hub 页面上找到。在讲述了如何在 GCP 上运行超参数调优工作之后,我将比较他们提供的三台预定义机器的培训时间和成本。
我还将展示如何从 api 自动检索训练运行中的最佳超参数。然后,您可以将它们直接传递到您的生产模型中,或者如果您正在运行实验,请将它们保存在 Google 云存储上的 csv 文件中、BigQuery 中的一个表中或任何您希望稍后进行分析的地方。
那么什么是超参数优化的贝叶斯优化呢?超参数调整是一个优化问题,这意味着确切的性质是未知的,并且计算起来很昂贵,因此以一种知情的方式进行将是有益的。
当函数的数学形式未知或者计算起来很昂贵时,贝叶斯优化是一种非常强大的技术。其背后的主要思想是基于数据计算目标函数的后验分布(使用著名的贝叶斯定理),然后选择好的点来尝试这个分布。来源
这意味着,随着更多的试验运行和后验分布开始改善,最有成效的超参数值开始出现。因此,通过根据模型所获得的信息对未来惠普价值做出明智的决策,我们可以加快找到最佳匹配的过程。要了解更多关于贝叶斯统计的知识,请查阅这本的书。
Photo by Jose Antonio Gallego Vázquez on Unsplash
在 GCP 上提交超参数调整工作有 4 个主要部分:
- 一个训练文件,其中包含您想要使用的模型的常用代码,以及您想要用来评估模型的分数。它还包括一个参数解析器,可以为每次试验添加不同参数的 hp 值
- 包含要在训练文件中使用的超参数值的 yaml 文件
- 提交培训作业的 shell 可执行文件
- 安装附加依赖项的安装文件
如果你不熟悉在云中或者 GCP 上工作,有一些额外的步骤,但是我认为它们是值得的,一旦你建立了框架,很容易适应不同的模型。
我在这里使用的模型是一个多类文本分类模型,来自我以前的文章。该模型在这里并不重要,但它是随机梯度下降,在此之前有特征创建(tf-idf)和维数减少(LSA)。如果您愿意,也可以调整这些参数的超参数。训练数据已经清理完毕,如下所示:
每个类都有 1,890 个示例,非常平衡。让我们仔细看看运行培训作业所需的每个文件。
培训文件
顶部是参数解析器。这将把每个踪迹的 hp 值从 yaml 文件馈送给估计器。模型的 hp 值将由参数解析器从 yaml 文件中传递,如下所示:
然后我们要从谷歌云存储中下载训练数据。从那里,文本通过 tf-idf 矢量器,我们定义我们的目标和特征,然后我们减少我们的目标的维度。然后通常的训练-测试-拆分,然后我们将训练数据拟合到分类器,并根据测试数据进行预测。
之后,我们定义我们的分数,在这种情况下只是准确性,因为我们有平衡的类。下一步是调用 hypertune 库,在这里我们设置度量以及与度量值相关的全局步长。每次试验后,模型都保存在您指定的 GCS 文件夹中。
超参数配置文件
在这个文件的第一部分,您指定了目标,在我们的例子中是最大化精度。如果你想基于 RMSE 这样的东西进行优化,那么你应该把它设置为最小化。然后,您设置想要运行的试验次数。试验越多越好,但肯定存在收益递减的问题。他们建议将轨迹的数量至少设置为参数数量的 10 倍,在我们的例子中是 50 个。
接下来,您必须指定想要运行的并发试验的数量。并行运行试验减少了运行时间,但在使用贝叶斯优化时也会降低效率。这是因为它使用先前试验的结果来通知后续试验的 hp 值。
然后,您必须传入 hp metric 标记,最后您还可以启用早期停止,这将在试验明显没有成效时停止试验,从而节省时间。之后,你为每个 hp 定义最小/最大值或不同的类型/类别,这是非常直接的,本质上就是你在网格搜索中所做的。
然后你必须定义你希望每个参数发生什么。当你有一个范围的值要研究时,你可以传入离散值,就像我在这里对“n_components”所做的那样,或者给定一个最小/最大范围,让它遍历并缩放这些值以线性搜索。如果您要搜索的空间非常大,它们还有一个对数刻度和一个反向对数刻度选项。对于分类 1,你必须传递那些谨慎的值。
你也可以选择指定一个搜索算法。如果你没有,它默认为贝叶斯优化。其他选择是网格搜索或随机搜索,所以你也可以这样做。这也是您可以通过使用“resumePreviousJobId”字段并传入作业 Id 来恢复更早的试验的地方,如果您认为更多的试验是值得的。
安装文件
这只是下载了我们需要的 hypertune 库依赖项。如果你需要其他不能直接下载到 AI 平台的依赖项,你可以在这里添加。这里我们唯一需要的是 hypertune 库。
命令过程
这包含了我们提交培训作业所需的变量和 gcloud 命令。就变量而言,“bucket name”是您希望将模型下载到的 bucket,“job directory”是您希望将模型保存到的 bucket 中的文件夹。为“作业名”添加时间戳是一个好的做法,以便将来识别。
“培训包路径”是您在 GCP 上保存文件的文件夹,而“主培训师模块”是带有模型和参数解析器的文件。您还需要设置 AI 平台的运行时版本、python 版本、区域、规模层以及指向 hp config yaml 文件的位置。
然后实际的 gcloud 命令运行训练作业,该作业使用我们定义的上述变量。最后一部分是一个可选命令,如果您想将日志流式传输到控制台,但是您当然可以在此时关闭 shell 并执行其他操作。
把所有东西放在一起
打开 GCP 上的代码编辑器,打开外壳,点击右下角的“笔”图标:
GCP 有一个内置的代码编辑器,这里的任何代码都可以很容易地推到一个云源代码库进行版本控制。当你打开它,你会看到你已经有一个文件夹与你的用户名。
创建一个培训作业文件夹,并随意命名。在主培训作业文件夹中,为培训文件和 yaml 配置文件创建一个子文件夹。您还需要添加一个空的“init”文件,这也是我放置 shell 脚本的地方。在主培训文件夹中是放置安装文件的位置。
接下来,将训练数据上传到云存储桶。你可以通过用户界面做到这一点。我使用的存储桶名称是“training_jobs_bucket ”,但是您可以使用任何您喜欢的名称。
现在,我们准备运行培训作业。假设您已经为在 AI 平台上运行培训作业做好了一切准备,您只需打开 shell 并输入以下命令来运行 shell 脚本:
chmod +x training_job_folder/trainer/submit_hp_job.sh
training_job_folder/trainer/submit_hp_job.sh
就是这样。您的作业现在将运行,您可以在 GCP 的 AI 平台部分检查输出。
它将显示每个试验的精确度从高到低排序,以及该试验的 hp 值。
人工智能平台也有一个 api,你也可以从那里得到结果。这样,您可以将最佳参数直接传递到您的生产模型中,或者您可以轻松地分析实验结果。这里有一个如何做到这一点的例子:
对于凭证,我使用一个服务帐户并提供凭证 json 文件的路径。然后只需提供项目 id 和作业名称。然后提出要求。返回的第一个对象将是最佳超参数。
我用三种不同的标准机器类型(基本型、标准型和高级型)进行了三次不同的测试。除了这三个预定义的层,他们还有带 GPU 和 TPU 的机器,您可以随时创建自定义机器。
使用相同的 hp 值运行了 50 次试验,启用了提前停止,并且我没有运行任何并发试验。如上所述,运行并发试验会加快进程,但这并不是我真正关心的。最后,毫不奇怪,所有三次运行都产生了大约 86%的最高准确率。
计算这些工作之一成本的公式是:
(Price per hour / 60) * job duration in minutes
- 基本:(. 19/60)* 432 = 1.37 美元
- 标准 _ 1:(1.988/60)* 194 = 6.43 美元
- premium _ 1:(16.5536/60)* 222 = 61.25 美元
有趣的是,高级层实际上比标准层花费的时间更长,而且成本几乎是标准层的 10 倍。这可能有几个原因,我启用了提前停止,所以在标准运行中可能有一些试验被提前停止,但在高级运行中没有。我也没有运行并发试验,所以我不知道在这种情况下标准会比溢价有多大优势。
与 standard 相比,Premium 拥有更大的主机(16 个 vcpu 对 8 个 vcpu),但真正的区别在于工作线程的数量(19 个对 4 个)和参数服务器的数量(11 个对 3 个)。所以你应该自己去探索这个问题,你不应该只是假设 premium 会给你最快的结果,这真的取决于你想要达到的目标。
结论
要使用 hyperparameter 服务,您还需要做更多的工作和一点点的学习曲线,但总的来说,我认为这是值得的,我自己也会继续使用它。很多事情,比如实现贝叶斯优化和记录结果,都是为你处理的。我真的很喜欢贝叶斯方法来调整,如果这在训练大量数据或运行大量实验时节省了我的时间,那么这里的额外努力对我来说绝对是值得的。
在 Keras 中使用回调进行超参数调优
通过可视化梯度下降调整超参数的简单方法
为什么这很重要?
本文展示了一种简单的方法,通过在 Keras 中使用回调访问模型权重来调整超参数。
应用机器学习是一个经验过程,您需要尝试不同的超参数设置,并推断哪些设置最适合您的应用。
这种技术通常被称为超参数调谐。
这些超参数可以是学习率(alpha)、迭代次数、最小批量等。
目标
通常通过在连续迭代中观察成本函数的趋势来执行调整。一个好的机器学习模型具有不断降低的成本函数,直到某个最小值。
本文展示了一种简单的方法,借助**等高线图、**为 Keras 模型可视化成本函数的最小化。
在我们的例子中,我们将考虑一个单变量线性回归问题,该问题根据花在广告上的钱数来预测特定产品的销售额。
注意:虽然选择的问题相当简单,但这项技术也适用于深度神经网络。
背景
成本函数和梯度下降
成本函数是根据模型估计输入和相应输出之间关系的能力来衡量模型错误程度的方法。
简单来说…
“你的模型表现有多差”
另一方面,梯度下降是一种通过重复更新网络的参数值来最小化成本函数的技术。
梯度下降的目标可以被认为是…
“反复调整参数,直到达到局部最小值”
问题描述
Advertising.csv 文件包含分配给各种来源(电视、广播、、报纸)的广告预算及其对特定产品销售的影响。
由于我们的重点是单变量回归,我们将只考虑分配给 TV 的预算作为我们的独立变量*。*
本文的代码和数据可以在这里找到。
在将 csv 文件加载到一个 pandas dataframe 中并删除不必要的列之后…
df = pd.read_csv(‘path/to/file/Advertising.csv’)
df.drop([‘Unnamed: 0’,’radio’,’newspaper’],axis = 1 , inplace=True)
X = df[‘TV’]
Y = df[‘sales’]
df.head()
…最终的数据帧将是这样的
Advertising Data Set
后来,我们将数据分成训练集和测试集
X_train, X_test, Y_train, Y_test = train_test_split(X, Y,
test_size = 0.2)
现在,请注意,Keras 并没有明确提供像 scikit-learn 这样的线性回归模型。但是我们可以用单个神经元的密集层来模拟线性回归。
model = Sequential()
model.add(Dense(1, activation = ‘linear’, use_bias = True,
input_dim = 1))
model.compile(optimizer = optimizers.RMSprop(lr = 0.01),
loss = ‘mean_squared_error’, metrics = [‘mae’])
设计的模型看起来会像…
Univariate Linear Regression “Network”
训练模型,我们得到一个相当令人满意的预测图…
绘制成本函数
线性回归的成本函数由下式给出
从等式中可以清楚地看出,我们对可视化成本最小化的要求是每次迭代后更新的图层的权重(和偏差)。
如果我们能够以某种方式访问图层的权重,我们将能够轻松地可视化成本最小化/梯度下降。
Keras 提供了一个 get_weights() 函数供用户访问网络层的权重。
model.get_weights()
但是该函数在训练后返回模型的最终权重(和偏差)。
我们需要一种方法来访问每次迭代(或每批)结束时的权重。
为此,我们将利用一个回调。
在 Keras 中定义回调
Keras 回调帮助您更快地修复 bug 并构建更好的模型。
“回调是在训练过程的给定阶段应用的一组函数。您可以在训练期间使用回调来查看模型的内部状态和统计数据。
这正是我们所需要的,因为现在我们可以在每次小批量之后(即每次迭代之后)获得 _weights()。重量存储在一个重量历史列表中,以备后用。还为偏差项维护了一个单独的列表。
weight_history = []
bias_history = []
class MyCallback(keras.callbacks.Callback):
def on_batch_end(self, batch, logs):
weight, bias = model.get_weights() B = bias[0]
W = weight[0][0]
weight_history.append(W)
bias_history.append(B)callback = MyCallback()
创建的回调与用于训练模型的输入和输出一起传递。
model.fit(X_train, Y_train, epochs = 10, batch_size = 10,
verbose = True, **callbacks=[callback]**)
现在,存储的权重可用于绘制关于权重(W)和偏差(B)的成本函数(J)。
等高线图仅根据重量历史和*偏差历史绘制。*这里不需要计算成本函数。
解读等高线图
等高线图的基本直觉是,连续的线代表恒定的量值(称为等高线),并且量值随着我们从图的中间部分到向外部分而增加。
等高线的大小已经给出,在这里,它表示成本函数(J)的可能值。您可以大致观察到,成本(红线)从接近 5000 开始,并继续下降,直到在特定点停止。
这与损失函数值相对应,损失函数值也被认为是均方误差。
注意:两个图之间的误差是由于均方误差(如上)是根据验证分割计算的,而等高线图是使用整个训练数据绘制的。
什么也有用?
如上所述,绘制迭代损失函数也可用于超参数调整。事实上,这是数据科学家最常用的技术。
为什么要使用等高线图?
等高线图提供的优势在于,它们给出了关于梯度下降算法在迭代中更新模型/网络参数所遵循的轨迹的更好的直觉。
最后…
因为我们已经获得了模型参数,所以观察它们随时间变化的趋势是值得的。
Weight vs. Time
Bias vs. Time
因此,可以观察到我们的模型的权重和偏差达到成本函数的局部最小值所遵循的趋势。
现在,您已经可以访问所有的图,您可以有效地检查您的模型是否学习缓慢或超调(学习率),是否小批量产生可观察到的好处,理想的迭代次数(或甚至是时期)等。
深度学习中的超参数
超参数调音就像调音你的吉他。然后奇迹发生了!
Photo by Roberta Sorge on Unsplash
当你处于学习阶段时,为你的吉他调音是至关重要的,因为你正在创造不同感官之间的联系。你的耳朵、手指和眼睛都在学吉他。习惯吉他走音就像养成了一个坏习惯,一个会破坏你爱上吉他学习过程的整个体验的习惯。
给你的吉他调音真的可以帮助你爱上吉他。机器学习和深度学习的超参数调整也是如此
超参数是我们在将学习算法应用于数据集之前需要设置的变量。
超参数的挑战在于,不存在放之四海而皆准的神奇数字。最佳数字取决于每个任务和每个数据集
超参数可分为两类:
1)优化器超参数
- 1.1 —学习率
- 1.2 —小批量
- 1.3 —历元数
2)模型特定超参数
- 2.1 —隐藏单元的数量
- 2.2 —第一层
- 2.3 —层数
1.优化程序超参数
它们更多地与优化和训练过程相关
1.1 学习率:
一个最重要的超参数,你应该始终确保它已被调整 Yoshua Bengio
良好的起点= 0.01
如果我们的学习率比最优值小,那么将需要更长的时间(数百或数千个)才能达到理想状态
或者,另一方面
如果我们的学习速率比最优值大得多,那么它将超过理想状态,并且我们的算法可能不收敛
这只是一个例证。在现实世界中,事情要复杂得多。
a)您的模型将有成百上千个参数,每个参数都有自己的误差曲线。学习率必须指导他们所有人
b)误差曲线不是整齐的 u 形。它们有更复杂的局部极小值形状
1.2 小批量尺寸:
批量大小对训练过程的资源需求、速度和迭代次数有影响,这种影响可能不像你想的那么微不足道
在历史上,有一个关于进行随机训练的争论,其中您将数据集的单个示例拟合到模型,并且仅使用一个示例,进行正向传递,计算误差,然后反向传递,并为所有超参数设置调整值。然后对数据集中的每个示例重复此操作。
或者,最好将整个数据输入训练步骤,并使用通过查看数据集中的所有示例而生成的误差来计算梯度。这被称为批量训练
目前常用的方法是设置一个小批量。
随机训练是指小批量=1,批量训练是指小批量=训练集中的样本数
推荐的实验起始值
1, 2, 4, 8, 16, 32, 64, 128, 256
较大的迷你批次大小允许在训练计算中利用矩阵乘法来提高计算能力,但这是以训练过程需要更多存储器为代价的。
较小的小批量会在误差计算中引入更多噪声,并且通常更有助于防止训练过程停止在局部最小值。
小型批量的良好价值= 32
因此,虽然计算能力的提升激励我们增加迷你批次的大小,但这种实际的算法优势激励我们实际上让它变得更小
1.3 历元数:
为了给我们的训练步骤选择正确的历元数,我们应该关注的度量是验证误差。
直观的手动方法是,只要验证误差不断减小,就让模型训练尽可能多的迭代次数。
有一种技术叫做提前停止来决定什么时候停止训练模型。如果验证误差在过去 10 或 20 个时期内没有改善,则停止训练过程
2.模型超参数
他们更多地参与到模型的结构中
2.1 隐藏单元数量:
隐藏单元数是其中最神秘的超参数之一。
神经网络是通用函数逼近器,对于学习逼近函数(或预测任务)的网络,它需要有足够的“能力”来学习函数
隐单元的数量是衡量模型学习能力的主要指标
‘Learning Capacity’ for a Simple Function
对于一个简单的函数,它可能需要较少数量的隐藏单元。
函数越复杂,模型需要的学习能力就越强
‘Learning Capacity’ for a Complex Function
单位数量略多于最佳数量不是问题,但数量大得多会导致模型过度拟合,即如果您提供的模型容量过大,它可能会过度拟合,并试图记住数据集。
2.2 第一个隐藏层:
涉及第一隐藏层的另一个启发是,已经观察到,将隐藏单元的数量设置为大于输入的数量会在任务数量上给出更好的结果。
2.3 层数:
Andrej Karpathy 在他的博客中告诉我们,在实践中,3 层神经网络往往会优于 2 层网络。但是更深入的研究很少会有更大的帮助。
卷积神经网络是一个例外,它越深入,性能越好。
感谢阅读!
- 如果你喜欢这个,关注我的 medium 了解更多。
- 你的掌声对你写更多、写得更好是一个巨大的鼓励和动力。
- 有兴趣合作吗?我们在 Linkedin 上连线吧。
- 请随意写下您的想法/建议/反馈。
参考资料: Udacity_DeepLearning
超参数优化
介绍如何使用随机搜索、自动超参数调整和人工神经网络调整等技术来微调机器和深度学习模型。
介绍
机器学习模型由两种不同类型的参数组成:
- 超参数 =用户在开始训练前可以任意设置的所有参数(如随机森林中的估计数)。
- 模型参数= 改为在模型训练期间学习(如神经网络中的权重、线性回归)。
模型参数定义了如何使用输入数据来获得期望的输出,并在训练时学习。相反,超参数首先决定了我们的模型是如何构建的。
机器学习模型调整是一种优化问题。我们有一组超参数,我们的目标是找到它们值的正确组合,这可以帮助我们找到函数的最小值(例如损失)或最大值(例如精度)(图 1)。
当比较不同的机器学习模型在数据集上的表现时,这可能特别重要。事实上,举例来说,将具有最佳超参数的 SVM 模型与未经优化的随机森林模型进行比较是不公平的。
在本帖中,将解释以下超参数优化方法:
- 手动搜索
- 随机搜索
- 网格搜索
- 自动超参数调整(贝叶斯优化,遗传算法)
- 人工神经网络调整
Figure 1: ML Optimization Workflow [1]
为了演示如何在 Python 中执行超参数优化,我决定对信用卡欺诈检测 Kaggle 数据集执行完整的数据分析。在本文中,我们的目标是正确分类哪些信用卡交易应该被标记为欺诈或真实(二元分类)。该数据集在发布前已被匿名化,因此,大部分特征的含义尚未公开。
在这种情况下,我决定只使用数据集的一个子集,以便加快训练时间,并确保在两个不同的类之间实现完美的平衡。此外,只有有限数量的功能被用来使优化任务更具挑战性。最终的数据集如下图所示(图 2)。
Figure 2: Credit Card Fraud Detection Dataset
本文中使用的所有代码(以及更多!)可以在我的 GitHub 库和 Kaggle 个人资料中找到。
机器学习
首先,我们需要将数据集分为训练集和测试集。
在本文中,我们将使用随机森林分类器作为优化模型。
随机森林模型由大量不相关的决策树组成,这些决策树连接在一起构成一个集合。在随机森林中,每个决策树做出自己的预测,并且选择整体模型输出作为最频繁出现的预测。
我们现在可以开始计算我们的基本模型精度。
[[110 6]
[ 6 118]]
precision recall f1-score support
0 0.95 0.95 0.95 116
1 0.95 0.95 0.95 124
accuracy 0.95 240
macro avg 0.95 0.95 0.95 240
weighted avg 0.95 0.95 0.95 240
使用带有默认 scikit-learn 参数的随机森林分类器可获得 95%的总体准确率。现在让我们看看应用一些优化技术是否可以获得更高的精度。
手动搜索
当使用手动搜索时,我们根据我们的判断/经验选择一些模型超参数。然后,我们训练该模型,评估其准确性,并再次开始该过程。重复这一循环,直到达到令人满意的精确度。
随机森林分类器使用的主要参数是:
- 标准 =用于评估分割质量的函数。
- max_depth =每棵树允许的最大层数。
- max_features =分割节点时考虑的最大特征数。
- min_samples_leaf =可以存储在树叶中的最小样本数。
- min_samples_split =节点中导致节点分裂所需的最小样本数。
- n_estimators =集合中的树的数量。
关于随机森林参数的更多信息可以在 scikit-learn 文档中找到。
作为手动搜索的一个例子,我试图在我们的模型中指定估计量的数量。不幸的是,这并没有带来任何准确性的提高。
[[110 6]
[ 6 118]]
precision recall f1-score support
0 0.95 0.95 0.95 116
1 0.95 0.95 0.95 124
accuracy 0.95 240
macro avg 0.95 0.95 0.95 240
weighted avg 0.95 0.95 0.95 240
随机搜索
在随机搜索中,我们创建超参数网格,并在这些超参数的一些随机组合上训练/测试我们的模型。在这个例子中,我还决定对训练集执行交叉验证。
当执行机器学习任务时,我们通常将数据集分为训练集和测试集。这样做是为了在训练模型后测试我们的模型(这样我们可以检查它在处理未知数据时的性能)。当使用交叉验证时,我们将训练集分成 N 个其他分区,以确保我们的模型不会过度拟合我们的数据。
最常用的交叉验证方法之一是 K 倍验证。在 K-Fold 中,我们将我们的训练集分成 N 个分区,然后使用 N-1 个分区迭代地训练我们的模型,并用剩余的分区对其进行测试(在每次迭代中,我们都改变剩余的分区)。一旦对模型进行了 N 次训练,我们就对每次迭代中获得的训练结果进行平均,以获得我们的总体训练性能结果(图 3)。
Figure 3: K-Fold Cross-Validation [2]
在实现超参数优化时使用交叉验证非常重要。通过这种方式,我们可以避免使用一些超参数,这些超参数对训练数据非常有效,但对测试数据却不太有效。
我们现在可以开始实现随机搜索,首先定义一个超参数网格,当调用***RandomizedSearchCV()时,将随机采样该网格。对于这个例子,我决定将我们的训练集分成 4 个部分( cv = 4 ),并选择 80 作为要采样的组合数( n_iter = 80 )。使用 sci kit-learnbest _ estimator _***属性,我们可以检索在训练期间表现最佳的一组超参数来测试我们的模型。
一旦训练了我们的模型,我们就可以想象改变它的一些超参数会如何影响整体模型的准确性(图 4)。在这种情况下,我决定观察改变估计量的数量和标准如何影响我们的随机森林精度。
Figure 4: Criterion vs N Estimators Accuracy Heatmap
然后,我们可以通过使我们的可视化更具互动性来更进一步。在下面的图表中,我们可以检查(使用滑块)在考虑所选 min_split 和 min_leaf 参数的情况下,改变模型中估计量的数量会如何影响模型的整体准确性。
通过更改 n_estimators 参数、放大和缩小图表、更改其方向以及将鼠标悬停在单个数据点上来获得有关它们的更多信息,您可以随意摆弄下面的图表!
如果你有兴趣了解更多关于如何使用 Plotly 创建这些动画,我的代码可以在这里找到。此外, Xoel López Barata 写的一篇文章也谈到了这一点。
我们现在可以使用随机搜索来评估我们的模型表现如何。在这种情况下,与我们的基本模型相比,使用随机搜索可以持续提高准确性。
[[115 1]
[ 6 118]]
precision recall f1-score support
0 0.95 0.99 0.97 116
1 0.99 0.95 0.97 124
accuracy 0.97 240
macro avg 0.97 0.97 0.97 240
weighted avg 0.97 0.97 0.97 240
网格搜索
在网格搜索中,我们建立超参数网格,并在每个可能的组合上训练/测试我们的模型。
为了选择在网格搜索中使用的参数,我们现在可以看看哪些参数最适合随机搜索,并基于它们形成一个网格,看看我们是否可以找到更好的组合。
网格搜索可以使用 scikit-learn***GridSearchCV()***函数在 Python 中实现。也是在这个场合,我决定把我们的训练集分成 4 折( cv = 4 )。
使用网格搜索时,会尝试网格中所有可能的参数组合。在这种情况下,训练时将使用 128000 个组合(2×10×4×4×10)。相反,在之前的网格搜索示例中,只使用了 80 种组合。
[[115 1]
[ 7 117]]
precision recall f1-score support
0 0.94 0.99 0.97 116
1 0.99 0.94 0.97 124
accuracy 0.97 240
macro avg 0.97 0.97 0.97 240
weighted avg 0.97 0.97 0.97 240
与随机搜索相比,网格搜索速度较慢,但它总体上更有效,因为它可以遍历整个搜索空间。相反,随机搜索可能会更快,但可能会错过搜索空间中的一些重要点。
自动超参数调谐
当使用自动超参数调整时,使用诸如贝叶斯优化、梯度下降和进化算法的技术来识别要使用的模型超参数。
贝叶斯优化
使用 Hyperopt 库可以在 Python 中执行贝叶斯优化。贝叶斯优化使用概率来寻找函数的最小值。最终目标是找到一个函数的输入值,它能给我们提供尽可能低的输出值。
贝叶斯优化已被证明比随机、网格或人工搜索更有效。因此,贝叶斯优化可以在测试阶段带来更好的性能,并减少优化时间。
在 Hyperopt 中,给函数 fmin() 三个主要参数,可以实现贝叶斯优化。
- 目标函数 =定义最小化的损失函数。
- 域空间 =定义要测试的输入值的范围(在贝叶斯优化中,该空间为每个使用的超参数创建一个概率分布)。
- 优化算法 =定义用于选择最佳输入值的搜索算法,以便在每次新的迭代中使用。
另外,还可以在 fmin() 中定义要执行的最大求值次数。
贝叶斯优化可以通过牢记过去的结果来选择输入值,从而减少搜索迭代的次数。通过这种方式,我们可以从一开始就将我们的搜索集中在与我们期望的输出更接近的值上。
我们现在可以使用 fmin() 函数运行我们的贝叶斯优化器。首先创建一个 Trials() 对象,以便以后能够可视化 fmin() 函数运行时发生的情况(例如,损失函数如何变化,以及使用的超参数如何变化)。
100%|██████████| 80/80 [03:07<00:00, 2.02s/it, best loss: -0.9339285714285713]{'criterion': 1,
'max_depth': 120.0,
'max_features': 2,
'min_samples_leaf': 0.0006380325074247448,
'min_samples_split': 0.06603114636418073,
'n_estimators': 1}
我们现在可以检索识别的最佳参数集,并使用训练期间创建的 最佳 字典测试我们的模型。一些参数已经使用索引数字存储在 best 字典中,因此,在将它们输入到我们的随机森林之前,我们需要首先将它们转换回字符串。
使用贝叶斯优化的分类报告如下所示。
[[114 2]
[ 11 113]]
precision recall f1-score support
0 0.91 0.98 0.95 116
1 0.98 0.91 0.95 124
accuracy 0.95 240
macro avg 0.95 0.95 0.95 240
weighted avg 0.95 0.95 0.95 240
遗传算法
遗传算法试图将自然选择机制应用于机器学习环境。它们受到达尔文自然选择过程的启发,因此通常也被称为进化算法。
让我们想象我们用一些预定义的超参数创建 N 个机器学习模型的群体。然后,我们可以计算每个模型的准确性,并决定只保留一半的模型(表现最好的模型)。我们现在可以生成一些子代,这些子代具有与最佳模型相似的超参数,从而再次得到 N 个模型的群体。在这一点上,我们可以再次计算每个模型的准确性,并重复定义数量的代的循环。通过这种方式,只有最好的模型会在流程结束时保留下来。
为了用 Python 实现遗传算法,我们可以使用 TPOT 自动机器学习库。TPOT 建立在 scikit-learn 库的基础上,可用于回归或分类任务。
使用遗传算法确定的训练报告和最佳参数显示在下面的代码片段中。
Generation 1 - Current best internal CV score: 0.9392857142857143
Generation 2 - Current best internal CV score: 0.9392857142857143
Generation 3 - Current best internal CV score: 0.9392857142857143
Generation 4 - Current best internal CV score: 0.9392857142857143
Generation 5 - Current best internal CV score: 0.9392857142857143
Best pipeline: RandomForestClassifier(CombineDFs(input_matrix, input_matrix), criterion=entropy, max_depth=406, max_features=log2, min_samples_leaf=4, min_samples_split=5, n_estimators=617)
我们的随机森林遗传算法优化模型的总体精度如下所示。
0.9708333333333333
人工神经网络(ann)调整
使用 KerasClassifier 包装器,可以像使用 scikit-learn 机器学习模型一样,对深度学习模型应用网格搜索和随机搜索。在下面的例子中,我们将尝试优化我们的一些人工神经网络参数,例如:每层使用多少个神经元,以及使用哪个激活函数和优化器。深度学习超参数优化的更多示例可在此处获得。
Max Accuracy Registred: 0.932 using {'activation': 'relu', 'neurons': 35, 'optimizer': 'Adam'}
使用我们的人工神经网络(ANN)获得的总体准确度可以在下面观察到。
[[115 1]
[ 8 116]]
precision recall f1-score support
0 0.93 0.99 0.96 116
1 0.99 0.94 0.96 124
accuracy 0.96 240
macro avg 0.96 0.96 0.96 240
weighted avg 0.96 0.96 0.96 240
估价
我们现在可以比较所有不同的优化技术在这个给定练习中的表现。总的来说,随机搜索和进化算法表现最好。
Base Accuracy vs Manual Search 0.0000%.
Base Accuracy vs Random Search 2.1930%.
Base Accuracy vs Grid Search 1.7544%.
Base Accuracy vs Bayesian Optimization Accuracy -0.4386%.
Base Accuracy vs Evolutionary Algorithms 2.1930%.
Base Accuracy vs Optimized ANN 1.3158%.
所获得的结果高度依赖于所选择的网格空间和所使用的数据集。因此,在不同的情况下,不同的优化技术会比其他技术表现得更好。
我希望你喜欢这篇文章,谢谢你的阅读!
联系人
如果你想了解我最新的文章和项目,请通过媒体关注我,并订阅我的邮件列表。以下是我的一些联系人详细信息:
文献学
[1]超参数优化:自动化算法的解释,Dawid Kopczyk。访问地点:https://dkopczyk.quantee.co.uk/hyperparameter-optimization/
[2]型号选择,ethen8181。访问网址:http://ethen 8181 . github . io/machine-learning/model _ selection/model _ selection . html
假设检验—双尾检验
在这篇文章中,我们将讨论如何对一个双尾检验进行假设检验。在我之前的帖子中,我已经用例子详细讨论了假设检验以及如何使用无效(H0) 和替代(H1) 假设来验证它。所以,在这篇文章中,我不会去探究假设检验的内容和方法。相反,我们将直接看到如何进行双尾检验,实施这种方法的条件和标准是什么。
所以,让我们直接进入一个问题,看看如何解决它。在解决问题的过程中,我会解释一些必要的概念,让你对这个方法更清楚。
问题陈述:一批学生平均身高 100 cm,标准差 15。然而,Tedd 认为这种情况已经改变,所以他决定测试该批中随机抽取的 75 名学生的身高。样本的平均高度是 105。是否有足够的证据表明平均身高发生了变化?
让我们重申一下执行假设检验的步骤:
- 指定零假设(H0)和替代假设(H1)
- 选择显著性水平(α)
- 找到关键值
- 查找测试统计数据
- 得出你的结论
让我们执行假设检验的第一步,即:
- 指定零假设(H0)和备择假设(H1)
零假设(H0): 这里的零假设指的是目前对总体而言为真的假设。在我们的例子中,这一批学生的平均身高是 100。
H0 : μ = 100
替代假设(H1): 替代假设总是被宣称的东西。“在我们的例子中,Tedd 认为(声明)实际值已经改变”。他不知道平均数是上升了还是下降了,但他相信平均数已经变了,不再是 100 了。
H1: μ ≠100
永远记住,一个替代假设总是用≠或< or >符号表示。请参考下表了解更多信息。
因此,如果另一个假设写有≠符号,这意味着我们将进行双尾检验,因为它可能大于 100 或小于 100,因此是双尾的。
所以,在陈述完无效假设和替代假设之后,是时候进入第二步了:
2。选择显著性水平(α)
显著性水平基本上被定义为曲线尾部的面积。通常,提供了显著性水平,但是如果没有,那么我们需要选择显著性水平。
因此,如果没有提供显著性水平,那么我们将其取为 0.05,因为这是最常见的值。让我们看看这是如何在双尾测试中表现出来的
在上面的曲线中,你可以看到显著性水平是 0.05,两条尾巴是对称的,这意味着它们有相同的面积。这意味着每条尾巴的面积为 0.025。
我们需要在曲线上看到的最后一点是,曲线的总面积是 1%或 100%。由于尾部的总面积等于 0.05,那么曲线中间的面积将是 95%或 0.95。
我们已经陈述了我们的重要性。现在让我们进入第三步
3。找到临界值
临界值基本上是分隔红色阴影区域(尾部区域)和曲线中间区域的 z 值或 t 值。
这里的临界值可以是一个 z 值或一个 t 值。让我们看看在我们的例子中会是什么。
请记住,当向我们提供总体标准差(σ)时,我们将使用 z 值。
我们将在以下情况下使用 t 值:
- 问题陈述中没有给出总体标准差(σ)。
- 抽取或提供的样本量小于 30。
在我们的例子中,我们将使用 z 值作为提供的总体标准差。为了计算 z 值,我们将使用下面给出的 z 表。
我们基本上可以使用几种方法来计算 z 值。
- 正如我们所知,不包括尾部的曲线面积是 0.95 或 95%,这意味着声明的置信水平是 95%。因此,我们可以使用置信度来查找 z 值。
- 我们还可以使用其中一条曲线的面积 0.025 来查找 z 值。
上表中需要注意的一点是“0 和 z 值之间的区域”一栏只不过是置信水平的一半(在我们的例子中是 0.4750)。但是,假设我们有一个上表中没有提供的置信度,那么您需要将该置信度除以 2,并在 Z 表的内部查找该区域,然后在外部查找相应的 Z 得分。
在我们的例子中,如果我们将置信水平除以 2,那么它将是 0.4750。因此,如果您在下表中查找并添加对应于 0.4750 的“**z”**的行值和列值,则结果为 1.96
所以,我们在曲线右尾的临界值是 1.96,在曲线左尾或低端,低于平均值的是-1.96
拒绝区域
这些临界值之所以如此重要,是因为它将红色区域与曲线中间分开。红色区域称为拒绝区域。
之所以称之为拒绝区域,是因为在下一步中,我们将执行一项测试,该测试将给出样本的 z 值。如果样本 z 值落在任何拒绝区域(红色区域),这意味着我们可以拒绝我们的零假设。现在,让我们进入第 4 步。
4。查找测试统计
这意味着我们将找到样本的 z 值。
z 值=(x-bar-μ)÷(σ÷√[ n])
其中 x-bar =样本平均值= 105
μ =总体平均值= 100
σ =样本的标准偏差= 15
n =样本量= 75
z 值=(105–100)÷(15÷√7.5)= 2.89
这个值 2.89 称为检验统计量。
这是我们的最后一步。
5。得出结论
所以,如果你看曲线,2.89 的值肯定位于曲线右侧的红色区域,因为临界值 1.96 小于 2.89。由于值位于拒绝区域,我们可以拒绝零假设。
结论:
拒绝 H0:μ= 100
接受 H1:也就是μ ≠ 100
因此,根据问题陈述,有足够的证据表明平均身高发生了变化,因为我们能够接受另一个假设,即平均身高不等于 100。
使用 Python 对欧洲足球数据进行假设检验
深入分析
主场优势、理想阵型和联赛间属性
康纳·安德森、凯文·维拉斯科和亚历克斯·什罗普希尔
简介和假设
欧洲足球队在主场比赛存在潜在优势的传统观念有统计学意义吗?哪种阵型的整体胜率更高,4-4-2 还是 4-3-3?当比较英超和法甲的球队属性时,平均而言,哪个联赛的防守侵略性更高?平均来说,哪一个更有能力让球员进入投篮位置?我们的假设测试会产生有价值的、有统计学意义的结论吗,或者只是留给我们更多没有答案的问题?
我们使用了来自 Kaggle.com 的欧洲足球数据库来探索这些假设,给出了一个 sqlite3 数据库,其中有 7 个数据表,涵盖了 2008 年至 2016 年来自 11 个欧洲国家的 25,000 场历史足球比赛,10,000 名球员和球队(球员&球队评级由 EA Sports 评估)。为了从单个统计假设的角度总结我们的方法,我们运行了四个双尾双样本 T 检验,阈值为拒绝或不拒绝每个零假设(alpha=0.05)。为了运行这些测试,我们的数据必须随机抽样,近似正态分布,并且是独立的。我们的测试产生了各种描述性的结果指标和有用的可视化,可以在本文末尾链接的 GitHub 资源库中更详细地查看,但为了简洁起见,我将坚持下面最重要的几点。
测试 1:主队与客队的胜率
H0(零假设):平均值之间无统计学显著差异。主场球队的胜率和平均成绩。客场球队的胜率
HA(替代 Hyp。):平均值之间存在统计上的显著差异。主场球队的胜率和平均成绩。客场球队的胜率
Is there any truth to home-field advantage?
测试 2:4–4–2 与 4–3–3 的成功率
H0:4–4–2 胜率和 4–3–3 胜率在统计上没有显著差异
哈:4–4–2 胜率和 4–3–3 胜率之间存在统计上的显著差异
Blue = 4–4–2 Formation | Red = 4–3–3 Formation
测试 3:防守侵略性评级(英超 vs 法甲)
H0: 两者的平均得分没有统计学上的显著差异。英国队和美国志愿队的防守侵略性评级。法国队防守攻击性评分
HA: 存在着统计学上的显著差异。英国队和美国志愿队的防守侵略性评级。法国队防守攻击性评分
测试 4:射门机会创造评级(英超 vs 法甲)
H0: 平均得分没有统计学上的显著差异。英格兰球队的投篮机会创造率和平均得分。法国队的射门机会创造评分
HA: 平均值之间存在统计学上的显著差异。英格兰球队的投篮机会创造率和平均得分。法国队的射门机会创造评分
流程和挑战概述
SQLite→PostgreSQL→Pandas data frames
Kaggle 以 SQLite 数据库格式提供了 7 个数据表,为了改善团队协作,我们选择通过指示pgloader
从 SQLite 文件加载数据,将数据移动到 PostgreSQL 数据库,这几乎可以完美地工作。 Player 表出现了一个错误,因此我们首先将它转换为 csv 格式,然后使用以下代码直接加载到 DataFrame 中,从而解决了这个问题:
import sqlite3
import pandas as pd
conn = sqlite3.connect('database.sqlite')
df = pd.read_sql_query("SELECT * FROM Player", conn)
df.to_csv('player.csv',index=False)player_df = pd.read_csv('player.csv')
player_df.head()
对于能够完全进入 PostgreSQL 的表,我们通过以下方式将它们加载到 Pandas 数据帧中:
conn = psycopg2.connect('dbname=soccer')
cur = conn.cursor()
query = '''
SELECT *
FROM Country
;'''
cur.execute(query)countries_data = cur.fetchall()
countries_df = pd.DataFrame(countries_data)
countries_df.columns = [i[0] for i in cur.description]
countries_df.head()
主场进球&客场进球栏目→二进制主场胜&客场胜栏目→主场胜率&客场胜率
我们决定利用我们对每支球队在每场比赛中的进球数的了解来创建 2 个二元列,其中 1 代表主队或客场队获胜,0 代表“未获胜”,或球队平局或失败。我们的胜率基本上是指总比赛数中的胜率,它完全基于特定球队在给定比赛中获胜的机会,并不会对输球和平局进行不同的处罚(传统上,联盟对获胜奖励 3 分,平局奖励 1 分,失败奖励 0 分)。如上所述,胜率将通过取这些二进制列的平均值来计算。
#initiate new columns with 0’s (there are other approaches)
match_df['home_team_win'] = np.zeros
match_df['away_team_win'] = np.zeros#set home team WINs equal to 1 in the new column
match_df['home_team_win'].loc[match_df['home_team_goal'] > match_df['away_team_goal']] = 1
#LOSS = 0
match_df['home_team_win'].loc[match_df['home_team_goal'] < match_df['away_team_goal']] = 0
#TIE = 0
match_df['home_team_win'].loc[match_df['home_team_goal'] == match_df['away_team_goal']] = 0
#repeat for away_team_win column#getting to a win rate for the entire dataset
home_team_win_array = np.array(match_df['home_team_win'])
home_win_rate = np.mean(home_team_win_array)
#repeat for away_team_win column
推算检验功效、效应大小和样本量
为了在每次测试中达到我们的理想样本量,我们计算了效应大小(Cohen 的 d ),它考虑了样本数据的平均值和混合方差之间的差异。我们用它来计算达到期望的α水平(0.05)和期望的功率水平(通常在 0.8 左右)所需的最小样本量。总之,这些决定有助于在测试返回 I 型错误(拒绝真 H0-假阳性)或 II 型错误(拒绝假 H0 失败-假阴性)的风险之间取得平衡。令我们惊讶的是,由于样本平均值之间的差异很小,计算表明我们实际上想要更多的样本用于我们的分析,而不是我们现有的样本。因此,在假设检验 2、3 和 4 中,我们检验的功效显著降低,增加了第二类错误的风险。尽管如此,我们还是继续进行测试,但是一个更理想的场景将允许我们在自信地结束测试之前获得更大的统计能力。
自举案例
推断统计学的一个目标是确定总体参数的值,这通常是昂贵的或不可能直接测量的。统计抽样帮助我们克服这一挑战。我们对人口进行抽样,测量一个关于人口的统计数据,并使用它来有希望地说一些关于相应人口的有意义的事情。在我们的第一个假设检验的情况下,我们希望确定主队有一个特定的平均胜率。收集每一场欧洲足球比赛的结果并不容易,因此我们从 2008 年至 2016 年的 25K 场比赛中取样,并说人口的平均胜率在我们样本的平均胜率的误差范围内。
假设我们想更准确地知道那段时间主队的平均胜率是多少,但是我们所能利用的就是这些样本。看起来之前的误差幅度可能是我们最好的猜测。然而,我们可以使用 bootstrapping 来改进这种猜测。为了做到这一点,我们从 25K 个已知匹配中随机抽取替换为的*。我们称之为引导样本。通过替换,该引导样本很可能与我们的初始样本不同。一些匹配可能在我们的样本中出现不止一次,而另一些可能被忽略。使用 Python,我们可以快速创建这些引导样本的数千次迭代。bootstrap 方法产生的估计样本通常形成正态分布,我们可以用集中趋势和方差的度量来概括。大致基于大数定律,如果我们一次又一次地取样,我们可以得出一种“小总体”。由于自举和快速计算机的帮助,即使你使用单个样本来生成数据,这也是适用的。*
#example of bootstrapping code applied to our home team win binary column
sample_means_home = []
for _ in range(1000): #number of iterations
sample_mean = np.random.choice(home_team_win_array,size=202).mean()
#sample size: 202
sample_means_home.append(sample_mean)
len(sample_means_home) #should be 1000
结论
测试 1:主队与客队的胜率
**结论:**否决 H0,赞成哈。主队和客场队的胜率有显著差异。主场优势肯定是存在的!下面是我们在假设检验之外创建的一个简单的可视化图,以说明团队和整体数据的情况:
Most teams tend to win more on their home field
测试 2:4–4–2 与 4–3–3 的成功率
**结论:**拒绝 H0,赞成哈。4–4–2 和 4–3–3 的胜率有显著差异。根据我们的数据,就胜率而言,4–4–2 是更好的阵型,尽管我们可以用更多的样本和/或更大的阵型平均得分差异来进行更强的测试。胜率。
4–4–2 is better on average, but our low power metric (0.67) indicates Type II risk
测试 3:防守侵略性评级(英超 vs 法甲)
**结论:**拒绝 H0,附带告诫。平均成绩似乎有所不同。英格兰队对法国队的防守侵略性评级(EA Sports),但我们的测试缺乏力量(冒着 II 型错误的风险)。我们不能自信地说 avg 真的有差别。联赛间的防守侵略。我们将能够用更多的样本和/或联盟平均值之间的更大差异来运行更强的测试。
测试 4:射门机会创造评级(英超 vs 法甲)
**结论:**拒绝 H0,附带警告。平均成绩似乎有所不同。英格兰队对法国队的投篮机会创造评级(EA Sports),但我们的测试缺乏动力(冒着 II 型错误的风险)。我们不能自信地说平均成绩有真正的差异。联赛间的投篮机会创造能力。我们将能够用更多的样本和/或联盟平均值之间的更大差异来运行更强的测试。
感谢您阅读我们简单易懂的欧洲足球假设检验概述!
深入我们的数据、代码和统计测试的细节,探索我们的 GitHub 库: 康纳——凯文——亚历克斯
在 LinkedIn 上与我们联系,分享您的想法和问题,或者关注我们的数据科学之旅: 康纳——凯文——亚历克斯
假设检验欧洲足球数据
Python 中探索的主场优势、理想阵型和联赛间属性
康纳·安德森、凯文·维拉斯科和亚历克斯·什罗普希尔
简介和假设
欧洲足球队在主场比赛存在潜在优势的传统观念有统计学意义吗?哪种阵型的整体胜率更高,4-4-2 还是 4-3-3?当比较英超和法甲的球队属性时,平均而言,哪个联赛的防守侵略性更高?平均来说,哪一个更有能力让球员进入投篮位置?我们的假设测试会产生有价值的、有统计学意义的结论吗,或者只是留给我们更多没有答案的问题?
我们使用了来自 Kaggle.com 的欧洲足球数据库来探索这些假设,给出了一个 sqlite3 数据库,其中有 7 个数据表,涵盖了 2008 年至 2016 年来自 11 个欧洲国家的 25,000 场历史足球比赛,10,000 名球员和球队(由 EA Sports 评估的球员&球队评级)。为了从单个统计假设的角度总结我们的方法,我们运行了四个双尾双样本 T 检验,阈值为拒绝或不拒绝每个零假设(alpha=0.05)。为了运行这些测试,我们的数据必须随机抽样,近似正态分布,并且是独立的。我们的测试产生了各种描述性的结果指标和有用的可视化,可以在本文末尾链接的 GitHub 资源库中更详细地查看,但为了简洁起见,我将坚持下面最重要的几点。
测试 1:主队与客队的胜率
H0(零假设):平均值之间没有统计学上的显著差异。主场球队的胜率和平均成绩。客场球队的胜率
哈(替代 Hyp。):平均值之间存在统计学上的显著差异。主场球队的胜率和平均成绩。客场球队的胜率
Is there any truth to home-field advantage?
测试 2:4–4–2 与 4–3–3 的成功率
H0:4–4–2 的胜率和 4–3–3 的胜率在统计上没有显著差异
HA:4–4–2 胜率和 4–3–3 胜率之间存在统计上的显著差异
Blue = 4–4–2 Formation | Red = 4–3–3 Formation
测试 3:防守侵略性评级(英超 vs 法甲)
H0: 两者的平均得分没有统计学上的显著差异。英国队和美国志愿队的防守侵略性评级。法国队防守攻击性评分
HA: 存在着统计学上的显著差异。英国队和美国志愿队的防守侵略性评级。法国队防守攻击性评分
测试 4:射门机会创造评级(英超 vs 法甲)
H0: 平均得分没有统计学上的显著差异。英格兰球队的投篮机会创造率和平均得分。法国队的射门机会创造评分
HA: 平均值之间存在统计学上的显著差异。英格兰球队的投篮机会创造率和平均得分。法国队的射门机会创造评分
流程和挑战概述
SQLite→PostgreSQL→Pandas data frames
Kaggle 以 SQLite 数据库格式提供了 7 个数据表,为了改善团队协作,我们选择通过指示pgloader
从 SQLite 文件加载数据,将数据移动到 PostgreSQL 数据库,这几乎可以完美地工作。 Player 表出现了一个错误,因此我们首先将它转换为 csv 格式,然后使用以下代码直接加载到 DataFrame 中,从而解决了这个问题:
import sqlite3
import pandas as pd
conn = sqlite3.connect('database.sqlite')
df = pd.read_sql_query("SELECT * FROM Player", conn)
df.to_csv('player.csv',index=False)player_df = pd.read_csv('player.csv')
player_df.head()
对于能够完全进入 PostgreSQL 的表,我们通过以下方式将它们加载到 Pandas 数据帧中:
conn = psycopg2.connect('dbname=soccer')
cur = conn.cursor()
query = '''
SELECT *
FROM Country
;'''
cur.execute(query)countries_data = cur.fetchall()
countries_df = pd.DataFrame(countries_data)
countries_df.columns = [i[0] for i in cur.description]
countries_df.head()
主场进球&客场进球栏目→二进制主场胜&客场胜栏目→主场胜率&客场胜率
我们决定利用我们对每支球队在每场比赛中的进球数的了解来创建 2 个二元列,其中 1 代表主队或客场队获胜,0 代表“未获胜”,或球队平局或失败。我们的胜率基本上是指总比赛数中的胜率,它完全基于特定球队在给定比赛中获胜的机会,不会对输球和平局进行不同的处罚(传统上,联盟对获胜奖励 3 分,平局奖励 1 分,失败奖励 0 分)。如上所述,胜率将通过取这些二进制列的平均值来计算。
#initiate new columns with 0’s (there are other approaches)
match_df['home_team_win'] = np.zeros
match_df['away_team_win'] = np.zeros#set home team WINs equal to 1 in the new column
match_df['home_team_win'].loc[match_df['home_team_goal'] > match_df['away_team_goal']] = 1
#LOSS = 0
match_df['home_team_win'].loc[match_df['home_team_goal'] < match_df['away_team_goal']] = 0
#TIE = 0
match_df['home_team_win'].loc[match_df['home_team_goal'] == match_df['away_team_goal']] = 0
#repeat for away_team_win column#getting to a win rate for the entire dataset
home_team_win_array = np.array(match_df['home_team_win'])
home_win_rate = np.mean(home_team_win_array)
#repeat for away_team_win column
推算检验功效、效应大小和样本量
为了在每次测试中达到我们的理想样本量,我们计算了效应大小(Cohen 的 d ),它考虑了样本数据的平均值和混合方差之间的差异。我们用它来计算达到期望的α水平(0.05)和期望的功率水平(通常在 0.8 左右)所需的最小样本量。总之,这些决定有助于在测试返回 I 型错误(拒绝真 H0-假阳性)或 II 型错误(拒绝假 H0 失败-假阴性)的风险之间取得平衡。令我们惊讶的是,由于样本平均值之间的差异很小,计算表明我们实际上想要更多的样本用于我们的分析,而不是我们现有的样本。因此,在假设检验 2、3 和 4 中,我们检验的功效显著降低,增加了第二类错误的风险。尽管如此,我们还是继续进行测试,但是一个更理想的场景将允许我们在自信地结束测试之前获得更大的统计能力。
自举案例
推断统计学的一个目标是确定总体参数的值,这通常是昂贵的或不可能直接测量的。统计抽样帮助我们克服这一挑战。我们对人口进行抽样,测量一个关于人口的统计数据,并使用它来有希望地说一些关于相应人口的有意义的事情。在我们的第一个假设检验的情况下,我们希望确定主队有一个特定的平均胜率。收集每一场欧洲足球比赛的结果并不容易,因此我们从 2008 年至 2016 年的 25K 场比赛中取样,并说人口的平均胜率在我们样本的平均胜率的误差范围内。
假设我们想更准确地知道那段时间主队的平均胜率是多少,但是我们所能利用的就是这些样本。看起来之前的误差幅度可能是我们最好的猜测。然而,我们可以使用 bootstrapping 来改进这种猜测。为了做到这一点,我们从 25K 个已知匹配中随机抽取替换为的*。我们称之为引导样本。通过替换,该引导样本很可能与我们的初始样本不同。一些匹配可能在我们的样本中出现不止一次,而另一些可能被忽略。使用 Python,我们可以快速创建这些引导样本的数千次迭代。bootstrap 方法产生的估计样本通常形成正态分布,我们可以用集中趋势和方差的度量来概括。大致基于大数定律,如果我们一次又一次地取样,我们可以得出一种“小总体”。由于自举和快速计算机的帮助,即使你使用单个样本来生成数据,这也是适用的。*
#example of bootstrapping code applied to our home team win binary column
sample_means_home = []
for _ in range(1000): #number of iterations
sample_mean = np.random.choice(home_team_win_array,size=202).mean()
#sample size: 202
sample_means_home.append(sample_mean)
len(sample_means_home) #should be 1000
结论
测试 1:主队与客队的胜率
**结论:**否决 H0,赞成哈。主队和客场队的胜率有显著差异。主场优势肯定是存在的!下面是我们在假设检验之外创建的一个简单的可视化图,以说明团队和整体数据的情况:
Most teams tend to win more on their home field
测试 2:4–4–2 与 4–3–3 的成功率
**结论:**拒绝 H0,赞成哈。4–4–2 和 4–3–3 的胜率有显著差异。根据我们的数据,就胜率而言,4–4–2 是更好的阵型,尽管我们可以用更多的样本和/或更大的阵型平均得分差异来进行更强的测试。胜率。
4–4–2 is better on average, but our low power metric (0.67) indicates Type II risk
测试 3:防守侵略性评级(英超 vs 法甲)
**结论:**拒绝 H0,附带告诫。平均成绩似乎有所不同。英格兰队对法国队的防守侵略性评级(EA Sports),但我们的测试缺乏力量(冒着 II 型错误的风险)。我们不能自信地说 avg 真的有差别。联赛间的防守侵略。我们将能够用更多的样本和/或联盟平均值之间的更大差异来运行更强的测试。
测试 4:射门机会创造评级(英超 vs 法甲)
**结论:**拒绝 H0,附带警告。平均成绩似乎有所不同。英格兰队对法国队的投篮机会创造评级(EA Sports),但我们的测试缺乏动力(冒着 II 型错误的风险)。我们不能自信地说平均成绩有真正的差异。联赛间的投篮机会创造能力。我们将能够用更多的样本和/或联盟平均值之间的更大差异来运行更强的测试。
感谢您阅读我们简单易懂的欧洲足球假设检验概述!