在PyTorch中,最小的计算单元是张量(tensor)。因此关于张量的学习还是至关重要的。通过本章节学习,希望你对张量有一个更清晰的了解。
文章目录
- 1 什么是Tensor
- 2 PyTorch中Tensor使用
- 2.1 创建Tensor
- 2.1.1 直接创建Tensor
- 2.1.2 间接创建Tensor
- 2.1.3 内置函数创建Tensor
- 3 Tensor的广播机制
- 4 PyTorch自动求导机制
- 5 参考
1 什么是Tensor
那什么是Tensor呢?按我的理解就是多维矩阵,只不过在此基础上添加了求导操作。
因此,tonsor支持所有矩阵运算操作,我们可以方便地使用PyTorch中的内置函数完成。同时,PyTorch有自己的数据类型,包括torch.int64
、torch.uint64
、torch.float64
等。在PyTorch中,我们只能使用PyTorch已定义的数据类型,并不支持自定义数据类型。
如果你想要了解更改tensor内容,参考官网网址:https://pytorch.org/docs/stable/tensors.html
2 PyTorch中Tensor使用
2.1 创建Tensor
创建Tensor有很多种方法,比如直接给定数据创建tensor、通过numpy创建tensor、通过内置函数创建tensor。下面分别对这三种方法讲解。
2.1.1 直接创建Tensor
tensor(data, dtype=None, device=None, requires_grad=False, pin_memory=False) -> Tensor
参数说明
- data: 数据
- dtype:数据类型。常见数据类型有torch.int8、torch.long、torch.float。更多数据类型请看: torch.Tensor
- device:指定Tensor运算设备。可指定 CPU 或者单个/多个 GPU。
- requires_grad:是否需要求导。
- pin_menory:是否常驻内存。这需要你在内存资源和运行速度之间做权衡。
示例
# 创建tensor,用dtype指定类型。注意类型要匹配
a = torch.tensor(1.0, dtype=torch.float)
b = torch.tensor(1, dtype=torch.long)
c = torch.tensor(1.0, dtype=torch.int8)
print(a, b, c)
-------------输出---------------
tensor(1.) tensor(1) tensor(1, dtype=torch.int8)
2.1.2 间接创建Tensor
间接创建指的是已经存在一个矩阵,需要转成Tensor。一般Tensor创建的来源有两个:list 和 array,但我们可以只用一个函数搞定。
as_tensor(data, dtype=None, device=None) -> Tensor
- List →Tensor
l = [[1, 2], [3, 4]] t = torch.as_tensor(l) print(t) ----------------------输出---------------------- tensor([[1, 2], [3, 4]])
- Array → Tensor
g = np.array([[1, 2, 3], [4, 5, 6]]) i = torch.from_numpy(g) print(i) ---------------------输出------------------------ tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.int32)
注意:torch.tensor创建得到的张量和原数据是不共享内存的,张量对应的变量是独立变量。
而torch.from_numpy()和torch.as_tensor()从numpy array创建得到的张量和原数据是共享内存的,张量对应的变量不是独立变量,修改numpy array会导致对应tensor的改变。
2.1.3 内置函数创建Tensor
对于比较规则的Tensor可以通过PyTorch的内置函数进行创建。
# 常见的构造Tensor的函数
k = torch.rand(2, 3)
l = torch.ones(2, 3)
m = torch.zeros(2, 3)
n = torch.arange(0, 10, 2)
print(k, "\n", l, "\n", m, "\n", n)
----------------------输出-----------------------------
tensor([[0.4003, 0.3830, 0.0535],
[0.6541, 0.4363, 0.7456]])
tensor([[1., 1., 1.],
[1., 1., 1.]])
tensor([[0., 0., 0.],
[0., 0., 0.]])
tensor([0, 2, 4, 6, 8])
3 Tensor的广播机制
在数学上,如果两个矩阵维度不符合运算原则是不允许运算的。但在PyTorch中,有一种情况例外,这就涉及到矩阵的广播机制。
矩阵的广播机制是指让两个不同shape的数组能够做一些运算,需要对参与运算的两个数组做一些处理或者说扩展,最终是参与运算的两个数组的shape一样,然后广播计算(对应位置数据进行某运算)得到结果。
当我们在进行元素级运算时常常会使用广播机制来提高代码可读性。
规则
比较两个数组的shape,从shape的尾部开始一一比对。
-
如果两个数组的维度相同,对应位置上轴的长度相同或其中一个的轴长度为1,广播兼容,可在轴长度为1的轴上进行广播机制处理。
-
如果两个数组的维度不同,那么给低维度的数组前扩展提升一维,扩展维的轴长度为1,然后在扩展出的维上进行广播机制处理。
比如下面这个例子,A矩阵是二维矩阵 [[1], [2], [3], [4], [5], [6]]
,B矩阵是一维矩阵 [2, 3]
。
- B 矩阵升维成二维矩阵
[[2, 3]]
- A 矩阵拓展
[[1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6]]
- B 矩阵拓展
[[2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3]]
- A + B
a = torch.arange(1, 7).view(6, 1)
print(a)
b = torch.arange(2, 4)
print(b)
print(a + b)
----------------------输出-----------------------------
tensor([[1],
[2],
[3],
[4],
[5],
[6]])
tensor([2, 3])
tensor([[3, 4],
[4, 5],
[5, 6],
[6, 7],
[7, 8],
[8, 9]])
4 PyTorch自动求导机制
torch.Tensor 是这个包的核心类。如果设置它的属性 .requires_grad 为 True,那么它将会追踪对于该张量的所有操作。当完成计算后可以通过调用 .backward(),来自动计算所有的梯度。这个张量的所有梯度将会自动累加到.grad属性。
这里将通过一个简单的函数 y = x 1 + 2 ∗ x 2 y=x_1+2*x_2 y=x1+2∗x2 来说明PyTorch自动求导的过程
import torch
x1 = torch.tensor(1.0, requires_grad=True)
x2 = torch.tensor(2.0, requires_grad=True)
y = x1 + 2 * x2
print(y)
## 反向传播后看导数大小, 导数是会累积的,重复运行相同命令,grad会增加
# 所以每次计算前需要清除当前导数值避免累积,这一功能可以通过pytorch的optimizer实现。或者调用zero_()
x1.grad.data.zero_()
x2.grad.data.zero_()
y.backward()
print(x1.grad.data)
print(x2.grad.data)
--------------------------输出------------------------
tensor(5., grad_fn=<AddBackward0>)
tensor(1.)
tensor(2.)
5 参考
- torch.Tensor - PyTorch, 2023
- NumPy广播机制详解 - Python学习园, 2024
- 2.2 自动求导 - ZhikangNiu, 深入浅出PyTorch, 2024