深度学习-07-反向传播的自动化

深度学习-07-反向传播的自动化


本文是《深度学习入门2-自製框架》 的学习笔记,记录自己学习心得,以及对重点知识的理解。如果内容对你有帮助,请支持正版,去购买正版书籍,支持正版书籍不仅是尊重作者的辛勤劳动,也是鼓励更多优秀作品问世。

当前笔记内容主要为:步骤7 反向传播的自动化 章节的相关理解。

书籍总共分为5个阶段,每个阶段分很多步骤,最终是一步一步实现一个深度学习框架。例如前两个阶段为:

第 1 阶段共包括 10 个步骤 。 在这个阶段,将创建自动微分的机制
第 2 阶段,从步骤11-24,该阶段的主要目标是扩展当前的 DeZero ,使它能够执行更复杂的计算 ,使它能 够处理接收多个输入的函数和返回多个输出的函数


1.为反向传播的自动化创造条件

之前我们在实现反向传播的时候,我们是手动编写进行反向传播计算的代码,这意味着我们每次都要编写这些代码。例如下面的:

    A = Square()
    B = Exp()
    C = Square()

    x = Variable(np.array(0.5))
    a = A(x)
    b = B(a)
    y = C(b)

    y.grad = np.array(1.0)
    b.grad = C.backward(y.grad)
    a.grad = B.backward(b.grad)
    x.grad = A.backward(a.grad)
    print(x.grad)

如果计算图不一样,那么我们每次就需要白那些不一样的代码来计算反向传播。

图:不同计算图的例子。

那我们就开始思考如果自动化这块内容?书中讲解了一种机制:无论普通的计算流程(正向传播)中是什么样的计算,反向传播都能 自动进行 。这里引入一个概念:Define- by-Run。
Define-by-Run;是在深度学习中进行计算时 ,在计算之间建立"连接"的机 制 。 这种机制也称为动态计算图


计算图都是流水线式的计算 。 因此,只要以列表的形式记录函数的顺序,就可以通过反向回溯自动进行反向传播
    
    
在实现反向传播的自动化之前,我们先思考一下变量和函数之间的关系。解决方案主要从这里入手。我们需要考察变量和函数的关系并且用代码表示出来。

函数的变量包括"输入变量 "(input) 和"输出变量"(output)。函数是变量的 "父母" 如果没有父母,说明这个变量是用户的输入变量。

修改Variable 定义,函数和变量之间的"连接,让这个"连接"在执行普通计算(正向传播)的那一刻创建。

class Variable:def __init__(self, data):self.data = dataself.grad = Noneself.creator = Nonedef set_creator(self,func):self.creator = func

上面代码,定义了熟悉 creator 标识是那个函数。并且定义了set 方法,来进行变量与函数之间的关联。

修改 Function 定义:

class Function:def __call__(self, input):x = input.datay = self.forward(x)output = Variable(y)output.set_creator(self)  # 输出者保存创造者对象self.input = inputself.output = output  # 保存输出者。我是创造者的信息,这是动态建立 "连接"这 一 机制的核心return outputdef forward(self, x):raise NotImplementedError()  # 使用Function  这个方法forward 方法的人 , 这个方法应该通过继承采实现def backward(self, gy):raise NotImplementedError()


在函数执行时,就设置输出变量的 creator 为”自己“。并且将输出保存起来。

经过上面的操作后,变量和函数之间建立的联系,并且这两种联系的建立时代码执行过程中创建的。

有了连接,我们手动检查下,计算下反向遍历计算图  

    A = Square()B = Exp()C = Square()x = Variable(np.array(0.5))a = A(x)b = B(a)y = C(b)assert y.creator == Cassert y.creator.input == bassert y.creator.input.creator == Bassert y.creator.input.creator.input == aassert y.creator.input.creator.input.creator == Aassert y.creator.input.creator.input.creator.input == x

没有抛出异常,这意味着 assert 语句的所有条件都得到了满足。


2.尝试反向传播

利用上面的变量与函数之间的关系。进行反向传播计算。

先 y ---> b 

    y.grad = np.array(1.0)C = y.creator  # 获取函数b = C.input     # 获取函数的输入b.grad = C.backward(y.grad)    # 调用函数的backward 方法

然后  b ---> a
    
 

    B = b.creatorb = B.inputa.grad = B.backward(b.grad)

最后  a----> x 

    A = a.creatorx = A.inputx.grad = A.backward(a.grad)print(x.grad)


    
