反向传播算法和计算图详细介绍及其原理详解

news2024/12/25 15:29:19

相关文章

  1. 梯度下降算法、随机梯度下降算法、动量随机梯度下降算法、AdaGrad算法、RMSProp算法、Adam算法详细介绍及其原理详解
  2. 反向传播算法和计算图详细介绍及其原理详解

文章目录

  • 相关文章
  • 前言
  • 一、反向传播算法
    • 1.1 什么是反向传播算法?
    • 1.2 更泛化的例子
  • 二、计算图
    • 2.1 什么是传播图?
    • 2.2 一个简单的例子
  • 总结


前言

  本文总结了关于反向传播算法以及计算图的相关内容以及原理,并通过举例说明整个运算过程。下面就是本篇博客的全部内容!


一、反向传播算法

1.1 什么是反向传播算法?

  假设现在有如下图的一个过程:

请添加图片描述

图1:只有一个神经元的前向传播过程

  使用直线 y = w x + b y=wx+b y=wx+b去拟合数据,初始输入值为 x x x,参数为 w , b w,b w,b,得到预测值 y y y,其真实值为 y g t y_{gt} ygt,那么可以得到损失函数为:
L = 1 2 ( y − y g t ) 2 L=\frac{1}{2}\left(y-y_{g t}\right)^{2} L=21(yygt)2
  现在我们的目的是通过更新参数 w , b w,b w,b使得损失值最小,为了更直观的演示,我们先给参数赋值,其中 ε \varepsilon ε表示学习率:

  • x = 1.5 x=1.5 x=1.5
  • w = 0.8 w=0.8 w=0.8
  • b = 0.2 b=0.2 b=0.2
  • ε = 0.1 \varepsilon=0.1 ε=0.1

  假设真实值 y g t = 0.8 y_{gt}=0.8 ygt=0.8,那么通过赋的初始值,可以得到:

  • y = 0.8 × 1.5 + 0.2 = 1.4 y=0.8×1.5+0.2=1.4 y=0.8×1.5+0.2=1.4
  • L = 0.17 L=0.17 L=0.17

  此时就要利用之前学过的梯度下降算法来更新参数,首先要求出损失函数 L L L对参数 w w w的偏导数:
∂ L ∂ w \frac{\partial L}{\partial w} wL
  然后更新参数 w w w
w = w − ε ∂ L ∂ w w = w-\varepsilon \frac{\partial L}{\partial w} w=wεwL
  另一个参数 b b b也是一样的过程,首先计算损失函数 L L L对参数 b b b的偏导数:
∂ L ∂ b \frac{\partial L}{\partial b} bL
  然后更新参数 b b b
b = b − ε ∂ L ∂ b b = b-\varepsilon \frac{\partial L}{\partial b} b=bεbL
  上面的过程看似很简单,但是如何求得 ∂ L ∂ w \frac{\partial L}{\partial w} wL ∂ L ∂ b \frac{\partial L}{\partial b} bL呢?以参数 w w w为例,很明显损失函数 L L L是关于参数 y y y的函数,而 y y y又是关于参数 w w w的偏导,所以根据高等数学中学过的链式求导法则可以得到:
∂ L ∂ w = ∂ L ∂ y ∂ y ∂ w \frac{\partial L}{\partial w}=\frac{\partial L}{\partial y} \frac{\partial y}{\partial w} wL=yLwy
  所以首先我们要求出损失函数 L L L对参数 y y y的偏导:
∂ L ∂ y = y − y g t \frac{\partial L}{\partial y}=y-y_{g t} yL=yygt
  然后再求出 y y y w w w的偏导:
∂ y ∂ w = x \frac{\partial y}{\partial w}=x wy=x
  再将其代入可以得到:
∂ L ∂ w = ∂ L ∂ y ∂ y ∂ w = ( y − y g t ) x \frac{\partial L}{\partial w}=\frac{\partial L}{\partial y} \frac{\partial y}{\partial w}=(y-y_{g t})x wL=yLwy=(yygt)x
  同理我们也可以求出 ∂ L ∂ b \frac{\partial L}{\partial b} bL
