当前位置: 首页 > news >正文

从 SGD 到梯度累积:Epoch、Batch、Step 的关系全解析

本文将简单介绍一些深度学习中的基本概念:
Epoch、Batch、Step 三者之间的关系
SGD、BGD、MBGD 方法的区别
梯度累积的使用和…

Epoch、Batch、Step 三者之间的关系

概念定义公式
Epoch整个训练集完整遍历一次-
Batch一小组样本,用于一次参数更新前的前/后向传播Number of Batches per Epoch=⌈NB⌉\text{Number of Batches per Epoch} = \left\lceil \frac{N}{B} \right\rceilNumber of Batches per Epoch=BN
Step一次完整的参数更新过程(前向+反向传播+更新参数)Total Steps=⌈NB⌉×E\text{Total Steps} = \left\lceil \frac{N}{B} \right\rceil \times ETotal Steps=BN×E

举例说明

假设:

  • 数据集大小 N=10,000N = 10,000N=10,000
  • batch size B=32B = 32B=32
  • epoch 数 E=5E = 5E=5
  1. 计算 1 个 epoch 中的 batch 数量:

Number of Batches per Epoch=⌈10,00032⌉=⌈312.5⌉=313 \text{Number of Batches per Epoch} = \left\lceil \frac{10,000}{32} \right\rceil = \left\lceil 312.5 \right\rceil = 313 Number of Batches per Epoch=3210,000=312.5=313

  1. 计算总步数:

Total Steps=⌈10,00032⌉×5=313×5=1565 \text{Total Steps} = \left\lceil \frac{10,000}{32} \right\rceil \times 5 = 313 \times 5 = 1565 Total Steps=3210,000×5=313×5=1565

图示(以前 2 个 epoch 为例):

Epoch 1└── Batch 1 → Step 1  (前向+反向传播+更新参数)└── Batch 2 → Step 2└── Batch 3 → Step 3└── ... └── Batch 313 → Step 313Epoch 2└── Batch 1 → Step 314└── Batch 2 → Step 315└── Batch 3 → Step 316└── ... └── Batch 313 → Step 626
  • 每个 epoch 包含多个 batch,每个 batch 对应 1 次参数更新(即 1 个 step)。
  • 我们可以用 epochs 控制训练回合数或用 max_steps 控制训练总 step 数(AI 画图的 UI 界面中常出现这个超参数选项)。
    我们来实现了一个基础的PyTorch二分类神经网络训练流程来进一步学习
代码示例
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
def same_seeds(seed=42):torch.manual_seed(seed)if torch.cuda.is_available():torch.cuda.manual_seed_all(seed)
# 设置随机种子
same_seeds()
# 数据集参数
N = 10000  # 数据集总样本数
B = 32     # batch_size
E = 5      # epochs# 创建一个示例数据集
X = torch.randn(N, 10)        # 生成服从标准正态分布(均值为0,方差为1)的随机数数列N*10
y = torch.randint(0, 2, (N,)) # 二分类标签  如果N=5,可能会得到类似这样的结果: tensor([0, 1, 1, 0, 1])
# 这里的 X 和 y 都是 torch.tensor 类型# 定义数据集和 DataLoader
dataset = TensorDataset(X, y)
dataloader = DataLoader(dataset, batch_size=B, shuffle=True, drop_last=False)# 定义模型
model = nn.Sequential(nn.Linear(10, 50),nn.ReLU(),nn.Linear(50, 2)
)# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)# 训练模型
steps_per_epoch = len(dataloader)   # 一个 epoch 内 batch 的数量
total_steps = steps_per_epoch * Edevice = "cuda" if torch.cuda.is_available() else "cpu"
# 这里设置 device 为 cuda,如果没有 cuda 设备,则使用 cpu
model.to(device)
# 记录最佳损失
best_loss = float('inf')
# 记录当前 step
current_step = 0# 这里设置成从 1 开始只是为了不在 print 中额外设置,实际写代码的时候不需要纠结这一点
for epoch in range(1, E + 1):for batch_idx, (inputs, targets) in enumerate(dataloader, start=1): inputs = inputs.to(device)targets = targets.to(device)# 清零梯度(这一步放在反向传播前和参数更新之后都可以)optimizer.zero_grad()# 前向传播outputs = model(inputs)# 计算损失loss = criterion(outputs, targets)# 反向传播(计算梯度)loss.backward()# 更新参数optimizer.step()best_loss = min(best_loss, loss.item())current_step += 1# 每 50 步打印一次if batch_idx % 50 == 0:# 如果不需要打印累积 step,可以去除 current_step 项直接使用 batch_idxprint(f"Epoch [{epoch}/{E}], Batch [{batch_idx}/{steps_per_epoch}], "f"Step [{current_step}/{total_steps}], Loss: {loss.item():.4f}")# 参数更新
print(best_loss)
# 可以看到:
# - epoch 从 1 到 E
# - batch 从 1 到 steps_per_epoch
# - step 累计从 1 到 total_steps

