1 张量

# 1 张量

pytorch的数据类型,类似pandas里的Dateframe。是基于标量、向量和矩阵概率的延伸。

# 导包
import torch
import numpy as np
1
2
3

# 1.1 数据类型

# 1.1.1 创建张量

arr = np.array([[1,2,3],[4,5,6]])
x = torch.Tensor(arr) # # 将 NumPy 数组转换为一个 PyTorch 张量

print(x)
1
2
3
4
tensor([[1., 2., 3.],
        [4., 5., 6.]])

# 1.1.2 创建张量随机数方法

# torch.rand

服从[0,1)的均匀分布

tensor1 = torch.rand(3,4)
tensor1
1
2
tensor([[0.5067, 0.0992, 0.2738, 0.5640],
        [0.8371, 0.4079, 0.1452, 0.8652],
        [0.8629, 0.9054, 0.6144, 0.2549]])

# torch.randn()

服从均值0,方差1的标准正态分布

tensor1 = torch.randn(3,4)
tensor1
1
2
tensor([[-2.3690, -0.6055, -0.5592, -1.6116],
        [ 0.4369,  0.2237, -0.7167, -0.1619],
        [ 1.4463,  1.3810, -0.3767, -2.4971]])

# torch.normal(means, std, out=None)

  1. 指定均值方差
tensor1 = torch.normal(mean=torch.arange(1.,11.), std=torch.arange(0, 1, 0.1))
tensor1
1
2
tensor([ 1.0000,  1.8565,  3.0861,  3.9785,  4.5556,  5.7291,  8.1138,  7.8268,
         8.4596, 10.6865])
  1. 共享均值方差
tensor1 = torch.normal(mean=10, std=torch.arange(0,1,0.1))
tensor1

tensor2 = torch.normal(1,2,size=(10,3))
tensor2
1
2
3
4
5
tensor([[ 0.1712, -1.1595,  0.5119],
        [-1.4520,  3.6885,  0.8588],
        [ 0.2594,  0.7861,  1.2009],
        [ 0.8792,  0.4400,  3.5033],
        [ 0.8518, -0.6514,  0.8435],
        [-4.5127,  1.6560,  1.8358],
        [ 1.0980, -0.0322,  4.6615],
        [ 0.2322, -3.3426,  5.0285],
        [-0.7733, -2.5316,  1.9540],
        [ 0.6214,  1.1227,  3.3353]])

# torch.linspace(start,end,steps)

注意:steps是产生的数量,不是步长!!!

tensor1 = torch.linspace(1,10,steps=3)
tensor1
1
2
tensor([ 1.0000,  5.5000, 10.0000])

# torch.arange(start=0, end, step=1)

tensor1 = torch.arange(start=0, end=10, step=3)
tensor1
1
2
tensor([0, 3, 6, 9])

# torch.manual_seed()

固定随机种子,仅用于最接近的随机数产生语句。

torch.manual_seed(3)
num1 = torch.rand(2)
print(num1)

torch.manual_seed(3)
num2 = torch.rand(2)
print(num2)
1
2
3
4
5
6
7
tensor([0.0043, 0.1056])
tensor([0.0043, 0.1056])

# ones()

全1数组

# zeros()

全0数组

# eye()

对角线全1

tensor1 = torch.eye(4,3)

tensor1
1
2
3
tensor([[1., 0., 0.],
        [0., 1., 0.],
        [0., 0., 1.],
        [0., 0., 0.]])

# 1.1.3 数据类型的转换

  • 创建时指定
tensor1 = torch.ones((3,1,6), dtype=torch.int64)
tensor1
1
2
tensor([[[1, 1, 1, 1, 1, 1]],

        [[1, 1, 1, 1, 1, 1]],

        [[1, 1, 1, 1, 1, 1]]])
  • 创建完再指定
tensor1 = torch.ones((3,1,6))
tensor1.type(torch.float64)
tensor1
1
2
3
tensor([[[1., 1., 1., 1., 1., 1.]],

        [[1., 1., 1., 1., 1., 1.]],

        [[1., 1., 1., 1., 1., 1.]]])

# 1.2 基本操作

