【youcans的深度学习 08】PyTorch入门教程:张量的就地操作和广播机制

欢迎关注『youcans的深度学习』系列,持续更新中…
【youcans的深度学习 01】安装环境之 miniconda
【youcans的深度学习 02】PyTorch CPU版本安装与环境配置
【youcans的深度学习 03】PyTorch CPU版本安装与环境配置
【youcans的深度学习 04】PyTorch入门教程:基础知识
【youcans的深度学习 05】PyTorch入门教程:快速入门
【youcans的深度学习 06】PyTorch入门教程:张量的基本操作 1
【youcans的深度学习 07】PyTorch入门教程:张量的基本操作 2
【youcans的深度学习 08】PyTorch入门教程:张量的就地操作和广播机制

PyTorch 中支持 100 多种张量操作,包括转置、索引、切⽚、数学运算、线性代数、随机数等等,详见【PyTorch官方文档】


1. 张量运算的种类和特点

1.1 张量运算的分类

PyTorch 将能够作用于张量的运算统称为算子,按算子的操作方式分为 6 类,以方便使用。

  1. 逐点运算(Pointwise Ops),是指针对张量的每个元素分别执行相同的运算操作。
  2. 规约运算(Reduction Ops),是指对张量进行操作得出某种总结值。
  3. 比较运算(Comparison Ops),是指对多个张量进行比较运算的方法。
  4. 谱运算(Spectral Ops),是指涉及信号处理傅里叶变换的操作。
  5. 线性代数运算(BLAS/LAP),是指基础线性代数程序集(Basic Linear Algeria Subprograms,BLAS)和线性代数包(Linear Algeria Package,LAP)定义的用于线性代数计算的函数和方法。
  6. 其它运算(Other Ops),其它数学运算。

本章主要介绍逐点运算、归约运算和比较运算。线性代数运算将单独进行介绍。谱运算需要理解傅里叶变换的数学基础,前期不会涉及;其它运算已经在张量的基本操作中介绍。


1.2 张量的就地操作( Inplace )

就地操作( Inplace ),也称为“原地操作“,是指在原有内存空间上直接修改赋值,不产生新的对象,不改变存储地址,因而节约了内存空间。

Inplace 操作的优点是可以节省内存,尤其是在处理高维数据时能显著减少额外的内存开销。但是 Inplace 操作也有缺点:(1)Inplace 操作会直接改变原对象的内容,覆盖计算梯度所需的值,破坏了模型的训练过程;(2)每个 Inplace 操作实际上都需要重写计算图。因此,叶子节点(Leaf tensor)不能使用 Inplace 操作,求梯度阶段不能使用 Inplace 操作。如果显存足够,最好还是避免使用 Inplace 操作。

在 PyTorch 中,很多函数使用在函数名后加下划线的后缀来实现 Inplace 操作,例如 x.add_(y)x.copy_(y)x.normal_(y)x.zero_(y)x.relu_(y)x.sigmoid_(y)

# BasicTorch05_v1.py
# torch05 of PyTroch
# 张量的基本运算

# 导入PyTorch
import torch

# (1) 张量的就地操作 (Inplace)
x = torch.tensor(10)
y1 = x.add(1)  # 非就地操作,不修改 x 的值
print("x={}, y1={}".format(x, y1))
print("id(x):{}, id(y1):{}".format(id(x), id(y1)))

y2 = x.add_(2)  # 就地操作,修改了 x 的值
print("x={}, y2={}".format(x, y2))
print("id(x):{}, id(y2):{}".format(id(x), id(y2)))

结果如下。

x=10, y1=11
id(x):2135179428144, id(y1):2135180570848
x=12, y2=12
id(x):2135179428144, id(y2):2135179428144

在激活函数中,Inplace 操作可以通过设置 inplace=True 实现,例如:

torch.nn.ReLU(inplace=True)
torch.nn.Sigmoid(inplace=True)
torch.nn.Tanh(inplace=True)


1.3 张量的广播机制(Broadcast)

1.3.1 广播机制的定义

Pytorch 中的广播机制和 Numpy 中的广播机制相似,都是数组的广播机制,是在运算过程中处理两个形状不同的多维数组的方法。

如果一个运算支持广播机制,则该操作的 Tensor 参数会被自动扩展为相同的形状,在不复制数据的情况下就能进行运算,可以避免不必要的复制,实现更高效的运算。


1.3.2 广播机制的规则

广播机制的条件是其中任意一个张量必须至少有一个维度或者相等,或者其中一个为 1,或者其中一个不存在。