输出

Epoch [1/5], Batch [50/313], Step [50/1565], Loss: 0.6813
Epoch [1/5], Batch [100/313], Step [100/1565], Loss: 0.6892
Epoch [1/5], Batch [150/313], Step [150/1565], Loss: 0.7314
Epoch [1/5], Batch [200/313], Step [200/1565], Loss: 0.7105
Epoch [1/5], Batch [250/313], Step [250/1565], Loss: 0.6966
Epoch [1/5], Batch [300/313], Step [300/1565], Loss: 0.6974
Epoch [2/5], Batch [50/313], Step [363/1565], Loss: 0.6866
Epoch [2/5], Batch [100/313], Step [413/1565], Loss: 0.6960
Epoch [2/5], Batch [150/313], Step [463/1565], Loss: 0.7177
Epoch [2/5], Batch [200/313], Step [513/1565], Loss: 0.7086
Epoch [2/5], Batch [250/313], Step [563/1565], Loss: 0.7078
Epoch [2/5], Batch [300/313], Step [613/1565], Loss: 0.6947
Epoch [3/5], Batch [50/313], Step [676/1565], Loss: 0.6869
Epoch [3/5], Batch [100/313], Step [726/1565], Loss: 0.7031
Epoch [3/5], Batch [150/313], Step [776/1565], Loss: 0.6880
Epoch [3/5], Batch [200/313], Step [826/1565], Loss: 0.7015
Epoch [3/5], Batch [250/313], Step [876/1565], Loss: 0.6961
Epoch [3/5], Batch [300/313], Step [926/1565], Loss: 0.6881
Epoch [4/5], Batch [50/313], Step [989/1565], Loss: 0.7042
Epoch [4/5], Batch [100/313], Step [1039/1565], Loss: 0.6856
Epoch [4/5], Batch [150/313], Step [1089/1565], Loss: 0.6768
Epoch [4/5], Batch [200/313], Step [1139/1565], Loss: 0.6967
Epoch [4/5], Batch [250/313], Step [1189/1565], Loss: 0.6800
Epoch [4/5], Batch [300/313], Step [1239/1565], Loss: 0.6909
Epoch [5/5], Batch [50/313], Step [1302/1565], Loss: 0.6770
...
Epoch [5/5], Batch [200/313], Step [1452/1565], Loss: 0.6987
Epoch [5/5], Batch [250/313], Step [1502/1565], Loss: 0.6860
Epoch [5/5], Batch [300/313], Step [1552/1565], Loss: 0.7003
0.6238939762115479
...

最best 的loss is 0.6238939762115479
我们来不断的尝试降低loss

首先了解调度器

  1. 学习率调度器(Scheduler)

    常见的学习率更新方式有两种:

    • 以 step 为基础:在每个 step 结束后更新学习率。

      scheduler = ...for epoch in range(E):for batch_idx, (inputs, targets) in enumerate(dataloader):# 前向、后向、更新参数...# 在每个 step 后更新学习率scheduler.step()
      
    • 以 epoch 为基础:在每个 epoch 结束后更新学习率。

      scheduler = ...for epoch in range(E):for batch_idx, (inputs, targets) in enumerate(dataloader):# 前向、后向、更新参数...# 在每个 epoch 后更新学习率scheduler.step()
      

    我们的代码是以 step 为基础的scheduler.step()
    让我们试一试以 epoch 为基础

修改如下

        # 更新参数# optimizer.step()best_loss = min(best_loss, loss.item())current_step += 1# 每 50 步打印一次if batch_idx % 50 == 0:# 如果不需要打印累积 step,可以去除 current_step 项直接使用 batch_idxprint(f"Epoch [{epoch}/{E}], Batch [{batch_idx}/{steps_per_epoch}], "f"Step [{current_step}/{total_steps}], Loss: {loss.item():.4f}")optimizer.step()
