在 PyTorch 训练中,当样本总数不能被 Batch Size 整除时,代码的处理方式需要特别注意

在 PyTorch 训练中,当样本总数不能被 Batch Size 整除时,代码的处理方式需要特别注意。以你的问题为例,假设train_sample=50batch_size=20,我们来详细分析:

1. 整除与非整除的计算逻辑

train_sample=50batch_size=20时:

  • 总批次数 = train_sample // batch_size = 50 // 20 = 2(整数除法)。
  • 最后一批的样本数 = train_sample % batch_size = 50 % 20 = 10

代码中的处理方式:

python
 
运行
 
 
 
 
for batch_index in range(train_sample // batch_size):
    x = train_x[batch_index * batch_size : (batch_index + 1) * batch_size]
    y = train_y[batch_index * batch_size : (batch_index + 1) * batch_size]
    # 训练代码...
 

  • 该循环只会执行 2 次,处理前 40 个样本(2 批 ×20 样本),最后 10 个样本会被丢弃。

2. 非整除时的正确处理方式

上述代码在样本不能被整除时会丢失部分数据,这是不合理的。正确的做法是使用DataLoader自动处理批次划分,包括最后一个不完整的批次:

python
 
运行
 
 
 
 
from torch.utils.data import DataLoader, TensorDataset

# 创建数据集
dataset = TensorDataset(train_x, train_y)
# 创建DataLoader,自动处理批次和不完整批次
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)

for epoch in range(epoch_num):
    model.train()
    watch_loss = []
    for x, y in dataloader:  # 自动迭代所有批次
        loss = model(x, y)
        loss.backward()
        optim.step()
        optim.zero_grad()
        watch_loss.append(loss.item())
    # 后续代码...
 

DataLoader会自动处理:

  • 总批次数:对于 50 样本 + 20 Batch Size,会划分为 3 批(2 批 ×20 样本 + 1 批 ×10 样本)。
  • 最后一批:即使样本数不足batch_size,也会作为一个独立批次处理,不会丢失数据。

3. 原代码的问题与影响

你提供的代码中,手动通过range(train_sample // batch_size)划分批次,会导致:

  1. 数据浪费:最后一批样本(如 50-40=10 个)被忽略,无法参与训练。
  2. 训练不充分:模型无法学习到这部分样本的规律,可能导致准确率下降。
  3. 样本分布偏差:如果最后一批样本的正负样本比例与前几批不同,会破坏数据分布的均衡性。

4. 为什么DataLoader是更好的选择?

DataLoader除了自动处理不完整批次外,还提供了更多实用功能:

  • 数据打乱(shuffle):每次 epoch 重新打乱数据,避免模型按顺序记忆样本。
  • 并行加载(num_workers):利用多线程加速数据读取,尤其是处理图像、文本等复杂数据时。
  • 数据预处理:可搭配Dataset类自定义数据增强、格式转换等操作。

5. 修正后的完整代码示例

以下是使用DataLoader改进后的代码片段:

python
 
运行
 
 
 
 
def main():
    # 配置参数
    epoch_num = 10
    batch_size = 20
    train_sample = 50
    input_size = 5
    learning_rate = 0.001
    
    model = TorchModel(input_size)
    optim = torch.optim.Adam(model.parameters(), lr=learning_rate)
    
    # 创建训练集
    train_x, train_y = build_dataset(train_sample)
    # 使用DataLoader处理批次
    from torch.utils.data import DataLoader, TensorDataset
    dataset = TensorDataset(train_x, train_y)
    dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
    
    for epoch in range(epoch_num):
        model.train()
        watch_loss = []
        for x, y in dataloader:  # 自动遍历所有批次,包括不完整批次
            loss = model(x, y)
            loss.backward()
            optim.step()
            optim.zero_grad()
            watch_loss.append(loss.item())
        print(f"第{epoch+1}轮平均loss:{np.mean(watch_loss):.4f}")
        acc = evaluate(model)
        log.append([acc, np.mean(watch_loss)])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

总结

  • 原代码的问题:手动划分批次时,若样本数不能被 Batch Size 整除,会丢弃最后一批不完整数据,导致训练不充分。
  • 解决方案:使用 PyTorch 的DataLoader自动处理批次划分,确保所有样本都参与训练,同时获得数据打乱、并行加载等额外优势。
  • 最佳实践:在实际项目中,无论样本数是否能被整除,都应使用DataLoader管理数据加载,避免手动划分批次带来的隐患。
 
 
posted @ 2025-06-23 20:56  m516606428  阅读(154)  评论(0)    收藏  举报