之前的文章中,我们进行了机器学习和深度学习的尝试,并提到过一个问题:模型的参数如何选择会对模型的效果产生非常大的影响,因此本节内容主要讨论如何找出模型的最优参数
首先,我们明确一个问题,一般来说,不会存在一组参数,能让模型适配所有的任务;因此,我们所说的模型最优参数,都是针对当前任务对应的数据集来说的,如果更换任务,甚至说更好输入模型的特征,都有可能导致模型的最优参数发生变化。
因此,调优是一个很繁琐的任务,不过现在有了很多封装好的工具包和ai,大大降低了任务难度,大家需要多运用这些工具
机器学习调优------随机搜索
(所谓调优,当然要先知道模型有哪些可以调整的参数,不知道就问ai)
python
# 1. RandomForest调参
print("调参RandomForest...")
param_dist_rf = {
'n_estimators': [100, 200, 300],
'max_depth': [None, 10, 20, 30],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4]
}
random_search_rf = RandomizedSearchCV(
RandomForestClassifier(random_state=42),
param_dist_rf,
n_iter=10,
cv=5,
random_state=42,
n_jobs=-1
)
random_search_rf.fit(X_train_scaled, y_train)
best_rf = random_search_rf.best_estimator_
saved_models.append(('RandomForest', best_rf, random_search_rf.best_score_))
print(f"RandomForest最佳CV分数: {random_search_rf.best_score_:.4f}")
# 2. DecisionTree调参
print("调参DecisionTree...")
param_dist_dt = {
'max_depth': [None, 10, 20, 30],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4],
'criterion': ['gini', 'entropy']
}
random_search_dt = RandomizedSearchCV(
DecisionTreeClassifier(random_state=42),
param_dist_dt,
n_iter=10,
cv=5,
random_state=42,
n_jobs=-1
)
random_search_dt.fit(X_train_scaled, y_train)
best_dt = random_search_dt.best_estimator_
saved_models.append(('DecisionTree', best_dt, random_search_dt.best_score_))
print(f"DecisionTree最佳CV分数: {random_search_dt.best_score_:.4f}")
这里仅介绍**RandomizedSearchCV(随机搜索交叉验证)** ,它是机器学习中高效、实用的超参数调优方法,核心是在指定超参数范围内随机采样组合,结合交叉验证筛选最优参数,专门解决网格搜索(GridSearchCV)参数组合过多、耗时过长的问题。
超参数调优的核心目标是找到一组超参数,让模型在未知数据上的泛化能力最优 ,RandomizedSearchCV 实现这一目标的逻辑分为 3 步:
- 定义参数空间 :为模型每个超参数指定一个待搜索的取值范围 / 列表(如随机森林的
n_estimators指定 [100,200,300]); - 随机采样参数组合 :从参数空间中随机抽取指定数量(
n_iter)的参数组合,而非遍历所有组合(这是和网格搜索的核心区别); - 交叉验证评估 :对每一组随机采样的参数,用K 折交叉验证(CV) 训练模型并计算验证分数,最终选择验证分数最高的参数组合作为最佳超参数,对应的模型为最佳估计器(best_estimator_)。
两者对比如下表,更能体现随机搜索的优势:
| 特性 | RandomizedSearchCV(随机搜索) | GridSearchCV(网格搜索) |
|---|---|---|
| 参数组合遍历方式 | 随机采样 n_iter 组 | 遍历所有组合 |
| 时间效率 | 高(采样数可控) | 低(组合数随参数维度指数增长) |
| 调优效果 | 接近最优(抽样覆盖关键组合) | 理论最优(遍历所有可能) |
| 适用场景 | 参数空间大、快速调优 | 参数空间小、追求极致调优 |
这里简要介绍一下代码内容,其实现在的ai写这种简单的调优已经很熟练了,完全可以交给ai



