Task1:《深度学习详解》笔记
提示:此处为作者对学习内容的简析和总结
Task1:《深度学习详解》笔记
提示:以下是本篇文章正文内容
局部极小值与鞍点
在深度学习的训练过程中,我们常常会遇到一个问题:随着参数的不断调整,训练损失到达某个点后似乎不再下降。这种情况有时让人感到困惑,因为我们期望通过不断的训练,损失会逐步减少。然而,现实中,深度神经网络的优化过程并非总是如此顺利,这可能是因为我们陷入了所谓的局部极小值或鞍点。
局部极小值和鞍点都是训练过程中可能遇到的“障碍物”。局部极小值意味着在某个点的周围,损失函数在所有方向上都是增加的,导致参数无法进一步优化。而鞍点则更加复杂,它的特点是损失函数在某些方向上可能增加,而在其他方向上可能减少。理解这两者对优化的影响对于提升模型性能至关重要。
1.临界点的定义
在梯度下降的过程中,临界点指的是损失函数的梯度为零的点。通常,临界点可以是局部极小值、局部极大值或者鞍点。为了更好地理解这些概念,我们可以使用一个简单的例子来说明。
假设我们在一个二维空间中进行优化,如图3.2所示,损失函数的图像可能会包含多个局部极小值(图3.2a)和鞍点(图3.2b)。当梯度为零时,参数的更新停止,因此模型可能会“卡”在这些点上。
2.判断临界点的类型
要判断一个临界点是局部极小值还是鞍点,我们需要了解损失函数在临界点附近的形状。通过泰勒级数近似,我们可以描述损失函数的局部行为:
L
(
θ
)
≈
L
(
θ
′
)
+
(
θ
−
θ
′
)
T
g
+
1
2
(
θ
−
θ
′
)
T
H
(
θ
−
θ
′
)
L(\theta) \approx L(\theta') + (\theta - \theta')^T g + \frac{1}{2} (\theta - \theta')^T H (\theta - \theta')
L(θ)≈L(θ′)+(θ−θ′)Tg+21(θ−θ′)TH(θ−θ′)
在这个公式中,𝑔表示梯度,𝐻是海森矩阵(Hessian Matrix)。梯度向量𝑔代表了损失函数的斜率,而海森矩阵 𝐻则包含了损失函数的二阶导数信息,描述了损失函数的曲率。
通过分析海森矩阵的特征值,我们可以判断临界点的性质:
如果所有特征值都为正,临界点是局部极小值。
如果所有特征值都为负,临界点是局部极大值。
如果特征值有正有负,则临界点是鞍点。
举个例子,假设我们有一个简单的神经网络,只有两个权重𝑤1和 𝑤2,没有激活函数或偏置,输出为𝑦=𝑤1𝑤2𝑥。当我们计算其梯度和海森矩阵时,可以通过海森矩阵的特征值来判断原点 (0,0) 是鞍点还是局部极小值。
4.海森矩阵的计算和应用
计算海森矩阵的过程虽然复杂,但它可以为我们提供有价值的信息。例如,海森矩阵的一个特征值为负时,对应的方向上损失函数会降低,这意味着我们可以沿着这个方向继续优化参数,帮助模型逃离鞍点。
举例来说,对于上面提到的神经网络,其损失函数 𝐿为:
L
=
(
1
−
w
1
w
2
)
2
L = (1 - w_1w_2)^2
L=(1−w1w2)2
我们可以计算得到的海森矩阵为:
H
=
[
0
−
2
−
2
0
]
H = \begin{bmatrix} 0 & -2 \\ -2 & 0 \end{bmatrix}
H=[0−2−20]
通过计算特征值,我们发现这个矩阵有一个正特征值和一个负特征值,这表明原点 (0,0) 是一个鞍点。我们可以利用这个信息,通过沿着负特征值对应的方向更新参数,找到损失更小的点。
5.鞍点的影响与逃离
虽然鞍点会导致训练的停滞,但它并不是不可逾越的障碍。事实上,随着深度神经网络维度的增加,鞍点反而可能更为常见。幸运的是,由于模型的高维特性,通常有很多路径可以帮助我们逃离鞍点,继续优化损失。
在实际训练中,并非总要需要计算海森矩阵并寻找特征值。随机梯度下降法和添加噪声的优化方法通常能够帮助我们跳出鞍点,找到更优的解。
6.代码实现
import numpy as np
# 定义损失函数L和其梯度
def loss_function(w1, w2):
return (1 - w1 * w2) ** 2
def gradient(w1, w2):
dL_dw1 = -2 * (1 - w1 * w2) * w2
dL_dw2 = -2 * (1 - w1 * w2) * w1
return np.array([dL_dw1, dL_dw2])
# 海森矩阵
def hessian_matrix(w1, w2):
d2L_dw1w1 = 2 * (w2 ** 2)
d2L_dw1w2 = -2 + 4 * w1 * w2
d2L_dw2w2 = 2 * (w1 ** 2)
return np.array([[d2L_dw1w1, d2L_dw1w2],
[d2L_dw1w2, d2L_dw2w2]])
# 判断临界点是否是局部极值或鞍点
def check_critical_point(w1, w2):
H = hessian_matrix(w1, w2)
eigenvalues = np.linalg.eigvals(H)
if np.all(eigenvalues > 0):
print("临界点是局部极小值")
elif np.all(eigenvalues < 0):
print("临界点是局部极大值")
else:
print("临界点是鞍点")
# 初始值设定
w1, w2 = 0, 0
# 损失函数值、梯度和海森矩阵
loss = loss_function(w1, w2)
grad = gradient(w1, w2)
Hessian = hessian_matrix(w1, w2)
print(f"损失函数值: {loss}")
print(f"梯度: {grad}")
print(f"海森矩阵: \n{Hessian}")
# 判断临界点的性质
check_critical_point(w1, w2)
批量和动量
在深度学习的训练过程中,我们常常会遇到一个问题:随着参数的不断调整,训练损失到达某个点后似乎不再下降。这种情况有时让人感到困惑,因为我们期望通过不断的训练,损失会逐步减少。然而,现实中,深度神经网络的优化过程并非总是如此顺利,这可能是因为我们陷入了所谓的局部极小值或鞍点。
局部极小值和鞍点都是训练过程中可能遇到的“障碍物”。局部极小值意味着在某个点的周围,损失函数在所有方向上都是增加的,导致参数无法进一步优化。而鞍点则更加复杂,它的特点是损失函数在某些方向上可能增加,而在其他方向上可能减少。理解这两者对优化的影响对于提升模型性能至关重要。
1.批量和梯度下降法
深度学习中,优化模型的参数是实现高效学习的关键。
梯度下降法作为主要的优化方法,通过计算损失函数的梯度来调整参数。然而,计算梯度时,并不是直接对整个数据集进行计算,而是将数据分成若干批量(batch)。每次只用一个批量的数据来计算梯度,然后更新模型参数。整个数据集被遍历一次的过程称为一个回合(epoch)。在每个回合开始前,数据通常会被随机打乱,这种做法有助于提升模型的泛化能力,避免过拟合。
2. 批量大小的影响
批量大小在梯度下降法中起着至关重要的作用。
极端情况下,如果批量大小等于整个数据集的大小,这种方法称为批量梯度下降法(Batch Gradient Descent, BGD)。在这种方法中,必须看完所有数据后才能更新一次参数,因此每次迭代的计算量较大,但更新方向较为稳定。
相反,若批量大小为1,则称为随机梯度下降法(Stochastic Gradient Descent, SGD)。这种方法每处理一笔数据就更新一次参数,因此更新速度快,但更新方向可能会受到数据噪声的影响,导致收敛路径曲折,且收敛过程可能较为缓慢。
在实际应用中,我们常会选择介于这两者之间的批量大小,也就是小批量梯度下降法(Mini-Batch Gradient Descent)。这种方法兼具计算效率和更新稳定性,能够更好地平衡这两者之间的关系。
3.并行计算与批量大小
在深度学习中,GPU的强大并行计算能力为大批量训练带来了显著的效率提升。举个例子,在处理MNIST数据集时,实验发现,当批量大小从1增加到1000时,计算梯度并更新参数的时间几乎保持不变。这是因为GPU能够同时处理大量的数据,因此即使批量大小较大,也能在相同的时间内完成计算。
然而,当批量大小进一步增大时,GPU的计算时间会随之增加。这是因为GPU在处理过大批量数据时,计算资源可能会被耗尽,导致效率降低。因此,在选择批量大小时,我们不仅需要考虑计算效率,还要在稳定性和随机性之间找到一个平衡点。
4. 动量法:克服局部最小值与鞍点
动量法(Momentum Method)是优化梯度下降法的一种改进。其原理类似于物理学中的惯性效应:当一个球从山坡上滚下时,尽管可能会遇到局部最小值或鞍点,但由于惯性,它仍可能继续滚动并越过这些障碍。动量法就是将这种“惯性”引入到参数更新过程中。
在动量法中,每次更新参数时,除了考虑当前的梯度方向,还会参考前一次的移动方向。这样,即使在梯度接近零的情况下,动量也能帮助模型继续前进,从而克服局部最小值或鞍点的影响。
动量法的更新规则为:
θ
t
+
1
=
θ
t
−
η
∇
L
(
θ
t
)
+
λ
(
θ
t
−
θ
t
−
1
)
\theta_{t+1} = \theta_t - \eta \nabla L(\theta_t) + \lambda (\theta_t - \theta_{t-1})
θt+1=θt−η∇L(θt)+λ(θt−θt−1)
其中,𝜂是学习率,𝜆是动量系数。
5. 动量的优点
引入动量后,模型在训练过程中更有可能摆脱局部最小值,甚至找到更好的解。传统的梯度下降法有时会在遇到局部最小值或鞍点时停滞不前,难以继续优化。这就像在山谷中行走,当地势平坦或下陷时,行进速度会减慢甚至停滞。但动量法则不同,它通过累积之前的梯度信息,为模型增加了“惯性”,使得模型在遇到这些困境时依然能够继续前进。
即使面对看似平坦的区域,动量法也能帮助模型找到突破口,推动其朝更优的方向发展。比如一个滚动的球,如果没有足够的动量,可能会在平坦或稍微倾斜的地面上停下来。但如果球有足够的动量,它就能继续滚动,甚至越过一些小的障碍,找到最终的下坡路径。动量法在优化过程中扮演的正是这样的角色,确保模型不会轻易被局部困难所阻碍,能够更顺畅地接近全局最优解。
6.代码实现
import numpy as np
# 简单的二次损失函数
def loss_function(theta):
return theta ** 4 - 3 * theta ** 3 + 2
# 损失函数的梯度
def gradient(theta):
return 4 * theta ** 3 - 9 * theta ** 2
# 批量梯度下降法
def gradient_descent(theta_init, lr=0.01, epochs=100):
theta = theta_init
history = []
for _ in range(epochs):
grad = gradient(theta)
theta = theta - lr * grad
history.append(theta)
return history
# 动量法
def momentum_method(theta_init, lr=0.01, momentum=0.9, epochs=100):
theta = theta_init
v = 0 # 初始化动量
history = []
for _ in range(epochs):
grad = gradient(theta)
v = momentum * v - lr * grad # 更新动量
theta = theta + v # 更新参数
history.append(theta)
return history
# 初始化参数
theta_init = 0.5
learning_rate = 0.01
epochs = 100
gd_history = gradient_descent(theta_init, lr=learning_rate, epochs=epochs)
momentum_history = momentum_method(theta_init, lr=learning_rate, momentum=0.9, epochs=epochs)
print(f"批量梯度下降法最终theta值: {gd_history[-1]}")
print(f"动量法最终theta值: {momentum_history[-1]}")
# 收敛曲线
import matplotlib.pyplot as plt
plt.plot(gd_history, label='Gradient Descent')
plt.plot(momentum_history, label='Momentum Method')
plt.xlabel('Epoch')
plt.ylabel('Theta')
plt.legend()
plt.title('Convergence of Gradient Descent vs Momentum Method')
plt.show()
总结
通过对深度学习优化方法的探索,我学习到批量大小的选择和动量法的使用对提升模型性能至关重要。适当的批量大小可以加快训练速度,而动量法则能帮助模型在遇到优化障碍时继续前进,避免陷入局部极小值。合理的优化策略不仅能够提升模型的整体性能,还能确保模型在面对复杂数据时,依然保持鲁棒的表现。