torch相比于numpy都干了什么——torch入门

news2024/11/17 16:20:52

Torch已深度学习框架被熟知,但它首先是作为Numpy的存在。我们首先比较一下Torch和Numpy有什么不同,为什么可以实现深度学习。

数据结构看起。Numpy的强大之处就在于array的数据结构,它是多维数组,要求所有元素是相同类型的,这样就可以以矩阵运算代替for循环,提高效率。相比之下,python原生的list支持元素是不同的数据类型,而在实现上list使用了指针的方法从而增加了内存(不连续)和CPU的消耗。

numpy还支持数组与标量的运算,维度不完全一致的数组直接的运算(广播)

#ndarray可与标量直接运算,数组之间也可矢量化运算
a=np.arange(0.0,1,0.1)
print (a+10,type(a))
b=np.arange(10,20,1)
print (a+b)
#ndarray可对维数不同的矢量进行广播计算
a=np.arange(1,4)
b=np.array([[1,2,3],[4,5,6]])
print (a+b)

既然Numpy及其array已经做到了较高的效率,那Pytorch还可以从哪方面改进呢?我们对比一下Tensor和ndarray的区别,发现Tensor复杂多了:

ndarray只保存了最大最小值,shape,size等变量。T

ensor记录了很多和grad相关的变量:_grad,_grad_fn,grad,grad_fn,requires_grad;和GPU相关的变量:device,is_cuda;还有与数据结构有关的:is_leaf,is_sparse。这意味着Pytorch从一开始就是为了深度学习而准备的。

初始化方法

x = torch.tensor([5.5, 3])
x = torch.rand(5, 3)
x = torch.empty(5, 3)
x = torch.zeros(5, 3, dtype=torch.long)

梯度的计算

对于计算图(Computational Graphs),前向传导是很自然的:前一个的输出作为下一个的输入。难点在于如何对梯度反向传播。其实,在forward的过程中可以为backward做一些准备工作:用一个标记位记录每个新产生的输出是通过什么运算得到的,这个标记位就是上文提到的grad_fn。fn表示function,意味着它记录了计算函数,所以在反向求导时就可以对应求导。事实上,grad_fn的取值有:MeanBackward0,SumBackward0,MulBackward0,AddBackward0.

执行loss.backward(),开始反向传播,对于变量w,w.grad就是loss对于w的偏导。注意,在这之前我们需要把w记录梯度的开关打开:设置它的属性 .requires_grad 为 True,那么autograd将会追踪对于该张量的所有操作。但这个条件只是必要条件而非充分条件,即便是requires_grad=True时,该变量的grad仍然可能为None。这就涉及到tensor中的is_leaf概念,只有当同时满足requires和is_leaf都是True时才记录梯度。叶子节点与非叶子节点的区别在这里就是网络参数和中间变量的区别。网络参数是我们初始化的,也是最关心的需要训练得到的,而中间变量是训练过程中由其他变量计算得到的,只起到桥梁的作用,没必要保存下来而浪费内存。

注意loss.backward()这个函数,一般情况下不必传入任何参数,这是因为一般模型对应的loss都是标量;当loss是多维的,则需要在backward()中指定一个gradient参数,它是形状匹配的张量。

为了搞清楚backward()的参数为什么这么奇怪,我们需要知道它到底计算的是什么。

梯度其实是一阶导,这就需要计算出雅克比矩阵。对于\vec{y}=f(\vec{x})

J=\begin{pmatrix} \frac{\partial y_1}{\partial x_1}& ...& \frac{\partial y_1}{\partial x_n} \\ ... & ... & ...\\ \frac{\partial y_m}{\partial x_1} & ... & \frac{\partial y_m}{\partial x_n} \end{pmatrix}

但其实backward()计算的是雅克比向量积。因为element-wise运算机制,雅克比矩阵表征的是y在各个维度对x各个维度的偏导,为了得到dY,需要将关于x_i的偏导数在v反向上进行投影(也可以理解为加权的过程)。而投影的结果就是雅克比向量积,它其实利用了求导的链式法则。标量函数l=g(\vec{y}),为了得到l对x的偏导,可以使用雅克比矩阵与l相对于\vec{y}的偏导的向量积:

J^T \dot v=\begin{pmatrix} \frac{\partial y_1}{\partial x_1}& ...& \frac{\partial y_1}{\partial x_n} \\ ... & ... & ...\\ \frac{\partial y_m}{\partial x_1} & ... & \frac{\partial y_m}{\partial x_n} \end{pmatrix}\begin{pmatrix} \frac{\partial l}{\partial y_1} \\ ... \\ \frac{\partial l}{\partial y_n} \end{pmatrix}=\begin{pmatrix} \frac{\partial l}{\partial x_1} \\ ... \\ \frac{\partial l}{\partial x_n} \end{pmatrix}

