Datawhale X 李宏毅苹果书AI夏令营:深度学习优化初探(鞍点与局部最小值)

259 阅读2分钟

0 前言:

在这一章节中我们会介绍一些基础的深度学习优化概念

1.局部极小值与鞍点:判断与逃离

1.1:鞍点与极小值

有时候有人会将深度学习的过程戏称为“调参”,但是在某些时候,我们会发现我们不论如何更新参数,训练的损失就不会再下降了。

此时我们可以做一猜想,我们在优化到某个地方的时候 这个地方对损失的微分为0(也就是损失不再变化)。就好像下图所示的一样。

image.png

这种情况下,梯度为0),该点也被称为临界点。在这个时候我们需要考虑损失的三种情况

  1. 局部极小值:梯度下降已经失效了(模型已经收敛于临界点)

image.png

  1. 鞍点:可以通过某些方法来逃离,这里鞍点的形状决定了其仍然有路径可以使得损失变得更低,也坑在某个地方更高

image.png

那么此时摆在我们面前的问题就变为了我们如何判断这个点是局部极小值点亦或者是鞍点,这里我们简单介绍一下判断的方法(其实就是一堆公式)

  1. 泰勒级数近似

    损失函数 L(θ)L(\theta) 在某点 θ\theta' 附近可以用泰勒级数近似:

    L(θ)L(θ)+(θθ)Tg+12(θθ)TH(θθ)L(\theta) \approx L(\theta') + (\theta - \theta')^T g + \frac{1}{2} (\theta - \theta')^T H (\theta - \theta')

    • gg 是梯度向量,gi=L(θ)θig_i = \frac{\partial L(\theta')}{\partial \theta_i}
    • HH 是海森矩阵,Hij=2L(θ)θiθjH_{ij} = \frac{\partial^2 L(\theta')}{\partial \theta_i \partial \theta_j}
  2. 在临界点

    • 梯度 g=0g = 0,因此损失函数简化为:

    L(θ)L(θ)+12(θθ)TH(θθ)L(\theta) \approx L(\theta') + \frac{1}{2} (\theta - \theta')^T H (\theta - \theta')

  3. 判断临界点类型

    • 定义 v=θθv = \theta - \theta',则:

    vTHvv^T H v

    • 正定矩阵:如果对所有 vvvTHv>0v^T H v > 0,则 θ\theta' 是局部极小值。
    • 负定矩阵:如果对所有 vvvTHv<0v^T H v < 0,则 θ\theta' 是局部极大值。
    • 鞍点:如果 vTHvv^T H v 有时大于零,有时小于零,则 θ\theta' 是鞍点。
  4. 特征值判断

    • 海森矩阵 HH 的特征值用于判断:
      • 所有特征值为正:局部极小值。
      • 所有特征值为负:局部极大值。
      • 特征值有正有负:鞍点。

我们可以上个简单的代码来表示这个过程

import numpy as np

# 定义损失函数及其梯度和海森矩阵
def loss_function(theta):
    # 示例损失函数
    return (1 - theta[0] * theta[1]) ** 2

def gradient(theta):
    # 计算梯度
    w1, w2 = theta
    grad_w1 = -2 * (1 - w1 * w2) * w2
    grad_w2 = -2 * (1 - w1 * w2) * w1
    return np.array([grad_w1, grad_w2])

def hessian(theta):
    # 计算海森矩阵
    w1, w2 = theta
    h11 = 2 * w2 * w2
    h12 = -2 + 4 * w1 * w2
    h21 = -2 + 4 * w1 * w2
    h22 = 2 * w1 * w1
    return np.array([[h11, h12], [h21, h22]])



import numpy as np

# 定义损失函数及其梯度和海森矩阵
def loss_function(theta):
    # 示例损失函数
    return (1 - theta[0] * theta[1]) ** 2

def gradient(theta):
    # 计算梯度
    w1, w2 = theta
    grad_w1 = -2 * (1 - w1 * w2) * w2
    grad_w2 = -2 * (1 - w1 * w2) * w1
    return np.array([grad_w1, grad_w2])

def hessian(theta):
    # 计算海森矩阵
    w1, w2 = theta
    h11 = 2 * w2 * w2
    h12 = -2 + 4 * w1 * w2
    h21 = -2 + 4 * w1 * w2
    h22 = 2 * w1 * w1
    return np.array([[h11, h12], [h21, h22]])

# 判断临界点类型
def check_critical_point(theta):
    H = hessian(theta)
    eigenvalues = np.linalg.eigvals(H)
    
    if all(eigenvalues > 0):
        return "局部极小值"
    elif all(eigenvalues < 0):
        return "局部极大值"
    else:
        return "鞍点"

# 示例参数
theta = np.array([0, 0])

# 计算梯度和海森矩阵
grad = gradient(theta)
H = hessian(theta)

print("梯度:", grad)
print("海森矩阵:\n", H)
print("临界点类型:", check_critical_point(theta))

1.2 一个简单网络的例子:

在这个神经元的例子中,我们研究一个简单的神经网络模型的优化问题。这里的神经网络如下图所示: image.png

网络结构

  • 模型:由两个权重 w1w_1w2w_2 组成的线性模型。
  • 公式:输入 xx 经过权重处理后,输出为 y=w1w2xy = w_1 w_2 x

数据集

  • 单个数据点:输入 x=1x = 1 时,期望输出 y=1y = 1
  • 目标:最小化输出与期望值之间的误差。

损失函数

  • 定义:使用平方误差:
    L=(1w1w2)2L = (1 - w_1 w_2)^2
    这是一个关于 w1w_1w2w_2 的函数。

我们可以看看其误差表面

image.png

梯度和海森矩阵

  1. 梯度

    • w1w_1w2w_2 求偏导:
      Lw1=2(1w1w2)w2\frac{\partial L}{\partial w_1} = -2 (1 - w_1 w_2) w_2
      Lw2=2(1w1w2)w1\frac{\partial L}{\partial w_2} = -2 (1 - w_1 w_2) w_1
  2. 海森矩阵

    • 二阶偏导数构成的矩阵:
      H=[2w222+4w1w22+4w1w22w12]H = \begin{bmatrix} 2w_2^2 & -2 + 4w_1w_2 \\ -2 + 4w_1w_2 & 2w_1^2 \end{bmatrix}

临界点分析

  • 原点 (w1=0,w2=0)(w_1 = 0, w_2 = 0)
    • 在此点,梯度为零,意味着它是一个临界点。
    • 海森矩阵在原点为:
      H=[0220]H = \begin{bmatrix} 0 & -2 \\ -2 & 0 \end{bmatrix}
    • 特征值为 $2-2$,由于存在正负特征值,原点是一个鞍点。

此时我们已经可以判断基本的鞍点了,这里还有一个问题,我们到底是局部最小点更多呢?还是鞍点更多。

这个答案我们需要通过升维来解决

这里我们可以看到一个一维度的误差表面,在这个表面上,我们得到的是一个局部最小值 image.png

但是我们不妨思考这么一个问题:这个一维的误差表面是否可能是某个二维误差表面的低维表示?或者换句话说,这个一维误差表面有没有可能是一个鞍点呢?答案当然是肯定的。

image.png

我们继续把这个例子推广到更加高维的情况(也就对应更加复杂的误差表面)

image.png

这里我们很容易做一个推导,在有参数量成千上万的网络中,维度是很高的(这里的参数量等同于维度)局部极小值的情况其实非常少,大部分实践都有很多的下降路径可走。

这里我们定义一个公式:最小值比例

image.png

我们可以观察到

image.png

由此可见,大部分时候我们还是多是遇到鞍点。