Pytorch 的tensor (张量)的介绍

2022-04-15 08:27:05 浏览数 (1)

Tensor是Pytorch中最基本的一种数据抽象,它类似于C或numpy中的数组,可以有多个维度。张量也可以在GPU上使用以提高性能。

  • 常用的创建张量的方法有:
  • torch.empty():创建未初始化的张量。
代码语言:javascript复制
>>> a = torch.empty(2,3)
>>> a 
tensor([[1.0286e-38, 9.0919e-39, 8.9082e-39],
        [9.2755e-39, 8.4490e-39, 9.6429e-39]])
>>> b = torch.empty(2,3)
>>> b
tensor([[1.0286e-38, 9.0919e-39, 8.9082e-39],
        [9.2755e-39, 8.4490e-39, 9.6429e-39]])
>>> a[0][0] = 55. # 可以给元素赋值
>>> a
tensor([[5.5000e 01, 9.0919e-39, 8.9082e-39],
        [9.2755e-39, 8.4490e-39, 9.6429e-39]])
>>> a[1] = 22. # 可以按某个维度统一赋值
>>> a
tensor([[5.5000e 01, 9.0919e-39, 8.9082e-39],
        [2.2000e 01, 2.2000e 01, 2.2000e 01]])
>>> a[:,1] = 44. # 可以按某个维度统一赋值 
>>> a
tensor([[5.5000e 01, 4.4000e 01, 8.9082e-39],
        [2.2000e 01, 4.4000e 01, 2.2000e 01]])
  • torch.zeros():创建元素值全为零的张量。
代码语言:javascript复制
>>> a = torch.zeros((2,3,4))
>>> a
tensor([[[0., 0., 0., 0.],
         [0., 0., 0., 0.],
         [0., 0., 0., 0.]],
        [[0., 0., 0., 0.],
         [0., 0., 0., 0.],
         [0., 0., 0., 0.]]])
  • torch.ones():创建元素值全为1的张量。
代码语言:javascript复制
>>> b = torch.ones((3,4))
>>> b
tensor([[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]])
        
>>> a = torch.empty((2,3))
>>> a
tensor([[-3.9696e-19,  4.5914e-41, -3.9696e-19],
        [ 4.5914e-41, -3.9696e-19,  4.5914e-41]])
# out参数可以指定生成的tensor输出给其它变量
# empty(), ones(), zeros()等都有out参数
>>> torch.ones((2,3), out=a) 
tensor([[1., 1., 1.],
        [1., 1., 1.]])
>>> a
tensor([[1., 1., 1.],
        [1., 1., 1.]])
  • 线性填充创建张量
代码语言:javascript复制
>>> torch.arange(1., 5.)  # 和numpy中的用法基本一致
tensor([1., 2., 3., 4.])
>>> torch.arange(1., 10., 2)
tensor([1., 3., 5., 7., 9.])
>>> torch.linspace(0,1,11)  # 和numpy中的用法基本一致
tensor([0.0000, 0.1000, 0.2000, 0.3000, 0.4000, 0.5000, 0.6000, 0.7000, 0.8000, 0.9000, 1.0000])
  • 创建随机张量。深度学习中常用于初始化权重张量w。
代码语言:javascript复制
>>> a = torch.rand(2,3)  # [0, 1) 均匀分布
>>> a
tensor([[0.4202, 0.3845, 0.9435],
        [0.8606, 0.9898, 0.7223]])
