Datawhale AI 夏令营(第五期)——向李宏毅学深度学习(进阶)

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=(1w1w2)2
我们可以计算得到的海森矩阵为:
H = [ 0 − 2 − 2 0 ] H = \begin{bmatrix} 0 & -2 \\ -2 & 0 \end{bmatrix} H=[0220]
通过计算特征值,我们发现这个矩阵有一个正特征值和一个负特征值,这表明原点 (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θt1)
其中,𝜂是学习率,𝜆是动量系数。

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()


总结

通过对深度学习优化方法的探索,我学习到批量大小的选择和动量法的使用对提升模型性能至关重要。适当的批量大小可以加快训练速度,而动量法则能帮助模型在遇到优化障碍时继续前进,避免陷入局部极小值。合理的优化策略不仅能够提升模型的整体性能,还能确保模型在面对复杂数据时,依然保持鲁棒的表现。

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值