《博主简介》
小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。
✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~
👍感谢小伙伴们点赞、关注!
《------往期经典推荐------》
二、机器学习实战专栏【链接】,已更新31期,欢迎关注,持续更新中~~
三、深度学习【Pytorch】专栏【链接】
四、【Stable Diffusion绘画系列】专栏【链接】
五、YOLOv8改进专栏【链接】,持续更新中~~
六、YOLO性能对比专栏【链接】,持续更新中~
《------正文------》
引言
梯度下降是机器学习、深度学习和许多其他数据科学领域中使用的最基本的优化技术之一。它的主要功能是迭代地最小化成本或损失函数,从而获得更好的模型性能或更准确的解决方案。在本文中,我们将了解梯度下降是如何工作的,重点是一个经典的例子-Rosenbrock函数,并使用Python代码以一种引人入胜的逐步方式可视化优化过程,以运行和可视化它。
什么是梯度下降?
梯度下降是一种用于最小化函数值的优化算法。它通过迭代地调整参数(例如机器学习中的权重)来减少函数的值。在数学术语中,该算法计算成本函数相对于每个参数的梯度或斜率,并在与梯度相反的方向上调整参数。
梯度指向最陡上升的方向,因此向相反方向移动会导致成本函数减小。
其他优化技术和梯度下降变体:
- 随机梯度下降
- 基于动量的梯度下降
- Adam优化器
Rosenbrock函数–一个复多元函数
在数学最优化中,Rosenbrock函数是一个用来测试最优化算法性能的非凸函数,由Howard Harry Rosenbrock在1960年提出 。也称为Rosenbrock山谷或Rosenbrock香蕉函数,也简称为香蕉函数。
Rosenbrock函数的定义如下:
Rosenbrock函数的每个等高线大致呈抛物线形,其全域最小值也位在抛物线形的山谷中(香蕉型山谷)。它有一个狭窄的曲线谷,导致全局最小值(1,1)和几个局部最小值,使其成为梯度下降的挑战。
由于其结构,Rosenbrock函数是一个很好的测试,可以可视化梯度下降在面对局部最小值时的行为以及它如何逐渐收敛到全局最小值。
Rosenbrock函数的梯度下降
下面提供的代码演示了如何将梯度下降应用于Rosenbrock函数,从任意点开始并向全局最小值移动。它还可视化了梯度下降在迭代中遵循的路径。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import imageio
import os
# Create a directory to store the frames
if not os.path.exists("frames"):
os.makedirs("frames")
# Rosenbrock function definition
def rosenbrock(x):
return (1 - x[0])**2 + 100 * (x[1] - x[0]**2)**2
# Gradient descent for the Rosenbrock function
def gradient_descent_rosenbrock(starting_point, learning_rate=0.001, n_iterations=1000):
x = np.array(starting_point, dtype=float) # Starting point
history = [x.copy()] # Store the history of points
for _ in range(n_iterations):
# Compute the gradient
grad = np.array([
-2 * (1 - x[0]) - 400 * x[0] * (x[1] - x[0]**2),
200 * (x[1] - x[0]**2)
])
# Update the parameters
x -= learning_rate * grad
history.append(x.copy())
return np.array(history)
# Run Gradient Descent starting from a specific point
starting_point = [-1.5, 2] # An arbitrary starting point
history = gradient_descent_rosenbrock(starting_point)
# Create a meshgrid for the surface plot
x1_range = np.linspace(-2, 2, 100)
x2_range = np.linspace(-1, 3, 100)
x1, x2 = np.meshgrid(x1_range, x2_range)
# Calculate Rosenbrock function values over the grid
Z = rosenbrock(np.array([x1, x2]))
# Create frames for the GIF
for i in range(len(history)):
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
# Plot the Rosenbrock function surface
ax.plot_surface(x1, x2, Z, alpha=0.5, cmap='viridis')
# Plot gradient descent path
ax.scatter(history[:i + 1, 0], history[:i + 1, 1],
rosenbrock(history[:i + 1].T),
color='red', label='Gradient Descent Path')
# Plot the current point
ax.scatter(history[i][0], history[i][1], rosenbrock(history[i]),
color='blue', s=100, label='Current Point')
ax.set_xlabel('X1')
ax.set_ylabel('X2')
ax.set_zlabel('Rosenbrock Function Value')
ax.set_title(f'Iteration {i + 1}')
ax.legend()
# Save frame
plt.tight_layout()
plt.savefig(f"frames/gradient_descent_rosenbrock_{i}.png")
plt.close()
# Create a GIF from the saved frames
images = []
for i in range(len(history)):
images.append(imageio.v2.imread(f"frames/gradient_descent_rosenbrock_{i}.png"))
imageio.mimsave('gradient_descent_rosenbrock_visualization.gif', images, duration=0.1)
# Clean up frames
for i in range(len(history)):
os.remove(f"frames/gradient_descent_rosenbrock_{i}.png")
print("GIF created successfully: 'gradient_descent_rosenbrock_visualization.gif'")
这段代码模拟了Rosenbrock函数的梯度下降算法,从随机选择的点开始,向全局最小值(1,1)移动。它生成了梯度下降算法如何导航通过函数的谷,并避免局部极小值的收敛过程中的动态可视化。
梯度下降路径可视化
以下是交互式GIF中的完整过程,您可以在其中看到算法在每次迭代中的路径:
关键点
- 窄谷:Rosenbrock函数特有的窄谷显示了梯度下降如何难以取得快速进展,特别是在早期迭代中。它需要仔细调整学习率,以避免过冲或卡住。
- 局部最小值与全局最小值:(1,1)处的全局最小值是最终目标,但沿着,梯度下降可能会通过局部最小值。梯度下降算法的持久性和随着时间的推移找到全局最小值的能力是至关重要的优势,但这个过程可能很慢,而且很有条理,这取决于起点。
- 学习率敏感性:调整学习率至关重要。太大的学习率会导致算法超过最优解,而太小的学习率会导致收敛缓慢。在这个可视化中,我们使用了0.001的中等学习率来确保渐进和平滑的下降。
Rosenbrock函数的路径是梯度下降的力量及其局限性的一个奇妙的演示。这个例子说明了梯度下降如何导航充满局部最小值的复杂优化景观,以及调整学习率等关键参数如何影响算法的性能。
通过这个详细的可视化,我们不仅探索了梯度下降的机制,还更深入地了解了它在Rosenbrock等具有挑战性的函数上的行为。正如我们所看到的,通往全局最小值的道路可能并不总是那么简单,但是通过正确的方法,梯度下降始终会找到它的道路。
好了,这篇文章就介绍到这里,喜欢的小伙伴感谢给点个赞和关注,更多精彩内容持续更新~~
关于本篇文章大家有任何建议或意见,欢迎在评论区留言交流!