print(best_loss)

此时best loss is 0.5978379249572754
效果更好了,为什么?
在深度学习中,以 step 和以 epoch 为基础更新学习率的主要区别体现在更新频率、数据覆盖度和实际应用场景上。以下是具体对比:


更新频率不同

  • Step-based

    • 每次迭代(batch)后更新:学习率在每个 step(即单个 batch 训练完成后)调整一次。
    • 更频繁:若数据集有 N 个样本,batch size 为 B,则每 epoch 包含 N/B 次更新。
    • 适用场景:适合动态调整(如损失波动大时需快速响应)或大数据集(epoch 耗时过长)。
  • Epoch-based

    • 每轮完整遍历数据后更新:学习率在每个 epoch 结束后调整一次。
    • 更稳定:适用于对噪声敏感的任务(如小数据集或需要稳定下降的场景)。

典型应用场景

  • Step-based 的常见用途

    • 学习率预热(Warmup):如 BERT 训练中,前几千个 step 线性增加学习率,避免初期梯度爆炸。
    • 大模型/大数据集:当 1 个 epoch 包含百万级 step 时(如 GPT-3),按 step 调整更高效。
    • 动态调度器:如 OneCycleLR 按 step 精细控制学习率变化周期。
  • Epoch-based 的常见用途

    • 简单衰减策略:如每 5 个 epoch 学习率乘以 0.1(经典 ResNet 训练)。
    • 依赖验证指标时:如根据 epoch 结束时的验证准确率决定是否调整。
    • 小数据集:epoch 耗时短,按 epoch 调整更易实现。

选择建议

  • 优先 Step-based:当数据量大、需要高频调整或使用 warmup 时。
  • 优先 Epoch-based:当训练稳定性和可解释性更重要(如学术实验复现)。
  • 混合策略:某些调度器(如 CosineAnnealingLR)可同时支持两种模式,需根据任务需求选择。

总之,两者的核心差异在于 更新的时间粒度,选择时需权衡调整频率与训练稳定性。实际应用中,step-based 更常见于现代大规模训练,而 epoch-based 多用于传统小规模任务。
因为是小规模,所以我们的模型loss更低了
接下来我们添加早停机制,因为我们可以观察训练过程发现模型在某个epoch就达到了best loss,但还在训练导致了过拟合

早停(Early Stopping)

可以基于 epoch 或 step 来监控验证集性能,若在一定 patience(耐心值)内验证性能没有提高,则提前停止训练来避免过拟合。

首先把训练函数封装成一个train_one_epoch函数

