• 数学运算与算子

  作为PyTorch中执行深度学习的基本数据类型,张量(Tensor)也拥有非常多的数学运算函数和方法,以及对应的一系列计算规则。在PyTorch中,能够作用与Tensor的运算,被统一称作为算子。并且相比于NumPy,PyTorch给出了更加规范的算子(运算)的分类,从而方便用户在不同场景下调用不同类型的算子(运算)。

  • 数学运算的分类
    PyToch总共为Tensor设计了六大类数学运算,分别是:

    • 1.逐点运算(Pointwise Ops):指的是针对Tensor中每个元素执行的相同运算操作;
    • 2.规约运算(Reduction Ops):指的是对于某一张量进行操作得出某种总结值;
    • 3.比较运算(Comparison Ops):指的是对多个张量进行比较运算的相关方法;
    • 4.谱运算(Spectral Ops):指的是涉及信号处理傅里叶变化的操作;
    • 5.BLAS和LAPACK运算:指的是基础线性代数程序集(Basic Linear Algeria Subprograms)和线性代数包(Linear Algeria Package)中定义的、主要用于线性代数科学计算的函数和方法;
    • 6.其他运算(Other Ops):其他未被归类的数学运算。

  由于谱运算(Spectral Ops)前期不会涉及,而要理解傅里叶变换本身需要更多额外的数学基础,而很多其他运算,我们在前面介绍张量的基本方法时已经介绍,因此接下来将主要围绕逐点运算、规约运算、比较运算和线性代数运算四块进行讲解,而线性代数部分由于涉及到大量的数学内容,因此将放在Lesson 4中单独进行讲解。

import torch
import numpy as np

关于数学运算的另一种分类方法,是根据运算使用场景进行分类,如基础数学运算、数理统计运算等。由于PyTorch官网是按照六类算子进行的分类,因此本节将结合两种分类方法进行讲解。

一、张量的广播(Broadcast)特性

  在具体介绍张量的运算操作之前,我们先要了解张量的运算规则,其中最重要的一点,就是张量具备和NumPy相同的广播特性,也就是允许不同形状的张量之间进行计算。

1.相同形状的张量计算

  根据官网说法,“same shapes are always broadcastable”,相同形状数组总是可以进行广播计算。这里简单强调一下,虽然我们往往觉得不同形状之间的张量计算才是应用到广播特性,但其实相同形状的张量计算,尽管是对应位置元素进行计算,但本质上也是应用到了广播特性。

t1 = torch.arange(3)
t1
#tensor([0, 1, 2])t1 + t1                      # 对应位置元素依次相加
#tensor([0, 2, 4])

思考:如果是两个list相加,是什么结果?

2.不同形状的张量计算

  广播的特性是在不同形状的张量进行计算时,一个或多个张量通过隐式转化,转化成相同形状的两个张量,从而完成计算的特性。但并非任何两个不同形状的张量都可以通过广播特性进行计算,因此,我们需要了解广播的基本规则及其核心依据。

2.1 标量和任意形状的张量

  标量可以和任意形状的张量进行计算,计算过程就是标量和张量的每一个元素进行计算。

t1 + 1                                     # 1是标量,可以看成是零维
#tensor([1, 2, 3])# 二维加零维
t1 + torch.tensor(1)
#tensor([1, 2, 3])t2 = torch.zeros((3, 4))
t2
#tensor([[0., 0., 0., 0.],
#        [0., 0., 0., 0.],
#        [0., 0., 0., 0.]])t2 + 1
#tensor([[1., 1., 1., 1.],
#        [1., 1., 1., 1.],
#        [1., 1., 1., 1.]])

2.2 相同维度、不同形状的张量之间计算

  对于不同形状的张量计算,我们首先需要回顾张量的形状属性,并深化对其的理解。

  首先,我们都知道,张量的形状可以用.shape属性查看

t2.shape
#torch.Size([3, 4])

