Skip to content
约 0 字 · 预计阅读 0 分钟

损失函数与优化器

阅读时长:约 12 分钟 难度等级:中级 读完你将学会:理解各类损失函数的原理与选择、掌握优化器的工作机制、理解学习率的影响

要点速览

  • MSE 用于回归,Cross-Entropy 用于分类
  • 学习率是最重要的超参数,需要仔细调整
  • Adam 是最常用的优化器,自适应调整每个参数的学习率

前置知识

阅读本文前,你需要了解:

本文不假设你了解:

  • 任何深度学习框架
  • 复杂的优化理论

损失函数

什么是损失函数?

损失函数(Loss Function)衡量模型预测值与真实值之间的差距。训练的目标就是最小化损失函数


均方误差(MSE)

用于回归问题:

L=1ni=1n(yiy^i)2

梯度推导

Ly^i=2n(y^iyi)
python
# 片段:MSE 损失
import numpy as np

def mse_loss(y_pred, y_true):
    """均方误差损失函数"""
    return np.mean((y_pred - y_true) ** 2)

def mse_loss_gradient(y_pred, y_true):
    """MSE 损失的梯度"""
    n = y_pred.shape[0]
    return 2 * (y_pred - y_true) / n

交叉熵损失(Cross-Entropy)

二元交叉熵

用于二分类问题:

L=1ni=1n[yilog(y^i)+(1yi)log(1y^i)]

梯度推导

Ly^i=yiy^i+1yi1y^i=y^iyiy^i(1y^i)

多类交叉熵

用于多分类问题:

L=i=1nc=1Cyi,clog(y^i,c)

对于 one-hot 编码的标签,简化为:

L=1ni=1nlog(y^i,yi)
python
# 片段:交叉熵损失
def cross_entropy_loss(y_pred, y_true):
    """
    交叉熵损失函数
    
    参数:
        y_pred: 预测概率分布
        y_true: 真实标签的 one-hot 编码
    """
    epsilon = 1e-15
    y_pred = np.clip(y_pred, epsilon, 1 - epsilon)
    return -np.sum(y_true * np.log(y_pred)) / y_pred.shape[0]

def cross_entropy_gradient(y_pred, y_true):
    """
    交叉熵损失的梯度
    
    对于 softmax + cross-entropy 组合,梯度简化为:
    ∂L/∂z = y_pred - y_true
    """
    return y_pred - y_true

损失函数选择

问题类型推荐损失函数输出层激活梯度
二分类Binary Cross-EntropySigmoidy^y
多分类Categorical Cross-EntropySoftmaxy^y
回归MSE无/Linear2n(y^y)

优化器

什么是优化器?

优化器(Optimizer)根据梯度更新模型参数,目标是找到损失函数的最小值。


梯度下降

最基础的优化算法:

θt+1=θtηL(θt)

其中 η 是学习率(Learning Rate)。

python
# 片段:梯度下降
def gradient_descent(params, gradients, learning_rate):
    """基础梯度下降"""
    for i in range(len(params)):
        params[i] -= learning_rate * gradients[i]
    return params

学习率的影响

学习率是最重要的超参数之一:

学习率现象
太大损失震荡、发散
太小收敛太慢、陷入局部最优
合适平稳收敛
学习率影响可视化

SGD(随机梯度下降)

python
# 片段:SGD 优化器
class SGD:
    def __init__(self, learning_rate=0.01):
        self.lr = learning_rate
    
    def step(self, params, gradients):
        for i in range(len(params)):
            params[i] -= self.lr * gradients[i]

SGD with Momentum

更新公式

vt=βvt1+(1β)L(θt)θt+1=θtηvt
python
# 片段:带动量的 SGD
class SGDMomentum:
    def __init__(self, learning_rate=0.01, momentum=0.9):
        self.lr = learning_rate
        self.momentum = momentum
        self.velocities = None
    
    def step(self, params, gradients):
        if self.velocities is None:
            self.velocities = [np.zeros_like(p) for p in params]
        
        for i in range(len(params)):
            self.velocities[i] = self.momentum * self.velocities[i] + (1 - self.momentum) * gradients[i]
            params[i] -= self.lr * self.velocities[i]

Momentum 的作用:

  • 加速收敛
  • 避免陷入局部最优
  • 平滑梯度方向

Adam

Adam 结合了动量和自适应学习率。

更新公式

mt=β1mt1+(1β1)gtvt=β2vt1+(1β2)gt2m^t=mt1β1tv^t=vt1β2tθt+1=θtηv^t+ϵm^t
python
# 片段:Adam 优化器
class Adam:
    def __init__(self, learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8):
        self.lr = learning_rate
        self.beta1 = beta1
        self.beta2 = beta2
        self.epsilon = epsilon
        self.m = None
        self.v = None
        self.t = 0
    
    def step(self, params, gradients):
        if self.m is None:
            self.m = [np.zeros_like(p) for p in params]
            self.v = [np.zeros_like(p) for p in params]
        
        self.t += 1
        
        for i in range(len(params)):
            g = gradients[i]
            
            # 更新一阶矩(梯度均值)
            self.m[i] = self.beta1 * self.m[i] + (1 - self.beta1) * g
            
            # 更新二阶矩(梯度方差)
            self.v[i] = self.beta2 * self.v[i] + (1 - self.beta2) * (g ** 2)
            
            # 偏差修正
            m_hat = self.m[i] / (1 - self.beta1 ** self.t)
            v_hat = self.v[i] / (1 - self.beta2 ** self.t)
            
            # 更新参数
            params[i] -= self.lr * m_hat / (np.sqrt(v_hat) + self.epsilon)

Adam 的优势:

  • 自适应学习率:每个参数有不同的学习率
  • 结合动量:加速收敛
  • 偏差修正:解决初始阶段偏差问题

优化器对比

优化器特点适用场景
SGD简单、稳定凸优化、精细调优
SGD+Momentum加速收敛深层网络
Adam自适应学习率大多数情况

权重初始化

为什么初始化很重要?

  • 全零初始化:所有神经元学习相同的特征
  • 过大初始化:激活值饱和,梯度消失
  • 过小初始化:激活值过小,梯度消失

Xavier 初始化

适用于 Sigmoid、Tanh 等饱和激活函数:

WN(0,2nin+nout)

He 初始化

适用于 ReLU 及其变体:

WN(0,2nin)
python
# 片段:权重初始化
def xavier_init(shape):
    """Xavier 初始化"""
    fan_in, fan_out = shape[1], shape[0]
    scale = np.sqrt(2.0 / (fan_in + fan_out))
    return np.random.randn(*shape) * scale

def he_init(shape):
    """He 初始化(适用于 ReLU)"""
    fan_in = shape[1]
    scale = np.sqrt(2.0 / fan_in)
    return np.random.randn(*shape) * scale

本节要点

记住这三点:

  1. MSE 用于回归,Cross-Entropy 用于分类
  2. 学习率是最重要的超参数,需要仔细调整
  3. Adam 是最常用的优化器,自适应调整每个参数的学习率

更新日志

日期内容
2026-03-28初稿发布

相关主题

基于 VitePress 构建