∂ L ∂ b = ∂ L ∂ y ∂ y ∂ b = y − y g t \frac{\partial L}{\partial b}=\frac{\partial L}{\partial y} \frac{\partial y}{\partial b}=y-y_{g t} bL=yLby=yygt
  然后再将预设好的数据值代入,就可以得到损失函数 L L L关于参数 w , b w,b w,b的偏导值:
∂ L ∂ w = 0.9 \frac{\partial L}{\partial w}=0.9\\ wL=0.9

∂ L ∂ b = 0.6 \frac{\partial L}{\partial b}=0.6 bL=0.6

  当我们所有的参数都计算出后,代入更新参数 w , b w,b w,b的公式,就可以根据梯度下降算法更新参数得到:

  • w = 0.71 w=0.71 w=0.71
  • b = 0.14 b=0.14 b=0.14
  • y = 0.71 × 1.5 + 0.14 = 1.205 y=0.71×1.5+0.14=1.205 y=0.71×1.5+0.14=1.205
  • L = 0.082 L=0.082 L=0.082

  可以看到,预测值越来越接近真实值,并且损失值也变小了。可以发现,我们要更新参数 w , b w,b w,b,就要从后向前依次求偏导才能得到结果,这种利用梯度从后向前更新参数的方法,也被称为反向传播算法(Back-Propagation,BR)。

1.2 更泛化的例子

  刚才介绍的例子参数比较少,计算过程也比较简单,那如果我们的情况更泛化,也更复杂呢?假设有如下图的一种情况:

请添加图片描述

图2:有两个神经元的前向传播过程

  此时我们要更新的参数为 w 1 , b 1 w_{1},b_{1} w1,b1,第一次计算的结果 y 1 y_{1} y1又当作参数传入下一个神经元,经过与参数 w 2 , b 2 w_{2},b_{2} w2,b2的计算得到最终的结果 y 2 y_{2} y2,然后用 L ( y 2 , y g t ) L(y_{2},y_{gt}) L(y2,ygt)表示经过两次拟合后的结果与真实值的误差。

  更新参数 w 1 , b 1 w_{1},b_{1} w1,b1最重要的就是求出 ∂ L ∂ w 1 \frac{\partial L}{\partial w_{1}} w1L ∂ L ∂ b 1 \frac{\partial L}{\partial b_{1}} b1L,我们先计算 ∂ L ∂ w 1 \frac{\partial L}{\partial w_{1}} w1L,根据函数关系,我们可以得到如下链式求导公式:
∂ L ∂ w 1 = ∂ L ∂ y 2 ∂ y 2 ∂ y 1 ∂ y 1 ∂ w 1 \frac{\partial L}{\partial w_{1}}=\frac{\partial L}{\partial y_{2}} \frac{\partial y_{2}}{\partial y_{1}} \frac{\partial y_{1}}{\partial w_{\mathbf{1}}} w1L=y2Ly1y2w1y1
  可以看到,整个计算过程是从后向前依次计算的,这也符合反向传播算法对此过程的描 述。当我们得到 ∂ L ∂ w 1 \frac{\partial L}{\partial w_{1}} w1L后,就可以利用参数更新公式来更新参数:
w 1 = w 1 − ε ∂ L ∂ w 1 w_{1} = w_{1}-\varepsilon \frac{\partial L}{\partial w_{1}} w1=w1εw1L
  同理,我们也可以得到关于参数 b 1 b_{1} b1的链式求导公式:
∂ L ∂ b 1 = ∂ L ∂ y 2 ∂ y 2 ∂ y 1 ∂ y 1 ∂ b 1 \frac{\partial L}{\partial b_{1}}=\frac{\partial L}{\partial y_{2}} \frac{\partial y_{2}}{\partial y_{1}} \frac{\partial y_{1}}{\partial b_{1}} b1L=y2Ly1y2b1y1
  然后再使用参数更新公式来更新参数即可:
b 1 = b 1 − ε ∂ L ∂ b 1 b_{1} = b_{1}-\varepsilon \frac{\partial L}{\partial b_{1}} b1=b1εb1L
  以上过程就是反向传播算法的全部过程,当然,在深度学习的应用中,反向传播算法需要计算的神经元个数是非常多的,但是原理与此无异,就是链式求导法则的一个应用。而在链式求导公式中的许多参数已经在上一步计算好了,所以不需要重复计算,这就使在神经网络训练过程中,节省很多不必要的计算,故反向传播算法就是神经网络中加速计算参数梯度值的方法。

