作者🕵️♂️:让机器理解语言か
专栏🎇:PyTorch
描述🎨:PyTorch 是一个基于 Torch 的 Python 开源机器学习库。
寄语💓:🐾没有白走的路,每一步都算数!🐾
张量(Tensor)介绍
PyTorch 中的所有操作都是在张量的基础上进行的,本实验主要讲解了张量定义和相关张量操作以及 GPU 和张量之间的关系,为以后使用 PyTorch 进行深度学习打下坚实的基础。
知识点🍉
- 🍓张量的创建
- 🍓张量的运算(加减乘除)
- 🍓自动计算梯度
- 🍓张量的切片
- 🍓张量的重塑
- 🍓NumPy 与 Tensor的转换
- 🍓GPU 上创建张量
张量:Tensor
什么是张量?
PyTorch 中的所有内容都基于 Tensor(张量) 操作的。张量可以具有不同的尺寸,它可以是 1 维(标量),2 维(矢量),甚至 3 维(矩阵)或更高。
特点:
- 比 NumPy 更灵活,可以使用 GPU 的强大计算能力。
- 开源高效的深度学习研究平台。
张量的创建
让我们看一下如何在 PyTorch 中创建张量。
-
🍅torch.empty( ):创建一个未初始化的tensor
下面,我们创建一个 2×3矩阵。使用 torch.empty 可以返回填充了未初始化数据的张量。张量的形状由可变参数大小定义。
import torch
torch.empty(2,3)
# 或者 torch.empty(2,3,out = result);print(result) # torch创建张量的每一个函数都有参数out:提供输出 Tensor 作为参数
'''
tensor([[1.1692e-19, 1.5637e-01, 5.0783e+31],
[4.2964e+24, 2.6908e+20, 2.7490e+20]])
'''
-
🍅torch.rand(size)
:
随机初始化值在 0-1 之间的tensor(服从均匀分布)
# torch.rand(size)
torch.rand(5, 3) # 初始化 5*3 大小的 0-1 之间的张量
-
🍅torch.zeros(size) /torch.ones(size):初始化全为 1 /全为 0 的tensor
x = torch.zeros(5, 3)
y = torch.ones(5, 3)
print(x)
print(y)
-
🍅
torch.tensor(list):
创建指定值的tensor
创建 Tensor 并使用现有数据初始化,list 可以为 NumPy 中的一个列表。
#创建的张量中的值为 [5.5,3]
x = torch.tensor([5.5, 3])
print(x)
print(x.size())
-
🍅x.new_ones( ) :根据现有张量创建新张量。
new_ones(size, dtype=None, device=None, requires_grad=False) → Tensor
- 返回一个与size大小相同的用1填充的张量。
- 默认情况下,返回的Tensor具有与此张量相同的torch.dtype和torch.device,除非设置新的值进行覆盖。
x = x.new_ones(5, 3, dtype=torch.double) # new_* 方法来创建对象
x
-
🍅 torch.randn_like( ):生成一个与输入张量形状相同的张量
torch.randn_like()函数的作用是生成一个与输入张量形状相同的张量,其中的元素是从标准正态分布中随机采样得到的。
torch.randn_like(input, dtype=None, layout=None, device=None, requires_grad=False)
- 其中,input是输入张量,dtype是输出张量的数据类型,layout是输出张量的布局,device是输出张量的设备,requires_grad表示是否需要计算梯度。默认情况下,返回的Tensor具有与此张量相同的torch.dtype、layout、device和requires_grad。
x = torch.randn_like(x, dtype=torch.float)
x
查看张量的大小 x.size()
x.size()
# torch.Size([5, 3])
# 传入的参数为想创建的张量大小
x = torch.empty(1) # scalar,大小为 1*1 的张量
print(x.size())
x = torch.empty(3) # vector, 1D,大小为 1*3 的张量
print(x.size())
x = torch.empty(2, 3) # matrix, 2D,大小为 2*3 的张量
print(x.size())
x = torch.empty(2, 2, 3) # tensor, 3D,大小为 2*2*3 的张量
print(x.size())
📌小贴士
torch.Size
返回值是 tuple 类型,所以它支持 tuple 类型的所有操作。
查看 张量中值的类型 x.dtype( )
x.dtype
# torch.float32
当然,也可以在初始化时传入 dtype
参数,指定数组值的类型:
x = torch.zeros(5, 3, dtype=torch.float16)
print(x)
# check type
print(x.dtype)
自动计算梯度
如果想要定义的张量能够自动计算梯度(这里先简单说明,详细请查看我的另一篇博客【PyTorch】第二节:梯度的求解),那么我们就需要将参数 requires_grad
置为 True
。
torch.tensor([5.5, 3], requires_grad=True)
# tensor([5.5000, 3.0000], requires_grad=True)
张量的运算
-
🥕张量的加法
y = torch.rand(2, 2)
x = torch.rand(2, 2)
# 两种方法:
z1 = x + y
z2 = torch.add(x, y)
z1,z2
还有一种原地相加的操作,相当于y += x或者y = y + x。
y.add_(x) # 将 x 加到 y
y
📌小贴士:
任何以下划线结尾的操作都会用结果替换原变量。例如:
x.copy_(y)
,x.t_()
, 都会改变x
。
-
🥕 张量的减法
# 使用 - 或者 .sub 都可以表示张量减法
z = x - y
z = torch.sub(x, y)
print(z)
-
🥕张量乘法
# 张量乘法(利用 * 或者 torch.mul表示)
z = x * y
z = torch.mul(x, y)
print(z)
-
🥕张量除法
# 张量除法(使用 / 或者 torch.div 表示)
z = x / y
z = torch.div(x, y)
print(z)
张量的切片
和 NumPy 的切片类似,如下:
💡 第一个值表示第一维(即行号),第二个值表示第二维(即列号)
x = torch.rand(5, 3)
print(x)
print(x[1, 1])
print(x[:, 0]) # 所有的行中的第 1 列
print(x[1, :]) # 第 2 行中所有的列
张量的重塑
重塑的意思就是将原张量的形状进行变换,即元素总个数不变的情况下改变行数和列数,使用 torch.view(size)
类似于 numpy.reshape
。
x = torch.randn(4, 4)
y = x.view(16) # 指定改变后的大小
z = x.view(2, 8) # 等价于z = x.view(-1, 8) # size -1 从其他维度推断
print(x.size(), y.size(), z.size())
# torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])
当 x 的大小为 12×23×32 ,而我们想把 x 转为 2×m 的大小时,我们就必须手动算出 12×23×32 的值,然后除以 2,进而得到 m 的值。为了避免这种情况,我们可以将 m 所在位置赋为 -1,即y = x.view(2, -1) 表示该维度由从其他维度推断得到。计算机看到 -1 时,会自动使用 12×23×32÷2 的值来替换 -1:
x = torch.randn(12, 23, 32)
y = x.view(2, -1) # 将需要计算的那个维度直接用 -1 表示 12*23*32/2 的值
x.size(), y.size()
# (torch.Size([12, 23, 32]), torch.Size([2, 4416]))
📌小贴士:
一次切片中只能有一个位置值为 -1 。
NumPy 与 Tensor的转换
将 PyTorch 张量转换为 NumPy 数组(反之亦然)是一件轻而易举的事。PyTorch 张量和 NumPy 数组将共享其底层内存位置,改变一个也将改变另一个。
-
🍌
tensor.numpy( )
:将 Tensor 类型的变量转为 NumPy 类型
a = torch.ones(5)
print(a)
b = a.numpy()
print(b)
print(type(b))
-
🍌
torch.from_numpy( )
:将 NumPy 类型的变量转为 Tensor
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
print(a)
print(b)
了解 NumPy 数组的值如何变化:
a.add_(1)
a, b
# (tensor([2., 2., 2., 2., 2.]), array([2., 2., 2., 2., 2.], dtype=float32))
可以看出, NumPy 类型的变量和 Tensor之间的转换其实是一种深复制,改变一个也将改变另一个。
GPU 上创建张量
默认情况下,所有的张量都是在 CPU 上创建的,但是你也可以使用 GPU 创建它,或者将 CPU 创建的向量移动到 GPU 中。
当然,下面代码只有在你的电脑支持 GPU 的情况下才过下才能运行。我们可以通过torch.cuda.is_available() 命令,查看本地环境时候支持 GPU :
torch.cuda.is_available()
# True 表示支持
# False 表示不支持
将变量放到 GPU 中运行的方式有两种,如下:
-
🥕在定义时就指定参数
device
# 如果支持 GPU 则传入字符串 cuda,否则传入 cpu device = torch.device("cuda") y = torch.ones_like(x, device=device) # 在 GPU 上直接创建张量
-
🥕创建张量后,使用
.to
方法将变量移动到 GPU 中x = torch.randn(4, 4) device = torch.device("cuda") x = x.to(device) # 将张量移动到 GPU
CUDA 张量
CUDA 张量是能够在 GPU 设备中运算的张量。
# is_available 函数判断是否有 GPU 可以使用
if torch.cuda.is_available():
device = torch.device("cuda") # torch.device 将张量移动到指定的设备中
y = torch.ones_like(x, device=device) # 直接从 GPU 创建张量
x = x.to(device) # 或者直接使用 .to("cuda") 将张量移动到 cuda 中
z = x + y
print(z)
print(z.to("cpu", torch.double)) # .to 也会对变量的类型做更改
# tensor([1.4566], device='cuda:0')
# tensor([1.4566], dtype=torch.float64)
如果未配置 GPU,那么上述代码没有输出结果。
实验总结
本实验主要讲解了张量的定义,以及如何使用 PyTorch 完成张量的加、减、乘、除、切片和重塑等操作。在实验的最后,我们对张量进行了扩展,阐述了如何查看本地环境是否支持 GPU ,以及如何将变量定义到 GPU 之中。