参考文章:https://blog.csdn.net/qq_37541097/article/details/104434557
目的:我们在图像预处理过程中通常会对图像进行标准化处理,这样能够加速网络的收敛
我们希望输入的所有训练数据样本满足某一分布规律,理论上是指所有的训练样本满足分布规律,而不是某一个样本满足。而Batch Normalization的目的就是使我们的feature map满足均值为0,方差为1的分布规律。
在实际的任务中,如果要计算机一下计算出所有样本的分布,显然是不可能的。所以我们针对模型喂入的batch图片数,计算一个batch的分布规律(batch越大越接近整个数据集的分布,效果越好)。对于图像 x x x而言,图像是RGB三通道则有 x = ( x ( 1 ) , x ( 2 ) , x ( 3 ) ) x= (x^{(1)} , x^{(2)} , x^{(3)}) x=(x(1),x(2),x(3)),分别对应三个通道的特征矩阵。
BN的计算公式如下:
我们根据上图的公式可以知道 μ β \mu\beta μβ代表着我们计算的feature map每个维度(channel)的均值,注意 μ β \mu\beta μβ是一个向量不是一个值, μ β \mu\beta μβ向量的每一个元素代表着一个维度(channel)的均值。 σ β 2 \sigma^2_\beta σβ2代表着我们计算的feature map每个维度(channel)的方差,注意 σ β 2 \sigma^2_\beta σβ2是一个向量而不是一个值, σ β 2 \sigma^2_\beta σβ2向量的每一个元素代表着一个维度(channel)的方差,然后根据 μ β \mu\beta μβ和 σ β 2 \sigma^2_\beta σβ2计算标准化处理后得到的值。下图给出了一个计算均值和方差的示例:
上图展示了一个batch size为2(两张图片)的Batch Normalization的计算过程,假设feature1、feature2分别是由image1、image2经过一系列卷积池化后得到的特征矩阵,feature的channel为2,那么 x ( 1 ) x^{(1)} x(1)代表该batch的所有feature的channel1的数据,同理 x ( 2 ) x^{(2)} x(2)代表该batch的所有feature的channel2的数据。然后分别计算 x ( 1 ) x^{(1)} x(1)和 x ( 2 ) x^{(2)} x(2)的均值与方差,得到我们的 μ β \mu\beta μβ和 σ β 2 \sigma^2_\beta σβ2两个向量。然后在根据标准差计算公式分别计算每个channel的值(公式中的 ϵ \epsilon ϵ是一个很小的常量,防止分母为零的情况)。在我们训练网络的过程中,我们是通过一个batch一个batch的数据进行训练的,但是我们在预测过程中通常都是输入一张图片进行预测,此时batch size为1,如果在通过上述方法计算均值和方差就没有意义了。所以我们在训练过程中要去不断的计算每个batch的均值和方差,并使用移动平均(moving average)的方法记录统计的均值和方差,在训练完后我们可以近似认为所统计的均值和方差就等于整个训练集的均值和方差。然后在我们验证以及预测过程中,就使用统计得到的均值和方差进行标准化处理。
注:在BN的计算公式中还存在可训练参数 γ \gamma γ和 β \beta β。其中 γ \gamma γ用来调整数值分布的方差大小, β \beta β用来调节数值均值的位置。这两个参数是在反向传播的过程中学习得到的, γ \gamma γ的默认值为1, β \beta β的默认值为0。
以上的内容,对于一个batch一个batch的计算均值和方差,是在样本训练过程中,而我们在预测和验证过程中到底是怎么样的呢 ?以前的理解是对于某个任务,逐个batch求均值和方差,然后计算其统计量,顾名思义就是对若干batch得均值和方差再求均值,使其适用于决大多数的样本分布。但是真的是这样的吗,其实并不是:在我们的验证和测试过程中所使用的均值和方差是一个统计量 μ t e s t \mu_{test} μtest和 σ t e s t 2 \sigma^2_{test} σtest2。将训练阶段得到的 μ β \mu\beta μβ均值记作 μ t r a i n \mu_{train} μtrain,将 σ β 2 \sigma^2_\beta σβ2方差记作 σ t r a i n 2 \sigma^2_{train} σtrain2,其中momentum默认取0.1,如下式所示:
μ t e s t + 1 = ( 1 − m o m e n t u m ) × μ t e s t + m o m e n t u m × μ t r a i n \mu_{test}+1 = (1 - momentum)\times \mu_{test} + momentum\times \mu_{train} μtest+1=(1−momentum)×μtest+momentum×μtrain
σ t e s t 2 + 1 = ( 1 − m o m e n t u m ) × σ t e s t 2 + m o m e n t u m × σ t r a i n 2 \sigma^2_{test}+1 = (1-momentum)\times \sigma^2_{test} + momentum\times \sigma^2_{train} σtest2+1=(1−momentum)×σtest2+momentum×σtrain2
这里要注意一下,在pytorch中对当前批次feature进行BN处理使所使用的 σ t r a i n 2 \sigma^2_{train} σtrain2是总体标准差,计算公式如下:
σ t r a i n 2 = 1 m ∑ i = 0 m ( x i − μ t r a i n ) 2 \sigma^2_{train} = \frac{1}{m} \sum_{i=0}^{m}{(x_i - \mu_{train})}^2 σtrain2=m1i=0∑m(xi−μtrain)2
在更新统计量 σ t e s t 2 \sigma^2_{test} σtest2时采用的 σ t r a i n 2 \sigma^2_{train} σtrain2是样本标准差,计算公式如下:
σ t r a i n 2 = 1 m − 1 ∑ i = 0 m ( x i − μ t r a i n ) 2 \sigma^2_{train} = \frac{1}{m-1} \sum_{i=0}^{m}{(x_i - \mu_{train})}^2 σtrain2=m−11i=0∑m(xi−μtrain)2
(1)训练时要将traning参数设置为True,在验证时将trainning参数设置为False。在pytorch中可通过创建模型的model.train()和model.eval()方法控制。
(2)batch size尽可能设置大点,设置小后表现可能很糟糕,设置的越大求的均值和方差越接近整个训练集的均值和方差。
(3)建议将bn层放在卷积层(Conv)和激活层(例如Relu)之间,且卷积层不要使用偏置bias,因为没有用,参考下图推理,即使使用了偏置bias求出的结果也是一样的。
参考文章:https://blog.csdn.net/qq_37541097/article/details/123754766
在Faster RCNN中,会使用RoIPool将RPN得到的Proposal(提议)池化到相同大小。这个过程会涉及quantization(量化)或者说取整操作,这会导致定位不是那么的准确(文中称为misalignment问题)。
下面的示意图就是RoIPool的执行过程,其中会经历两次quantization。假设通过RPN得到了一个Proposal,它在原图上的左上角坐标是(10,10),右下角的坐标是(124,124),对应要映射的特征层相对原图的步距为32,通过RoIPool期望的输出为2x2大小:
由于RoIPool中,对于类似 5 × 5 5\times5 5×5的proposal区域进行池化,会产生不规则的区域用于池化输出,作者认为这种方式丢失了精确的空间定位信息。所以提出了RoIAlign。
下面的示意图就是RoIAlign的执行过程。同样假设通过RPN得到了一个Proposal,它在原图上的左上角坐标是(10,10),右下角的坐标是(124,124),对应要映射的特征层相对原图的步距为32,通过RoIAlign期望的输出为2x2大小:
参考文章:https://blog.csdn.net/qq_37541097/article/details/112564822
线性插值是指插值函数为一次多项式的插值方式。线性插值的几何意义即为利用过A点和B点的直线来近似表示原函数。线性插值可以用来近似代替原函数,也可以用来计算得到查表过程中表中没有的数值。
那么如下图所示,假设已知 y 1 = f ( x 1 ) y_1=f(x_1) y1=f(x1), y 2 = f ( x 2 ) y_2 = f(x_2) y2=f(x2) ,现在要通过线性插值的方式得到区间 [ x 1 , x 2 ] [x_1, x_2] [x1,x2]内任何一点的 f ( x ) f(x) f(x)值。
双线性插值,又称为双线性内插,在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值。
通过以上介绍我们知道,双线性插值就是分别在两个方向上分别进行一次简单的线性插值即可。如下图所示,每个点的数值是由 z = f ( x , y ) z=f(x,y) z=f(x,y)即 x , y x,y x,y两个变量决定。下图可理解为沿z轴方向的俯视图。我们已知 Q 11 、 Q 12 、 Q 21 、 Q 22 Q_{11}、Q_{12}、Q_{21}、Q_{22} Q11、Q12、Q21、Q22四个点的值,现在要在 Q 11 、 Q 12 、 Q 21 、 Q 22 Q_{11}、Q_{12}、Q_{21}、Q_{22} Q11、Q12、Q21、Q22四个点中插入一个点 P P P,并算出 P P P点的值。
在求 P P P点之前,首次根据线性插值的方法求得 R 1 、 R 2 R_1、R_2 R1、R2的值。对于 R 1 R_1 R1点,我们可以根据 Q 11 、 Q 21 Q_{11}、Q_{21} Q11、Q21两个点的线性插值得到。而 Q 11 、 Q 21 Q_{11}、Q_{21} Q11、Q21两个点的 y y y值是相同的,所以两点的连线可以只看做变量 x x x的函数。
在图像处理中,常见的坐标系如下图所示,以图像左上角为坐标原点,水平向右为x轴正方向,竖直向下为y轴正方向。注意像素值是从 ( 0 , 0 ) (0,0) (0,0)点开始,假设我们在图像中插入一个点 P P P,离 P P P点最近的相邻四个像素点是 Q 11 , Q 12 , Q 21 , Q 22 Q_{11}, Q_{12}, Q_{21}, Q_{22} Q11,Q12,Q21,Q22,并利用双线性插值的方法求其值。
在图像中,像素点都是行列排序,如果插入一点,取其相邻像素的四个点,这四个点在排列组合上可能存在同行或者同列,也就是相隔一个像素取一个值。所以也就是取的四个点,相邻点之间的像素间隔为1个像素。所以该公式在图像区域内也是同理。
f ( P ) = ( x 2 − x ) ( y 2 − y ) ( x 2 − x 1 ) ( y 2 − y 1 ) × f ( Q 11 ) + ( x − x 1 ) ( y 2 − y ) ( x 2 − x 1 ) ( y 2 − y 1 ) × f ( Q 21 ) + ( x 2 − x ) ( y − y 1 ) ( x 2 − x 1 ) ( y 2 − y 1 ) × f ( Q 12 ) + ( x − x 1 ) ( y − y 1 ) ( x 2 − x 1 ) ( y 2 − y 1 ) × f ( Q 22 ) f(P)=\frac{(x_2 - x)(y_2 - y)}{(x_2 - x_1)(y_2 - y_1)}\times f(Q_{11}) + \frac{(x - x_1)(y_2-y)}{(x_2 - x_1)(y_2-y_1)}\times f(Q_{21}) + \frac{(x_2 - x)(y - y_1)}{(x_2 - x_1)(y_2 - y_1)}\times f(Q_{12}) + \frac{(x - x_1)(y-y_1)}{(x_2 - x_1)(y_2-y_1)}\times f(Q_{22}) f(P)=(x2−x1)(y2−y1)(x2−x)(y2−y)×f(Q11)+(x2−x1)(y2−y1)(x−x1)(y2−y)×f(Q21)+(x2−x1)(y2−y1)(x2−x)(y−y1)×f(Q12)+(x2−x1)(y2−y1)(x−x1)(y−y1)×f(Q22)
RPN的全称是 r e g i o n p r o p o s a l n e t w o r k region proposal network regionproposalnetwork---->候选检测框生成网络
RPN网络的输入是:backbone输出得到的多尺度 f e a t u r e m a p s feature maps featuremaps。
RPN网络的输出是: p r o p o s a l s proposals proposals候选区域。
推理第一阶段先找出图片中待检测物体的anchor矩形框(对背景、待检测物体进行二分类),第二阶段对anchor框内待检测物体进行分类。
Rcnn算法流程可分为4个步骤
参考文章:https://www.cnblogs.com/wangguchangqing/p/12021638.html
均方误差是模型预测输出值 f ( x ) f(x) f(x)与模型真实标签值 y y y之间差值的平方的的均值,其公式如下:
M S E = ∑ i = 1 n ( f x i − y i ) 2 n MSE=\frac{\sum_{i=1}^{n}{(f_{x_i}-y_i)^2}}{n} MSE=n∑i=1n(fxi−yi)2
其中, y i y_i yi和 f ( x i ) f(x_i) f(xi)分别表示第 i i i个样本的真实标签及其对应的预测输出值。当真实标签和预测输出的差值大于1时,他们的平方将会更大,则当差值小于1时,他们的平方会更小。 M S E MSE MSE对于较大的误差(>1)给予较大的惩罚,较小的误差(<1)给予较小的惩罚。我们多次训练降低我们的损失函数( M S E MSE MSE)值时,那些相较于真实标签差距大的预测点,我们会更加关注,其对损失函数的影响以及贡献也就越大。
注意:还需要知道的是, M S E MSE MSE在图像化表示上为一个凹曲线,凹点为0原点。这也就是说, M S E MSE MSE的函数曲线光滑、连续、处处可导,在使用梯度下降法(梯度下降法是优化器),在优化的过程中,随着误差的减小,梯度也在减小,利于优化。
图像化表示:
均值绝对差是指模型预测输出值 f ( x ) f(x) f(x)与真实标签 y y y之间差值绝对值的均值,其可以表示为:
M A E = ∑ i = 1 n ∣ f ( x i ) − y i ∣ n MAE=\frac{\sum_{i=1}^{n}{|f(x_i)-y_i|}}{n} MAE=n∑i=1n∣f(xi)−yi∣
其图形化表示如下;
MAE曲线连续,但是在 y − f ( x ) = 0 y−f(x)=0 y−f(x)=0处不可导。而且 MAE 大部分情况下梯度都是相等的,这意味着即使对于小的损失值,其梯度也是大的,这不利于函数的收敛和模型的学习。但是,无论对于什么样的输入值,都有着稳定的梯度,不会导致梯度爆炸问题,具有较为稳健性的解。
由于MAE对于大部分情况的梯度都相等,所以对于离群点(与真实标签相差较大的点)也不是很敏感,也可以说对于任意大小位置的预测点,其惩罚力度都是一样的,损失函数对所有点的关注相同。
总的说各有利弊,对于一些异常值(离群点)毕竟是样本中的个别,所以对于异常点的学习好像又没什么必要,但是MAE导数不连续。而针对MSE损失函数,其容易受异常点(离群点)点的影响,我们可设置阈值将异常点的导数设置为0来避免这种情况(这里要说的就是:对于离群点,在MSE图像化中可以发现,其差值越大,其梯度越大)。
公式如下;
S m o o t h L 1 ( x ) = { 0.5 x 2 , i f ∣ x ∣ < 1 ∣ x ∣ − 0.5 , ∣ x ∣ > = 1 SmoothL_1(x)=\begin{cases} 0.5x^2,&if |x|<1 \cr |x|-0.5,&|x|>=1 \end{cases} SmoothL1(x)={0.5x2,∣x∣−0.5,if∣x∣<1∣x∣>=1
上式中, L 1 ( x ) = x = f ( x i ) − y i L_1(x)=x= f(x_i)-y_i L1(x)=x=f(xi)−yi为预测值与真实值的差值。
S m o o t h L 1 SmoothL_1 SmoothL1能从两个方面限制梯度:
参考文章: https://zhuanlan.zhihu.com/p/38241764
正文: 交叉熵主要是用来判定实际的输出与期望的输出的接近程度
信息量:它是用来衡量一个事件的不确定性的;一个事件发生的概率越大,不确定性越小,则它所携带的信息量就越小。
熵:它是用来衡量一个系统的混乱程度的,代表一个系统中信息量的总和;信息量总和越大,表明这个系统不确定性就越大。
交叉熵:主要刻画的是实际输出(概率)与期望输出(概率)的距离,交叉熵的值越小,两个概率分布就越接近。假设概率分布 y ^ \hat{y} y^为预测输出(则为真实标签为0或1时,其对应的概率),概率分布 y y y为期望输出( y y y可以认为是一个样本的真实标签:0或者1), L L L为交叉熵,对于(单个样本的损失函数)二分类问题的表达式为:
L = − [ y l o g y ^ + ( 1 − y ) l o g ( 1 − y ^ ) ] L=-[ylog\hat{y}+(1-y)log(1-\hat{y})] L=−[ylogy^+(1−y)log(1−y^)]
在二分类问题中,如果某样本的真实标签为1( y = 1 y=1 y=1),则交叉熵公式为: L = − l o g y ^ L=-log\hat{y} L=−logy^,这时,其图像化表示为:
从上图可以发现,对于真实标签为1的样本,其交叉熵函数为 L = − l o g y ^ L=-log\hat{y} L=−logy^,也就是预测输出 y ^ \hat{y} y^越接近真实标签的值1,则交叉熵函数损失越小。同理,当真实标签为0时,只有期望输出值 y ^ \hat{y} y^越接近0,则损失函数才会越小。
如果是计算N个样本的总的损失函数,则表达式为:
L = − ∑ i = 1 N y i l o g y i ^ + ( 1 − y i ) l o g ( 1 − y i ^ ) L=-\sum_{i=1}^{N}{y^ilog\hat{y^i}+(1-y^i)log(1-\hat{y^i})} L=−i=1∑Nyilogyi^+(1−yi)log(1−yi^)
对于多样本的情况,也是同理,在真实标签 y i y^i yi的情况下,将期望输出 y i ^ \hat{y^i} yi^的概率无限逼近真实标签,则就有了多样本的交叉熵损失函数。
论文提出影响一阶段检测网络精度的原因在于:
则最终的 F o c a l L o s s Focal Loss FocalLoss损失函数可以表达为:
F L ( y ^ ) = { − α ( 1 − y ^ ) γ l o g y ^ , i f y = 1 − ( 1 − α ) y ^ γ l o g ( 1 − y ^ ) , y = 0 F_L(\hat{y}) = \begin{cases}-\alpha (1-\hat{y})^\gamma log\hat{y},&if y=1 \cr -(1- \alpha)\hat{y}^\gamma log(1-\hat{y}),&y=0\end{cases} FL(y^)={−α(1−y^)γlogy^,−(1−α)y^γlog(1−y^),ify=1y=0
另一种写法:
F L ( P t ) = − α t ( 1 − P t ) γ l o g ( P t ) F_L(P_t) = -\alpha_t(1-P_t)^\gamma log(P_t) FL(Pt)=−αt(1−Pt)γlog(Pt)
参考文章:https://zhuanlan.zhihu.com/p/66534632
梯度下降法就是反向传播的一种方式。
梯度下降法可以理解为针对于损失函数的优化算法,为什么这么说呢?在模型进行训练的过程中,模型读入一个batch,两个,以及更多,直到所有的迭代次数完成,模型只是针对于你设定的epoch数完成了训练,得到一堆大得离谱的损失值,为什么呢,因为没有参数更新,得不到最优的参数,而得到最优的参数仅仅是参数更新吗,也不是。这就有了优化器的作用,他会辅助损失函数进行梯度回传,然后进行参数的更新,以保证损失值越来越小,也就是模型在向着最优解逐步靠近。
参数更新:
参数的更新对象其实就是 W W W和 b b b,对于 W x + b Wx+b Wx+b来说, d W dW dW就是输入值乘以 x x x, d b db db就等于输入值。这里用 d W dW dW和 d b db db表示反向传播到 W W W和 b b b节点时的计算结果。
那现在该怎样更新W和b呢?