深入浅出PyTorch(算子篇)

Tensor
自从张量(Tensor)计算这个概念出现后,神经网络的算法就可以看作是一系列的张量计算。所谓的张量,它原本是个数学概念,表示各种向量或者数值之间的关系。PyTorch的张量(torch.Tensor)表示的是N维矩阵与一维数组的关系。

torch.Tensor的使用方法和numpy很相似(https://pytorch.org/...tensor-tutorial-py),两者唯一的区别在于torch.Tensor可以使用GPU来计算,这就比用CPU的numpy要快很多。
张量计算的种类有很多,比如加法、乘法、矩阵相乘、矩阵转置等,这些计算被称为算子(Operator),它们是PyTorch的核心组件。
算子的backend一般是C/C++的拓展程序,PyTorch的backend是称为"ATen"的C/C++库,ATen是"A Tensor"的缩写。
Operator
PyTorch所有的Operator都定义在Declarations.cwrap和native_functions.yaml这两个文件中,前者定义了从Torch那继承来的legacy operator(aten/src/TH),后者定义的是native operator,是PyTorch的operator。
相比于用C++开发的native code,legacy code是在PyTorch编译时由gen.py根据Declarations.cwrap的内容动态生成的。因此,如果你想要trace这些code,需要先编译PyTorch。
legacy code的开发要比native code复杂得多。如果可以的话,建议你尽量避开它们。

MatMul
本文会以矩阵相乘--torch.matmul()为例来分析PyTorch算子的工作流程。
我在深入浅出全连接层(fully connected layer)中有讲在GPU层面是如何进行矩阵相乘的。Nvidia、AMD等公司提供了优化好的线性代数计算库--cuBLAS/rocBLAS/openBLAS,PyTorch只需要调用它们的API即可。

Figure 1是torch.matmul()在ATen中的function flow。可以看到,这个flow可不短,这主要是因为不同类型的tensor(2d or Nd, batched gemm or not,with or without bias,cuda or cpu)的操作也不尽相同。
at::matmul()主要负责将Tensor转换成cuBLAS需要的格式。前面说过,Tensor可以是N维矩阵,如果tensor A是3d矩阵,tensor B是2d矩阵,就需要先将3d转成2d;如果它们都是>=3d的矩阵,就要考虑batched matmul的情况;如果bias=True,后续就应该交给at::addmm()来处理;总之,matmul要考虑的事情比想象中要多。
除此之外,不同的dtype、device和layout需要调用不同的操作函数,这部分工作交由c10::dispatcher来完成。
Dispatcher
dispatcher主要用于动态调用dtype、device以及layout等方法函数。用过numpy的都知道,np.array()的数据类型有:float32, float16,int8,int32,.... 如果你了解C++就会知道,这类程序最适合用模板(template)来实现。
很遗憾,由于ATen有一部分operator是用C语言写的(从Torch继承过来),不支持模板功能,因此,就需要dispatcher这样的动态调度器。
类似地,PyTorch的tensor不仅可以运行在GPU上,还可以跑在CPU、mkldnn和xla等设备,Figure 1中的dispatcher4就根据tensor的device调用了mm的GPU实现。
layout是指tensor中元素的排布。一般来说,矩阵的排布都是紧凑型的,也就是strided layout。而那些有着大量0的稀疏矩阵,相应地就是sparse layout。

Figure 2是strided layout的演示实例,这里创建了一个2行2列的矩阵a,它的数据实际存放在一维数组(a.storage)里,2行2列只是这个数组的视图。
stride充当了从数组到视图的桥梁,比如,要打印第2行第2列的元素时,可以通过公式:\(1 * stride(0) + 1 * stride(1)\)来计算该元素在数组中的索引。
除了dtype、device、layout之外,dispatcher还可以用来调用legacy operator。比如说addmm这个operator,它的GPU实现就是通过dispatcher来跳转到legacy::cuda::_th_addmm。

END
到此,就完成了对PyTorch算子的学习。如果你要学习其他算子,可以先从aten/src/ATen/native目录的相关函数入手,从native_functions.yaml中找到dispatch目标函数,详情可以参考Figure 1。
更多精彩文章,欢迎扫码关注下方的公众号, 并访问我的简书博客:https://www.jianshu.com/u/c0fe8671254e
欢迎转发至朋友圈,工作号转载请后台留言申请授权~

深入浅出PyTorch(算子篇)的更多相关文章
- Ascend Pytorch算子功能验证
Ascend Pytorch算子功能验证 编写测试用例 以add算子为例,测试脚本文件命名为:add_testcase.py.以下示例仅为一个简单的用例实现,具体算子的实现,需要根据算子定义进行完整的 ...
- Ascend Pytorch算子适配层开发
Ascend Pytorch算子适配层开发 适配方法 找到和PyTorch算子功能对应的NPU TBE算子,根据算子功能计算出输出Tensor的size,再根据TBE算子原型构造对应的input/ou ...
- Spark算子篇 --Spark算子之aggregateByKey详解
一.基本介绍 rdd.aggregateByKey(3, seqFunc, combFunc) 其中第一个函数是初始值 3代表每次分完组之后的每个组的初始值. seqFunc代表combine的聚合逻 ...
- 深入浅出 RPC - 深入篇
<深入篇>我们主要围绕 RPC 的功能目标和实现考量去展开,一个基本的 RPC 框架应该提供什么功能,满足什么要求以及如何去实现它? RPC 功能目标 RPC 的主要功能目标是让构建分布式 ...
- (转)深入浅出 RPC - 深入篇
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/mindfloating/article/details/39474123 <深入篇>我们 ...
- 深入浅出RPC——深入篇(转载)
本文转载自这里是原文 <深入篇>我们主要围绕 RPC 的功能目标和实现考量去展开,一个基本的 RPC 框架应该提供什么功能,满足什么要求以及如何去实现它? RPC 功能目标 RPC的主要功 ...
- Spark算子篇 --Spark算子之combineByKey详解
一.概念 rdd.combineByKey(lambda x:"%d_" %x, lambda a,b:"%s@%s" %(a,b), lambda a,b:& ...
- 时序数据库深入浅出之存储篇——本质LSMtree,同时 metric(比如温度)+tags 分片
什么是时序数据库 先来介绍什么是时序数据.时序数据是基于时间的一系列的数据.在有时间的坐标中将这些数据点连成线,往过去看可以做成多纬度报表,揭示其趋势性.规律性.异常性:往未来看可以做大数据分析,机器 ...
- spark算子篇-repartition and coalesce
我们知道 RDD 是分区的,但有时候我们需要重新设置分区数量,增大还是减少需要结合实际场景,还有可以通过设置 RDD 分区数来指定生成的文件的数量 重新分区有两种方法:repartition and ...
随机推荐
- android小Demo--圆球跟随手指轨迹移动
eatwhatApp的客户端基本实现,会再后续进行整改,今天做一个在网上找到的小Demo,让屏幕中出现一个圆球,并跟随手指移动. 写个java类DrawView继承于View: public clas ...
- Spring_基于配置文件的方式配置AOP
applicationContext-xml.xml <?xml version="1.0" encoding="UTF-8"?> <bean ...
- MVC案例
MVC案例分析: - 没有业务层,直接Servlet调用Dao,所以也没有业务操作.所有在DAO直接获取Connection对象 -采用MVCDs设计模式 -使用到的技术: mvc设计模式:JSP ...
- Mysql多个字段合并成一个返回
可以使用CONCAT函数进行合并: SELECT CONCAT(IFNULL(t1.CITYNAME,''),IFNULL(t1.AREANAME,''),IFNULL(t1.STREETNAME,' ...
- Java实现蓝桥杯算法提高 哥德巴赫猜想
试题 算法提高 哥德巴赫猜想 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 根据所给函数(判断一个整数是否是素数),然后依托该函数,将输入N内的偶数(6-N),输出为两个素数之和( ...
- Java实现 LeetCode 306 累加数
306. 累加数 累加数是一个字符串,组成它的数字可以形成累加序列. 一个有效的累加序列必须至少包含 3 个数.除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相加的和. 给定一个只包含数字 ...
- Java实现 LeetCode 141 环形链表
141. 环形链表 给定一个链表,判断链表中是否有环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 -1,则在该链表中没有环. ...
- Java实现 LeetCode 127 单词接龙
127. 单词接龙 给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度.转换需遵循如下规则: 每次转换只能改变一个字 ...
- redis基础知识详解
一.redis基础知识 1.Redis是什么Redis是一个开源的key-value存储系统. 和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表 ...
- 总结梳理:webpack中如何使用vue
1. 安装vue的包 cnpm i vue -S 2. 由于在webpack中,推荐使用 .vue这个组件模板文件定义的组件,所以,需要安装, 能解析这个文件的loader: cnpm i vu ...