PyTorch中的张量运算函数超过100种,包括转置、索引、切片、数学运算、线性代数、随机采样。更详细的张量运算请查看官方文档:
torch — PyTorch 1.12 documentation
以上所有运算都可以在GPU上运行,比CPU的运算速度更快。
首先,要确保你的电脑已经安装了GPU版本的PyTorch,用以下命令来查看:
torch.cuda.is_available()
若返回 True
,则GPU是可用的。否则,只能在CPU上进行张量运算。
接下来,我们使用 to('cuda')
函数把张量移动到GPU上。
【注意】原本在CPU的张量只是复制了一个副本过去GPU,其本身仍旧存储在CPU上。因此使用 to('cuda')
函数时,要声明一个新的变量来接收GPU张量。
举个栗子:
import torch
tensor = torch.rand(3, 4) # 创建形状为(3, 4)的随机张量
if torch.cuda.is_available(): # 检查GPU是否可用
tensor_gpu = tensor.to('cuda') # 声明了新变量tensor_gpu来接收
print(f"GPU张量现在存储在:{tensor_gpu.device}")
print(f"原张量存储在:{tensor.device}")
输出:
GPU张量现在存储在:cuda:0
原张量存储在:cpu
以二维张量 (矩阵) 为例,我们先创建一个形状为 (4, 4) 的二维张量 tensor
:
import torch
tensor = torch.ones(4, 4)
print(f"Ones tensor: \n {tensor}")
输出:
Ones tensor:
tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])
张量切片的标准格式为:
tensor[r1:r2, c1:c2]
其中:
r1
表示切片开始的行数,r2
表示结束的行数。c1
表示切片开始的列数,c2
表示结束的列数。tensor[r1:r2, :]
;同理,若想选择整列,写成:tensor[:, c1:c2]
;全选则写成:tensor[:, :]
。:
,只写行号 (列号) 。举几个栗子:
1.标准切片
import torch
tensor = torch.ones(4, 4).to('cuda')
print(f"Ones tensor: \n{tensor} \n")
tensor[1:3, 1:3] = 0
print(tensor)
输出:
Ones tensor:
tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]], device='cuda:0')
tensor([[1., 1., 1., 1.],
[1., 0., 0., 1.],
[1., 0., 0., 1.],
[1., 1., 1., 1.]], device='cuda:0')
2.整行切片
tensor[1:3, :] = 0
输出:
Ones tensor:
tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]], device='cuda:0')
tensor([[1., 1., 1., 1.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[1., 1., 1., 1.]], device='cuda:0')
3.一列切片
tensor[:, 2] = 0
输出:
Ones tensor:
tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]], device='cuda:0')
tensor([[1., 1., 0., 1.],
[1., 1., 0., 1.],
[1., 1., 0., 1.],
[1., 1., 0., 1.]], device='cuda:0')
4.全部切片
tensor[:, :] = 0
输出:
Ones tensor:
tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]], device='cuda:0')
tensor([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]], device='cuda:0')
学会了以上操作,其他情况相信你可以很轻易地举一反三。
通过 torch.cat()
函数 ,可以把若干个张量按照你指定的维度方向进行拼接。
举个栗子:
import torch
tensor = torch.ones(4, 4).to('cuda')
tensor[:, 1] = 0
print(f"Origin tensor:\n{tensor}\n")
t1 = torch.cat([tensor, tensor, tensor], dim=1) # 水平拼接
print(f"Horizontal concatenate:\n{t1}\n")
t2 = torch.cat([tensor, tensor], dim=0) # 竖直拼接
print(f"Vertical concatenate:\n{t2}\n")
输出:
Origin tensor:
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]], device='cuda:0')
Horizontal concatenate:
tensor([[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.]], device='cuda:0')
Vertical concatenate:
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]], device='cuda:0')
tensor = torch.ones(4, 4).to('cuda')
tensor[:, 1] = 0
print(f"Origin tensor:\n{tensor}\n")
t1 = tensor.T # 张量的转置
print(f"Transposing tensor: \n{t1}")
输出:
Origin tensor:
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]], device='cuda:0')
Transposing tensor:
tensor([[1., 1., 1., 1.],
[0., 0., 0., 0.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]], device='cuda:0')
1.点乘
张量每个元素对应相乘,用 a ⋅ b a\cdot b a⋅b 表示。要求两个张量形状 (维度) 完全相同。
import torch
tensor = torch.ones(4, 4).to('cuda')
tensor[:, 1] = 2
print(f"Origin tensor:\n{tensor}\n")
# 张量的点乘:逐个元素对应相乘
t1 = tensor.mul(tensor)
print(f"tensor.mul(tensor): \n{t1}\n")
# 等价写法
t2 = tensor * tensor
print(f"tensor * tensor: \n{t2}\n")
输出:
Origin tensor:
tensor([[1., 2., 1., 1.],
[1., 2., 1., 1.],
[1., 2., 1., 1.],
[1., 2., 1., 1.]], device='cuda:0')
tensor.mul(tensor):
tensor([[1., 4., 1., 1.],
[1., 4., 1., 1.],
[1., 4., 1., 1.],
[1., 4., 1., 1.]], device='cuda:0')
tensor * tensor:
tensor([[1., 4., 1., 1.],
[1., 4., 1., 1.],
[1., 4., 1., 1.],
[1., 4., 1., 1.]], device='cuda:0')
2.叉乘
也称为矩阵乘法,矩阵的乘法就是矩阵 A A A 的第 m m m 行乘以矩阵 B B B 的第 n n n 列,各个元素对应相乘然后求和作为第 m m m 行 n n n 列元素的值。用 a × b a\times b a×b 表示。
要求:矩阵 A A A 的第 m m m 行元素数量等于矩阵 B B B 的第 n n n 列 。
# 张量的叉乘:矩阵乘法
t3 = tensor.matmul(tensor.T)
print(f"tensor.matmul(tensor.T): \n{t3}\n")
# 等价写法
t4 = tensor @ tensor.T
print(f"tensor @ tensor.T: \n{t4}")
输出:
tensor.matmul(tensor.T):
tensor([[7., 7., 7., 7.],
[7., 7., 7., 7.],
[7., 7., 7., 7.],
[7., 7., 7., 7.]], device='cuda:0')
tensor @ tensor.T:
tensor([[7., 7., 7., 7.],
[7., 7., 7., 7.],
[7., 7., 7., 7.],
[7., 7., 7., 7.]], device='cuda:0')
自动赋值运算在函数后添加 _
后缀来表示。例如,tensor.add_(x)
操作会改变 tensor
本身的值。
import torch
tensor = torch.ones(4, 4).to('cuda')
tensor[:, 1] = 2
print(f"Origin tensor:\n{tensor}\n")
tensor.add_(5) # 广播机制,每个元素都加5
print(f"tensor.add(5): \n{tensor}")
输出:
Origin tensor:
tensor([[1., 2., 1., 1.],
[1., 2., 1., 1.],
[1., 2., 1., 1.],
[1., 2., 1., 1.]], device='cuda:0')
tensor.add_(5):
tensor([[6., 7., 6., 6.],
[6., 7., 6., 6.],
[6., 7., 6., 6.],
[6., 7., 6., 6.]], device='cuda:0')
注意:
自动赋值运算虽然可以节省内存, 但在求导时会因为丢失了中间过程而导致一些问题,所以PyTprch官方并不鼓励使用它。