在深度学习中,优化器的核心作用是通过调整模型参数(如权重和偏置),最小化损失函数,从而使模型逐步学习到数据中的规律。不同优化器通过不同的参数更新策略,在收敛速度、稳定性、泛化能力等方面表现出差异。本文将详细拆解主流优化器的原理、公式推导,并提供基于PyTorch的可运行完整代码。相关论文及代码可以自取

原文、资料 这里!

一、优化器核心背景:参数更新的本质

所有优化器的本质都是迭代更新模型参数,其通用框架为:
对于模型参数 θ \theta θ(如权重矩阵 W W W、偏置 b b b),每次迭代时根据损失函数的梯度 ∇ L ( θ ) \nabla L(\theta) L(θ)(损失对参数的偏导数)和优化器特定的更新规则,调整参数:
θ t + 1 = θ t − η ⋅ UpdateRule ( ∇ L ( θ t ) , 历史信息 ) \theta_{t+1} = \theta_t - \eta \cdot \text{UpdateRule}(\nabla L(\theta_t), \text{历史信息}) θt+1=θtηUpdateRule(L(θt),历史信息)

其中:

  • t t t:迭代步数(epoch或step);
  • η \eta η:学习率(Learning Rate),控制每次参数更新的幅度,是优化器的关键超参数;
  • UpdateRule \text{UpdateRule} UpdateRule:优化器的核心策略,决定是否利用历史梯度、动量等信息。

二、主流优化器详解(原理+公式+代码)

1. 随机梯度下降(SGD):最基础的优化器

SGD是所有优化器的“基石”,直接使用当前批次的梯度更新参数,无额外复杂策略。

1.1 原理
  • 全批量梯度下降(GD):使用全部训练数据计算梯度,梯度准确但计算量大(适用于小数据集);
  • 随机梯度下降(SGD):使用单个样本计算梯度,计算快但梯度波动大(易震荡);
  • 小批量SGD(Mini-batch SGD):使用一小批样本(如32、64、128)计算梯度,平衡计算效率和梯度稳定性(实际训练中最常用,下文简称“SGD”)。
1.2 核心公式

参数更新规则仅依赖当前批次的梯度 ∇ L ( θ t ) \nabla L(\theta_t) L(θt)
θ t + 1 = θ t − η ⋅ ∇ L ( θ t ) \theta_{t+1} = \theta_t - \eta \cdot \nabla L(\theta_t) θt+1=θtηL(θt)

1.3 优缺点
  • 优点:实现简单、内存占用低、泛化能力较强(震荡可能跳出局部最优);
  • 缺点:收敛速度慢(梯度方向波动大)、学习率难以选择(固定学习率可能导致后期不收敛或更新幅度过小)。
1.4 可运行代码(PyTorch)
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

# 1. 构造模拟数据(输入维度10,输出维度2,样本数1000)
X = torch.randn(1000, 10)  # 输入特征
y = torch.randint(0, 2, (1000,))  # 标签(二分类)
dataset = TensorDataset(X, y)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)  # 小批量加载

# 2. 定义简单模型(全连接网络)
class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.fc1 = nn.Linear(10, 20)  # 输入层→隐藏层
        self.fc2 = nn.Linear(20, 2)   # 隐藏层→输出层

    def forward(self, x):
        x = torch.relu(self.fc1(x))  # ReLU激活函数
        x = self.fc2(x)
        return x

model = SimpleModel()

# 3. 定义损失函数和优化器(SGD)
criterion = nn.CrossEntropyLoss()  # 交叉熵损失(适用于分类)
optimizer = optim.SGD(model.parameters(), lr=0.01)  # 学习率η=0.01

# 4. 模型训练(迭代10个epoch)
num_epochs = 10
for epoch in range(num_epochs):
    model.train()  # 训练模式
    total_loss = 0.0
    for batch_X, batch_y in dataloader:
        # 前向传播:计算模型输出
        outputs = model(batch_X)
        # 计算损失
        loss = criterion(outputs, batch_y)
        # 反向传播:计算梯度
        optimizer.zero_grad()  # 清空上一轮梯度(避免累积)
        loss.backward()        # 计算损失对参数的梯度
        # 参数更新:执行SGD更新
        optimizer.step()
        # 累加损失
        total_loss += loss.item() * batch_X.size(0)
    # 计算每个epoch的平均损失
    avg_loss = total_loss / len(dataset)
    print(f"Epoch [{epoch+1}/{num_epochs}], Avg Loss: {avg_loss:.4f}")

