🚀PyTorch 入门指南 2:Tensor 的深度解析(操作篇)

💡一、Tensor 的类型

在 PyTorch 中,Tensor 拥有多种数据类型,满足不同计算需求。以下是常见类型及对应表示:

数据类型描述PyTorch 类型表示(方式一)PyTorch 类型表示(方式二)旧版 Tensor 类型表示
32 位浮点数torch.float32torch.floattorch.*.FloatTensor
64 位浮点数torch.float64torch.doubletorch.*.DoubleTensor
16 位浮点数torch.float16torch.halftorch.*.HalfTensor
8 位无符号整数torch.uint8torch.*.ByteTensor
8 位有符号整数torch.int8torch.*.CharTensor
16 位有符号整数torch.int16torch.shorttorch.*.ShortTensor
32 位有符号整数torch.int32torch.inttorch.*.IntTensor
64 位有符号整数torch.int64torch.longtorch.*.LongTensor
布尔类型torch.booltorch.*.BoolTensor

不同类型在存储和精度上有差异,需根据任务(如模型精度、内存占用)选择。例如,图像数据常用 torch.float32,内存敏感场景可用 torch.float16

🛒二、Tensor 的创建

PyTorch 提供丰富函数创建 Tensor,以下是常用函数、功能说明及代码示例:

📝2.1 基础构造函数与数据转换

  • Tensor(*size):按指定维度创建未初始化的 Tensor(值随机,不建议直接用其值)
  • Tensor(data):类似 np.array,根据输入数据(如列表)创建 Tensor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import torch

# Tensor(*size) 示例
uninitialized_tensor = torch.Tensor(2, 3)
print("未初始化 Tensor 形状:", uninitialized_tensor.shape) # 输出:torch.Size([2, 3])
print("未初始化 Tensor 值(随机):\n", uninitialized_tensor)

# Tensor(data) 示例
data_list = [[1, 2], [3, 4]]
data_tensor = torch.Tensor(data_list)
print("\n根据列表创建的 Tensor:\n", data_tensor)
# 输出:
# tensor([[1., 2.],
# [3., 4.]])

✨2.2 特殊值 Tensor

  • ones(*size):创建全 1 的 Tensor
  • zeros(*size):创建全 0 的 Tensor
  • eye(*size):创建对角线为 1、其余为 0 的 Tensor(适用于方阵)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# ones 示例
ones_tensor = torch.ones(2, 3)
print("\n全 1 的 Tensor:\n", ones_tensor)
# 输出:
# tensor([[1., 1., 1.],
# [1., 1., 1.]])

# zeros 示例
zeros_tensor = torch.zeros(3, 4)
print("\n全 0 的 Tensor:\n", zeros_tensor)
# 输出:
# tensor([[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]])

# eye 示例
eye_tensor = torch.eye(3)
print("\n对角线为 1 的 Tensor:\n", eye_tensor)
# 输出:
# tensor([[1., 0., 0.],
# [0., 1., 0.],
# [0., 0., 1.]])

📈2.3 序列与分布 Tensor

  • arange(s, e, step):创建从 se(不包含 e)、步长为 step 的 1 维 Tensor
  • linspace(s, e, steps):创建从 se、均匀切分成 steps 份的 1 维 Tensor
  • rand(*size):创建服从均匀分布的 Tensor
  • randn(*size):创建服从标准正态分布的 Tensor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# arange 示例
arange_tensor = torch.arange(1, 10, 2)
print("\narange 创建的 Tensor:", arange_tensor)
# 输出:tensor([1, 3, 5, 7, 9])

# linspace 示例
linspace_tensor = torch.linspace(1, 10, 4)
print("\nlinspace 创建的 Tensor:", linspace_tensor)
# 输出:tensor([ 1.0000, 4.0000, 7.0000, 10.0000])

# rand 示例
rand_tensor = torch.rand(2, 3)
print("\n均匀分布的 Tensor:\n", rand_tensor)
# 输出(数值随机):
# tensor([[0.1234, 0.5678, 0.9012],
# [0.3456, 0.7890, 0.2345]])

# randn 示例
randn_tensor = torch.randn(2, 2)
print("\n标准正态分布的 Tensor:\n", randn_tensor)
# 输出(数值随机):
# tensor([[ 0.123, -0.456],
# [ 0.789, -0.012]])

🎲2.4 特定分布 Tensor

  • normal(mean, std):创建指定均值和标准差的正态分布 Tensor
  • uniform_(from, to):对已有 Tensor 填充区间均匀分布的值
  • randperm(m):创建 0 到 m-1 的随机排列 1 维 Tensor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# normal 示例
normal_tensor = torch.normal(mean=0.0, std=1.0, size=(2, 2))
print("\n指定均值标准差的正态分布 Tensor:\n", normal_tensor)
# 输出(数值随机):
# tensor([[ 0.12, -0.34],
# [ 0.56, -0.78]])

# uniform_ 示例
uniform_tensor = torch.zeros(2, 2)
uniform_tensor.uniform_(0, 1) # 原地修改为 0-1 均匀分布
print("\n均匀分布填充的 Tensor:\n", uniform_tensor)
# 输出(数值随机):
# tensor([[0.123, 0.456],
# [0.789, 0.012]])

# randperm 示例
randperm_tensor = torch.randperm(5)
print("\n随机排列的 Tensor:", randperm_tensor)
# 输出(数值随机,如):tensor([3, 1, 4, 2, 0])

📜三、Tensor 的属性

