机器学习算法有超参数,允许算法针对特定数据集进行调整。
尽管超参数的影响通常可以理解,但它们对数据集的具体影响以及学习过程中的相互作用可能不为人知。因此,作为机器学习项目的一部分,调整算法超参数的值非常重要。
通常使用朴素优化算法来调整超参数,例如网格搜索和随机搜索。另一种方法是使用随机优化算法,如随机爬山算法。
在本教程中,您将学习如何手动优化机器学习算法的超参数。
完成本教程后,您将了解:
- 随机优化算法可以代替网格搜索和随机搜索用于超参数优化。
- 如何使用随机爬山算法调整感知器算法的超参数。
- 如何手动优化XGBoost梯度提升算法的超参数。
我的新书《机器学习优化》将助您启动项目,书中包含分步教程和所有示例的Python源代码文件。
让我们开始吧。
如何手动优化机器学习模型超参数
图片来源:john farrell macdonald,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 手动超参数优化
- 感知器超参数优化
- XGBoost超参数优化
手动超参数优化
机器学习模型具有您必须设置的超参数,以根据您的数据集自定义模型。
通常,超参数对模型的一般影响是已知的,但如何为给定数据集最佳设置超参数以及相互作用的超参数组合则具有挑战性。
一种更好的方法是客观地搜索模型超参数的不同值,并选择一个子集,使模型在给定数据集上达到最佳性能。这称为超参数优化或超参数调整。
可以使用一系列不同的优化算法,尽管其中两种最简单和最常见的方法是随机搜索和网格搜索。
- 随机搜索。将搜索空间定义为超参数值的有界域,并从该域中随机采样点。
- 网格搜索。将搜索空间定义为超参数值的网格,并评估网格中的每个位置。
网格搜索非常适合对已知表现良好的组合进行抽查。随机搜索非常适合发现和获取您凭直觉无法猜到的超参数组合,尽管它通常需要更多执行时间。
有关超参数调整的网格搜索和随机搜索的更多信息,请参阅教程
网格搜索和随机搜索是原始优化算法,我们可以使用任何我们喜欢的优化算法来调整机器学习算法的性能。例如,可以使用随机优化算法。当需要良好或出色性能且有足够资源可用于调整模型时,这可能是可取的。
接下来,让我们看看如何使用随机爬山算法来调整感知器算法的性能。
想要开始学习优化算法吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
感知器超参数优化
感知器算法是最简单的人工神经网络类型。
它是一个单神经元模型,可用于两类分类问题,并为以后开发更大的网络奠定基础。
在本节中,我们将探讨如何手动优化感知器模型的超参数。
首先,让我们定义一个合成的二元分类问题,我们可以将其作为优化模型的重点。
我们可以使用make_classification()函数来定义一个包含1000行和五个输入变量的二元分类问题。
以下示例创建数据集并总结数据的形状。
1 2 3 4 5 6 |
# 定义一个二元分类数据集 from sklearn.datasets import make_classification # 定义数据集 X, y = make_classification(n_samples=1000, n_features=5, n_informative=2, n_redundant=1, random_state=1) # 总结数据集的形状 print(X.shape, y.shape) |
运行示例会打印创建数据集的形状,证实了我们的预期。
1 |
(1000, 5) (1000,) |
scikit-learn通过Perceptron类提供了感知器模型的实现。
在调整模型超参数之前,我们可以使用默认超参数建立性能基线。
我们将使用RepeatedStratifiedKFold类通过重复分层k折交叉验证的最佳实践来评估模型。
以下列出了使用默认超参数在我们的合成二元分类数据集上评估感知器模型的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# 感知器二元分类的默认超参数 from numpy import mean from numpy import std from sklearn.datasets import make_classification from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedStratifiedKFold from sklearn.linear_model import Perceptron # 定义数据集 X, y = make_classification(n_samples=1000, n_features=5, n_informative=2, n_redundant=1, random_state=1) # 定义模型 model = Perceptron() # 定义评估过程 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) # 评估模型 scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) # 报告结果 print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores))) |
运行该示例会评估模型并报告分类准确性的平均值和标准差。
注意:由于算法或评估过程的随机性或数值精度的差异,您的结果可能会有所不同。考虑多次运行示例并比较平均结果。
在这种情况下,我们可以看到默认超参数的模型达到了约78.5%的分类准确率。
我们希望通过优化超参数,能够实现比这更好的性能。
1 |
平均准确率:0.786 (0.069) |
接下来,我们可以使用随机爬山算法优化感知器模型的超参数。
我们可以优化许多超参数,尽管我们将重点关注两个可能对模型学习行为影响最大的参数:
- 学习率 (eta0)。
- 正则化 (alpha)。
学习率控制模型根据预测误差更新的程度,并控制学习速度。 eta 的默认值为 1.0。合理的值大于零(例如,大于 1e-8 或 1e-10),并且可能小于 1.0
默认情况下,感知器不使用任何正则化,但我们将启用“弹性网络”正则化,它在学习过程中同时应用L1和L2正则化。这将鼓励模型寻找较小的模型权重,进而通常会获得更好的性能。
我们将调整“alpha”超参数,该参数控制正则化的权重,即其对学习的影响程度。如果设置为 0.0,则表示未使用正则化。合理的值介于 0.0 和 1.0 之间。
首先,我们需要为优化算法定义目标函数。我们将使用重复分层k折交叉验证通过平均分类精度评估配置。我们将力求在配置中最大化精度。
下面的objective()函数实现了这一点,它接收数据集和配置值列表。配置值(学习率和正则化权重)被解包,用于配置模型,然后评估模型,并返回平均精度。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# 目标函数 def objective(X, y, cfg): # 解包配置 eta, alpha = cfg # 定义模型 model = Perceptron(penalty='elasticnet', alpha=alpha, eta0=eta) # 定义评估过程 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) # 评估模型 scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) # 计算平均精度 result = mean(scores) return result |
接下来,我们需要一个函数来在搜索空间中迈出一步。
搜索空间由两个变量(eta 和 alpha)定义。搜索空间中的一步必须与先前的值有某种关系,并且必须限制在合理的值(例如,0 到 1 之间)。
我们将使用一个“步长”超参数,它控制算法允许从现有配置移动的距离。新配置将使用高斯分布以概率方式选择,其中当前值作为分布的均值,步长作为分布的标准差。
我们可以使用randn() NumPy 函数生成具有高斯分布的随机数。
下面的 step() 函数实现了这一点,它将在搜索空间中迈出一步,并使用现有配置生成新配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# 在搜索空间中迈出一步 def step(cfg, step_size): # 解包配置 eta, alpha = cfg # 步进 eta new_eta = eta + randn() * step_size # 检查 eta 的边界 if new_eta <= 0.0: new_eta = 1e-8 # 步进 alpha new_alpha = alpha + randn() * step_size # 检查 alpha 的边界 if new_alpha < 0.0: new_alpha = 0.0 # 返回新配置 return [new_eta, new_alpha] |
接下来,我们需要实现随机爬山算法,该算法将调用我们的 objective() 函数来评估候选解决方案,并调用我们的 step() 函数来在搜索空间中迈出一步。
搜索首先生成一个随机初始解决方案,在本例中,eta 和 alpha 值在 0 到 1 之间。然后评估初始解决方案,并将其作为当前最佳工作解决方案。
1 2 3 4 5 |
... # 搜索的起始点 solution = [rand(), rand()] # 评估初始点 solution_eval = objective(X, y, solution) |
接下来,算法会迭代固定次数,作为搜索的超参数提供。每次迭代都涉及迈出一步并评估新的候选解决方案。
1 2 3 4 5 |
... # 迈出一步 candidate = step(solution, step_size) # 评估候选点 candidate_eval = objective(X, y, candidate) |
如果新解决方案优于当前工作解决方案,则将其作为新的当前工作解决方案。
1 2 3 4 5 6 7 |
... # 检查是否应该保留新点 if candidate_eval >= solution_eval: # 存储新点 solution, solution_eval = candidate, candidate_eval # 报告进度 print('>%d, cfg=%s %.5f' % (i, solution, solution_eval)) |
在搜索结束时,返回最佳解决方案及其性能。
将所有这些联系起来,下面的 hillclimbing() 函数实现了随机爬山算法,用于调整感知器算法,它将数据集、目标函数、迭代次数和步长作为参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 爬山局部搜索算法 def hillclimbing(X, y, objective, n_iter, step_size): # 搜索的起始点 solution = [rand(), rand()] # 评估初始点 solution_eval = objective(X, y, solution) # 运行爬山算法 for i in range(n_iter): # 迈出一步 candidate = step(solution, step_size) # 评估候选点 candidate_eval = objective(X, y, candidate) # 检查是否应该保留新点 if candidate_eval >= solution_eval: # 存储新点 solution, solution_eval = candidate, candidate_eval # 报告进度 print('>%d, cfg=%s %.5f' % (i, solution, solution_eval)) return [solution, solution_eval] |
然后我们可以调用算法并报告搜索结果。
在这种情况下,我们将算法运行100次迭代,并使用0.1的步长,这是经过一些尝试和错误后选择的。
1 2 3 4 5 6 7 8 9 |
... # 定义总迭代次数 n_iter = 100 # 搜索空间中的步长 step_size = 0.1 # 执行爬山搜索 cfg, score = hillclimbing(X, y, objective, n_iter, step_size) print('Done!') print('cfg=%s: Mean Accuracy: %f' % (cfg, score)) |
将这些结合起来,下面列出了手动调整感知器算法的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# 手动搜索感知器超参数以进行二元分类 from numpy import mean from numpy.random import randn from numpy.random import rand from sklearn.datasets import make_classification from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedStratifiedKFold from sklearn.linear_model import Perceptron # 目标函数 def objective(X, y, cfg): # 解包配置 eta, alpha = cfg # 定义模型 model = Perceptron(penalty='elasticnet', alpha=alpha, eta0=eta) # 定义评估过程 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) # 评估模型 scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) # 计算平均精度 result = mean(scores) return result # 在搜索空间中迈出一步 def step(cfg, step_size): # 解包配置 eta, alpha = cfg # 步进 eta new_eta = eta + randn() * step_size # 检查 eta 的边界 if new_eta <= 0.0: new_eta = 1e-8 # 步进 alpha new_alpha = alpha + randn() * step_size # 检查 alpha 的边界 if new_alpha < 0.0: new_alpha = 0.0 # 返回新配置 return [new_eta, new_alpha] # 爬山局部搜索算法 def hillclimbing(X, y, objective, n_iter, step_size): # 搜索的起始点 solution = [rand(), rand()] # 评估初始点 solution_eval = objective(X, y, solution) # 运行爬山算法 for i in range(n_iter): # 迈出一步 candidate = step(solution, step_size) # 评估候选点 candidate_eval = objective(X, y, candidate) # 检查是否应该保留新点 if candidate_eval >= solution_eval: # 存储新点 solution, solution_eval = candidate, candidate_eval # 报告进度 print('>%d, cfg=%s %.5f' % (i, solution, solution_eval)) return [solution, solution_eval] # 定义数据集 X, y = make_classification(n_samples=1000, n_features=5, n_informative=2, n_redundant=1, random_state=1) # 定义总迭代次数 n_iter = 100 # 搜索空间中的步长 step_size = 0.1 # 执行爬山搜索 cfg, score = hillclimbing(X, y, objective, n_iter, step_size) print('Done!') print('cfg=%s: Mean Accuracy: %f' % (cfg, score)) |
运行示例会在搜索过程中每次看到改进时报告配置和结果。在运行结束时,将报告最佳配置和结果。
注意:由于算法或评估过程的随机性或数值精度的差异,您的结果可能会有所不同。考虑多次运行示例并比较平均结果。
在这种情况下,我们可以看到最佳结果是使用略高于 1 的学习率 1.004 和大约 0.002 的正则化权重,平均准确率达到约 79.1%,优于默认配置的 78.5% 准确率。
你能取得更好的结果吗?
在下面的评论中告诉我。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
>0, cfg=[0.5827274503894747, 0.260872709578015] 0.70533 >4, cfg=[0.5449820307807399, 0.3017271170801444] 0.70567 >6, cfg=[0.6286475606495414, 0.17499090243915086] 0.71933 >7, cfg=[0.5956196828965779, 0.0] 0.78633 >8, cfg=[0.5878361167354715, 0.0] 0.78633 >10, cfg=[0.6353507984485595, 0.0] 0.78633 >13, cfg=[0.5690530537610675, 0.0] 0.78633 >17, cfg=[0.6650936023999641, 0.0] 0.78633 >22, cfg=[0.9070451625704087, 0.0] 0.78633 >23, cfg=[0.9253366187387938, 0.0] 0.78633 >26, cfg=[0.9966143540220266, 0.0] 0.78633 >31, cfg=[1.0048613895650054, 0.002162219228449132] 0.79133 完成! cfg=[1.0048613895650054, 0.002162219228449132]: 平均准确率: 0.791333 |
现在我们已经熟悉了如何使用随机爬山算法调整简单机器学习算法的超参数,接下来让我们看看如何调整更高级的算法,例如XGBoost。
XGBoost超参数优化
XGBoost 是 Extreme Gradient Boosting 的缩写,是随机梯度提升机器学习算法的高效实现。
随机梯度提升算法,也称为梯度提升机或树提升,是一种强大的机器学习技术,在各种具有挑战性的机器学习问题上表现良好甚至最佳。
首先,必须安装 XGBoost 库。
您可以使用 pip 进行安装,如下所示
1 |
sudo pip install xgboost |
安装完成后,您可以通过运行以下代码来确认是否成功安装以及您使用的是否是新版本
1 2 3 |
# xgboost import xgboost print("xgboost", xgboost.__version__) |
运行代码后,您应该会看到以下版本号或更高。
1 |
xgboost 1.0.1 |
尽管 XGBoost 库有其自己的 Python API,但我们可以通过 XGBClassifier 包装器类将 XGBoost 模型与 scikit-learn API 一起使用。
模型的实例可以实例化并像任何其他 scikit-learn 类一样用于模型评估。例如
1 2 3 |
... # 定义模型 model = XGBClassifier() |
在调整 XGBoost 的超参数之前,我们可以使用默认超参数建立性能基线。
我们将使用上一节中相同的合成二元分类数据集和相同的重复分层 k 折交叉验证测试工具。
以下列出了使用默认超参数评估 XGBoost 性能的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# 具有默认超参数的XGBoost二元分类 from numpy import mean from numpy import std from sklearn.datasets import make_classification from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedStratifiedKFold from xgboost import XGBClassifier # 定义数据集 X, y = make_classification(n_samples=1000, n_features=5, n_informative=2, n_redundant=1, random_state=1) # 定义模型 model = XGBClassifier() # 定义评估过程 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) # 评估模型 scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) # 报告结果 print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores))) |
运行示例会评估模型并报告分类准确率的平均值和标准差。
注意:由于算法或评估过程的随机性或数值精度的差异,您的结果可能会有所不同。考虑多次运行示例并比较平均结果。
在这种情况下,我们可以看到具有默认超参数的模型达到了约 84.9% 的分类准确率。
我们希望通过优化超参数,能够实现比这更好的性能。
1 |
平均准确率:0.849 (0.040) |
接下来,我们可以调整随机爬山优化算法来调整 XGBoost 模型的超参数。
XGBoost 模型有许多我们可能想要优化的超参数。
有关如何调整 XGBoost 模型的概述,请参阅教程
我们将重点关注四个关键超参数:它们是
- 学习率 (learning_rate)
- 树的数量 (n_estimators)
- 子样本百分比 (subsample)
- 树深度 (max_depth)
学习率控制每棵树对集成模型的贡献。合理的值小于 1.0 且略高于 0.0(例如 1e-8)。
树的数量控制集成模型的大小,通常情况下,更多的树在收益递减点之前会更好。合理的值介于 1 棵树和数百或数千棵树之间。
子样本百分比定义了用于训练每棵树的随机样本大小,以原始数据集大小的百分比表示。值介于略高于 0.0(例如 1e-8)和 1.0 之间
树深度是每棵树的层数。更深的树更具体于训练数据集,可能会过拟合。较短的树通常泛化能力更好。合理的值介于 1 到 10 或 20 之间。
首先,我们必须更新 objective() 函数,以解包 XGBoost 模型的超参数,对其进行配置,然后评估平均分类准确率。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# 目标函数 def objective(X, y, cfg): # 解包配置 lrate, n_tree, subsam, depth = cfg # 定义模型 model = XGBClassifier(learning_rate=lrate, n_estimators=n_tree, subsample=subsam, max_depth=depth) # 定义评估过程 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) # 评估模型 scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) # 计算平均精度 result = mean(scores) return result |
接下来,我们需要定义用于在搜索空间中迈出一步的 step() 函数。
每个超参数的范围都大不相同,因此,我们将为每个超参数单独定义步长(分布的标准差)。为了简单起见,我们还将直接在函数中定义步长,而不是作为函数的参数。
树的数量和深度都是整数,因此步进值四舍五入。
所选的步长是任意的,经过一些尝试和错误后选定。
更新后的步进函数如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# 在搜索空间中迈出一步 def step(cfg): # 解包配置 lrate, n_tree, subsam, depth = cfg # 学习率 lrate = lrate + randn() * 0.01 if lrate <= 0.0: lrate = 1e-8 if lrate > 1: lrate = 1.0 # 树的数量 n_tree = round(n_tree + randn() * 50) if n_tree <= 0.0: n_tree = 1 # 子样本百分比 subsam = subsam + randn() * 0.1 if subsam <= 0.0: subsam = 1e-8 if subsam > 1: subsam = 1.0 # 最大树深度 depth = round(depth + randn() * 7) if depth <= 1: depth = 1 # 返回新配置 return [lrate, n_tree, subsam, depth] |
最后,必须更新 hillclimbing() 算法以定义具有适当值的初始解决方案。
在这种情况下,我们将使用合理的默认值定义初始解决方案,与默认超参数匹配或接近。
1 2 3 |
... # 搜索的起始点 solution = step([0.1, 100, 1.0, 7]) |
将这些结合起来,下面列出了使用随机爬山算法手动调整 XGBoost 算法超参数的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# XGBoost二元分类的手动超参数优化 from numpy import mean from numpy.random import randn from numpy.random import rand from numpy.random import randint from sklearn.datasets import make_classification from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedStratifiedKFold from xgboost import XGBClassifier # 目标函数 def objective(X, y, cfg): # 解包配置 lrate, n_tree, subsam, depth = cfg # 定义模型 model = XGBClassifier(learning_rate=lrate, n_estimators=n_tree, subsample=subsam, max_depth=depth) # 定义评估过程 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) # 评估模型 scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) # 计算平均精度 result = mean(scores) return result # 在搜索空间中迈出一步 def step(cfg): # 解包配置 lrate, n_tree, subsam, depth = cfg # 学习率 lrate = lrate + randn() * 0.01 if lrate <= 0.0: lrate = 1e-8 if lrate > 1: lrate = 1.0 # 树的数量 n_tree = round(n_tree + randn() * 50) if n_tree <= 0.0: n_tree = 1 # 子样本百分比 subsam = subsam + randn() * 0.1 if subsam <= 0.0: subsam = 1e-8 if subsam > 1: subsam = 1.0 # 最大树深度 depth = round(depth + randn() * 7) if depth <= 1: depth = 1 # 返回新配置 return [lrate, n_tree, subsam, depth] # 爬山局部搜索算法 def hillclimbing(X, y, objective, n_iter): # 搜索的起始点 solution = step([0.1, 100, 1.0, 7]) # 评估初始点 solution_eval = objective(X, y, solution) # 运行爬山算法 for i in range(n_iter): # 迈出一步 candidate = step(solution) # 评估候选点 candidate_eval = objective(X, y, candidate) # 检查是否应该保留新点 if candidate_eval >= solution_eval: # 存储新点 solution, solution_eval = candidate, candidate_eval # 报告进度 print('>%d, cfg=[%s] %.5f' % (i, solution, solution_eval)) return [solution, solution_eval] # 定义数据集 X, y = make_classification(n_samples=1000, n_features=5, n_informative=2, n_redundant=1, random_state=1) # 定义总迭代次数 n_iter = 200 # 执行爬山搜索 cfg, score = hillclimbing(X, y, objective, n_iter) print('Done!') print('cfg=[%s]: Mean Accuracy: %f' % (cfg, score)) |
运行示例会在搜索过程中每次看到改进时报告配置和结果。在运行结束时,将报告最佳配置和结果。
注意:由于算法或评估过程的随机性或数值精度的差异,您的结果可能会有所不同。考虑多次运行示例并比较平均结果。
在这种情况下,我们可以看到最佳结果是使用大约 0.02 的学习率、52 棵树、大约 50% 的子样本率和 53 层的深度。
此配置的平均准确率约为 87.3%,优于默认配置的 84.9% 准确率。
你能取得更好的结果吗?
在下面的评论中告诉我。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
>0, cfg=[[0.1058242692126418, 67, 0.9228490731610172, 12]] 0.85933 >1, cfg=[[0.11060813799692253, 51, 0.859353656735739, 13]] 0.86100 >4, cfg=[[0.11890247679234153, 58, 0.7135275461723894, 12]] 0.86167 >5, cfg=[[0.10226257987735601, 61, 0.6086462443373852, 17]] 0.86400 >15, cfg=[[0.11176962034280596, 106, 0.5592742266405146, 13]] 0.86500 >19, cfg=[[0.09493587069112454, 153, 0.5049124222437619, 34]] 0.86533 >23, cfg=[[0.08516531024154426, 88, 0.5895201311518876, 31]] 0.86733 >46, cfg=[[0.10092590898175327, 32, 0.5982811365027455, 30]] 0.86867 >75, cfg=[[0.099469211050998, 20, 0.36372573610040404, 32]] 0.86900 >96, cfg=[[0.09021536590375884, 38, 0.4725379807796971, 20]] 0.86900 >100, cfg=[[0.08979482274655906, 65, 0.3697395430835758, 14]] 0.87000 >110, cfg=[[0.06792737273465625, 89, 0.33827505722318224, 17]] 0.87000 >118, cfg=[[0.05544969684589669, 72, 0.2989721608535262, 23]] 0.87200 >122, cfg=[[0.050102976159097, 128, 0.2043203965148931, 24]] 0.87200 >123, cfg=[[0.031493266763680444, 120, 0.2998819062922256, 30]] 0.87333 >128, cfg=[[0.023324201169625292, 84, 0.4017169945431015, 42]] 0.87333 >140, cfg=[[0.020224220443108752, 52, 0.5088096815056933, 53]] 0.87367 完成! cfg=[[0.020224220443108752, 52, 0.5088096815056933, 53]]: 平均准确率: 0.873667 |
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
教程
API
- sklearn.datasets.make_classification API.
- sklearn.metrics.accuracy_score API.
- numpy.random.rand API.
- sklearn.linear_model.Perceptron API.
文章
总结
在本教程中,您学习了如何手动优化机器学习算法的超参数。
具体来说,你学到了:
- 随机优化算法可以代替网格搜索和随机搜索用于超参数优化。
- 如何使用随机爬山算法调整感知器算法的超参数。
- 如何手动优化XGBoost梯度提升算法的超参数。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
再次感谢——非常容易理解和实验。
我尝试在循环中减小步长。出于某种原因,爬山算法在 etha = 0.009 的情况下得到了最好的结果
cfg=[0.00916649745512498, 0.012304975044232886]: 平均准确率: 0.844000
对于 XGBClassifier - 无论我做什么,都无法超越
cfg=[0.00779, 42, 0.5165, 174]: 平均准确率: 0.875667
太酷了!
干得好!
亲爱的杰森博士
如何通过应用回归手动优化机器学习模型超参数?
您可以直接将上述示例应用于回归问题。
谢谢 Jason。
变量名中的小错字:candidte_eval => candidate_eval
问题:当我们有多个维度时,我知道理论上可能会陷入局部最大值。在机器学习中进行这种超参数优化时,这种情况有多常见?这就是我一直害怕自己编写优化器的原因,我想内置库应该能处理这个问题。例如,如果你从许多随机的起始点开始,它们多久收敛到一个点,以及你多久得到不同的最大值?例如,我们会多次调用 hillclimbing()。
谢谢
威廉
谢谢,已修正。
这很常见。如果可能的话,多次运行搜索是个好主意。
这种黑箱爬山算法是一种非常简单的优化算法,除了“可能比没有好”之外,几乎没有其他保证。请记住,这里没有梯度,甚至没有考虑到算法后续运行的粗略估计。希望它能落入某个明显的斜坡并略微改善,但实际上很难知道它是否真的比网格或随机搜索有所改进。Bergstra 和 Bengio 有一篇很棒的论文对此进行了一些讨论:https://www.jmlr.org/papers/volume13/bergstra12a/bergstra12a.pdf
我很高兴发现这个页面。我必须感谢您为此付出的时间,特别是这篇精彩的阅读!我绝对非常喜欢它的每一部分,我也已经将您保存到收藏夹中,以便查看您网站上的新信息。
谢谢。
超参数搜索/确定和调整就像在巨大的沼泽中寻找旱地(或者在沼泽迷雾中盲飞)99% 的时间你都找不到它。它比中彩票头奖更难,因为蛮力方法确定的可能性太多了,由于非凸、非线性行为,浪费了大量时间和精力。机器学习的主要障碍就是“什么是正确的超参数”???另一个问题是这些工具不能使用/或在并行处理/硬件加速的使用中存在很大问题。一个人从一开始就面临着 HP 和 HP 问题。我尝试过 H20 AutoML,我可以说是扔掉了 60% AUC 的糟糕结果;对于相同的数据集,我有更好的手动解决方案。我花了几个月才通过蛮力方法找到它,但准确率仍然不够高,这就是神经网络的主要问题。为什么商业解决方案要好得多?为什么 ChatGPT 能工作?他们拥有一支由博士级工程师组成的军队来测试和尝试所有有希望的可能性,而单个人根本无法做到和测试。作为这个领域的新手,一个人会遇到巨大的问题才能掌握它,因为软件不发达,特别是开源软件,如果软件在体验和易用性上不能显着改进!创建神经网络是幼稚简单的,但从中获得结果是“不可能完成的任务”。这就是今天的现实和事实,无论别人怎么说。ChatGPT 可以在几秒钟内找到任何数据集的正确超参数,但遗憾的是你无法访问该服务的那部分。他们正在使用你的数据,而不是提供任何东西!