2. 动量梯度下降(Momentum):解决SGD震荡问题

Momentum借鉴物理中的“动量”概念,通过累积历史梯度的指数移动平均(EMA) 来平滑梯度方向,减少震荡,加速收敛。

2.1 原理
  • 引入“动量项” v t v_t vt(velocity,速度),表示历史梯度的累积趋势;
  • 动量项通过衰减系数 γ \gamma γ(通常取0.9)控制历史信息的权重,当前梯度仅占小部分;
  • 最终参数更新方向由动量项决定,而非单一当前梯度,从而减少方向波动。
2.2 核心公式
  1. 计算当前动量项(累积历史梯度):
    v t = γ ⋅ v t − 1 + η ⋅ ∇ L ( θ t ) v_t = \gamma \cdot v_{t-1} + \eta \cdot \nabla L(\theta_t) vt=γvt1+ηL(θt)
  2. 更新参数(沿动量项方向移动):
    θ t + 1 = θ t − v t \theta_{t+1} = \theta_t - v_t θt+1=θtvt

其中:

  • v t − 1 v_{t-1} vt1:上一步的动量项(初始为0);
  • γ \gamma γ:动量衰减系数(典型值0.9,控制历史梯度的影响程度)。
2.3 优缺点
  • 优点:减少SGD的震荡,加速收敛(尤其在损失函数的“狭长峡谷”区域);
  • 缺点:动量项可能导致“过冲”(即参数越过最优值),且学习率仍需手动调整。
2.4 可运行代码(PyTorch)

仅需修改优化器定义部分,其余代码与SGD一致:

# 定义Momentum优化器(γ=0.9为默认值,可显式指定)
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

# 后续训练代码与SGD完全相同(略)

3. 自适应梯度(Adagrad):动态调整学习率

Adagrad针对不同参数单独调整学习率:频繁更新的参数(如高频特征的权重)使用较小的学习率,稀疏更新的参数(如低频特征的权重)使用较大的学习率,适用于稀疏数据(如NLP、推荐系统)。

3.1 原理
  • 引入“梯度累积平方项” G t G_t Gt,记录每个参数从训练开始到当前的梯度平方和;
  • 学习率通过 1 / G t + ϵ 1/\sqrt{G_t + \epsilon} 1/Gt+ϵ 动态调整( ϵ \epsilon ϵ 为极小值,避免分母为0);
  • 核心逻辑:参数的梯度越大(更新越频繁),学习率衰减越快。
3.2 核心公式
  1. 累积当前参数的梯度平方(按元素平方和累积):
    G t = G t − 1 + ∇ L ( θ t ) ⊙ ∇ L ( θ t ) G_t = G_{t-1} + \nabla L(\theta_t) \odot \nabla L(\theta_t) Gt=Gt1+L(θt)L(θt)
    ⊙ \odot 表示按元素乘法)
  2. 动态调整学习率并更新参数:
    θ t + 1 = θ t − η G t + ϵ ⋅ ∇ L ( θ t ) \theta_{t+1} = \theta_t - \frac{\eta}{\sqrt{G_t + \epsilon}} \cdot \nabla L(\theta_t) θt+1=θtGt+ϵ ηL(θt)

其中:

  • G t − 1 G_{t-1} Gt1:上一步的梯度平方累积项(初始为0);
  • ϵ \epsilon ϵ:数值稳定性项(典型值 1 0 − 8 10^{-8} 108,避免分母为0或过小);
  • η \eta η:全局学习率(Adagrad中通常取0.01,无需手动微调)。
3.3 优缺点
  • 优点:无需手动调整学习率,对稀疏数据友好;
  • 缺点:梯度平方项 G t G_t Gt 持续累积,导致学习率逐渐趋近于0,训练后期可能停止收敛。
3.4 可运行代码(PyTorch)
# 定义Adagrad优化器(η=0.01为默认值,ε=1e-10为默认值)
optimizer = optim.Adagrad(model.parameters(), lr=0.01, eps=1e-10)

# 后续训练代码与SGD完全相同(略)

4. 自适应动量估计(Adam):当前最常用的优化器

Adam(Adaptive Moment Estimation)结合了Momentum的动量项Adagrad的自适应学习率,同时解决了SGD震荡、Adagrad学习率衰减过快的问题,在图像、NLP等多数任务中表现最优,是当前默认选择。