>>> b = torch.rand(2,3)
>>> b
tensor([[0.5876, 0.8672, 0.1454],
        [0.8283, 0.6713, 0.1481]]
>>> torch.randn((2,6))  #标准正态分布(mean为0,std为1的normal分布)
tensor([[-0.6857, -0.5643,  1.1925,  1.9629,  0.7755, -0.0425],
        [ 0.0553,  0.3286,  1.7301, -0.7192,  0.9045, -1.5953]])
>>>torch.randint(-1, 10, (1,20)) # low=-1, high=10 整数均匀分布
tensor([[4, 3, 3, 3, 6, 4, 4, 3, 1, 0, 1, 2, 1, 8, 3, 8, 8, 8, 1, 6]])

可以手动设置随机种子

代码语言:javascript复制
>>> torch.manual_seed(317)
<torch._C.Generator object at 0x000001935EE0FE28>
>>> a = torch.rand(2,3)
>>> torch.manual_seed(317)
<torch._C.Generator object at 0x000001935EE0FE28>
>>> b = torch.rand(2,3)
>>> a
tensor([[0.9137, 0.1671, 0.9334],
        [0.3699, 0.6616, 0.1785]])
>>> b
tensor([[0.9137, 0.1671, 0.9334],
        [0.3699, 0.6616, 0.1785]])
>>> a == b
tensor([[True, True, True],
        [True, True, True]])
  • torch.eye() 创建单位矩阵式的二维张量,主对角线元素全为1,其它元素全为0。
代码语言:javascript复制
>>> torch.eye(4)
tensor([[1., 0., 0., 0.],
        [0., 1., 0., 0.],
        [0., 0., 1., 0.],
        [0., 0., 0., 1.]])
  • torch.xxxx_like()根据其它张量的形状创建张量。
代码语言:javascript复制
>>> a = torch.ones((3,2)) # shape参数也可以传入tuple或list
>>> a
tensor([[1., 1.],
        [1., 1.],
        [1., 1.]])
>>> torch.empty_like(a)
tensor([[1., 1.],
        [1., 1.],
        [1., 1.]])
>>> torch.zeros_like(a)
tensor([[0., 0.],
        [0., 0.],
        [0., 0.]])
>>> torch.ones_like(a)
tensor([[1., 1.],
        [1., 1.],
        [1., 1.]])
  • pytorch.tensor() 给定元素手动创建张量
代码语言:javascript复制
>>> torch.tensor(1)  # 零维张量(标量)
tensor(1)
>>> torch.tensor((1,2)) # 1维张量
tensor([1, 2])
>>> torch.tensor([[1,2],[3,4]]) # 2维张量
tensor([[1, 2],
        [3, 4]])
>>> torch.tensor(((1,2),[3,4])) # 2维张量, tuple 和 list 可以混用
tensor([[1, 2],
        [3, 4]])
  • tensor 的数据类型,常见的数据类型有 torch.bool torch.int8 torch.uint8 torch.int16 torch.int32 torch.int64 torch.half torch.float torch.double torch.bfloat
代码语言:javascript复制
# 可以在创建时通过dtype参数指定数据类型
a = torch.ones((2, 3), dtype=torch.int16)
print(a)
b = torch.rand((2, 3), dtype=torch.float64) * 20.
print(b)

# 也可以转换
c = b.to(torch.int32)
  • tensor 的 维度信息(size)
代码语言:javascript复制
>>> x = torch.ones((1,2,3))
>>> x
tensor([[[1., 1., 1.],
         [1., 1., 1.]]])
>>> x.shape
torch.Size([1, 2, 3])
>>> x.size()
torch.Size([1, 2, 3])
>>> x.shape == x.size()
True
>>> x.shape is x.size()
False
代码语言:javascript复制
>>> x.shape[0]
1
>>> x.shape[1]
2
代码语言:javascript复制
>>> x = torch.tensor(5.)
>>> x
tensor(5.)
>>> x.shape
torch.Size([]) # 零维度张量的shape
  • tensor 的 reshape。同numpy一样,可以改变tensor的shape,新的tensor只是是原来tensor的视图,二者共享存储空间。
代码语言:javascript复制
>>> a = torch.rand((3,4))
>>> b = a.reshape((4,3))
>>> b[0,0]=22.22
>>> a
tensor([[22.2200,  0.9620,  0.7581,  0.1273],
        [ 0.5137,  0.9653,  0.1091,  0.3371],
        [ 0.0306,  0.7359,  0.7835,  0.9451]])
# 也可以用view()
>>> c = a.view(2,-1) # 同numpy一样,最后一个维度可以设为-1,自动分配。
>>> c
tensor([[22.2200,  0.9620,  0.7581,  0.1273,  0.5137,  0.9653],
        [ 0.1091,  0.3371,  0.0306,  0.7359,  0.7835,  0.9451]])
>>> c[0,1]=33.33
>>> a
tensor([[2.2220e 01, 3.3330e 01, 7.5810e-01, 1.2730e-01],
        [5.1369e-01, 9.6526e-01, 1.0907e-01, 3.3712e-01],
        [3.0613e-02, 7.3591e-01, 7.8346e-01, 9.4511e-01]])

零维tensor转为python数值

  • tensor的切片操作,同numpy一样。
代码语言:javascript复制
>>> x
tensor([[8, 4, 4, 0, 3],
        [5, 4, 9, 3, 2],
        [4, 6, 0, 2, 2],
        [3, 8, 3, 9, 9],
        [3, 6, 7, 9, 3]])
>>> x[1:3,2:-1]
tensor([[9, 3],
        [0, 2]])
  • tensors的拼接
代码语言:javascript复制
>>> a = torch.randn(3,2)
>>> b = torch.randn(3,1)
>>> torch.cat((a,b),dim=1)
tensor([[-0.4081, -0.1116,  0.3356],
        [-0.6456,  0.0837,  0.4141],
        [ 0.7786,  1.0901, -0.6719]])

tensor 与 numpy数组 互相转化

代码语言:javascript复制
>>> t2 = torch.from_numpy(n)
>>> t2
tensor([99.,  1.,  1.,  1.,  1.])
>>> n[2]=22.22
>>> n
array([99.  ,  1.  , 22.22,  1.  ,  1.  ], dtype=float32)
>>> t2  # tensor 和 array 共享存储空间
tensor([99.0000,  1.0000, 22.2200,  1.0000,  1.0000])

tensor的数学运算。

  • size相同的tensors之间可以进行数学运算。除非可以进行broadcast,不同size的tensors之间不可以进行数学计算。
代码语言:javascript复制
>>> a = torch.rand((2,3))
>>> a
tensor([[0.7301, 0.3747, 0.4656],
        [0.9889, 0.8834, 0.7723]])
>>> b = torch.ones_like(a)
>>> b
tensor([[1., 1., 1.],
        [1., 1., 1.]])
>>> a b
tensor([[1.7301, 1.3747, 1.4656],
        [1.9889, 1.8834, 1.7723]])
>>> a*b  # 等价于 torch.mul(a,b)
tensor([[0.7301, 0.3747, 0.4656],
        [0.9889, 0.8834, 0.7723]])
>>> a *= b
>>> a
tensor([[0.7301, 0.3747, 0.4656],
        [0.9889, 0.8834, 0.7723]])
>>> a -= b
>>> a
tensor([[-0.2699, -0.6253, -0.5344],
        [-0.0111, -0.1166, -0.2277]])
  • 和numpy一样,torch也自带许多数学函数,如
代码语言:javascript复制
>>> torch.sin(a)
tensor([[-0.2667, -0.5853, -0.5093],
        [-0.0111, -0.1163, -0.2257]])
>>> torch.cos(a)
tensor([[0.9638, 0.8108, 0.8606],
        [0.9999, 0.9932, 0.9742]])
>>> torch.asin(a)
tensor([[-0.2733, -0.6755, -0.5637],
        [-0.0111, -0.1168, -0.2297]])
>>> torch.sinh(a)
tensor([[-0.2732, -0.6669, -0.5601],
        [-0.0111, -0.1168, -0.2297]])
>>> torch.max(a)
tensor(-0.0111)
>>> a.mean()
tensor(-0.2975)
>>> a.mean(dim=1) # 可以指定维度
tensor([-0.4765, -0.1185])
>>> b
tensor([[3., 3., 3.],
        [3., 3., 3.]])
>>> torch.std_mean(b) # 计算b标准差和mean
(tensor(0.), tensor(3.))
>>> torch.svd(b) # SVD 分解
torch.return_types.svd(
U=tensor([[-0.7071,  0.7071],
        [-0.7071, -0.7071]]),
S=tensor([7.3485e 00, 4.0850e-07]),
V=tensor([[-0.5774, -0.8165],
        [-0.5774,  0.4082],
        [-0.5774,  0.4082]]))
>>> a = torch.randn(4,4)
>>> torch.det(a) # 计算方阵的行列式
tensor(0.6460)
# 等等等等
  • 矩阵乘法,torch.matmul()
代码语言:javascript复制
>>> a = torch.randn(3,2)
>>> b=torch.randn(2,5)
>>> torch.matmul(a,b)
tensor([[-3.4743, -0.5266,  0.3270, -2.7448, -0.7288],
        [-5.9377, -1.4233,  0.9677, -2.2013, -3.4487],
        [-2.5309, -0.8615,  0.6115,  0.2738, -2.5426]])
  • tensor 的广播(broadcast),与 numpy 的广播类似
代码语言:javascript复制
a
tensor([[1., 1., 1.],
        [1., 1., 1.]])
b = a 2
b
tensor([[3., 3., 3.],
        [3., 3., 3.]])
b**2
tensor([[9., 9., 9.],
        [9., 9., 9.]])
(torch.rand(2, 2) - 0.5) * 2
tensor([[-0.1330, -0.1400],
        [-0.9692, -0.5754]])
  • 不同shape的tensors之间广播的规则如下:
  1. 不能有空的tensor
  2. 从后往前比较两个tensors的维度(从右往左对齐观察), 每个维度的大小都相等,或者 其中一个维度的大小必须是1,或者 其中一个tensor的某个维度缺失。
代码语言:javascript复制
a = torch.ones(4, 3, 2)

b = a * torch.rand(   3, 2) # 3rd & 2nd dims identical to a, dim 1 absent
print(b)

c = a * torch.rand(   3, 1) # 3rd dim = 1, 2nd dim identical to a
print(c)

d = a * torch.rand(   1, 2) # 3rd dim identical to a, 2nd dim = 1
print(d)
  • tensor 可以转到 GPU 上进行计算
代码语言:javascript复制
b = a.to("cuda")
b
tensor([[ 1.2982, -0.1432, -0.9152,  0.8028],
        [-0.3701,  0.2217,  0.7523,  0.7443],
        [-0.1457,  0.7082, -1.1346,  0.8564],
        [-0.2956,  0.1779,  0.9134, -0.0069]], device='cuda:0')
b**2
tensor([[1.6853e 00, 2.0511e-02, 8.3754e-01, 6.4442e-01],
        [1.3698e-01, 4.9144e-02, 5.6598e-01, 5.5392e-01],
        [2.1235e-02, 5.0161e-01, 1.2873e 00, 7.3339e-01],
        [8.7371e-02, 3.1664e-02, 8.3422e-01, 4.8006e-05]], device='cuda:0')

GPU上的 tensor 可以转回CPU.

代码语言:javascript复制
c = b.to("cpu")
c
tensor([[ 1.2982, -0.1432, -0.9152,  0.8028],
        [-0.3701,  0.2217,  0.7523,  0.7443],
        [-0.1457,  0.7082, -1.1346,  0.8564],
        [-0.2956,  0.1779,  0.9134, -0.0069]])
c.device
device(type='cpu')

不同设备上的tensors 之间不能进行计算。

代码语言:javascript复制
a b
Traceback (most recent call last):
  File "E:Python36libcode.py", line 91, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!

0 人点赞