具体而言,如果满足以下规则,则两个张量是“可广播的(Broadcastable)”:

  • 每个张量至少有一个维度;
  • 遍历两个张量所有维度时,从右向前逐维度进行遍历,两个张量满足下列情况之一:
    • 两个张量的该维度的大小相等;
    • 两个张量的该维度的大小不相等,其中一个张量该维度的大小为 1;
    • 两个张量维数不同,其中一个张量该维度不存在。
  • 如果两个 tensor 是“可广播的”,则计算过程遵循下列规则:
    • 如果两个 tensor 的维度不同,则在维度较小的 tensor 的前面增加维度,使它们维度相等。
    • 对于每个维度,计算结果的维度值取两个 tensor 中较大的那个值。
    • 两个 tensor 扩展维度的过程是将数值进行复制。

举例说明如下。

  1. 两个相同维度的张量,一定是“可广播的”。
# 相同维度的两个张量是 可广播的
x=torch.ones(1,4,7)
y=torch.ones(1,4,7)
  1. 两个张量都至少有一个维度,才是“可广播的”。
# 两个张量都至少有一个维度才是 可广播的
x = torch.empty((0,))  # 不可广播
y = torch.empty(2,2)
  1. 按从右往左顺序遍历两个张量每一个维度,都要能够匹配:(1)两个张量该维度的大小相等;(2)其中一个张量没有该维度;(3)其中一个张量该维度的大小为 1。
# 逐个维度遍历两个张量,都满足广播规则,才是可广播的
x = torch.empty(1,3,1,5)
y = torch.empty(  3,2,1)

1.3.3 广播机制的运算方式

两个张量使用广播机制的运算方式如下。

(1)如果一个张量没有该维度,则插入大小为 1 的维度。例如:

两个张量原有的维度:
x = torch.ones(1,3,1,5)
y = torch.ones(  3,2,1)
插入大小为 1 的维度后:
x = torch.ones(1,3,1,5)
y = torch.ones(1,3,2,1)  # 插入大小为 1 的维度

(2)如果两个张量的某些维度大小不相等,且其中一个张量该维度大小为 1,则该维度大小变成另一张量在该维度的大小。例如:

两个张量原有的维度:
x = torch.ones(1,3,1,5)
y = torch.ones(1,3,2,1)
张量维度大小调整后:
x = torch.ones(1,3,2,5)  # dim=2 大小从 1 变成 2
y = torch.ones(1,3,2,5)  # dim=3 大小从 1 变成 5

(3)对于应用广播机制后,形状相同的两个张量,按照函数的方法进行操作。

例程如下。

# (2) 张量的广播机制 (Broadcast)
a = torch.rand(3, 5, 5)
b = torch.rand(1, 5, 5)
c = a * b
# print(a, b, c)
print("a.shape:{}\nb.shape:{}\nc.shape:{}".format(a.shape, b.shape, c.shape))

a = torch.rand(1,3,5,5)
b = torch.rand(  3,5,5)
c = a + b
# print(a, b, c)
print("\na.shape:{}\nb.shape:{}\nc.shape:{}".format(a.shape, b.shape, c.shape))

x = torch.ones(1,3,1,5)
y = torch.ones(  3,3,1)
z = torch.add(x, y)
# print(x, y, z)
# print(x.shape, y.shape, z.shape)
print("\nx.shape:{}\ny.shape:{}\nz.shape:{}".format(x.shape, y.shape, z.shape))

例程运行结果如下。

a.shape:torch.Size([3, 5, 5])
b.shape:torch.Size([1, 5, 5])
c.shape:torch.Size([3, 5, 5])

a.shape:torch.Size([1, 3, 5, 5])
b.shape:torch.Size([3, 5, 5])
c.shape:torch.Size([1, 3, 5, 5])

x.shape:torch.Size([1, 3, 1, 5])
y.shape:torch.Size([3, 3, 1])
z.shape:torch.Size([1, 3, 3, 5])

广播机制的本质是,不同形状的张量进行计算时,通过隐式转化,转换为相同形状的两个张量,从而完成计算。

但并不是任何两个不同形状的张量都可以通过广播特性进行计算,张量的插入维度或维度大小变化,实际上都相当于对原有张量进行数据共享。

【本节完】


版权声明:
欢迎关注『youcans的深度学习』系列,转发请注明原文链接:
【youcans的深度学习 06】PyTorch入门教程:张量的就地操作和广播机制(https://youcans.blog.csdn.net/article/details/130654698)
Copyright 2023 youcans, XUPT
Crated:2023-05-12

猜你喜欢

转载自blog.csdn.net/youcans/article/details/130654698
今日推荐