Machine-Learning-Mastery-优化教程-八-

106 阅读1小时+

Machine Learning Mastery 优化教程(八)

原文:Machine Learning Mastery

协议:CC BY-NC-SA 4.0

Python 中从零开始的随机爬山

原文:machinelearningmastery.com/stochastic-…

最后更新于 2021 年 10 月 12 日

随机爬山是一种优化算法。

它利用随机性作为搜索过程的一部分。这使得该算法适用于其他局部搜索算法运行不佳的非线性目标函数。

它也是一种局部搜索算法,这意味着它修改单个解,并搜索搜索空间的相对局部区域,直到找到局部最优解。这意味着它适用于单峰优化问题或在应用全局优化算法后使用。

在本教程中,您将发现函数优化的爬山优化算法

完成本教程后,您将知道:

  • 爬山是一种用于函数优化的随机局部搜索算法。
  • 如何在 Python 中实现从零开始的爬山算法?
  • 如何应用爬山算法并检验算法的结果?

用我的新书机器学习优化启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

Let’s get started.Stochastic Hill Climbing in Python from Scratch

从零开始用 Python 随机爬山 图片由约翰提供,保留部分权利。

教程概述

本教程分为三个部分;它们是:

  1. 爬山算法
  2. 爬山算法的实现
  3. 应用爬山算法的示例

爬山算法

随机爬山算法是一种随机局部搜索优化算法。

它以一个初始点作为输入和一个步长,其中步长是搜索空间内的一个距离。

该算法将初始点作为当前最佳候选解,并在所提供点的步长距离内生成一个新点。计算生成的点,如果它等于或优于当前点,则将其作为当前点。

新点的生成使用随机性,通常称为随机爬山。这意味着,作为搜索的一部分,该算法可以跳过响应表面的颠簸、噪声、不连续或欺骗性区域。

随机爬山从上坡动作中随机选择;选择的概率可以随着上坡运动的陡度而变化。

—第 124 页,人工智能:现代方法,2009 年。

重要的是接受具有相等评估的不同点,因为它允许算法继续探索搜索空间,例如跨越响应表面的平坦区域。限制这些所谓的“横向”移动以避免无限循环可能也会有所帮助。

*> 如果我们总是在没有上坡移动时允许侧向移动,那么每当算法达到不是路肩的平坦局部最大值时,就会出现无限循环。一个常见的解决方案是限制允许的连续横向移动的次数。例如,我们可以允许多达 100 次连续的横向移动

—第 123 页,人工智能:现代方法,2009 年。

该过程持续进行,直到满足停止条件,例如功能评估的最大数量或者在给定数量的功能评估内没有改善。

该算法得名于它将(随机地)爬上响应面的山丘到达局部最优解的事实。这并不意味着它只能用于目标函数最大化;这只是一个名字。事实上,通常情况下,我们将功能最小化,而不是最大化。

爬山搜索算法(最陡爬坡版本)[……]只是一个不断向增值方向移动的循环——即上坡。当到达没有邻居具有更高值的“峰值”时,它终止。

—第 122 页,人工智能:现代方法,2009 年。

作为一种局部搜索算法,它会陷入局部最优。然而,多次重启可以允许算法定位全局最优。

随机重启爬山……从随机生成的初始状态开始进行一系列爬山搜索,直到找到目标。

—第 124 页,人工智能:现代方法,2009 年。

步长必须足够大,以允许搜索空间中更好的邻近点被定位,但不能大到搜索跳出包含局部最优值的区域。

爬山算法的实现

在撰写本文时,SciPy 库没有提供随机爬山的实现。

尽管如此,我们可以自己实现。

首先,我们必须定义我们的目标函数和目标函数的每个输入变量的界限。目标函数只是一个 Python 函数,我们将其命名为目标()。边界将是一个 2D 数组,每个输入变量都有一个维度,定义了变量的最小值和最大值。

例如,一维目标函数和边界可以定义如下:

# objective function
def objective(x):
	return 0

# define range for input
bounds = asarray([[-5.0, 5.0]])

接下来,我们可以将初始解生成为问题边界内的随机点,然后使用目标函数对其进行评估。

...
# generate an initial point
solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
# evaluate the initial point
solution_eval = objective(solution)

现在,我们可以循环定义为“ n_iterations ”的算法的预定义迭代次数,例如 100 或 1000 次。

...
# run the hill climb
for i in range(n_iterations):
	...

算法迭代的第一步是迈出一步。

这需要一个预定义的“步长”参数,该参数与搜索空间的边界相关。我们将采用高斯分布的随机步长,其中平均值是当前点,标准偏差由“步长定义。这意味着大约 99%的步骤将在当前点的(3 *步长)以内。

...
# take a step
candidate = solution + randn(len(bounds)) * step_size

我们没有必要以这种方式采取措施。您可能希望在 0 和步长之间使用均匀分布。例如:

...
# take a step
candidate = solution + rand(len(bounds)) * step_size

接下来我们需要用目标函数评估新的候选解。

...
# evaluate candidate point
candidte_eval = objective(candidate)

然后,我们需要检查这个新点的评估是否与当前最佳点一样好或更好,如果是,用这个新点替换我们当前的最佳点。

...
# check if we should keep the new point
if candidte_eval <= solution_eval:
	# store the new point
	solution, solution_eval = candidate, candidte_eval
	# report progress
	print('>%d f(%s) = %.5f' % (i, solution, solution_eval))

就这样。

我们可以将这个爬山算法实现为一个可重用的函数,该函数以目标函数的名称、每个输入变量的界限、总迭代次数和步骤作为参数,并返回找到的最佳解及其评估。

# hill climbing local search algorithm
def hillclimbing(objective, bounds, n_iterations, step_size):
	# generate an initial point
	solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
	# evaluate the initial point
	solution_eval = objective(solution)
	# run the hill climb
	for i in range(n_iterations):
		# take a step
		candidate = solution + randn(len(bounds)) * step_size
		# evaluate candidate point
		candidte_eval = objective(candidate)
		# check if we should keep the new point
		if candidte_eval <= solution_eval:
			# store the new point
			solution, solution_eval = candidate, candidte_eval
			# report progress
			print('>%d f(%s) = %.5f' % (i, solution, solution_eval))
	return [solution, solution_eval]

现在我们知道了如何在 Python 中实现爬山算法,让我们看看如何使用它来优化目标函数。

应用爬山算法的示例

在本节中,我们将把爬山优化算法应用于目标函数。

首先,让我们定义我们的目标函数。

我们将使用一个简单的一维 x² 目标函数,其边界为[-5,5]。

下面的示例定义了函数,然后为输入值网格创建了函数响应面的线图,并用红线标记 f(0.0) = 0.0 处的 optima。

# convex unimodal optimization function
from numpy import arange
from matplotlib import pyplot

# objective function
def objective(x):
	return x[0]**2.0

# define range for input
r_min, r_max = -5.0, 5.0
# sample input range uniformly at 0.1 increments
inputs = arange(r_min, r_max, 0.1)
# compute targets
results = [objective([x]) for x in inputs]
# create a line plot of input vs result
pyplot.plot(inputs, results)
# define optimal input value
x_optima = 0.0
# draw a vertical line at the optimal input
pyplot.axvline(x=x_optima, ls='--', color='red')
# show the plot
pyplot.show()

运行该示例会创建目标函数的线图,并清楚地标记函数最优值。

Line Plot of Objective Function With Optima Marked with a Dashed Red Line

用红色虚线标记最优值的目标函数线图

接下来,我们可以将爬山算法应用于目标函数。

首先,我们将播种伪随机数发生器。一般来说,这不是必需的,但是在这种情况下,我希望确保每次运行算法时都得到相同的结果(相同的随机数序列),这样我们就可以在以后绘制结果。

...
# seed the pseudorandom number generator
seed(5)

接下来,我们可以定义搜索的配置。

在这种情况下,我们将搜索算法的 1000 次迭代,并使用 0.1 的步长。假设我们使用高斯函数来生成步长,这意味着大约 99%的所有步长将在给定点的(0.1 * 3)距离内,例如三个标准偏差。

...
n_iterations = 1000
# define the maximum step size
step_size = 0.1

接下来,我们可以执行搜索并报告结果。

...
# perform the hill climbing search
best, score = hillclimbing(objective, bounds, n_iterations, step_size)
print('Done!')
print('f(%s) = %f' % (best, score))

将这些结合在一起,完整的示例如下所示。

# hill climbing search of a one-dimensional objective function
from numpy import asarray
from numpy.random import randn
from numpy.random import rand
from numpy.random import seed

# objective function
def objective(x):
	return x[0]**2.0

# hill climbing local search algorithm
def hillclimbing(objective, bounds, n_iterations, step_size):
	# generate an initial point
	solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
	# evaluate the initial point
	solution_eval = objective(solution)
	# run the hill climb
	for i in range(n_iterations):
		# take a step
		candidate = solution + randn(len(bounds)) * step_size
		# evaluate candidate point
		candidte_eval = objective(candidate)
		# check if we should keep the new point
		if candidte_eval <= solution_eval:
			# store the new point
			solution, solution_eval = candidate, candidte_eval
			# report progress
			print('>%d f(%s) = %.5f' % (i, solution, solution_eval))
	return [solution, solution_eval]

# seed the pseudorandom number generator
seed(5)
# define range for input
bounds = asarray([[-5.0, 5.0]])
# define the total iterations
n_iterations = 1000
# define the maximum step size
step_size = 0.1
# perform the hill climbing search
best, score = hillclimbing(objective, bounds, n_iterations, step_size)
print('Done!')
print('f(%s) = %f' % (best, score))

运行该示例会报告搜索的进度,包括迭代次数、函数输入以及每次检测到改进时目标函数的响应。

在搜索结束时,找到最佳解决方案并报告其评估。

在这种情况下,我们可以看到算法的 1000 次迭代中有大约 36 次改进,并且有一个非常接近 0.0 的最优输入的解,其计算结果为 f(0.0) = 0.0。

