全连接层简介
全连接层又被称为密连接层,通常可以用Affine或Dense表示
实现原理
正向传递
全连接层在正向传递时和感知机完全一致,都是直接将输入值乘以权值在加上偏置即可,这里尤为注意的是我们使用的是矩阵。公式非常简单
y
=
x
⋅
w
+
b
y=x \cdot w + b
y=x⋅w+b
反向传递
对于正向传递的表达式,我们可以将整个正向传递过程看成两步
y
1
=
x
⋅
w
;
y
=
y
1
+
b
y1=x \cdot w; \\ y=y1+b
y1=x⋅w;y=y1+b
这样我们就将问题转换成了乘法层和加法层的堆叠
∂
y
∂
y
1
=
1
\frac{ \partial y}{\partial y1}=1
∂y1∂y=1
∂
y
∂
b
=
1
\frac{ \partial y}{\partial b}=1
∂b∂y=1
∂
y
∂
y
1
∂
y
1
∂
x
=
w
\frac{ \partial y}{\partial y1}\frac{ \partial y1}{\partial x}=w
∂y1∂y∂x∂y1=w
∂
y
∂
y
1
∂
y
1
∂
w
=
x
\frac{ \partial y}{\partial y1}\frac{ \partial y1}{\partial w}=x
∂y1∂y∂w∂y1=x
∂
y
∂
b
=
1
\frac{ \partial y}{\partial b}=1
∂b∂y=1
根据链式法则每个偏导都应该乘以下一层传来的偏导数值,本文代码用dout
表示,故
∂
L
∂
y
∂
y
∂
y
1
∂
y
1
∂
x
=
∂
L
∂
y
⋅
w
\frac{ \partial L}{\partial y}\frac{ \partial y}{\partial y1}\frac{ \partial y1}{\partial x}=\frac{ \partial L}{\partial y} \cdot w
∂y∂L∂y1∂y∂x∂y1=∂y∂L⋅w
∂
L
∂
y
∂
y
∂
y
1
∂
y
1
∂
w
=
∂
L
∂
y
⋅
x
\frac{ \partial L}{\partial y}\frac{ \partial y}{\partial y1}\frac{ \partial y1}{\partial w}=\frac{ \partial L}{\partial y} \cdot x
∂y∂L∂y1∂y∂w∂y1=∂y∂L⋅x
∂
L
∂
y
∂
y
∂
b
=
∂
L
∂
y
⋅
1
\frac{ \partial L}{\partial y}\frac{ \partial y}{\partial b}=\frac{ \partial L}{\partial y} \cdot 1
∂y∂L∂b∂y=∂y∂L⋅1
代码实现
class Affine:
def __init__(self, W, b):
self.W =W
self.b = b
self.x = None
self.original_x_shape = None
# 权重和偏置参数的导数
self.dW = None
self.db = None
def forward(self, x):
# 对应张量
self.original_x_shape = x.shape
x = x.reshape(x.shape[0], -1)
self.x = x
out = np.dot(self.x, self.W) + self.b
return out
def backward(self, dout):
dx = np.dot(dout, self.W.T)
self.dW = np.dot(self.x.T, dout)
self.db = np.sum(dout, axis=0)
dx = dx.reshape(self.original_x_shape) # 还原输入数据的形状(对应张量)
return dx