具体完整代码

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
def same_seeds(seed=42):torch.manual_seed(seed)if torch.cuda.is_available():torch.cuda.manual_seed_all(seed)
# 设置随机种子
same_seeds()
# 数据集参数
N = 10000  # 数据集总样本数
B = 32     # batch_size
E = 5      # epochs# 创建一个示例数据集
X = torch.randn(N, 10)        # 生成服从标准正态分布(均值为0,方差为1)的随机数数列N*10
y = torch.randint(0, 2, (N,)) # 二分类标签  如果N=5,可能会得到类似这样的结果: tensor([0, 1, 1, 0, 1])
# 这里的 X 和 y 都是 torch.tensor 类型# 定义数据集和 DataLoader
dataset = TensorDataset(X, y)
dataloader = DataLoader(dataset, batch_size=B, shuffle=True, drop_last=False)# 定义模型
model = nn.Sequential(nn.Linear(10, 50),nn.ReLU(),nn.Linear(50, 2)
)# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)# 训练模型
steps_per_epoch = len(dataloader)   # 一个 epoch 内 batch 的数量
total_steps = steps_per_epoch * Edevice = "cuda" if torch.cuda.is_available() else "cpu"
# 这里设置 device 为 cuda,如果没有 cuda 设备,则使用 cpu
model.to(device)
# 记录最佳损失
best_loss = float('inf')
# 记录当前 step
current_step = 0
# 这里设置 patience=2,即如果连续 2 次没有提升,则提前结束训练
patience=5
origin_patience=patience
def train_one_epoch(model, dataloader,optimizer,criterion,current_step=0):epoch_best_loss=float('inf')for batch_idx, (inputs, targets) in enumerate(dataloader, start=1): inputs = inputs.to(device)targets = targets.to(device)# 清零梯度(这一步放在反向传播前和参数更新之后都可以)optimizer.zero_grad()# 前向传播outputs = model(inputs)# 计算损失loss = criterion(outputs, targets)# 反向传播(计算梯度)loss.backward()# 更新参数# optimizer.step()epoch_best_loss = min(epoch_best_loss, loss.item())current_step += 1# 每 50 步打印一次if batch_idx % 50 == 0:# 如果不需要打印累积 step,可以去除 current_step 项直接使用 batch_idxprint(f"Epoch [{epoch}/{E}], Batch [{batch_idx}/{steps_per_epoch}], "f"Step [{current_step}/{total_steps}], Loss: {loss.item():.4f}")optimizer.step()return epoch_best_loss# 这里设置成从 1 开始只是为了不在 print 中额外设置,实际写代码的时候不需要纠结这一点
for epoch in range(1, E + 1):current_loss=train_one_epoch(model, dataloader,optimizer,criterion,current_step=current_step)if current_loss<best_loss:best_loss=current_losspatience=origin_patience# 保存最佳模型参数print(f"Best model saved with loss {best_loss:.4f}")torch.save(model.state_dict(), "best_model.pth")else:patience-=1if patience==0:print(f"No improvement in validation for {epoch} epochs, stopping early.")breakprint(f'Training complete with best loss {best_loss:.6f}')
# 可以看到:
# - epoch 从 1 到 E
# - batch 从 1 到 steps_per_epoch
# - step 累计从 1 到 total_steps
# - 最佳模型保存了
Epoch [1/5], Batch [50/313], Step [50/1565], Loss: 0.6825
Epoch [1/5], Batch [100/313], Step [100/1565], Loss: 0.6923
Epoch [1/5], Batch [150/313], Step [150/1565], Loss: 0.7371
Epoch [1/5], Batch [200/313], Step [200/1565], Loss: 0.7104
Epoch [1/5], Batch [250/313], Step [250/1565], Loss: 0.6962
Epoch [1/5], Batch [300/313], Step [300/1565], Loss: 0.6859
Best model saved with loss 0.6125
Epoch [2/5], Batch [50/313], Step [50/1565], Loss: 0.7190
Epoch [2/5], Batch [100/313], Step [100/1565], Loss: 0.7225
Epoch [2/5], Batch [150/313], Step [150/1565], Loss: 0.7078
Epoch [2/5], Batch [200/313], Step [200/1565], Loss: 0.7102
Epoch [2/5], Batch [250/313], Step [250/1565], Loss: 0.6941
Epoch [2/5], Batch [300/313], Step [300/1565], Loss: 0.7258
Epoch [3/5], Batch [50/313], Step [50/1565], Loss: 0.7133
Epoch [3/5], Batch [100/313], Step [100/1565], Loss: 0.7375
Epoch [3/5], Batch [150/313], Step [150/1565], Loss: 0.6734
Epoch [3/5], Batch [200/313], Step [200/1565], Loss: 0.7107
Epoch [3/5], Batch [250/313], Step [250/1565], Loss: 0.7341
Epoch [3/5], Batch [300/313], Step [300/1565], Loss: 0.7034
Epoch [4/5], Batch [50/313], Step [50/1565], Loss: 0.7158
Epoch [4/5], Batch [100/313], Step [100/1565], Loss: 0.6138
Epoch [4/5], Batch [150/313], Step [150/1565], Loss: 0.6502
Epoch [4/5], Batch [200/313], Step [200/1565], Loss: 0.7071
Epoch [4/5], Batch [250/313], Step [250/1565], Loss: 0.7239
Epoch [4/5], Batch [300/313], Step [300/1565], Loss: 0.7386
...
Epoch [5/5], Batch [250/313], Step [250/1565], Loss: 0.6980
Epoch [5/5], Batch [300/313], Step [300/1565], Loss: 0.7369
Best model saved with loss 0.5978
Training complete with best loss 0.597838

没啥变化loss,我们可以增大epoch from 5 to 50
还是没任何变化

Training complete with best loss 0.597838

我们试一试增加batch size不过要注意

Batch Size 与显存

