机器学习优化速成课程。
用Python在7天内找到函数最优值。
所有机器学习模型都涉及优化。作为实践者,我们会优化最合适的超参数或特征子集。决策树算法优化拆分点。神经网络优化权重。我们很可能使用计算算法来优化。
在数值优化方面有很多方法。SciPy 提供了许多方便的函数。我们也可以尝试自己实现优化算法。
在本速成课程中,您将了解到如何在七天内开始并自信地使用Python运行算法来优化函数。
这是一篇内容丰富且重要的文章。您可能想把它加入书签。
通过我的新书《机器学习优化》,包含分步教程和所有示例的Python源代码文件,为您的项目提供启动支持!
让我们开始吧。

机器学习优化(7天迷你课程)
照片由 Brewster Malevich 拍摄,保留部分权利。
本速成课程适合谁?
在开始之前,让我们确保您来对了地方。
本课程面向可能了解一些应用机器学习的开发人员。也许您已经端到端地构建了一些模型并进行了一些项目,或者从流行工具的现有示例代码中修改以解决您自己的问题。
本课程的课程假设您具备以下几点:
- 您熟悉基本的Python编程。
- 您可能了解一些基本的NumPy用于数组操作。
- 您听说过梯度下降、模拟退火、BFGS 或其他一些优化算法,并希望加深理解。
您不需要是
- 成为数学高手!
- 成为机器学习专家!
本速成课程将帮助您从一个了解少量机器学习的开发人员,转变为一个能够有效且熟练地应用函数优化算法的开发人员。
注意:本速成课程假设您有一个可用的 Python 3 SciPy 环境,并且至少安装了 NumPy。如果您的环境需要帮助,您可以按照这里的分步教程进行操作。
速成课程概览
本速成课程分为七节课。
您可以每天完成一节课(推荐),或者在一天内完成所有课程(硬核)。这真的取决于您的可用时间和热情程度。
以下是七个课程列表,将帮助您开始并熟练掌握Python中的优化:
- 第01课:为什么要优化?
- 第02课:网格搜索
- 第03课:SciPy中的优化算法
- 第04课:BFGS算法
- 第05课:爬山算法
- 第06课:模拟退火
- 第07课:梯度下降
每节课可能需要您60秒到30分钟不等。请按自己的节奏学习。随时提问,甚至在下面的评论中发布您的结果。
课程可能需要您自行查找如何做某些事情。我会给您一些提示,但每节课的要点之一就是迫使您学习去哪里查找有关算法和Python中最佳工具的帮助。(提示:所有答案都在本博客上;请使用搜索框。)
在评论中发布您的结果;我会为您加油!
坚持下去;不要放弃。
第01课:为什么要优化?
在本课中,您将了解为什么以及何时需要进行优化。
机器学习与其他软件项目不同之处在于,编写程序的方式不那么直接。编程中的一个简单示例是编写一个 for 循环来打印数字 1 到 100。您确切地知道需要一个计数变量,并且循环需要 100 次迭代来计数。机器学习中的一个简单示例是使用神经网络进行回归,但您不知道确切需要多少次迭代来训练模型。您可能设置的次数太少或太多,并且您没有规则来判断正确的数量是多少。因此,许多人将机器学习模型视为黑箱。结果是,尽管模型有许多我们可以调整的变量(例如,超参数),但我们不知道在测试之前什么才是正确的值。
在本课中,您将了解为什么机器学习从业者应该学习优化以提高他们的技能和能力。优化在数学中也称为函数优化,旨在找到某个函数的最大值或最小值。对于函数的不同性质,可以应用不同的方法。
机器学习是关于开发预测模型。一个模型是否比另一个模型好,我们有一些评估指标来衡量模型在特定数据集上的性能。从这个意义上说,如果我们考虑创建模型的参数作为输入,将模型的内部算法和相关数据集视为常数,并将从模型中评估的指标视为输出,那么我们就构建了一个函数。
以决策树为例。我们知道它是一个二叉树,因为每个中间节点都在问一个是/否问题。这是恒定的,我们无法更改它。但是这棵树应该有多深是一个我们可以控制的超参数。从数据中选择哪些特征以及允许决策树使用多少特征是另一个。这些超参数的不同值会改变决策树模型,进而产生不同的指标,例如分类问题中的 k 折交叉验证的平均准确率。那么我们就定义了一个函数,该函数以超参数为输入,以准确率为输出。
从决策树库的角度来看,一旦您提供了超参数和训练数据,它也可以将它们视为常数,并将特征的选择和每个节点处的拆分阈值作为输入。指标仍然是这里的输出,因为决策树库的共同目标是做出最佳预测。因此,该库也定义了一个函数,但这与上面提到的函数不同。
这里的函数并不意味着您需要在编程语言中显式定义一个函数。一个概念上的函数就足够了。我们接下来要做的是操纵输入并检查输出来找到最佳输出。在机器学习的情况下,最佳可能意味着
- 最高的准确率、精确率或召回率
- ROC曲线的 AUC 值最大
- 分类问题的 F1 分数或回归问题的 R2 分数最大
- 误差或对数损失最小
或者类似的东西。我们可以通过随机采样或随机扰动等随机方法来操纵输入。我们也可以假设函数具有某些属性,并尝试一系列输入来利用这些属性。当然,我们也可以检查所有可能的输入,当我们耗尽可能性时,我们就知道最佳答案。
这些是关于为什么我们想进行优化、它是什么以及我们如何做到的基本知识。您可能没有注意到,训练机器学习模型就是在进行优化。您也可能显式地进行优化以选择特征或微调超参数。如您所见,优化在机器学习中很有用。
您的任务
对于本课,您必须找到一个机器学习模型,并列出可能用于或有助于训练和使用该模型的三个优化示例。这些可能与上述原因有关,也可能是您自己的个人动机。
请在下面的评论中发布您的答案。我很想看看您能想出什么。
在下一课中,您将学习如何对任意函数执行网格搜索。
第02课:网格搜索
在本课中,您将了解用于优化的网格搜索。
让我们从这个函数开始
f (x, y) = x2 + y2
这是一个具有二维输入(x, y)和一维输出的函数。我们可以做什么来找到该函数的最小值?换句话说,对于什么 x 和 y,f (x, y) 的值最小?
在不查看 f (x, y) 的具体内容的情况下,我们可以首先假设 x 和 y 位于某个有界区域内,例如从 -5 到 +5。然后我们可以检查此范围内 x 和 y 的所有组合。如果我们记住 f (x, y) 的值,并跟踪我们见过的最小值,那么在耗尽该区域后,我们就可以找到它的最小值。在 Python 代码中,它看起来像这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
from numpy import arange, inf # 目标函数 def objective(x, y): return x**2.0 + y**2.0 # 定义输入范围 r_min, r_max = -5.0, 5.0 # 生成网格样本 sample = list() step = 0.1 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 = x best_y = y best_eval = eval # 总结最佳解决方案 print('Best: f(%.5f,%.5f) = %.5f' % (best_x, best_y, best_eval)) |
此代码以 0.1 的增量步长从范围的下限 -5 扫描到上限 +5。此范围对 x 和 y 都相同。这将创建大量的 (x, y) 对样本。这些样本是通过 x 和 y 在范围内的组合而创建的。如果我们把它们的坐标画在坐标纸上,它们就形成了一个网格,因此我们称之为网格搜索。
有了样本网格后,我们为每个 (x, y) 样本评估目标函数 f (x, y)。我们跟踪该值,并记住我们见过的最小值。一旦我们用完了网格上的样本,我们就将找到的最小值作为优化结果。
您的任务
对于本课,您应该查找如何使用 numpy.meshgrid() 函数并重写示例代码。然后您可以尝试将目标函数替换为 f (x, y, z) = (x – y + 1)2 + z2,这是一个具有 3D 输入的函数。
请在下面的评论中发布您的答案。我很想看看您能想出什么。
在下一课中,您将学习如何使用 SciPy 来优化函数。
第03课:SciPy中的优化算法
在本课中,您将了解如何利用 SciPy 来优化您的函数。
文献中有许多优化算法。每种算法都有其优点和缺点,并且每种算法都适用于不同的情况。重用我们在上一课中介绍的相同函数,
f (x, y) = x2 + y2
我们可以利用 SciPy 中的一些预定义算法来找到其最小值。最简单的可能是 Nelder-Mead 算法。该算法基于一系列规则来确定如何探索函数的曲面。在不深入细节的情况下,我们可以简单地调用 SciPy 并应用 Nelder-Mead 算法来找到函数的最小值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
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('Status : %s' % result['message']) print('Total Evaluations: %d' % result['nfev']) # 评估解 solution = result['x'] evaluation = objective(solution) print('Solution: f(%s) = %.5f' % (solution, evaluation)) |
在上面的代码中,我们需要将函数写成单个向量参数。因此,函数实际上变为
f (x[0], x[1]) = (x[0])2 + (x[1])2
Nelder-Mead 算法需要一个起始点。我们为此选择一个在 -5 到 +5 范围内的随机点(rand(2) 是 numpy 生成 0 到 1 之间随机坐标对的方式)。minimize() 函数返回一个 OptimizeResult 对象,其中包含有关搜索结果的信息,可以通过键进行访问。“message”键提供关于搜索成功或失败的可读消息,“nfev”键显示优化过程中进行的函数评估次数。其中最重要的是“x”键,它指定了达到最小值的输入值。
Nelder-Mead 算法适用于凸函数,即形状平滑且呈盆状的函数。对于更复杂的函数,该算法可能会陷入局部最优而未能找到真正的全局最优。
您的任务
对于本课,您应该用以下函数替换示例代码中的目标函数:
1 2 3 4 5 |
from numpy import e, pi, cos, sqrt, exp def objective(v): x, y = v return ( -20.0 * exp(-0.2 * sqrt(0.5 * (x**2 + y**2))) - exp(0.5 * (cos(2*pix)+cos(2*piy))) + e + 20 ) |
这定义了 Ackley 函数。全局最小值在 v=[0,0]。然而,Nelder-Mead 最可能找不到它,因为该函数有许多局部最小值。尝试多次重复您的代码并观察输出。每次运行程序时,您应该会得到不同的输出。
请在下面的评论中发布您的答案。我很想看看您能想出什么。
在下一课中,您将学习如何使用相同的 SciPy 函数来应用不同的优化算法。
第04课:BFGS算法
在本课中,您将了解如何利用 SciPy 来应用 BFGS 算法来优化您的函数。
正如我们在上一课中看到的,我们可以利用 scipy.optimize 的 minimize() 函数使用 Nelder-Mead 算法来优化函数。这是简单的“模式搜索”算法,不需要知道函数的导数。
一阶导数是指对目标函数进行一次微分。类似地,二阶导数是指对一阶导数再进行一次微分。如果我们有目标函数的二阶导数,我们可以应用牛顿法来找到其最优值。
还有一类优化算法可以从一阶导数近似二阶导数,并利用该近似来优化目标函数。它们被称为拟牛顿方法。BFGS 是这一类中最著名的一种。
回顾我们在前几课中使用的相同目标函数,
f (x, y) = x2 + y2
我们可以看出,一阶导数是
∇f = [2x, 2y]
这是一个包含两个分量的向量,因为函数 f (x, y) 接收一个包含两个分量(x, y)的向量值并返回一个标量值。
如果我们为一阶导数创建一个新函数,我们可以调用 SciPy 并应用 BFGS 算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
from scipy.optimize import minimize from numpy.random import rand # 目标函数 def objective(x): return x[0]**2.0 + x[1]**2.0 # 目标函数的导数 def derivative(x): return [x[0] * 2, x[1] * 2] # 定义输入范围 r_min, r_max = -5.0, 5.0 # 将起始点定义为从域中随机采样 pt = r_min + rand(2) * (r_max - r_min) # 执行 bfgs 算法搜索 result = minimize(objective, pt, method='BFGS', jac=derivative) # 总结结果 print('Status : %s' % result['message']) print('Total Evaluations: %d' % result['nfev']) # 评估解 solution = result['x'] evaluation = objective(solution) print('Solution: f(%s) = %.5f' % (solution, evaluation)) |
目标函数的一阶导数通过“jac”参数传递给 minimize() 函数。该参数命名为雅可比矩阵,这是我们称呼接受向量并返回向量的函数的“一阶导数”的方式。BFGS 算法将利用一阶导数来计算海森矩阵的逆(即向量函数的二阶导数),并用它来找到最优值。
除了 BFGS 之外,还有 L-BFGS-B。它是前者的一个版本,它使用的内存更少(“L”),并且定义域被限制在一个区域(“B”)。要使用此变体,我们只需替换方法名称:
1 2 |
... result = minimize(objective, pt, method='L-BFGS-B', jac=derivative) |
您的任务
对于本课,您应该创建一个具有更多参数的函数(即,函数的向量参数远不止两个分量),并观察 BFGS 和 L-BFGS-B 的性能。您注意到速度上的差异了吗?这两个方法的结果有何不同?如果您的函数不是凸函数而是有许多局部最优值,会发生什么?
请在下面的评论中发布您的答案。我很想看看您能想出什么。
第05课:爬山算法
在本课中,您将了解如何实现爬山算法并使用它来优化您的函数。
爬山算法的思想是从目标函数上的一个点开始。然后我们稍微朝着一个随机方向移动该点。如果移动能让我们找到一个更好的解决方案,我们就保留新的位置。否则我们就停留在原地。在执行此操作足够多的迭代次数后,我们应该足够接近此目标函数的最佳值。之所以命名为“爬山”,是因为它就像我们在爬山一样, wherever we can go up (or down) whenever we can.
在 Python 中,我们可以将上述用于最小化的爬山算法编写为一个函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
from numpy.random import randn def in_bounds(point, bounds): # 枚举点的所有维度 for d in range(len(bounds)): # 检查此维度是否超出界限 if point[d] < bounds[d, 0] or point[d] > bounds[d, 1]: return False return True def hillclimbing(objective, bounds, n_iterations, step_size): # 生成初始点 solution = None while solution is None or not in_bounds(solution, bounds): solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0]) # 评估初始点 solution_eval = objective(solution) # 运行爬山算法 for i in range(n_iterations): # 迈出一步 candidate = None while candidate is None or not in_bounds(candidate, bounds): candidate = solution + randn(len(bounds)) * step_size # 评估候选点 candidte_eval = objective(candidate) # 检查是否应该保留新点 if candidte_eval <= solution_eval: # 存储新点 solution, solution_eval = candidate, candidte_eval # 报告进度 print('>%d f(%s) = %.5f' % (i, solution, solution_eval)) return [solution, solution_eval] |
此函数允许传入任何目标函数,只要它接受一个向量并返回一个标量值。“bounds”参数应为 n×2 维的 numpy 数组,其中 n 是目标函数期望的向量的大小。它指定了我们应该寻找最小值的范围的下限和上限。例如,对于期望二维向量(如前一课中的)且向量分量在 -5 到 +5 范围内的目标函数,我们可以进行如下设置:
1 |
bounds = np.asarray([[-5.0, 5.0], [-5.0, 5.0]]) |
此“爬山法”函数将在边界内随机选择一个初始点,然后进行迭代测试目标函数。每当找到目标函数产生的值更小,该解就会被记住,下一个测试点将从其邻域生成。
您的任务
对于本课,您应该提供自己的目标函数(例如,复制前一课中的函数),设置“n_iterations”和“step_size”,并应用“hillclimbing”函数来查找最小值。观察算法如何找到解。尝试使用不同的“step_size”值,并比较找到接近最终解所需的迭代次数。
请在下面的评论中发布您的答案。我很想看看您能想出什么。
第 06 课:模拟退火
在本课中,您将了解模拟退火的工作原理以及如何使用它。
对于非凸函数,您在前几课中学到的算法很容易陷入局部最优,而无法找到全局最优。原因是算法的贪婪性质:只要找到一个更好的解,它就不会放手。因此,如果存在一个更好的解但不在邻域内,算法将找不到它。
模拟退火试图通过平衡“探索”和“利用”来改进这种行为。起初,当算法对要优化的函数了解不多时,它倾向于探索其他解,而不是坚持找到的最佳解。在后期,随着探索的解越来越多,找到更好解的机会减少,算法倾向于保留在已找到最佳解的邻域内。
以下是模拟退火在 Python 函数中的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
from numpy.random import randn, rand 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 # 报告进度 print('>%d f(%s) = %.5f' % (i, best, best_eval)) # 候选点与当前点评估的差值 diff = candidate_eval - curr_eval # 计算当前 epoch 的温度 t = temp / float(i + 1) # 计算 Metropolis 接受准则 metropolis = exp(-diff / t) # 检查是否应该保留新点 if diff < 0 or rand() < metropolis: # 存储新的当前点 curr, curr_eval = candidate, candidate_eval return [best, best_eval] |
与上一课中的爬山算法类似,该函数从一个随机的初始点开始。同样与上一课中的类似,该算法在“n_iterations”计数的规定下进行循环。在每次迭代中,都会选择当前点的一个随机邻域点,并在其上评估目标函数。迄今为止找到的最佳解存储在变量“best”和“best_eval”中。与爬山算法的区别在于,每次迭代中的当前点“curr”不一定是最佳解。是否将点移动到邻域或保持不变取决于一个概率,该概率与我们进行的迭代次数以及邻域能带来的改进程度有关。由于这种随机性,我们有机会摆脱局部最小值以获得更好的解。最后,无论我们最终在哪里结束,我们总是返回模拟退火算法迭代过程中找到的最佳解。
事实上,机器学习中遇到的大多数超参数调整或特征选择问题都不是凸的。因此,对于这些优化问题,模拟退火比爬山法更合适。
您的任务
对于本课,您应该重复上一课中进行的练习,使用上面的模拟退火代码。尝试使用目标函数 f(x, y) = x^2 + y^2,这是一个凸函数。您是否发现模拟退火或爬山法需要更少的迭代次数?将目标函数替换为第 03 课中介绍的 Ackley 函数。您是否发现模拟退火或爬山法找到的最小值更小?
请在下面的评论中发布您的答案。我很想看看您能想出什么。
第 07 课:梯度下降
在本课中,您将了解如何实现梯度下降算法。
梯度下降算法是训练神经网络所用的“算法”。尽管有许多变体,但它们都基于函数的**梯度**,即一阶导数。其思想在于梯度函数的物理意义。如果函数接受一个向量并返回一个标量值,那么函数在任何点的梯度都会告诉您函数增长最快的**方向**。因此,如果我们旨在找到函数的最小值,我们应该探索的方向恰好与梯度相反。
在数学方程中,如果我们正在寻找 f(x) 的最小值,其中 x 是一个向量,而 f(x) 的梯度记为 ∇f(x)(它也是一个向量),那么我们知道
xnew = x – α × ∇f(x)
将比 x 更接近最小值。现在让我们尝试在 Python 中实现它。重用我们从第 4 天学到的示例目标函数及其导数,这就是梯度下降算法及其用于查找目标函数最小值的应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
from numpy import asarray from numpy import arange from numpy.random import rand # 目标函数 def objective(x): return x[0]**2.0 + x[1]**2.0 # 目标函数的导数 def derivative(x): return asarray([x[0]*2, x[1]*2]) # 梯度下降算法 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 = solution - step_size * gradient # 评估候选点 solution_eval = objective(solution) # 报告进度 print('>%d f(%s) = %.5f' % (i, solution, solution_eval)) return [solution, solution_eval] # 定义输入范围 bounds = asarray([[-5.0, 5.0], [-5.0, 5.0]]) # 定义总迭代次数 n_iter = 40 # 定义步长 step_size = 0.1 # 执行梯度下降搜索 solution, solution_eval = gradient_descent(objective, derivative, bounds, n_iter, step_size) print("Solution: f(%s) = %.5f" % (solution, solution_eval)) |
该算法不仅依赖于目标函数,还依赖于其导数。因此,它可能不适用于所有类型的问题。该算法也对步长敏感,相对于目标函数而言过大的步长可能导致梯度下降算法无法收敛。如果发生这种情况,我们将看到进度没有朝着较低的值移动。
有几种变体可以使梯度下降算法更健壮,例如
- 在过程中添加**动量**,即移动不仅遵循梯度,还部分遵循先前迭代梯度的平均值。
- 为向量 x 的每个分量设置不同的步长
- 使步长自适应于进度
您的任务
对于本课,您应该使用不同的“step_size”和“n_iter”运行上面的示例程序,并观察算法进度的差异。在哪个“step_size”下,上述程序将无法收敛?然后尝试将新的参数 β 添加到 gradient_descent() 函数中作为**动量权重**,更新规则现在变为
xnew = x – α × ∇f(x) – β × g
其中 g 是例如五次先前迭代中 ∇f(x) 的平均值。您是否看到对这种优化有任何改进?它是使用动量的一个合适的例子吗?
请在下面的评论中发布您的答案。我很想看看您能想出什么。
这是最后一课。
结束!
(看看您取得了多大的进步)
您做到了。干得好!
花点时间回顾一下您已经走了多远。
您发现了:
- 优化在应用机器学习中的重要性。
- 如何进行网格搜索以通过穷举所有可能的解决方案来优化。
- 如何使用 SciPy 来优化您自己的函数。
- 如何实现爬山算法进行优化。
- 如何使用模拟退火算法进行优化。
- 什么是梯度下降,如何使用它,以及该算法的一些变体。
总结
您对这个迷你课程的学习情况如何?
您喜欢这个速成课程吗?
您有任何问题吗?有没有遇到什么难点?
告诉我。在下面留言。
第一课的任务
1. KNN – 我们希望使预测的 Y 与实际的 Y 之间的差异尽可能小。
2. K-Means – 我们希望分组方式与数据中的实际分组方式相似。
3. 线性回归 – 就像 KNN 一样,并且我们也希望可解释部分尽可能大,但解释变量不应过多。
感谢您传播的知识,您太棒了
回答得很好。继续!
嗨 Jason!感谢您提供的精彩教程!我认为您来到这个世界的部分原因是为了帮助他人享受掌握数据科学的乐趣。感谢 JBL。我将在这里发布我的第 01 课的答案
找到一个机器学习模型:词袋模型(Bag of words)。
列举优化可能用于或有助于训练和使用模型的三个例子
1. 选择要包含在词汇表中的最佳单词数量。不多也不少。
2. 使用 TF-IDF 还是不使用?哪个能产生更高的分数(精确率/召回率)?
3. 是否应该使用词干提取?哪个能产生更高的分数?
我不确定 2 和 3 是否是您想要的……感谢任何反馈!
这些都有道理!感谢分享。继续!
第 02 课
from numpy import arange, inf
# 目标函数
def objective(x,y,z)
return (x - y + 1)**2.0 + z**2.0
# return x**2.0 + y**2.0
# 定义输入范围
r_min, r_max = -5.0, 5.0
# 生成网格样本 sample = list()
sample = []
step = 0.1
for x in arange(r_min, r_max+step, step)
for y in arange(r_min, r_max+step, step)
for z in arange(r_min, r_max+step, step)
sample.append([x,y,z])
# 评估样本
best_eval = inf
best_x, best_y, best_z = None, None, None
for x,y, z in sample
eval = objective(x,y,z)
if eval > best_eval: # 存在这里的一个错误,应该是 <
感谢分享。您可以使用 meshgrid 替换三个 arange()。但做得很好!
第 1 课:无监督算法是我的最爱……K-Means……期望最大化……两者都需要将聚类优化到密度分布假设的混合异常值不存在的点。对于 K-Means,因为主要是调整质心,但对于 EM 则更多是围绕似然最大化。感谢 Jason 将我们推向极限:)))
做得好。感谢分享。
大家好!
感谢 Adrian 提供如此出色的课程!
您在第 3 课的任务中是否有一个错误?目标函数中的 C 代表什么?
return (-20.0 * exp(-0.2 * sqrt(0.5 * (x**2+y**2)))
– exp(0.5 * (cos(2 * pi * C * x)+cos(2 * pi*y)) + e + 20)
不应该是
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)?
是的,确实如此。抓得好。
你好
我想用 SA 算法解决 f(x) = x^3-500x^2+700x+100。有人能帮我吗?
您尝试将其输入到示例代码了吗?
第一天任务
机器学习模型的起点之一是线性回归。有几种优化方法。这些可以是
-普通最小二乘法
-批量梯度下降
-随机梯度下降
-小批量梯度下降
第 2 天任务
代码
from numpy import meshgrid, inf
# 目标函数
def objective(x,y,z)
return (x-y + 1)**2.0+z**2.0
# 定义输入范围
r_min,r_max=-5.0, 5.0
# 生成网格样本 sample = list()
sample = []
step = 0.1
for x in meshgrid(r_min,r_max+step, step)
for y in meshgrid(r_min,r_max+step, step)
for z in meshgrid(r_min,r_max+step, step)
sample.append([x,y,z])
# 评估样本
best_eval = inf
best_x, best_y = None, None
for x,y, z in sample
eval = objective(x,y,z)
if eval < best_eval
best_x = x
best_y = y
best_z = z
best_eval = eval
# 总结最佳解决方案
print('Best: f(%.5f,%.5f,%.5f) = %.5f' % (best_x, best_y,best_z, best_eval))
输出
Best: f(-5.00000,-5.00000,0.10000) = 1.01000
第 3 天任务
代码
from scipy.optimize import minimize
from numpy.random import rand
from numpy import e, pi, cos, sqrt, exp
# 目标函数
def objective(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)
# 定义输入范围
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(‘Status : %s’ % result[‘message’])
print(‘Total Evaluations: %d’ % result[‘nfev’])
# 评估解
solution = result[‘x’]
evaluation = objective(solution)
print(‘Solution: f(%s) = %.5f’ % (solution, evaluation))
输出(每次执行时不同)
Status : Optimization terminated successfully.
Total Evaluations: 51
Solution: f([-1.97441491 -1.97444489]) = 6.55965
第 4 天任务
BFGS 和 L-BFGS-B 这两种方法的性能有一些差异。在这些方法中,我们总共进行了 4 次和 3 次评估。这意味着 L-BFGS-B 的工作方式更好(速度更快)。解决方案没有太大的显著差异。对于非凸问题,它效果不佳。
任务 01
由于我的领域与强化学习相关,主要的优化任务将是
– 寻找最优策略。
– 探索/利用权衡。
– 函数逼近的优化器。
任务 02
代码如下:
import numpy as np
from numpy import arange, inf
def objective(x,y)
return x**2.0+y**2.0
r_min = -5
r_max = 5
step = 0.1
sample = []
x = arange(r_min,r_max+step, step)
y = arange(r_min,r_max+step, step)
xx,yy = np.meshgrid(x,y, sparse = True)
eval = objective(xx,yy)
[a, b] = np.shape(eval)
best_value = inf
best_x, best_y = None, None
for i in range(a)
for j in range(b)
if zz[i,j] < best_value
best_x = x[i]
best_y = y[j]
best_value = zz[i,j]
print('Best: f(%.5f,%.5f) = %.5f' % (best_x,best_y,best_value))
任务 02:(请删除上一条)
代码如下:
import numpy as np
from numpy import arange, inf
def objective(x,y,z)
>return (x+1 -y)**2.0+z**2.0 #x**2.0+y**2.0
r_min = -5
r_max = 5
step = 0.1
sample = []
x = arange(r_min,r_max+step, step)
y = arange(r_min,r_max+step, step)
z = arange(r_min,r_max+step, step)
xx,yy,zz = np.meshgrid(x,y,z, sparse = True)
eval = objective(xx,yy,zz)
[a, b, c] = np.shape(eval)
best_value = inf
best_x, best_y, best_z = None, None, None
for i in range(a)
>for j in range(b)
>>for k in range(c)
>>>if eval[i,j,k]>>> best_x=x[i]
>>>>best_y = y[j]
>>>>best_z = z[k]
>>>>best_value = eval[i,j,k]
print(‘Best: f(%.5f,%.5f,%.5f) = %.5f’ % (best_x,best_y,best_z, best_value))
任务 03
结果确实每次都在变化。纯粹是运气,我得到了这个最理想的结果
Status : Optimization terminated successfully.
Total Evaluations: 74
Solution: f([-3.55101317e-05 5.56025188e-05]) = 0.00019
这很有趣哈哈。
问题:为什么这次我们使用 x,y 而不是 x[0], x[1]?
from numpy import arange, inf
# 目标函数
def objective(x, y, z)
return (x-y + 1)**2.0 + z**2.0
# 定义输入范围
r_min, r_max = -5.0, 5.0
# generate a grid sample from the domain
sample = list()
step = 0.1
for x in arange(r_min, r_max+step, step)
for y in arange(r_min, r_max+step, step)
for z in arange(r_min, r_max+step, step)
sample.append([x,y,z])
# 评估样本
best_eval = inf
best_x, best_y, best_z = None, None, None
for x,y, z in sample
eval = objective(x,y,z)
if eval < best_eval
best_x = x
best_y = y
best_z = z
best_eval = eval
# 总结最佳解决方案
print('Best: f(%.5f,%.5f,%.5f) = %.5f' % (best_x, best_y,best_z, best_eval))
Best: f(-5.00000,-4.00000,-0.00000) = 0.00000
你好,
我喜欢您的教学方法,我已经将其推荐给任何寻找优秀参考资料的人。谢谢。
我有一个关于优化的疑问,非常感谢您的想法。
我是否可以在包含机器学习预测的函数中使用优化?
f = sum(pred(x1,x2,…,MLmodel)) ,
范围 x1,x2,… & 起始点 x1,x2,… 以最大化该总和为目标?
这对于此类问题是合理且最佳的方法吗?
我还可以引入额外的条件,例如 sum(X1) <=n1,…吗?
嗨 Shima…是的,你可以那样做。我强烈建议你研究一下贝叶斯优化。
非常感谢你的快速回复。我会研究你关于贝叶斯优化的帖子。
嗨,对于第5课(爬山算法),除了randn之外,你还需要导入rand,因为代码中使用了rand,如果不导入的话会报错。这似乎是导入语句中的一个“拼写错误”。第6课(模拟退火)导入了rand和randn,因为它使用了两者,与爬山算法类似。顺便说一下,这些课程都很棒。
感谢 Jude 的反馈!
感谢信息丰富的课程。您能否展示一个使用贝叶斯推断进行疾病爆发预测建模的插值示例?
嗨 Isatou…你可能会对以下资源感兴趣
http://www.ijtmgh.com/article_95527.html
在第4课的任务中,我尝试了
# 目标函数
def objective(x)
return x[0]**4.0 + x[1]**3.0 + 3*x[2]**5
# 目标函数的导数
def derivative(x)
return [4.0 * x[0]**3, 3.0*x[1]**2, 15*x[2]**4]
# 定义输入范围
r_min, r_max = -5.0, 5.0
# 将起始点定义为从域中随机采样
pt = r_min + rand(2) * (r_max – r_min)
# 执行 bfgs 算法搜索
result = minimize(objective, pt, method=’L-BFGS-B’, jac=derivative)
然后我收到了以下错误:
IndexError: index 2 is out of bounds for axis 0 with size 2
为什么会这样?唯一定义的边界是 [-5,5] 的范围,这并没有真正指定它是在 x0、x1(还是 x2)方向上。您如何解决这个问题?
嗨 Joseph…你是自己输入的代码还是复制粘贴的?
我复制粘贴了代码,然后它工作了。然后我修改了它,得到了那个错误。我将修改后的版本复制并粘贴到了这个消息中。
嗨 Joseph…你可能也想在 Google Colab 中试试。StackOverflow 也是一个与机器学习从业者讨论错误的好资源。
万一有人遇到同样的问题,错误在于它应该是 rand(3)
在开发体育博彩模型时,人们可能更注重利润而不是准确性。利润可能被计算为对模型做出的每一次选择都投入一个神话般的 1 英镑赌注,但这可能导致扭曲的、不现实的结果,如果一个冷门选手爆冷获胜。因此,人们可能是在优化可变赌注,换句话说,总是赢 1 英镑,例如以 2/1 的赔率下注 50 便士等。
问题:在第 05 课爬山算法中,代码行 23,为什么使用 randn(正态分布)而不是 rand(均匀分布)?
嗨 Youcef…两者都可以用来阐述概念。两者都试试,然后告诉我们你的发现。
我尝试了两种分布(均匀和正态),配置如下:
目标函数:f = x**2 + y**2
步长 = 0.2
迭代次数 = 100
运行次数 = 100
对于均匀分布:
找到的平均解是:0.011702
到达解的平均步数:31
对于正态分布:
找到的平均解是:0.028597
到达解的平均步数:31
所以是的,基本上我们用这两种分布得到的结果是相同的。
另外,对于第 23 行,我对随机生成的向量进行了归一化,并将步长设置为决定其大小。我不确定这是否有区别。
无导数优化是一种机器学习方法。粒子群优化、遗传算法、贝叶斯优化是一些例子。
感谢 Rehan 的反馈!
感谢 James 的精彩课程。
Q1)我选择了非线性回归分析用于结构可靠性,以及 Box-Behnken RSM 用于基于风险的设计优化(RBDO)。
嗨 Lexi…不用谢!继续努力,如果我们在内容方面有什么问题,请随时告诉我们。
第 5 课:爬山法
from numpy.random import randn
from numpy import asarray
bounds = asarray([[-5.0, 5.0], [-5.0, 5.0]])
n_iterations = 100
step_size = 0.1
def objective(x)
return x[0]**2.0 + x[1]**2.0
结果
>0 f([-3.68579761 1.46120481]) = 15.72022
>1 f([-3.5723113 1.51378226]) = 15.05294
>3 f([-3.54142472 1.54298156]) = 14.92248
.
.
.
>92 f([-0.78315513 0.46426033]) = 0.82887
>93 f([-0.58243179 0.54524862]) = 0.63652
>95 f([-0.4682943 0.58038478]) = 0.55615
>99 f([-0.37237035 0.63859304]) = 0.54646
第 6 课:模拟退火
bounds = asarray([[-5.0, 5.0], [-5.0, 5.0]])
n_iterations = 100
step_size = 0.1
temp = -0.01
# Ackley 函数
def objective(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)
输出结果:
>0 f([0.1717444 0.27422098]) = 2.43902
>2 f([0.0853289 0.20363316]) = 1.55872
>5 f([0.07214107 0.1278015 ]) = 0.91070
>10 f([0.00746073 0.04047236]) = 0.16089
>14 f([-0.02684032 0.00021496]) = 0.09499
>44 f([ 0.00773109 -0.01292497]) = 0.04863
任务_1
———-
让我们以决策树为例进行机器学习模型。决策树是一种流行的模型类型,可用于分类和回归问题。以下是与此模型相关的三个示例:
超参数调优:决策树模型有几个重要的超参数,例如树的深度、最小样本数和分裂标准。可以使用优化方法来查找这些超参数的最佳值。例如,可以使用网格搜索或贝叶斯优化等技术进行优化,以找到产生最佳性能的超参数组合。
特征选择:决策树通常会接收大量特征,但有时选择最重要的特征而不是使用所有特征会更有效。可以使用优化方法来确定最关键的特征并降低模型复杂度。这可以提高模型的整体性能并加速训练过程。
训练时间优化:在大型数据集上训练决策树可能很耗时。可以使用优化来减少训练时间或优化内存使用。例如,通过使用并行计算或专用训练算法,可以优化训练时间。
这些示例代表了优化可应用于决策树的不同场景。但是,无论选择哪种模型,都要记住,在大多数机器学习模型的训练或使用过程中,许多情况下优化都可以带来益处。
嗨 Peri…感谢您的反馈!如果您对材料有任何疑问,请随时告知我们!
对于需要优化的三个示例,机器学习中有许多算法拥有许多参数需要优化以获得高效的工作,例如:
1- 随机森林分类器,它由多个决策树构成,需要优化许多参数,例如使用的决策树数量以及内部节点分裂所需的最小样本数。
同样,用于特征的数量也应该减少,并删除不相关的特征,以获得更准确的预测。
2- ANN,代表人工神经网络,它有许多参数需要优化,例如神经网络中的层数和每层中的神经元数量,以及学习率。
3- 长短期记忆(LSTM),它有许多参数需要优化才能获得良好的准确结果,例如 LSTM 层数、每层中的隐藏单元数和学习率。
嗨 moh…很棒的例子!如果您对我们的内容有任何疑问,请随时告诉我们。