每个 Tensor 包含三种核心属性:torch.dtype(数据类型)、torch.device(存储设备)、torch.layout(内存布局)。

📍3.1 torch.dtype:数据类型

表示 Tensor 存储的数据类型,创建时可显式指定,也可通过已有 Tensor 查看。

1
2
3
4
5
6
7
8
9
10
11
import torch

# 创建时指定 dtype
float_tensor = torch.tensor([1.1, 2.2], dtype=torch.float32)
print("指定 float32 类型的 Tensor 数据类型:", float_tensor.dtype)
# 输出:torch.float32

# 从已有数据推断 dtype
int_tensor = torch.tensor([1, 2, 3])
print("\n自动推断类型的 Tensor 数据类型:", int_tensor.dtype)
# 输出:torch.int64

💾3.2 torch.device:存储设备

标识 Tensor 存储在 'cpu''cuda'(需 GPU 可用)。可创建时指定,或通过 to() 方法移动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import torch

# 创建时指定存储设备(假设 GPU 可用)
if torch.cuda.is_available():
gpu_tensor = torch.tensor([1, 2, 3], device=torch.device('cuda'))
print("GPU 上的 Tensor 设备:", gpu_tensor.device)
# 输出:cuda:0(若有多个 GPU,编号可能不同)

# 将 CPU 上的 Tensor 移动到 GPU
cpu_tensor = torch.tensor([4, 5, 6])
gpu_tensor_again = cpu_tensor.to(torch.device('cuda'))
print("\n移动到 GPU 后的 Tensor 设备:", gpu_tensor_again.device)
# 输出:cuda:0

# CPU 设备示例(无论有无 GPU 都适用)
cpu_only_tensor = torch.tensor([7, 8, 9], device=torch.device('cpu'))
print("\nCPU 上的 Tensor 设备:", cpu_only_tensor.device)
# 输出:cpu

📦3.3 torch.layout:内存布局

  • 密集布局(torch.strided:普通 Tensor 的默认布局,连续存储元素。
  • 稀疏布局(如 torch.sparse_coo:用于稀疏张量,存储非零元素的坐标和值。
1
2
3
4
5
6
import torch

# 密集布局(默认)
dense_tensor = torch.tensor([[1, 2], [3, 4]])
print("密集布局 Tensor 的 layout:", dense_tensor.layout)
# 输出:torch.strided

🗄️四、Tensor 的属性——稀疏的张量

对于大部分元素为零的矩阵,PyTorch 用稀疏张量优化存储和计算,仅存储非零元素的坐标和值,减少内存占用,提升计算效率。

🔍4.1 稀疏张量的原理

稀疏张量通过记录非零元素的索引(坐标)和对应值,省略零元素存储。例如一个 100×100 的矩阵若只有 10 个非零元素,稀疏张量只需存储这 10 个元素的位置和值,而非 10000 个元素。

🧰4.2 稀疏张量的创建

使用 torch.sparse_coo_tensor,需传入非零元素索引 indices、值 values 和形状 shape

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import torch

# 定义非零元素索引(二维矩阵示例,索引格式为 [行索引列表, 列索引列表])
indices = torch.tensor([[0, 1, 1], [2, 0, 2]]) # 表示 3 个非零元素的坐标(0,2)(1,0)(1,2)
values = torch.tensor([3.0, 4.0, 5.0], dtype=torch.float32) # 非零元素的值
shape = (2, 4) # 稀疏张量的形状

sparse_tensor = torch.sparse_coo_tensor(indices, values, shape)
print("稀疏张量:\n", sparse_tensor)
# 输出:
# tensor(indices=tensor([[0, 1, 1],
# [2, 0, 2]]),
# values=tensor([3., 4., 5.]),
# size=(2, 4), nnz=3, layout=torch.sparse_coo)

🌐4.3 稀疏张量的应用场景

  • 自然语言处理(NLP):词袋模型中,文档 - 词项矩阵稀疏,用稀疏张量存储可节省内存。
  • 推荐系统:用户 - 物品评分矩阵稀疏,稀疏张量优化存储和协同过滤计算。
  • 图神经网络:邻接矩阵常稀疏,稀疏张量提升图数据处理效率。

🔄4.4 稀疏张量与密集张量的转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import torch

# 稀疏张量转密集张量
indices = torch.tensor([[0, 1, 1], [2, 0, 2]])
values = torch.tensor([3.0, 4.0, 5.0], dtype=torch.float32)
shape = (2, 4)
sparse_tensor = torch.sparse_coo_tensor(indices, values, shape)

dense_tensor = sparse_tensor.to_dense()
print("稀疏张量转密集张量:\n", dense_tensor)
# 输出:
# tensor([[0., 0., 3., 0.],
# [4., 0., 5., 0.]])

# 密集张量转稀疏张量
new_sparse_tensor = torch.sparse_coo_tensor.from_dense(dense_tensor)
print("\n密集张量转稀疏张量:\n", new_sparse_tensor)
# 输出:
# tensor(indices=tensor([[0, 1, 1],
# [2, 0, 2]]),
# values=tensor([3., 4., 5.]),
# size=(2, 4), nnz=3, layout=torch.sparse_coo)

🎯五、总结

通过以上内容,全面学习了 Tensor 的类型、创建方法、核心属性以及稀疏张量的相关知识。实际应用中,可根据任务需求灵活选择 Tensor 的类型、创建方式和存储设备,对稀疏数据合理使用稀疏张量优化流程。