对于返回结果,我们可以看成是一个序列,代表着张量各维度的信息。当然,对于二维张量,由于我们可以将其视作一个矩阵,因此我们可以说t2是一个拥有三行四列的二维张量,但这种理解方式对于更高维度张量就存在一定的局限,因此我们需要树立另外一种理解方法,那就是:t2是由3个一维张量组成,并且该一维张量、每个都包含四个元素。类似的,我们可以创建更高维度张量并对其形状进行解释。

t3 = torch.zeros(3, 4, 5)
t3
#tensor([[[0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.]],
#
#        [[0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.]],
#
#        [[0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.]]])t3.shape
#torch.Size([3, 4, 5])

我们可以将t3解释为:t3是3个二维张量组成了三维张量,并且这些每个二维张量,都是由四个包含五个元素的一维张量所组成。由二维拓展至三维,即可拓展至N维。

接下来,我们以t2为例,来探讨相同维度、不同形状的张量之间的广播规则。

t2
#tensor([[0., 0., 0., 0.],
#        [0., 0., 0., 0.],
#        [0., 0., 0., 0.]])t2.shape
#torch.Size([3, 4])t21 = torch.ones(1, 4)
t21
#tensor([[1., 1., 1., 1.]])

t21的形状是(1, 4),和t2的形状(3, 4)在第一个分量上取值不同,但该分量上t21取值为1,因此可以广播,也就可以进行计算

t21 + t2
#tensor([[1., 1., 1., 1.],
#        [1., 1., 1., 1.],
#        [1., 1., 1., 1.]])

而t21和t2的实际计算过程如下:

注意理解:此处的广播相当于将t21的形状(1, 4)拓展成了t2的(3, 4),也就是复制了第一行三次,然后二者进行相加。当然,也可以理解成t21的第一行和t2的三行分别进行了相加。

t22 = torch.ones(3, 1)
t22
#tensor([[1.],
#        [1.],
#        [1.]])t2
#tensor([[0., 0., 0., 0.],
#        [0., 0., 0., 0.],
#        [0., 0., 0., 0.]])t2.shape
#torch.Size([3, 4])t22 + t2              # 形状为(3,1)的张量和形状为(3,4)的张量相加,可以广播
#tensor([[1., 1., 1., 1.],
#        [1., 1., 1., 1.],
#        [1., 1., 1., 1.]])

t2和t22实际计算过程如下:

t23 = torch.ones(2, 4)
t23.shape
#torch.Size([2, 4])t2.shape
#torch.Size([3, 4])'''注:此时t2和t23的形状第一个分量维度不同,但二者取值均不为1,因此无法广播'''
t2 + t23
---------------------------------------------------------------------------
#RuntimeError                              Traceback (most recent call last)
#<ipython-input-21-994547ec6516> in <module>
#----> 1 t2 + t23
#
#RuntimeError: The size of tensor a (3) must match the size of tensor b (2) at non-#singleton dimension 0
t24 = torch.arange(3).reshape(3, 1)
t24
#tensor([[0],
#        [1],
#        [2]])t25 = torch.arange(3).reshape(1, 3)
t25
#tensor([[0, 1, 2]])'''此时,t24的形状是(3, 1),而t25的形状是(1, 3),二者的形状在两个份量上均不相同,但都有存在1的情况,因此也是可以广播的'''
t24 + t25
#tensor([[0, 1, 2],
#        [1, 2, 3],
#        [2, 3, 4]])

二者计算过程如下:

 三维张量的广播

