Python深度学习基础(三)——全连接层以及反向传递的理解与手动实现
全连接层以及反向传递的理解与手动实现
- 全连接层简介
- 实现原理
-
- 正向传递
- 反向传递
- 代码实现
全连接层简介
全连接层又被称为密连接层,通常可以用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