【youcans的深度学习 06】PyTorch入门教程:张量的基本操作

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



1. 张量及其数据结构

“张量”(Tensor)是 PyTorch 的基本数据结构。

PyTorch 中主要通过张量对数据进行存储和变换操作。张量的数据结构与操作与 Numpy 多维数组 ndarray 类似,但可以在GPU上使用以加速计算,更适合深度学习。

张量是一个多维数组,它是标量、向量、矩阵的高维拓展。标量(scalar)是 0 维张量,向量(vector)是 1 维张量,矩阵(matrix)是 2 维张量。


在这里插入图片描述


可以使用 ndim 检查张量的维数,使用shapesize()检查张量的形状,使用 dtype 查看数据类型,使用numel() 检查张量的元素个数。

# 导入PyTorch
import pytorch

# (1) 通过数据直接创建Tensor
x = torch.tensor([[1.0, 2.0, 3.6], [0.0, 4.0, 7.0]])
print(x)

# (2) 查看张量的维数,形状和类型
print("x.ndim:", x.ndim)  # 张量的维数
print("x.shape:", x.shape)  # 张量的形状
print("x.size:", x.size())  # 张量的形状
print("x.numel:", x.numel())  # 张量的元素个数
print("x.dtype:", x.dtype)  # 张量的数据类型

输出为:

tensor([[1.0000, 2.0000, 3.6000],
[0.0000, 4.0000, 7.0000]])
x.ndim: 2
x.shape: torch.Size([2, 3])
x.size: torch.Size([2, 3])
x.numel: 6
x.dtype: torch.float32

说明:torch.Size本质上是元组(typle),支持元组的各种操作。


注意 0 维张量虽然只有一个元素,但并不是一个数。

# (3) 0 维张量只有一个元素,但不是数值类型
x = torch.tensor([2009])
print("x = ", x)  # x 是张量
print("x.ndim:", x.ndim)  # 张量的维数
print("x.shape:", x.shape)  # 张量的形状
print("x.type:", x.type())  # x 的类型是张量

n = 2009
print("n = ", n)  # n 是标量,不是张量,没有维数、形状
print("type(n):", type(n))  # n 的类型是整型数值

输出结果:

x = tensor([2009])
x.ndim: 1
x.shape: torch.Size([1])
x.type: torch.LongTensor
n = 2009
type(n): <class ‘int’>


标准的 Python 数据结构是一个单层内存对象,可以保持数据和元数据。

PyTorch 的数据结构是分层设计的,其框架支持互操作,内核的计算密集部分通过 ATen 和 Caffe2 迁移到 C/C++ 后端。

PyTorch 面向用户的主要数据结构是一个 THTensor 对象,保存有关维度、偏移、步长等信息,另外还存储了一个指向 THStorage 对象的指针。


2. 张量的创建

2.1 torch.empty() 创建未初始化的张量

使用 ndim 检查张量的维度,使用shape检查张量的形状。

# (4) 创建一个未初始化的张量
x = torch.empty(2, 3)  # x=torch.empty(size=(2, 3)
print(x)
print("x.ndim:", x.ndim)
print("x.shape:", x.shape)

输出为:

tensor([[6.8943e+34, 1.6212e-19, 1.4585e-19],
[7.7179e+28, 1.6217e-19, 1.4586e-19]])
x.ndim: 2
x.shape: torch.Size([2, 3])


2.2 torch.rand() 创建随机数张量

机器学习模型通常从随机数的张量开始,并通过样本学习来调整和更新这些随机数值。

  • 使用 torch.rand() 可以创建服从均匀分布的随机数张量,区间为[0,1)
  • 使用 torch.randint() 可以创建服从均匀分布的随机整数张量,区间为[low,high)
  • 使用 torch.randn() 可以创建服从标准正态分布的随机数张量,均值为0,方差为1