4.1 原理
  • 维护两个状态变量:
    1. 一阶矩(动量项) m t m_t mt:梯度的指数移动平均(类似Momentum,平滑梯度方向);
    2. 二阶矩(梯度平方项) v t v_t vt:梯度平方的指数移动平均(类似Adagrad,动态调整学习率);
  • 对两个矩进行偏差修正(初始阶段矩的估计偏差较大,修正后更准确)。
4.2 核心公式
  1. 计算一阶矩(动量项,衰减系数 β 1 \beta_1 β1 通常取0.9):
    m t = β 1 ⋅ m t − 1 + ( 1 − β 1 ) ⋅ ∇ L ( θ t ) m_t = \beta_1 \cdot m_{t-1} + (1 - \beta_1) \cdot \nabla L(\theta_t) mt=β1mt1+(1β1)L(θt)
  2. 计算二阶矩(梯度平方项,衰减系数 β 2 \beta_2 β2 通常取0.999):
    v t = β 2 ⋅ v t − 1 + ( 1 − β 2 ) ⋅ ∇ L ( θ t ) ⊙ ∇ L ( θ t ) v_t = \beta_2 \cdot v_{t-1} + (1 - \beta_2) \cdot \nabla L(\theta_t) \odot \nabla L(\theta_t) vt=β2vt1+(1β2)L(θt)L(θt)
  3. 偏差修正(解决初始阶段矩估计偏小的问题):
    m ^ t = m t 1 − β 1 t \hat{m}_t = \frac{m_t}{1 - \beta_1^t} m^t=1β1tmt
    v ^ t = v t 1 − β 2 t \hat{v}_t = \frac{v_t}{1 - \beta_2^t} v^t=1β2tvt
  4. 自适应更新参数:
    θ t + 1 = θ t − η v ^ t + ϵ ⋅ m ^ t \theta_{t+1} = \theta_t - \frac{\eta}{\sqrt{\hat{v}_t} + \epsilon} \cdot \hat{m}_t θt+1=θtv^t +ϵηm^t

其中:

  • β 1 , β 2 \beta_1, \beta_2 β1,β2:矩的衰减系数(默认0.9、0.999,几乎无需调整);
  • ϵ \epsilon ϵ:数值稳定性项(默认 1 0 − 8 10^{-8} 108);
  • η \eta η:全局学习率(默认0.001,多数任务无需微调)。
4.3 优缺点
  • 优点:收敛速度快、稳定性强、无需手动调整大量超参数、适用场景广(图像分类、目标检测、NLP等);
  • 缺点:在极少数极端任务(如生成模型的某些场景)中,可能不如专门优化的优化器(如AdamW),但通用性最优。
4.4 可运行代码(PyTorch)
# 定义Adam优化器(默认参数:lr=0.001, betas=(0.9, 0.999), eps=1e-08)
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 后续训练代码与SGD完全相同(略)

5. AdamW:Adam的改进版(解决权重衰减问题)

AdamW是Adam的优化版,核心改进是将“权重衰减(Weight Decay)”与梯度更新解耦,避免Adam原有的权重衰减效果被自适应学习率削弱,在需要正则化的任务(如深度学习分类、回归)中表现更优。

5.1 原理
  • Adam原有的权重衰减是“在梯度更新后叠加衰减”,而AdamW是“先对权重进行衰减,再执行梯度更新”;
  • 权重衰减本质是L2正则化,用于防止模型过拟合,AdamW确保衰减效果不依赖于梯度大小,更稳定。
5.2 核心公式

在Adam的参数更新前,先对参数进行衰减:

  1. 权重衰减( λ \lambda λ 为权重衰减系数,典型值 1 0 − 4 10^{-4} 104):
    θ t decay = θ t ⋅ ( 1 − η ⋅ λ ) \theta_t^{\text{decay}} = \theta_t \cdot (1 - \eta \cdot \lambda) θtdecay=θt(1ηλ)
  2. 后续步骤与Adam完全一致(使用 θ t decay \theta_t^{\text{decay}} θtdecay 替代原 θ t \theta_t θt 进行梯度更新):
    θ t + 1 = θ t decay − η v ^ t + ϵ ⋅ m ^ t \theta_{t+1} = \theta_t^{\text{decay}} - \frac{\eta}{\sqrt{\hat{v}_t} + \epsilon} \cdot \hat{m}_t θt+1=θtdecayv^t +ϵηm^t