更大的 batch size 意味着每个 step 会处理更多数据,占用更多显存。当遇到 GPU 内存不足(Out of Memory,OOM)错误时,可以尝试减小 batch size,如果仍想达成大 batch size 的效果,使用梯度累积技巧(见下文)。

梯度累积(Gradient Accumulation)

当 GPU 显存不足以支持较大的 batch_size 时,可以使用梯度累积。梯度累积的核心思想是将多个小批量(mini-batch)的梯度累加起来,然后再更新参数,这样可以模拟更大的 batch_size。

代码示例
假设理想 batch_size = 32,但受显存限制只能一次处理 8 个样本(b=8),则需要累积 4 次(32/8=4)小批次的梯度后再更新参数:
梯度累积的基本步骤:
在每个小批次(batch_size=8)中,我们执行一次前向传播、一次反向传播,并将梯度累加到模型参数的 .grad 中。
当累计了 4 次(也就是相当于处理了 32 个样本后),我们执行 optimizer.step() 来更新参数,然后用 optimizer.zero_grad() 清空累积的梯度。
使用 accelerate 可以自动管理设备与梯度累积逻辑,先进行安装:

pip install accelerate

完整实现代码

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
from accelerate import Accelerator
def same_seeds(seed=42):torch.manual_seed(seed)if torch.cuda.is_available():torch.cuda.manual_seed_all(seed)
# 设置随机种子
same_seeds()
# 数据集参数
N = 10000  # 数据集总样本数
B = 32     # 理想batch_size
b = 8      # 实际 batch size
E = 50      # epochs
gradient_accumulation_steps = B // b  # 等于 4,可以手动设置
# gradient_accumulation_steps:梯度累积步数,这是一个重要的训练技巧。它允许你在较小的实际batch size下模拟较大的有效batch size。
accelerator=Accelerator(gradient_accumulation_steps=gradient_accumulation_steps)# 创建一个示例数据集
X = torch.randn(N, 10)        # 生成服从标准正态分布(均值为0,方差为1)的随机数数列N*10
y = torch.randint(0, 2, (N,)) # 二分类标签  如果N=5,可能会得到类似这样的结果: tensor([0, 1, 1, 0, 1])
# 这里的 X 和 y 都是 torch.tensor 类型# 定义数据集和 DataLoader
dataset = TensorDataset(X, y)
dataloader = DataLoader(dataset, batch_size=B, shuffle=True, drop_last=False)# 定义模型
model = nn.Sequential(nn.Linear(10, 50),nn.ReLU(),nn.Linear(50, 2)
)# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)# 将模型和优化器交给 Accelerator 管理
model, optimizer, dataloader = accelerator.prepare(model, optimizer, dataloader)# 训练模型
steps_per_epoch = len(dataloader)   # 一个 epoch 内 batch 的数量
total_steps = steps_per_epoch * Edevice = "cuda" if torch.cuda.is_available() else "cpu"
# 这里设置 device 为 cuda,如果没有 cuda 设备,则使用 cpu
model.to(device)
# 记录最佳损失
best_loss = float('inf')
# 记录当前 step
current_step = 0
# 这里设置 patience=2,即如果连续 2 次没有提升,则提前结束训练
patience=50
origin_patience=patience
def train_one_epoch(model, dataloader,optimizer,criterion,current_step=0):epoch_best_loss=float('inf')for batch_idx, (inputs, targets) in enumerate(dataloader, start=1): # with acceleratorwith accelerator.accumulate(model):inputs = inputs.to(device)targets = targets.to(device)# 清零梯度(这一步放在反向传播前和参数更新之后都可以)optimizer.zero_grad()# 前向传播outputs = model(inputs)# 计算损失loss = criterion(outputs, targets)# 反向传播(计算梯度)# loss.backward()# accelerator.backward(loss) 会自动把 loss 累积到当前的 batch 内,然后反向传播accelerator.backward(loss)# 更新参数# optimizer.step()epoch_best_loss = min(epoch_best_loss, loss.item())current_step += 1# 每 50 步打印一次if batch_idx % 50 == 0:# 如果不需要打印累积 step,可以去除 current_step 项直接使用 batch_idxprint(f"Epoch [{epoch}/{E}], Batch [{batch_idx}/{steps_per_epoch}], "f"Step [{current_step}/{total_steps}], Loss: {loss.item():.4f}")optimizer.step()return epoch_best_loss# 这里设置成从 1 开始只是为了不在 print 中额外设置,实际写代码的时候不需要纠结这一点
for epoch in range(1, E + 1):current_loss=train_one_epoch(model, dataloader,optimizer,criterion,current_step=current_step)if current_loss<best_loss:best_loss=current_losspatience=origin_patience# 保存最佳模型参数print(f"Best model saved with loss {best_loss:.4f}")torch.save(model.state_dict(), "best_model.pth")else:patience-=1if patience==0:print(f"No improvement in validation for {epoch} epochs, stopping early.")breakprint(f'Training complete with best loss {best_loss:.6f}')
# 可以看到:
# - epoch 从 1 到 E
# - batch 从 1 到 steps_per_epoch
# - step 累计从 1 到 total_steps
# - 最佳模型保存了

