Pytorch基础知识 - Notebook
Tensor张量
grad属性记录张量的梯度值
grad_fn记录使用的运算方法
data返回Tensor的实际值:out.data的效果等价于out.detach(),没有requires_grad
线性回归
逻辑回归
sigmoid(w1*x1+w2*x2+w3*x3+b)无法拟合“异或运算”,单层神经元要求数据是线性可分的,异或问题无法找到一条直线分割两个类。
单层神经元无法解决线性不可分问题,这个问题使神经网络的发展停滞了很多年。
多层感知器(MLP)
为了继续使经网络解决线性不可分问题,模仿生物神经元的设计在网络的输入和输出直接插入更多神经元。
添加激活函数,使得网络可以拟合非线性问题,当神经元接受的信号超过某一个值时,该神经元就会被激活,从而将信息继续传递下去。
修正线性单元relu:f(x) = max(x, 0)
对于逻辑回归,可以使用sigmoid解决二分类问题
tanh双曲正切激活函数,取值范围(-1, 1),常用于生成网络(输入:-1~1)
Leak relu带泄露的修正线性单元,相对于relu,生成器的激活函数,如果是自定义激活函数要保证线性可导
多分类问题与通用训练函数
softmax分类,当只有两个类别时,与sigmoid对数几率回归完全相同
torchvision库:PyTorch通过torchvision库提供了一些常用的数据集,模型、转换函数等等
torchvidion库提供的内置数据集可用于测试、学习和创建基准模型
为了统一数据加载和处理代码,Pytorch提供了两个类,用以处理数据和加载:
1、torch.utils.data.Dataset类
2、torch.utils.data.DataLoader类
通过这两个类可以使我们的数据集加载和预处理代码与模型训练代码脱钩,从而获得更好的代码模块化和代码可读性
torchvision加载的内置图片数据集均继承自torch.utils.data.Dataset类,因此我们可以直接使用加载的内置数据集创建DataLoader
PyTorch内置图片数据集均在torchvision.datasets模块下如CIFAR、CityScapes、COCO、Fashion-MNIST、ImageNet、MNIST,可以使用迅雷下载
常见的优化函数
SGD:
随机梯度下降优化器SGD和min-batch,抽取m个小批量(独立同分布)样本,通过计算他们平均梯度值。使用单个样本进行梯度下降时,模型可能会由于单个样本可能存在异常值引起梯度剧烈的震荡。
lr: float >=0.
momentum: float >= 0.
decay: float >0.
nesterov: boolean
RMSprop:
RMSProp增加了一个衰减系数来控制历史信息的获取多少,并且会对学习率进行衰减,通常是训练循环神经网络RNN的不错选择,建议使用优化器的默认参数。
lr: float >= 0.
rho: float >= 0. RMSProp梯度平方的移动均值的衰减率
epsilon: float >= 0. 模糊因子,若为None,默认为K.epsilon()
decay: float >= 0 每次参数更新后学习率衰减值
Adam:
Adam算法可以看作修正后的Momentum+RMSProp算法,超参数的选择非常鲁棒,学习率建议设置为0.001。Adam是一种可以替代传统随机梯度下降的一阶优化算法,它能基于训练数据迭代地更新神经网络权重,并且Adam通过计算梯度的一阶矩估计和二阶矩估计从而为不同的参数设计独立的自适应学习率。
lr: float >= 0. 学习率
beta_1: float, 0 < beta < 1. 通常接近于1
beta_2: float, 0 < beta < 1. 通常接近于1
decay: float >= 0. 么此参数更新后学习率衰减值
基础部分总结
创建模型的三种方法:
一、单层创建 nn.Linear
二、torch.nn.Sequential
三、自定义类(继承自nn.Module)
数据输入方式:
一、使用torchvision的内置数据集
二、从ndarray创建Tensor直接切片输入
三、使用torch.utils.data.TensorDataset创建dataset
四、使用toch.utils.data.DataLoader封装,创建batch,对数据进行shuffle,可以充分利用多cpu对数据进行处理,每次迭代返回一个批次的数据。
模型的训练步骤:
1、数据预处理
2、创建模型和优化方法
3、模型的调用
4、计算损失
5、梯度归零
6、计算梯度
7、反向传播
8、模型优化
9、打印指标
不同问题使用的损失函数和输出设置:
回归问题:预测连续的值
损失函数:均方误差 mse
输出层不需要激活
二分类问题:
损失函数:BCELoss 输出层激活方式:sigmoid
损失函数:CrossEntropyLoss 不进行激活
多分类问题:
损失函数:CrossEntropyLoss 不进行激活
损失函数:nn.NLLLoss labels必须是独热编码 使用torch.log softmax进行激活
计算机视觉基础
卷积神经网络:
卷积层 conv2d
ksize 卷积核大小
strides 卷积核移动步幅
padding 边缘填充
非线性层 relu/sigmoid/tanh
池化(下采样层)pooling2d
全连接层 w*x + b
网络通过这些层减少参数运算、过滤噪声,突出重要信息,使得网络可以拟合复杂任务。
CNN手写数字分类
模型在GPU上训练只需要两步:1、将模型转移到GPU 2、将每一批数据转移到GPU
四种天气分类
(1)取平均的作用
(2)减少神经元之间复杂的共适应关系:因为dropout导致两个神经元不一定每次都在一个dropout网络中出现。这样权值更新不再依赖有固定关系的隐含节点共同作用,阻止了某些特征仅仅在其它特定特征下才有效果的情况。
(3)Dropout更类似于性别在生物进化中的作用,物种为了生存往往会主动去适应环境,环境突变则会导致生物难以及时做出改变,而性别的出现又可以使物种在繁衍中不断进化以适应新的环境,从而有效阻止过拟合,避免了因环境改变导致物种灭绝的风险。
什么是标准化?
传统机器学习中标准化也叫归一化,一般是将数据映射到指定的范围,去除不同维度的量纲和量纲单位,有助于模型的学习以及对新数据的泛化。
常见的数据标准化:标准化和归一化,将数据减均值使其中心为0,然后除方差使其标准差为1,使其变为标准的正太分布。
什么是批标准化?
批标准化Batch Normalization和普通标准化类似,也是优化神经网络的一种方法。批标准化不仅在数据输入模型前做标准化,而且在网络的每一次变换后都考虑对数据进行标准化。即在模型训练过程中的数据均值和方差都在随时间发生变化,适当对数据进行标准化可以解决梯度消失和梯度爆炸问题。
为什么要做批标准化?
以sigmoid为例,sigmoid可以是模型输出到(0, 1)之间:
如果输入很大,对应的斜率就很小,反向传播的梯度就很小,模型的学习速率就会很慢。
由于在数据预处理阶段对数据进行标准化可以加速收敛,因此在神经网络中间使用标准化也可以提高模型的收敛速度,并且还有更多好处:
(1)具有正则化的效果
(2)提高模型的泛化能力
(3)允许使用更大的学习率加快模型收敛
批标准化有助于梯度传播,对于一些特别深度的网络只有包含多个BatchNormalization层时才能训练。且BatchNormalization广泛应用于pytorch内置的许多高级神经网络架构如ResNet、Inception V3等。
实现批标准化:
BatchNormalization通常在卷积层或全连接层之后使用:
nn.BatchNorm2d()
nn.BatchNorm1d()
批标准化的实现过程:
1、求每一批训练数据的均值
2、求每一批训练数据的方差
3、使用均值和方差对数据进行标准化:减均值除方差
4、训练两个参数γ和β
5、输出y通过γ和β线性变换的值,在反向传播过程中,根据求得的γ和β通过链式求导得到学习速率来改变权值
批标准化的预测过程:
预测阶段使用的均值和方差也来源于训练集,在模型训练时记录下每个batch的均值和方差,训练完毕后,求整个训练样本均值和方差的期望值,作为预测进行BatchNormalizaion的均值和方差。
批标准化的使用位置:
model.train()和model.eval()表示模型是在训练模式还是预测模式,当模型处在训练模式下,会使用当前批次输入数据的均值和方差对其进行标准化。当模型处在推理模式下,将使用在训练期间学习到的移动统计数据均值和方差的期望对其进行标准化。在原始论文中,批标准化一般作用于非线性激活函数之前,但是在实际应用中放在激活函数后面效果可能更好。
网络容量:可以认为与网络中可训练的参数成正比
网络中神经单元数量越多,网络的层数越多,网络的拟合能力就越强,但是网络训练难度就越大,越容易产生过拟合。
如何选择超参数?
所谓超参数,是需要人为设定不属于梯度下降优化的参数,比如模型中间层神经元的个数以及学习率等等。
如何提高网络的拟合能力?
1、增加网络层数
2、增加隐藏单元的个数
这两种方法哪种更好呢?
单纯增加神经单元个数对网络性能的提升并不明显,增加网络层数可以显著提高网络的拟合能力,这也是为什么现在网络层数越来越深的原因。单层神经单元的个数如果太少,会造成信息瓶颈,使网络欠拟合。理想的模型是介于欠拟合与过拟合,刚好能够拟合数据。
模型参数的选择原则:
首先开发一个过拟合的模型:
(1)增加网络层数
(2)增加每一层隐藏单元的数量
(3)增加模型训练的轮数
之后,抑制过拟合:
(1)添加dropout层
(2)使用BatchNormalization层
(3)使用图像增强
最后,调节模型的超参数:
(1)调整学习率
(2)调节隐藏单元数
(3)改变模型训练轮数
超参数的选择是基于先前的经验以及不断测试的结果,经典机器学习方法,如特征工程、增加训练数据和交叉验证,保证网络容量足够拟合数据。
构建网络的总原则:
一、增加网络容量直到过拟合
二、采取适当措施抑制过拟合
三、继续增大网络容量直到过拟合
预训练模型(迁移学习)
预训练网络是一个在大规模数据集(图像分类任务)上训练好的模型,如果这个原始数据集足够大且足够通用,预训练网络学习到的特征空间层次结构可以作为有效提取视觉世界特征的模型。即使新的任务与原视任务完全不同,模型学习到的特征也可以在不同问题之间进行移植,这也是深度学习相比浅层学习方法的一个重要优势,它使得深度学习对于解决小数据问题十分有效。
VGG在加深网络层数的同时为了避免参数过多,在网络的所有曾都采用3x3小卷积核,卷积步长设置为1,输入被设置为224x224大小RGB图像,并在训练集上计算所有图像的RGB均值,然后传入VGG网络,中间使用3x3或1x1大小的滤波器,卷积的步长固定为1。其中,VGG全连接层有3层,根据卷积层+全连接层数目的不同可以分为VGG11~VGG19,最少的VGG11有8个卷积层+3个全连接层,最多的VGG19有16个卷积层+3个全连接层,而且VGG网络并不是每一个卷积层后面都跟一个全连接层,总数还是5个全连接层,分布在不同的卷积层后面。
conv表示卷积层、FC表示全连接层
conv3-64表示卷积层使用3x3大小的滤波器且深度为64
在调整学习率时,既要使其足够小,保证不发生超调,也要让其足够大,保证loss能尽快下降,从而通过较少的迭代次数尽快地完成学习。
所谓微调,就是共同训练新添加的分类器层和部分或全部卷积层。通过“微调”基础模型中高阶特征表示,使其与特定任务更加相关。此外,只有分类器训练好了才能微调卷积基的卷积层。如果不这样做的话,刚开始训练的误差很大,微调之前卷积层学习到的特征就会被破坏掉。
微调步骤:
一、在预训练卷积基上添加自定义层
二、冻结卷积基所有层
三、只训练新添加的分类曾
四、解冻卷积基一部分层
五、联合训练解冻的卷积层和添加的自定义层
Dataset数据输入
现代网络架构
增加层的缺陷:模型想要获得更高的正确率,一种显然的思路是增加更多的层。随着网络层数的增加,模型的准确率逐渐提高,之后会发生过拟合,这时再增加更多的层模型的准确率就会下降。当网络到达一档的深度后再继续添加层可能会导致模型产生梯度消失或者梯度爆炸。这是我们可以通过更好的初始化权重、添加BN层等方法解决。现代的模型架构,试图引入不同的技术来解决这些问题,如残差连接。
网络特别深的时候会出现梯度消失和梯度爆炸,为了使得深层网络训练出更好的效果,何凯明作者等提出了残差模块Residual Block。通过堆叠ResBlock构成深度残差网络ResNet,ResNet通过增加残差连接(shortcut connection),显式地让网络拟合残差映射(residual mapping)。
ResNet不再尝试学习x到H(x)的潜在映射,而是学习两者之间的残差(residual),之后计算H(x),将残差加到输入上。这里假设残差F(x) = H(x) - x,我们将尝试学习F(x) + x,而不是直接学习H(x)。
每个Residual Block包含一系列层,残差连接把块的输入加到块的输出上。由于是元素级别的累加,所以模块输入和输出的大小要一致,如果大小不同,需要对网络进行填充。即ResNet网络为多个Residual Block的串联,实验表明通过学习残差相比直接学习输入、输出之间的映射更容易收敛,可以达到更高的分类精度,而且即使采用上百层的网络,ResNet都能展现出非常不错的表现。
ResNet-34与34层普通网络以及VGG的对比
ResNet网络的结构特点
1、与单纯堆叠网络层数,ResNet使用了非常多的“残差连接”,即shortcut路径,也就是我们说的Residual Block。
2、在ResNet中,所有的Residual Block都没有pooling层,降采样是通过conv和stride实现的。
3、通过Average Pooling得到最后的特征,而不是全连接层,每个卷积层后面都跟着一个BatchNorm层。
4、ResNet网络结构非常容易修改和进行扩展,只需要调整block里面的channel数量和堆叠block数量就可以很容易地调整网络的宽度和深度,进而得到不同表达能力的网络而不需要担心网络的”退化“问题。只要训练数据足够,通过加深网络就可以获得更好的性能表现。
ResNet使用了残差连接来搭建更深的网络,DenseNet则更进一步,每一层都接收所有前置层的特征平面作为输入。
Dense Block对比于Residual Block,每一个Dense Block中的任何两层都有直接的连接。也就是说,网络的每一层输入都是前面所有层输出的并集,该层所学习的特征图也会直接作为后面所有层的输入。通过层与层之间的密集连接,可以缓解梯度消失问题,加强特征传播,鼓励特征复用,从而极大地减少参数量。但这并不会增加网络的参数量和计算量,DenseNet相比于其他网络的计算效率更高,关键就在于网络每一层计算量的减少以及特征的重复利用,让每一层的输入之间影响到之后的所有层。DenseNet的密集连接方式需要特征图的大小保持一致,为了解决这个问题,DenseNet网络中使用了DenseBlock+Transition的结构。
DenseBlock模块的每层特征图大小相同,层与层之间采用密集连接的方式。而Transition模块是连接两个相同的DenseBlock,并通过Pooling层使特征图的大小降低。
Inception模块将不同滤波器尺寸的卷积1x1、3x3、5x5、7x7的卷积组合起联合在一起输出:
此结构主要有以下改进:
1、一层bolck包含1x1卷积、3x3卷积、5x5卷积和3x3池化。网络的每一层都能学习到“稀疏”(3x3、5x5)或 “不稀疏”(1x1)的特征,既能增加网络的宽度,也能增加网络对尺度的适应性。采用不同大小的卷积核意味着不同大小的感受野,最后拼接将不同尺度的特征进行融合。之所以卷积核采用1、3、5主要是为了方便对齐,并且嵌入pooling层,输出层使用concat合并而不是add相加,通过concat在每个block后合成特征,获得非线性属性。
2、为了降低算力成本,作者在3x3和5x5的卷积层之前添加额外的1x1卷积来限制输入信道的数量,对数据进行降维,引入更多的非线性,提高网络的泛化能力。
GoogleNet采用了模块化的Inception结构:
基础阶段已完结!
- 点赞
- 收藏
- 关注作者
评论(0)