看darkent的网络框架的小伙伴们,有没有发现其与caffe,pytorch的不同,有没有发现里面没有计算loss的代码,嗯嗯嗯????,forward函数一直在计算l.delta,backward函数也是和l.delta有关系的,看l.delta的计算方式,怎么看都不像是loss的公式,那么,l.delta究竟是什么,搞明白这个问题需要了解反向传播的原理,由于pytorch已经将反向传播完全自动化,即使你将反向传播当作一个黑匣子来看,也不影响你在工作中对网络的训练和测试,可是只知其然不知其所以然的感觉还是很难受的,这种理论的缺失,会在理解某些论文,以及后面的前进的道路上限制我们的发展,俗话说,积累的东西,总是在不经意间发挥作用,厚积薄发么。
一、反向传播
内容来自《Neural Networks and Deep Learning》,不懂的请自行阅读该书籍。
反向传播的核心是立即损失函数
C
C
C针对权重
w
w
w或者偏置
b
b
b的偏导数
∂
C
∂
w
\frac{\partial C}{\partial w}
∂w∂C,这个偏导数告诉我们,当改变权重
w
w
w时,这种改变是如何快速的影响损失函数。每层的卷积层都自己的权重
w
w
w,并且该层的权重
w
w
w由是多维元素组成的,如何取求每个权重元素关于
C
C
C的偏导数呢。
首先我们要定义一些符号,帮助我们更好的使用公式推倒反向传播,
w
j
k
l
w^l_{jk}
wjkl表示将第
l
-
1
l-1
l-1层的第
k
k
k个神经元与第
l
l
l层的第
j
j
j个神经元相连接的权重,例如下图:
同样的道理,偏值
b
j
l
b^l_j
bjl表示第
l
l
l层的第
j
j
j个神经元,使用
a
j
l
a^l_j
ajl表示第
l
l
l层的第
j
j
j个激活值,示意图如下:
那么某个激活函数值计算方式:
z
j
l
=
∑
k
w
j
k
l
a
k
l
−
1
+
b
j
l
z^l_j = \sum_k w^l_{jk}a^{l-1}_k + b^l_j
zjl=k∑wjklakl−1+bjl
a
j
l
=
σ
(
z
j
l
)
a^l_j = \sigma(z^l_j)
ajl=σ(zjl)
其实,反向传播计算的就是
∂
C
∂
w
j
k
l
\frac{\partial C}{\partial w^l_{jk}}
∂wjkl∂C 和
∂
C
∂
b
j
l
\frac{\partial C}{\partial b^l_{j}}
∂bjl∂C,但是这个公式很复杂,因此引入了中间变量delta
δ
j
l
\delta^l_j
δjl,可以看作是第
l
l
l层的第
j
j
j个神经元的错误,反向传播将先计算
δ
j
l
\delta^l_j
δjl,然后
∂
C
∂
w
j
k
l
\frac{\partial C}{\partial w^l_{jk}}
∂wjkl∂C 和
∂
C
∂
b
j
l
\frac{\partial C}{\partial b^l_{j}}
∂bjl∂C都是和
δ
j
l
\delta^l_j
δjl相关,我们定义下面:
δ
j
l
=
∂
C
∂
z
j
l
\delta^l_j = \frac{\partial C}{\partial z^l_{j}}
δjl=∂zjl∂C
接下来,我们将利用求导的链式法则,来探索
δ
j
l
\delta^l_j
δjl与
∂
C
∂
w
j
k
l
\frac{\partial C}{\partial w^l_{jk}}
∂wjkl∂C 和
∂
C
∂
b
j
l
\frac{\partial C}{\partial b^l_{j}}
∂bjl∂C的关系:
公式一:
δ
j
l
=
∂
C
∂
z
j
l
=
∑
k
∂
C
∂
a
k
l
∂
a
k
l
∂
z
j
l
,
其
中
由
a
j
l
=
σ
(
z
j
l
)
可
知
z
j
l
只
与
a
j
l
有
关
系
=
∂
C
∂
a
j
l
∂
a
j
l
∂
z
j
l
=
∂
C
∂
a
j
l
σ
′
(
z
j
l
)
(
1
)
\begin{aligned} \delta^l_j &= \frac{\partial C}{\partial z^l_{j}} \\ &=\sum_k \frac{\partial C}{\partial a^l_{k}} \frac{\partial a^l_{k}}{\partial z^l_{j}}, 其中由a^l_j = \sigma(z^l_j)可知z^l_{j}只与a^l_{j}有关系 \\ &=\frac{\partial C}{\partial a^l_{j}} \frac{\partial a^l_{j}}{\partial z^l_{j}} \\ &= \frac{\partial C}{\partial a^l_{j}} \sigma'( z^l_{j}) (1) \end{aligned}
δjl=∂zjl∂C=k∑∂akl∂C∂zjl∂akl, 其中由ajl=σ(zjl)可知zjl只与ajl有关系 =∂ajl∂C∂zjl∂ajl=∂ajl∂Cσ′(zjl) (1)
公式二:
注:其中l+1层是l层的线性组合,因此,l+1层的每个输入都与
z
j
l
z^l_{j}
zjl有关系
δ
j
l
=
∂
C
∂
z
j
l
=
∑
k
∂
C
∂
z
k
l
+
1
∂
z
k
l
+
1
∂
z
j
l
\begin{aligned} \delta^l_j &= \frac{\partial C}{\partial z^l_{j}} \\ &=\sum_k \frac{\partial C}{\partial z^{l+1}_{k}} \frac{\partial z^{l+1}_{k}}{\partial z^l_{j}}\\ \end{aligned}
δjl=∂zjl∂C=k∑∂zkl+1∂C∂zjl∂zkl+1
由于
z
k
l
+
1
=
∑
m
w
k
m
l
a
m
l
+
b
k
l
=
∑
m
w
k
m
l
σ
(
z
m
l
)
+
b
k
l
z^{l+1}_{k} = \sum_m w^l_{km}a^{l}_m + b^l_k=\sum_m w^l_{km}\sigma(z^{l}_m )+ b^l_k
zkl+1=∑mwkmlaml+bkl=∑mwkmlσ(zml)+bkl,因此在
z
k
l
+
1
z^{l+1}_{k}
zkl+1的组成部分中(l层神经元输出的线性组合),只有当m=j的那个部分是和
z
j
l
z^{l}_{j}
zjl有关系的,因此下面的公式可以变为:
δ
j
l
=
∑
k
δ
k
l
+
1
w
k
j
σ
′
(
z
j
l
)
(
2
)
\begin{aligned} \delta^l_j &= \sum_k\delta^{l+1}_kw_{kj}\sigma'(z^l_{j}) (2) \end{aligned}
δjl=k∑δkl+1wkjσ′(zjl) (2)
公式三:
由
z
j
l
=
∑
k
w
j
k
l
a
k
l
−
1
+
b
j
l
z^l_j =\sum_k w^l_{jk}a^{l-1}_k + b^l_j
zjl=∑kwjklakl−1+bjl可知:
∂
C
∂
b
j
l
=
∑
k
∂
C
∂
z
k
l
∂
z
k
l
∂
b
j
l
,
其
中
b
j
l
只
与
z
j
l
有
关
系
=
∂
C
∂
z
j
l
∂
z
j
l
∂
b
j
l
,
=
δ
j
l
(
3
)
\begin{aligned} \frac{\partial C}{\partial b^l_{j}} &= \sum_k\frac{\partial C}{\partial z^l_{k}} \frac{\partial z^l_{k}}{\partial b^l_{j}} , 其中 b^l_{j}只与z^l_{j}有关系 \\ &= \frac{\partial C}{\partial z^l_{j}} \frac{\partial z^l_{j}}{\partial b^l_{j}},\\ &=\delta^l_j (3) \end{aligned}
∂bjl∂C=k∑∂zkl∂C∂bjl∂zkl,其中 bjl只与zjl有关系 =∂zjl∂C∂bjl∂zjl,=δjl (3)
公式四:
由
z
j
l
=
∑
k
w
j
k
l
a
k
l
−
1
+
b
j
l
z^l_j =\sum_k w^l_{jk}a^{l-1}_k + b^l_j
zjl=∑kwjklakl−1+bjl可知:
∂
C
∂
w
j
k
l
=
∂
C
∂
z
j
l
∂
z
j
l
∂
w
j
k
l
=
δ
j
l
∂
z
j
l
∂
w
j
k
l
=
δ
j
l
a
k
l
−
1
(
4
)
\begin{aligned} \frac{\partial C}{\partial w^l_{jk}}&=\frac{\partial C}{\partial z^l_{j}} \frac{\partial z^l_{j}}{\partial w^l_{jk}} \\ &=\delta^l_j \frac{\partial z^l_{j}}{\partial w^l_{jk}} \\ &=\delta^l_j a^{l-1}_k (4) \end{aligned}
∂wjkl∂C=∂zjl∂C∂wjkl∂zjl=δjl∂wjkl∂zjl=δjlakl−1 (4)
二、yolo_layer.c中objectness位置的l.delta的推倒
对于objectness_score位置的预测,作者采用的是logistic regression(逻辑回归),正样本向1逼近,负样本向0逼近,逻辑回归层的图如下:
逻辑回归的损失函数C为:
C
=
−
y
l
o
g
(
a
)
−
(
1
−
y
)
l
o
g
(
1
−
a
)
,
其
中
a
=
1
1
+
e
−
z
C = -ylog(a) -(1-y)log(1-a), \qquad其中a = \frac{1}{1+e^{-z}}
C=−ylog(a)−(1−y)log(1−a),其中a=1+e−z1
下面是C关于z的导数计算公式,其中:
1
−
a
=
e
−
z
(
1
+
e
z
)
a
n
d
∂
a
∂
z
=
−
e
−
z
(
1
+
e
z
)
2
=
−
a
(
1
−
a
)
1-a = \frac{e^{-z}}{(1+e^z)} \quad and \quad \frac{\partial a}{\partial z} =- \frac{e^{-z}}{(1+e^z)^2}= -a(1-a)
1−a=(1+ez)e−zand∂z∂a=−(1+ez)2e−z=−a(1−a)
∂
C
∂
z
=
−
y
a
∂
a
∂
z
+
1
−
y
1
−
a
∂
a
∂
z
=
−
y
a
a
(
a
−
1
)
+
1
−
y
1
−
a
a
(
a
−
1
)
=
y
(
1
−
a
)
−
(
1
−
y
)
a
=
y
−
y
a
−
a
+
y
a
=
y
−
a
\begin{aligned} \frac{\partial C}{\partial z} &= -\frac{y}{a} \frac{\partial a}{\partial z} + \frac{1-y}{1-a}\frac{\partial a}{\partial z} \\ &=-\frac{y}{a} a(a-1) + \frac{1-y}{1-a}a (a-1) \\ &= y(1-a) - (1-y)a \\ &= y -ya - a + ya\\ &= y - a \end{aligned}
∂z∂C=−ay∂z∂a+1−a1−y∂z∂a=−aya(a−1)+1−a1−ya(a−1)= y(1−a)−(1−y)a= y−ya−a+ya= y−a
∂
C
∂
z
=
1
−
a
,
当
l
a
b
e
l
=
1
时
\frac{\partial C}{\partial z} = 1 - a , 当label = 1时
∂z∂C=1−a,当label=1时
∂
C
∂
z
=
0
−
a
,
当
l
a
b
e
l
=
0
时
\frac{\partial C}{\partial z} = 0 - a , 当label = 0时
∂z∂C=0−a,当label=0时
在yolo_layer.c的代码中我们发现:
l.delta[objectness] = 1 - pred_objectness_score, anchor框为正样本
l.delta[objectness] = 0 - pred_objectness_score, anchor框为负样本
l.delta[objectness] = 0 , anchor框不参与训练
yolo_layer.c是最后一层,先求出该层的 δ \delta δ,根据公式(2),计算出下一层的 δ \delta δ,然后再去计算该层权重和偏值的偏导数,你取看darknet的backward函数,会发现,即使根据这些公式来的,具体的请自己将代码与公式结合进行理解。