我在尝试理解使用小批量随机梯度下降(SGD)时如何计算梯度。我在CS231在线课程中实现了它,但后来才意识到,在中间层,梯度基本上是对每个样本计算的梯度之和(Caffe或Tensorflow中的实现也是如此)。只有在最后一层(损失层),它们才按样本数量进行平均。这是否正确?如果是这样,是否意味着由于在最后一层进行了平均,在进行反向传播时,所有梯度也会自动平均?谢谢!
回答:
最好先理解为什么SGD有效。
通常,神经网络实际上是一个非常复杂的复合函数,它的输入是向量x,标签y(或目标变量,根据问题是分类还是回归而变化)以及一些参数向量w。假设我们正在进行分类。我们实际上是在对变量向量w进行最大似然估计(实际上是MAP估计,因为我们肯定会使用L2或L1正则化,但这现在技术性太强了)。假设样本是独立的;那么我们有以下成本函数:
p(y1|w,x1)p(y2|w,x2) ... p(yN|w,xN)
由于所有这些概率都是相乘的,针对w进行优化会变得一团糟(这将产生一个对w的极其复杂的导数)。我们使用对数概率代替(取对数不会改变极值点,我们除以N,因此我们可以将训练集视为一个经验概率分布,p(x))
J(X,Y,w)=-(1/N)(log p(y1|w,x1) + log p(y2|w,x2) + ... + log p(yN|w,xN))
这就是我们实际拥有的成本函数。神经网络实际上做的就是对概率函数p(yi|w,xi)进行建模。这可以是一个非常复杂的1000+层ResNet,也可以只是一个简单的感知器。
现在,w的导数很容易表述,因为我们现在有一个加法:
dJ(X,Y,w)/dw = -(1/N)(dlog p(y1|w,x1)/dw + dlog p(y2|w,x2)/dw + ... + dlog p(yN|w,xN)/dw)
理想情况下,上述是实际的梯度。但这种批量计算并不容易进行。如果我们在一个有100万个训练样本的数据集上工作呢?更糟糕的是,训练集可能是一个无限大小的样本流x。
SGD的随机部分在这里发挥作用。从训练集中随机且均匀地选择m个样本,其中m << N,并使用它们计算导数:
dJ(X,Y,w)/dw =(approx) dJ'/dw = -(1/m)(dlog p(y1|w,x1)/dw + dlog p(y2|w,x2)/dw + ... + dlog p(ym|w,xm)/dw)
记住,我们有一个经验的(或在无限训练集的情况下是实际的)数据分布p(x)。从p(x)中抽取m个样本并对它们进行平均的上述操作实际上产生了实际导数dJ(X,Y,w)/dw的无偏估计器dJ’/dw。这意味着什么呢?取许多这样的m个样本并计算不同的dJ’/dw估计值,也对它们进行平均,你会非常接近地得到dJ(X,Y,w)/dw,甚至在无限抽样的极限下完全准确。可以证明,这些有噪声但无偏的梯度估计在长期来看会像原始梯度一样表现。平均而言,SGD将遵循实际梯度的路径(但它可能会卡在一个不同的局部最小值,这完全取决于学习率的选择)。小批量大小m直接关系到噪声估计dJ’/dw中的固有误差。如果m很大,你会得到低方差的梯度估计,你可以使用更大的学习率。如果m很小或m=1(在线学习),估计器dJ’/dw的方差非常高,你应该使用较小的学习率,否则算法可能会轻易失控。
现在理论讲得够多了,你的实际问题是
只有在最后一层(损失层),它们才按样本数量进行平均。这是否正确?如果是这样,是否意味着由于在最后一层进行了平均,在进行反向传播时,所有梯度也会自动平均?谢谢!
是的,在最后一层除以m就足够了,因为链式法则会将因子(1/m)传播到所有参数,一旦最底层被它乘以。你不需要为每个参数单独进行,这将是无效的。