5分钟玩转PyTorch |熟练掌握Tensor的科学运算与线代运算

Python绿色通道

共 6754字,需浏览 14分钟

 ·

2021-12-11 07:31

AI因你而升温,记得加个星标哦!

↑ 关注 + 星标 ,每天学Python新技能

后台回复【大礼包】送你Python自学大礼包


前两节介绍了张量的科学运算与矩阵运算,本文就对以上内容进行浓缩总结,帮助大家熟练掌握Tensor的运算技巧,为深度学习打好基础。

一、张量的科学运算

1 进行数值调整

t = torch.randn(5)
t
# tensor([ 0.3806,  0.9064, -1.9179,  2.0816, -0.4153])

1.1 返回绝对值

torch.abs(t)
# tensor([0.3806, 0.9064, 1.9179, 2.0816, 0.4153])

1.2 返回相反数

torch.neg(t)
# tensor([-0.3806, -0.9064,  1.9179, -2.0816,  0.4153])

1.3 四舍五入

torch.round(t)
# tensor([ 0.,  1., -2.,  2., -0.])

1.4 向上取整

torch.ceil(t) 
# tensor([ 1.,  1., -1.,  3., -0.])

1.5 向下取整

torch.floor(t)
# tensor([ 0.,  0., -2.,  2., -1.])

注意

虽然此类型函数并不会对原对象进行调整,而是输出新的结果。

# t本身并未发生变化
t
# tensor([ 0.3806,  0.9064, -1.9179,  2.0816, -0.4153])

若要对原对象本身进行修改,可使用方法_()

# 使用方法_()
t.round_()
# tensor([ 0.,  1., -2.,  2., -0.])

# 原对象也进行了改变
t
# tensor([ 0.,  1., -2.,  2., -0

2 常用的数学计算

需要注意的有以下两点:

  1. 因为张量能指定在CPU或者GPU上运行,因此tensor的大多数科学计算只能作用于tensor对象,而不能和Python对象混用
# 计算3的3次方
torch.pow(3, 3)
# 报错!TypeError

# 需使用tensor对象
torch.pow(torch.tensor(3), 3)
# tensor(27)
  1. 由于会涉及GPU计算,所以对运算结果一般是小数的函数,要求函数只能输入浮点型张量,而不能是整型
t = torch.arange(1, 4)
t.dtype
# torch.int64
torch.exp(t)
# 报错!RuntimeError

# 需要传入浮点型数据
torch.exp(t.float())
# tensor([1.0000, 2.7183, 0.1353, 7.3891, 1.0000])

常用数学计算:

数学运算函数数学公式功能
幂运算

torch.exp(t)
返回以e为底、t中元素为幂的张量
torch.pow(t,n)
返回t的n次幂
torch.sqrt(t)
返回t的平方根
torch.square(t)
返回输入的元素平方
对数运算

torch.log10(t)
返回以10为底的t的对数
torch.log(t)
返回以e为底的t的对数
torch.log2(t)
返回以2为底的t的对数

3 统计分析

此类计算是对某张量进行某种总结,最后得出一个具体总结值的函数。

函数功能
torch.mean(t)返回张量均值
torch.var(t)返回张量方差
torch.std(t)返回张量标准差
torch.var_mean(t)返回张量方差和均值
torch.std_mean(t)返回张量标准差和均值
torch.max(t)返回张量最大值
torch.argmax(t)返回张量最大值索引
torch.min(t)返回张量最小值
torch.argmin(t)返回张量最小值索引
torch.median(t)返回张量中位数
torch.sum(t)返回张量求和结果
torch.prod(t)返回张量累乘结果
torch.dist(t1, t2)计算两个张量的闵式距离,可使用不同范式
torch.topk(t)返回t中最大的k个值对应的指标
  • 这里着重介绍一下常用的距离公式dist(),为闵可夫斯基距离,通过输入不同的p值,可方便计算曼哈顿距离、欧拉距离:
# 输入float型
t1 = torch.tensor([1, 2, 3]).float()
t2 = torch.tensor([4, 5, 6]).float()

# 计算曼哈顿距离
torch.dist(t1, t2, 1)
# tensor(9.)

# 计算欧拉距离
torch.dist(t1, t2, 2)
# tensor(5.1962)

二、张量的线代运算

大学时学的《线代》,其实就是学了矩阵的性质和运算,而矩阵的本质可看为线性方程,线性方程又是一个个基础的神经元。

1 矩阵形变的构造

