终于把机器学习中的超参数调优搞懂了!!
今天给大家分享机器学习中的一个关键概念,超参数调优
在了解什么是超参数调优之前,我们需要先区分一下什么是参数和超参数。
-
参数:是模型在训练过程中从数据中学习和优化得到的变量。例如,线性回归中的权重 和偏置 ,神经网络中的层间权重和偏置。
-
超参数:是在模型开始训练之前,需要人为设定的变量,它们控制着模型的结构和训练过程。超参数的值不会在训练过程中自动学习。例如,学习率、正则化系数、神经网络的层数与节点数。

程序员学长
关注推荐系统、计算广告、大数据技术领域,专注个人能力提升
662篇原创内容
公众号
超参数调优,又称超参数优化,是机器学习领域一个至关重要的环节。
它指的是选择一组最优的超参数,使得机器学习模型在验证集上的性能指标(如准确率、F1分数、均方误差等)达到最佳的过程。

为什么需要超参数调优
-
模型性能的关键
超参数对模型的性能有着至关重要的影响。不同的超参数组合可以导致模型从欠拟合(Underfitting)到过拟合(Overfitting)的巨大差异。
-
训练效率:某些超参数(如学习率、批次大小)直接影响训练的速度和收敛性。
-
泛化能力:调优有助于平衡模型的偏差(Bias)和方差(Variance),找到一个既能很好地拟合训练数据,又具有强大泛化能力(在未见过的数据上表现良好)的模型。
常见的超参数调优方法
1.网格搜索
网格搜索是最简单、最基础的超参数调优方法。它预先为每个待调优的超参数设定一个有限的、离散的取值集合。
然后,它会穷举所有这些超参数取值集合的笛卡尔积,生成所有可能的超参数组合。
对于每一种组合,模型都会用交叉验证进行训练和评估。最终,选择性能最佳的那组超参数。

步骤
-
定义每个超参数的取值列表。
-
生成所有可能的组合(形成一个“网格”)。
-
遍历网格中的每一点
-
使用该点对应的超参数组合训练模型。
-
在验证集上或通过交叉验证评估模型性能。
-
-
返回性能最佳的超参数组合。
优点
-
简单易懂,易于实现。
-
如果最优解位于网格点上,一定能找到。
缺点
-
计算开销巨大:随着超参数数量(维度)和每个参数取值数量的增加,搜索空间呈指数级增长,导致训练时间过长。
-
效率低下:它在每个维度上都是“均匀”地搜索,很多计算资源可能浪费在模型性能很差的区域。如果最优值落在两个网格点之间,它也无法找到。
import numpy as np
from scipy.stats import randint, uniform
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV, train_test_split
from sklearn.metrics import accuracy_score
# 1. 加载数据
iris = load_iris()
X, y = iris.data, iris.target
# 2. 划分训练集和测试集 (用于最终评估,调优过程使用交叉验证)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 3. 定义基础模型
model = RandomForestClassifier(random_state=42)
# 4. 交叉验证折数
cv_folds = 5
print("--- 1. 网格搜索 (Grid Search) 示例 ---")
# 定义超参数网格
# n_estimators: 树的数量
# max_depth: 树的最大深度
param_grid_gs = {
'n_estimators': [50, 100, 200], # 3个取值
'max_depth': [5, 10, None], # 3个取值
'criterion': ['gini', 'entropy'] # 2个取值
}
# 总组合数: 3 * 3 * 2 = 18 种组合
# 初始化 GridSearchCV
grid_search = GridSearchCV(
estimator=model, # 待优化的模型
param_grid=param_grid_gs, # 超参数网格
scoring='accuracy', # 评估指标
cv=cv_folds, # 交叉验证折数
verbose=1, # 详细输出
n_jobs=-1 # 使用所有核心进行并行计算
)
# 开始训练和搜索
grid_search.fit(X_train, y_train)
# 输出结果
print("\n网格搜索最优参数:", grid_search.best_params_)
print("网格搜索最佳交叉验证分数: {:.4f}".format(grid_search.best_score_))
# 使用最优参数在测试集上评估
best_model_gs = grid_search.best_estimator_
y_pred_gs = best_model_gs.predict(X_test)
print("测试集准确率: {:.4f}".format(accuracy_score(y_test, y_pred_gs)))
2.随机搜索
随机搜索不像网格搜索那样对所有组合进行遍历。它为每个超参数定义一个连续或离散的取值范围(分布)。
然后,在给定的预算(如迭代次数或总时间)内,随机采样超参数组合,并评估模型性能。

