反向传播中偏差项的梯度

数据挖掘 Python 神经网络 反向传播
2021-10-12 22:49:39

我试图从头开始实现神经网络以了解其背后的数学原理。当我们对偏差求导时,我的问题与反向传播完全相关)并且我导出了反向传播中使用的所有方程。现在每个方程都与神经网络的代码匹配,除了关于偏差的导数。

z1=x.dot(theta1)+b1

h1=1/(1+np.exp(-z1))
z2=h1.dot(theta2)+b2
h2=1/(1+np.exp(-z2))

dh2=h2-y
#back prop

dz2=dh2*(1-dh2)
H1=np.transpose(h1)
dw2=np.dot(H1,dz2)
db2=np.sum(dz2,axis=0,keepdims=True)

我在网上查了代码,我想知道为什么我们将矩阵相加,然后db2=np.sum(dz2,axis=0,keepdims=True)从原始偏差中减去标量,为什么不减去整个矩阵。谁能帮我给出一些直觉。如果我对偏差进行损失的偏导,它将只给我上梯度,即 dz2,因为 z2=h1.dot(theta2)+b2h1 和 theta 将为 0,b2 将为 1。所以上项将被保留。

b2+=-alpha*db2
4个回答

我想解释一下它的含义,db2=np.sum(dz2,axis=0,keepdims=True)因为它曾经让我感到困惑并且没有得到回答。

L(loss) wrt的导数b上游导数乘以局部导数

Lb=LZZb

如果我们有多个样本Z并且L都是矩阵。b 仍然是一个向量。

局部导数只是一个向量

Zb=bW×X+b=1

这意味着我们的完整导数是矩阵乘法,如下所示(例如,2 个样本和 3 个输出)

LZ×1=[......][111]

请注意,这是行的总和

这就是db2=np.sum(dz2, axis=0, keepdims=True)从哪里来的。它只是局部和上游导数的矩阵乘法的缩写。

偏差项非常简单,这就是为什么您经常看不到它被计算出来的原因。实际上

db2 = dz2

因此,您对单个项目的偏差的更新规则是:

b2 += -alpha * dz2

b1 += -alpha * dz1

在数学方面,如果你的损失是J, 而且你知道Jzi对于给定的神经元i有偏差项bi. . .

Jbi=Jzizibi

zibi=1

因为zi=(something unaffected by bi)+bi


看起来您复制的代码使用了表单

db2=np.sum(dz2,axis=0,keepdims=True)

因为该网络旨在处理(小)批次中的示例,因此您一次计算多个示例的梯度。总和将结果压缩为单个更新。如果您还显示了权重的更新代码,这将更容易确认。

首先,您必须更正 Sigmoid 函数梯度的公式。

sigmoid函数的一阶导数是: (1−σ(x))σ(x)

您的 dz2 公式将变为: dz2 = (1-h2)*h2 * dh2

您必须使用 sigmoid 函数的输出而σ(x)不是梯度。

您必须对偏差的梯度求和,因为该梯度来自许多单个输入(输入数 = 批量大小)。因此,我们必须累积它们来更新第 2 层的偏差。但是,对于第 1 层的梯度,由于它们来自第 2 层的许多节点,因此您必须对所有梯度求和才能更新第 1 层的偏差和权重. 这种情况与第 2 层中的偏差之和不同。

我对两个具有激活函数的全连接层的实现是 sigmoid 函数:

lr = 1e-3
f = lambda x: 1.0/(1.0 + np.exp(-x))
# pass through layer 1
out_l1 = np.dot(x, W_1) + b_1

out_s1 = f(out_l1)

# pass through layer 2
out_l2 = np.dot(x, W_2) + b_2

out_s2 = f(out_l2)

loss = get_loss(out_s2, y)

# BACKWARD PASS
grad = out_s2 - y

d_h2 = (1 - out_s2) * out_s2 * grad

# Accumulate the gradient come from all examples
d_W2 = out_s1.T.dot(d_h2)
d_b2 = np.sum(d_h2, axis=0, keepdims=True)

# sum of gradient come out from prev node:
grad_1 = np.sum(d_W2.T, axis=0, keepdims=True)
d_h1 = (1 - out_l1) * out_l1 * grad_1

d_W1 = x.T.dot(d_h1)
d_b1 = np.sum(d_h1, axis=0, keepdims=True)

W_1 -= d_W1 * lr
b_1 -= d_b1 * lr

W_2 -= d_W2 * lr
b_2 -= d_b2 * lr

在此处输入图像描述

L(损失)wrt b的导数的实现非常混乱。特别是,参数axis=0意味着您要计算列的总和而不是行的总和。如果我错了,请纠正我。