# 1.2.1 改变形状 view

x = torch.rand(3,2)
print(x)

y = x.view(2,3)
print(y)
1
2
3
4
5
tensor([[0.6483, 0.2148],
        [0.9493, 0.0121],
        [0.1809, 0.1877]])
tensor([[0.6483, 0.2148, 0.9493],
        [0.0121, 0.1809, 0.1877]])

# 1.2.2 增加删除维度

  • 增加维度 unsqueeze

它是按索引位添加维度,比如0即是在第0位添加一个维度。

a = torch.rand(3,4)
b = torch.unsqueeze(a,0)
c = b.unsqueeze(0)
print(a.shape)
print(b.shape)
print(c.shape)
1
2
3
4
5
6
torch.Size([3, 4])
torch.Size([1, 3, 4])
torch.Size([1, 1, 3, 4])
  • 删除维度 squeeze(input, dim)

    只 在 tensor.shape[dim] == 1 时,才会删除那个维度。

a = torch.rand(1,2,3,4)
b = torch.squeeze(a,0)
c = b.squeeze()
print(a.shape)
print(b.shape)
print(c.shape)
1
2
3
4
5
6
torch.Size([1, 2, 3, 4])
torch.Size([2, 3, 4])
torch.Size([2, 3, 4])
  • 拉平成一维
view(-1)
1

# 1.2.3 交换维度 permute

或者transpose()

tensor1 = torch.rand(2,3,2)
print(tensor1)

tensor2 = tensor1.permute(1,0,2)
print(tensor2)
1
2
3
4
5
tensor([[[0.8536, 0.0303],
         [0.7106, 0.5128],
         [0.9775, 0.8324]],

        [[0.2388, 0.3827],
         [0.8727, 0.2676],
         [0.6810, 0.0939]]])
tensor([[[0.8536, 0.0303],
         [0.2388, 0.3827]],

        [[0.7106, 0.5128],
         [0.8727, 0.2676]],

        [[0.9775, 0.8324],
         [0.6810, 0.0939]]])

# 1.2.4 拼接、分割

  • 拼接

    不会增加维度

a = torch.rand(1,2,1)
b = torch.rand(1,2,1)
c = torch.rand(1,2,1)
print(a)
res1 = torch.cat([a,b,c],dim = 0)
res2 = torch.cat([a,b,c],dim = 1)
print(f'res1:{res1}\n, res2:{res2}')
1
2
3
4
5
6
7
tensor([[[0.7706],
         [0.6560]]])
res1:tensor([[[0.7706],
         [0.6560]],

        [[0.0419],
         [0.5257]],

        [[0.7046],
         [0.1369]]])
, res2:tensor([[[0.7706],
         [0.6560],
         [0.0419],
         [0.5257],
         [0.7046],
         [0.1369]]])
  • 分割 split

分割是分成num块,按dim=0

tensor1 = torch.rand(3,4)
res1 = torch.split(tensor1, 2)

print(tensor1)

print(res1)
1
2
3
4
5
6
tensor([[0.8660, 0.0405, 0.9147, 0.8523],
        [0.9055, 0.3671, 0.6700, 0.6978],
        [0.3117, 0.5756, 0.7466, 0.8590]])
(tensor([[0.8660, 0.0405, 0.9147, 0.8523],
        [0.9055, 0.3671, 0.6700, 0.6978]]), tensor([[0.3117, 0.5756, 0.7466, 0.8590]]))

# 1.2.5 堆叠和分解

  • 堆叠 stack()

    会增加维度

a = torch.rand(1,2)
b = torch.rand(1,2)
c = torch.rand(1,2)

res1 = torch.stack([a,b,c], dim=0)
1
2
3
4
5
tensor([[[0.9387, 0.2398]],

        [[0.4198, 0.6112]],

        [[0.5861, 0.3208]]])
  • 分解 chunk()
a = torch.rand(3,4)
res1 = torch.chunk(a, 2, dim=0)
res1
1
2
3
(tensor([[0.6000, 0.4391, 0.8994, 0.0217],
         [0.6418, 0.5846, 0.6675, 0.0933]]),
 tensor([[0.3516, 0.1336, 0.7224, 0.6623]]))

