文章目录
- 一、张量简介与创建
- 1.1 简介
- 1.2 张量的创建
- 二、张量的操作
- 2.1 张量的拼接与切分
- 2.2 张量索引
- 三、张量的数学运算
一、张量简介与创建
1.1 简介
1. 张量是一个多维数组,它是标量、向量、矩阵的高维拓展。
2. 在张量的定义中,方括号用于表示张量的形状。例如,torch.tensor([[1, 2, 3], [4, 5, 6]])
定义了一个2x3的二维张量,其中方括号 [[…], […]] 表示该张量有2行3列。 例如,torch.tensor([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
定义了一个2x2x3的三维张量,其中方括号 [[[…, …], […, …]], [[…, …], […, …]]] 表示该张量有2个2x3的矩阵。
3. PyTorch中的张量(Tensor)和数组(Array)之间存在一些关键区别。尽管它们在许多方面都很相似,但在一些重要的方面也有所不同。以下是它们之间的主要区别:
- 底层库:PyTorch的张量是基于PyTorch库的,而数组通常是基于NumPy库的。这是两者之间的主要区别。
- 动态计算图:PyTorch的张量支持动态计算图,这意味着可以在运行时动态构建、修改和执行计算图。这使得PyTorch非常适合于构建复杂的神经网络和其他动态计算任务。数组则不支持动态计算图。
- GPU加速:PyTorch的张量可以方便地在CPU和GPU之间移动,以便利用GPU加速计算。这使得PyTorch非常适合于大规模数据处理和深度学习任务。数组也可以通过NumPy的库函数在GPU上运行,但不如PyTorch方便。
- 自动求导:PyTorch的张量支持自动求导功能,可以自动计算函数的梯度。这使得PyTorch非常适合于深度学习和优化任务。数组本身不支持自动求导,但可以通过NumPy的库函数手动计算梯度。
- 操作和函数:PyTorch的张量和NumPy的数组都提供了大量的操作和函数,用于执行各种数学运算、统计分析等。然而,PyTorch的张量还提供了一些专门用于深度学习的函数和操作,如卷积、池化等。
4. 张量中的8个属性:
data
:存储的实际数据,是一个多维数组。dtype
:张量中元素的数据类型,如torch.float32、torch.int64等。shape
:张量的形状,表示每个维度的大小。它是一个元组,例如(3, 256, 832)。device
:张量所在的设备,可以是CPU或GPU。requires_grad
:一个布尔值,表示是否需要计算梯度。如果设置为True,则PyTorch将记录该张量的操作历史,以便在反向传播时自动计算梯度。grad
:张量的梯度,形状与data一致。它存储了关于张量的梯度信息,用于反向传播和优化。grad_fn
:创建该张量时所用的函数(Function)。它记录了创建张量的操作历史,是自动求导的关键。is_leaf
:一个布尔值,表示该张量是否是叶子节点。叶子节点是指在计算图中没有依赖其他张量的节点。对于叶子节点,反向传播结束时其梯度仍会保存,非叶子节点的梯度会被释放,以节省内存。
1.2 张量的创建
1. 直接创建:
import torch
# 定义一个标量张量
x = torch.tensor(5)
print(x)
# 定义一个一维张量(向量)
y = torch.tensor([1, 2, 3, 4, 5])
print(y)
# 定义一个二维张量(矩阵)
z = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(z)
# 定义一个高维张量
w = torch.tensor([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
print(w)
2. 依据数值创建:
arr = np.array([1, 2, 3, 4, 5])
print(arr)
x = torch.tensor(arr)
print(x)
3. torch.arange
用于创建一个包含等间隔数值的一维张量(tensor)。注意:数值区间是[start, end)。
import torch
# 创建一个从 0 到 9 的一维张量,步长为 1
a = torch.arange(0, 10)
print(a)
# 输出:tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 创建一个从 1 到 10 的一维张量,步长为 2
b = torch.arange(1, 10, step=2)
print(b)
# 输出:tensor([1, 3, 5, 7, 9])
4. torch.linspace
用于创建一个包含等间隔数值的一维张量(tensor)。与torch.arange
不同的是,torch.linspace` 指定了序列中数值的个数,而不是步长。
import torch
# 创建一个从 0 到 1 的一维张量,包含 10 个数值
a = torch.linspace(0, 1, steps=10)
print(a)
# 输出:tensor([0.0000, 0.1111, 0.2222, 0.3333, 0.4444, 0.5556, 0.6667, 0.7778, 0.8889, 1.0000])
5. torch.normal
用于生成服从正态分布(高斯分布)的张量。其中每个元素都是从给定均值和标准差的正态分布中随机采样得到的。它可以用于生成随机数、模拟数据等。它的用法是:torch.normal(mean, std, size)
。
- mean:正态分布的均值。
- std:正态分布的标准差。
- size:生成张量的形状。
import torch
# 生成一个形状为 (3, 3) 的张量,服从均值为 0、标准差为 1 的正态分布
a = torch.normal(0, 1, size=(3, 3))
print(a)
#输出如下:
tensor([[ 0.6692, -0.6885, -0.3282],
[-1.0229, 0.2951, 1.3966],
[ 0.2123, -0.6048, 0.9535]])
6. torch.randn
用于生成服从标准正态分布(均值为 0,标准差为 1)的张量。torch.randn
函数返回一个指定形状的张量,其中每个元素都是从标准正态分布中随机采样得到的。它可以用于生成随机数、模拟数据等。与torch.normal
不同的是,torch.randn
默认生成的是标准正态分布的张量,而torch.normal
可以指定均值和标准差。
import torch
# 生成一个形状为 (3, 3) 的张量,服从标准正态分布
a = torch.randn(3, 3)
print(a)
二、张量的操作
2.1 张量的拼接与切分
1. torch.cat()
用于将多个张量按照指定的维度连接成一个新的张量。它的用法是:torch.cat(tensors, dim=0)
。
- tensors:一个包含多个张量的序列或元组。
- dim:连接的维度,默认为 0,表示在第 0 维上进行连接。
import torch
# 创建两个形状为 (3, 4) 的张量
a = torch.tensor([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
b = torch.tensor([[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]])
# 在第 0 维上连接两个张量
c = torch.cat((a, b), dim=0)
print(c)
#输出为:
tensor([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12],
[13, 14, 15, 16],
[17, 18, 19, 20],
[21, 22, 23, 24]])
2. torch.stack()
用于将多个张量沿着新的维度进行堆叠。它的用法是:torch.stack(seq, dim=0)
。注意:torch.stack()
函数要求所有被堆叠的张量的形状必须相同。
- 将 seq 序列中的每个张量视为一行,构建一个新的二维张量(即矩阵),其中第 i 行对应于第 i 个张量。
- 在指定的 dim 维度上对这些行进行堆叠,从而得到一个新的张量。
import torch
# 创建两个形状为 (3,) 的张量
a = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])
# 在第 0 维上堆叠两个张量
c = torch.stack((a, b), dim=0)
print(c)
#输出为:
tensor([[1, 2, 3],
[4, 5, 6]])
3. torch.chunk()
用于将张量拆分成多个块。它的用法是:torch.chunk(input, chunks, dim=0)
。
- input:要拆分的输入张量。
- chunks:拆分后的块数。
- dim:要进行拆分的维度,默认为0(第 0 维)。
函数会将输入张量在指定的维度上均匀拆分成 chunks 个块,并返回一个包含这些块的元组。每个块的形状是将输入张量的形状在第 dim 维上分割成 chunks 个相等的部分而得到的。
import torch
# 创建一个形状为 (6,) 的张量
x = torch.tensor([1, 2, 3, 4, 5, 6])
# 在第 0 维上拆分成 3 个块
chunks = torch.chunk(x, 3)
# 打印拆分后的块
for i, chunk in enumerate(chunks):
print(f"Chunk {i}: {chunk}")
#输出为:
Chunk 0: tensor([1, 2])
Chunk 1: tensor([3, 4])
Chunk 2: tensor([5, 6])
4. torch.split()
用于将张量拆分成多个块,与torch.chunk()
类似。它的用法是:torch.split(tensor, split_size, dim=0)
。
- tensor:要拆分的输入张量。
- split_size:每个块的大小。
- dim:要进行拆分的维度,默认为0(第 0 维)。
import torch
# 创建一个形状为 (8, 3) 的张量
x = torch.randn(8, 3)
# 在第 0 维上拆分成大小为 2 的块
splits = torch.split(x, 2, dim=0)
# 打印拆分后的块
for i, split in enumerate(splits):
print(f"Split {i}: {split.shape}")
#输出为:
Split 0: torch.Size([2, 3])
Split 1: torch.Size([2, 3])
Split 2: torch.Size([2, 3])
Split 3: torch.Size([2, 3])
在这个示例中,我们创建了一个形状为 (8, 3) 的张量 x。然后,我们使用 torch.split(x, 2, dim=0) 在第 0 维上将其拆分成大小为 2 的块。最后,我们打印了每个块的形状。可以看到,输入张量被均匀拆分成了 4 个大小为 (2, 3) 的块。
2.2 张量索引
1. torch.index_select()
用于沿着指定维度对张量进行索引。它返回一个新的张量,该张量是按照给定的索引从源张量中选择的元素构成的。它的用法是:torch.index_select(input, dim, index)
。
- input:源张量,即要进行索引操作的张量。
- dim:要进行索引的维度。
- index:包含索引值的张量。索引值必须是非负整数,且不超过源张量在指定维度上的大小。
import torch
# 创建一个 3x3 的张量
x = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 选择第 0 行(索引为 0)和第 2 行(索引为 2)
indices = torch.tensor([0, 2])
# 沿着维度 0(即行)进行索引选择
selected = torch.index_select(x, 0, indices)
print(selected)
#输出为:
tensor([[1, 2, 3],
[7, 8, 9]])
在这个例子中,我们首先创建了一个 3x3 的张量 x。然后,我们指定要选择的行的索引,即第 0 行和第 2 行。最后,我们调用torch.index_select()
函数,指定要索引的维度为 0(即行),并传入源张量和索引张量。函数返回一个新的张量,其中包含了选择的行。
2. torch.masked_select()
用于根据掩码张量从源张量中选择元素。它返回一个新的张量(返回值:一维张量),该张量包含源张量中对应掩码值为 True 的元素。它的用法是:torch.masked_select(input, mask)
。
- input:源张量,即要进行选择的张量。
- mask:掩码张量,具有与源张量相同的形状,并包含布尔值。True 表示选择对应的元素,False 表示不选择。
import torch
# 创建一个 3x3 的张量
x = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 创建一个掩码张量,选择大于 4 的元素
mask = x > 4
# 根据掩码选择元素
selected = torch.masked_select(x, mask)
print(selected)
#输出为:
tensor([5, 6, 7, 8, 9])
在这个例子中,我们首先创建了一个 3x3 的张量 x。然后,我们创建一个掩码张量 mask,其中大于 4 的元素被标记为 True。最后,我们调用 torch.masked_select() 函数,传入源张量和掩码张量。函数返回一个新的张量,其中包含了源张量中对应掩码值为 True 的元素。
三、张量的数学运算
1. torch.reshape()
用于改变张量的形状。它返回一个新的张量,该张量与原始张量共享数据,但具有不同的形状。它的用法是:torch.reshape(input, shape)
。
- input:要进行形状改变的原始张量。
- shape:新的形状,表示为一个整数列表或元组。新的形状必须与原始张量中的元素总数相同。
import torch
# 创建一个形状为 [2, 3] 的张量
x = torch.tensor([[1, 2, 3], [4, 5, 6]])
# 改变形状为 [3, 2]
reshaped = torch.reshape(x, [3, 2])
print(reshaped)
#输出为:
tensor([[1, 2],
[3, 4],
[5, 6]])
在这个例子中,我们首先创建了一个形状为 [2, 3] 的张量 x。然后,我们调用 torch.reshape() 函数,将 x 的形状改变为 [3, 2]。函数返回一个新的张量 reshaped,它与 x 共享数据,但具有不同的形状。
2. torch.transpose()
用于交换张量中的两个维度。它返回一个新的张量,其中指定的两个维度互换位置。它的用法是:torch.transpose(input, dim0, dim1)
。
- input:要进行维度交换的原始张量。
- dim0:要交换的第一个维度的索引。
- dim1:要交换的第二个维度的索引。
import torch
# 创建一个形状为 [2, 3, 4] 的张量
x = torch.randn(2, 3, 4)
print(x)
# 交换第 0 和第 1 个维度
y = torch.transpose(x, 0, 1)
print(y)
print(y.shape) # 输出:torch.Size([3, 2, 4])
在这个例子中,我们首先创建了一个形状为 [2, 3, 4] 的张量 x。然后,我们调用 torch.transpose() 函数,将 x 中的第 0 和第 1 个维度交换。函数返回一个新的张量 y,其中第 0 和第 1 个维度互换位置,形状变为 [3, 2, 4]。