其实每一步的规律是:
1 获取函数 
2 获取函数的输入 
3 调用函数的 backward 方法


最后执行的结果为  
3.29744

3.增加backward 方法

前面这些反向传播的代码可以看山,它们有着相同的处理流程准确 来说,是从一个变量到前一个变量的反向传播逻辑相同。

修改Variable 类,增加一个新的方法-backward 


class Variable:def __init__(self, data):self.data = dataself.grad = Noneself.creator = Nonedef set_creator(self,func):self.creator = funcdef backward(self):f = self.creator  # 获取函数if f is not None:x = f.input # 获取函数的输入x.grad =f.backward(self.grad) # 调用函数的backward() 方法x.backward()  # 调用自己前面的那个变量的 backward()方法
4.项目代码
'''
step07.py
自动实现反向传播'''import numpy as npclass Variable:def __init__(self, data):self.data = dataself.grad = Noneself.creator = Nonedef set_creator(self,func):self.creator = funcdef backward(self):f = self.creator  # 获取函数if f is not None:x = f.input # 获取函数的输入x.grad =f.backward(self.grad) # 调用函数的backward() 方法x.backward()  # 调用自己前面的那个变量的 backward()方法class Function:def __call__(self, input):x = input.datay = self.forward(x)output = Variable(y)output.set_creator(self)  # 输出者保存创造者对象self.input = inputself.output = output  # 保存输出者。我是创造者的信息,这是动态建立 "连接"这 一 机制的核心return outputdef forward(self, x):raise NotImplementedError()  # 使用Function  这个方法forward 方法的人 , 这个方法应该通过继承采实现def backward(self, gy):raise NotImplementedError()class Square(Function):def forward(self, x):y = x ** 2return ydef backward(self, gy):x= self.input.datagx = 2 * x * gy     #方法的参数 gy 是 一个 ndarray 实例 , 它是从输出传播而来的导数 。return gxclass Exp(Function):def forward(self, x):y = np.exp(x)return ydef backward(self, gy):x = self.input.datagx = np.exp(x) * gyreturn gxif __name__ == '__main__':A = Square()B = Exp()C = Square()x = Variable(np.array(0.5))a = A(x)b = B(a)y = C(b)assert y.creator == Cassert y.creator.input == bassert y.creator.input.creator == Bassert y.creator.input.creator.input == aassert y.creator.input.creator.input.creator == Aassert y.creator.input.creator.input.creator.input == x# 反向传播y.grad = np.array(1.0)C = y.creator  # 获取函数b = C.input     # 获取函数的输入b.grad = C.backward(y.grad)    # 调用函数的backward 方法B = b.creatorb = B.inputa.grad = B.backward(b.grad)A = a.creatorx = A.inputx.grad = A.backward(a.grad)print(x.grad)# 自动反向传播x = Variable(np.array(0.5))a = A(x)b = B(a)y = C(b)y.grad = np.array(1.0)y.back()print(x.grad)
5.总结

经过此小节的代码丰富,目前我们可以执行自动反向传播计算。

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

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

相关文章

OJ题目【栈和队列】

题目导入 栈: 题目一:有效的括号题目二:用栈实现队列 队列 题目:实现循环队列 栈 题目一 有效的括号 题目要求 给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘…

LeetCode746使用最小花费爬楼梯

题目描述 给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。请你计算并返回达到楼梯顶部的最低花费。 解析 动态…

七校联赛题铅笔姿态及笔迹检测装置--mpu6050识别数字

前言 前几天打完比赛,收获还是挺大的,数字识别部分基本上浪费了绝大部分时间。先将思路简单说明。 1、题目 2、思路 针对笔迹检测,我们首先考虑的肯定是陀螺仪来测量加速度方向来判断书写的方向,从而得到书写的数字。 我们的方案…

LLM的基础模型3:Transformer变种

大模型技术论文不断,每个月总会新增上千篇。本专栏精选论文重点解读,主题还是围绕着行业实践和工程量产。若在某个环节出现卡点,可以回到大模型必备腔调或者LLM背后的基础模型新阅读。而最新科技(Mamba,xLSTM,KAN)则提…

【软件测试】自动化测试如何管理测试数据

前言 在之前的自动化测试框架相关文章中,无论是接口自动化还是UI自动化,都谈及data模块和config模块,也就是测试数据和配置文件。 随着自动化用例的不断增加,需要维护的测试数据也会越来越多,维护成本越来越高&#…

编译 freetype、sdl、sdl_ttf

