优化涉及找到目标函数的输入,使函数的输出达到最小值或最大值。
名为 SciPy 的开源 Python 科学计算库提供了一套优化算法。其中许多算法被用作其他算法的构建块,最著名的是 scikit-learn 库中的机器学习算法。
这些**优化算法**可以直接独立使用来优化函数。最著名的是局部搜索算法和全局搜索算法,这是您在机器学习项目中可能遇到的两种主要优化类型。
在本教程中,您将了解 SciPy 库提供的优化算法。
完成本教程后,您将了解:
- SciPy 库提供了适用于不同用途的一套不同优化算法。
- SciPy 中可用的局部搜索优化算法。
- SciPy 中可用的全局搜索优化算法。
使用我的新书《机器学习优化》**启动您的项目**,其中包括**分步教程**和所有示例的**Python 源代码**文件。
让我们开始吧。
使用 SciPy 进行函数优化
图片由Manoel Lemos提供,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 使用 SciPy 进行优化
- 使用 SciPy 进行局部搜索
- 使用 SciPy 进行全局搜索
使用 SciPy 进行优化
用于科学计算的 Python SciPy 开源库提供了一套优化技术。
许多算法在 SciPy 库以及 scikit-learn 等机器学习库中用作其他算法的构建块。
在回顾具体技术之前,我们先看看该库提供的算法类型。
它们是
- **标量优化**:凸单变量函数的优化。
- **局部搜索**:单峰多变量函数的优化。
- **全局搜索**:多峰多变量函数的优化。
- **最小二乘**:解决线性和非线性最小二乘问题。
- **曲线拟合**:将曲线拟合到数据样本。
- **求根**:找到函数的根(输出为零的输入)。
- **线性规划**:受约束的线性优化。
所有算法都假设正在优化的目标函数是一个最小化函数。如果您的函数是最大化函数,可以通过在目标函数返回的值中添加负号来将其转换为最小化函数。
除了上述列表,该库还提供了某些算法使用的实用函数以及 Rosenbrock 测试问题。
有关 SciPy 库优化功能的良好概述,请参阅
现在我们对该库支持的优化技术类型有了高层次的了解,接下来我们更详细地了解在应用机器学习中更可能使用的两组算法。它们是局部搜索和全局搜索。
想要开始学习优化算法吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
使用 SciPy 进行局部搜索
局部搜索,或局部函数优化,指的是寻找函数输入的算法,该输入导致函数或搜索的约束区域的最小或最大输出,其中假设该区域具有单个最优值,例如单峰。
正在优化的函数可能凸也可能不凸,并且可能有一个或多个输入变量。
如果函数被认为是或已知是单峰的,则可以直接应用局部搜索优化来优化函数;否则,局部搜索算法可以用于微调全局搜索算法的结果。
SciPy 库通过 minimize() 函数提供局部搜索。
`minimize()` 函数接受要最小化的目标函数的名称和开始搜索的初始点作为输入,并返回一个 OptimizeResult,该结果总结了搜索的成功或失败以及找到的解决方案的详细信息。
1 2 3 |
... # 最小化目标函数 result = minimize(objective, point) |
如果已知目标函数的额外信息,例如输入变量的边界、计算函数一阶导数(梯度或雅可比矩阵)的函数、计算函数二阶导数(海森矩阵)的函数以及输入的任何约束,都可以提供。
重要的是,该函数提供了“*method*”参数,允许指定局部搜索中使用的具体优化方法。
提供了一套流行的局部搜索算法,例如
- Nelder-Mead 算法 (method='Nelder-Mead')。
- 牛顿法 (method='Newton-CG')。
- Powell 方法 (method='Powell')。
- BFGS 算法及其扩展 (method='BFGS')。
下面的示例演示了如何使用 L-BFGS-B 局部搜索算法求解二维凸函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 凸函数的 l-bfgs-b 算法局部优化 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) # 执行 l-bfgs-b 算法搜索 result = minimize(objective, pt, method='L-BFGS-B') # 总结结果 print('Status : %s' % result['message']) print('Total Evaluations: %d' % result['nfev']) # 评估解 solution = result['x'] evaluation = objective(solution) print('Solution: f(%s) = %.5f' % (solution, evaluation)) |
运行该示例将执行优化并报告搜索的成功或失败、执行的函数评估次数以及导致函数最优值的输入。
1 2 3 |
Status : b'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL' Total Evaluations: 9 Solution: f([3.38059583e-07 3.70089258e-07]) = 0.00000 |
现在我们熟悉了使用 SciPy 的局部搜索算法,接下来我们看看全局搜索。
使用 SciPy 进行全局搜索
全局搜索或全局函数优化是指寻找函数输入的算法,该输入导致函数或搜索的约束区域的最小或最大输出,其中假设该区域具有多个局部最优值,例如多峰。
被优化的函数通常是非线性、非凸的,并且可能有一个或多个输入变量。
全局搜索算法通常是随机的,这意味着它们在搜索过程中利用随机性,并且可能在搜索过程中管理或不管理候选解决方案的群体。
SciPy 库提供了许多随机全局优化算法,每种算法都通过不同的函数实现。它们是
- 通过 basinhopping() 函数进行 Basin Hopping 优化。
- 通过 differential_evolution() 函数进行 差分进化优化。
- 通过 dual_annealing() 函数进行 模拟退火。
该库还提供了用于序列优化的 shgo() 函数和用于网格搜索优化的 brute() 函数。
每个算法都返回一个 OptimizeResult 对象,该对象总结了搜索的成功或失败以及找到的解决方案的详细信息。
下面的示例演示了如何使用模拟退火求解二维多峰函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 多峰目标函数的模拟退火全局优化 from scipy.optimize import dual_annealing # 目标函数 def objective(v): x, y = v return (x**2 + y - 11)**2 + (x + y**2 -7)**2 # 定义输入范围 r_min, r_max = -5.0, 5.0 # 定义搜索的边界 bounds = [[r_min, r_max], [r_min, r_max]] # 执行模拟退火搜索 result = dual_annealing(objective, bounds) # 总结结果 print('Status : %s' % result['message']) print('Total Evaluations: %d' % result['nfev']) # 评估解 solution = result['x'] evaluation = objective(solution) print('Solution: f(%s) = %.5f' % (solution, evaluation)) |
运行该示例将执行优化并报告搜索的成功或失败、执行的函数评估次数以及导致函数最优值的输入。
1 2 3 |
状态:['已达到最大迭代次数'] 总评估次数:4028 解:f([-3.77931027 -3.283186 ]) = 0.00000 |
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
API
文章
总结
在本教程中,您学习了 SciPy 库提供的优化算法。
具体来说,你学到了:
- SciPy 库提供了适用于不同用途的一套不同优化算法。
- SciPy 中可用的局部搜索优化算法。
- SciPy 中可用的全局搜索优化算法。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
你不知道我有多高兴你正在制作这个优化模块。
感谢您的贡献!
不客气!
太棒了
谢谢!
尊敬的先生,早上好
这篇文章非常棒。而且
我想攻读与此领域相关的博士学位,您能指导我吗?我现在正在攻读机器学习和人工智能的研究生课程。
目标:检测水果和蔬菜中的化学物质含量。因为在我的国家,现在人们使用大量化学物质来种植植物。因此,如果我们能检测水果和蔬菜中的化学物质含量,这将有助于我们避免食用这些食物。并提高人们对这些化学物质危害的认识。
所以请问您能指导我吗?
谢谢。
这听起来是一个很棒的项目。
抱歉,我没有能力担任您的研究顾问——我建议您与您大学的研究小组/顾问讨论您的项目。
这些细节太棒了,杰森。我会彻底研究并回复你。
谢谢!
嗨
我正在尝试解决一个项目,旨在为保险代理人找到最佳激励措施,以最大化订阅者支付的保费总收入。代理人的努力小时数是给定激励措施的复杂指数函数,支付保费的概率增加百分比是代理人努力小时数的复杂指数函数。总收入是(所有订阅者的)基准概率加上支付保费的概率增加百分比乘以保费金额减去支付给代理人的激励的总和。我可以在这里使用优化算法吗?如果可以,如何使用?您能帮我解决这个问题吗?
这听起来是一个很棒的项目!
也许可以从尝试定义候选解决方案的评估函数开始——它可能是一个模拟或复杂的计算。如果你能定义一个目标函数并评估候选解决方案,你就走上了正确的道路,然后开始尝试不同的手工解决方案,最终使用优化算法。
非常感谢,这真的很有帮助!!
您知道如何使用训练好的神经网络模型作为目标函数来应用 optimize.minimize 函数吗?
当然,创建一个函数,该函数使用您的模型作为矢量输入并输出预测值。
嗨,Jason,
感谢您的出色工作。我正在尝试使用神经网络模型来最小化液化天然气工厂的运营支出。您能举例说明如何在 scipy.optimize 包中使用神经网络模型吗?
感谢您的回复。
我不太确定我是否理解,但 scipy.optimize 是为了找到用户定义函数的最小值。因此,您需要定义一个函数,该函数将参数作为输入,然后在该函数中,您使用参数构建一个神经网络模型,进行训练,并使用该模型生成一些值(例如,错误指标)。然后可以使用 scipy 对该函数进行优化。
Jason,有没有关于如何从头开始检查 scipy 优化器工作的链接或博客?
手头没有,抱歉。