1.Yolov4整体网络架构
网络整体由三部分组成backbone、neck、head部分,注意蓝色卷积是属于head部分(但在网络实现时往往和neck一起定义,简便起见)。
1.1backbone模块
backbone部分包含CBM、CSP两个子模块。CBM表示Conv+Normalization+Mish结构,CSP表示CBM+ResUnit+concat组成,输入(608,608,3),输出(76,76,256)、(38,38,512)、(19,19,1024),具体如下:
1.1.1CBM子模块
CBM是backbone中的基础模块,由基本的单层卷积层conv、单层BatchNormalization和一个Mish激活函数层组成。Mish激活函数公式如下:
f
(
x
)
=
x
tanh
?
(
log
?
(
1
+
e
x
)
)
(1)
\bm{f(x)=x\tanh(\log(1+e^{x}))\tag{1}}
f(x)=xtanh(log(1+ex))(1)
注意: pytorch并未实现Mish激活函数的API调用,因此需要自己定义使用,代码如下:
class Mish(nn.Module):
def __init__(self):
super(Mish, self).__init__()
def forward(self, x):
return x * torch.tanh(F.softplus(x))
1.1.2CSPX子模块
注意:CSPX其中的X表示下分路两个CBM中间残差单元(Res unit)的个数 in : 表示上一个网络子模块的输出,该输出走向两个分路:
- 下分路为CBM、Res unit、CBM
- 上分路为一个CBM子模块
- 上下分路输出进行concat
concat: 上下分路采用concat堆叠到一起,例如上路输出
(
152
,
152
,
282
)
(152,152,282)
(152,152,282)、下路输出
(
152
,
152
,
318
)
(152,152,318)
(152,152,318),concat后变为
(
152
,
152
,
600
)
(152,152,600)
(152,152,600)。 CBM: 同上1.1.1 Res unit: Res unit由两个CBL组成的上分路和作为下分路的原输入进行add操作,例如上路输出
(
152
,
152
,
282
)
(152,152,282)
(152,152,282)、下路输出
(
152
,
152
,
318
)
(152,152,318)
(152,152,318),各通道对应位置元素直接相加(add),维度还是
(
152
,
152
,
318
)
(152,152,318)
(152,152,318)。 CBL:由基本的单层卷积层conv、单层BatchNormalization和一个Leakyrelu激活函数层组成。Leakyrelu激活函数公式如下:
f
(
x
)
=
{
z
,
i
f
(
z
>
0
)
a
z
,
i
f
(
z
≦
0
)
(2)
\bm{f(x)=\left\{\begin{aligned}&z, &if(z>0)\\ &az, &if(z\leqq0)\end{aligned}\right.\tag{2}}
f(x)={?z,az,?if(z>0)if(z≦0)?(2)
1.2neck模块
neck部分包含CBL、SPP以及上采样三个子模块。CBL表示Conv+BatchNormalization+LeakyRelu结构 SPP表示一个特征图经过3个最大池化+一个直连,最后通过拼接得到输出。 上采样层输入(608,608,3),输出(76,76,256)、(38,38,512)、(19,19,1024),具体如下:
1.2.1CBL层
CBL是由基本的单层卷积层conv、单层BatchNormalization和一个Leakyrelu激活函数层组成。Leakyrelu激活函数公式如下:
f
(
x
)
=
{
z
,
i
f
(
z
>
0
)
a
z
,
i
f
(
z
≦
0
)
(2)
\bm{f(x)=\left\{\begin{aligned}&z, &if(z>0)\\ &az, &if(z\leqq0)\end{aligned}\right.\tag{2}}
f(x)={?z,az,?if(z>0)if(z≦0)?(2)
1.2.2SPP层
SPP对输入分别进行三个maxpooling,并保持特征图维度不变,将其结果同输入(直连)共同拼接在一起(concat),如下图所示: concat的输入均为(19,19,512),输出变成一张(19,19,2048)的特征图。
1.2.3上采样层
上采样(upsample)仅扩大特征图大小(YOLOV4中上采样为原来的2倍),不改变通道数,如下:
1.3head模块
head包含yolo模型最后一层的conv层,以及yolo-decode(模型输出进行解码操作)。 yolo-head包括两个头部,大小分别为
(
76
,
76
)
(76,76)
(76,76)、
(
38
,
38
)
(38,38)
(38,38)、
(
19
,
19
)
(19,19)
(19,19)。
1.3.1conv层
conv层用于将结果压缩到相应输出维度,对应维度为:
(
76
,
76
,
3
?
(
4
+
1
+
c
l
a
s
s
)
)
(76,76,3*(4+1+class))
(76,76,3?(4+1+class))、
(
38
,
38
,
3
?
(
4
+
1
+
c
l
a
s
s
)
)
(38,38,3*(4+1+class))
(38,38,3?(4+1+class))、
(
19
,
19
,
3
?
(
4
+
1
+
c
l
a
s
s
)
)
(19,19,3*(4+1+class))
(19,19,3?(4+1+class))
- class表示需要的分类维度,比如检测行人和车辆class可以设置为2用来输出anchor属于两个类别的概率
- 3表示每个网格上设置三个候选框(anchor1、anchor2、anchor3)
- 4是预测框中心点和宽高的位置信息(tx,ty,tw,th)
- 1表示属于物体的概率(conf)
注意:后续讲解均以(19,19)的yolo-head举例说明,其他维度的decode均类似 对conv层的输出进行reshape后就变成
(
3
,
19
,
19
,
4
+
1
+
c
l
a
s
s
)
(3,19,19,4+1+class)
(3,19,19,4+1+class)
1.3.2yolo-decode
tx、ty经过sigmoid后分别表示对应网格上的相对值,相对该网格边界的位置,例如:
σ
(
t
x
)
\bm{\sigma(t_x)}
σ(tx?)即为tx经过sigmoid函数后的结果,假设为0.3,则表示该预测框(模型预测的物体检测框)的中心点位于19*19特征图中某个网格(假设为第四行、第五列)中的相对位置,该网格左边界上为0,右边界上为1 同理
σ
(
t
y
)
\bm{\sigma(t_y)}
σ(ty?)。 tw、th表示对于预设anchor的缩放比例,比如预设anchor为[142.0,65.0],tw、th经过
e
t
w
e^{tw}
etw、
e
t
h
e^{th}
eth函数后表示预测框为预设框的缩放比例,比如1.3表示预测框宽度为:
i
n
t
(
142.0
?
1.3
)
=
i
n
t
(
184.6
)
=
184
int(142.0*1.3)=int(184.6)=184
int(142.0?1.3)=int(184.6)=184 同理
t
h
\bm{th}
th。 tx、ty:
t
x
,
t
y
=
o
u
t
p
u
t
[
…
,
0
]
,
o
u
t
p
u
t
[
…
,
1
]
(3)
tx,ty=output[…,0],output[…,1]\tag{3}
tx,ty=output[…,0],output[…,1](3)
g
r
i
d
_
x
=
[
1
2
?
19
?
?
1
2
?
19
]
(4)
grid\_x=\begin{bmatrix} 1&2&\cdots&19\\ &\cdots&\cdots\\ 1&2&\cdots&19\\ \end{bmatrix}\tag{4}
grid_x=???11?2?2?????1919????(4)
g
r
i
d
_
y
=
[
0
0
?
0
?
?
19
19
?
19
]
(5)
grid\_y=\begin{bmatrix} 0&0&\cdots&0\\ &\cdots&\cdots\\ 19&19&\cdots&19\\ \end{bmatrix}\tag{5}
grid_y=???019?0?19?????019????(5)
b
x
=
s
i
g
m
o
i
d
(
t
x
)
,
b
y
=
s
i
g
m
o
i
d
(
t
y
)
(6)
bx=sigmoid(tx),by=sigmoid(ty)\tag{6}
bx=sigmoid(tx),by=sigmoid(ty)(6)
b
x
+
=
g
r
i
d
_
x
,
b
y
+
=
g
r
i
d
_
y
(7)
bx+=grid\_x,by+=grid\_y\tag{7}
bx+=grid_x,by+=grid_y(7)
b
x
=
b
x
/
W
,
b
y
=
b
y
/
W
(8)
bx=bx/W,by=by/W\tag{8}
bx=bx/W,by=by/W(8) 此时的bx、by表示预测框中心点位于原图的相对位置,例如:原图(608,608),bx=0.3则表示该预测框的中心点的x坐标为:
i
n
t
(
608
?
0.3
)
=
i
n
t
(
182.4
)
=
182
(9)
int(608*0.3)=int(182.4)=182\tag{9}
int(608?0.3)=int(182.4)=182(9) tw、th: 这里tw的计算主要在于将tw经过
e
t
w
e^{tw}
etw后表示对于预设anhor的宽的缩放,乘anchor大小表示预测框在原图上的宽,再除以608,表示相对大小,例如:预测框大小为上面计算的182,则相对大小为182/608=0.2993,从而将tw得到的bw统一到tx、ty一个标准大小之中。 同理th。 只不过是后面计算的这些公式比较繁琐
b
w
=
s
c
a
l
e
_
x
_
y
?
e
t
w
?
0.5
?
(
s
c
a
l
e
_
x
_
y
?
1
)
(10)
bw=scale\_x\_y*e^{tw}-0.5*(scale\_x\_y-1)\tag{10}
bw=scale_x_y?etw?0.5?(scale_x_y?1)(10)
b
h
=
s
c
a
l
e
_
x
_
y
?
e
t
h
?
0.5
?
(
s
c
a
l
e
_
x
_
y
?
1
)
(11)
bh=scale\_x\_y*e^{th}-0.5*(scale\_x\_y-1)\tag{11}
bh=scale_x_y?eth?0.5?(scale_x_y?1)(11)
b
w
?
=
a
n
c
h
o
r
/
32
,
b
h
?
=
a
n
c
h
o
r
/
32
(12)
bw*=anchor/32,bh*=anchor/32\tag{12}
bw?=anchor/32,bh?=anchor/32(12) 这里的32是608/19,即19的yolo_head对应的原图缩小的倍数。
b
w
/
=
19
,
b
h
/
=
19
(13)
bw/=19,bh/=19\tag{13}
bw/=19,bh/=19(13) 此时的bw、bh即为相对原图608的预测框的宽度和高度。 计算预测框左上和右下坐标位置:
b
x
1
=
b
x
?
b
w
/
2
(14)
bx1=bx-bw/2\tag{14}
bx1=bx?bw/2(14)
b
y
1
=
b
y
?
b
h
/
2
(15)
by1=by-bh/2\tag{15}
by1=by?bh/2(15)
b
x
2
=
b
x
+
b
w
/
2
(16)
bx2=bx+bw/2\tag{16}
bx2=bx+bw/2(16)
b
y
2
=
b
x
+
b
h
/
2
(17)
by2=bx+bh/2\tag{17}
by2=bx+bh/2(17)
b
x
1
=
b
x
1
?
608
(
w
)
(18)
bx1=bx1*608(w)\tag{18}
bx1=bx1?608(w)(18)
b
y
1
=
b
y
1
?
608
(
h
)
(19)
by1=by1*608(h)\tag{19}
by1=by1?608(h)(19)
b
x
2
=
b
x
1
?
608
(
w
)
(20)
bx2=bx1*608(w)\tag{20}
bx2=bx1?608(w)(20)
b
y
2
=
b
y
1
?
608
(
h
)
(21)
by2=by1*608(h)\tag{21}
by2=by1?608(h)(21) 此时的(bx1,by1),(bx2,by2)即为预测框在原图中的坐标位置,如果是做测试,则对该区域绘制预测框即为目标预测结果。
|