torch.rand(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor
torch.randint(low=0, high, size, generator=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor
torch.randn(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor

参数说明:

  • size:定义tensor的形状,整数序列 list 或 元组tuple
  • dtype:可选,指定返回tensor的数据类型
  • layout:可选,表示torch.Tensor内存布局的对象
  • device:可选,tensor存放的device
# (5) 创建随机数张量
x1 = torch.rand(2, 3)  # 均匀分布随机数,[0,1) 区间
print(x1)
print("x1.shape:", x1.shape)
x2 = torch.randn(2, 3)  # 正态分布随机数,均值为 0 方差为1
print(x2)
print("x2.shape:", x2.shape)
x3 = torch.randint(low=0, high=10, size=(2,3))  # 均匀分布随机整数,[low,high) 区间
print(x3)
print("x3.shape:", x3.shape)

输出为:

tensor([[0.5007, 0.1634, 0.4525],
[0.1331, 0.5705, 0.0439]])
x1.shape: torch.Size([2, 3])
tensor([[ 0.5210, 1.8041, -0.5655],
[-2.0804, 0.3897, 0.4336]])
x2.shape: torch.Size([2, 3])
tensor([[5, 0, 6],
[1, 8, 2]])
x3.shape: torch.Size([2, 3])


2.3 创建全0矩阵/全1矩阵/单位矩阵/对角矩阵等特殊张量

使用 torch.zeros() 可以创建 全0张量,使用 torch.ones() 可以创建 全1张量,使用 torch.eye() 可以创建单位矩阵张量。

使用 torch.diag() 可以创建对角矩阵张量,但需要用一维张量来创建。

# (6) 创建全0矩阵/全1矩阵/单位矩阵/对角矩阵等特殊张量
xZeros = torch.zeros(3, 5)  # 全0矩阵
print(xZeros)
xOnes = torch.ones(3, 5)  # 全1矩阵
print(xOnes)
xEye = torch.eye(3)  # 单位矩阵
print(xEye)
x1 = torch.tensor([1.2, 2.5])  # 一维张量
xDiag = torch.diag(x1)  # 对角矩阵
print(xDiag)

输出为:

tensor([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])
tensor([[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.]])
tensor([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
tensor([[1.2000, 0.0000],
[0.0000, 2.5000]])


2.4 通过数据直接创建张量

也可以通过自己的数据直接创建 tensor,数据格式可以是列表、元组或 Numpy数组。

# (7) 通过数据直接创建Tensor
# 通过列表创建
x1 = torch.tensor([[1, 2, 3],
               [4, 5, 6]])
print(x1)
# 通过元组创建
x2 = torch.tensor(((1, 2, 3), (4, 5, 6)))
print(x2)
# 通过Numpy创建
xnp = np.array([[1, 2, 3], [4, 5, 6]])
x3 = torch.tensor(xnp)
print(x3)

输出为:

tensor([[1, 2, 3],
[4, 5, 6]])
tensor([[1, 2, 3],
[4, 5, 6]])
tensor([[1, 2, 3],
[4, 5, 6]], dtype=torch.int32)


2.5 通过已有张量的形状创建新的张量

也可以通过已有张量的形状来创建新的张量,所创建张量的形状与已有张量相同。

根据指定对象的形状进行数值填充,只需要在上述函数后面加上 _like 即可,即 torch.*_like()。此方法默认重用所输入tensor的一些属性,例如数据类型,但也可以自定义数据类型。

torch.zeros_like(input, *, dtype=None, layout=None, device=None) → Tensor
torch.ones_like(input, *, dtype=None, layout=None, device=None) → Tensor
torch.randn_like(input, *, dtype=None, layout=None, device=None) → Tensor

# (8) 通过已有张量的形状创建新的张量
x = torch.ones((2, 3), dtype=torch.float32)  # 均匀分布随机数
print(x)
print("x:", x.shape, x.type(), x.device)
# 返回的张量默认具有相同的 dtype
y1 = torch.rand_like(x)  # 默认具有相同的数据类型
y2 = torch.zeros_like(x, dtype=torch.int)  # 用户指定新的数据类型
print("y1:", y1.shape, y1.type(), y1.device)
print("y2:", y2.shape, y2.type(), y2.device)

输出为:

tensor([[1., 1., 1.],
[1., 1., 1.]])
x: torch.Size([2, 3]) torch.FloatTensor cpu
y1: torch.Size([2, 3]) torch.FloatTensor cpu
y2: torch.Size([2, 3]) torch.IntTensor cpu


2.6 从Numpy数组创建张量

torch.from_numpy(ndarray)

函数 torch.from_numpy 将 numpy 数组转换为张量

# (9) 将 numpy 数组转换为张量
x_NP = np.random.rand(2, 3)
x = torch.from_numpy(x_NP)
print(x_NP)
print(x)

输出为:

[[0.02711595 0.35572182 0.67692876]
[0.73672641 0.01211524 0.22966701]]
tensor([[0.0271, 0.3557, 0.6769],
[0.7367, 0.0121, 0.2297]], dtype=torch.float64)


2.7 创建顺序的一维张量

函数 torch.arange() 返回一个一维张量,数值在区间 [start, end) (左闭右开),步长为 step。
函数 torch.range() 返回一个一维张量,数值在区间 [start, end) (左闭右闭),步长为 step。在以后版本中该函数被删除。
函数 torch.linspace() 返回一个一维张量,包含在区间 [ s t a r t , e n d ] [start, end] [start,end] 的等距的 steps 个数据点,步长自动计算。
函数 torch.logspace() 返回一个一维张量,包含以base为底、指数在区间 [ s t a r t , e n d ] [start, end] [start,end] 的等距的 steps 个数据点。

torch.arange(start=0, end, step=1, *, out=None, dtype=None)
torch.range(start=0, end, step=1, *, out=None, dtype=None) # 新版删除
torch.linspace(start, end, steps, *, out=None, dtype=None)
torch.logspace(start, end, steps, base=10.0, *, out=None, dtype=None)

参数说明:

  • start:起始值,默认值为 0
  • end:结束值
  • step:步长,默认值为 1
  • steps:数据点数

注意:张量的第一个元素不一定是 start,最后一个元素不一定是 end。

# (10) 创建顺序的一维张量
x1 = torch.arange(1, 3.6, 0.5)  # 6 个元素,(3.6-1.0)//0.5+1
print(x1)
print("x1:", x1.shape)
x2 = torch.linspace(3, 6, 10)  # 10 个元素,steps=10
print(x2)
print("x2:", x2.shape)
x3 = torch.logspace(3, 6, 10)  # # 10 个元素,steps=10
print(x3)
print("x3:", x3.shape)

输出为:

tensor([1.0000, 1.5000, 2.0000, 2.5000, 3.0000, 3.5000])
x1: torch.Size([6])
tensor([3.0000, 3.3333, 3.6667, 4.0000, 4.3333, 4.6667, 5.0000, 5.3333, 5.6667,
6.0000])
x2: torch.Size([10])
tensor([ 1000.0000, 2154.4346, 4641.5889, 10000.0000, 21544.3477,
46415.8867, 100000.0000, 215443.4688, 464158.8750, 1000000.0000])
x3: torch.Size([10])

其它创建张量的方法,详见【PyTorch官方文档】


3. 张量的数据类型

3.1 张量的属性

张量在 PyTorch 中表示为 torch.Tensor,主要属性如下。

  • data: 张量的数据,可以是数值、数值列表、Numpy数组等。
  • dtype: 张量的数据类型
  • shape: 张量的形状和维度
  • device: 张量存储的设备类型,支持 CPU(‘cpu’)和 GPU(‘cuda’)
  • layout: 张量在内存中的布局模式,支持 torch.strided 和 torch.sparse_coo
  • grad: data 的梯度
  • grad_fn: 创建张量的函数,用于自动求导
  • requires_grad: 是否需要计算梯度,布尔值
  • is_leaf: 是否叶子节点,布尔值

3.2 PyTorch 定义的张量类型

张量是一个多维矩阵,包含单一 数据类型的元素。

最常见的张量类型是 torch.float32 或 torch.float,被称为“32 位浮点数”。但也有 16 位浮点数 (torch.float16 or torch.half) 和 64 位浮点数 (torch.float64 or torch.double)。此外,还有 8 位、16 位、32 位和 64 位整数类型、布尔类型、复数类型。

注意 PyTorch 并没有 string 类型,但可以通过 one-hot 编码或 Word2vec 模型来表示。

特别地,PyTorch中某些张量类型专用于 CPU,有些则更适合 GPU。例如,带有 torch.cuda 的张量都被用于 GPU(Nvidia GPU 被称为 CUDA 的计算工具包)。

Torch 使用 CPU 和 GPU 变体定义了 9 种不同的张量类型,默认的数据类型是 32位浮点型( torch.float32)。

Data type dtype CPU tensor GPU tensor
32-bit float torch.float32 torch.FloatTensor torch.cuda.FloatTensor
64-bit float torch.float64 torch.DoubleTensor torch.cuda.DoubleTensor
16-bit float torch.float16 torch.HalfTensor torch.cuda.HalfTensor
8-bit integer (unsigned) torch.uint8 torch.ByteTensor torch.cuda.ByteTensor
8-bit integer (signed) torch.int8 torch.CharTensor torch.cuda.CharTensor
16-bit integer (signed) torch.int16 torch.ShortTensor torch.cuda.ShortTensor
32-bit integer (signed) torch.int32 torch.IntTensor torch.cuda.IntTensor
64-bit integer (signed) torch.int64 torch.LongTensor torch.cuda.LongTensor
Boolean torch.bool torch.BoolTensor torch.cuda.BoolTensor

3.3 查看张量的数据类型

PyTorch 提供了几种方法来检查与判断数据类型:

  • type(x):返回变量的数据类型,适用于张量、Numpy数组、列表、数值等类型。
  • x.dtype:返回变量的数据类型,适用于张量、Numpy 数组,不适用于列表、数值等类型。
  • x.type():返回变量的数据类型,适用于张量,不适用于 Numpy 数组、列表、数值等类型。
  • isinstance(x, torch.FloatTensor):比较数据类型,返回 True/False
# (11) 张量的数据类型
x_numpy = np.random.rand(2, 3)
x_list = x_numpy.tolist()
x_data = x_numpy[0,0].item()
x_tensor = torch.from_numpy(x_numpy)
print(type(x_numpy))  # <class 'numpy.ndarray'>
print(type(x_list))  # <class 'list'>
print(type(x_data))  # <class 'float'>
print(type(x_tensor))  # <class 'torch.Tensor'>
# 查看张量的数据类型
print(x_tensor.type())  # torch.DoubleTensor
print(x_tensor.dtype)  # torch.float64
# 判断张量的数据类型
print(isinstance(x_tensor, torch.FloatTensor))  # False

注意:

(1)对于张量 x,可以用 x.type() 或 type(x) 查看数据类型,但返回值的格式不同。x.type() 返回张量的具体数据类型,而 type(x) 返回数据类型的类名。
(2)对于 Numpy 数组、list 列表与数值,可以用 type(x) 查看数据类型,但不能使用 x.type() 方法。


3.3 指定张量的数据类型

创建张量时,默认的数据类型是 32位浮点型( torch.FloatTensor )。

用户可以在创建张量时指定张量的数据类型,也可以更改已有张量的数据类型。

更改张量 x 的数据类型,可以使用 x.int() 更改为 torch.int32,也可以使用 x.type(torch.int32)。

# (12) 指定张量的数据类型
# 在创建时指定张量的数据类型
x1 = torch.zeros(3, 3)
x2 = torch.zeros(3, 3, dtype=torch.float64)
x3 = torch.zeros(3, 3, dtype=torch.long)
print("x1.dtype: ", x1.dtype)
print("x2.dtype: ", x2.dtype)
print("x3.dtype: ", x3.dtype)
# 更改张量的数据类型
x1 = x1.long()  # x1=x1.type(torch.int64)
x2 = x2.int()  # x2=x2.type(torch.int32)
x3 = x3.type(torch.float64)
print("x1.long: ", x1.dtype)
print("x2.int: ", x2.dtype)
print("x3.float64: ", x3.dtype)

输出为:

x1.dtype: torch.float32
x2.dtype: torch.float64
x3.dtype: torch.int64

x1.long: torch.int64
x2.int: torch.int32
x3.float64: torch.float64


4. 张量的存储设备

张量可以存储在 CPU 或 GPU 设备上。对于复杂网络模型和大规模数据,使用 GPU 进行特定类型的运算(如矩阵乘法)比 CPU 快得多。

注意两个张量只有在同一设备上才可以运算(CPU或者同一个GPU) 。存放在 CPU 上的数据不能与存放在 GPU 上的数据进行运算,位于不同 GPU 上的数据也不能直接运算。

4.1 检查 GPU 设备

在 PyTorch 中用 torch.device('cpu') 表示 CPU 设备,用 torch.device('cuda') 表示 GPU 设备。

CPU 设备包括所有物理 CPU 和内存,即 PyTorch 计算将尝试使用所有 CPU 核心。而 GPU 设备只代表一个 GPU 显卡与相应的显存。如果系统中有多个 GPU,使用 torch.device('cuda:{i}') 表示第 i 块 GPU 显卡,cuda:0 也可以以简写为 cuda 。

使用 torch.cuda.is_available() 可以检查系统是否具有 GPU 设备。如果没有 GPU 设备,则张量只能在 CPU 设备存储和运算。通常,面向用户的 API 与设备无关,开发者编写代码时无需关注具体的存储和运算设备,代码将根据设备情况在 CPU 或 GPU(如果可用)上运行。

# (13) 检查 GPU 设备
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print("device=", device)

print("CUDA版本: ", torch.version.cuda)
print("Pytorch版本: ", torch.__version__)
print("显卡是否可用: ", "GPU 可用" if(torch.cuda.is_available()) else " GPU 不可用")
print("显卡数量: ", torch.cuda.device_count())
print("是否支持BF16格式: ", "支持 BF16" if (torch.cuda.is_bf16_supported()) else "不支持 BF16")
print("当前显卡的型号: ", torch.cuda.get_device_name())
print("当前显卡的算力: ", torch.cuda.get_device_capability())
print("当前显卡的显存: ", torch.cuda.get_device_properties(0).total_memory/1024/1024/1024,'GB')
print("是否支持TensorCore: ", "支持" if (torch.cuda.get_device_properties(0).major >= 7) else "不支持")
print("当前显卡的使用率: ", torch.cuda.memory_allocated(0)/torch.cuda.get_device_properties(0).total_memory*100, "%")

输出结果:

device= cuda
CUDA版本: 11.7
Pytorch版本: 1.13.1
显卡是否可用: GPU 可用
显卡数量: 1
是否支持BF16格式: 支持 BF16
当前显卡的型号: NVIDIA GeForce RTX 3060
当前显卡的算力: (8, 6)
当前显卡的显存: 11.99951171875 GB
是否支持TensorCore: 支持
当前显卡的使用率: 0.0 %


4.2 指定张量的存储设备

创建张量时,默认的张量存储设备时。

通过 to(device) 方法可以把张量和模型放在特定设备上。

用户可以在创建张量时指定张量的存储设备,也可以更改已有张量的存储设备。更改张量 x 的存储设备,可以使用 x.cuda(0) 更改为 GPU,也可以使用 x.to(“cuda:0”) 方法。

由于 NumPy 不能使用 GPU,如果要使用 NumPy 与张量进行交互,就要将张量返回 CPU。

# (14) 指定张量的存储设备
# 在创建时指定张量的存储设备
x1 = torch.rand(3, 3, device="cpu")
x2 = torch.rand(3, 3, device="cuda")
x3 = torch.rand(3, 3, device="cuda:0")
# 获取张量的设备
print("x1: {}\nx2: {}\nx3: {}".format(x1.device, x2.device, x3.device))
# 修改张量的数据类型
x1 = x1.cuda(0)  # 将张量 x1 从 CPU 转移到 0#GPU
x2 = x1.to("cuda:0")  # # 将张量 x1 从 CPU 转移到 GPU
x3 = x3.cpu()  # # 将张量 x2 从 GPU 转移到 CPU
print("x1: {}\nx2: {}\nx3: {}".format(x1.device, x2.device, x3.device))

输出结果:

x1: cpu
x2: cuda:0
x3: cuda:0

x1: cuda:0
x2: cuda:0
x3: cpu


4.3 模型的 GPU 运算

PyTorch 模型也可以存储在 CPU 或 GPU 上。 默认情况 PyTorch 将数据创建在内存,利用 CPU 来计算。

类似地,可以检查模型参数的 device 属性来查看模型存放的设备,通过 to() 方法将模型转移到指定设备。

# (15) 模型的存储设备
model = torch.nn.Linear(3, 1)  # 线性模型
print("Linear model:\n", list(model.parameters()))
print("device of model: ", list(model.parameters())[0].device)

x = torch.rand(2, 3, device="cuda")  # 输入张量 x 在 GPU 设备
# print(model(x))  # 模型 model 与 输入张量 x 不在同一设备,程序报错

model.cuda()  # 将模型转移到 GPU
print("device of model: ", list(model.parameters())[0].device)
print(model(x))

输出结果:

Linear model:
[Parameter containing:
tensor([[ 0.3656, -0.1920, 0.5609]], requires_grad=True), Parameter containing:
tensor([-0.0030], requires_grad=True)]
device of model: cpu
device of model: cuda:0
tensor([[0.4553],
[0.4906]], device=‘cuda:0’, grad_fn=)

程序说明:

(1)Pytorch 模型需要与模型输入的 Tensor 在同一设备上,才能进行运算,否则将会报错:

RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cpu and cuda:0! (when checking argument for argument mat1 in method wrapper_addmm)

(2)由于输入参数存储在 GPU 设备,将模型转移到 GPU后,才能进行运算。


版权声明:
欢迎关注『youcans的深度学习』系列,转发请注明原文链接:
【youcans的深度学习 04】PyTorch入门教程:张量的基本操作(https://youcans.blog.csdn.net/article/details/130158748)
Copyright 2023 youcans, XUPT
Crated:2023-04-12


猜你喜欢

转载自blog.csdn.net/youcans/article/details/130158748