深度学习——pytorch学习

Pytorch学习

[toc]

pytorch基本操作

pytorch使用前首先了解一个一个概念:张量。个人觉得没必要去了解他到底是一种什么东西,可以将其与我们numpy中数组一起进行了解

张量可以看作是⼀个多维数组。标量可以看作是0维张量,向量可以看作1维张量,矩阵可以看作是⼆维张量

那么我们后续也都是围绕张量进行展开了解

数据操作

创建张量

1680163291680

注意使用pytorch就不得不了解一大特点:利用GPU计算。

1
2
3
4
5
6
7
8
9
>>a = torch.ones(5,3,device='cuda',dtype=torch.float64)#设置类型,gpu
>>a
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], device='cuda:0', dtype=torch.float64)
>>print(a.size(),a.shape)
torch.Size([5, 3]) torch.Size([5, 3])

操作

  • 加法运算
1
2
3
4
5
6
7
8
9
print(x+y)
print(torch.add(x,y))
print(y.add(x))
->tensor([[0.9841, 1.1514, 1.0982],
[0.9974, 0.4662, 1.5250],
[0.5120, 0.3424, 1.6973],
[1.1808, 1.1172, 1.6786],
[1.9113, 1.3679, 1.3846]])
三个结果都一样
  • 索引
    索引出来的结果与原数据共享内存,也即修改⼀个,另⼀个会跟着修改。

    1
    2
    3
    4
    5
    6
    b = x[0:1]
    print(b)
    ->tensor([[0.6847, 0.9743, 0.9259]])
    b +=2
    print(x[0,:])
    ->tensor([2.6847, 2.9743, 2.9259])

    1680164219080

  • 改变形状

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    c = x.view(15)
    c
    ->tensor([2.6847, 2.9743, 2.9259, 0.7470, 0.2349, 0.6642, 0.3026, 0.1884, 0.9414,
    0.4747, 0.8469, 0.7788, 0.9762, 0.4373, 0.6214])
    c +=1
    x
    ->tensor([[3.6847, 3.9743, 3.9259],
    [1.7470, 1.2349, 1.6642],
    [1.3026, 1.1884, 1.9414],
    [1.4747, 1.8469, 1.7788],
    [1.9762, 1.4373, 1.6214]])

    利用view()函数返回的新tensor与源tensor共享内存(其实是同⼀个tensor),也即更改其中的⼀个,另
    外⼀个也会跟着改变。所以如果我们想返回⼀个真正新的副本(即不共享内存)该怎么办呢?Pytorch还提供了⼀个reshape()可以改变形状,但是此函数并不能保证返回的是其拷⻉,所以不推荐使⽤。推荐先
    ⽤ clone 创造⼀个副本。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    x_clone = x.clone()
    x_clone +=1
    print(x_clone, '\n', x)
    ->tensor([[4.6847, 4.9743, 4.9259],
    [2.7470, 2.2349, 2.6642],
    [2.3026, 2.1884, 2.9414],
    [2.4747, 2.8469, 2.7788],
    [2.9762, 2.4373, 2.6214]])
    tensor([[3.6847, 3.9743, 3.9259],
    [1.7470, 1.2349, 1.6642],
    [1.3026, 1.1884, 1.9414],
    [1.4747, 1.8469, 1.7788],
    [1.9762, 1.4373, 1.6214]])
  • 线性代数

    1680164657109

    官方文档:torch.Tensor — PyTorch 2.0 documentation

  • 广播机制
    线性代数告诉我们,要是两个矩阵形状不同是不可以直接相加的,但是pytorch的广播机制可以实现此类计算。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    x = torch.arange(1, 3).view(1, 2)
    print(x)
    y = torch.arange(1, 4).view(3, 1)
    print(y)
    print(x + y)
    ->tensor([[1, 2]])
    tensor([[1],
    [2],
    [3]])
    tensor([[2, 3],
    [3, 4],
    [4, 5]])

    计算过程中,由于x,y的形状是不相同的,通过广播机制,会将x进行拓展,也就是将x变成3x2,y变成3x2而后再进行计算。

tensor和numpy相互转换

我们很容易⽤ numpy() 和 from_numpy() 将 Tensor 和NumPy中的数组相互转换。但是需要注意的⼀
点是: 这两个函数所产⽣的的 Tensor 和NumPy中的数组共享相同的内存(所以他们之间的转换很
快),改变其中⼀个时另⼀个也会改变!!!

还有⼀个常⽤的将NumPy中的array转换成 Tensor 的⽅法就是 torch.tensor() , 需要注意的
是,此⽅法总是会进⾏数据拷⻉(就会消耗更多的时间和空间),所以返回的 Tensor 和原来的数
据不再共享内

  • numpy()
    将tensor转换为numpy形式
  • torch.from_numpy()
    将numpy转换为tensor

自动求梯度

A Gentle Introduction to torch.autograd — PyTorch Tutorials 2.0.0+cu117 documentation

在生成tensor时候我们添加属性 (requires_grad=True ),它将开始追踪(track)在其上的所有操作(这样就可以利⽤链式法则进⾏梯度传播了)。完成计算后,可以调⽤.backward() 来完成所有梯度计算。此Tensor的梯度将累积到.grad 属性中。

如果不想要被继续追踪,可以调⽤ .detach() 将其从追踪记录中分离出来,这样就可以防⽌将来的计算被追踪,这样梯度就传不过去了。此外,还可以⽤ with torch.no_grad() 将不想被追踪的操作代码块包裹起来,这种⽅法在评估模型的时候很常⽤,因为在评估模型时,我们并不需要计算可训练参数(requires_grad=True)的梯度。

通俗的来讲就是我们添加 requires_grad 可以记录在张量上所进行的所有的操作

1
2
3
4
5
6
7
8
9
10
x = torch.ones(2,2,requires_grad=True)
y = x+ 2
z = y*y*3
p = z.mean()
print(p)
->tensor(27., grad_fn=<MeanBackward0>)
p.backward()
print(x.grad)
->tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])

计算结果怎么来的呢?首先我们知道p所进行的计算如下

$$
p=\frac{1}{4}\sum3(x_i+2)^2
$$

$$
\dfrac{\partial p}{\partial x}|_{x_i=1}=\frac{9}{2}=4.5
$$

不过在此处需要一个注意事项,我们的p必须是一个标量,也就是说p必须是一个数字,不然结果会报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
x = torch.tensor([2., 1.], requires_grad=True)
y = torch.tensor([[1., 2.], [3., 4.]], requires_grad=True)

z = torch.mm(x.view(1, 2), y)
print(f"z:{z}")
z.backward(torch.Tensor([[1., 0]]), retain_graph=True)
print(f"x.grad: {x.grad}")
print(f"y.grad: {y.grad}")

-->z:tensor([[5., 8.]], grad_fn=<MmBackward>)
x.grad: tensor([[1., 3.]])
y.grad: tensor([[2., 0.],
[1., 0.]])

算法解释如下:
1680176521877
我们在对z进行求梯度的时候,指定了参数[1,0]也就是相对于进行了加权操作

参考

https://www.w3cschool.cn/article/9034837.html

https://blog.csdn.net/qq_39208832/article/details/117415229

https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html#sphx-glr-beginner-blitz-autograd-tutorial-py