现在我们可以解释backward()这个函数中的参数了,当loss是标量时,相当于v是一个全1数组,因此 out.backward() 和 out.backward(torch.tensor(1.)) 等价,这也解释了反向传播到x时各个维度的结果一样;当loss是多维的向量,可以人为构造一个标量函数l,l对loss的偏导作为v传入backward()。刚才也提到,v可以理解为权重向量或者投影向量,官方叫法是easy feed external gradient(grad_variables),要求它的大小与向量函数的个数对应:

The graph is differentiated using the chain rule. If any of variables are non-scalar (i.e. their data has more than one element) and require gradient, the function additionally requires specifying grad_variables. It should be a sequence of matching length, that contains gradient of the differentiated function w.r.t. corresponding variables (None is an acceptable value for all variables that don’t need gradient tensors).

这样设计的原因是为了避免tensor对tensor求导的问题,只允许标量scalar对张量tensor求导,结果是和自身tensor维度一样的tensor。如果loss是多维的,那么就会根据用户提供的v构造l=torch.sum(y,v),v同时就是l对y的导数。

当不想跟踪变量的梯度时,不必逐个更改requires_grad属性,可以将整个代码段放在with torch.no_grad()中:

with torch.no_grad():
    print((x ** 2).requires_grad)

backward()在计算图中计算,而pytorch的计算图是动态的,在backward()之后被释放,所以没办法连续两次backward()。如果你需要多次backward可以在第一次中指定不释放:

loss.backward(retain_graph=True) # 添加retain_graph=True标识,让计算图不被立即释放
loss.backward()

backward()之前要对网络和学习器中记录的梯度清零,否则梯度会累加:

net.zero_grad()     # 清零所有参数(parameter)的梯度缓存
# 创建优化器(optimizer)
optimizer = optim.SGD(net.parameters(), lr=0.01)
optimizer.zero_grad()   # 清零梯度缓存,因为网络参数已经放入优化器,所以在优化器中清除梯度和对网络清除梯度是等效的

对于一个变量,可以使用detach()将其从图中分离开,返回的值不会再要求梯度的计算。

Returns a new Tensor, detached from the current graph.The result will never require gradient.

tensor相比于numpy已经针对网络做了更新,但为了更方便地构建网络,torch又把tensor封装成了variable。操作和Tensor是一样的,但是每个Variable都有三个属性,Varibale的Tensor本身的.data,对应Tensor的梯度.grad,以及这个Variable是通过什么方式得到的.grad_fn。

Reference:

1.PyTorch 的 Autograd - 知乎

2.https://pytorch.apachecn.org/docs/1.4/blitz/tensor_tutorial.html

3.backwardhttps://www.cnblogs.com/JeasonIsCoding/p/10164948.html

4.pytorch中backward()函数详解_Camlin_Z的博客-CSDN博客_backward()

5.githubGitHub - pytorch/pytorch: Tensors and Dynamic neural networks in Python with strong GPU acceleration

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

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

相关文章

人与人之间赚钱的差距在哪里呢?体现在这几个因素中

同样生而为人,同样接受九年制义务教育的熏陶,但最终赚钱能力却千差万别,因此也就形成了我们所谓的圈层,阶层,穷人和富人。 一个人的赚钱能力跟什么有关?资源技能、学历、认知,这些都会决定一个人…

搞清楚动态库和静态库的区别

什么是库文件 一般来说,一个程序,通常都会包含目标文件和若干个库文件。经过汇编得到的目标文件再经过和库文件的链接,就能构成可执行文件。库文件像是一个代码仓库或代码组件的集合,为目标文件提供可直接使用的变量、函数、类等…

visual studio 改变界面语言

在使用visual studio 2019 时,开始是英文界面,后面变成了中文界面。但是看视频教学时有的是英文界面,我就想回到英文界面,所以有切换界面语言的需要。其实操作很简单:工具-> 选项 打开界面在界面里选择环境&#xf…

axios中的resolvePromise为什么影响promise状态

axios的取消请求意思很简单,就是在发送请求后不久停止发送请求 本文探讨的是v0.22.0之前的CancelToken API,因为在阅读源码交流的时候发现很多朋友不理解为什么CancelToken中的resolvePromise会影响到实例对象身上的promise状态 即下图所示代码&#xf…

为乡村振兴塑形铸魂,VR全景助力美丽乡村建设

民族要复兴,乡村必振兴,文旅部一直推动乡村文化产业和乡村旅游融合发展,大力推进乡村文化数字化,为乡村文化振兴注入新动能。为了更好的给乡村振兴塑形铸魂,VR智慧乡村助力数字化乡村建设发展,利用VR全景展…

CMD SET % 字符串截取

