Pytorch快速入门笔记
本笔记从小土堆Pytorch教程中记录一些实用的Pytorch相关操作.
1. 加载数据
1.1 PIL
PIL类可以用于加载图像、保存图像等操作
1 |
|
1.2 DataSet
DataSet是一个抽象类,需要实现其中的__getitem__
方法,以及最好是实现__len__
方法,不然不能用迭代器,用for循环的方式取数据,
以下是一个自定义数据集的设置方式,可以看到需要重写__getitem__
方法取数据
1 |
|
1.3 DataLoader
如果把DataSet看做一副牌,那么DataLoader就是用于定义如何发牌,或者对牌进行一些操作(洗牌、转换格式等),如果已经有一个数据集,那么可以通过这种方式定义data_loader
1 |
|
定义好的数据集,可以通过DataLoader加载,并通过for循环取数据,例如:
1 |
|
1.4 torchvision数据集的下载和使用
如果是一些成熟的数据集,比如CIFAR10,可以用封装好的方式获取数据集,这些数据集也是重写了DataSet类,可以传入transform
1 |
|
2. Tensorboard 的使用
TensorBoard是一个可视化工具,它可以用来展示网络图、张量的指标变化、张量的分布情况等。特别是在训练网络的时候,我们可以设置不同的参数(比如:权重W、偏置B、卷积层数、全连接层数等),使用TensorBoader可以很直观的帮我们进行参数的选择。它通过运行一个本地服务器,来监听6006端口。在浏览器发出请求时,分析训练时记录的数据,绘制训练过程中的图像。
首先定义一个SummaryWriter(),然后就可以用writer里面的方法往tensorboard里面写数据,不仅可以添加过程量还可以添加单张图像。默认的路径保存到本地runs目录下,可以用SummaryWriter()
1 |
|
查看数据:cd到保存文件的文件夹下,输入tensorboard --logdir runs
runs对应文件保存的目录,然后就可以通过访问http://localhost:6006/#timeseries
查看记录的结果
3. Transforms 的使用
Transforms用来对一张图片进行一系列的转换,可以用Compose定义需要转换的内容
1 |
|
定义好转换之后,可以对单张图片进行转换,把图像传入就可以,例如:
1 |
|
4. 常用函数
4.1卷积函数
卷积函数的定义网上有很多了就不再赘述了,定义一个卷积核,然后和现在的矩阵进行卷积操作,可得到一个结果。
借用知乎2D卷积,nn.Conv2d和F.conv2d一段话:卷积操作:卷积核和扫过的小区域对应位置相乘再求和的操作,卷积完成后一般要加个偏置bias。一种Kernel如果分成多个通道上的子Kernel做卷积运算,最后运算结果还要加在一起后,再加偏置。
使用卷积运算的时候需要注意输入输出的尺寸,需要对齐,比如Conv2D 如果是函数就要求B ,C 两个维度要对齐。
需要注意的点是输入输出维度会根据stride、padding的设置改变,比如64×64的图像进去,不设置padding出来的图像可能就变成62×62了,如果还要保持图像尺寸一致(特别是复现论文的场景),需要反算一下stride和padding的值,这里公式在Pytorch Conv2d文档,需要的时候直接查阅就好。
关于可视化展示卷积函数中的stride、padding、dilation参数的含义,可参考文档:Convolution arithmetic
1 |
|
4.2 池化函数
池化函数是深度学习中常用的技术,主要用于降低数据的维度和减少计算量。常见的池化函数包括:
- 最大池化(Max Pooling):在池化窗口内选取最大值作为输出,能够提取图像中的主要特征。
- 平均池化(Average Pooling):在池化窗口内取平均值作为输出,可以平滑输入数据,减少噪声的影响。
- 自适应池化(Adaptive Pooling):根据输入的大小自动调整池化窗口的大小,以适应不同的输入尺寸。
池化操作可以分为一维池化、二维池化和三维池化,具体取决于被池化的张量维数。池化不仅可以减小数据大小,还可以增加数据大小,具体取决于应用场景。
1 |
|
5. 神经网络的搭建
5.1 卷积层、池化层、非线性激活层
通过引入torch.nn
引入常见神经网络的层,包括卷积层、池化层等.以及非线性激活层,RELU SOFTMAX之类的,具体就不再展开了。
1 |
|
5.2线性层及其他层
- 线性层:线性层又叫全连接层,其中每个神经元和上一层所有的神经元相连,使用
nn.Linear(in_features,out_features,bias)
定义,运算公式是 $$y=xA^T+b$$ ,注意默认是加上bias的,即bias=True
代码例子:
1 |
|
- 展平层:将多维度的张量展平。默认参数:
start_dim: int = 1, end_dim: int = -1
从开始的维度展开到结束的维度
代码例子:
1 |
|
一般说来,Flatten层常用于把多维的输入一维化,常用在从卷积层到全连接层的过渡。Flatten默认不影响batch的大小(start_dim =1 )。
5.3 Sequential的使用
nn.Sequential() 可以作为容器,里面放入模型的各种层,在forward的时候将会贯序列执行各层,通常有2种定义方式
- 定义方式1
1 |
|
- 定义方式2:给每个层添加一个名称
1 |
|
我们可以将前面所学的层组合起来,形成深层神经网络的架构,例如我们可以编写一个自己的网络如下:
1 |
|
通过使用Sequential()的方式可以便捷的完成网络的定义,快速实现网络。
5.4 小网络搭建实战
以vgg16这个网络(图待补充)为例,搭建模型如下(暂未添加Relu层),其实和我们之前写的模型很像
1 |
|
6 损失函数与反向传播
6.1 损失函数
损失函数(Loss Function)是一个衡量预测结果与真实结果之间差异的函数 ,也称为误差函数。它通过计算模型的预测值与真实值之间的不一致程度,来评估模型的性能.
根据任务不同,选择的损失函数也不同,对于回归任务,常见的损失函数有MSELoss
,对于分类任务常见的损失函数有交叉熵损失CrossEntropyLoss
交叉熵的损失函数可以描述为 $$loss(x,class) = -log(exp(x[class]/sum_j(exp(x[j])))=-x[class]+ln(sum_j(exp(x[j])]))$$
举例说明:
1 |
|
其他的案例也差不多
1 |
|
6.2 反向传播
首先说一下什么是反向传播算法。
反向传播算法(Backpropagation,简称BP算法)是“误差反向传播”的简称,是适合于多层神经元网络的一种学习算法,它建立在梯度下降法的基础上。梯度下降法是训练神经网络的常用方法,许多的训练方法都是基于梯度下降法改良出来的,因此了解梯度下降法很重要。梯度下降法通过计算损失函数的梯度,并将这个梯度反馈给最优化函数来更新权重以最小化损失函数。
在PyTorch中,loss.backward()函数用于计算模型参数相对于损失函数的梯度。
前向传播
首先,模型通过前向传播计算输出值。在这个过程中,PyTorch会记录计算图(Computation Graph),这个计算图记录了从输入到输出的每一步运算及其依赖关系。每个张量(Tensor)都有一个.grad_fn属性,指向一个函数,这个函数描述了如何计算这个张量关于其输入的梯度。
反向传播
当调用loss.backward()时,PyTorch开始反向遍历计算图。这个过程从损失函数开始,沿着图反向传播误差,计算每一个参与运算的张量关于损失的梯度。这是通过链式法则(Chain Rule)完成的,即将损失对某个中间变量的导数分解为其后续操作导数的乘积。
梯度计算
在反向传播过程中,每个运算都会计算其输出关于输入的梯度,并将这个梯度累积到输入张量的.grad属性中(如果是标量损失,它没有.grad属性)。这意味着如果一个张量被多个路径使用,它的.grad属性会累积从所有路径来的梯度.
在使用loss.backward()时,有几个重要的注意事项:
梯度归零:在每次反向传播之前,通常需要调用optimizer.zero_grad()来将梯度归零,以避免梯度累加
6.3 优化器
优化器决定了模型以何种方式的梯度下降算法更新模型。常见的优化器有 SGD, adam等。
在PyTorch中,optimizer.step()是优化器对象的一个方法,用于执行模型参数的更新。在深度学习训练过程中,参数更新是通过反向传播算法计算损失函数的梯度后,使用优化器根据这些梯度进行的。optimizer.step()方法正是用于根据梯度和学习率等超参数来更新模型参数,从而使损失函数值最小化的步骤
7 使用常用模型
7.1 使用库的方式调用常用模型
一些常用的模型,比较经典的模型都是包装在库里面了,可以通过torchvision.models.xxx
调用模型.
例如:
1 |
|
7.2 对常用模型进行增加或修改
- 增加某层
1 |
|
- 修改某层
1 |
|
- 删除某层
如果想删除某一层,直接将其删除即可,命令为
1 |
|
- 冻结部分层
我们现在只想训练最后的fc1层,然后就有了下面的
1 |
|
8 完整的训练流程
包括数据集准备,dataLoader准备、网络构建、损失函数定义、循环、计算误差、tensorboard可视化等
1 |
|
运行代码的效果:
1 |
|
8.1 使用GPU训练
除了8.1的方式在所有张量用.cuda()
送入显存的方式使用GPU训练外,还可以用tensor.to(device)
的方式送入显存
1 |
|