梯度下降优化:核心算法详解

梯度下降优化:核心算法详解
引言
想象您被蒙住眼睛站在山上,迫切地寻找最低点。您只能感受到脚下地面的斜率。这基本上就是梯度下降为机器学习算法所做的。它是一个强大的优化算法,通过迭代地"下坡"移动来帮助我们找到模型的最佳参数,从而最小化成本函数。本文将揭开这个核心算法背后的魔法,使其对初学者和经验丰富的机器学习爱好者都易于理解。
理解地形:成本函数和梯度
在我们开始下坡之旅之前,我们需要理解地形。在机器学习中,我们的""成本函数表示,也称为损失函数或目标函数。这个函数量化了我们的模型表现如何;较低的值表示更好的性能。我们的目标是找到最小化这个成本函数的参数(如神经网络中的权重和偏置)。
梯度是我们的指南针。它是一个向量,指向给定点处成本函数最陡峭上升的方向。直观地说,它告诉我们成本最大增加的方向。为了下降,我们只需沿梯度的相反方向移动。
在数学上,梯度是成本函数相对于每个参数的偏导数向量。对于简单的成本函数 J(θ),其中 θ 表示我们的参数,梯度表示为 ∇J(θ)。这个向量的每个元素表示当我们稍微调整相应参数时成本变化多少。
下降:梯度下降算法
梯度下降算法是一个迭代过程。我们从参数的初始猜测开始,并基于梯度重复更新它们,直到达到最小值(或对其的满意近似)。以下是简化的分解:
初始化参数: 从参数的随机或预定义值开始。
计算梯度: 使用微积分(或数值近似)计算 ∇J(θ)。
更新参数: 沿梯度的相反方向调整参数:
θ = θ - α ∇J(θ)
其中 α 学习率,一个控制步长的超参数。较小的 α 导致较小的步长,可能收敛较慢但精度更高,而较大的 α 导致较大的步长,可能收敛较快但有过冲最小值的风险。
重复步骤2和3: 继续迭代,直到满足停止标准(例如,梯度足够小,成本函数停止显著减少,或达到最大迭代次数)。
以下是Python伪代码表示:
  1. # 初始化参数 theta
  2. theta = initialize_parameters()

  3. # 设置学习率 alpha
  4. alpha = 0.01

  5. # 迭代直到收敛
  6. while not converged:
  7. # 计算梯度
  8. gradient = calculate_gradient(theta)
  9. # 更新参数
  10. theta = theta - alpha * gradient
  11. # 检查收敛
  12. if convergence_criteria_met(theta):
  13. break