:: 使用 CSDN Cobol 格式化风格。:: *. 百分号 (%) :: (1) % 作为变量引导符,有几种用途:在命令行窗口中,用 1 个 % 引号变量; 在批处理文件中,用 2 个 % 引号变量。[1] 两个 % 夹着一个变量名称,表示取(扩…

HashMap如何避免内存泄露问题

HashMap对于Java开发人员来说,应该是一种非常非常熟悉的数据结构了,应用场景相当广泛。 本文重点不在于介绍如何使用HashMap,而是关注在使用HashMap过程中,可能会导致内存泄露的情况,下面将以示例的形式展开具体介绍。…

【Java】properties 和 yml 的区别

文章目录properties和yml的区别① 定义和定位不同② 语法不同③ yml更好的配置多种数据类型④ yml可以跨语言⑤ 总结properties和yml的区别 这几天刚好看到Spring Boot当中有两种配置文件的方式,但是这两种配置方式有什么区别呢? properties和yml都是S…

hadoop考试应急

概述 四大特点:大量化、快速化、多元化、价值化 关键技术:采集、存储管理、处理分析、隐私和安全 计算模式:批处理、流、图、查询分析计算 Hadoop处理架构 了解就好 2007年,雅虎在Sunnyvale总部建立了M45——一个包含了4000…

Leetcode 每日一题 2341. 数组能形成多少数对

Halo,这里是Ppeua。平时主要更新C语言,C,数据结构算法......感兴趣就关注我吧!你定不会失望。 🌈个人主页:主页链接 🌈算法专栏:专栏链接 我会一直往里填充内容哒! &…

《Java并发编程之美》- 线程终止的方法

多线程并发编程之美 等待线程执行终止的 join 方法 执行的代码 public class MyThreadThree {public static void main(String[] args) throws InterruptedException {Thread thread_anew Thread(()->{try {Thread.sleep(1000);} catch (InterruptedException e) {e.prin…

信息系统项目管理师真题精选(三)

1、以下关于我国现阶段电子政务建设的叙述中,不正确的是:( )。A.我国电子政务建设一直坚持统一规划,加强领导,需求主导,突出重点的原则B.我国电子政务建设一直坚持整合资源,拉动产业…

静态代理和动态代理的区别以及实现过程

前言 代理模式是一种设计模式,能够使得在不修改源目标的前提下,额外扩展源目标的功能。即通过访问源目标的代理类,再由代理类去访问源目标。这样一来,要扩展功能,就无需修改源目标的代码了。只需要在代理类上增加就可…

《真象还原》读书笔记——第五章 保护模式进阶,向内核迈进(特权级,更新)

5.4 特权级深入浅出 5.4.1 特权级哪点事 计算机 访问 可分为访问者和被访问者。 建立特权机制为了通过特权来检查合法性。 0、1、2、3级,数字越小,权力越大。 0特权级是系统内核特权级。 用户程序是3特权级,被设计为“有需求就找操作系统”…

QT+OpenGL光照

QTOpenGL光照 本篇完整工程见gitee:QtOpenGL 对应点的tag,由turbolove提供技术支持,您可以关注博主或者私信博主 颜色 现实生活中看到的物体的颜色并不是这个物体真正拥有的颜色,而是它所反射的颜色 太阳光能被看见的白光是多找演的的组合…

Linux部署项目

一、手动部署 1、终端直接部署(前台运行) (1)在IDEA中开发SpringBoot项目并打成jar包 (2)将jar包上传到Linux服务器 mkdir /usr/local/app #创建目录,将项目jar包放到此目录(3&…

C++——哈希4|布隆过滤器

目录 布隆过滤器 完整代码 布隆过滤器应用 布隆过滤器的查找 布隆过滤器删除 布隆过滤器优点 布隆过滤器缺陷 布隆过滤器海量数据处理 布隆过滤器 位图只能映射整形,而对于字符串却无能为力。 把字符串用哈希算法转成整形,映射一个位置进行标…

Axure教程(一)——线框图与高保真原型图制作

前面我们学习了制作网页的技能,从这里开始我们来学习前端必备技能,就是用Axure来制作原型图,一方面我们能提前绘制出我们所需的页面,这在我们开发的时候能节省大量的时间,另一方面我们能通过给用户进行体验从而能够发现…

robotframework + selenium自动化测试常见的问题

1、 插入中文数据提示 FAIL UnicodeEncodeError: ‘latin-1’ codec can’t encode characters in position 92-107: ordinal not in range(25 DataBaseLibrary插入中文乱码的解决:修改D:\Python27\Lib\site-packages\DatabaseLibrary\connection_manager.py里的co…

极客大挑战 2021

题量很大,收获挺多,持续时间也长,据说结束之后会再持续一段时间,然后题目会开源。 WEB Dark 暗网签到,难以置信 Welcome2021 改个请求方法会提示你文件,再进去就好了 babysql 直接把请求包扔sqlmap里&…