深度学习——pytorch学习
Pytorch学习
[toc]
pytorch基本操作
pytorch使用前首先了解一个一个概念:张量。个人觉得没必要去了解他到底是一种什么东西,可以将其与我们numpy中数组一起进行了解
张量可以看作是⼀个多维数组。标量可以看作是0维张量,向量可以看作1维张量,矩阵可以看作是⼆维张量
那么我们后续也都是围绕张量进行展开了解
数据操作
创建张量
注意使用pytorch就不得不了解一大特点:利用GPU计算。
1 | >>a = torch.ones(5,3,device='cuda',dtype=torch.float64)#设置类型,gpu |
操作
- 加法运算
1 | print(x+y) |
索引
索引出来的结果与原数据共享内存,也即修改⼀个,另⼀个会跟着修改。1
2
3
4
5
6b = x[0:1]
print(b)
->tensor([[0.6847, 0.9743, 0.9259]])
b +=2
print(x[0,:])
->tensor([2.6847, 2.9743, 2.9259])改变形状
1
2
3
4
5
6
7
8
9
10
11c = 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
13x_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]])线性代数
广播机制
线性代数告诉我们,要是两个矩阵形状不同是不可以直接相加的,但是pytorch的广播机制可以实现此类计算。1
2
3
4
5
6
7
8
9
10
11
12x = 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 | x = torch.ones(2,2,requires_grad=True) |
计算结果怎么来的呢?首先我们知道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 | x = torch.tensor([2., 1.], requires_grad=True) |
算法解释如下:
我们在对z进行求梯度的时候,指定了参数[1,0]也就是相对于进行了加权操作
参考
https://www.w3cschool.cn/article/9034837.html