训练神经网络时,特别是处理大型数据集时,一次性处理整个数据集来计算损失并更新权重,可能耗费大量计算资源和内存。此外,每次权重更新都使用整个数据集(如同传统批次梯度下降)可能会导致收敛速度减慢或停留在局部最优解。为解决此问题,训练过程通常会划分为更小、更易于管理的分步操作,采用批次和周期的思想。周期:完整的数据遍历一个周期表示对整个训练数据集的一次完整遍历。如果你的数据集包含10,000张图片,一个周期就是在模型恰好一次性看过并从中学习过这10,000张图片之后完成。训练深度学习模型通常需要多个周期。为什么呢?因为仅一次遍历很少能让模型的权重收敛到最佳值。网络需要多次查看数据,以便高效地掌握数据中蕴含的规律。这就像备考一样:你不会只看一遍课本;你会多次复习材料(多个周期)以巩固理解。周期数是你在训练开始前设定的一个超参数。选择合适的数量很重要:周期数过少: 模型可能出现欠拟合,意思是它没有充分学习数据中的规律。周期数过多: 模型可能出现过拟合,意思是它过度适应了训练数据,包括数据中的噪声,导致在新、未见过的数据上表现不佳。我们将在下一节讨论如何使用验证数据来检测过拟合。批次:分块处理数据在一个周期内,我们不一次性处理整个数据集,而是将数据集划分为更小的子集,称之为批次。批次大小决定了每个批次中包含多少个训练样本。在每个周期中,训练数据通常会被打乱顺序,然后分成这些批次。模型一次处理一个批次:将批次数据输入网络(前向传播)。根据该批次的预测结果计算损失。计算损失相对于模型权重的梯度(反向传播)。根据这些梯度,使用所选优化器更新模型权重。此过程在周期内对所有批次重复进行。模型每次处理一个批次并更新其权重时,称为一次迭代或步。例如,如果你有一个包含2,000个样本的数据集,并将批次大小设定为100,那么一个周期将包含: $$ \text{每个周期迭代次数} = \frac{\text{训练样本总数}}{\text{批次大小}} = \frac{2000}{100} = 20 \text{ 次迭代} $$在一个周期内,模型的权重将更新20次。digraph G { rankdir=LR; node [shape=box, style=filled, fillcolor="#e9ecef", fontname="sans-serif"]; edge [fontname="sans-serif"]; subgraph cluster_epoch { label = "周期 1"; bgcolor="#f8f9fa"; Dataset [label="训练数据集 (N个样本)", shape=cylinder, fillcolor="#a5d8ff"]; Batch1 [label="批次 1 (大小 B)", fillcolor="#ffec99"]; Batch2 [label="批次 2 (大小 B)", fillcolor="#ffec99"]; BatchN [label="批次 ... (大小 B)", fillcolor="#ffec99"]; ModelUpdate1 [label="处理批次 1\n更新权重", shape=ellipse, fillcolor="#b2f2bb"]; ModelUpdate2 [label="处理批次 2\n更新权重", shape=ellipse, fillcolor="#b2f2bb"]; ModelUpdateN [label="处理批次 ...\n更新权重", shape=ellipse, fillcolor="#b2f2bb"]; Dataset -> Batch1 [label="迭代 1"]; Dataset -> Batch2 [label="迭代 2"]; Dataset -> BatchN [label="迭代 N/B"]; Batch1 -> ModelUpdate1; Batch2 -> ModelUpdate2; BatchN -> ModelUpdateN; } }一张图解,展示了在单个周期内,完整的训练数据集如何被划分为批次。每个批次被顺序处理,从而进行一次权重更新(迭代)。为何使用批次?使用批次(通常称为小批次梯度下降)相较于一次性处理整个数据集(批次梯度下降)或一次处理一个样本(随机梯度下降,或SGD,尽管实践中SGD常指小批次SGD)具有多项优势:内存效率: 处理整个数据集可能需要比可用内存(RAM或GPU显存)更多的空间。批次使得通过每次仅加载一部分数据来处理大型数据集成为可能。计算效率: GPU等硬件针对并行计算进行了优化。处理一批数据比顺序处理单个样本更能充分利用这种并行性。尽管一次性处理整个数据集看似可以并行,但内存限制通常使得小批次在实践中速度更快。梯度估计: 从小批次计算的梯度是对真实梯度(即在整个数据集上计算的梯度)的近似。这种近似结果带有噪声,这实际上可能是有益的。这些噪声可以帮助优化器摆脱陡峭的局部最小值,并有可能找到更好、更平坦的最小值,这些最小值对于未见过的数据通常具有更好的泛化能力。更新更快: 相较于批次梯度下降(在处理完整个数据集后更新),权重更新的频率更高(每个批次后更新)。这通常会加速收敛,尽管每次更新所依据的信息较少。批次大小的选择批次大小是另一个重要的超参数。常见的批次大小是2的幂(例如,32、64、128、256),这是因为硬件内存对齐优化所致,但其他值也可能有效。选择时需要权衡利弊:小批次大小(例如,1、8、16、32):优点: 带有噪声的梯度更新有助于脱离局部最小值(具有正则化作用)。需要更少的内存。有时可以使每个周期内初步收敛速度更快(更新次数更多)。缺点: 梯度近似结果噪声很大,可能导致训练不稳定,并且在实际运行时间上收敛较慢。由于硬件并行性利用不足,计算效率较低。大批次大小(例如,128、256、512及以上):优点: 更精确的梯度近似结果会使收敛更稳定。计算效率高,能最大限度地利用硬件并行性。缺点: 需要更多内存。可能收敛到尖锐的最小值,其泛化能力可能不如小批次常找到的更平坦的最小值。即使每个周期所需时间更短,也可能需要更多周期才能达到与小批次相同的表现水平。在实际操作中,批次大小设为32或64通常是一个好的起始选择。你可以在超参数调整过程中尝试不同的尺寸。Keras中的设定当你调用Keras的fit()方法时,你会指定这些参数:# 假设 'model' 已编译,并且 'x_train'、'y_train' 是 NumPy 数组 history = model.fit( x_train, y_train, batch_size=32, # 每次梯度更新的样本数量 epochs=10, # 遍历整个数据集的次数 validation_data=(x_val, y_val) # 用于在每个周期结束时评估损失和指标的数据 )此处,模型将训练10个周期。在每个周期中,它将以32个样本为一批次处理x_train数据,并在每个批次处理后更新权重。每个周期的迭代次数将是len(x_train) / 32。理解批次和周期对于控制训练过程非常重要。它们决定了模型如何随时间从数据中学习,影响着训练的稳定性、速度、内存使用,并最终影响模型的泛化表现。