可变形卷积
普通卷积
一般的卷积计算,即通过定义一个滑动窗口(又叫卷积核或滤波器),按照给定规则在图像中滑动,每滑动到一个位置,就让该位置的像素值与卷积核上的对应位置进行加权和计算,这一过程可以由如下公式概括:
y
(
p
0
)
=
∑
p
n
∈
R
w
(
p
n
)
⋅
x
(
p
0
+
p
n
)
\mathbf{y}(\mathbf{p}_0)=\sum_{\mathbf{p}_n\in\mathcal{R}}\mathbf{w}(\mathbf{p}_n)\cdot\mathbf{x}(\mathbf{p}_0 + \mathbf{p}_n)
y(p0)=pn∈R∑w(pn)⋅x(p0+pn)
p
0
p_0
p0是窗口中心点位置;
p
n
p_n
pn表示窗口中的其他像素点与中心像素点的相对位置;
R
\mathcal{R}
R 是一个存储了所有相对位置坐标矩阵,如下图所示:
x \mathrm{x} x 是输入的特征图; x ( p 0 + p n ) \mathrm{x}(p_0+p_n) x(p0+pn) 相当于取出位于图像 p 0 + p n p_0+pn p0+pn 处的像素值; w ( p n ) \mathrm{w}(p_n) w(pn) 表示对应卷积核上的权值。以后通过一个求和符号,将每个点上的采样结果进行求和,得到输出特征图 y ( p 0 ) \mathrm{y}(p_0) y(p0)。
DCNv1
其实就是在普通卷积公式的基础上,加上一个偏移量 Δ p n \Delta p_n Δpn:
y
(
p
0
)
=
∑
p
n
∈
R
w
(
p
n
)
⋅
x
(
p
0
+
p
n
+
Δ
p
n
)
\mathbf{y}(\mathbf{p}_0)=\sum_{\mathbf{p}_n\in\mathcal{R}}\mathbf{w}(\mathbf{p}_n)\cdot\mathbf{x}(\mathbf{p}_0+\mathbf{p}_n+\Delta\mathbf{p}_n)
y(p0)=pn∈R∑w(pn)⋅x(p0+pn+Δpn)
这个偏移量是通过学习得到的,具体学习流程下面会涉及。让我们先来理解一下可变形卷积的原理。
可变形卷积,顾名思义就是卷积的位置是可变形的。传统的
N
×
N
N \times N
N×N 的网格上做卷积,仅仅只能提取到矩形框的特征,束缚了网络感受野的形状,限制了网络对几何形变的适应能力。为了克服这个缺陷, 可变形卷积在卷积核的每一个采样点上添加一个可学习的偏移量,让采样点不再局限于规则的网格点,效果如下如所示:
如上图所示,显然提高了网络对不规则形变的适应能力。
添加偏移量后的卷积操作示意图(绿色点表示原来的采样点,蓝色点表示施加偏移量后的采样点):
那么可变形卷积的偏移量是怎么学习到的呢?
具体来说,可变形卷积引入了一个平行分支,经过一个卷积层(下图中的conv)来端到端地学习出一个偏移量场,上面存储着卷积核采样点的位置偏移量,如下图所示:
这个偏移量场的通道数由下列公式计算得出:
o
u
t
c
h
a
n
n
e
l
=
2
∗
k
e
r
n
e
l
_
s
i
z
e
∗
k
e
r
n
e
l
_
s
i
z
e
\mathrm{out~channel=2*kernel\_size*kernel\_size}
out channel=2∗kernel_size∗kernel_size
其中,
k
e
r
n
e
l
_
s
i
z
e
∗
k
e
r
n
e
l
_
s
i
z
e
\mathrm{kernel\_size*kernel\_size}
kernel_size∗kernel_size 对应卷积核上的每一格采样点,前面乘上一个
2
2
2 是因为每一个格子会进行
x
x
x 和
y
y
y 两个方向的偏移,可以这么理解:比如
3
×
3
3\times 3
3×3 卷积,那么会生成
3
×
3
×
2
=
18
3\times 3 \times 2= 18
3×3×2=18 个特征图(通道),其中的每个特征图就对应着一个偏移动作。
接下来,将平行分支学习得到的偏移量场,施加在原输入特征图上,得到最新的采样点位置,接着进行正常的卷积运算即可,整个流程大致就是这样。
注意,因为施加偏移量后的新采样点坐标往往是浮点类型,而输入特征图的像素值是定义在整数位置上的,因此采样点处的像素值不好去估计,所以用双线性插值来获得新采样点处的近似像素值。
双线性插值是一种基于周围整数点的加权平均方法,根据周围整数位置的像素值来计算出采样点在非整数位置的近似像素值,从而使得可变形卷积能够在这些偏移后的位置上进行有效的采样。双线性插值操作公式如下:
x
(
p
)
=
∑
q
G
(
q
,
p
)
⋅
x
(
q
)
x(p)=\sum_qG(q,p)\cdot \mathrm{x}(q)
x(p)=q∑G(q,p)⋅x(q)
其中双线性插值核公式如下:
G
(
q
,
p
)
=
g
(
q
x
,
p
x
)
⋅
g
(
q
y
,
p
y
)
=
max
(
0
,
1
−
∣
q
x
−
p
x
∣
)
⋅
max
(
0
,
1
−
∣
q
y
−
p
y
∣
)
G(\boldsymbol{q},\boldsymbol{p})\\=g(q_x,p_x)\cdot g(q_y,p_y)\\=\max(0,1-\mid q_x-p_x\mid)\cdot\max(0,1-\mid q_y-p_y\mid)
G(q,p)=g(qx,px)⋅g(qy,py)=max(0,1−∣qx−px∣)⋅max(0,1−∣qy−py∣)
经过插值之后,就可以将获得的新值进行正常卷积操作了,整体流程如下:
可变形卷积可以端到端地学习几何形变的偏移量,不需要额外的监督信息,并且只增加了少许计算量,最终却能带来效果的显著提升,因此成为深度学习中一种很实用的trick。
【补充:空洞卷积也可以看成一种特殊的可变形卷积】