>1 f([-2.74290923]) = 7.52355
>3 f([-2.65873147]) = 7.06885
>4 f([-2.52197291]) = 6.36035
>5 f([-2.46450214]) = 6.07377
>7 f([-2.44740961]) = 5.98981
>9 f([-2.28364676]) = 5.21504
>12 f([-2.19245939]) = 4.80688
>14 f([-2.01001538]) = 4.04016
>15 f([-1.86425287]) = 3.47544
>22 f([-1.79913002]) = 3.23687
>24 f([-1.57525573]) = 2.48143
>25 f([-1.55047719]) = 2.40398
>26 f([-1.51783757]) = 2.30383
>27 f([-1.49118756]) = 2.22364
>28 f([-1.45344116]) = 2.11249
>30 f([-1.33055275]) = 1.77037
>32 f([-1.17805016]) = 1.38780
>33 f([-1.15189314]) = 1.32686
>36 f([-1.03852644]) = 1.07854
>37 f([-0.99135322]) = 0.98278
>38 f([-0.79448984]) = 0.63121
>39 f([-0.69837955]) = 0.48773
>42 f([-0.69317313]) = 0.48049
>46 f([-0.61801423]) = 0.38194
>48 f([-0.48799625]) = 0.23814
>50 f([-0.22149135]) = 0.04906
>54 f([-0.20017144]) = 0.04007
>57 f([-0.15994446]) = 0.02558
>60 f([-0.15492485]) = 0.02400
>61 f([-0.03572481]) = 0.00128
>64 f([-0.03051261]) = 0.00093
>66 f([-0.0074283]) = 0.00006
>78 f([-0.00202357]) = 0.00000
>119 f([0.00128373]) = 0.00000
>120 f([-0.00040911]) = 0.00000
>314 f([-0.00017051]) = 0.00000
Done!
f([-0.00017051]) = 0.000000

将搜索的进度作为一个线形图来回顾可能会很有趣,它显示了每次出现改进时最佳解决方案评估的变化。

我们可以更新*爬山()*来跟踪每次有改进的目标函数评估,并返回这个分数列表。

# hill climbing local search algorithm
def hillclimbing(objective, bounds, n_iterations, step_size):
	# generate an initial point
	solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
	# evaluate the initial point
	solution_eval = objective(solution)
	# run the hill climb
	scores = list()
	scores.append(solution_eval)
	for i in range(n_iterations):
		# take a step
		candidate = solution + randn(len(bounds)) * step_size
		# evaluate candidate point
		candidte_eval = objective(candidate)
		# check if we should keep the new point
		if candidte_eval <= solution_eval:
			# store the new point
			solution, solution_eval = candidate, candidte_eval
			# keep track of scores
			scores.append(solution_eval)
			# report progress
			print('>%d f(%s) = %.5f' % (i, solution, solution_eval))
	return [solution, solution_eval, scores]

然后,我们可以创建这些分数的折线图,以查看搜索过程中发现的每个改进的目标函数的相对变化。

...
# line plot of best scores
pyplot.plot(scores, '.-')
pyplot.xlabel('Improvement Number')
pyplot.ylabel('Evaluation f(x)')
pyplot.show()

将这些联系在一起,下面列出了在搜索过程中执行搜索并绘制改进解决方案的目标函数分数的完整示例。

# hill climbing search of a one-dimensional objective function
from numpy import asarray
from numpy.random import randn
from numpy.random import rand
from numpy.random import seed
from matplotlib import pyplot

# objective function
def objective(x):
	return x[0]**2.0

# hill climbing local search algorithm
def hillclimbing(objective, bounds, n_iterations, step_size):
	# generate an initial point
	solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
	# evaluate the initial point
	solution_eval = objective(solution)
	# run the hill climb
	scores = list()
	scores.append(solution_eval)
	for i in range(n_iterations):
		# take a step
		candidate = solution + randn(len(bounds)) * step_size
		# evaluate candidate point
		candidte_eval = objective(candidate)
		# check if we should keep the new point
		if candidte_eval <= solution_eval:
			# store the new point
			solution, solution_eval = candidate, candidte_eval
			# keep track of scores
			scores.append(solution_eval)
			# report progress
			print('>%d f(%s) = %.5f' % (i, solution, solution_eval))
	return [solution, solution_eval, scores]

# seed the pseudorandom number generator
seed(5)
# define range for input
bounds = asarray([[-5.0, 5.0]])
# define the total iterations
n_iterations = 1000
# define the maximum step size
step_size = 0.1
# perform the hill climbing search
best, score, scores = hillclimbing(objective, bounds, n_iterations, step_size)
print('Done!')
print('f(%s) = %f' % (best, score))
# line plot of best scores
pyplot.plot(scores, '.-')
pyplot.xlabel('Improvement Number')
pyplot.ylabel('Evaluation f(x)')
pyplot.show()

运行该示例执行搜索并像以前一样报告结果。

创建一个线形图,显示爬山搜索过程中每项改进的目标函数评估。在搜索过程中,我们可以看到目标函数评估的大约 36 个变化,随着算法收敛到最优值,最初的变化很大,搜索结束时的变化非常小,甚至察觉不到。

Line Plot of Objective Function Evaluation for Each Improvement During the Hill Climbing Search

爬山搜索过程中每次改进的目标函数评估线图

假设目标函数是一维的,我们可以像上面那样直接绘制响应面。

通过将搜索过程中找到的最佳候选解决方案绘制为响应面中的点来查看搜索进度可能会很有趣。我们期望一系列的点沿着响应面到达最优值。

这可以通过首先更新*爬山()*功能来跟踪每个最佳候选解在搜索过程中的位置,然后返回最佳解列表来实现。

# hill climbing local search algorithm
def hillclimbing(objective, bounds, n_iterations, step_size):
	# generate an initial point
	solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
	# evaluate the initial point
	solution_eval = objective(solution)
	# run the hill climb
	solutions = list()
	solutions.append(solution)
	for i in range(n_iterations):
		# take a step
		candidate = solution + randn(len(bounds)) * step_size
		# evaluate candidate point
		candidte_eval = objective(candidate)
		# check if we should keep the new point
		if candidte_eval <= solution_eval:
			# store the new point
			solution, solution_eval = candidate, candidte_eval
			# keep track of solutions
			solutions.append(solution)
			# report progress
			print('>%d f(%s) = %.5f' % (i, solution, solution_eval))
	return [solution, solution_eval, solutions]

然后,我们可以创建目标函数响应面的图,并像以前一样标记 optima。

...
# sample input range uniformly at 0.1 increments
inputs = arange(bounds[0,0], bounds[0,1], 0.1)
# create a line plot of input vs result
pyplot.plot(inputs, [objective([x]) for x in inputs], '--')
# draw a vertical line at the optimal input
pyplot.axvline(x=[0.0], ls='--', color='red')

最后,我们可以将通过搜索找到的候选解决方案的顺序绘制为黑点。

...
# plot the sample as black circles
pyplot.plot(solutions, [objective(x) for x in solutions], 'o', color='black')

将这些联系在一起,下面列出了在目标函数的响应面上绘制改进解决方案序列的完整示例。

# hill climbing search of a one-dimensional objective function
from numpy import asarray
from numpy import arange
from numpy.random import randn
from numpy.random import rand
from numpy.random import seed
from matplotlib import pyplot

# objective function
def objective(x):
	return x[0]**2.0

# hill climbing local search algorithm
def hillclimbing(objective, bounds, n_iterations, step_size):
	# generate an initial point
	solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
	# evaluate the initial point
	solution_eval = objective(solution)
	# run the hill climb
	solutions = list()
	solutions.append(solution)
	for i in range(n_iterations):
		# take a step
		candidate = solution + randn(len(bounds)) * step_size
		# evaluate candidate point
		candidte_eval = objective(candidate)
		# check if we should keep the new point
		if candidte_eval <= solution_eval:
			# store the new point
			solution, solution_eval = candidate, candidte_eval
			# keep track of solutions
			solutions.append(solution)
			# report progress
			print('>%d f(%s) = %.5f' % (i, solution, solution_eval))
	return [solution, solution_eval, solutions]

# seed the pseudorandom number generator
seed(5)
# define range for input
bounds = asarray([[-5.0, 5.0]])
# define the total iterations
n_iterations = 1000
# define the maximum step size
step_size = 0.1
# perform the hill climbing search
best, score, solutions = hillclimbing(objective, bounds, n_iterations, step_size)
print('Done!')
print('f(%s) = %f' % (best, score))
# sample input range uniformly at 0.1 increments
inputs = arange(bounds[0,0], bounds[0,1], 0.1)
# create a line plot of input vs result
pyplot.plot(inputs, [objective([x]) for x in inputs], '--')
# draw a vertical line at the optimal input
pyplot.axvline(x=[0.0], ls='--', color='red')
# plot the sample as black circles
pyplot.plot(solutions, [objective(x) for x in solutions], 'o', color='black')
pyplot.show()

运行该示例执行爬山搜索,并像以前一样报告结果。

如前所述,创建响应面图,显示熟悉的函数碗形,垂直红线标记函数的最佳值。

搜索过程中找到的最佳解决方案序列显示为黑点,沿碗形向下延伸至最佳位置。

Response Surface of Objective Function With Sequence of Best Solutions Plotted as Black Dots

目标函数的响应面,最佳解序列绘制为黑点

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

教程

蜜蜂

文章

摘要

在本教程中,您发现了函数优化的爬山优化算法

具体来说,您了解到:

  • 爬山是一种用于函数优化的随机局部搜索算法。
  • 如何在 Python 中实现从零开始的爬山算法?
  • 如何应用爬山算法并检验算法的结果?

你有什么问题吗? 在下面的评论中提问,我会尽力回答。*

随机优化算法的简单介绍

原文:machinelearningmastery.com/stochastic-…

最后更新于 2021 年 10 月 12 日

随机优化是指在目标函数或优化算法中使用随机性。

具有挑战性的优化算法,如高维非线性目标问题,可能包含多个局部最优解,确定性优化算法可能陷入局部最优解。

随机优化算法提供了一种替代方法,允许在搜索过程中作出次优的局部决策,这可能增加过程定位目标函数全局最优值的概率。

在本教程中,您将发现随机优化的温和介绍。

完成本教程后,您将知道:

  • 随机优化算法利用随机性作为搜索过程的一部分。
  • 模拟退火和遗传算法等随机优化算法的例子。
  • 使用随机优化算法时的实际考虑,如重复评估。

用我的新书机器学习优化启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

Let’s get started.A Gentle Introduction to Stochastic Optimization Algorithms

随机优化算法简介 约翰摄,版权所有。

教程概述

本教程分为三个部分;它们是:

  1. 什么是随机优化?
  2. 随机优化算法
  3. 随机优化的实际考虑