为什么有效
有研究表明,在许多情况下,少数几个超参数对最终性能的影响远大于其他超参数。
随机搜索倾向于更密集地探索少数重要超参数的不同值,而不是均匀地探索整个高维空间。
这意味着在相同的计算预算下,随机搜索很大概率比网格搜索找到更好的结果。
步骤
-
定义每个超参数的搜索范围(可以是离散集合或连续分布)。
-
设定总共尝试的次数 。
-
重复 次
-
从每个超参数的分布中随机采样,形成一组超参数组合。
-
使用该组合训练和评估模型。
-
-
返回性能最佳的超参数组合。
优点
-
效率更高:相比网格搜索,随机搜索在大多数情况下能更快地找到接近最优的解。
-
易于实现:同样简单,且只需设置一个总次数 ,不依赖于参数数量。
缺点
-
无法保证最优:由于是随机采样,它不能保证找到全局最优解。
print("\n--- 2. 随机搜索 (Random Search) 示例 ---")
# 定义超参数分布
# n_estimators: 在 50 到 250 之间随机取整数
# max_depth: 在 3 到 20 之间随机取整数 (或 None)
# min_samples_split: 在 2 到 11 之间随机取整数
param_dist_rs = {
'n_estimators': randint(50, 250),
'max_depth': randint(3, 20),
'min_samples_split': randint(2, 11),
'max_features': uniform(0.5, 0.5) # 在 0.5 到 0.5+0.5=1.0 之间随机取浮点数
}
# 设定采样的组合数量
n_iter_search = 20
# 初始化 RandomizedSearchCV
random_search = RandomizedSearchCV(
estimator=model,
param_distributions=param_dist_rs, # 超参数分布
n_iter=n_iter_search, # 采样的组合数
scoring='accuracy',
cv=cv_folds,
verbose=1,
random_state=42, # 保证结果可复现
n_jobs=-1
)
# 开始训练和搜索
random_search.fit(X_train, y_train)
# 输出结果
print("\n随机搜索最优参数:", random_search.best_params_)
print("随机搜索最佳交叉验证分数: {:.4f}".format(random_search.best_score_))
# 使用最优参数在测试集上评估
best_model_rs = random_search.best_estimator_
y_pred_rs = best_model_rs.predict(X_test)
print("测试集准确率: {:.4f}".format(accuracy_score(y_test, y_pred_rs)))
3.贝叶斯优化
贝叶斯优化是一种基于模型的优化方法,它旨在用尽可能少的评估次数找到全局最优解。
它通过构建一个代理模型来近似目标函数 ,并利用采集函数指导下一次采样,使搜索更加智能。

-
代理模型
根据已有的历史评估结果(超参数和对应性能),用于拟合超参数配置与模型性能之间的未知函数关系。
常用的代理模型是高斯过程,它能提供关于预测值的不确定性估计。
-
采集函数
基于代理模型的预测,它决定了下一次应该评估哪个超参数组合。
采集函数的目标是平衡探索(在不确定性高的区域采样)和利用(在预测性能好的区域采样)。
常见的采集函数有:预期提升、概率提升和上下置信界等。
步骤
-
初始采样:随机选择若干组超参数 ,计算其性能 ;
-
建立代理模型:利用已观测数据 拟合一个概率模型(如高斯过程);
-
计算采集函数:找到使采集函数最大化的超参数组合 。
-
评估:在 上训练模型并获得真实的性能 。
-
更新: 将 加入历史评估结果集。
-
重复步骤 2-5 直到达到停止条件。
优点
-
效率极高:尤其适用于评估成本高昂(训练时间长)的复杂模型。它倾向于用更少的迭代次数找到最优解。
-
智能搜索:能够根据历史信息进行有目的地搜索。
缺点
-
实现复杂:比网格搜索和随机搜索复杂得多,理解和实现贝叶斯优化更为复杂。
from bayes_opt import BayesianOptimization
# 1. 定义目标函数:将超参数配置转换为模型性能指标
def rf_cv_score(n_estimators, max_depth, min_samples_split):
"""
贝叶斯优化将尝试最大化此函数的返回值。
注意:超参数必须以浮点数形式传递,需要在函数内部转换为整数(如果需要)。
"""
# 转换超参数类型
n_estimators = int(n_estimators)
max_depth = int(max_depth)
min_samples_split = int(min_samples_split)
# 定义模型
model_bo = RandomForestClassifier(
n_estimators=n_estimators,
max_depth=max_depth,
min_samples_split=min_samples_split,
random_state=42,
n_jobs=-1
)
# 执行交叉验证
from sklearn.model_selection import cross_val_score
score = cross_val_score(model_bo, X_train, y_train, cv=cv_folds, scoring='accuracy').mean()
return score
# 2. 定义超参数搜索范围 (pbounds: Parameter Bounds)
# n_estimators: [50, 250]
# max_depth: [3, 20]
# min_samples_split: [2, 11]
pbounds = {
'n_estimators': (50, 250),
'max_depth': (3, 20),
'min_samples_split': (2, 11),
}
# 3. 初始化贝叶斯优化器
optimizer = BayesianOptimization(
f=rf_cv_score, # 目标函数
pbounds=pbounds, # 搜索范围
random_state=42,
verbose=0 # 设置为 0 则不打印每次迭代的详细信息
)
# 4. 开始优化
# init_points: 初始随机探索的次数
# n_iter: 贝叶斯优化迭代的次数 (利用代理模型进行智能探索)
optimizer.maximize(
init_points=5,
n_iter=15
)
# 输出结果
print("\n贝叶斯优化最优参数:", optimizer.max['params'])
print("贝叶斯优化最佳交叉验证分数: {:.4f}".format(optimizer.max['target']))
# 提取最优参数并四舍五入
best_params_bo = {k: int(v) if k in ['n_estimators', 'max_depth', 'min_samples_split'] else v
for k, v in optimizer.max['params'].items()}
# 使用最优参数在测试集上评估
best_model_bo = RandomForestClassifier(**best_params_bo, random_state=42)
best_model_bo.fit(X_train, y_train)
y_pred_bo = best_model_bo.predict(X_test)
print("测试集准确率: {:.4f}".format(accuracy_score(y_test, y_pred_bo)))
更多推荐


所有评论(0)