矩阵的形变与构造的方法与二维张量的方法相同。

# 创建一个2*3的矩阵
t1 = torch.arange(6).reshape(23).float()
t1
# tensor([[0., 1., 2.],
#         [3., 4., 5.]])

1.1 t:转置

torch.t(t1)
# tensor([[0., 3.],
#         [1., 4.],
#         [2., 5.]])

矩阵的转置是每个元素行列位置进行互换。

1.2 eye:单位矩阵

torch.eye(3)
# tensor([[1., 0., 0.],
#         [0., 1., 0.],
#         [0., 0., 1.]])

1.3 diag:对角矩阵

注意参数的数据类型必须是张量。

t = torch.arange(1, 4)
t
# tensor([1, 2, 3])

torch.diag(t)
# tensor([[1, 0, 0],
#         [0, 2, 0],
#         [0, 0, 3]])

1.4 triu:取上三角矩阵

t2 = torch.arange(1, 10).reshape(3, 3)
t2
# tensor([[1, 2, 3],
#         [4, 5, 6],
#         [7, 8, 9]])
  • 取上三角矩阵
torch.triu(t2)
# tensor([[1, 2, 3],
#         [0, 5, 6],
#         [0, 0, 9]])

1.5 tril:取下三角矩阵

torch.tril(t2)
# tensor([[1, 0, 0],
#         [4, 5, 0],
#         [7, 8, 9]])

2 矩阵的基本运算与意义

矩阵的线性代数含义主要体现在它的基本运算上。

2.1 dot\vdot:点积计算

PyTorch中,dotvdot只能用于一维张量。两种函数只在进行复数运算时有区别。

t = torch.arange(1, 4)
t
# tensor([1, 2, 3])

torch.dot(t, t)
# tensor(14)

torch.vdot(t, t)
# tensor(14)

2.2 mm:矩阵乘法

t1 = torch.arange(1, 7).reshape(2, 3)
t1
# tensor([[1, 2, 3],
#         [4, 5, 6]])

t2 = torch.arange(1, 10).reshape(3, 3)
t2
# tensor([[1, 2, 3],
#         [4, 5, 6],
#         [7, 8, 9]])

矩阵对应位置元素相乘,要求两个矩阵的形状相同。

t1 * t1
# tensor([[ 1,  4,  9],
#         [16, 25, 36]])

而矩阵乘法两个矩阵的形状可以不同。

torch.mm(t1, t2)
# tensor([[ 1,  4,  9],
#         [16, 25, 36]])

计算过程如下所示:

规律总结如下:

  1. 左边矩阵的列数要和右边矩阵的行数相等,左边矩阵每行与右边矩阵每列对应位置元素相乘后相加
  2. 左边矩阵的行数决定了结果矩阵的行数,右边矩阵的列数决定了结果矩阵的列数

矩阵相乘需要注意:

  • 不满足交换律:
A = torch.tensor([1, 1, -1, -1])..reshape(2, 2)
A
# tensor([[ 1,  1],
#         [-1, -1]])
        
B = torch.tensor([1, -1, -1, 1]).reshape(2, 2)
B
# tensor([[ 1, -1],
#         [-1,  1]])

torch.mm(A, B)
# tensor([[0, 0],
#         [0, 0]])

torch.mm(B, A)
# tensor([[ 2,  2],
#         [-2, -2]])
  • 不满足消去律:
C = torch.tensor([0, 0, 0, 0]).reshape(2, 2)
C
# tensor([[0, 0],
#         [0, 0]])

torch.mm(A, B)
# tensor([[0, 0],
#         [0, 0]])
        
torch.mm(A, C)
# tensor([[0, 0],
#         [0, 0]])

2.3 mv:矩阵与向量相乘

矩阵和向量相乘的过程中,需要矩阵的列数和向量的元素个数相同。

m = torch.arange(1, 7).reshape(2, 3)
m
# tensor([[1, 2, 3],
#         [4, 5, 6]])

v = torch.arange(1, 4)
v
# tensor([1, 2, 3])

torch.mv(m, v)
# tensor([14, 32])

矩阵和向量相乘的过程我们可以看成是先将向量转化为列向量然后再相乘。

# 转化为列向量
v.reshape(3, 1)     
# tensor([[1],
#         [2],
#         [3]])

torch.mm(m, v.reshape(3, 1))
# tensor([[14],
#         [32]])
        
torch.mm(m, v.reshape(3, 1)).flatten()
# tensor([14, 32])

2.4 矩阵的本质是线性方程