什么是随机优化?

优化指的是寻找函数输入的优化算法,其结果是目标函数的最小值或最大值。

随机优化或随机搜索是指以某种方式涉及随机性的优化任务,例如从目标函数或优化算法中。

随机搜索和优化属于在提供给算法的测量中存在随机性噪声和/或在算法本身中存在注入(蒙特卡罗)随机性的问题。

—第十三页,随机搜索与优化简介,2003。

目标函数中的随机性意味着候选解的评估涉及一些不确定性或噪声,并且必须选择能够在存在这种噪声的情况下在搜索中取得进展的算法。

算法中的随机性被用作一种策略,例如随机或概率决策。它被用作确定性决策的替代方案,以努力提高定位全局最优或更好的局部最优的可能性。

标准的随机优化方法是脆弱的,对步长选择和其他算法参数敏感,并且在表现良好的目标族之外表现出不稳定性。

——随机优化中更好模型的重要性,2019。

在讨论随机优化时,更常见的是指使用随机性的算法,而不是包含噪声评估的目标函数。这是因为目标函数中的随机性可以通过在优化算法中使用随机性来解决。因此,随机优化可以被称为“鲁棒优化

确定性算法可能会被候选解的噪声评估或噪声函数梯度误导(例如“T0”欺骗了或“混淆了”),导致算法反弹或停滞(例如无法收敛)。

随机优化方法提供了一种处理固有系统噪声和处理高度非线性、高维或不适合经典确定性优化方法的模型或系统的方法。

——随机优化,2011。

在优化算法中使用随机性允许搜索过程在可能具有非线性响应面的具有挑战性的优化问题上表现良好。这是通过算法在搜索空间中采取局部次优的步骤或移动来实现的,这允许它避开局部最优。

随机性有助于避开局部最优,增加找到全局最优的机会。

—第 8 页,优化算法,2019。

随机优化算法中使用的随机性不一定是真正的随机性;相反,伪随机就足够了。一个伪随机数发生器几乎普遍用于随机优化。

在随机优化算法中使用随机性并不意味着该算法是随机的。相反,这意味着在搜索过程中做出的一些决定涉及到某种程度的随机性。例如,我们可以将其概念化为由算法进行的从搜索空间中的当前点到下一点的移动可以根据相对于最优移动的概率分布来进行。

现在我们已经了解了什么是随机优化,让我们来看一些随机优化算法的例子。

随机优化算法

算法中随机性的使用通常意味着这些技术被称为“启发式搜索”,因为它们使用粗略的经验法则来寻找最优解,而不是精确的过程。

许多随机算法受生物或自然过程的启发,可被称为“元试探法”,作为为目标函数的特定搜索提供条件的高阶过程。它们也被称为“T2”黑盒“T3”优化算法。

元启发式是一个相当不幸的术语,经常用来描述随机优化的一个主要子领域,实际上是主要子领域。

—第 7 页,元试探法精要,2011。

有许多随机优化算法。

随机优化算法的一些例子包括:

  • 迭代局部搜索
  • 随机爬山
  • 随机梯度下降
  • 禁忌搜索
  • 贪婪随机自适应搜索过程

受生物或物理过程启发的随机优化算法的一些例子包括:

  • 模拟退火
  • 进化策略
  • 遗传算法
  • 差分进化
  • 粒子群优化算法

现在我们已经熟悉了一些随机优化算法的例子,让我们看看使用它们时的一些实际考虑。

随机优化的实际考虑

使用随机优化算法时有一些重要的考虑因素。

该过程的随机性质意味着算法的任何一次运行都是不同的,给定算法所使用的不同的随机源,以及搜索的不同起点和搜索过程中做出的决定。

用作随机源的伪随机数发生器可以被播种,以确保在算法的每次运行中提供相同的随机数序列。这对于小演示和教程来说很好,尽管它很脆弱,因为它与算法固有的随机性背道而驰。

相反,可以多次执行给定的算法来控制过程的随机性。

这种算法多次运行的想法可用于两种关键情况:

  • 比较算法
  • 评估最终结果

可以基于所找到的结果的相对质量、所执行的功能评估的数量或者这些考虑的某种组合或推导来比较算法。任何一次运行的结果都将取决于算法所使用的随机性,并且单独不能有意义地表示算法的能力。相反,应该使用重复评估的策略。

随机优化算法之间的任何比较都需要用不同的随机性来源重复评估每个算法,并总结找到的最佳结果的概率分布,例如目标值的平均值和标准偏差。然后可以比较每个算法的平均结果。

在可能存在多个局部极小值的情况下,在满足我们的终止条件后,结合随机重启可能是有益的,其中我们从随机选择的初始点重启我们的局部下降方法。

—第 66 页,优化算法,2019。

类似地,单独选择的优化算法的任何单次运行都不能有意义地代表目标函数的全局最优。相反,应该使用重复评估的策略来开发最优解的分布。

分布的最大值或最小值可以作为最终的解决方案,分布本身将提供一个参考点和信心,即考虑到所花费的资源,找到的解决方案是“相对好的””或“足够好的””。**

*** 多次重启:一种通过对优化问题重复应用随机优化算法来提高定位全局最优解的可能性的方法。

随机优化算法在目标函数上的重复应用有时被称为多次重启策略,并且可以内置于优化算法本身,或者更一般地被规定为围绕所选随机优化算法的过程。

每次你做一次随机重启,爬山者就会以某种(可能是新的)局部最优状态结束。

—第 26 页,元试探法精要,2011。

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

相关教程

报纸

文章

摘要

在本教程中,您发现了随机优化的温和介绍。

具体来说,您了解到:

  • 随机优化算法利用随机性作为搜索过程的一部分。
  • 模拟退火和遗传算法等随机优化算法的例子。
  • 使用随机优化算法时的实际考虑,如重复评估。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。**

如何选择优化算法

原文:machinelearningmastery.com/tour-of-opt…

最后更新于 2021 年 10 月 12 日

优化是寻找目标函数的一组输入的问题,该目标函数导致最大或最小的函数求值。

从拟合逻辑回归模型到训练人工神经网络,这是许多机器学习算法背后的挑战性问题。

在流行的科学代码库中,可能有数百种流行的优化算法,也可能有数十种算法可供选择。这使得知道对于给定的优化问题要考虑哪些算法变得很有挑战性。

在本教程中,您将发现不同优化算法的导游。

完成本教程后,您将知道:

  • 优化算法可以分为使用导数的算法和不使用导数的算法。
  • 经典算法使用目标函数的一阶导数,有时也使用二阶导数。
  • 直接搜索和随机算法是为函数导数不可用的目标函数设计的。

用我的新书机器学习优化启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

Let’s get started.How to Choose an Optimization Algorithm

如何选择优化算法 图片由 Matthewjs007 提供,保留部分权利。

教程概述

本教程分为三个部分;它们是:

  1. 优化算法
  2. 可微目标函数
  3. 非微分目标函数

优化算法

优化是指寻找函数的输入参数或自变量的过程,这些参数或自变量导致函数的最小或最大输出。

机器学习中遇到的最常见的优化问题类型是连续函数优化,其中函数的输入参数是实值数值,例如浮点值。函数的输出也是输入值的实值计算。

我们可以将这类问题称为连续函数优化,以区别于采用离散变量的函数,并称为组合优化问题。

有许多不同类型的优化算法可以用于连续函数优化问题,也许还有许多方法可以对它们进行分组和总结。

对优化算法进行分组的一种方法是基于正在被优化的目标函数的可用信息量,该信息量又可以被优化算法使用和利用。

通常,关于目标函数的可用信息越多,如果该信息可以有效地用于搜索,该函数就越容易优化。

也许优化算法的主要分歧在于目标函数是否能在某一点上被微分。也就是说,对于给定的候选解,是否可以计算函数的一阶导数(梯度或斜率)。这将算法分为可以利用计算出的梯度信息的算法和不利用计算出的梯度信息的算法。

  • 可微目标函数?
    • 使用导数信息的算法。
    • 不使用导数信息的算法。

在本教程中,我们将把它作为分组优化算法的主要部分,并研究可微和不可微目标函数的算法。

:这并不是对连续函数优化算法的详尽介绍,尽管它确实涵盖了你作为一名常规从业者可能遇到的主要方法。

可微目标函数

一个可微函数是一个可以计算输入空间中任意给定点的导数的函数。

一个函数对一个值的导数是函数在该点的变化率或变化量。它通常被称为斜坡。

  • 一阶导数:目标函数在给定点的斜率或变化率。

具有一个以上输入变量(例如多元输入)的函数的导数通常称为梯度。

  • 梯度:多元连续目标函数的导数。

多元目标函数的导数是一个向量,向量中的每个元素都称为偏导数,或者是给定变量在假设所有其他变量保持不变的情况下的变化率。

  • 偏导数:多元目标函数导数的元素。

我们可以计算目标函数导数的导数,即目标函数变化率的变化率。这叫做二阶导数。

  • 二阶导数:目标函数导数变化的速率。

对于一个接受多个输入变量的函数,这是一个矩阵,称为黑森矩阵。

  • 黑森矩阵:具有两个或多个输入变量的函数的二阶导数。

简单的可微函数可以使用微积分进行分析优化。通常,我们感兴趣的目标函数无法解析求解。

如果可以计算出目标函数的梯度,优化就容易得多,因此,对使用导数的优化算法的研究比不使用导数的算法多得多。

使用梯度信息的一些算法组包括:

  • 包围算法
  • 局部下降算法
  • 一阶算法
  • 二阶算法

:本分类受 2019 年《优化的算法》一书启发

让我们依次仔细看看每一个。

包围算法

包围优化算法旨在解决具有一个输入变量的优化问题,其中最优解已知存在于特定范围内。

包围算法能够有效地导航已知范围并定位最优解,尽管它们假设只存在一个最优解(称为单峰目标函数)。

如果导数信息不可用,一些包围算法可以在没有导数信息的情况下使用。

包围算法的例子包括:

  • 斐波那契搜索
  • 黄金分割搜索
  • 等分法

局部下降算法

局部下降优化算法适用于具有多个输入变量和单个全局最优值(例如单峰目标函数)的优化问题。

也许局部下降算法最常见的例子是线性搜索算法。

  • 行搜索

线性搜索有许多变体(例如布伦特-德克尔算法),但是该过程通常涉及选择在搜索空间中移动的方向,然后在所选方向上的线或超平面中执行包围式搜索。

