Deep Residual Learning for Image Recognition
0. Tips
-
图像卷积中的维度是指通道数。
-
过拟合问题:训练集误差低,但验证集误差高。
退化问题:随着网络深度的增加,训练集和验证集误差都越来越高。
出现退化现象的原因:存在一个合理的猜测,对于神经网络来说,通过非线性层来拟合恒等映射并不容易,会出现退化现象。
也就是说,尽管网络层次加深,但是高层网络无法完全保留低层网络的信息,当低层将特征传向高层时会发生改变。如果低层已经得到了最佳特征,但是经过非线性映射后传到高层反而会使得训练出来的网络偏离最佳效果。
-
Top-1 Error:假设模型预测某个对象的类别,模型输出1个预测结果,那么这一个结果能判断正确的概率就是Top-1正确率。判断错误的概率就是Top-1错误率。简言之就是模型判错的概率。
Top-5 Error :假设模型预测某个对象的类别,模型输出5个预测结果,只要其中一个能判断正确类别,这个概率就是Top-5正确率,反之,预测输出的五个结果都错误的概率就是Top-5错误率。
一般来说,Top-1 Error和Top-5 Error越低,模型的性能也就越好。且Top-5 Error 往往小于Top-1 Error。
-
残差网络中的”残差“并非数理统计中的”观察值与预测值的差值“,而是”(部分)网络的输入特征(即低层特征)与理想的输出特征(即高层特征)之间的‘差值’“。
说明几点:
- 上面所说的”(部分)网络“可以理解为,在一般的卷积网络中,我们总是对低层的特征进行卷积从而得到高层特征,对于高层特征与低层特征的“差值”就是ResNet中所谓的“残差”。另外,这里所说的“差值”是一种抽象的概念,按照论文中的讲解,可以把“差值”理解为对应通道的每个像素之差。
- 论文作者认为“理想的高层特征由训练完成的残差与低层特征相加得到”,所以只需要对残差进行训练,而低层特征直接传递到高层与训练完成的残差进行相加即可。
-
训练残差函数相对于一般网络直接训练的特征函数的优势:在ResNet中残差的思想就是去掉相同的主体部分,从而突出微小的变化,让模型集中注意去学习一些这些微小的变化部分。
通过这篇博客理解一下残差:REF
-
identity mapping、shortcut connection、skip connection都是一个含义,理解为跨层连接。
1. 残差网络的数学原理
残差单元可以表示为:
y
l
=
h
(
x
l
)
+
F
(
x
l
,
W
l
)
x
l
+
1
=
f
(
y
l
)
y_l=h(x_l)+F(x_l,W_l) \\ x_{l+1}=f(y_l)\\
yl=h(xl)+F(xl,Wl)xl+1=f(yl)
其中,
x
l
x_l
xl 和
x
l
+
1
x_{l+1}
xl+1 分别表示第
l
l
l 个残差单元的输入和输出,注意每个残差单元一般包含多层结构;
F
F
F 是残差函数,通过训练学习到的残差;
h
(
x
l
)
h(x_l)
h(xl) 表示跨层连接的方式,(假设输入/输出维度相同)可以选择恒等映射,此时
h
(
x
l
)
=
x
l
h(x_l)=x_l
h(xl)=xl,还可以选择投影映射,即对应论文中的公式Eqn.(2),那么
h
(
x
l
)
=
W
s
x
l
h(x_l)=W_sx_l
h(xl)=Wsxl;
f
f
f 是ReLU激活函数。
假设不考虑升维或者降维的情况,那么残差块可以表示为:(注意使用的是ReLU函数,故可以将两个式子合并)
x
l
+
1
=
x
l
+
F
(
x
l
,
W
l
)
x_{l+1}=x_l+F(x_l,W_l)
xl+1=xl+F(xl,Wl)
对于一个更深的层
L
L
L,其与
l
l
l 层的关系可以表示为:
x
L
=
(
(
x
l
+
F
(
x
l
,
W
l
)
)
+
F
(
x
l
+
1
,
W
l
+
1
)
+
.
.
.
)
+
F
(
x
L
−
1
,
W
L
−
1
)
=
x
l
+
∑
i
=
l
L
−
1
F
(
x
i
,
W
i
)
\left. \begin{array}{ll} x_L&=((x_l+F(x_l,W_l))+F(x_{l+1},W_{l+1})+...) + F(x_{L-1},W_{L-1})\\ &= x_l+\sum_{i=l}^{L-1}F(x_i,W_i)\\ \end{array} \right.
xL=((xl+F(xl,Wl))+F(xl+1,Wl+1)+...)+F(xL−1,WL−1)=xl+∑i=lL−1F(xi,Wi)
从反向传播的角度来看,假设损失函数为
l
o
s
s
loss
loss,则:
∂
l
o
s
s
∂
x
l
=
∂
l
o
s
s
∂
x
L
∂
x
L
∂
x
l
=
∂
l
o
s
s
∂
x
L
(
1
+
∂
∂
x
L
∑
i
=
l
L
−
1
F
(
x
i
,
W
i
)
)
\left. \begin{array}{ll} \frac{\partial loss}{\partial x_l}&=\frac{\partial loss}{\partial x_L}\frac{\partial x_L}{\partial x_l}\\ &=\frac{\partial loss}{\partial x_L}(1+\frac{\partial}{\partial x_L}\sum_{i=l}^{L-1}F(x_i,W_i)) \\ \end{array} \right.
∂xl∂loss=∂xL∂loss∂xl∂xL=∂xL∂loss(1+∂xL∂∑i=lL−1F(xi,Wi))
式子的第一个因子
∂
l
o
s
s
∂
x
L
\frac{\partial loss}{\partial x_L}
∂xL∂loss 表示的损失函数到达
L
L
L 层的梯度,小括号中的
1
1
1 表明短路机制可以无损地传播梯度,而另外一项残差梯度则需要经过带有
w
e
i
g
h
t
s
weights
weights 的层,梯度不是直接传递过来的。残差梯度不会那么巧全为
−
1
-1
−1,而且就算其比较小,有
1
1
1 的存在也不会导致梯度消失。所以残差学习会更容易。
2. 残差网络的优点
也即残差网络解决的问题:相比于普通深度神经网络,随着网络深度的增加,残差网络容易优化,且不会出现比加深网络前更高的训练误差。因此残差网络可以设计地非常深。
并非可以无限加深网络。经论文作者测试,当网络很深时,虽然训练集和验证集正确率不会降低,但是测试集的正确率会出现降低,猜测是出现了过拟合。
梯度消失/爆炸已经可以通过BN和网络初始化等方法结果;退化问题通过ResNet解决。
3. 1 × 1 1×1 1×1 卷积的意义
其实 1 × 1 1×1 1×1 卷积可以是看成经过一个线性方程组对各个channel的加权运算,把每个channel的信息融合了
对于图像卷积而言,一个 1 × 1 1×1 1×1 卷积核并非只包含一个参数,其参数量等于通道数。经过一个卷积核的卷积操作将得到一幅特征图(一个通道),所以规定有多少个卷积核就会得到多少幅特征图(通道数)。 1 × 1 1×1 1×1 卷积通常用于升维和降维,图像卷积中的维度表示的是通道数。
4. 两种跨层连接(identity mapping)处理维度不匹配的方式
残差块的输入特征维度与输出特征维度不同时无法直接进行通道加法,所以论文作者提出了下面的两种方式:
option A:添加全零的特征图以扩充深度,也可以视为添加全零padding,只不过这里的padding的维度是深度这一维度。
option B:采用投影映射的方式,即 y = F ( x , { W i } ) + W s x y=\mathcal{F}(x,\{W_i\})+W_sx y=F(x,{Wi})+Wsx,简而言之就是通过 W s W_s Ws 对输入特征进行 1 × 1 1×1 1×1 卷积以升维。
5. ResNet中跨层连接(identity mapping)的设计
论文作者采用了输入输出维度不同使用投影映射(option B),维度匹配使用直接传递的方式,该方法性价比最高。
另外的两种方式:
- 维度不同使用全零padding(option A),维度匹配使用直接传递的方式,该方式效果不如上面的方式好;
- 不考虑维度是否匹配,所有的跨层连接均采用投影映射(option B),该方式效果与上面的方式差不多,但是参数个数要比上面多。
6. b o t t l e n e c k b l o c k bottleneck\space\space block bottleneck block 残差块
6.1. 在残差网络中的作用
下图是ResNet50的网络框架, b o t t l e n e c k b l o c k bottleneck\space\space block bottleneck block 主要用在深层ResNet网络框架的每个大模块(虚线框内)中,多个 b o t t l e n e c k b l o c k bottleneck\space\space block bottleneck block 组成了一个大模块。通过下图可以看出,因为输入通道数和输出通道数不同,每个大模块的第一个残差块都会进行升维卷积(即跨层连接对于维度变化的情况采用了论文中的optionB);而其他残差块,由于输入通道数与输出通道数相同,所以采用直接将底层特征传递给高层的方式进行跨层连接(即论文中的optionA)。 b o t t l e n e c k b l o c k bottleneck\space\space block bottleneck block 中的第一个 1 × 1 1×1 1×1 卷积层是进行降维操作,第二个 1 × 1 1×1 1×1 卷积层,也即最后块内最后一个,是进行升维操作。
6.2. 需要更少的参数
当维度比较高的时候,采用 b o t t l e n e c k b l o c k bottleneck block bottleneckblock 比采用 b a s i c b l o c k basic block basicblock 要训练更少的参数。
情况1(
b
l
o
c
k
block
block 的输入维度和输出维度相同,假设均为
256
256
256,即跨层连接为直连):
采用
b
o
t
t
l
e
n
e
c
k
b
l
o
c
k
bottleneck block
bottleneckblock 的参数个数:
1
×
1
×
256
×
64
+
3
×
3
×
64
×
64
+
1
×
1
×
64
×
256
=
69
,
632
1×1×256×64 + 3×3×64×64 + 1×1×64×256 = 69,632
1×1×256×64+3×3×64×64+1×1×64×256=69,632(注意不要忘记图像卷积的卷积核是三维的,前两维为尺寸,最后一维为通道数,与被卷积的图像通道数相同)
采用
b
a
s
i
c
b
l
o
c
k
basic block
basicblock 的参数个数:
相当于两个卷积层,每一层有
256
256
256 个
3
×
3
×
256
3×3×256
3×3×256 的卷积核,故
3
×
3
×
256
×
256
×
2
=
1
,
179
,
648
3×3×256×256×2 = 1,179,648
3×3×256×256×2=1,179,648,差了
16.94
16.94
16.94 倍。
情况2(
b
l
o
c
k
block
block 的输入维度和输出维度不同,假设输入为
256
256
256,输出为
512
512
512,即跨层连接为映射,
1
×
1
1×1
1×1 的卷积操作降维至
128
128
128):
采用
b
o
t
t
l
e
n
e
c
k
b
l
o
c
k
bottleneck block
bottleneckblock 的参数个数:
1
×
1
×
256
×
128
+
3
×
3
×
128
×
128
+
1
×
1
×
128
×
512
+
1
×
1
×
256
×
512
=
376
,
832
1×1×256×128 + 3×3×128×128 + 1×1×128×512 + 1×1×256×512 = 376,832
1×1×256×128+3×3×128×128+1×1×128×512+1×1×256×512=376,832
其中最后一个加法项表示的是跨层连接涉及的参数个数。
采用
b
a
s
i
c
b
l
o
c
k
basic block
basicblock 的参数个数:
3
×
3
×
256
×
512
+
3
×
3
×
512
×
512
+
1
×
1
×
256
×
512
=
3
,
670
,
016
3×3×256×512+ 3×3×512×512+ 1×1×256×512= 3,670,016
3×3×256×512+3×3×512×512+1×1×256×512=3,670,016,差了
9.73
9.73
9.73 倍。
其中最后一个加法项表示的是跨层连接涉及的参数个数。
可见,无论残差块输入输出是否发生维度的变化, b o t t l e n e c k b l o c k bottleneck block bottleneckblock 的参数量都比 b a s i c b l o c k basic block basicblock 的参数量少;而且如果输入输出的维度越大, b o t t l e n e c k b l o c k bottleneck block bottleneckblock 的效果越明显(两种残差块涉及参数个数的差值)。因此, b o t t l e n e c k b l o c k bottleneck block bottleneckblock 对于降低开销非常关键。
情况2( b l o c k block block 的输入维度和输出维度不同,假设输入为 64 64 64,输出为 256 256 256,即跨层连接为映射, 1 × 1 1×1 1×1 的卷积操作):
采用 b o t t l e n e c k b l o c k bottleneck block bottleneckblock 的参数个数: 1 × 1 × 64 × 64 + 3 × 3 × 64 × 64 + 1 × 1 × 64 × 256 + 1 × 1 × 64 × 256 = 73 , 728 1×1×64×64 + 3×3×64×64 + 1×1×64×256 + 1×1×64×256 = 73,728 1×1×64×64+3×3×64×64+1×1×64×256+1×1×64×256=73,728
其中最后一个加法项表示的是跨层连接涉及的参数个数。
采用 b a s i c b l o c k basic block basicblock 的参数个数:
3 × 3 × 64 × 256 + 3 × 3 × 256 × 256 + 1 × 1 × 64 × 256 = 753 , 664 3×3×64×256 + 3×3×256×256 + 1×1×64×256 = 753,664 3×3×64×256+3×3×256×256+1×1×64×256=753,664
其中最后一个加法项表示的是跨层连接涉及的参数个数。对于情况2,我举的这个例子不是很合理,因为输入为 64 64 64 输出为 256 256 256,我们用 1 × 1 1×1 1×1 卷积降维,实际上还是化为了 64 64 64 维,所以相当于没降维,参数完全多余了。尽管如此,采用 b o t t l e n e c k b l o c k bottleneck block bottleneckblock 使用的参数量仍然小于采用 b a s i c b l o c k basic block basicblock,可见, b o t t l e n e c k b l o c k bottleneck block bottleneckblock 对于降低开销非常关键。