二、计算图

2.1 什么是传播图?

  还是刚才的例子,输入数据经过两个神经元的运算得到最终的输出数据 y 2 y_{2} y2,通过与真实值的比较得到损失函数 L ( y 2 , y g t ) L(y_{2},y_{gt}) L(y2,ygt),整个过程如下图所示:

请添加图片描述

图3:有两个神经元的前向传播过程

  从左往右的计算过程也叫前向传播,这个很好理解,就是一级一级的向下计算传播。那么计算机中如何表示这个过程呢?计算机会将每个运算小步骤保存下来,记录为一个参数,等待下次运算,具体的运算过程可见下图:

请添加图片描述

图4:有两个神经元的前向传播计算图

  引入的变量 u 1 u_{1} u1就是为了存储参数 x x x w 1 w_{1} w1运算小步骤的结果,然后等待下次运算的时候,直接将其作为参数进行计算即可,后面的参数同理,很明显这样看起来更“舒服”,符合计算机逐步运算的逻辑,经过运算最终可以得到最终的预测值 y 2 y_{2} y2和损失函数 L {L} L,这种模块化的计算过程图就称为计算图(Computation Graphs)。

  现在我们已经知道计算机如何利用计算图通过前向传播得到最终的预测值 y 2 y_{2} y2和损失函数 L {L} L了,那么计算机又如何利用计算图进行反向传播呢?也就是说,计算机如何利用计算图计算出损失函数 L L L对于各个参数的梯度呢?对于这个计算过程,可见下图:

请添加图片描述

图5:有两个神经元的反向传播计算图

  可以看到,计算损失函数 L L L对于各个参数的梯度仍和之前的计算方法一致,只是由于引入了中间变量 u i , ( 1 ≤ i ≤ 2 ) u_{i},(1≤i≤2) ui,(1i2),所以每次计算关于损失函数 L L L对于 u u u中参数的偏导数时,要先计算损失函数 L L L对于 u u u的偏导数,其余计算过程并没有变化,其中需要注意:

  • 黄色的变量:通过此步骤的之前步骤得到的运算结果
  • 绿色的变量:通过前向传播得到的已知的数据

  最终同样可以得到损失函数 L L L关于参数 w i , b i , ( 1 ≤ i ≤ 2 ) w_{i},b_{i},(1≤i≤2) wi,bi,(1i2)的偏导数,然后就可以利用之前介绍的梯度下降算法进行参数的优化更新了。

2.2 一个简单的例子

  我们现在已经明白什么是计算图了,那么计算机如何利用计算图的原理去进行有关深度学习的计算呢?我们以Pytorch中的乘法运算为例,其运算图如下所示:

请添加图片描述

图6:神经网络中乘法运算的计算图
  1. 前向传播

    Pytorch中乘法运算的前向传播代码如下所示:

    class Multiply(torch.autograd.Function):
    	@staticmethod
    	def forward(ctx, x, y):
    	ctx.save_for_backward(x,y)
    	z = x * y
    	return z
    

    可以看到,整段代码的运算过程恰如乘法运算计算图中绿色所示部分,直接获取到关于 x x x y y y的参数,然后进行相乘得到 z z z,最后返回 z z z即可。

  2. 反向传播

    Pytorch中乘法运算的反向传播代码如下所示:

    class Multiply(torch.autograd.Function):
    	@staticmethod
    	def backward(ctx, grad_z):
    	x, y = ctx.saved_tensors
    	grad_x = grad_z * y
    	grad_y = grad_z * x
    	return grad_x, grad_y
    

    这个就和前向传播的代码有所不同,因为其计算需要求损失函数 L L L关于各个参数的偏导数,所以此段代码对应乘法运算计算图中黄色所示部分。其中, g e a d _ z = ∂ L ∂ z gead\_z=\frac{\partial L}{\partial z} gead_z=zL,而我们需要求得损失函数 L L L分别对 x , y x,y x,y的偏导数,其具体表示为:

    • grad_x = grad_z * y对应:

    ∂ L ∂ x = ∂ L ∂ z ∂ z ∂ x = ∂ L ∂ z y \frac{\partial L}{\partial x}=\frac{\partial L}{\partial z} \frac{\partial z}{\partial x}=\frac{\partial L}{\partial z} y xL=zLxz=zLy

    • grad_y = grad_z * x对应:
      ∂ L ∂ y = ∂ L ∂ z ∂ z ∂ y = ∂ L ∂ z x \frac{\partial L}{\partial y}=\frac{\partial L}{\partial z} \frac{\partial z}{\partial y}=\frac{\partial L}{\partial z} x yL=zLyz=zLx

  这样就可以通过计算图利用反向传播算法来更新数以亿计的网络参数了。