/* * three lib */ /* 字符串生成位图 */ http://www.libsdl.org/projects/SDL_ttf/release/ http://www.libsdl.org/download-1.2.php https://freetype.org/ /* Freetype 2.13.0 */ ./configure CCaarch64-v01c01-linux-gnu-gcc --buildaarch64 …

一个简约而不简单的记账 App(一刻记账)

前言 在两年多前, 我曾经写过一个本地化的记账 App, 当时没有想过以后的发展. 全程是本地化的, 当时主要是为了练习 Compose 而写的. TallyApp 而现在一个完整的记账 App 它来了 一刻记账 算是圆了我两年前的梦了吧. 也让我可以真正的使用自己的记账软件. 下面是 一刻记账 记…

10 -力扣高频 SQL 50 题(基础版)

10 - 每台机器的进程平均运行时间 -- sum(if(activity_type end,timestamp ,-timestamp )) -- 如果activity_type为“end”,值为timestamp,为“start” 为-timestamp,所有数相加end-start -- count(distinct process_id),获取同一机器有几个进行id -- r…

鸿蒙HarmonyOS实战—如何使用Video组件播放视频

1.视频播放 鸿蒙系统中,关于视频播放,可以使用上层视频组件Video。 参数如下 src 支持file:///data/storage路径前缀的字符串,用于读取应用沙箱路径内的资源。需要保证目录包路径下的文件有可读权限。 说明:视频支持的格式是&am…

为何限定项目的 Node.js 版本

首先区分三个概念nvm,npm,nodejs。 Node.js: Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境。它允许开发者使用 JavaScript 在服务器端编写应用程序,而不仅限于在浏览器中运行 JavaScript。Node.js 提供了一系列内置的模块和 API,使得开发…

Python中数字比较与获取较大值的深入解析

目录 一、引言 二、Python数字类型概述 三、数字比较操作符 四、获取较大值的逻辑与实现 五、高级话题:使用内置函数和库 六、性能分析与优化 七、案例分析 八、总结与展望 一、引言 在编程世界中,数字的比较和获取较大值是基础且常见的操作。P…

四川景源畅信:抖音做直播有哪些人气品类?

随着互联网科技的飞速发展,抖音作为新兴的社交媒体平台,已经成为了人们日常生活中不可或缺的一部分。而在抖音平台上,直播功能更是吸引了大量的用户和观众。那么,在抖音上做直播有哪些人气品类呢?接下来,就让我们一起…

目标检测数据集 - 智能零售柜商品检测数据集下载「包含VOC、COCO、YOLO三种格式」

数据集介绍:智能零售柜商品检测数据集,真实智能零售柜监控场景采集高质量商品图片数据,数据集含常见智能零售柜商品图片,包括罐装饮料类、袋装零食类等等。数据标注标签包含 113 个商品类别;适用实际项目应用&#xff…

C++的爬山算法

爬山算法(Hill Climbing Algorithm)是一种局部搜索算法,它通过迭代搜索的方式寻找问题的局部最优解。在爬山过程中,算法总是选择当前状态邻域中最好(即函数值最大或最小)的状态作为下一个状态,直…

直播美颜插件详解:美颜SDK的技术原理

美颜SDK作为实现美颜功能的核心技术,已被广泛应用于各种直播和短视频应用中。那么,美颜SDK究竟是如何工作的?它背后的技术原理又是什么?本文将对直播美颜插件及其技术原理进行详解。 一、美颜SDK的概述 美颜SDK包含了各种图像处…

⌈ 传知代码 ⌋ 微表情识别系统

💛前情提要💛 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间,对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

leetcode74搜索二维矩阵

题目 给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 fa…

培养核心人才,落实IPD体系

IPD体系已经成为业界公认的研发管理优秀框架与实践,不过在企业范围内,真正落实IPD体系、并且取得收益,却并非一件容易的事情,流程体系建立好了,却发现找不到合适人员去落实,任命了相关团队和成员&#xff0…

大文件上传处理:分卷压缩

大文件上传处理:分卷压缩 大文件上传处理:分卷压缩1、分卷压缩(1)Bandizip压缩工具:(2)分卷压缩后: 2、分卷压缩解压3、解压缩工具下载 大文件上传处理:分卷压缩 1、分卷…

第 400 场 LeetCode 周赛题解

A 候诊室中的最少椅子数 计数:记录室内顾客数,每次顾客进入时,计数器1,顾客离开时,计数器-1 class Solution {public:int minimumChairs(string s) {int res 0;int cnt 0;for (auto c : s) {if (c E)res max(res, …