第57课 - 网格搜索超参数调优
学习目标
通过本课学习,你将能够:
- 理解什么是超参数(Hyperparameter),并区分它与模型参数(Parameter)。
- 掌握网格搜索(Grid Search)的基本原理及其在模型调优中的作用。
- 使用 Scikit-learn 库中的
GridSearchCV函数实现模型超参数的系统化搜索。 - 分析网格搜索的结果,并选择出最优的参数组合。
- 了解网格搜索的优缺点及其适用场景。
核心概念
在机器学习中,模型的性能不仅取决于算法本身,还极度依赖于超参数的设置。你可以将超参数想象成学习计划中的“宏观策略”,例如:
- 学习率 (learning_rate):决定每一步学习时更新知识的幅度。
- 正则化强度 (C, alpha):防止模型“死记硬背”(过拟合)的严厉程度。
- 树的深度 (max_depth):在基于树的模型中,允许决策“分叉”的复杂程度。
与模型参数(如线性回归的权重和偏置)不同,超参数不能在训练过程中自动学习,需要我们在训练开始前人为指定。设置不同的超参数,会训练出性能迥异的模型。
网格搜索是一种最直观的超参数调优方法。它的核心思想是“穷举”。你为每个想要尝试的超参数设定一个候选值列表(一个“网格”),然后算法会遍历这些值的所有可能组合,为每一种组合训练一个模型,并在交叉验证中评估其性能。最后,返回在验证集上得分最高的那组参数。
这个过程可以概括为:
- 定义网格:为你关心的超参数设定多个可能的值。
- 穷举组合:计算所有值的排列组合。
- 训练与评估:使用每一组参数训练模型,并通过交叉验证得到评估分数。
- 选择最优:挑选出平均验证分数最高的参数组合。
代码示例
下面是一个使用Scikit-learn对支持向量机(SVM)分类器进行网格搜索调优的完整示例。
# 1. 导入必要的库
from sklearn.datasets import load_iris
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
import numpy as np
# 2. 加载并准备数据
iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 3. 创建模型流水线(推荐做法:先标准化,再建模)
pipeline = make_pipeline(StandardScaler(), SVC(random_state=42))
# 4. 定义要搜索的超参数网格
# 注意:参数名称的格式是 `小写步骤名__参数名`
# `svc` 是流水线中SVC步骤的名称(小写),`C` 和 `gamma` 是SVC的参数。
param_grid = {
'svc__C': [0.1, 1, 10, 100], # 正则化参数
'svc__gamma': [1, 0.1, 0.01, 0.001], # 核函数系数(RBF核)
'svc__kernel': ['rbf', 'linear'] # 核函数类型
}
# 这个网格共有:4 * 4 * 2 = 32 种参数组合。
# 5. 实例化GridSearchCV对象
grid_search = GridSearchCV(estimator=pipeline,
param_grid=param_grid,
cv=5, # 5折交叉验证
scoring='accuracy', # 使用准确率作为评估指标
verbose=1, # 打印搜索过程
n_jobs=-1) # 使用所有CPU核心并行计算
# 6. 在训练集上执行网格搜索
grid_search.fit(X_train, y_train)
# 7. 分析结果
print("最佳参数组合:", grid_search.best_params_)
print("最佳交叉验证准确率:", grid_search.best_score_)
# 8. 使用最佳模型在测试集上进行最终评估
best_model = grid_search.best_estimator_
test_score = best_model.score(X_test, y_test)
print("测试集准确率:", test_score)
# (可选)查看所有参数组合的搜索结果
import pandas as pd
results = pd.DataFrame(grid_search.cv_results_)
print("\n部分搜索结果预览:")
print(results[['params', 'mean_test_score', 'rank_test_score']].sort_values('rank_test_score').head())
输出示例:
Fitting 5 folds for each of 32 candidates, totalling 160 fits
最佳参数组合: {'svc__C': 10, 'svc__gamma': 0.1, 'svc__kernel': 'rbf'}
最佳交叉验证准确率: 0.9666666666666668
测试集准确率: 1.0
部分搜索结果预览:
params mean_test_score rank_test_score
5 {'svc__C': 1, 'svc__gamma': 0.1, 'svc__kernel... 0.966667 1
...
实践练习
练习1:基础网格搜索 使用鸢尾花数据集,对K近邻(KNN)分类器进行调优。
- 要求:调整
n_neighbors(尝试1, 3, 5, 7, 9) 和weights(尝试uniform,distance) 两个参数。 - 预期输出:打印出最佳参数、最佳交叉验证分数和测试集分数。
练习2:加入预处理的流水线
对糖尿病数据集(sklearn.datasets.load_diabetes)的回归任务进行调优。
- 要求:
- 使用
Ridge回归器。 - 创建一个包含
StandardScaler和Ridge的流水线。 - 对
Ridge的alpha参数进行网格搜索(尝试[0.01, 0.1, 1, 10, 100])。 - 使用均方误差(
neg_mean_squared_error)作为评分函数。
- 使用
- 预期输出:最佳
alpha值和最佳(负)均方误差分数。
练习3:理解计算成本
思考并回答:在上述SVM调优示例中,我们使用了5折交叉验证和32种参数组合。请问GridSearchCV总共训练了多少个模型?如果换用10折交叉验证,总模型数会变成多少?
常见错误
- 参数网格名称错误:在使用流水线时,容易忘记在参数名前加
步骤名__。例如,将'svc__C'写成'C',会导致错误或调优无效。 - 评分函数选择不当:分类问题误用回归评分函数(如
r2),或回归问题使用分类指标(如accuracy)。应根据任务类型选择合适的scoring(例如分类:accuracy,f1;回归:neg_mean_squared_error,r2)。 - 忽视计算成本:网格搜索的复杂度随参数数量和候选值数量呈指数级增长。如果网格太密、维度太高,可能导致运行时间过长甚至无法完成。应先粗调,再细调。
- 在验证集上过拟合:严格来说,我们选择最佳模型依据的是交叉验证的平均分数,而不是在单独划分的测试集上的分数。测试集应该仅用于最终、一次性的评估,以避免信息泄露和对测试集的过拟合。
- 混淆模型参数与超参数:试图用网格搜索调优模型内部的参数(如神经网络各层的权重),这些参数是训练得到的,不是搜索的对象。
小结
本节课我们学习了机器学习中至关重要的超参数调优技术——网格搜索。
- 核心要点:
- 超参数是人为设定的、影响模型学习过程的“旋钮”。
- 网格搜索通过穷举所有参数组合,并结合交叉验证来寻找最优超参数配置。
- 使用
GridSearchCV可以方便地实现这一流程,它返回的最佳模型best_estimator_可以直接用于预测。 - 该方法简单、直观,但计算成本高,尤其在参数空间较大时。
网格搜索是超参数调优的基石。在下一课中,我们将学习随机搜索和贝叶斯优化,它们是应对高维参数空间和更高计算效率需求的更高级策略。
练习编辑器
rust
Loading...