最后结果

Training complete with best loss 0.58797

使用了梯度累计实现了实际的batchsize=32和未实现但是batchsize=32相比Loss更低了

Q:使用了梯度累积后,step 和 batch 的对应关系有什么变化?

  • 无梯度累积时:1 个 batch 对应 1 次参数更新(1 step)。
  • 有梯度累积时:多个小批次(k 个 batch)累积后才更新一次参数,这时 k 个 batch 才对应 1 次 step。

也就是说,step 的频率降低了,但每次 step 的意义相当于在更大有效 batch_size 上进行一次更新。:

SGD、BGD、MBGD 之间的区别

SGD(随机梯度下降)、BGD(批量梯度下降)和MBGD(小批量梯度下降)是梯度下降算法的三种主要变体,核心区别在于每次迭代时使用的数据量不同,进而影响计算效率、收敛速度和稳定性。以下是具体对比:


1. BGD(批量梯度下降)

  • 数据使用:每次迭代使用全部训练数据计算梯度。
  • 特点
    • 稳定性高:梯度方向是全局最优方向,收敛平稳。
    • 计算开销大:尤其数据量大时,每次更新需遍历整个数据集。
    • 内存占用高:需同时加载所有数据。
  • 适用场景:小数据集或凸优化问题。

2. SGD(随机梯度下降)

  • 数据使用:每次迭代随机选取一个样本计算梯度。
  • 特点
    • 速度快:单样本计算,迭代频率高。
    • 波动大:梯度噪声多,可能无法收敛到最优解(但可能跳出局部最优)。
    • 泛化性好:适合在线学习(动态数据流)。
  • 适用场景:大数据集、非凸问题(如深度学习)。

3. MBGD(小批量梯度下降)

  • 数据使用:每次迭代使用小批量样本(如32、64个)计算梯度。
  • 特点
    • 平衡BGD和SGD:兼顾计算效率和稳定性。
    • 并行化友好:适合GPU加速(深度学习常用)。
    • 需调批量大小:批量过小则波动大,过大则接近BGD。
  • 适用场景:绝大多数深度学习任务。

对比总结

指标BGDSGDMBGD
梯度准确性高(全局最优)低(单样本噪声)中(小批量平均)
收敛速度慢(每步计算量大)快(但需更多迭代)中(平衡步长与迭代)
内存需求
收敛稳定性平滑波动大相对稳定
典型应用传统机器学习在线学习深度学习

选择建议

  • 数据量小 → 用BGD。
  • 数据量大或动态数据 → 用SGD或MBGD。
  • 深度学习默认MBGD(结合动量、Adam等优化器效果更佳)。

扩展

如果你还想进一步降低Loss但是没有好的方法,或者效果不好
,我只能说这是没有意义的
因为数据是随机生成的

X = torch.randn(N, 10)
y = torch.randint(0, 2, (N,))

X 是 高斯分布噪声
y 是 完全随机的 0/1 标签

这里 特征和标签之间没有任何关系!换句话说,模型是没法“学会规律”的,因为压根没有规律
当然你还是执着于的话可以这样设置