5.3 优缺点
  • 优点:继承Adam的所有优点,同时增强权重衰减的正则化效果,有效缓解过拟合;
  • 缺点:需额外调整权重衰减系数 λ \lambda λ(但通常取 1 0 − 4 10^{-4} 104 即可)。
5.4 可运行代码(PyTorch)
# 定义AdamW优化器(权重衰减系数weight_decay=1e-4为常用值)
optimizer = optim.AdamW(model.parameters(), lr=0.001, weight_decay=1e-4)

# 后续训练代码与SGD完全相同(略)

三、优化器选择与超参数调优建议

优化器 适用场景 核心超参数 优点 缺点
SGD 小数据集、需强泛化能力 lr(0.001-0.1) 简单、泛化好 收敛慢、震荡
Momentum 需加速SGD收敛的场景 lr、momentum(0.9) 减少震荡、收敛快 可能过冲
Adagrad 稀疏数据(NLP、推荐) lr(0.01) 自适应学习率、无需微调 后期学习率趋近0
Adam 多数通用场景(默认选择) lr(0.001) 收敛快、稳定、通用性强 极端场景正则化弱
AdamW 需强正则化的场景(防过拟合) lr、weight_decay(1e-4) 继承Adam优点,增强正则化 需调整权重衰减系数

调优建议

  1. 优先选择AdamW:在图像、NLP等多数任务中,AdamW的综合表现最优,默认参数(lr=0.001,weight_decay=1e-4)可覆盖80%以上场景;
  2. 学习率调整:若训练发散(损失爆炸),可降低学习率(如0.0001);若收敛慢,可适当提高(如0.005);
  3. 批量大小匹配:批量大小(batch_size)增大时,可适当提高学习率(如batch_size从32→64,lr从0.001→0.002);
  4. 后期微调:若模型过拟合,可增大weight_decay(如1e-3);若欠拟合,可减小(如1e-5)。

四、完整对比实验代码

以下代码对比SGD、Momentum、Adagrad、Adam、AdamW在同一任务上的收敛效果:

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
import matplotlib.pyplot as plt
import numpy as np
from tqdm import tqdm  # 用于显示进度条

# 设置随机种子以确保实验可重复性
torch.manual_seed(42)
np.random.seed(42)

# 1. 生成复杂的训练数据
def create_training_data(samples=5000, features=30, classes=2):
    """创建具有非线性关系的复杂数据集,使优化器差异更明显"""
    # 生成基础特征
    X = torch.randn(samples, features)
    
    # 添加非线性特征交互
    X[:, :5] = torch.sin(X[:, :5] * 3.14)  # 正弦函数非线性
    X[:, 5:10] = torch.exp(X[:, 5:10] * 0.3)  # 指数函数非线性
    X[:, 10:15] = X[:, 10:15] ** 3  # 立方非线性
    X[:, 15:20] = torch.tanh(X[:, 15:20] * 2)  # tanh非线性
    X[:, 20:25] = X[:, 20:25] * torch.exp(X[:, 25:30])  # 特征交互
    
    # 生成标签(通过一个隐藏的决策边界)
    weights = torch.randn(features, classes)
    biases = torch.randn(classes)
    logits = X @ weights + biases + torch.randn(samples, classes) * 0.5  # 添加噪声
    y = torch.argmax(logits, dim=1)
    
    return X, y

# 生成训练和验证数据
X_train, y_train = create_training_data(samples=5000)
X_val, y_val = create_training_data(samples=1000)

# 创建数据加载器
train_dataset = TensorDataset(X_train, y_train)
val_dataset = TensorDataset(X_val, y_val)
train_loader = DataLoader(train_dataset, batch_size=128, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=128, shuffle=False)

