Numpy实现神经网络全连接层

Numpy实现神经网络全连接层

详细源码戳:https://github.com/AKGWSB/Convolution-Neural-Network-Frame-only-based-on-Numpy-
(位于 Layer.py 文件中 的 Dense 类 的 FP 函数中)

Part 1 前向传播

首先假设一个这样的全连接层(不带偏置项)

输入是一个(3, 1)的矩阵,输出是一个(2, 1)的矩阵,那么权重矩阵的大小就应该是 (3, 2)

  • 即(输入神经元个数, 输出神经元个数)

那么根据全连接层的定义,输出项的计算公式如下:

O1 = W11 * I1 + W21 * I2 + W31 * I3
O2 = W12 * I1 + W22 * I2 + W32 * I3

结论:输出矩阵 = 权重矩阵的转置 左乘 输入矩阵 (矩阵乘法)

如果算上偏置项:

self.output = self.weights.T.dot(self.input) + self.bias

Part 2 更新当前层权重

已知上一层的梯度,即损失函数对输出矩阵O的偏导 g,并且g的形状和输出的形状一致
根据求导的链式法则我们有:

损失函数对权重矩阵的偏导 = 损失函数对输出矩阵的偏导 * 输出矩阵对输入矩阵的偏导


结论:

输出矩阵对权重矩阵的偏导 = 输入矩阵的转置 复制到 [ 输出神经元个数 ] 个数
(图中复制了两次)

在 Numpy 中使用 tile 函数进行复制,得到输出对权重矩阵的导数:

grad_for_w = np.tile(self.input.T, self.output_shape)   # gradient for weights

那么,根据链式法则

损失函数对权重矩阵的偏导 = 损失函数对输出矩阵的偏导 * 输出矩阵对输入矩阵的偏导

我们可以求得权重矩阵对损失函数的偏导数,从而更新权重矩阵 ( lr是学习率 , gradient 是损失函数对当前层之后一层的输入矩阵的偏导,即损失函数对当前层输出矩阵的偏导 )

self.weights -= (grad_for_w * self.gradient).T * lr

如果算上偏置项,其实输出对偏置项的导数就是 1:

self.bias -= self.gradient * lr  # gradient for bias mat is 1

Part 3 反向传播

我们还需要计算损失函数对输入矩阵的偏导,即损失函数对当前层之前一层的输出的偏导
同样,根据链式法则

损失函数对当前层输入矩阵的偏导 = 损失函数对当前层输出矩阵的偏导 * 当前层输出矩阵对输入矩阵的偏导

如图,可以推导出:

结论:

损失函数对当前层输入矩阵的偏导 = 权重矩阵 左乘 损失函数对当前层输出矩阵的偏导

即 权重矩阵 左乘 后一层回传的梯度矩阵(后一层的输入就是当前层的输出)

即 权重矩阵 左乘 损失函数对后一层输入矩阵的偏导

即:

last_layer_gradient = self.weights.dot(self.gradient)

(gradient 是损失函数对当前层之后一层的输入矩阵的偏导,即损失函数对当前层输出矩阵的偏导 )

Layer 类完整实现的代码:
详细戳:https://github.com/AKGWSB/Convolution-Neural-Network-Frame-only-based-on-Numpy-/blob/master/Layers.py

# Forward propagation
# param x : last layer's output
# 前向传播
# x 是当前层的输入
def FP(self, x):
    self.input = x.copy()
    self.output = self.weights.T.dot(self.input) + self.bias
    self.next_layer.FP(x=self.output)

# Back propagation
# param gradient : last layer's gradient
# param lr       : learning rate
# 反向传播,gradient是当前层输出对损失函数的梯度, lr是学习率
def BP(self, gradient, lr):
    self.gradient = gradient.copy()
    last_layer_gradient = self.weights.dot(self.gradient)
    self.last_layer.BP(gradient=last_layer_gradient, lr=lr)

    grad_for_w = np.tile(self.input.T, self.output_shape)   # gradient for weights
    self.weights -= (grad_for_w * self.gradient).T * lr
    self.bias -= self.gradient * lr  # gradient for bias mat is 1
    

你可能感兴趣的:(机器学习,深度学习,神经网络,python,人工智能,矩阵)