基础组件详情-深度学习实战
基础组件详解
划分数据集
当我们拿到一个完整的数据集时候,我们普遍将数据集划分成三部分:训练集,验证集,测试集。他们的比例是7:2:1。
划分原则:
- 三个子集尽可能同分布:如果三个子集划分分布不均,可能导致训练出来的模型效果不好。
- 不能数据泄露:测试集与训练集必须隔离,划分的测试集必须是模型从未见过的数据。
- 数据较少时候,可以合并
dev/test
数据集。
预处理
不同的行业的数据,会有着不同的评价指标,就具有不同的量纲,例如:对于评价房价来说量纲指:面积、房价数、楼层等;对于预测某个人患病率来说量纲指:身高、体重等。)和量纲单位(例如:面积单位:平方米、平方厘米等;身高:米、厘米等),这些都会对数据分析发生影响。对数据进行归一化,可以消除数据之间的量纲的影响。
优点:
- 归一化加快梯度下降求最优解的速度
- 归一化有可能提高精度(归一化是让不同维度之间的特征在数值上有一定的比较性)。
方法:
min-max
标准化(Min-Max Normalization
)(线性函数归一化)
- 定义:也称为离差标准化,是对原始数据的线性变换,使得结果映射到0-1之间。
- 本质:把数变为【0,1】之间的小数。
- 转换函数:(X-Min)/(Max-Min)
- 如果想要将数据映射到-1,1,则将公式换成:(X-Mean)/(Max-Min)
其中: max为样本数据的最大值,min为样本数据的最小值,Mean表示数据的均值。
缺陷: 当有新数据加入时,可导致max和min的变化,需要重新定义。
- 0 均值标准化(
Z-score standardization
)
- 定义:这种方法给与原始数据的均值(
mean
)和标准差(standard deviation
)进行数据的标准化。经过处理的数据符合标准正态分布,即均值为0,标准差为1. - 本质:把有量纲表达式变成无量纲表达式。
- 转换函数:(
X-Mean
)/(Standard deviation
)
其中,Mean为所有样本数据的均值。Standard deviation为所有样本数据的标准差。
初始化模型参数
目的:
- 加快模型收敛
- 抑制梯度消失与爆炸
经典初始化方法:
Xavier
目的:使得网络中信息更好的流动,每一层输出的方差应该尽量相等。
实现:
from torch import nn
nn.init.xavier_uniform_(model.weight,gain=nn.init.calculate_gain('tahn'))
Kaiming/He
- 前向传播的时候, 每一层的卷积计算结果的方差为1.
- 反向传播的时候, 每一 层的继续往前传的梯度方差为1(因为每层会有两个梯度的计算, 一个用来更新当前层的权重, 一个继续传播, 用于前面层的梯度的计算.)
实现:
nn.init.kaiming_uniform_(model.weight,a=1,mode= 'fan_in',nonlinearity='leaky_relu')
激活函数
作用:赋予神经网络非线性能力,以便使网络更加强大,增加它的能力,使它可以学习复杂的事物,复杂的表单数据,以及表示输入输出之间非线性的复杂的任意函数映射。
原因:
如果不用激活函数,每一层输出都是上层输入的线性函数,无论神经网络有多少层,输出都是输入的线性组合,这种情况就是最原始的感知机(Perceptron)。没有激活函数的每层都相当于矩阵相乘。就算你叠加了若干层之后,无非还是个矩阵相乘罢了。
如果使用的话,激活函数给神经元引入了非线性因素,使得神经网络可以任意逼近任何非线性函数,这样神经网络就可以应用到众多的非线性模型中。
常见激活函数:
sigmoid
函数
优点:
- Sigmoid函数的输出映射在(0,1)之间,单调连续,输出范围有限,优化稳定,可以用作输出层。
- 求导容易。
缺点:
- 由于其软饱和性,容易产生梯度消失,导致训练出现问题。
- 其输出并不是以0为中心的。
tanh
函数
优点:
- 比Sigmoid函数收敛速度更快。
- 相比Sigmoid函数,其输出以0为中心。
缺点:
- 还是没有改变Sigmoid函数的最大问题——由于饱和性产生的梯度消失。
ReLU
优点:
- 相比起Sigmoid和tanh,ReLU在SGD中能够快速收敛。
- Sigmoid和tanh涉及了很多很expensive的操作(比如指数),ReLU可以更加简单的实现。
- 有效缓解了梯度消失的问题。
- 在没有无监督预训练的时候也能有较好的表现。
- 提供了神经网络的稀疏表达能力。
缺点:
- 随着训练的进行,可能会出现神经元死亡,权重无法更新的情况。如果发生这种情况,那么流经神经元的梯度从这一点开始将永远是0。也就是说,ReLU神经元在训练中不可逆地死亡了。
Mish
经过ReLU
、Swish
、Mish三
个不同激活函数后的输出对比,从中可以发现Mish
相对于ReLU
、Swish
显得更加平滑一些。
优化器
参考:www.cnblogs.com/guoyaohua/p…
- BGD(Batch Gradient Descent )
缺点:由于这种方法是在一次更新中,就对整个数据集计算梯度,所以计算起来非常慢,遇到很大量的数据集也会非常棘手,而且不能投入新数据实时更新模型。
Batch gradient descent 对于凸函数可以收敛到全局极小值,对于非凸函数可以收敛到局部极小值。
- SGD(Stochastic Gradient Descent )
**缺点:**SGD 因为更新比较频繁,会造成 cost function 有严重的震荡。
BGD 可以收敛到局部极小值,当然 SGD 的震荡可能会跳到更好的局部极小值处。
当我们稍微减小 learning rate
,SGD 和 BGD 的收敛性是一样的。
- Nesterov Accelerated Gradient
超参数设定值: 一般 γ 仍取值 0.9 左右。
NAG 会先在前一步的累积梯度上(brown vector)有一个大的跳跃,然后衡量一下梯度做一下修正(red vector),这种预期的更新可以避免我们走的太快。
NAG 可以使 RNN 在很多任务上有更好的表现。
- Adam
超参数设定值: 建议 β1 = 0.9,β2 = 0.999,ϵ = 10e−8
Normalization
相关使用:
""" NHWC
N: batch size : 8
H: height: 224,
W: width: 224,
C: channel: 16
NCHW, NHWC
"""
""" batch norm
在N 求E(x), Var(x)
适用于大的 batch size
不太适用于变长数据:text, speech
"""
bn_norm = nn.BatchNorm2d(num_features=16) # input shape: NCHW
norm_out = bn_norm(output_from_pre_layer.permute(0, 3, 1, 2)) # NHWC -> NCHW
print('norm from bn', norm_out.shape)
""" layer normalization
在[224,224,16]求E(x), Var(x)
对batch size 不敏感, 适用sequence data(序列变长的数据): RNN/Transformer
"""
ln_norm = nn.LayerNorm([224, 224, 16]) # input shape: [N, *]
norm_out = ln_norm(output_from_pre_layer)
print('norm from ln', norm_out.shape)
""" instance normalization
在channel 这个维度上求的E(x), Var(x)
适用GAN(生成式神经网络)
"""
in_norm = nn.InstanceNorm2d(16) # input shape: NCHW
norm_out = in_norm(output_from_pre_layer.permute(0, 3, 1, 2))
print('norm from in', norm_out.shape)
""" group normalization
在分组后的group上求的E(x), Var(x): [224, 224, group_number, 16/group_number]
group number: 需要精心设置
"""
gn_norm = nn.GroupNorm(num_groups=4, num_channels=16) # input shape: (N, C, *)
norm_out = gn_norm(output_from_pre_layer.permute(0, 3, 1, 2))
print('norm from gn', norm_out.shape)
final_output = F.relu(norm_out)
提升模型表现
我们在训练模型时候,会出现下面三种情况:
左-右:欠拟合 正常 过拟合
常见的是过拟合情况,解决过拟合的方案如下:
- 增加训练数据
这是解决过拟合现象的根本办法,若没有过多的训练数据,我们可以通过数据增广方式来在增加数据的数量,从而让模型的泛化能力增强。
- 控制模型复杂度
过于复杂的模型容易造成过拟合现象。对于模型的设计而言,我们应该选择简单、合适的模型解决复杂的问题。
L1/L2
正则化
L1 正则化:
L2 正则化:
dropout
机制
Dropout
指的是在训练过程中每次按一定的概率(比如50%)随机地“删除”(将该部分神经元的激活函数设为0(激活函数的输出为0),让这些神经元不计算而已。)一部分隐藏单元(神经元)。
Dropout
为什么有助于防止过拟合呢?
- 在训练过程中会产生不同的训练模型,不同的训练模型也会产生不同的的计算结果。随着训练的不断进行,计算结果会在一个范围内波动,但是均值却不会有很大变化,因此可以把最终的训练结果看作是不同模型的平均输出。
- 它消除或者减弱了神经元节点间的联合,降低了网络对单个神经元的依赖,从而增强了泛化能力。
- Early stopping (早停)
为了获得性能良好的神经网络,训练过程中可能会经过很多次 epoch(遍历整个数据集的次数,一次为一个epoch)。
如果epoch数量太少,网络有可能发生欠拟合;
如果epoch数量太多,则有可能发生过拟合。
Early stopping旨在解决epoch数量需要手动设置的问题。具体做法:每个epoch(或每N个epoch)结束后,在验证集上获取测试结果,随着epoch的增加,如果在验证集上发现测试误差上升,则停止训练,将停止之后的权重作为网络的最终参数。
转载自:https://juejin.cn/post/7125819725006766111