反向传播公式推导与Python代码简单实现

之前一直对反向传播机制一知半解,最近花了点时间把这个问题想了想,记录于此。
反向传播时神经网络学习能力的具体体现,他表示损失函数对参数的梯度反向流动,以此来更新网络中的参数值。在这期间需要注意的是,网络的可学习参数值是自变量,输入为可学习参数的权重,损失函数是因变量。其核心思想时链式求导法则。
一个反向传播的全过程包括误差传播,可学习参数的更新。
以全连接神经网络为例,一个完整的正向传播如下图所示:
全连接正向传播图
这是一个二分类的网络前向传播图,每个节点表示一个神经元,其包含可学习参数W和b。
对上图进行简单化和抽象化,我们形成了下图每层一个神经元的神经网络:
单神经元的全连接网络
前一个神经元激活函数的输出会作为下一个神经元的输入。

1、前向传播

由此我们可以得到一个中间层神经元的前向传播的计算公式:
在这里插入图片描述

2、反向传播

2.1每个隐藏层只含单神经元

根据上图给的单神经元的全连接网络的前向传播图,我们可以推出损失函数对图中对hi和ai的偏导数为:

在这里插入图片描述

2.2每个隐藏层含多个神经元

对于一层中存在多个神经元的情况,在求hij的偏导数时只需将同一层个神经元对应的偏导数相加即可,如下公式:
在这里插入图片描述

2.3对可学习参数W,b的偏导数

通过上述公式可以很容易得到W和b的偏导数,具体公式如下所示:
在这里插入图片描述
在这里插入图片描述

3、反向传播代码实现

from torch.nn import Sigmoid, Tanh, ReLU, Softmax

class Layer():
    def __init__(self) -> None:
        self.W #(input_dim, out_dim)
        self.b #(1, out_dim)
        self.activate = Sigmoid()
    
    def forward(self, input_data):
        h = input_data @ self.W + self.b
        a = self.activate(h)
        return a
    
    def backward(self, input_grad):
        h_grad = input_grad * self.activate.grad(a)
        b_grad = h_grad
        W_grad = (input_data.T) @ h_grad

        self.b -= learning_rate * b_grad 
        self.W -= learning_rate * W_grad

        return h_grad @ (self.W).T

4、softmax的反向传播公式

上述代码为反向传播机制的伪代码,上面介绍的反向传播的输出层用到的都是sigmoid函数,该激活函数h与a是一一对应的,如果用到的激活函数为softmax函数h与a是多对多的关系,则下式中逐元素相乘是失效的:
在这里插入图片描述
但最后上式会转化成a-y,a为激活函数,y为one-hot编码的向量

在这里插入图片描述
在这里插入图片描述
上述推导公式的隐藏层和激活函数输出分别为a和h。
python伪代码如下:

# * 表示element-wise乘积,· 表示矩阵乘积

class Output_layer(Layer):
    '''属性和forward方法继承Layer类'''

    def backward(input_grad):
       '''输出层backward方法'''
       '''单个样本的反向传播'''
       a_grad = input_grad                 # (1, output_dim)
       b_grad = a_grad                     # (1, output_dim)
       W_grad = (input_data.T) @ a_grad    # (input_dim, output_dim)

       self.b -= learning_rate * b_grad 
       self.W -= learning_rate * W_grad

       return a_grad @ (self.W).T          # (1, input_dim)

5、批量计算的反向传播

python伪代码如下所示:

# * 表示element-wise乘积,· 表示矩阵乘积

class Layer:
    '''中间层类'''

    def forward(self, input_data):       # input_data: (batch_size, input_dim)
       '''batch_size个样本的前向传播'''
       input_data @ self.W + self.b = a  # a: (1, output_dim)
       h = self.activate(a)              # h: (1, output_dim)
       return h

    def backward(input_grad):             # input_grad: (batch_size, output_dim)
       '''batch_size个样本的反向传播'''
       a_grad = input_grad * activate’(a) # (batch_size, output_dim)

       b_grad = a_grad.mean(axis=0)       # (1, output_dim)
       W_grad = (input_data.reshape(batch_size,input_dim,1) 
       			@ a_grad.reshape(batch_size,1,output_dim)).mean(axis=0)
       # (input_dim, output_dim) 
       
       self.b -= lr * b_grad
       self.W -= lr * W_grad

       return a_grad @ (self.W).T         # output_grad: (batch_size, input_dim)


class Output_layer(Layer):
    '''输出层类:属性和forward方法继承Layer类'''

    def backward(input_grad):             # input_grad: (batch_size, output_dim)
       '''输出层backward方法'''
       '''batch_size个样本的反向传播'''
       a_grad = input_grad                # (batch_size, output_dim)

       b_grad = a_grad.mean(axis=0)       # (1, output_dim)
       W_grad = (input_data.reshape(batch_size,input_dim,1) 
       			@ a_grad.reshape(batch_size,1,output_dim)).mean(axis=0)
       # (input_dim, output_dim) 

       self.b -= learning_rate * b_grad 
       self.W -= learning_rate * W_grad

       return a_grad @ (self.W).T          # output_grad: (batch_size, input_dim)

参考链接:
知乎–反向传播详解

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卡比兽-Carpe_diem

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值