t3 = torch.zeros(3, 4, 5)
t3
#tensor([[[0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.]],
#
#        [[0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.],
#        [0., 0., 0., 0., 0.]],
#
#        [[0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.],
#         [0., 0., 0., 0., 0.]]])t31 = torch.ones(3, 4, 1)
t31
#tensor([[[1.],
#         [1.],
#         [1.],
#         [1.]],
#
#        [[1.],
#         [1.],
#         [1.],
#         [1.]],
#
#        [[1.],
#         [1.],
#         [1.],
#         [1.]]])t3 + t31
#tensor([[[1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.]],
#
#        [[1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.]],
#
#        [[1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.]]])t32 = torch.ones(3, 1, 5)
t32
#tensor([[[1., 1., 1., 1., 1.]],
#
#        [[1., 1., 1., 1., 1.]],
#
#        [[1., 1., 1., 1., 1.]]])t32 + t3
#tensor([[[1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.]],
#
#        [[1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.]],
#
#        [[1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.]]])

两个张量的形状上有两个分量不同时,只要不同的分量仍然有一个取值为1,则仍然可以广播

t3.shape
#torch.Size([3, 4, 5])t33 = torch.ones(1, 1, 5)
t33
#tensor([[[1., 1., 1., 1., 1.]]])t3 + t33
#tensor([[[1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.]],
#
#        [[1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.]],
#
#        [[1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.],
#         [1., 1., 1., 1., 1.]]])

t3和t33计算过程如下

注:此处标注的两次广播,我们也可认为上述全部过程的实现是一次“大的”广播。同时,此处最开始的t33也就相当于一个一维的、包含五个元素的张量,因此上述过程也可视为一个一维张量和一个三维张量计算时的广播过程。

2.3 不同维度的张量计算过程中广播

  在理解相同维度、不同形状的张量广播之后,对于不同维度的张量之间的广播其实就会容易很多,因为对于不同维度的张量,我们首先可以将低维的张量升维,然后依据相同维度不同形状的张量广播规则进行广播。而低维向量的升维也非常简单,只需将更高维度方向的形状填充为1即可,例如:

# 二维张量转化为三维张量
t2 = torch.arange(4).reshape(2, 2)
t2
#tensor([[0, 1],
#        [2, 3]])# 转化为三维张量
t2.reshape(1, 2, 2)
#tensor([[[0, 1],
#         [2, 3]]])
'''转化之后表示只包含一个二维张量的三维张量,且二维张量就是t2'''# 转化为四维张量
t2.reshape(1, 1, 2, 2)
#tensor([[[[0, 1],
#          [2, 3]]]])
'''转化之后表示只包含一个三维张量的四维张量,且三维张量只包含一个二维张量,且二维张量就是t2'''t3 = torch.zeros(3, 2, 2)
'''t3和t2的计算过程,就相当于形状为(1,2,2)和(3,2,2)的两个张量进行计算'''t3 + t2
#tensor([[[0., 1.],
#         [2., 3.]],
#
#        [[0., 1.],
#         [2., 3.]],
#
#        [[0., 1.],
#         [2., 3.]]])t3 + t2.reshape(1, 2, 2)
#tensor([[[0., 1.],
#         [2., 3.]],
#
#        [[0., 1.],
#         [2., 3.]],
#
#        [[0., 1.],
#         [2., 3.]]])

思考:形状为(2,1)的张量和形状为(3,2,3)的张量可以进行广播计算么?计算过程是怎样的?

二、逐点运算(Pointwise Ops)

  PyTorch中逐点运算大部分都是可以针对Tensor中每个元素都进行的数学科学运算,并且都是较为通用的数学科学运算,和NumPy中针对Array的科学运算类似。在PyTorch中文文档中有全部运算符的相关介绍,此处仅针对常用计算函数进行介绍。
  逐点运算主要包括数学基本运算、数值调整运算和数据科学运算三块,相关函数如下:

Tensor基本数学运算

t1 = torch.tensor([1, 2])
t1
#tensor([1, 2])t2 = torch.tensor([3, 4])
t2
#tensor([3, 4])torch.add(t1, t2)
#tensor([4, 6])t1 + t2
#tensor([4, 6])t1 / t2
#tensor([0.3333, 0.5000])

Tensor数值调整函数