重复这个过程,直到没有进一步的改进。

限制在于优化搜索空间中的每个方向移动在计算上是昂贵的。

一阶算法

一阶优化算法明确涉及使用一阶导数(梯度)来选择在搜索空间中移动的方向。

该过程包括首先计算函数的梯度,然后使用步长(也称为学习率)沿相反方向(例如下坡至最小化问题的最小值)跟随梯度。

步长是一个超参数,它控制在搜索空间中移动多远,这与“局部下降算法”不同,后者对每个方向的移动执行一个完整的直线性搜索。

步长过小会导致搜索耗时较长并可能被卡住,而步长过大则会导致搜索空间的曲折或跳跃,完全错过最佳值。

一阶算法通常称为梯度下降,更具体的名称是指程序的微小扩展,例如:

  • 梯度下降
  • 动力
  • 阿达格勒
  • RMSProp
  • 圣经》和《古兰经》传统中)亚当(人类第一人的名字

梯度下降算法还为流行的随机版本算法提供了模板,该算法被称为随机梯度下降(SGD),用于训练人工神经网络(深度学习)模型。

重要的区别是梯度是适当的,而不是直接计算的,使用训练数据的预测误差,如一个样本(随机),所有例子(批次),或训练数据的小子集(小批次)。

旨在加速梯度下降算法(动量等)的扩展。)可以是并且通常与 SGD 一起使用。

  • 随机梯度下降
  • 分批梯度下降
  • 小批量梯度下降

二阶算法

二阶优化算法明确涉及使用二阶导数(Hessian)来选择在搜索空间中移动的方向。

这些算法只适用于那些可以计算或近似黑森矩阵的目标函数。

单变量目标函数的二阶优化算法示例包括:

  • 牛顿法
  • 割线法

多元目标函数的二阶方法称为拟牛顿法。

  • 拟牛顿法

有许多拟牛顿方法,它们通常以算法的开发者命名,例如:

  • 戴维森-弗莱彻-鲍威尔
  • 布赖登-弗莱彻-戈德法布-尚诺(BFGS)
  • 有限记忆 BFGS(左 BFGS)

现在我们已经熟悉了所谓的经典优化算法,让我们看看当目标函数不可微时使用的算法。

非微分目标函数

利用目标函数导数的优化算法快速有效。

然而,有些目标函数的导数无法计算,这通常是因为该函数由于各种现实原因而变得复杂。或者导数可以在定义域的某些区域计算,但不是全部,或者不是很好的指导。

上一节描述的经典算法的目标函数的一些困难包括:

  • 没有功能的分析描述(例如模拟)。
  • 多重全局最优(例如多模态)。
  • 随机函数评估(如噪声)。
  • 不连续的目标函数(例如,具有无效解的区域)。

因此,有些优化算法不期望一阶或二阶导数可用。

这些算法有时被称为黑盒优化算法,因为它们对目标函数的假设很少或没有(相对于经典方法)。

这些算法的组合包括:

  • 直接算法
  • 随机算法
  • 人口算法

让我们依次仔细看看每一个。

直接算法

直接优化算法适用于无法计算导数的目标函数。

算法是确定性的过程,并且通常假设目标函数具有单个全局最优值,例如单峰。

直接搜索方法通常也被称为“模式搜索,因为它们可以使用几何形状或决策(例如模式)来导航搜索空间。

梯度信息直接从目标函数比较搜索空间中的点的分数之间的相对差异的结果来近似(因此得名)。然后,这些直接估计被用于选择在搜索空间中移动的方向,并对最优区域进行三角测量。

直接搜索算法的例子包括:

  • 循环坐标搜索
  • 鲍威尔方法
  • 胡克-吉夫斯方法
  • NelderMead 单纯形搜索

随机算法

随机优化算法是在目标函数的搜索过程中利用随机性的算法,这些目标函数的导数无法计算。

与确定性直接搜索方法不同,随机算法通常需要对目标函数进行更多的采样,但能够处理具有欺骗性局部最优的问题。

随机优化算法包括:

  • 模拟退火
  • 进化策略
  • 交叉熵方法

人口算法

种群优化算法是一种随机优化算法,它维护一个候选解池(种群),这些解一起用于采样、探索和钻研一个最优解。

这种类型的算法旨在解决更具挑战性的目标问题,这些问题可能具有噪声函数评估和许多全局最优(多模态),并且使用其他方法找到好的或足够好的解决方案是具有挑战性的或不可行的。

候选解决方案库增加了搜索的健壮性,增加了克服局部最优的可能性。

群体优化算法的例子包括:

  • 遗传算法
  • 差分进化
  • 粒子群优化算法

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

文章

摘要

在本教程中,您发现了不同优化算法的导游。

具体来说,您了解到:

  • 优化算法可以分为使用导数的算法和不使用导数的算法。
  • 经典算法使用目标函数的一阶导数,有时也使用二阶导数。
  • 直接搜索和随机算法是为函数导数不可用的目标函数设计的。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。

Python 中的单变量函数优化

原文:machinelearningmastery.com/univariate-…

最后更新于 2021 年 10 月 12 日

如何优化一元函数?

单变量函数优化包括从目标函数中找到导致最优输出的函数的输入。

当用一个参数拟合模型或调整具有单个超参数的模型时,这是机器学习中常见的过程。

需要一种有效的算法来解决这种类型的优化问题,该算法将以目标函数的最少评估次数找到最佳解决方案,因为目标函数的每次评估可能在计算上很昂贵,例如在数据集上拟合和评估模型。

这不包括昂贵的网格搜索和随机搜索算法,而是支持像布伦特方法这样的高效算法。

在本教程中,您将发现如何在 Python 中执行单变量函数优化。

完成本教程后,您将知道:

  • 单变量函数优化涉及到为一个目标函数寻找一个最佳输入,这个目标函数需要一个连续的参数。
  • 如何对无约束凸函数进行单变量函数优化?
  • 如何对无约束非凸函数进行单变量函数优化?

用我的新书机器学习优化启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

Let’s get started.Univariate Function Optimization in Python

Python 中的单变量函数优化 图片由 Robert Haandrikman 提供,保留部分权利。

教程概述

本教程分为三个部分;它们是:

  1. 单变量函数优化
  2. 凸单变量函数优化
  3. 非凸单变量函数优化

单变量函数优化

我们可能需要找到采用单个参数的函数的最优值。

在机器学习中,这可能发生在许多情况下,例如:

  • 寻找模型的系数以适合训练数据集。
  • 找到导致最佳模型表现的单个超参数的值。

这被称为单变量函数优化。

我们可能对函数的最小结果或最大结果感兴趣,尽管这可以简化为最小化,因为最大化函数可以通过给函数的所有结果添加负号来最小化。

函数的输入可能有限制,也可能没有限制,即所谓的无约束或约束优化,我们假设输入的小变化对应于函数输出的小变化,例如,它是平滑的。

该功能可能有也可能没有单个 optima,尽管我们更希望它有一个 optima,并且该功能的形状看起来像一个大盆。如果是这种情况,我们知道我们可以在一个点对函数进行采样,并找到向下到达函数最小值的路径。从技术上讲,这被称为最小化的凸函数(最大化的凹函数),不具有这种盆形的函数被称为非凸函数。

  • 凸目标函数:有一个单一的最优值,目标函数的形状导致这个最优值。

然而,目标函数足够复杂,我们不知道导数,这意味着我们不能只使用微积分来分析计算梯度为零的函数的最小值或最大值。这被称为不可微函数。

虽然我们可能能够用候选值对函数进行采样,但我们不知道会产生最佳结果的输入。这可能是因为评估候选解决方案的成本很高。

因此,我们需要一种算法来有效地对函数的输入值进行采样。

解决单变量函数优化问题的一种方法是使用布伦特方法

Brent 的方法是一种优化算法,结合了二等分算法(Dekker 的方法)和逆二次插值。它可用于有约束和无约束的单变量函数优化。

布伦特-德克尔方法是平分法的扩展。它是一种寻根算法,结合了割线法和逆二次插值的元素。它具有可靠和快速的收敛特性,是许多流行的数值优化包中首选的单变量优化算法。

—第 49-51 页,优化算法,2019。

二等分算法使用输入值的括号(下括号和上括号)来分割输入域,将其二等分,以便定位 optima 在域中的位置,很像二分搜索法。德克尔的方法是连续域有效实现这一点的一种方法。

