赞
踩
转子:https://zhuanlan.zhihu.com/p/560482252
批梯度下降(Batch gradient descent):遍历全部数据集算一次损失函数,计算量开销大,计算速度慢,不支持在线学习。随机梯度下降(Stochastic gradient descent,SGD): 每看一个数据就算一下损失函数,然后求梯度更新参数。这个方法速度比较快,但是收敛性能不太好。批量随机梯度下降(Min-batch SGD):用一些小样本来近似全部的,其本质就是既然1个样本的近似不一定准,那就用更大的30个或50个样本来近似。将样本分成m个mini-batch,每个mini-batch包含n个样本。
我个人理解批量随机梯度下降其实更接近现在的Pytorch实际使用SGD优化器?
深度学习中的batch与mini-batch
使用动量(Momentum)的随机梯度下降法(SGD): 在随机梯度的学习算法中,每一步的步幅都是固定的,而在动量学习算法中,每一步走多远不仅依赖于本次的梯度的大小还取决于过去的速度。速度v是累积各轮训练参的梯度。
动量主要解决SGD的两个问题:一是随机梯度的方法(引入的噪声);二是Hessian矩阵病态问题(可以理解为SGD在收敛过程中和正确梯度相比来回摆动比较大的问题)。
1.2 Adam算法
RMSprop将学习率分解成一个平方梯度的指数衰减的平均。 Adam中动量直接并入了梯度一阶矩(指数加权)的估计。其次,相比于缺少修正因子导致二阶矩估计可能在训练初期具有很高偏置的RMSProp,Adam还包括偏置修正,修正从原点初始化的一阶矩(动量项)和(非中心的)二阶矩估计。
本质上是带有动量项的RMSprop,它利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率。Adam的优点主要在于经过偏置校正后,每一次迭代学习率都有个确定范围,使得参数比较平稳
1.3 Adam与SGD的区别
SGD缺点是其更新方向完全依赖于当前batch计算出的梯度,因而十分不稳定。
Adam的优点主要在于:
考虑历史步中的梯度更新信息,能够降低梯度更新噪声。
此外经过偏差校正后,每一次迭代学习率都有个确定范围,使得参数比较平稳。
但是Adam也有其自身问题:可能会对前期出现的特征过拟合,后期才出现的特征很难纠正前期的拟合效果。二者似乎都没法很好避免局部最优问题。
出现的原因:
模型复杂度过高,参数过多
训练数据比较小
训练集和测试集分布不一致
样本里面的噪声数据干扰过大,导致模型过分记住了噪声特征。
解决的方法:
降低模型复杂度
数据增强
正则化:
L1 惩罚权重绝对值, 生成简单、可解释的模型
L2 惩罚权重平方和, 能够学习复杂数据模式
dropout
早停
过拟合(overfitting)和欠拟合(underfitting)比较:
欠拟合在训练集和测试集上的性能都较差,而过拟合往往能较好地学习训练集数据的性质,而在测试集上的性能较差。在神经网络训练的过程中,欠拟合主要表现为输出结果的高偏差 Bias,模型不能适配训练样本,有一个很大的偏差。而过拟合主要表现为输出结果的高方差 Variance ,模型很好的适配训练样本,但在测试集上表现很糟,有一个很大的方差。
方差的含义:方差度量了同样大小的训练集的变动所导致的学习性能的变化,即刻画了数据扰动所造成的影响。
偏差的含义:偏差度量了学习算法的期望预测与真实结果的偏离程度,即刻画了学习算法本身的拟合能力。
BN计算公式如下
训练与推理时BN中的均值、方差计算差异
训练时,均值、方差分别是该批次内数据相应维度的均值与方差;推理时,均值、方差是基于所有批次的期望计算所得。其中在推理时所用的均值和方差是通过移动平均计算得到的,可以减少存储每个batch均值方差的内存。
具体的均值方差计算可视化图参考。
BN层的作用:
加快网络的训练与收敛的速度; 控制梯度爆炸防止梯度消失。
3.2 LN层
LN层的计算
LN层与BN相比,只考虑单个sample内的统计变量,因此也不用使用BN实现中的running mean, running var.,LN也完全不用考虑输入batch_size的问题。
至于为什么transformer中不使用BN归一化
解释一:CV和NLP数据特性的不同,对于NLP数据,前向和反向传播中,batch统计量及其梯度都不太稳定,一个Batch中每个句子对应位置的分量不一定有意义。
解释二:要能在某个维度做独立同分布假设,才能合理归一化。对于CV来说,batch之间的图像是独立的,可以使用BN,而对于自然语言的token,相互是具有较强的关联性,不是相互独立的。
transformer 为什么使用 layer normalization,而不是其他的归一化方法?
不可以,在神经网络中,如果将权值初始化为 0 ,或者其他统一的常量,会导致后面的激活单元具有相同的值,所有的单元相同意味着它们都在计算同一特征,网络变得跟只有一个隐含层节点一样,这使得神经网络失去了学习不同特征的能力!
对于逻辑回归来说,把参数初始化为0是可以的。
5. 网络感受野的计算
表示第
层的感受野,
表示第
层卷积核的大小,则第
层卷积输出特征的感受野为:
特别地对于第1层即输入而言,感受野大小为1。
除了上述式子外,还可以从后往前推导,如下:
最后一层的感受野为该层卷积核大小,依次往前推导, stride为步长,Ksize为卷积核大小。
给定参数:输入图片大小(w, w), 卷积核大小 (k, k), 步长 s, padding值 p, 输出特征图大小为:
import numpy as np
img = np.random.rand(2, 5, 5, 3) # bs x h x w x c
ker = np.ones([3, 3, 3, 6]) # h x w x c_in x c_out
def conv(img, ker, stride=1, padding=0):
size = list(img.shape)
pad_img = np.zeros([size[0], size[1] + 2 * padding, size[2] + 2 * padding, size[3]])
pad_img[:, padding:-padding, padding:-padding, :] = img
img = pad_img
# 套用卷积特征输出大小计算公式
out_size = (img.shape[1] + 2* padding - ker.shape[0]) // stride + 1
res = np.zeros([img.shape[0], out_size, out_size, ker.shape[3]])
# 假设batchsize等于1, 则忽略此循环
for i in range(img.shape[0]):
# 卷积后的输出的通道数
for out_c in range(ker.shape[3]):
# hi表示padding后原图的坐标 每一次都是移动stride大小
for hi in range(0, out_size * stride, stride):
for wi in range(0, out_size * stride, stride):
# 确定要计算conv的区域
region = img[i, hi:hi + ker.shape[0], wi:wi + ker.shape[0], :]
# 卷积计算
res[i, hi // stride, wi // stride, out_c] = np.sum(region * ker[:, :, :, out_c])
return res
8. IoU与NMS python实现
IoU
import numpy as np
pred_box = np.rand(10, 4)
gt_box = np.rand(10, 4)
def get_IoU(pred_box, gt_box):
x_min = max(pred_box[0], gt_box[0])
y_min = max(pred_box[1], gt_box[1])
x_max = min(pred_box[2], gt_box[2])
y_max = min(pred_box[3], gt_box[3])
w = np.maximum(xmax-xmin+1, 0)
h = np.maximum(ymax-ymin+1, 0)
inter = w * h
union = (pred_box[2]-pred_box[0] + 1.0) * (pred_bbox[3] - pred_bbox[1] + 1.) + (gt_bbox[2] - gt_bbox[0] + 1.) * (gt_bbox[3] - gt_bbox[1] + 1.) - inter
IoU = inetr / union
return IoU
NMS 实现原理:
首先对于每个类别,将其中分类置信度小于阈值的框置信度设置为0;
之后对所有box按照得分进行排序,选出最高分对应的box_1;
遍历其余的box,如果和上面选择的box_1重叠面积IoU大于一定阈值,则筛掉该box;
对剩余box继续选择一个最高分的box_2,重复上面步骤直到剩余的box集合为空。
深度可分离卷积
一些轻量级的网络,如mobilenet中,会有深度可分离卷积depthwise separable convolution,由depthwise(DW)和pointwise(PW)两个部分结合起来,用来提取特征feature map,其中前者卷积核每次只计算单张feature map,卷积核大小为 k x k x 1,后者是卷积只计算单个空间位置上的点,卷积核大小为 1x1 x c_in.
转置卷积/反卷积
self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
def forward(self, x):
B, N, C = x.shape
# qkv: 3 x B x heads_num x N x c // heads_num
qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
# q, k, v : B x heads_num x N x c // heads_num
q, k, v = qkv[0], qkv[1], qkv[2] # make torchscript happy (cannot use tensor as tuple)
# attn : B x heads_num x N x N
attn = (q @ k.transpose(-2, -1)) * self.scale
attn = attn.softmax(dim=-1)
weights = attn
attn = self.attn_drop(attn)
x = (attn @ v).transpose(1, 2).reshape(B, N, C)
x = self.proj(x)
x = self.proj_drop(x)
return x, weights
梯度爆炸的原因:一般出现在深层网络和权值初始化值太大的情况下。在深层神经网络或循环神经网络中,误差的梯度可在更新中累积相乘。如果网络层之间的梯度值大于 1.0,那么重复相乘会导致梯度呈指数级增长,梯度变的非常大,然后导致网络权重的大幅更新,并因此使网络变得不稳定。
梯度爆炸会使得在训练过程中,权重的值变得非常大,以至于溢出,导致模型损失变成 NaN等等。
解决方法:梯度剪切,对梯度设定阈值;权重正则化;batch normalization;残差网络的捷径(shortcut);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。