t = torch.randn(5)
t
#tensor([ 1.1971,  1.7523,  1.5678, -2.2227, -0.3082])torch.round(t)
#tensor([ 1.,  2.,  2., -2., -0.])torch.abs(t)
#tensor([1.1971, 1.7523, 1.5678, 2.2227, 0.3082])torch.neg(t)
#tensor([-1.1971, -1.7523, -1.5678,  2.2227,  0.3082])'''注:虽然此类型函数是数值调整函数,但并不会对原对象进行调整,而是输出新的结果。'''
t                # t本身并未发生变化
#tensor([ 1.1971,  1.7523,  1.5678, -2.2227, -0.3082])

而若要对原对象本身进行修改,则可考虑使用方法_()的表达形式,对对象本身进行修改。此时方法就是上述同名函数。

t.abs_()
#tensor([1.1971, 1.7523, 1.5678, 2.2227, 0.3082])t
#tensor([1.1971, 1.7523, 1.5678, 2.2227, 0.3082])t.neg_()
#tensor([-1.1971, -1.7523, -1.5678, -2.2227, -0.3082])t
#tensor([-1.1971, -1.7523, -1.5678, -2.2227, -0.3082])'''除了上述数值调整函数有对应的同名方法外,本节介绍的许多科学计算都有同名方法。'''
t.exp_()
#tensor([0.3021, 0.1734, 0.2085, 0.1083, 0.7348])t
#tensor([0.3021, 0.1734, 0.2085, 0.1083, 0.7348])

Tensor常用科学计算

  • tensor的大多数科学计算只能作用于tensor对象
# 计算2的2次方
torch.pow(2, 2)
#---------------------------------------------------------------------------
#TypeError                                 Traceback (most recent call last)
#<ipython-input-125-89fb35bb773f> in <module>
#      1 # 计算2的2次方
#----> 2 torch.pow(2, 2)
#
#TypeError: pow() received an invalid combination of arguments - got (int, int), #but expected one of:
# * (Tensor input, Tensor exponent, *, Tensor out)
# * (Number self, Tensor exponent, *, Tensor out)
# * (Tensor input, Number exponent, *, Tensor out)torch.pow(torch.tensor(2), 2)
#tensor(4)

理解:相比于Python原生数据类型,张量是一类更加特殊的对象,例如张量可以指定运行在CPU或者GPU上,因此很多张量的科学计算函数都不允许张量和Python原生的数值型对象混合使用。

  • tensor的大多数科学运算具有一定的静态性

  所谓静态性,指的是对输入的张量类型有明确的要求,例如部分函数只能输入浮点型张量,而不能输入整型张量。

t = torch.arange(1, 4)
t.dtype
#torch.int64torch.exp(t)
#tensor([ 2.7183,  7.3891, 20.0855])

需要注意的是,虽然Python是动态编译的编程语言,但在PyTorch中,由于会涉及GPU计算,因此很多时候元素类型不会在实际执行函数计算时进行调整。此处的科学运算大多数都要求对象类型是浮点型,我们需要提前进行类型转化。

t1 = t.float()
t1
#tensor([1., 2., 3.])torch.exp(t1)
#tensor([ 2.7183,  7.3891, 20.0855])torch.expm1(t1)
#tensor([ 1.7183,  6.3891, 19.0855])

注,此处返回结果是