总结

  以上就是本篇博客的全部内容了,文章内容不算太长,但是有些地方还是不太好理解的,最好有些高等数学的基础,学起来会更“舒服”。本系列还会一直更新,敬请期待!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/126672.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

我把这一年学的 CSS 知识点精炼总结成了一篇文档

文章目录一.CSS简介1.什么是CSS?二.CSS语法1.语法规则2.注释三.CSS选择器1.CSS的id选择器2.CSS的class选择器四.CSS创建1.外部样式表2.内部样式表3.内联样式4.多重样式5.多重样式的优先级五.CSS 背景1.背景颜色2.背景图像3.背景图像 - 水平或垂直平铺4.背景图像- 设…

【云原生 | Kubernetes 实战】18、K8s 安全实战篇之 RBAC 认证授权(上)

目录 一、k8s 安全管理:认证、授权、准入控制概述 1.1 认证 认证基本介绍 授权基本介绍 准入控制基本介绍 为什么需要准入控制器呢? k8s 客户端访问 apiserver 的几种认证方式 kubeconfig 文件 1.2 授权 Role、RoleBinding、ClusterRole 和 C…

springboot学习(七十六) springboot中为多个controller添加统一访问URL的前缀

文章目录前言一、配置文件内添加前缀配置二、配置映射的实体三、自定义注解四、自定义PathMatch添加前缀五、测试前言 在某些情况下,服务的controller中前缀是一致的,例如所有URL的前缀都为/context-path/api/v1,需要为某些URL添加统一的前缀…

IFCOpenShell编译经验

IFCOpenShell编译经验 环境准备: Git:官网 CMake:官网 VisualStudio:官网 安装环境后需设置环境变量: C:\Program Files\Git\cmd D:\Program Files (x86)\cmake-3.25.1-x86_64\bin 下载开发包 编译官网 git clone --recursive https://github.com/IfcO…

【LeetCode每日一题】——1539.第 k 个缺失的正整数

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【题目进阶】九【时间频度】十【代码实现】十一【提交结果】一【题目类别】 二分查找 二【题目难度】 简单 三【题目编号】 1539.第 k 个缺失的正整数 四…

关于VSCode的三个配置文件