# 1.2.6 索引和切片

a = torch.rand(2,3,4)

x = a[:,:2,:]
print(x.shape)
1
2
3
4
torch.Size([2, 2, 4])

# 1.2.7 基本数学运算

# 求和 sum

  • 所有元素加起来
a = torch.rand(2,3)
res = torch.sum(a)
res
1
2
3
tensor(3.6691)
  • 指定维度 torch.sum(input,dim,keepdim=True)

    keepdim:保证维度不变

a = torch.rand(2,3)
print(a)
res = torch.sum(a,dim=1,keepdim=True)
print(res)
1
2
3
4
tensor([[0.6204, 0.4698, 0.9045],
        [0.9678, 0.6092, 0.5209]])
tensor([[1.9946],
        [2.0979]])
  • 按索引求和

    torch.Tensor.index_add(dim,index,tensor)

arr1 = torch.Tensor([[1,2],[3,4]])
arr2 = torch.Tensor([[0,1],[2,3]])

index = torch.LongTensor([0,1])
res = arr1.index_add(0,index,arr2)

print(res)
1
2
3
4
5
6
7
tensor([[1., 3.],
        [5., 7.]])

# 乘积 prod

torch.prod(input,dim,keepdim=True)()

# 平均数 mean

方法同求和

# 方差 var

方法同求和

# 最值 max、min

方法同求和

# 1.2.8 向量运算

# 点乘 dot

a = torch.Tensor([1,2,3])
b = torch.Tensor([1,1,1])

res = torch.dot(a,b)
print(res) # 等价于 1*1+2*1+3*1
1
2
3
4
5
tensor(6.)

# 叉乘 multiply

逐元素乘法

a = torch.Tensor([1,2,3])
b = torch.Tensor([1,1,1])

res = torch.multiply(a,b)
print(res) # 等价于 1*1 2*1 3*1
1
2
3
4
5
tensor([1., 2., 3.])

# 1.2.9 矩阵运算

# 内积 inner

对两个张量的“最后一维”做内积

a = torch.ones(2,2)
b = torch.Tensor([[2,3],[4,5]])
print(a)
print(b)
res = torch.inner(a,b)
print(res)
# res[i, j] 就是对 a[i, :] 和 b[j, :] 做内积
1
2
3
4
5
6
7
tensor([[1., 1.],
        [1., 1.]])
tensor([[2., 3.],
        [4., 5.]])
tensor([[5., 9.],
        [5., 9.]])

# 外积 matmul

线代的矩阵乘积

a = torch.ones(2,2)
b = torch.Tensor([[2,3],[4,5]])
print(a)
print(b)
res = torch.matmul(a,b)
print(res)
# res[i, j] 就是对 a[i, :] 和 b[j, :] 做内积
1
2
3
4
5
6
7
tensor([[1., 1.],
        [1., 1.]])
tensor([[2., 3.],
        [4., 5.]])
tensor([[6., 8.],
        [6., 8.]])

# 1.3 张量与Numpy

# 1.3.1 张量转Numpy

numpy() 二者会共享内存

tensor1 = torch.ones(3,3)
arr = tensor1.numpy()

print(arr)
1
2
3
4
[[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]

# 1.3.2 Numpy转张量

  • torch.Tensor(arr)

    会 复制 一份数据,创建新的张量,和原 NumPy 数组无关。

  • torch.from_numpy(arr)

    不会复制,新建的张量和原 NumPy 数组 共享内存,修改其中一个,另一个也跟着变。

# 1.4 Cuda张量与CPU张量

  • 转为CPU
tensor1 = torch.rand(2,3)
tensor = tensor1.cpu() # 默认是cpu,如果是Cuda可以转

print(tensor.device)
1
2
3
4
cpu
  • 转为Cuda

方法1:

tensor1 = torch.rand(2,3)
tensor = tensor1.cuda()

print(tensor.device)
1
2
3
4
cuda:0

方法2:

x = torch.rand(3,3)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
if torch.cuda.is_available():
    x = x.to(device)
    print(device)
1
2
3
4
5
cuda