在每一层中,您的神经网络一遍又一遍地产生以下中间计算:
z[l] = a[l] * w[l] + b[l]
a[l+1] = f[l](z[l])
其中 a[0] 是您对神经网络的原始输入。 z[l] 是前一个激活 a[l] 的加权和(记住 a[0] 是输入),然后第 l 层 w[l] 的权重加上 b[l],即偏置向量。然后通过在先前计算的 z 上应用激活函数 (f[l](x) - 请记住,您可以为每一层设置不同的激活函数)来计算当前层的激活。
这是你的前传。您一遍又一遍地重复上述步骤,层数不限。
为了向后传播错误,您必须区分成本函数相对于从最后一个到第一个的每个权重矩阵:
dw[l], dw[l-1], ..., dw[1], dw[0]
让我们举一个玩具的例子。您有一个具有单个隐藏层和一个输出层的神经网络,因此您的输入有 a[0],z[0] 作为隐藏层上的加权一些,a[1] 作为隐藏层上的激活, z[1] 作为输出层的一些加权,a[2] 作为网络对输入的猜测。隐藏层的权重也有 w[0],输出层的权重有 w[1]。最后当然有 b[0] 用于隐藏,b[1] 用于输出偏差。
现在,要更新您的权重,您必须找到:
第一个是输出层的权重,接下来是隐藏层的权重。
dE/dw[0] := dE/da[2] * da[2]/dz[1] * dz[1]/dw[1]
If, E := np.mean(np.sum(.5 * (a[2] - Y)**2, axis=1), axis=0)
then:
dE/da[2] = (a[2] - Y)
For da[2]/dz[1], remember that a[l+1] = f[l](z[1]):
da[2]/dz[1] = df[l](z[1])
Finally:
dz[1]/dw[1] = a[1]
dE/dw[0] = (a[2] - Y) * df[l](z[1]) @ a[1]
其中,* 是逐元素乘法,@ 是众所周知的标准矩阵乘法。现在,有不同的方法来初始化权重矩阵和组织小批量梯度下降的输入矩阵,所以上述仍然需要一些工作。通常您必须转置 a[1] 和/或将 a[1].T 与其余部分相乘。但是计算是这样的。
现在,对于隐藏层,事情还在继续:
dE/dw[0] := dE/da[2] * da[2]/dz[1] * dz[1]/da[1] * da[1]/dz[0] * dz[0]/dw[0]
Where dE/da[2] * da[2]/dz[1] is common and is called d[1] a.k.a the delta for the output layer.
dz[1]/da[1] = w[1]
da[1]/dz[0] = df[0](z[0])
dz[0]/dw[0] = a[0]
dE/dw[0] = d[1] @ w[1] * df[0](z[0]) * a[0]
w[1] 和 a[0] 可能需要再次转换,这取决于您设计网络的方式,但计算就在那里。
长话短说,这只是一次又一次地应用链式法则。给定一个层 [i],您将有一些来自下一层的 delta d[i+1],然后您需要为当前层计算 dw[i],为前一层 [i-1] 计算 d[i] -第层:
d[i] = d[i+1] @ w[i+1] * df[i](z[i])
dw[i] = d[i] @ a[i]
然后对网络中的所有层从最后到第一重复此操作。我希望这能解决问题。