关于VSCode的三个配置文件 若要使用VSCode来开发C程序,则应该了解以下三种配置文件,分别为: tasks.json:编译器相关的配置文件。比如,设置编译指令。 注:对于复杂的编译任务(涉及多个源文件的编…

《Linux运维总结:Centos7.6部署redis6.2.8哨兵集群》

一、部署redis服务 1.1、环境信息 环境信息如下: 主机IP操作系统Redis版本CPU架构端口角色192.168.1.191Centos7.66.2.8x86_647001master192.168.1.192Centos7.66.2.8x86_647002slave192.168.1.193Centos7.66.2.8x86_647003slave192.168.1.191Centos7.66.2.8x86_6…

【嵌入式·单片机】老生常谈:学习单片机和嵌入式是否需要学习算法?

文章目录前言什么是算法嵌入式是否需要算法如何学习算法参考资料前言 刚学习单片机或嵌入式的同学可能会听说过「算法」这个词,部分电子信息类专业的同学也会在自己的培养计划上看到《数据结构与算法》这门课程,这个时候我们可能会感到疑惑,…

九、Java 16 新特性

九、Java 16 新特性 JDK 16 在 2021 年 3 月 16 号发布!根据发布的规划,这次发布的 JDK 17 是一个长期维护的版本(LTS)。Java 16 提供了数千个性能、稳定性和安全性更新,以及 17 个 JEP(JDK 增强提案)&…

特征工程资料整理,如何从数据中挖掘特征

特征工程资料整理,如何从数据中挖掘特征一、特征工程是什么二、探索性数据分析EDA参考资料:1. pandas_profiling【推荐】2. Sweetviz3. pandasgui4.D-tale【推荐】结论三、特征处理参考资料:1. 数值特征⭐️⭐️⭐️⭐️⭐️数值特征小结&…

用于高精度干涉仪的奇特量子效应

使用物质波放大、跟踪加速度,以前从未以便携式形式实现。(图片来源:网络) 来自法国的一组研究人员开发了第一个三向混合量子惯性传感器,它可以在不使用卫星信号的情况下测量加速度。这个突破性设备的核心是“物质波干涉…

传统目标跟踪——MeanShift算法

目录 一、均值漂移(MeanShift) 二、流程 三、代码 3.1 meanshift+固定框的代码 3.2 优化:meanshift鼠标选择 3.3 meanshift自己实现函数 四、补充知识 4.1 直方图 4.2 归一化 4.3 直方图反投影 一、均值漂移(…

Maven 教程

Maven 教程 Maven 翻译为"专家"、“内行”,是 Apache 下的一个纯 Java 开发的开源项目。基于项目对象模型(缩写:POM)概念,Maven利用一个中央信息片断能管理一个项目的构建、报告和文档等步骤。 Maven 是一…

手把手教你阿里云服务器的购买及环境搭建

1.服务器相关 程序员都需要一个自己的服务器! 用于发布自己的网站和项目!用于操作系统的练习!将自己的远程仓库、远程数据库、远程tomcat… 搭建在服务器上!用于Linux进行任意的环境部署操作! 服务器如何购买 若果你没超过24岁&am…

【Bp2Lua】多返回值和Out参数说明

【Bp2Lua】多返回值和Out参数说明 这块比较繁琐,有四部分需要了解: U蓝图LuaUnLua 最后再解释 Bp2Lua 如何处理,以及后续潜在的风险 Bp2Lua 如何处理 先说结论 统一当作多返回值返回特殊处理了 out参数 不在参数列表最后的情况&#xf…

分布式理论之分布式锁

写在前面 在分布式理论之分布式互斥 一文中我们分析了分布式环境中的分布式互斥问题,其中解决该问题有如下的三种方案: 1:集中式算法 2:分布式算法 3:令牌环算法而本文要分析的分布式锁,就是其中的算法1,…

折腾了我一周,原来Netty网络编程就是这么个破玩意儿!!!

1、阻塞 阻塞模式下,相关方法都会导致线程暂停 ServerSocketChannel.accept 会在没有连接建立时让线程暂停SocketChannel.read 会在通道中没有数据可读时让线程暂停阻塞的表现其实就是线程暂停了,暂停期间不会占用 cpu,但线程相当于闲置 单线…

flowable学习笔记(四):动态多实例

1.定义流程模板 【测试用户任务多实例】任务节点配置了以下属性: 集合(多实例):userList。这个创建流程实例时入参需要加上这个参数。 元素变量(多实例):user。工作流创建多实例时会将集合(多实例)的值拆分成元素变量(多实例),这个…

Git复习,GitHub\Gitee的使用,IDEA集成Git

今天想把自己的课设上传到GitHub,因为长久不用,Git的命令忘得差不多了,所以今天把Git重新学一遍。 文章目录Git的介绍Git的安装Git的常用命令工作机制常用命令用户签名初始化本地库查看本地库状态添加暂存区提交本地库查看引用日志信息修改文…

Python常用函数笔记汇总2

1.分组汇总groupby 2.计算空值 # py计算空值 data.isnull().sum(axis0) data.notnull().sum(axis0)# py去重计数 data_op[id_num_op].value_counts().size data_op[id_num_op].size3.保留两位小数 # predict_proba保留两位小数 gnb GaussianNB() pre gnb.fit(X_train,y_tr…