欢迎关注『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官方文档】。
PyTorch 将能够作用于张量的运算统称为算子,按算子的操作方式分为 6 类,以方便使用。
本章主要介绍逐点运算、归约运算和比较运算。线性代数运算将单独进行介绍。谱运算需要理解傅里叶变换的数学基础,前期不会涉及;其它运算已经在张量的基本操作中介绍。
就地操作( 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)
Pytorch 中的广播机制和 Numpy 中的广播机制相似,都是数组的广播机制,是在运算过程中处理两个形状不同的多维数组的方法。
如果一个运算支持广播机制,则该操作的 Tensor 参数会被自动扩展为相同的形状,在不复制数据的情况下就能进行运算,可以避免不必要的复制,实现更高效的运算。
广播机制的条件是其中任意一个张量必须至少有一个维度或者相等,或者其中一个为 1,或者其中一个不存在。
具体而言,如果满足以下规则,则两个张量是“可广播的(Broadcastable)”:
举例说明如下。
# 相同维度的两个张量是 可广播的
x=torch.ones(1,4,7)
y=torch.ones(1,4,7)
# 两个张量都至少有一个维度才是 可广播的
x = torch.empty((0,)) # 不可广播
y = torch.empty(2,2)
# 逐个维度遍历两个张量,都满足广播规则,才是可广播的
x = torch.empty(1,3,1,5)
y = torch.empty( 3,2,1)
两个张量使用广播机制的运算方式如下。
(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