在 PyTorch 训练中,当样本总数不能被 Batch Size 整除时,代码的处理方式需要特别注意
在 PyTorch 训练中,当样本总数不能被 Batch Size 整除时,代码的处理方式需要特别注意。以你的问题为例,假设
train_sample=50,batch_size=20,我们来详细分析:1. 整除与非整除的计算逻辑
当
train_sample=50,batch_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)划分批次,会导致:- 数据浪费:最后一批样本(如 50-40=10 个)被忽略,无法参与训练。
- 训练不充分:模型无法学习到这部分样本的规律,可能导致准确率下降。
- 样本分布偏差:如果最后一批样本的正负样本比例与前几批不同,会破坏数据分布的均衡性。
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管理数据加载,避免手动划分批次带来的隐患。

浙公网安备 33010602011771号