之前用了tensorflow的keras api,比较简单快捷.单光那样肯定是不行的
PyTorch 是 Facebook 主导开发的,基于 Python 的科学计算包
安装
直接在官网按教程即可.一般都需要gpu版的,所以需要cuda(当然也需要英伟达的gpu了).
知道cuda版本后对应安装即可.conda和pip无所谓.
cuDNN是一个SDK,是一个专门用于神经网络的加速包,注意,它跟我们的CUDA没有一一对应的关系,即每一个版本的CUDA可能有好几个版本的cuDNN与之对应,但一般有一个最新版本的cuDNN版本与CUDA对应更好。
检验
1 | print(torch.cuda.is_available()) |
1 | True |
我cuda版本是11.6,pytorch版本1.110.安装的gpu版本对应cuda11.3
张量
tensors与numpy中的数组类似,差别是其可以用gpu计算1
2
3import torch
torch.empty(5, 3)
使用 torch.empty
可以返回填充了未初始化数据的张量。张量的形状由可变参数大小定义。
创建随机初始化矩阵1
2
3torch.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)
获取张量size1
x.size()
针对张量的操作
加法运算1
2y = torch.rand(5, 3)
torch.add(x, y)
提供输出 Tensor 作为参数1
2
3result = torch.empty(5, 3)
torch.add(x, y, out=result)
y.add_(x) # 将 x 加到 y
任何以下划线结尾的操作都会用结果替换原变量1
x[:, 1]
1
2
3x = torch.randn(4, 4)
y = x.view(16)
z = x.view(-1, 8) # size -1 从其他维度推断
如果张量只有一个元素,使用 .item()
来得到 Python 数据类型的数值1
2x = torch.randn(1)
print(x.item())
与numpy转换
1 | b = a.numpy() |
NumPy 数组转换成 PyTorch 张量时,可以使用 from_numpy
完成1
2
3
4
5import 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_grad
为True
,那么将会追踪所有对于该张量的操作。当完成计算后通过调用.backward()
会自动计算所有的梯度,这个张量的所有梯度将会自动积累到.grad
属性。这也就完成了自动求导的过程
要阻止张量跟踪历史记录,可以调用 .detach()
方法将其与计算历史记录分离。为了防止跟踪历史记录(和使用内存),可以将代码块包装在 with torch.no_grad():
语句中。这一点在评估模型时特别有用,因为模型可能具有 requires_grad=True
的可训练参数,但是我们并不需要计算梯度.
自动求导中还有另外一个重要的类 Function
。Tensor
和 Function
互相连接并生成一个非循环图,其存储了完整的计算历史。
如果需要计算导数,你可以在 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
5f1 = torch.randn(1,requires_grad=True)
f1 = 2*f1
f2 = y+z
# 查看变量是否存在求梯度函数
print(f1.grad_fn)
结果为MulBackward0 object1
f1.backward(retain_graph=True)
计算梯度.1
2
3
4
5
6
7a = 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
来构建神经网络
它是一个简单的前馈神经网络,它接受一个输入,然后一层接着一层地传递,最后输出计算的结果。
神经网络的典型训练过程如下:
定义包含可学习参数(权重)的神经网络模型。
在数据集上迭代。
通过神经网络处理输入。
计算损失(输出结果和正确值的差值大小)。
将梯度反向传播回网络节点。
更新网络的参数,一般可使用梯度下降等最优化方法。
停止张量梯队计算
如果我们不需要某些张量的梯度计算,我们就可以使用下面三种方法告诉计算机停止梯度的计算:
x.requires_grad_(False)
。x.detach()
。with torch.no_grad():
为了避免多次求导后梯度累加情况,一般我们在计算完梯度后,都会清空梯度,即清空 x.grad
。在清空梯度后,我们再进行其他张量的梯度求解
使用 x.grad.zero_()
清空梯度