# 2. 定义统一的神经网络模型
class ComparisonModel(nn.Module):
    def __init__(self, input_dim=30, hidden_dim=128, output_dim=2):
        super(ComparisonModel, self).__init__()
        self.network = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.BatchNorm1d(hidden_dim),
            nn.ReLU(),
            nn.Dropout(0.3),
            
            nn.Linear(hidden_dim, hidden_dim//2),
            nn.BatchNorm1d(hidden_dim//2),
            nn.ReLU(),
            nn.Dropout(0.2),
            
            nn.Linear(hidden_dim//2, hidden_dim//4),
            nn.BatchNorm1d(hidden_dim//4),
            nn.ReLU(),
            
            nn.Linear(hidden_dim//4, output_dim)
        )
        
    def forward(self, x):
        return self.network(x)

# 3. 定义评估函数
def evaluate(model, dataloader, criterion):
    """在指定数据集上评估模型性能"""
    model.eval()
    total_loss = 0.0
    correct = 0
    total = 0
    
    with torch.no_grad():  # 关闭梯度计算,节省内存和计算资源
        for inputs, labels in dataloader:
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            
            total_loss += loss.item() * inputs.size(0)
            _, predicted = torch.max(outputs.data, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()
    
    avg_loss = total_loss / total
    accuracy = correct / total * 100
    return avg_loss, accuracy

# 4. 定义训练函数
def train_optimizer(optimizer_name, optimizer, epochs=50):
    """使用指定优化器训练模型并记录训练过程"""
    # 为每个优化器创建独立模型,确保公平比较
    model = ComparisonModel()
    criterion = nn.CrossEntropyLoss()
    
    # 记录训练过程的指标
    history = {
        'train_loss': [], 'train_acc': [],
        'val_loss': [], 'val_acc': []
    }
    
    # 进度条
    progress_bar = tqdm(range(epochs), desc=f"训练 {optimizer_name}")
    
    for epoch in progress_bar:
        # 训练阶段
        model.train()
        train_running_loss = 0.0
        train_correct = 0
        train_total = 0
        
        for inputs, labels in train_loader:
            # 前向传播
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            
            # 反向传播和优化
            optimizer.zero_grad()  # 清零梯度
            loss.backward()        # 反向传播计算梯度
            optimizer.step()       # 更新参数
            
            # 记录训练指标
            train_running_loss += loss.item() * inputs.size(0)
            _, predicted = torch.max(outputs.data, 1)
            train_total += labels.size(0)
            train_correct += (predicted == labels).sum().item()
        
        # 计算训练集指标
        train_avg_loss = train_running_loss / train_total
        train_accuracy = train_correct / train_total * 100
        
        # 在验证集上评估
        val_avg_loss, val_accuracy = evaluate(model, val_loader, criterion)
        
        # 保存指标
        history['train_loss'].append(train_avg_loss)
        history['train_acc'].append(train_accuracy)
        history['val_loss'].append(val_avg_loss)
        history['val_acc'].append(val_accuracy)
        
        # 更新进度条
        progress_bar.set_postfix({
            'Train Loss': f'{train_avg_loss:.4f}',
            'Val Acc': f'{val_accuracy:.2f}%'
        })
    
    return history

# 5. 定义要比较的优化器
def get_optimizers():
    """创建所有要比较的优化器实例"""
    base_model = ComparisonModel()
    
    optimizers = {
        # SGD优化器
        'SGD': optim.SGD(
            base_model.parameters(),
            lr=0.01,           # 学习率
            weight_decay=1e-4  # 权重衰减(L2正则化)
        ),
        # 带动量的SGD
        'Momentum': optim.SGD(
            base_model.parameters(),
            lr=0.01,
            momentum=0.9,      # 动量系数
            weight_decay=1e-4
        ),
        # Adagrad优化器
        'Adagrad': optim.Adagrad(
            base_model.parameters(),
            lr=0.01,
            weight_decay=1e-4,
            eps=1e-8           # 数值稳定性参数
        ),
        # Adam优化器
        'Adam': optim.Adam(
            base_model.parameters(),
            lr=0.001,          # Adam通常使用较小的学习率
            betas=(0.9, 0.999),# 动量参数
            weight_decay=1e-4,
            eps=1e-8
        ),
        # AdamW优化器
        'AdamW': optim.AdamW(
            base_model.parameters(),
            lr=0.001,
            betas=(0.9, 0.999),
            weight_decay=1e-4,  # AdamW中该参数效果更明显
            eps=1e-8
        )
    }
    return optimizers

# 6. 运行对比实验
if __name__ == "__main__":
    # 获取所有优化器
    optimizers = get_optimizers()
    
    # 训练所有优化器并记录结果
    results = {}
    num_epochs = 50
    print(f"开始优化器对比实验,共训练 {num_epochs} 个 epoch...\n")
    
    for name, optimizer in optimizers.items():
        results[name] = train_optimizer(name, optimizer, num_epochs)
    
    # 7. 可视化实验结果
    plt.figure(figsize=(16, 12))
    
    # 绘制训练损失曲线
    plt.subplot(2, 2, 1)
    for name, history in results.items():
        plt.plot(range(1, num_epochs+1), history['train_loss'], label=name, linewidth=2)
    plt.title('训练损失对比', fontsize=14)
    plt.xlabel('Epoch', fontsize=12)
    plt.ylabel('损失值', fontsize=12)
    plt.grid(alpha=0.3)
    plt.legend()
    
    # 绘制验证损失曲线
    plt.subplot(2, 2, 2)
    for name, history in results.items():
        plt.plot(range(1, num_epochs+1), history['val_loss'], label=name, linewidth=2)
    plt.title('验证损失对比', fontsize=14)
    plt.xlabel('Epoch', fontsize=12)
    plt.ylabel('损失值', fontsize=12)
    plt.grid(alpha=0.3)
    plt.legend()
    
    # 绘制训练准确率曲线
    plt.subplot(2, 2, 3)
    for name, history in results.items():
        plt.plot(range(1, num_epochs+1), history['train_acc'], label=name, linewidth=2)
    plt.title('训练准确率对比', fontsize=14)
    plt.xlabel('Epoch', fontsize=12)
    plt.ylabel('准确率 (%)', fontsize=12)
    plt.grid(alpha=0.3)
    plt.legend()
    
    # 绘制验证准确率曲线
    plt.subplot(2, 2, 4)
    for name, history in results.items():
        plt.plot(range(1, num_epochs+1), history['val_acc'], label=name, linewidth=2)
    plt.title('验证准确率对比', fontsize=14)
    plt.xlabel('Epoch', fontsize=12)
    plt.ylabel('准确率 (%)', fontsize=12)
    plt.grid(alpha=0.3)
    plt.legend()
    
    plt.tight_layout()
    plt.savefig('optimizer_comparison.png', dpi=300, bbox_inches='tight')
    plt.show()
    
    # 8. 输出最终结果统计
    print("\n" + "="*60)
    print(f"{'优化器':<10} | {'最终训练损失':<15} | {'最终验证损失':<15} | {'最终验证准确率':<15}")
    print("-"*60)
    for name, history in results.items():
        final_train_loss = history['train_loss'][-1]
        final_val_loss = history['val_loss'][-1]
        final_val_acc = history['val_acc'][-1]
        print(f"{name:<10} | {final_train_loss:.6f}         | {final_val_loss:.6f}         | {final_val_acc:.2f}%")
    print("="*60)
    

这个对比实验代码包含以下关键部分:

  1. 数据生成模块:创建了具有多种非线性关系的复杂数据集,包括正弦函数、指数函数、立方函数等变换,使优化器的性能差异更加明显。

  2. 模型定义:使用包含批归一化和dropout层的神经网络,增加模型复杂度,同时防止过拟合,使优化过程更具挑战性。

  3. 完整训练流程

    • 分离训练集和验证集,全面评估模型性能
    • 记录训练损失、训练准确率、验证损失和验证准确率四个关键指标
    • 使用进度条可视化训练过程
      训练进度
  4. 五种优化器对比

    • SGD:基础随机梯度下降
    • Momentum:带动量的SGD
    • Adagrad:自适应学习率优化器
    • Adam:结合动量和自适应学习率
    • AdamW:Adam的改进版,优化权重衰减
  5. 结果可视化:通过四个子图分别展示训练损失、验证损失、训练准确率和验证准确率的对比曲线,并保存图像。
    结果可视化

  6. 结果统计:以表格形式输出各优化器的最终性能指标(简单的demo)效果可能不好,便于定量比较。
    运行结果

预期实验结论

运行此代码后,您将观察到:

  • 收敛速度:Adam和AdamW通常最快达到稳定状态,其次是Momentum,然后是Adagrad,SGD最慢。
  • 最终性能:AdamW通常能获得最高的验证准确率,且过拟合现象最轻;Adam紧随其后;Momentum和SGD需要更多迭代才能接近前两者的性能;Adagrad可能在后期收敛停滞。
  • 稳定性:Adam和AdamW的损失和准确率曲线最平滑,SGD和Momentum波动较大。

这些结果验证了AdamW作为当前深度学习任务中默认优化器的合理性,它在收敛速度、最终性能和稳定性之间取得了最佳平衡。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