德克尔的方法被卡在非凸问题上。布伦特的方法修改了德克尔的方法,以避免陷入困境,并且还近似了目标函数的二阶导数(称为割线方法,以加速搜索。

因此,考虑到效率,布伦特的单变量函数优化方法通常优于大多数其他单变量函数优化算法。

Brent 的方法在 Python 中可以通过minimum _ scalar()SciPy 函数获得,该函数采用要最小化的函数的名称。如果目标函数被限制在一个范围内,可以通过“边界参数来指定。

它返回一个optimizer result对象,该对象是一个包含解决方案的字典。重要的是,' x 键总结了 optima 的输入,' fun 键总结了 optima 的功能输出,' nfev 总结了已执行的目标功能的评估数量。

...
# minimize the function
result = minimize_scalar(objective, method='brent')

现在我们知道了如何在 Python 中执行单变量函数优化,让我们看一些例子。

凸单变量函数优化

在这一节中,我们将探讨如何解决一个凸的单变量函数优化问题。

首先,我们可以定义一个函数来实现我们的功能。

在这种情况下,我们将使用 x² 函数的简单偏移版本,例如简单的抛物线 (u 形)函数。这是一个最小化目标函数,其最优值为-5.0。

# objective function
def objective(x):
	return (5.0 + x)**2.0

我们可以用-10 到 10 的输入值绘制这个函数的粗网格,以了解目标函数的形状。

下面列出了完整的示例。

# plot a convex target function
from numpy import arange
from matplotlib import pyplot

# objective function
def objective(x):
	return (5.0 + x)**2.0

# define range
r_min, r_max = -10.0, 10.0
# prepare inputs
inputs = arange(r_min, r_max, 0.1)
# compute targets
targets = [objective(x) for x in inputs]
# plot inputs vs target
pyplot.plot(inputs, targets, '--')
pyplot.show()

运行该示例使用目标函数评估指定范围内的输入值,并创建函数输入与函数输出的关系图。

我们可以看到函数的 U 形,目标是-5.0。

Line Plot of a Convex Objective Function

凸目标函数的线图

:在一个真正的优化问题中,我们不可能这么容易地对目标函数进行这么多的评估。这个简单的函数用于演示目的,因此我们可以学习如何使用优化算法。

接下来,我们可以使用优化算法来寻找最优解。

...
# minimize the function
result = minimize_scalar(objective, method='brent')

优化后,我们可以总结结果,包括 optima 的输入和评估以及定位 optima 所需的功能评估数量。

...
# summarize the result
opt_x, opt_y = result['x'], result['fun']
print('Optimal Input x: %.6f' % opt_x)
print('Optimal Output f(x): %.6f' % opt_y)
print('Total Evaluations n: %d' % result['nfev'])

最后,我们可以再次绘制该函数,并标记 optima,以确认它位于我们期望该函数出现的位置。

...
# define the range
r_min, r_max = -10.0, 10.0
# prepare inputs
inputs = arange(r_min, r_max, 0.1)
# compute targets
targets = [objective(x) for x in inputs]
# plot inputs vs target
pyplot.plot(inputs, targets, '--')
# plot the optima
pyplot.plot([opt_x], [opt_y], 's', color='r')
# show the plot
pyplot.show()

下面列出了优化无约束凸单变量函数的完整示例。

# optimize convex objective function
from numpy import arange
from scipy.optimize import minimize_scalar
from matplotlib import pyplot

# objective function
def objective(x):
	return (5.0 + x)**2.0

# minimize the function
result = minimize_scalar(objective, method='brent')
# summarize the result
opt_x, opt_y = result['x'], result['fun']
print('Optimal Input x: %.6f' % opt_x)
print('Optimal Output f(x): %.6f' % opt_y)
print('Total Evaluations n: %d' % result['nfev'])
# define the range
r_min, r_max = -10.0, 10.0
# prepare inputs
inputs = arange(r_min, r_max, 0.1)
# compute targets
targets = [objective(x) for x in inputs]
# plot inputs vs target
pyplot.plot(inputs, targets, '--')
# plot the optima
pyplot.plot([opt_x], [opt_y], 's', color='r')
# show the plot
pyplot.show()

运行示例首先解决优化问题并报告结果。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到 optima 是在对输入为-5.0 的目标函数进行 10 次评估后找到的,目标函数值为 0.0。

Optimal Input x: -5.000000
Optimal Output f(x): 0.000000
Total Evaluations n: 10

再次创建函数的图,这一次,optima 标记为红色方块。

Line Plot of a Convex Objective Function with Optima Marked

带有最优标记的凸目标函数的线图

非凸单变量函数优化

凸函数是一个不像盆地的函数,这意味着它可能有一个以上的山或谷。

这使得定位全局最优值变得更具挑战性,因为多个山丘和山谷会导致搜索陷入停滞,并报告错误或局部最优值。

我们可以定义一个非凸单变量函数如下。

# objective function
def objective(x):
	return (x - 2.0) * x * (x + 2.0)**2.0

我们可以对该函数进行采样,并创建输入值到目标值的线图。

下面列出了完整的示例。

# plot a non-convex univariate function
from numpy import arange
from matplotlib import pyplot

# objective function
def objective(x):
	return (x - 2.0) * x * (x + 2.0)**2.0

# define range
r_min, r_max = -3.0, 2.5
# prepare inputs
inputs = arange(r_min, r_max, 0.1)
# compute targets
targets = [objective(x) for x in inputs]
# plot inputs vs target
pyplot.plot(inputs, targets, '--')
pyplot.show()

运行该示例使用目标函数评估指定范围内的输入值,并创建函数输入与函数输出的关系图。

我们可以看到一个函数在-2.0 左右有一个假最优值,在 1.2 左右有一个全局最优值。

Line Plot of a Non-Convex Objective Function

非凸目标函数的线图

:在一个真正的优化问题中,我们不可能这么容易地对目标函数进行这么多的评估。这个简单的函数用于演示目的,因此我们可以学习如何使用优化算法。

接下来,我们可以使用优化算法来寻找最优解。

和之前一样,我们可以调用minimum _ scalar()函数来优化函数,然后汇总结果,在线图上绘制最优值。

下面列出了无约束非凸单变量函数优化的完整例子。

# optimize non-convex objective function
from numpy import arange
from scipy.optimize import minimize_scalar
from matplotlib import pyplot

# objective function
def objective(x):
	return (x - 2.0) * x * (x + 2.0)**2.0

# minimize the function
result = minimize_scalar(objective, method='brent')
# summarize the result
opt_x, opt_y = result['x'], result['fun']
print('Optimal Input x: %.6f' % opt_x)
print('Optimal Output f(x): %.6f' % opt_y)
print('Total Evaluations n: %d' % result['nfev'])
# define the range
r_min, r_max = -3.0, 2.5
# prepare inputs
inputs = arange(r_min, r_max, 0.1)
# compute targets
targets = [objective(x) for x in inputs]
# plot inputs vs target
pyplot.plot(inputs, targets, '--')
# plot the optima
pyplot.plot([opt_x], [opt_y], 's', color='r')
# show the plot
pyplot.show()

运行示例首先解决优化问题并报告结果。

在这种情况下,我们可以看到 optima 是在对输入约为 1.28 的目标函数进行 15 次评估后定位的,实现了约为-9.91 的目标函数值。

Optimal Input x: 1.280776
Optimal Output f(x): -9.914950
Total Evaluations n: 15

再次创建函数的图,这一次,optima 标记为红色方块。

我们可以看到,优化没有被伪最优解欺骗,成功地找到了全局最优解。

Line Plot of a Non-Convex Objective Function with Optima Marked

带有最优标记的非凸目标函数的线图

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

蜜蜂

文章

摘要

在本教程中,您发现了如何在 Python 中执行单变量函数优化。

具体来说,您了解到:

  • 单变量函数优化涉及到为一个目标函数寻找一个最佳输入,这个目标函数需要一个连续的参数。
  • 如何对无约束凸函数进行单变量函数优化?
  • 如何对无约束非凸函数进行单变量函数优化?

你有什么问题吗? 在下面的评论中提问,我会尽力回答。

Python 中函数优化的可视化

原文:machinelearningmastery.com/visualizati…

最后更新于 2021 年 10 月 12 日

函数优化包括从目标函数中找到导致最优值的输入。

优化算法在输入变量的搜索空间中导航以定位最优解,并且目标函数的形状和算法在搜索空间中的行为在现实问题中都是不透明的。

因此,通常使用简单的低维函数来研究优化算法,这些函数可以很容易地直接可视化。此外,由优化算法产生的这些简单函数的输入空间中的样本可以用它们适当的上下文可视化。

低维函数和这些函数上的算法行为的可视化可以帮助开发直觉,这种直觉可以延续到以后更复杂的高维函数优化问题。

在本教程中,您将发现如何在 Python 中为函数优化创建可视化。

完成本教程后,您将知道:

  • 可视化是研究函数优化算法的重要工具。
  • 如何使用线图可视化一维函数和样本。
  • 如何使用等高线和曲面图可视化二维函数和样本。

用我的新书机器学习优化启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

Let’s get started.Visualization for Function Optimization in Python

Python 函数优化可视化 图片由 Nathalie 提供,保留部分权利。

教程概述

本教程分为三个部分;它们是:

  1. 函数优化可视化
  2. 可视化 1D 函数优化
    1. 测试功能
    2. 样本测试功能
    3. 测试函数的线图
    4. 测试函数的散点图
    5. 带有标记 Optima 的线图
    6. 带有样本的线图
  3. 可视化 2D 函数优化
    1. 测试功能
    2. 样本测试功能
    3. 测试函数的等高线图
    4. 测试函数的填充等高线图
    5. 用样本填充测试函数的等高线图
    6. 测试函数的曲面图

函数优化可视化

函数优化是一个数学领域,它涉及到寻找函数的输入,从而得到函数的最优输出,通常是最小值或最大值。

对于可以解析计算解的简单微分函数,优化可能是简单的。然而,我们在应用机器学习中感兴趣解决的大多数函数可能表现良好,也可能表现不佳,并且可能是复杂的、非线性的、多元的和不可微的。

因此,了解可用于解决函数优化问题的各种不同算法非常重要。

研究函数优化的一个重要方面是了解正在优化的目标函数,并了解优化算法随时间的行为。

开始进行函数优化时,可视化发挥了重要作用。

我们可以选择简单且易于理解的测试函数来研究优化算法。可以绘制这些简单的函数来理解目标函数的输入和目标函数的输出之间的关系,并突出显示山丘、山谷和最优区域。

此外,通过优化算法从搜索空间中选择的样本也可以绘制在目标函数图的顶部。这些算法行为图可以提供关于具体优化算法如何工作的洞察力和直觉,并在搜索空间中导航,从而可以概括未来的新问题。

通常,选择一维或二维函数来研究优化算法,因为它们很容易使用标准图来可视化,如线图和曲面图。我们将在本教程中探讨这两者。

首先,让我们探索如何可视化一维函数优化。

可视化 1D 函数优化

一维函数接受单个输入变量,并输出对该输入变量的评估。

输入变量通常是连续的,由实值浮点值表示。通常,输入域是不受约束的,尽管对于测试问题,我们强加了一个感兴趣的域。

测试功能

在这种情况下,我们将用一个简单的 x² 目标函数来探索函数可视化:

  • f(x) = x²

这有一个最佳值,输入 x=0.0,等于 0.0。

下面的示例实现了这个目标函数,并对单个输入进行了评估。

# example of a 1d objective function

# objective function
def objective(x):
	return x**2.0

# evaluate inputs to the objective function
x = 4.0
result = objective(x)
print('f(%.3f) = %.3f' % (x, result))

运行该示例用目标函数计算值 4.0,等于 16.0。

f(4.000) = 16.000

对测试函数进行采样

对于新函数,我们首先要做的是定义感兴趣的输入范围,并使用统一的网格对感兴趣的域进行采样。

此示例将为以后生成绘图提供基础。

在这种情况下,我们将在 x=-5.0 到 x=5.0 的最佳值周围定义一个感兴趣的域,并以 0.1 的增量对该范围内的值网格进行采样,例如-5.0、-4.9、-4.8 等。

...
# define range for input
r_min, r_max = -5.0, 5.0
# sample input range uniformly at 0.1 increments
inputs = arange(r_min, r_max, 0.1)
# summarize some of the input domain
print(inputs[:5])

然后,我们可以评估样本中的每个 x 值。

...
# compute targets
results = objective(inputs)
# summarize some of the results
print(results[:5])

最后,我们可以检查一些输入和它们相应的输出。

...
# create a mapping of some inputs to some results
for i in range(5):
	print('f(%.3f) = %.3f' % (inputs[i], results[i]))

将这些联系在一起,下面列出了对输入空间进行采样并评估样本中所有点的完整示例。

# sample 1d objective function
from numpy import arange

# objective function
def objective(x):
	return x**2.0

# define range for input
r_min, r_max = -5.0, 5.0
# sample input range uniformly at 0.1 increments
inputs = arange(r_min, r_max, 0.1)
# summarize some of the input domain
print(inputs[:5])
# compute targets
results = objective(inputs)
# summarize some of the results
print(results[:5])
# create a mapping of some inputs to some results
for i in range(5):
	print('f(%.3f) = %.3f' % (inputs[i], results[i]))

运行该示例首先生成一个输入点的统一样本,正如我们所期望的那样。

然后使用目标函数评估输入点,最后,我们可以看到目标函数的输入到输出的简单映射。

[-5\.  -4.9 -4.8 -4.7 -4.6]
[25\.   24.01 23.04 22.09 21.16]
f(-5.000) = 25.000
f(-4.900) = 24.010
f(-4.800) = 23.040
f(-4.700) = 22.090
f(-4.600) = 21.160

既然我们对生成输入样本和用目标函数评估它们有了一些信心,我们就可以考虑生成函数的图了。

测试函数的线图

我们可以对输入空间进行随机采样,但是均匀的线或点网格的好处是可以用来生成平滑的图。

它是平滑的,因为输入空间中的点是从最小到最大排序的。这种排序很重要,因为我们期望(希望)目标函数的输出在值之间具有类似的平滑关系,例如,输入的微小变化导致函数输出的局部一致(平滑)变化。

在这种情况下,我们可以使用样本生成目标函数的线图,输入点(x)在图的 x 轴上,目标函数输出(结果)在图的 y 轴上。

...
# create a line plot of input vs result
pyplot.plot(inputs, results)
# show the plot
pyplot.show()

将这些联系在一起,完整的示例如下所示。

# line plot of input vs result for a 1d objective function
from numpy import arange
from matplotlib import pyplot

# objective function
def objective(x):
	return x**2.0

# define range for input
r_min, r_max = -5.0, 5.0
# sample input range uniformly at 0.1 increments
inputs = arange(r_min, r_max, 0.1)
# compute targets
results = objective(inputs)
# create a line plot of input vs result
pyplot.plot(inputs, results)
# show the plot
pyplot.show()

运行该示例会创建目标函数的线图。

我们可以看到函数有一个很大的 U 型,叫做抛物线。这是学习曲线时常见的形状,例如学习微积分

Line Plot of a One-Dimensional Function

一维函数的线图

测试函数的散点图

这条线是一个结构。它并不是真正的函数,只是函数的一个流畅的总结。永远记住这一点。

回想一下,事实上,我们在输入空间中生成了一个样本点,并对这些点进行了相应的评估。

因此,创建点的散点图会更准确;例如:

# scatter plot of input vs result for a 1d objective function
from numpy import arange
from matplotlib import pyplot

# objective function
def objective(x):
	return x**2.0

# define range for input
r_min, r_max = -5.0, 5.0
# sample input range uniformly at 0.1 increments
inputs = arange(r_min, r_max, 0.1)
# compute targets
results = objective(inputs)
# create a scatter plot of input vs result
pyplot.scatter(inputs, results)
# show the plot
pyplot.show()

运行该示例会创建目标函数的散点图。

我们可以看到函数熟悉的形状,但是我们没有从直接绘制点中获得任何东西。

线和它提供的点之间的平滑插值更有用,因为我们可以在线的顶部绘制其他点,例如 optima 的位置或通过优化算法采样的点。

Scatter Plot of a One-Dimensional Function

一维函数的散点图

带有标记 Optima 的线图

接下来,我们再画一次线图,这次画一个函数的已知最优值所在的点。

这在研究优化算法时很有帮助,因为我们可能想看看优化算法能多接近最优。

首先,我们必须定义 optima 的输入,然后评估该点以给出用于绘图的 x 轴和 y 轴值。

...
# define the known function optima
optima_x = 0.0
optima_y = objective(optima_x)

然后我们可以用我们喜欢的任何形状或颜色来绘制这个点,在这个例子中,是一个红色的正方形。

...
# draw the function optima as a red square
pyplot.plot([optima_x], [optima_y], 's', color='r')

将这些联系在一起,下面列出了用一个点突出显示的 optima 创建函数的线图的完整示例。

# line plot of input vs result for a 1d objective function and show optima
from numpy import arange
from matplotlib import pyplot

# objective function
def objective(x):
	return x**2.0

# define range for input
r_min, r_max = -5.0, 5.0
# sample input range uniformly at 0.1 increments
inputs = arange(r_min, r_max, 0.1)
# compute targets
results = objective(inputs)
# create a line plot of input vs result
pyplot.plot(inputs, results)
# define the known function optima
optima_x = 0.0
optima_y = objective(optima_x)
# draw the function optima as a red square
pyplot.plot([optima_x], [optima_y], 's', color='r')
# show the plot
pyplot.show()

运行该示例会创建熟悉的函数线图,这一次,函数的最优值,例如导致函数最小输出的输入,用红色方块标记。

Line Plot of a One-Dimensional Function With Optima Marked by a Red Square

用红方标记最优值的一维函数的线图

这是一个非常简单的功能,optima 的红色方块很容易看到。

有时函数可能更复杂,有很多山丘和山谷,我们可能想让 optima 更明显。

在这种情况下,我们可以在整个情节上画一条垂直线。

...
# draw a vertical line at the optimal input
pyplot.axvline(x=optima_x, ls='--', color='red')

将这些联系在一起,完整的示例如下所示。

# line plot of input vs result for a 1d objective function and show optima as line
from numpy import arange
from matplotlib import pyplot

# objective function
def objective(x):
	return x**2.0

# define range for input
r_min, r_max = -5.0, 5.0
# sample input range uniformly at 0.1 increments
inputs = arange(r_min, r_max, 0.1)
# compute targets
results = objective(inputs)
# create a line plot of input vs result
pyplot.plot(inputs, results)
# define the known function optima
optima_x = 0.0
# draw a vertical line at the optimal input
pyplot.axvline(x=optima_x, ls='--', color='red')
# show the plot
pyplot.show()

运行该示例会创建相同的图,这一次绘制了一条红线,清楚地标记输入空间中标记 optima 的点。

Line Plot of a One-Dimensional Function With Optima Marked by a Red Line

用红线标记最优值的一维函数的线图

带有样本的线图

最后,我们可能想要绘制由优化算法选择的输入空间的样本。

我们将使用从输入域中抽取的随机点来模拟这些样本。

...
# simulate a sample made by an optimization algorithm
seed(1)
sample = r_min + rand(10) * (r_max - r_min)
# evaluate the sample
sample_eval = objective(sample)

然后我们可以绘制这个样本,在这种情况下使用黑色小圆圈。

...
# plot the sample as black circles
pyplot.plot(sample, sample_eval, 'o', color='black')

下面列出了创建函数线图的完整示例,其中 optima 用红线标记,算法示例用小黑点绘制。

# line plot of domain for a 1d function with optima and algorithm sample
from numpy import arange
from numpy.random import seed
from numpy.random import rand
from matplotlib import pyplot

# objective function
def objective(x):
	return x**2.0

# define range for input
r_min, r_max = -5.0, 5.0
# sample input range uniformly at 0.1 increments
inputs = arange(r_min, r_max, 0.1)
# compute targets
results = objective(inputs)
# simulate a sample made by an optimization algorithm
seed(1)
sample = r_min + rand(10) * (r_max - r_min)
# evaluate the sample
sample_eval = objective(sample)
# create a line plot of input vs result
pyplot.plot(inputs, results)
# define the known function optima
optima_x = 0.0
# draw a vertical line at the optimal input
pyplot.axvline(x=optima_x, ls='--', color='red')
# plot the sample as black circles
pyplot.plot(sample, sample_eval, 'o', color='black')
# show the plot
pyplot.show()

运行该示例会创建域的线图,并像以前一样用红线标记 optima。

这一次,来自算法选择的域的样本(实际上是点的随机样本)用黑点绘制。

我们可以想象,当一个真正的优化算法从一个起点向下搜索时,它会在域中显示出缩小的点。

Line Plot of a One-Dimensional Function With Optima Marked by a Red Line and Samples Shown with Black Dots

一维函数的线图,其中 Optima 用红线标记,样本用黑点表示

接下来,让我们看看如何为二维函数的优化执行类似的可视化。

可视化 2D 函数优化

二维函数是采用两个输入变量的函数,例如 xy

测试功能

我们可以使用相同的 函数,并将其放大为二维函数;例如:

  • f(x,y) = x² + y²

这有一个最佳值,输入为[x=0.0,y=0.0],等于 0.0。

下面的示例实现了这个目标函数,并对单个输入进行了评估。

# example of a 2d objective function

# objective function
def objective(x, y):
	return x**2.0 + y**2.0

# evaluate inputs to the objective function
x = 4.0
y = 4.0
result = objective(x, y)
print('f(%.3f, %.3f) = %.3f' % (x, y, result))

运行该示例计算点[x=4,y=4],该点等于 32。

f(4.000, 4.000) = 32.000

接下来,我们需要一种对域进行采样的方法,这样我们就可以依次对目标函数进行采样。

样本测试功能

对二维函数进行采样的一种常见方式是首先沿着每个变量 xy 生成一个均匀的样本,然后使用这两个均匀的样本创建一个样本网格,称为网格

这不是输入空间上的二维数组;相反,当两个二维数组一起使用时,它们定义了一个跨越两个输入变量的网格。

这是通过为每个 y 采样点复制整个 x 采样阵列,并为每个 x 采样点类似地复制整个 y 采样阵列来实现的。

这可以使用 meshgrid() NumPy 功能来实现;例如:

...
# define range for input
r_min, r_max = -5.0, 5.0
# sample input range uniformly at 0.1 increments
xaxis = arange(r_min, r_max, 0.1)
yaxis = arange(r_min, r_max, 0.1)
# create a mesh from the axis
x, y = meshgrid(xaxis, yaxis)
# summarize some of the input domain
print(x[:5, :5])

然后,我们可以使用我们的目标函数来评估每对点。

...
# compute targets
results = objective(x, y)
# summarize some of the results
print(results[:5, :5])

最后,我们可以回顾一些输入到相应输出值的映射。

...
# create a mapping of some inputs to some results
for i in range(5):
	print('f(%.3f, %.3f) = %.3f' % (x[i,0], y[i,0], results[i,0]))

下面的例子演示了我们如何在二维输入空间和目标函数中创建一个统一的样本网格。

# sample 2d objective function
from numpy import arange
from numpy import meshgrid

# objective function
def objective(x, y):
	return x**2.0 + y**2.0

# define range for input
r_min, r_max = -5.0, 5.0
# sample input range uniformly at 0.1 increments
xaxis = arange(r_min, r_max, 0.1)
yaxis = arange(r_min, r_max, 0.1)
# create a mesh from the axis
x, y = meshgrid(xaxis, yaxis)
# summarize some of the input domain
print(x[:5, :5])
# compute targets
results = objective(x, y)
# summarize some of the results
print(results[:5, :5])
# create a mapping of some inputs to some results
for i in range(5):
	print('f(%.3f, %.3f) = %.3f' % (x[i,0], y[i,0], results[i,0]))

运行示例首先总结网格中的一些点,然后对一些点进行目标函数评估。

最后,我们列举二维输入空间中的坐标及其相应的函数求值。

[[-5\.  -4.9 -4.8 -4.7 -4.6]
 [-5\.  -4.9 -4.8 -4.7 -4.6]
 [-5\.  -4.9 -4.8 -4.7 -4.6]
 [-5\.  -4.9 -4.8 -4.7 -4.6]
 [-5\.  -4.9 -4.8 -4.7 -4.6]]
[[50\.   49.01 48.04 47.09 46.16]
 [49.01 48.02 47.05 46.1  45.17]
 [48.04 47.05 46.08 45.13 44.2 ]
 [47.09 46.1  45.13 44.18 43.25]
 [46.16 45.17 44.2  43.25 42.32]]
f(-5.000, -5.000) = 50.000
f(-5.000, -4.900) = 49.010
f(-5.000, -4.800) = 48.040
f(-5.000, -4.700) = 47.090
f(-5.000, -4.600) = 46.160

现在,我们已经熟悉了如何对输入空间进行采样和评估点,让我们看看如何绘制函数。

测试函数的等高线图

一个流行的二维函数图是等高线图

此图为每个 x 和 y 坐标创建了目标函数输出的平面表示,其中颜色和轮廓线表示目标函数输出的相对值或高度。

这就像是一幅风景的等高线图,在这里山和谷是可以区分的。

这可以使用轮廓()Matplotlib 函数来实现,该函数将网格和网格的评估直接作为输入。

然后,我们可以指定要在轮廓上绘制的级别数和要使用的配色方案。在这种情况下,我们将使用 50 级和流行的“ jet ”配色方案,其中低级使用冷配色方案(蓝色),高级使用热配色方案(红色)。

...
# create a contour plot with 50 levels and jet color scheme
pyplot.contour(x, y, results, 50, alpha=1.0, cmap='jet')
# show the plot
pyplot.show()

将这些联系在一起,下面列出了创建二维目标函数等高线图的完整示例。

# create a contour plot with 50 levels and jet color scheme
pyplot.contour(x, y, results, 50, alpha=1.0, cmap='jet')
# show the plot
pyplot.show()

Tying this together, the complete example of creating a contour plot of the two-dimensional objective function is listed below.

# contour plot for 2d objective function
from numpy import arange
from numpy import meshgrid
from matplotlib import pyplot

# objective function
def objective(x, y):
	return x**2.0 + y**2.0

# define range for input
r_min, r_max = -5.0, 5.0
# sample input range uniformly at 0.1 increments
xaxis = arange(r_min, r_max, 0.1)
yaxis = arange(r_min, r_max, 0.1)
# create a mesh from the axis
x, y = meshgrid(xaxis, yaxis)
# compute targets
results = objective(x, y)
# create a contour plot with 50 levels and jet color scheme
pyplot.contour(x, y, results, 50, alpha=1.0, cmap='jet')
# show the plot
pyplot.show()

运行该示例会创建等高线图。

我们可以看到,边缘周围曲面的弯曲部分越多,显示细节的轮廓越多,中间曲面的弯曲部分越少,轮廓越少。

我们可以看到,正如预期的那样,域的最低部分是中间。

Contour Plot of a Two-Dimensional Objective Function

二维目标函数的等高线图

测试函数的填充等高线图

这也有助于给轮廓之间的图着色,以显示更完整的表面。

同样,颜色只是简单的线性插值,不是真正的函数求值。对于更复杂的功能,这一点必须牢记在心,因为在这些功能中不会显示细节。

我们可以使用采用相同参数的函数的 contourf()版本来填充等高线图。

...
# create a filled contour plot with 50 levels and jet color scheme
pyplot.contourf(x, y, results, levels=50, cmap='jet')

我们也可以在剧情上展示 optima,在这种情况下是一颗白色的星星,它将在剧情最低部分的蓝色背景颜色中脱颖而出。

...
# define the known function optima
optima_x = [0.0, 0.0]
# draw the function optima as a white star
pyplot.plot([optima_x[0]], [optima_x[1]], '*', color='white')

将这些联系在一起,下面列出了带有 optima 标记的填充等高线图的完整示例。

# filled contour plot for 2d objective function and show the optima
from numpy import arange
from numpy import meshgrid
from matplotlib import pyplot

# objective function
def objective(x, y):
	return x**2.0 + y**2.0

# define range for input
r_min, r_max = -5.0, 5.0
# sample input range uniformly at 0.1 increments
xaxis = arange(r_min, r_max, 0.1)
yaxis = arange(r_min, r_max, 0.1)
# create a mesh from the axis
x, y = meshgrid(xaxis, yaxis)
# compute targets
results = objective(x, y)
# create a filled contour plot with 50 levels and jet color scheme
pyplot.contourf(x, y, results, levels=50, cmap='jet')
# define the known function optima
optima_x = [0.0, 0.0]
# draw the function optima as a white star
pyplot.plot([optima_x[0]], [optima_x[1]], '*', color='white')
# show the plot
pyplot.show()

运行该示例可以创建填充等高线图,从而更好地了解目标函数的形状。

然后,在[x=0,y=0]处的 optima 用白星清楚地标记出来。

Filled Contour Plot of a Two-Dimensional Objective Function With Optima Marked by a White Star

白星标记最优值的二维目标函数的填充等高线图

用样本填充测试函数的等高线图

我们可能想展示一个优化算法的进展,以便在目标函数形状的上下文中了解它的行为。

在这种情况下,我们可以用输入空间中的随机坐标模拟优化算法选择的点。

...
# simulate a sample made by an optimization algorithm
seed(1)
sample_x = r_min + rand(10) * (r_max - r_min)
sample_y = r_min + rand(10) * (r_max - r_min)

然后,这些点可以直接绘制成黑色圆圈,它们的背景颜色可以表示它们的相对质量。

...
# plot the sample as black circles
pyplot.plot(sample_x, sample_y, 'o', color='black')

将这些联系在一起,下面列出了绘制了最优样本和输入样本的填充等高线图的完整示例。

# filled contour plot for 2d objective function and show the optima and sample
from numpy import arange
from numpy import meshgrid
from numpy.random import seed
from numpy.random import rand
from matplotlib import pyplot

# objective function
def objective(x, y):
	return x**2.0 + y**2.0

# define range for input
r_min, r_max = -5.0, 5.0
# sample input range uniformly at 0.1 increments
xaxis = arange(r_min, r_max, 0.1)
yaxis = arange(r_min, r_max, 0.1)
# create a mesh from the axis
x, y = meshgrid(xaxis, yaxis)
# compute targets
results = objective(x, y)
# simulate a sample made by an optimization algorithm
seed(1)
sample_x = r_min + rand(10) * (r_max - r_min)
sample_y = r_min + rand(10) * (r_max - r_min)
# create a filled contour plot with 50 levels and jet color scheme
pyplot.contourf(x, y, results, levels=50, cmap='jet')
# define the known function optima
optima_x = [0.0, 0.0]
# draw the function optima as a white star
pyplot.plot([optima_x[0]], [optima_x[1]], '*', color='white')
# plot the sample as black circles
pyplot.plot(sample_x, sample_y, 'o', color='black')
# show the plot
pyplot.show()

运行该示例,我们可以看到像以前一样的填充等高线图,并标记了 optima。

我们现在可以看到绘制为黑点的样本,它们周围的颜色和相对于 optima 的距离给出了算法(在这种情况下是随机点)解决问题的接近程度。

Filled Contour Plot of a Two-Dimensional Objective Function With Optima and Input Sample Marked

标注最优值和输入样本的二维目标函数的填充等高线图

测试函数的曲面图

最后,我们可能想创建一个目标函数的三维图,以更全面地了解函数的曲率。

这可以使用 plot_surface() Matplotlib 函数来实现,该函数与等高线图一样,直接采用网格和函数求值。

...
# create a surface plot with the jet color scheme
figure = pyplot.figure()
axis = figure.gca(projection='3d')
axis.plot_surface(x, y, results, cmap='jet')

下面列出了创建曲面图的完整示例。

# surface plot for 2d objective function
from numpy import arange
from numpy import meshgrid
from matplotlib import pyplot
from mpl_toolkits.mplot3d import Axes3D

# objective function
def objective(x, y):
	return x**2.0 + y**2.0

# define range for input
r_min, r_max = -5.0, 5.0
# sample input range uniformly at 0.1 increments
xaxis = arange(r_min, r_max, 0.1)
yaxis = arange(r_min, r_max, 0.1)
# create a mesh from the axis
x, y = meshgrid(xaxis, yaxis)
# compute targets
results = objective(x, y)
# create a surface plot with the jet color scheme
figure = pyplot.figure()
axis = figure.gca(projection='3d')
axis.plot_surface(x, y, results, cmap='jet')
# show the plot
pyplot.show()

运行该示例会创建目标函数的三维表面图。

Surface Plot of a Two-Dimensional Objective Function

二维目标函数的曲面图

此外,该图是交互式的,这意味着您可以使用鼠标拖动周围表面上的透视图,并从不同的角度查看它。

Surface Plot From a Different Angle of a Two-Dimensional Objective Function

从二维目标函数的不同角度绘制曲面

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

蜜蜂

文章

摘要

在本教程中,您发现了如何在 Python 中为函数优化创建可视化。

具体来说,您了解到:

  • 可视化是研究函数优化算法的重要工具。
  • 如何使用线图可视化一维函数和样本。
  • 如何使用等高线和曲面图可视化二维函数和样本。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。

为什么优化在机器学习中很重要

原文:machinelearningmastery.com/why-optimiz…

最后更新于 2021 年 10 月 12 日

机器学习包括使用算法从历史数据中学习和归纳,以便对新数据进行预测。

这个问题可以描述为近似一个函数,该函数将输入的例子映射到输出的例子。逼近一个函数可以通过将问题框架化为函数优化来解决。这是机器学习算法定义参数化映射函数(例如,输入的加权和)的地方,并且优化算法用于为参数(例如,模型系数)的值提供资金,当用于将输入映射到输出时,该参数最小化函数的误差。

这意味着,每次我们在训练数据集上拟合机器学习算法时,我们都在解决一个优化问题。

在本教程中,您将发现优化在机器学习中的核心作用。

完成本教程后,您将知道:

  • 机器学习算法执行函数逼近,这是使用函数优化来解决的。
  • 函数优化是我们在拟合机器学习算法时最小化误差、成本或损失的原因。
  • 在预测建模项目的数据准备、超参数调整和模型选择过程中,也会执行优化。

用我的新书机器学习优化启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

Let’s get started.Why Optimization Is Important in Machine Learning

为什么优化在机器学习中很重要 图片由马尔科·韦奇提供,版权所有。

教程概述

本教程分为三个部分;它们是:

  1. 机器学习与优化
  2. 学习即优化
  3. 机器学习项目中的优化
    1. 数据准备作为优化
    2. 超参数优化
    3. 作为优化的模型选择

机器学习与优化

函数优化是寻找目标目标函数的输入集的问题,该输入集导致函数的最小值或最大值。

这可能是一个具有挑战性的问题,因为函数可能有几十个、几百个、几千个甚至几百万个输入,并且函数的结构是未知的,并且通常是不可微的和有噪声的。

  • 函数优化:找到导致目标函数最小或最大的输入集。

机器学习可以描述为函数逼近。也就是说,近似未知的潜在函数,该函数将输入示例映射到输出,以便对新数据进行预测。

这可能很有挑战性,因为我们可以用来近似函数的例子通常数量有限,并且被近似的函数的结构通常是非线性的、有噪声的,甚至可能包含矛盾。

  • 函数逼近:从具体的例子中归纳出一个可重用的映射函数,用于对新的例子进行预测。

函数优化通常比函数逼近简单。

重要的是,在机器学习中,我们经常使用函数优化来解决函数逼近的问题。

几乎所有机器学习算法的核心都是优化算法。

此外,处理预测建模问题的过程除了学习模型之外,还涉及多个步骤的优化,包括:

  • 模型超参数的选择。
  • 在建模之前选择要应用于数据的转换
  • 选择要用作最终模型的建模管道。

现在我们知道优化在机器学习中起着核心作用,让我们看看一些学习算法的例子以及它们如何使用优化。

学习即优化

预测建模问题涉及到根据输入示例进行预测。

在回归问题的情况下,必须预测数字量,而在分类问题的情况下,必须预测类别标签。

预测建模的问题非常具有挑战性,以至于我们无法编写代码来进行预测。相反,我们必须使用应用于历史数据的学习算法来学习一个名为“预测模型”的“”程序,我们可以使用该程序对新数据进行预测。

在统计学习(机器学习的一种统计观点)中,问题被框架化为给定输入数据( X )和相关输出数据( y 的例子的映射函数(f)的学习。

  • y = f(X)

给定新的输入示例( Xhat ),我们必须使用我们学习的函数( fhat )将每个示例映射到预期的输出值( yhat )。

  • yhat = fhat

所学的映射将是不完美的。没有一个模型是完美的,考虑到问题的难度、观测数据中的噪声以及学习算法的选择,预计会有一些预测误差。

数学上,学习算法通过解决函数优化问题来解决逼近映射函数的问题。

具体来说,给定输入和输出的示例,找到导致最小损失、最小成本或最小预测误差的映射函数的输入集。

映射函数的选择越偏向或受约束,优化就越容易解决。

让我们看一些例子来说明这一点。

线性回归(用于回归问题)是一种高度受限的模型,可以使用线性代数进行解析求解。映射函数的输入是模型的系数。

我们可以使用优化算法,如拟牛顿局部搜索算法,但它的效率几乎总是低于解析解。

  • 线性回归:函数输入是模型系数,可以解析求解的优化问题。

逻辑回归(用于分类问题)受到的约束稍少,必须作为优化问题来解决,尽管在模型施加的约束下,已知正在解决的优化函数的结构。

这意味着可以使用类似拟牛顿法的局部搜索算法。我们可以使用像随机梯度下降这样的全局搜索,但它几乎总是效率较低。

  • 逻辑回归:函数输入是模型系数,需要迭代局部搜索算法的优化问题。

神经网络模型是一种非常灵活的学习算法,几乎没有约束。映射函数的输入是网络权重。给定的搜索空间是多模态和高度非线性的,不能使用局部搜索算法;相反,必须使用全局搜索算法。

通常使用全局优化算法,特别是随机梯度下降,并且更新是以知道模型结构的方式进行的(反向传播和链式规则)。我们可以使用一种全局搜索算法,它不考虑模型的结构,就像遗传算法一样,但它几乎总是效率较低。

  • 神经网络:函数输入是模型权重,需要迭代全局搜索算法的优化问题。

我们可以看到,每个算法对映射函数的形式做出不同的假设,这影响了要解决的优化问题的类型。

我们还可以看到,每个机器学习算法使用的默认优化算法并不是任意的;它代表了用于解决由该算法构成的特定优化问题的最有效算法,例如,神经网络的随机梯度下降而不是遗传算法。偏离这些默认值需要一个很好的理由。

并非所有的机器学习算法都能解决优化问题。一个值得注意的例子是 k 近邻算法,它存储训练数据集,并查找每个新例子的 k 个最佳匹配,以便进行预测。

现在我们已经熟悉了机器学习算法中的学习作为优化,让我们看看机器学习项目中一些相关的优化示例。

机器学习项目中的优化

除了在训练数据集上拟合学习算法之外,优化在机器学习项目中起着重要的作用。

在拟合模型之前准备数据的步骤和调整所选模型的步骤也可以被视为优化问题。事实上,整个预测建模项目可以被认为是一个大的优化问题。

让我们依次仔细看看这些案例。

数据准备作为优化

数据准备包括将原始数据转换成最适合学习算法的形式。

这可能涉及缩放值、处理缺失值以及改变变量的概率分布。

可以进行转换来改变历史数据的表示,以满足特定学习算法的期望或要求。然而,有时当期望被违背或者当对数据执行不相关的转换时,可以获得好的或者最好的结果。

我们可以把选择应用于训练数据的变换看作是一个搜索或优化问题,最好地将数据的未知底层结构暴露给学习算法。

  • 数据准备:函数输入是需要迭代全局搜索算法的变换、优化问题的序列。

这个优化问题通常是通过人工试错来完成的。然而,有可能使用全局优化算法来自动化该任务,其中函数的输入是应用于训练数据的变换的类型和顺序。

数据变换的数量和排列通常是非常有限的,并且可以对常用序列进行穷举搜索或网格搜索。

有关此主题的更多信息,请参见教程:

超参数优化

机器学习算法具有超参数,这些超参数可以被配置为针对特定数据集定制算法。

虽然许多超参数的动态是已知的,但是它们对给定数据集上的结果模型的表现的具体影响是未知的。因此,测试所选机器学习算法的关键算法超参数的一组值是标准做法。

这被称为超参数调谐或超参数优化

为此,通常使用简单的优化算法,如随机搜索算法或网格搜索算法。

  • 超参数调整:函数输入是算法超参数,需要迭代全局搜索算法的优化问题。

有关此主题的更多信息,请参见教程:

然而,使用迭代全局搜索算法来解决这个优化问题变得越来越普遍。一种流行的选择是贝叶斯优化算法,它能够在优化目标函数的同时(使用替代函数)逼近正在优化的目标函数。

这是所希望的,因为评估模型超参数的单个组合是昂贵的,需要根据模型评估程序的选择,在整个训练数据集上拟合模型一次或多次(例如重复 k 倍交叉验证)。

有关此主题的更多信息,请参见教程:

作为优化的模型选择

模型选择包括从许多候选机器学习模型中选择一个用于预测建模问题。

实际上,它包括选择机器学习算法或产生模型的机器学习管道。然后用它来训练一个最终的模型,这个模型可以用在期望的应用中,对新的数据进行预测。

这个模型选择的过程通常是由机器学习实践者执行的手动过程,包括准备数据、评估候选模型、调整表现良好的模型以及最终选择最终模型等任务。

这可以被框架化为一个优化问题,包含部分或整个预测建模项目。

  • 模型选择:功能输入为数据变换、机器学习算法、算法超参数;需要迭代全局搜索算法的优化问题。

自动机器学习(AutoML)算法越来越多地被用于选择算法、算法和超参数,或者数据准备、算法和超参数,而几乎没有用户干预。

有关 AutoML 的更多信息,请参见教程:

与超参数调整一样,通常使用也近似目标函数的全局搜索算法,例如贝叶斯优化,因为每个函数评估都很昂贵。

这种自动优化机器学习的方法也是现代机器学习即服务产品的基础,这些产品由谷歌、微软和亚马逊等公司提供。

尽管快速高效,但这种方法仍然无法超越由高技能专家(如参加机器学习竞赛的专家)准备的手工模型。

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

教程

文章

摘要

在本教程中,您发现了优化在机器学习中的核心作用。

具体来说,您了解到:

  • 机器学习算法执行函数逼近,这是使用函数优化来解决的。
  • 函数优化是我们在拟合机器学习算法时最小化误差、成本或损失的原因。
  • 在预测建模项目的数据准备、超参数调整和模型选择过程中,也会执行优化。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。