pytorch学习

之前用了tensorflow的keras api,比较简单快捷.单光那样肯定是不行的

PyTorch 是 Facebook 主导开发的,基于 Python 的科学计算包

安装

直接在官网按教程即可.一般都需要gpu版的,所以需要cuda(当然也需要英伟达的gpu了).

知道cuda版本后对应安装即可.conda和pip无所谓.

cuDNN是一个SDK,是一个专门用于神经网络的加速包,注意,它跟我们的CUDA没有一一对应的关系,即每一个版本的CUDA可能有好几个版本的cuDNN与之对应,但一般有一个最新版本的cuDNN版本与CUDA对应更好。

检验

1
2
print(torch.cuda.is_available())
print(torch.__version__)
1
2
True
1.11.0+cu113

我cuda版本是11.6,pytorch版本1.110.安装的gpu版本对应cuda11.3

张量

tensors与numpy中的数组类似,差别是其可以用gpu计算

1
2
3
import torch

torch.empty(5, 3)

使用 torch.empty 可以返回填充了未初始化数据的张量。张量的形状由可变参数大小定义。

创建随机初始化矩阵

1
2
3
torch.rand(5,3)  #均匀分布
torch.zeros(5, 3, dtype=torch.long) #0填充矩阵 类型long
x = torch.tensor([5.5, 3]) #创建一个tensor

根据现有张量创建新张量。这些方法将重用输入张量的属性,除非设置新的值进行覆盖

1
x = x.new_ones(5, 3, dtype=torch.double)

覆盖 dtype,对象的 size 是相同的,只是值和类型发生了变化

1
x = torch.randn_like(x, dtype=torch.float)

获取张量size

1
x.size()

针对张量的操作

加法运算

1
2
y = torch.rand(5, 3)
torch.add(x, y)

提供输出 Tensor 作为参数

1
2
3
result = torch.empty(5, 3)
torch.add(x, y, out=result)
y.add_(x) # 将 x 加到 y

任何以下划线结尾的操作都会用结果替换原变量

1
x[:, 1]
1
2
3
x = torch.randn(4, 4)
y = x.view(16)
z = x.view(-1, 8) # size -1 从其他维度推断

如果张量只有一个元素,使用 .item() 来得到 Python 数据类型的数值

1
2
x = torch.randn(1)
print(x.item())

与numpy转换

1
b = a.numpy()

NumPy 数组转换成 PyTorch 张量时,可以使用 from_numpy 完成

1
2
3
4
5
import numpy as np

a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out=a)

所有的 Tensor 类型默认都是基于 CPU

gpu

CUDA 张量是能够在 GPU 设备中运算的张量。使用 .to 方法可以将 Tensor 移动到 GPU 设备中

1
2
3
4
5
6
7
8
# is_available 函数判断是否有 GPU 可以使用
if torch.cuda.is_available():
device = torch.device("cuda") # torch.device 将张量移动到指定的设备中
y = torch.ones_like(x, device=device) # 直接从 GPU 创建张量
x = x.to(device) # 或者直接使用 .to("cuda") 将张量移动到 cuda 中
z = x + y
print(z)
print(z.to("cpu", torch.double))

autograd

autograd为张量上的所有操作提供了自动求导。它是一个在运行时定义的框架,这意味着反向传播是根据你的代码来确定如何运行。torch.Tensor 是这个包的核心类。如果设置 .requires_gradTrue,那么将会追踪所有对于该张量的操作。当完成计算后通过调用 .backward() 会自动计算所有的梯度,这个张量的所有梯度将会自动积累到 .grad 属性。这也就完成了自动求导的过程

要阻止张量跟踪历史记录,可以调用 .detach() 方法将其与计算历史记录分离。为了防止跟踪历史记录(和使用内存),可以将代码块包装在 with torch.no_grad(): 语句中。这一点在评估模型时特别有用,因为模型可能具有 requires_grad=True 的可训练参数,但是我们并不需要计算梯度.

自动求导中还有另外一个重要的类 FunctionTensorFunction 互相连接并生成一个非循环图,其存储了完整的计算历史。

如果需要计算导数,你可以在 Tensor 上调用 .backward()。 如果 Tensor 是一个标量(即它包含一个元素数据)则不需要为 backward() 指定任何参数。但是,如果它有多个元素,你需要指定一个 gradient 参数来匹配张量的形状。

.requiresgrad( … )可以改变现有张量的requires_grad属性。 如果没有指定的话,默认输入的 flag 是False.

注意:将某个变量设置为requires_grad=True后,意味着后面涉及到这个变量计算产生的变量其grad_fn存在。x.grad_fn只有产生这个变量x的变量中有requires_grad且x不是末端情况下存在

1
2
3
4
5
f1 = torch.randn(1,requires_grad=True)
f1 = 2*f1
f2 = y+z
# 查看变量是否存在求梯度函数
print(f1.grad_fn)

结果为MulBackward0 object

1
f1.backward(retain_graph=True)

计算梯度.

1
2
3
4
5
6
7
a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)

如果使用函数 k.backward(p) 则得到的的变量 x.grad 的值为:

完成了梯度的自动追踪后,下面通过反向传播打印对应节点的梯度。因为 out 是一个纯量 Scalar,out.backward() 等于 out.backward(torch.tensor(1))

总结一下,x.grad_fn就是看有没有梯度函数.

x.backward()计算梯度,x.grad显示值.

可以使用 torch.nn来构建神经网络

它是一个简单的前馈神经网络,它接受一个输入,然后一层接着一层地传递,最后输出计算的结果。

神经网络的典型训练过程如下:

  1. 定义包含可学习参数(权重)的神经网络模型。

  2. 在数据集上迭代。

  3. 通过神经网络处理输入。

  4. 计算损失(输出结果和正确值的差值大小)。

  5. 将梯度反向传播回网络节点。

  6. 更新网络的参数,一般可使用梯度下降等最优化方法。

    停止张量梯队计算

如果我们不需要某些张量的梯度计算,我们就可以使用下面三种方法告诉计算机停止梯度的计算:

  • x.requires_grad_(False)
  • x.detach()
  • with torch.no_grad():

为了避免多次求导后梯度累加情况,一般我们在计算完梯度后,都会清空梯度,即清空 x.grad 。在清空梯度后,我们再进行其他张量的梯度求解

使用 x.grad.zero_() 清空梯度

-------------本文结束感谢您的阅读-------------
感谢阅读.

欢迎关注我的其它发布渠道