mv函数本质上提供了一种二维张量和一维张量相乘的方法,在线性代数运算过程中,有很多矩阵乘向量的场景,典型的如线性回归的求解过程。

矩阵的最初目的,只是为线性方程组提供一个简写形式。

通常情况下我们需要将行向量(x,y)转化为列向量然后进行计算,但PyTorch中单独设置了一个矩阵和向量相乘的方法,从而简化了将向量转化为列向量的转化过程。

2.5 bmm:批量矩阵相乘

批量矩阵相乘指的是三维张量的矩阵乘法,本质是三维张量内部各对应位置的矩阵相乘,在深度学习中有非常多的应用场景。

t3 = torch.arange(1, 13).reshape(3, 2, 2)
t3
# tensor([[[ 1,  2],
#          [ 3,  4]],

#         [[ 5,  6],
#          [ 7,  8]],

#         [[ 9, 10],
#          [11, 12]]])
         
t4 = torch.arange(1, 19).reshape(3, 2, 3)
t4
# tensor([[[ 1,  2,  3],
#          [ 4,  5,  6]],

#         [[ 7,  8,  9],
#          [10, 11, 12]],

#         [[13, 14, 15],
#          [16, 17, 18]]])

torch.bmm(t3, t4)
# tensor([[[  9,  12,  15],
#          [ 19,  26,  33]],

#         [[ 95, 106, 117],
#          [129, 144, 159]],

#         [[277, 296, 315],
#          [335, 358, 381]]])

需要注意:

  • 三维张量包含的矩阵个数需要相同
  • 每个内部矩阵,需要满足左乘矩阵的列数要等于右乘矩阵的行数

2.6 addmm:矩阵相乘后相加

  • addmm函数结构:addmm(input, mat1, mat2, beta=1, alpha=1)

  • 输出结果:beta * input + alpha * (mat1 * mat2)

  • 相当于y = ax + b中加偏置的过程,就是线性方程或基本的神经元

t1
# tensor([[1, 2, 3],
#         [4, 5, 6]])
        
t2
# tensor([[1, 2, 3],
#         [4, 5, 6],
#         [7, 8, 9]])

t = torch.arange(3)
t
# tensor([0, 1, 2]

# 矩阵乘法
torch.mm(t1, t2)
# tensor([[30, 36, 42],
#         [66, 81, 96]])

# 先乘法后相加
torch.addmm(t, t1, t2)
# tensor([[30, 37, 44],
#         [66, 82, 98]])

torch.addmm(t, t1, t2, beta = 0, alpha = 10)
# tensor([[300, 360, 420],
#         [660, 810, 960]])

2.7 addbmm:批量矩阵相乘后相加

不同的是addbmm是批量矩阵相乘,并且在相加的过程中也是矩阵相加,而非向量加矩阵。

t = torch.arange(6).reshape(2, 3)
t
# tensor([[0, 1, 2],
#         [3, 4, 5]])
        
t3
# tensor([[[ 1,  2],
#          [ 3,  4]],

#         [[ 5,  6],
#          [ 7,  8]],

#         [[ 9, 10],
#          [11, 12]]])
         
t4
# tensor([[[ 1,  2,  3],
#          [ 4,  5,  6]],

#         [[ 7,  8,  9],
#          [10, 11, 12]],

#         [[13, 14, 15],
#          [16, 17, 18]]])
         
torch.bmm(t3, t4)
# tensor([[[  9,  12,  15],
#          [ 19,  26,  33]],

#         [[ 95, 106, 117],
#          [129, 144, 159]],

#         [[277, 296, 315],
#          [335, 358, 381]]])
         
torch.addbmm(t, t3, t4)
# tensor([[381, 415, 449],
#         [486, 532, 578]])

addbmm会在原来三维张量基础之上,对其内部矩阵进行求和,而不是矩阵和向量相加。

《5分钟精通PyTorch》经过1个月的连载,已经介绍了张量的常规操作以及运算技巧,相信大家都有所收获。之后的章节就进入到深度学习部分,会以理论和代码结合的方式为大家呈现,帮助大家理解其中细节,敬请期待!

推荐阅读

  1. 又一款超酷的可视化神器:cutecharts

  2. 机密!网易员工数据分析内训课程,白嫖了!(另附价值399元资料包)

  3. 豆瓣评分 9.0,超 10 万开发者的入门选择,这本经典好书终于升级啦!

  4. 卧槽!又来一个Python学习神器!!!



浏览 128
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报