python
梯度下降的类型
梯度下降有几种变体,每种都有其优缺点:
批量梯度下降: 在每次迭代中使用整个数据集计算梯度。这导致准确的梯度估计,但对于大型数据集可能在计算上很昂贵。
随机梯度下降(SGD): 在每次迭代中仅使用单个数据点(或一小批数据点)计算梯度。这要快得多,但在梯度估计中引入噪声,导致更不稳定的下降。
小批量梯度下降: 批量GD和SGD之间的折衷,在每次迭代中使用数据的小随机子集(小批量)来计算梯度。这平衡了计算效率和梯度准确性。
实际应用和意义
梯度下降是许多机器学习模型背后的主力。它对训练以下模型至关重要:
神经网络: 用于调整权重和偏置以最小化预测误差。
线性回归: 通过最小化平方误差之和找到最佳拟合线。
逻辑回归: 用于优化模型参数以最大化正确分类数据点的可能性。
支持向量机(SVM): 某些SVM训练算法利用梯度下降来优化模型参数。
挑战和局限性
虽然非常强大,但梯度下降并非没有挑战:
局部最小值: 算法可能陷入局部最小值,这是其附近最低但不是全局最小值(绝对最低点)的点。
学习率选择: 选择正确的学习率至关重要。太小,收敛缓慢;太大,算法可能过冲最小值并无法收敛。
鞍点: 在高维空间中,算法可能陷入鞍点,其中梯度为零,但它不是最小值或最大值。
梯度下降的未来
梯度下降仍然是机器学习中的基础算法。正在进行的研究专注于提高其效率和稳健性,包括:
自适应学习率: 像Adam和RMSprop这样的算法动态调整每个参数的学习率,提高收敛速度和稳定性。
基于动量的方法: 这些技术为下降添加惯性,帮助逃离局部最小值并加速收敛。
二阶优化方法: 这些方法使用成本函数曲率信息(Hessian矩阵)来更有效地指导下降,但它们通常在计算上更昂贵。
实际代码示例
让我们通过Python代码来深入理解梯度下降算法:
  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. from mpl_toolkits.mplot3d import Axes3D

  4. # 1. 基本梯度下降实现
  5. def basic_gradient_descent():
  6. """基本梯度下降算法"""
  7. def cost_function(x):
  8. """成本函数: f(x) = x² + 2x + 1"""
  9. return x**2 + 2*x + 1
  10. def gradient_function(x):
  11. """梯度函数: f'(x) = 2x + 2"""
  12. return 2*x + 2
  13. def gradient_descent(cost_func, grad_func, x0, learning_rate=0.1, max_iterations=100):
  14. """梯度下降算法"""
  15. x = x0
  16. history = [x]
  17. costs = [cost_func(x)]
  18. for i in range(max_iterations):
  19. grad = grad_func(x)
  20. x = x - learning_rate * grad
  21. history.append(x)
  22. costs.append(cost_func(x))
  23. # 检查收敛
  24. if abs(grad) < 1e-6:
  25. break
  26. return x, history, costs
  27. # 运行梯度下降
  28. x0 = 5.0
  29. optimal_x, history, costs = gradient_descent(cost_function, gradient_function, x0)
  30. print(f"初始值: x = {x0}")
  31. print(f"最优值: x = {optimal_x:.6f}")
  32. print(f"成本值: f(x) = {cost_function(optimal_x):.6f}")
  33. print(f"迭代次数: {len(history)}")
  34. # 可视化
  35. x_plot = np.linspace(-3, 7, 100)
  36. y_plot = cost_function(x_plot)
  37. plt.figure(figsize=(15, 5))
  38. # 函数和优化路径
  39. plt.subplot(1, 3, 1)
  40. plt.plot(x_plot, y_plot, 'b-', label='f(x) = x² + 2x + 1')
  41. plt.plot(history, costs, 'ro-', label='优化路径')
  42. plt.plot(optimal_x, cost_function(optimal_x), 'go', markersize=10, label='最优解')
  43. plt.xlabel('x')
  44. plt.ylabel('f(x)')
  45. plt.title('梯度下降优化')
  46. plt.legend()
  47. plt.grid(True, alpha=0.3)
  48. # 成本函数收敛
  49. plt.subplot(1, 3, 2)
  50. plt.plot(costs, 'b-')
  51. plt.xlabel('迭代次数')
  52. plt.ylabel('成本值')
  53. plt.title('成本函数收敛')
  54. plt.grid(True, alpha=0.3)
  55. # 梯度收敛
  56. plt.subplot(1, 3, 3)
  57. gradients = [gradient_function(x) for x in history]
  58. plt.plot(gradients, 'r-')
  59. plt.axhline(y=0, color='k', linestyle='--', alpha=0.5)
  60. plt.xlabel('迭代次数')
  61. plt.ylabel('梯度值')
  62. plt.title('梯度收敛')
  63. plt.grid(True, alpha=0.3)
  64. plt.tight_layout()
  65. plt.show()
  66. return optimal_x, history, costs

  67. # 2. 学习率影响分析
  68. def learning_rate_analysis():
  69. """学习率对梯度下降的影响"""
  70. def cost_function(x):
  71. return x**2 + 2*x + 1
  72. def gradient_function(x):
  73. return 2*x + 2
  74. def gradient_descent_with_lr(cost_func, grad_func, x0, learning_rate, max_iterations=100):
  75. """带学习率的梯度下降"""
  76. x = x0
  77. history = [x]
  78. for i in range(max_iterations):
  79. grad = grad_func(x)
  80. x = x - learning_rate * grad
  81. history.append(x)
  82. if abs(grad) < 1e-6:
  83. break
  84. return x, history
  85. # 测试不同学习率
  86. learning_rates = [0.01, 0.1, 0.5, 1.0, 1.5]
  87. x0 = 5.0
  88. results = []
  89. for lr in learning_rates:
  90. optimal_x, history = gradient_descent_with_lr(cost_function, gradient_function, x0, lr)
  91. results.append({
  92. 'learning_rate': lr,
  93. 'optimal_x': optimal_x,
  94. 'iterations': len(history),
  95. 'history': history
  96. })
  97. print(f"学习率 {lr}: 最优值 = {optimal_x:.6f}, 迭代次数 = {len(history)}")
  98. # 可视化不同学习率的效果
  99. plt.figure(figsize=(15, 5))
  100. # 优化路径
  101. plt.subplot(1, 3, 1)
  102. x_plot = np.linspace(-3, 7, 100)
  103. y_plot = cost_function(x_plot)
  104. plt.plot(x_plot, y_plot, 'k-', alpha=0.3, label='成本函数')
  105. colors = ['red', 'blue', 'green', 'orange', 'purple']
  106. for i, result in enumerate(results):
  107. history = result['history']
  108. costs = [cost_function(x) for x in history]
  109. plt.plot(history, costs, f'{colors[i]}o-',
  110. label=f'LR={result["learning_rate"]}')
  111. plt.xlabel('x')
  112. plt.ylabel('f(x)')
  113. plt.title('不同学习率的优化路径')
  114. plt.legend()
  115. plt.grid(True, alpha=0.3)
  116. # 收敛速度
  117. plt.subplot(1, 3, 2)
  118. for i, result in enumerate(results):
  119. history = result['history']
  120. costs = [cost_function(x) for x in history]
  121. plt.plot(costs, f'{colors[i]}-', label=f'LR={result["learning_rate"]}')
  122. plt.xlabel('迭代次数')
  123. plt.ylabel('成本值')
  124. plt.title('收敛速度比较')
  125. plt.legend()
  126. plt.grid(True, alpha=0.3)
  127. # 迭代次数
  128. plt.subplot(1, 3, 3)
  129. lrs = [r['learning_rate'] for r in results]
  130. iterations = [r['iterations'] for r in results]
  131. plt.bar(range(len(lrs)), iterations, color=colors)
  132. plt.xlabel('学习率')
  133. plt.ylabel('迭代次数')
  134. plt.title('收敛所需迭代次数')
  135. plt.xticks(range(len(lrs)), lrs)
  136. plt.grid(True, alpha=0.3)
  137. plt.tight_layout()
  138. plt.show()
  139. return results

  140. # 3. 多维梯度下降
  141. def multidimensional_gradient_descent():
  142. """多维梯度下降"""
  143. def cost_function_2d(x, y):
  144. """二维成本函数: f(x,y) = x² + y²"""
  145. return x**2 + y**2
  146. def gradient_2d(x, y):
  147. """二维梯度: [∂f/∂x, ∂f/∂y] = [2x, 2y]"""
  148. return np.array([2*x, 2*y])
  149. def gradient_descent_2d(cost_func, grad_func, x0, learning_rate=0.1, max_iterations=100):
  150. """二维梯度下降"""
  151. x = np.array(x0, dtype=float)
  152. history = [x.copy()]
  153. costs = [cost_func(x[0], x[1])]
  154. for i in range(max_iterations):
  155. grad = grad_func(x[0], x[1])
  156. x = x - learning_rate * grad
  157. history.append(x.copy())
  158. costs.append(cost_func(x[0], x[1]))
  159. if np.linalg.norm(grad) < 1e-6:
  160. break
  161. return x, history, costs
  162. # 从不同起点运行
  163. starting_points = [np.array([3.0, 4.0]), np.array([-2.0, 1.0]), np.array([0.0, 5.0])]
  164. results = []
  165. for i, x0 in enumerate(starting_points):
  166. optimal_point, history, costs = gradient_descent_2d(cost_function_2d, gradient_2d, x0)
  167. results.append({
  168. 'start': x0,
  169. 'optimal': optimal_point,
  170. 'history': history,
  171. 'costs': costs
  172. })
  173. print(f"起点 {i+1}: {x0} -> 最优点: {optimal_point}, 成本: {cost_function_2d(optimal_point[0], optimal_point[1]):.6f}")
  174. # 可视化
  175. x = np.linspace(-4, 4, 100)
  176. y = np.linspace(-4, 4, 100)
  177. X, Y = np.meshgrid(x, y)
  178. Z = cost_function_2d(X, Y)
  179. plt.figure(figsize=(12, 8))
  180. # 等高线图
  181. plt.contour(X, Y, Z, levels=20, alpha=0.6)
  182. plt.colorbar(label='f(x, y)')
  183. # 优化路径
  184. colors = ['red', 'blue', 'green']
  185. for i, result in enumerate(results):
  186. history = np.array(result['history'])
  187. plt.plot(history[:, 0], history[:, 1], f'{colors[i]}o-',
  188. label=f'路径 {i+1}: {result["start"]} -> {result["optimal"]:.2f}')
  189. plt.plot(result['start'][0], result['start'][1], f'{colors[i]}s', markersize=10)
  190. plt.plot(result['optimal'][0], result['optimal'][1], f'{colors[i]}*', markersize=15)
  191. plt.xlabel('x')
  192. plt.ylabel('y')
  193. plt.title('多维梯度下降优化路径')
  194. plt.legend()
  195. plt.grid(True, alpha=0.3)
  196. plt.axis('equal')
  197. plt.show()
  198. return results

  199. # 4. 不同类型的梯度下降
  200. def gradient_descent_variants():
  201. """梯度下降变体比较"""
  202. # 生成数据
  203. np.random.seed(42)
  204. X = np.random.randn(100, 2)
  205. y = 2 * X[:, 0] + 3 * X[:, 1] + 1 + 0.1 * np.random.randn(100)
  206. def linear_model(X, w, b):
  207. """线性模型"""
  208. return np.dot(X, w) + b
  209. def mse_loss(y_true, y_pred):
  210. """均方误差损失"""
  211. return np.mean((y_true - y_pred) ** 2)
  212. def compute_gradient(X, y, w, b):
  213. """计算梯度"""
  214. y_pred = linear_model(X, w, b)
  215. dw = -2 * np.mean(X.T * (y - y_pred), axis=1)
  216. db = -2 * np.mean(y - y_pred)
  217. return dw, db
  218. # 批量梯度下降
  219. def batch_gradient_descent(X, y, learning_rate=0.01, max_iterations=1000):
  220. """批量梯度下降"""
  221. w = np.zeros(2)
  222. b = 0.0
  223. history = []
  224. for i in range(max_iterations):
  225. dw, db = compute_gradient(X, y, w, b)
  226. w = w - learning_rate * dw
  227. b = b - learning_rate * db
  228. y_pred = linear_model(X, w, b)
  229. loss = mse_loss(y, y_pred)
  230. history.append(loss)
  231. if i % 100 == 0:
  232. print(f"批量GD - Epoch {i}: 损失 = {loss:.6f}")
  233. return w, b, history
  234. # 随机梯度下降
  235. def stochastic_gradient_descent(X, y, learning_rate=0.01, max_iterations=1000):
  236. """随机梯度下降"""
  237. w = np.zeros(2)
  238. b = 0.0
  239. history = []
  240. for i in range(max_iterations):
  241. # 随机选择一个样本
  242. idx = np.random.randint(0, len(X))
  243. X_sample = X[idx:idx+1]
  244. y_sample = y[idx:idx+1]
  245. dw, db = compute_gradient(X_sample, y_sample, w, b)
  246. w = w - learning_rate * dw
  247. b = b - learning_rate * db
  248. if i % 100 == 0:
  249. y_pred = linear_model(X, w, b)
  250. loss = mse_loss(y, y_pred)
  251. history.append(loss)
  252. print(f"随机GD - Epoch {i}: 损失 = {loss:.6f}")
  253. return w, b, history
  254. # 小批量梯度下降
  255. def mini_batch_gradient_descent(X, y, batch_size=32, learning_rate=0.01, max_iterations=1000):
  256. """小批量梯度下降"""
  257. w = np.zeros(2)
  258. b = 0.0
  259. history = []
  260. for i in range(max_iterations):
  261. # 随机选择小批量
  262. indices = np.random.choice(len(X), batch_size, replace=False)
  263. X_batch = X[indices]
  264. y_batch = y[indices]
  265. dw, db = compute_gradient(X_batch, y_batch, w, b)
  266. w = w - learning_rate * dw
  267. b = b - learning_rate * db
  268. if i % 100 == 0:
  269. y_pred = linear_model(X, w, b)
  270. loss = mse_loss(y, y_pred)
  271. history.append(loss)
  272. print(f"小批量GD - Epoch {i}: 损失 = {loss:.6f}")
  273. return w, b, history
  274. # 运行比较
  275. print("=== 批量梯度下降 ===")
  276. w_batch, b_batch, history_batch = batch_gradient_descent(X, y)
  277. print("\n=== 随机梯度下降 ===")
  278. w_sgd, b_sgd, history_sgd = stochastic_gradient_descent(X, y)
  279. print("\n=== 小批量梯度下降 ===")
  280. w_mb, b_mb, history_mb = mini_batch_gradient_descent(X, y)
  281. # 结果比较
  282. print(f"\n批量GD: w = {w_batch}, b = {b_batch:.4f}")
  283. print(f"随机GD: w = {w_sgd}, b = {b_sgd:.4f}")
  284. print(f"小批量GD: w = {w_mb}, b = {b_mb:.4f}")
  285. print(f"真实值: w = [2, 3], b = 1")
  286. # 可视化比较
  287. plt.figure(figsize=(15, 5))
  288. # 损失收敛
  289. plt.subplot(1, 3, 1)
  290. epochs = range(0, len(history_batch) * 100, 100)
  291. plt.plot(epochs, history_batch, 'b-', label='批量GD')
  292. plt.plot(epochs, history_sgd, 'r-', label='随机GD')
  293. plt.plot(epochs, history_mb, 'g-', label='小批量GD')
  294. plt.xlabel('Epoch')
  295. plt.ylabel('损失')
  296. plt.title('损失收敛比较')
  297. plt.legend()
  298. plt.grid(True, alpha=0.3)
  299. # 参数收敛
  300. plt.subplot(1, 3, 2)
  301. methods = ['批量GD', '随机GD', '小批量GD']
  302. w1_values = [w_batch[0], w_sgd[0], w_mb[0]]
  303. w2_values = [w_batch[1], w_sgd[1], w_mb[1]]
  304. x = np.arange(len(methods))
  305. width = 0.35
  306. plt.bar(x - width/2, w1_values, width, label='w1', alpha=0.8)
  307. plt.bar(x + width/2, w2_values, width, label='w2', alpha=0.8)
  308. plt.axhline(y=2, color='red', linestyle='--', alpha=0.7, label='真实w1')
  309. plt.axhline(y=3, color='orange', linestyle='--', alpha=0.7, label='真实w2')
  310. plt.xlabel('方法')
  311. plt.ylabel('权重值')
  312. plt.title('参数收敛比较')
  313. plt.xticks(x, methods)
  314. plt.legend()
  315. plt.grid(True, alpha=0.3)
  316. # 预测质量
  317. plt.subplot(1, 3, 3)
  318. y_pred_batch = linear_model(X, w_batch, b_batch)
  319. y_pred_sgd = linear_model(X, w_sgd, b_sgd)
  320. y_pred_mb = linear_model(X, w_mb, b_mb)
  321. plt.scatter(y, y_pred_batch, alpha=0.6, label='批量GD')
  322. plt.scatter(y, y_pred_sgd, alpha=0.6, label='随机GD')
  323. plt.scatter(y, y_pred_mb, alpha=0.6, label='小批量GD')
  324. plt.plot([y.min(), y.max()], [y.min(), y.max()], 'k--', alpha=0.5)
  325. plt.xlabel('真实值')
  326. plt.ylabel('预测值')
  327. plt.title('预测质量比较')
  328. plt.legend()
  329. plt.grid(True, alpha=0.3)
  330. plt.tight_layout()
  331. plt.show()
  332. return w_batch, w_sgd, w_mb

  333. # 5. 局部最小值和鞍点问题
  334. def local_minima_and_saddle_points():
  335. """局部最小值和鞍点问题"""
  336. def complex_function(x, y):
  337. """具有多个局部最小值的函数"""
  338. return np.sin(x) + 0.5 * x**2 + np.cos(y) + 0.3 * y**2
  339. def complex_gradient(x, y):
  340. """复杂函数的梯度"""
  341. dx = np.cos(x) + x
  342. dy = -np.sin(y) + 0.6 * y
  343. return np.array([dx, dy])
  344. def gradient_descent_with_momentum(cost_func, grad_func, x0, learning_rate=0.1, momentum=0.9, max_iterations=1000):
  345. """带动量的梯度下降"""
  346. x = np.array(x0, dtype=float)
  347. velocity = np.zeros_like(x)
  348. history = [x.copy()]
  349. for i in range(max_iterations):
  350. grad = grad_func(x[0], x[1])
  351. velocity = momentum * velocity - learning_rate * grad
  352. x = x + velocity
  353. history.append(x.copy())
  354. if np.linalg.norm(grad) < 1e-6:
  355. break
  356. return x, history
  357. # 从不同起点运行
  358. starting_points = [np.array([-3.0, 2.0]), np.array([1.0, -2.0]), np.array([0.0, 0.0])]
  359. results = []
  360. for i, x0 in enumerate(starting_points):
  361. optimal_point, history = gradient_descent_with_momentum(complex_function, complex_gradient, x0)
  362. results.append({
  363. 'start': x0,
  364. 'optimal': optimal_point,
  365. 'history': history,
  366. 'value': complex_function(optimal_point[0], optimal_point[1])
  367. })
  368. print(f"起点 {i+1}: {x0} -> 最优点: {optimal_point}, 函数值: {complex_function(optimal_point[0], optimal_point[1]):.6f}")
  369. # 可视化
  370. x = np.linspace(-4, 4, 100)
  371. y = np.linspace(-4, 4, 100)
  372. X, Y = np.meshgrid(x, y)
  373. Z = complex_function(X, Y)
  374. plt.figure(figsize=(15, 5))
  375. # 3D表面图
  376. ax1 = plt.subplot(1, 3, 1, projection='3d')
  377. surf = ax1.plot_surface(X, Y, Z, cmap='viridis', alpha=0.8)
  378. ax1.set_title('复杂函数表面')
  379. ax1.set_xlabel('x')
  380. ax1.set_ylabel('y')
  381. ax1.set_zlabel('f(x,y)')
  382. # 等高线图
  383. ax2 = plt.subplot(1, 3, 2)
  384. contour = ax2.contour(X, Y, Z, levels=20)
  385. ax2.clabel(contour, inline=True, fontsize=8)
  386. colors = ['red', 'blue', 'green']
  387. for i, result in enumerate(results):
  388. history = np.array(result['history'])
  389. ax2.plot(history[:, 0], history[:, 1], f'{colors[i]}o-',
  390. label=f'路径 {i+1}: {result["start"]} -> {result["optimal"]:.2f}')
  391. ax2.plot(result['start'][0], result['start'][1], f'{colors[i]}s', markersize=10)
  392. ax2.plot(result['optimal'][0], result['optimal'][1], f'{colors[i]}*', markersize=15)
  393. ax2.set_title('优化路径')
  394. ax2.set_xlabel('x')
  395. ax2.set_ylabel('y')
  396. ax2.legend()
  397. ax2.grid(True, alpha=0.3)
  398. # 函数值收敛
  399. ax3 = plt.subplot(1, 3, 3)
  400. for i, result in enumerate(results):
  401. history = np.array(result['history'])
  402. values = [complex_function(x[0], x[1]) for x in history]
  403. ax3.plot(values, f'{colors[i]}-', label=f'路径 {i+1}')
  404. ax3.set_xlabel('迭代次数')
  405. ax3.set_ylabel('函数值')
  406. ax3.set_title('函数值收敛')
  407. ax3.legend()
  408. ax3.grid(True, alpha=0.3)
  409. plt.tight_layout()
  410. plt.show()
  411. return results

  412. # 6. 自适应学习率算法
  413. def adaptive_learning_rate_algorithms():
  414. """自适应学习率算法"""
  415. def rosenbrock_function(x):
  416. """Rosenbrock函数"""
  417. return (1 - x[0])**2 + 100 * (x[1] - x[0]**2)**2
  418. def rosenbrock_gradient(x):
  419. """Rosenbrock函数梯度"""
  420. dx1 = -2 * (1 - x[0]) - 400 * x[0] * (x[1] - x[0]**2)
  421. dx2 = 200 * (x[1] - x[0]**2)
  422. return np.array([dx1, dx2])
  423. # AdaGrad
  424. def adagrad(cost_func, grad_func, x0, learning_rate=0.1, max_iterations=1000):
  425. """AdaGrad算法"""
  426. x = np.array(x0, dtype=float)
  427. G = np.zeros_like(x) # 梯度平方累积
  428. history = [x.copy()]
  429. for i in range(max_iterations):
  430. grad = grad_func(x)
  431. G += grad**2
  432. x = x - learning_rate * grad / (np.sqrt(G) + 1e-8)
  433. history.append(x.copy())
  434. if np.linalg.norm(grad) < 1e-6:
  435. break
  436. return x, history
  437. # RMSprop
  438. def rmsprop(cost_func, grad_func, x0, learning_rate=0.01, beta=0.9, max_iterations=1000):
  439. """RMSprop算法"""
  440. x = np.array(x0, dtype=float)
  441. v = np.zeros_like(x) # 移动平均
  442. history = [x.copy()]
  443. for i in range(max_iterations):
  444. grad = grad_func(x)
  445. v = beta * v + (1 - beta) * grad**2
  446. x = x - learning_rate * grad / (np.sqrt(v) + 1e-8)
  447. history.append(x.copy())
  448. if np.linalg.norm(grad) < 1e-6:
  449. break
  450. return x, history
  451. # Adam
  452. def adam(cost_func, grad_func, x0, learning_rate=0.01, beta1=0.9, beta2=0.999, max_iterations=1000):
  453. """Adam算法"""
  454. x = np.array(x0, dtype=float)
  455. m = np.zeros_like(x) # 一阶矩估计
  456. v = np.zeros_like(x) # 二阶矩估计
  457. history = [x.copy()]
  458. for i in range(max_iterations):
  459. grad = grad_func(x)
  460. m = beta1 * m + (1 - beta1) * grad
  461. v = beta2 * v + (1 - beta2) * grad**2
  462. # 偏差修正
  463. m_hat = m / (1 - beta1**(i+1))
  464. v_hat = v / (1 - beta2**(i+1))
  465. x = x - learning_rate * m_hat / (np.sqrt(v_hat) + 1e-8)
  466. history.append(x.copy())
  467. if np.linalg.norm(grad) < 1e-6:
  468. break
  469. return x, history
  470. # 比较算法
  471. x0 = np.array([-1.0, 1.0])
  472. algorithms = [
  473. ('AdaGrad', adagrad),
  474. ('RMSprop', rmsprop),
  475. ('Adam', adam)
  476. ]
  477. results = []
  478. for name, algorithm in algorithms:
  479. optimal_point, history = algorithm(rosenbrock_function, rosenbrock_gradient, x0)
  480. results.append({
  481. 'name': name,
  482. 'optimal': optimal_point,
  483. 'history': history,
  484. 'value': rosenbrock_function(optimal_point)
  485. })
  486. print(f"{name}: 最优点 = {optimal_point}, 函数值 = {rosenbrock_function(optimal_point):.6f}")
  487. # 可视化比较
  488. plt.figure(figsize=(15, 5))
  489. # 优化路径
  490. plt.subplot(1, 3, 1)
  491. x = np.linspace(-2, 2, 100)
  492. y = np.linspace(-1, 3, 100)
  493. X, Y = np.meshgrid(x, y)
  494. Z = np.zeros_like(X)
  495. for i in range(X.shape[0]):
  496. for j in range(X.shape[1]):
  497. Z[i, j] = rosenbrock_function([X[i, j], Y[i, j]])
  498. plt.contour(X, Y, Z, levels=20, alpha=0.6)
  499. colors = ['red', 'blue', 'green']
  500. for i, result in enumerate(results):
  501. history = np.array(result['history'])
  502. plt.plot(history[:, 0], history[:, 1], f'{colors[i]}o-',
  503. label=f'{result["name"]}: {result["optimal"]:.3f}')
  504. plt.plot(1, 1, 'k*', markersize=15, label='全局最优 (1,1)')
  505. plt.xlabel('x1')
  506. plt.ylabel('x2')
  507. plt.title('优化路径比较')
  508. plt.legend()
  509. plt.grid(True, alpha=0.3)
  510. # 函数值收敛
  511. plt.subplot(1, 3, 2)
  512. for i, result in enumerate(results):
  513. history = np.array(result['history'])
  514. values = [rosenbrock_function(x) for x in history]
  515. plt.plot(values, f'{colors[i]}-', label=result['name'])
  516. plt.xlabel('迭代次数')
  517. plt.ylabel('函数值')
  518. plt.title('收敛速度比较')
  519. plt.legend()
  520. plt.grid(True, alpha=0.3)
  521. plt.yscale('log')
  522. # 梯度范数
  523. plt.subplot(1, 3, 3)
  524. for i, result in enumerate(results):
  525. history = np.array(result['history'])
  526. gradients = [np.linalg.norm(rosenbrock_gradient(x)) for x in history]
  527. plt.plot(gradients, f'{colors[i]}-', label=result['name'])
  528. plt.xlabel('迭代次数')
  529. plt.ylabel('梯度范数')
  530. plt.title('梯度收敛比较')
  531. plt.legend()
  532. plt.grid(True, alpha=0.3)
  533. plt.yscale('log')
  534. plt.tight_layout()
  535. plt.show()
  536. return results

  537. # 运行所有示例
  538. if __name__ == "__main__":
  539. print("=== 基本梯度下降 ===")
  540. optimal_x, history, costs = basic_gradient_descent()
  541. print("\n=== 学习率分析 ===")
  542. lr_results = learning_rate_analysis()
  543. print("\n=== 多维梯度下降 ===")
  544. md_results = multidimensional_gradient_descent()
  545. print("\n=== 梯度下降变体 ===")
  546. variant_results = gradient_descent_variants()
  547. print("\n=== 局部最小值和鞍点 ===")
  548. local_min_results = local_minima_and_saddle_points()
  549. print("\n=== 自适应学习率算法 ===")
  550. adaptive_results = adaptive_learning_rate_algorithms()
python
总结
梯度下降是现代机器学习的基石。其直观的概念,广泛的适用性和持续的改进确保了其在塑造人工智能未来方面的持续重要性。理解其机制和局限性对于任何寻求掌握机器学习领域的人来说都是必不可少的。
关键要点:
基本原理:沿梯度相反方向迭代更新参数
学习率选择:平衡收敛速度和稳定性
算法变体:批量、随机、小批量梯度下降
挑战:局部最小值、鞍点、学习率调优
改进方法:动量、自适应学习率、二阶方法
实际应用:
神经网络训练:权重和偏置优化
线性模型:参数估计
深度学习:大规模模型训练
强化学习:策略优化
梯度下降算法不仅是理论工具,更是现代机器学习系统实现的核心技术。随着自动微分和高级优化算法的发展,梯度下降继续在人工智能领域发挥关键作用,推动着机器学习的快速发展。