N = 10000  # 数据集总样本数
B = 1     # 理想batch_size
b = 1      # 实际 batch size
E = 50      # epochs
gradient_accumulation_steps = B // b  # 等于 4,可以手动设置
Epoch [1/50], Batch [50/10000], Step [50/500000], Loss: 0.8390
Epoch [1/50], Batch [100/10000], Step [100/500000], Loss: 0.6147
Epoch [1/50], Batch [150/10000], Step [150/500000], Loss: 0.5295
Epoch [1/50], Batch [200/10000], Step [200/500000], Loss: 0.6609
Epoch [1/50], Batch [250/10000], Step [250/500000], Loss: 0.4225
Epoch [1/50], Batch [300/10000], Step [300/500000], Loss: 1.0206
Epoch [1/50], Batch [350/10000], Step [350/500000], Loss: 0.8659
Epoch [1/50], Batch [400/10000], Step [400/500000], Loss: 0.5234
Epoch [1/50], Batch [450/10000], Step [450/500000], Loss: 0.8742
Epoch [1/50], Batch [500/10000], Step [500/500000], Loss: 0.8313
Epoch [1/50], Batch [550/10000], Step [550/500000], Loss: 0.5952
Epoch [1/50], Batch [600/10000], Step [600/500000], Loss: 0.7431
Epoch [1/50], Batch [650/10000], Step [650/500000], Loss: 0.5761
Epoch [1/50], Batch [700/10000], Step [700/500000], Loss: 0.6298
Epoch [1/50], Batch [750/10000], Step [750/500000], Loss: 0.6725
Epoch [1/50], Batch [800/10000], Step [800/500000], Loss: 0.5078
Epoch [1/50], Batch [850/10000], Step [850/500000], Loss: 0.8275
Epoch [1/50], Batch [900/10000], Step [900/500000], Loss: 0.5330
Epoch [1/50], Batch [950/10000], Step [950/500000], Loss: 0.8798
Epoch [1/50], Batch [1000/10000], Step [1000/500000], Loss: 0.8836
Epoch [1/50], Batch [1050/10000], Step [1050/500000], Loss: 0.5622
Epoch [1/50], Batch [1100/10000], Step [1100/500000], Loss: 0.5411
Epoch [1/50], Batch [1150/10000], Step [1150/500000], Loss: 0.7891
Epoch [1/50], Batch [1200/10000], Step [1200/500000], Loss: 0.7982
Epoch [1/50], Batch [1250/10000], Step [1250/500000], Loss: 0.4537
...
Epoch [19/50], Batch [9950/10000], Step [9950/500000], Loss: 0.5194
Epoch [19/50], Batch [10000/10000], Step [10000/500000], Loss: 1.6206
No improvement in validation for 19 epochs, stopping early.
Training complete with best loss 0.143794

最后best_loss:0.143794

http://www.lryc.cn/news/625433.html

相关文章:

  • 边缘智能体:Go编译在医疗IoT设备端运行轻量AI模型(上)
  • Ansible 角色管理指南
  • Ansible 角色管理
  • Apache IoTDB(4):深度解析时序数据库 IoTDB 在Kubernetes 集群中的部署与实践指南
  • Redisson 分布式锁核心机制解析
  • 2025年09月计算机二级MySQL选择题每日一练——第一期
  • 寻找旋转排序数组中的最小值
  • 【C语言强化训练16天】--从基础到进阶的蜕变之旅:Day7
  • web开发,在线%服装商城开发demo,基于html,css,jquery,asp.net,webform,sqlserver数据库
  • hadoop技术栈(九)Hbase替代方案
  • 20250819 强连通分量,边双总结
  • k8s运维实践:高可用Redis Cluster(三主三从)与Proxy部署方案
  • RadioIrqProcess函数详细分析与流程图
  • 【实时Linux实战系列】基于实时Linux的物联网系统设计
  • “道法术器” 思维:解析华为数字化转型
  • 企业知识管理革命:RAG系统在大型组织中的落地实践
  • 服务器如何隐藏端口才能不被扫描?
  • 08.19总结
  • 17.web api 8
  • C++ 默认参数深度解析【C++每日一学】
  • 0.开篇简介
  • 把 AI 天气预报塞进「打火机」——基于时空扩散模型的微型气象站
  • 项目管理.管理理念学习
  • 推理还是训练 || KV缓存和CoT技术
  • Orange的运维学习日记--46.Ansible进阶之LNMP部署最佳实践
  • 鱼骨图图片制作全指南:使用工具推荐 + 行业案例
  • 叉车结构设计cad+三维图+设计说明书
  • Matplotlib数据可视化实战:Matplotlib基础与实践-快速上手数据可视化
  • 主从切换是怎么保证数据一致的?从库为什么会延迟
  • Pandas数据处理与分析实战:Pandas数据处理与Matplotlib可视化入门