Lesson 3.张量的广播和科学运算相关推荐

  1. 关于远程桌面链接下调用显卡加速科学运算

    最近由于项目需要,准备购置图形工作站进行CUDA运算,面临一个问题:假设工作站操作系统是windows server 2016,局域网远程连接后能否正常调用显卡做CUDA科学运算?通常认为:既然程序是 ...

  2. Numpy的广播与科学计算

    一.广播计算规则 Numpy所具备的广播特性,可以使得数组的科学计算变得高效而便捷,是NumPy最核大的特色之一. 例如:两个三个元素的数组,在进行减法运算时,每个位置上的元素依次相减. 当然,目前也 ...

  3. Lesson 4.张量的线性代数运算

    也就是PyTorch中BLAS和LAPACK模块的相关运算.   PyTorch中并未设置单独的矩阵对象类型,因此PyTorch中,二维张量就相当于矩阵对象,并且拥有一系列线性代数相关函数和方法.   ...

  4. PyTorch常用的张量创建、变形及运算总结(速查表)

    PyTorch张量常用的创建.变形及数学运算总结 目录 PyTorch张量常用的创建.变形及数学运算总结 1. 张量(tensor)的创建 1.1 torch.Tensor()与torch.tenso ...

  5. 基于Python3的科学运算与常用算法-第1,2章

    第一章 开篇说明写作的中心思想.路线图.内容 本系列是使用Ubuntu 64位操作系统上,anaconda环境下,采用jupyter notebook 实现python3科学计算的文章,应用于青岛科技 ...

  6. 基于Python3的科学运算与常用算法-第4 符号运算

    本系列是使用Ubuntu 64位操作系统上,anaconda环境下,采用jupyter notebook 实现python3科学计算的文章,应用于青岛科技大学信息学院科学计算与数据挖掘等多个课程中py ...

  7. Numpy中的广播和数组运算

    https://www.toutiao.com/a6677441250955624973/ 一.概述 在Numpy中当数组进行运算时,如果两个数组的形状相同,那么两个数组相乘就是两个数组的对应位相乘, ...

  8. Lesson 2.张量的索引、分片、合并以及维度调整

    张量作为有序的序列,也是具备数值索引的功能,并且基本索引方法和Python原生的列表.NumPy中的数组基本一致,当然,所有不同的是,PyTorch中还定义了一种采用函数来进行索引的方式. 而作为Py ...

  9. 爬虫python编程与cvi编程_与爬虫无关,简单的用python进行科学运算

    1.算积分 1.1一重积分 例:如计算半圆的面积,积分公式: # -*- coding:utf-8 -*- from scipy import integrate#输入scipy的integrate函 ...

最新文章

  1. Java程序员常用工具集
  2. jQuery unbind 删除绑定事件 / 移除标签方法
  3. Python编程基础:第五十四节 排序Sort
  4. iptables详解--转
  5. OA应用分析:机电企业如何选型OA系统
  6. QtCreator添加图片资源
  7. 嵌入式常见笔试题总结
  8. Unity打开的文件是杂项文件的处理方法
  9. 服务器安装mysql文档_Linux 服务器安装MySQL数据库
  10. L2-015 互评成绩(排序)
  11. 电路基础知识 -- 虚短和虚断
  12. JavaScript判断数组是否包含某元素
  13. 计算机系统关机后自动重启,小白教你电脑关机后自动重启是什么原因
  14. 涨跌的例题用C语言编辑,基于LSTM的股票涨跌分析-pytorch
  15. 48盘位 云存储服务器_搭建云存储NAS服务器的3个技巧
  16. 【ESP 保姆级教程】疯狂Node.js服务器篇 ——案例:ESP8266 + MQ3酒精传感器 + NodeJs本地服务 + 文件存储数据
  17. Django(静态文件和Django应用和分布式路由)
  18. Unity实时GI与烘焙GI
  19. NatApp免费内网穿透
  20. NOIP2018 NearlyAFO

热门文章

  1. 四年级计算机考试反思,考试后的反思四年级作文
  2. 会员直推奖php程序_PHP自适应卡益源码 前台直销源码 报单费 直推奖 有内部商城...
  3. java 市场_java市场前景怎样?
  4. 不同的PCB混装方式及加工工艺
  5. cla作用matlab,共轭亚油酸(CLA)怎么吃?共轭亚油酸副作用
  6. html页面vertical,vertical.html
  7. Java高阶代码_Java高阶语法---Volatile
  8. EditText控件的基本使用(点击Button按钮,Toast提示EditText中的内容)
  9. elasticsearch python API
  10. 计算机操作系统32跟64区别是什么,32位和64位计算机操作系统之间的区别32位和64位win7系统之间的区别...