深度学习调优------Optuna (以MLP为例)
python
# 3. MLP调参 (Optuna)
print("调参MLP...")
# 定义TunedMLP类(全局)
class TunedMLP(nn.Module):
def __init__(self, input_size, dropout_rate):
super(TunedMLP, self).__init__()
self.fc1 = nn.Linear(input_size, 128)
self.bn1 = nn.BatchNorm1d(128)
self.dropout1 = nn.Dropout(dropout_rate)
self.fc2 = nn.Linear(128, 64)
self.bn2 = nn.BatchNorm1d(64)
self.dropout2 = nn.Dropout(dropout_rate)
self.fc3 = nn.Linear(64, 32)
self.bn3 = nn.BatchNorm1d(32)
self.dropout3 = nn.Dropout(dropout_rate)
self.fc4 = nn.Linear(32, 1)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
x = self.dropout1(torch.relu(self.bn1(self.fc1(x))))
x = self.dropout2(torch.relu(self.bn2(self.fc2(x))))
x = self.dropout3(torch.relu(self.bn3(self.fc3(x))))
x = self.sigmoid(self.fc4(x))
return x
def objective(trial):
lr = trial.suggest_float('lr', 1e-5, 1e-1, log=True)
dropout_rate = trial.suggest_float('dropout', 0.1, 0.5)
model = TunedMLP(X_train_scaled.shape[1], dropout_rate)
optimizer = optim.Adam(model.parameters(), lr=lr)
criterion = nn.BCELoss()
# 简短训练
for epoch in range(20):
model.train()
optimizer.zero_grad()
outputs = model(X_train_tensor)
loss = criterion(outputs, y_train_tensor)
loss.backward()
optimizer.step()
# 验证准确率
model.eval()
with torch.no_grad():
y_pred_prob = model(X_val_tensor)
y_pred = (y_pred_prob > 0.5).float()
acc = accuracy_score(y_val, y_pred.numpy().flatten())
return acc
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=10)
best_params = study.best_params
print(f"MLP最佳参数: {best_params}, 验证准确率: {study.best_value:.4f}")
# 训练最佳MLP
best_mlp = TunedMLP(X_train_scaled.shape[1], best_params['dropout'])
optimizer = optim.Adam(best_mlp.parameters(), lr=best_params['lr'])
criterion = nn.BCELoss()
for epoch in range(50): # 更长训练
best_mlp.train()
optimizer.zero_grad()
outputs = best_mlp(X_train_tensor)
loss = criterion(outputs, y_train_tensor)
loss.backward()
optimizer.step()
saved_models.append(('MLP', best_mlp, study.best_value))
基于 Optuna 的贝叶斯超参数优化 ,这是深度学习调优的主流高效方法(区别于机器学习的随机搜索 / 网格搜索),核心是通过贝叶斯推理智能搜索超参数空间,用更少的试错次数找到最优超参数。
核心:Optuna 贝叶斯优化的调优原理(区别于随机 / 网格搜索)
深度学习的超参数(如学习率、dropout 率)多为连续值 / 对数分布值 ,且参数间存在隐性关联 (如学习率和 batch size 相互影响),传统的随机 / 网格搜索 "无记忆、无关联" 的采样方式效率极低。Optuna 的贝叶斯优化核心逻辑是边试错、边学习、边聚焦:
- 初始化采样:先随机试几组超参数,记录每组参数的验证效果(如 MLP 验证准确率);
- 构建概率模型:基于已试的参数和效果,构建一个「超参数→模型效果」的概率预测模型(如高斯过程、树结构 Parzen 估计器);
- 智能选下一组参数:根据概率模型,优先选择最可能提升效果的超参数组合(聚焦参数空间的 "最优潜力区域",而非盲目随机);
- 迭代优化 :重复 2-3 步,直到达到指定试错次数(
n_trials),最终选择效果最优的参数。
简单说:Optuna 会 "记住" 之前的调优结果,智能避开无效区域、聚焦最优区域,比随机搜索少用 50% 以上的试错次数就能找到更优超参数,是深度学习调优的首选工具。
1. 定义可调参的 MLP 模型

- 核心设计:将需要调优的超参数(
dropout_rate)作为模型初始化参数,非调参参数(如隐藏层维度 128/64/32)固定,简化调优空间; - 关键细节:
BatchNorm1d+ReLU+Dropout的顺序是深度学习训练的黄金顺序,能有效缓解梯度消失、抑制过拟合、提升训练稳定性; - 适用场景:二分类任务(如本例中的泰坦尼克生存预测),最终用
Sigmoid输出 0~1 的概率,符合BCELoss损失函数要求。
2. 定义 Optuna 目标函数(objective)------ 调优的核心

- 参数建议方法 :
trial.suggest_*系列方法,根据参数类型选择(如浮点型suggest_float、整型suggest_int、类别型suggest_categorical);- 学习率
lr设为对数分布(log=True):深度学习中学习率的有效范围是对数级的(如 1e-4 比 0.01 更优的概率远高),对数采样能更均匀覆盖有效范围; - Dropout 率设为均匀分布:0.1~0.5 的范围是 MLP 的常规有效范围,均匀采样即可。
- 学习率
- 简短训练 :仅训练 20 轮,目的是快速评估参数效果,而非追求高精度------ 调优阶段的核心是 "筛选参数",全量收敛训练放在后续,大幅提升调优效率;
- 评估规范 :必须用独立验证集(X_val/y_val) 评估,且切换
model.eval()+with torch.no_grad(),避免训练模式的 Dropout/BN 干扰验证结果,保证评估准确。
3. 启动 Optuna 超参数搜索

- 核心参数:
direction:优化方向,分类任务设maximize(最大化准确率 / AUC),回归任务设minimize(最小化 MSE/RMSE);n_trials:试错次数,小数据集(如泰坦尼克)设 10~20 即可,中等 / 大数据集可设 30~50,兼顾效率和效果;
- 关键属性:
study.best_params:返回最优参数字典,可直接用于后续模型初始化;study.best_value:返回最优参数对应的验证指标值(如准确率)。
4. 用最优参数全量训练 MLP 模型

当然,深度学习调优不仅是超参数调优 ,还包含模型结构、训练策略、正则化等维度,且各维度相互影响,这是和机器学习(如随机森林)调优的本质区别。Optuna的方法也不仅限于这些,条鱼的目的在于提高模型的指标和泛化能力。
Optuna运行后输出如下

经过测试,目前RF在kaggle上表现最好
