机器学习优化算法:从网格搜索到梯度下降
1. 机器学习优化七日速成课
在机器学习实践中,优化算法扮演着至关重要的角色。无论是调整超参数还是选择特征子集,决策树算法寻找最佳分割点,神经网络优化权重参数,我们都在使用各种计算算法进行优化。
1.1 为什么需要专门学习优化?
许多刚入门的机器学习从业者常把模型视为"黑箱",虽然知道可以调节各种参数,却不清楚如何系统性地寻找最优解。与传统编程不同,机器学习中的最优迭代次数、最佳超参数等往往没有显而易见的规则可循。
优化(或称函数优化)在数学上指寻找函数最大值或最小值的过程。在机器学习中,我们可以将模型参数作为输入,模型算法和数据集作为常量,评估指标作为输出,这样就构建了一个可优化的函数。
1.2 优化在机器学习中的应用场景
- 超参数调优 :如决策树的深度、神经网络的学习率等
- 特征选择 :从原始特征中找出最有价值的子集
- 模型训练 :如神经网络中的权重优化
- 集成学习 :确定各基学习器的最佳权重组合
2. 优化基础与网格搜索
2.1 网格搜索原理
网格搜索是最直观的优化方法,特别适合低维问题。其基本思想是在预设的参数范围内,均匀地采样各参数组合,然后逐一评估,最终找到最优解。
以二维函数f(x,y)=x²+y²为例,假设x和y的范围都是[-5,5],步长为0.1,我们需要评估(5-(-5))/0.1=100个x值,同样数量的y值,总共100×100=10,000个点。
from numpy import arange, inf
def objective(x, y):
return x**2.0 + y**2.0
# 定义输入范围
r_min, r_max = -5.0, 5.0
step = 0.1
# 生成网格样本
sample = []
for x in arange(r_min, r_max+step, step):
for y in arange(r_min, r_max+step, step):
sample.append([x,y])
# 评估样本
best_eval = inf
best_x, best_y = None, None
for x,y in sample:
eval = objective(x,y)
if eval < best_eval:
best_x, best_y, best_eval = x, y, eval
print(f'Best: f({best_x:.5f},{best_y:.5f}) = {best_eval:.5f}')
2.2 网格搜索的优缺点
优点 :
- 实现简单直观
- 可以找到全局最优(在给定的搜索范围内)
- 不需要计算导数
缺点 :
- 维度灾难:参数数量增加时计算量呈指数增长
- 步长选择困难:步长太大可能错过最优解,太小则计算成本高
提示:对于高维问题,建议使用更高效的优化算法,或者先使用大步长网格搜索定位大致范围,再在小范围内进行精细搜索。
3. SciPy中的优化算法
SciPy库提供了多种优化算法,适合不同特性的函数优化问题。
3.1 Nelder-Mead算法
Nelder-Mead(又称下山单纯形法)是一种不需要导数的优化方法,适合解决低维非线性优化问题。
from scipy.optimize import minimize
from numpy.random import rand
def objective(x):
return x[0]**2.0 + x[1]**2.0
# 定义范围并随机生成初始点
r_min, r_max = -5.0, 5.0
pt = r_min + rand(2) * (r_max - r_min)
# 执行优化
result = minimize(objective, pt, method='nelder-mead')
print(f'Status: {result["message"]}')
print(f'Evaluations: {result["nfev"]}')
print(f'Solution: f({result["x"]}) = {result["fun"]:.5f}')
3.2 算法选择建议
- 凸函数 :BFGS或L-BFGS-B
- 非凸函数 :模拟退火或遗传算法
- 有约束条件 :SLSQP或trust-constr
- 高维问题 :L-BFGS-B或CG
4. 基于梯度的优化方法
4.1 BFGS算法
BFGS是一种拟牛顿法,通过近似Hessian矩阵来加速收敛,适合光滑的凸函数优化。
def derivative(x):
return [x[0]*2, x[1]*2]
result = minimize(objective, pt, method='BFGS', jac=derivative)
4.2 L-BFGS-B算法
L-BFGS-B是BFGS的内存高效版本,支持边界约束。
result = minimize(objective, pt, method='L-BFGS-B', jac=derivative,
bounds=[(-5,5), (-5,5)])
4.3 梯度下降实现
梯度下降是神经网络训练的基础算法,核心思想是沿着梯度反方向更新参数。
def gradient_descent(objective, derivative, bounds, n_iter, step_size):
solution = bounds[:,0] + rand(len(bounds)) * (bounds[:,1]-bounds[:,0])
for i in range(n_iter):
gradient = derivative(solution)
solution -= step_size * gradient
print(f'>{i} f({solution}) = {objective(solution):.5f}')
return solution
bounds = asarray([[-5.0,5.0], [-5.0,5.0]])
solution = gradient_descent(objective, derivative, bounds, 40, 0.1)
5. 无梯度优化方法
5.1 爬山算法
爬山算法是一种简单的局部搜索方法,适合解决低维优化问题。
def hillclimbing(objective, bounds, n_iterations, step_size):
# 生成初始解
solution = bounds[:,0] + rand(len(bounds)) * (bounds[:,1]-bounds[:,0])
solution_eval = objective(solution)
for i in range(n_iterations):
# 生成候选解
candidate = solution + randn(len(bounds)) * step_size
candidate_eval = objective(candidate)
# 接受更好的解
if candidate_eval < solution_eval:
solution, solution_eval = candidate, candidate_eval
print(f'>{i} f({solution}) = {solution_eval:.5f}')
return [solution, solution_eval]
5.2 模拟退火算法
模拟退火通过引入"温度"概念来避免陷入局部最优,适合非凸函数优化。
def simulated_annealing(objective, bounds, n_iterations, step_size, temp):
best = bounds[:,0] + rand(len(bounds)) * (bounds[:,1]-bounds[:,0])
best_eval = objective(best)
curr, curr_eval = best, best_eval
for i in range(n_iterations):
candidate = curr + randn(len(bounds)) * step_size
candidate_eval = objective(candidate)
if candidate_eval < best_eval:
best, best_eval = candidate, candidate_eval
diff = candidate_eval - curr_eval
t = temp / float(i + 1)
metropolis = exp(-diff / t)
if diff < 0 or rand() < metropolis:
curr, curr_eval = candidate, candidate_eval
return [best, best_eval]
6. 优化算法性能比较
6.1 测试函数选择
- 凸函数 :f(x,y) = x² + y²
-
非凸函数
:Ackley函数
def ackley(v): x, y = v return (-20.0 * exp(-0.2 * sqrt(0.5 * (x**2 + y**2))) - exp(0.5 * (cos(2*pi*x) + cos(2*pi*y))) + e + 20)
6.2 实验结果对比
| 算法 | 凸函数收敛速度 | 非凸函数找到的解质量 | 内存需求 | 适用维度 |
|---|---|---|---|---|
| 网格搜索 | 慢 | 全局最优 | 高 | 低(<5) |
| Nelder-Mead | 中等 | 可能陷入局部最优 | 低 | 低(<10) |
| BFGS | 快 | 可能陷入局部最优 | 中等 | 中等 |
| L-BFGS-B | 快 | 可能陷入局部最优 | 低 | 高 |
| 爬山算法 | 中等 | 可能陷入局部最优 | 低 | 低(<20) |
| 模拟退火 | 慢 | 较好 | 低 | 中等 |
7. 优化实践建议
- 了解你的问题 :首先分析目标函数的性质(凸性、连续性、可导性等)
- 从小规模开始 :先用少量数据或简化版本测试优化算法
- 监控进度 :记录每次迭代的目标函数值,绘制收敛曲线
- 超参数调优 :优化算法本身也可能有需要调整的参数
- 组合策略 :可以先使用全局搜索定位大致区域,再用局部搜索精细优化
在机器学习项目中,优化算法的选择往往取决于问题的规模和性质。对于超参数优化,网格搜索和随机搜索仍然很流行;对于神经网络训练,梯度下降及其变种(如Adam)是标准选择;对于复杂的非凸问题,可能需要考虑进化算法等更高级的方法。
优化是机器学习的核心,掌握各种优化算法不仅能帮助你更好地训练模型,还能加深对机器学习本质的理解。建议从简单的例子开始,逐步尝试更复杂的优化问题,积累实践经验。
更多推荐
所有评论(0)