图中,蓝色圆形为求和单元,黄色方形为激活单元。假设网络为 L L L层,每层的神经元个数为 N ( l ) N(l) N(l)个。输入为 { x 1 , 0 , x 2 , 0 , . . . , x N ( 0 ) , 0 } \lbrace{x_{1,0},x_{2,0},...,x_{N(0),0}}\rbrace {x1,0,x2,0,...,xN(0),0} ,表示初始层的输入。第 l l l层第 n n n个神经元的输入为 { y 1 , l − 1 , y 2 , l − 1 , . . . , y N ( l − 1 ) , l − 1 } \lbrace{y_{1,l-1},y_{2,l-1},...,y_{N(l-1),l-1}}\rbrace {y1,l−1,y2,l−1,...,yN(l−1),l−1},对应的仿射变换的权重为 { w 1 , n , l − 1 , w 2 , n , l − 1 , . . . , w N ( l − 2 ) , n , l − 1 } \lbrace{w_{1,n,l-1},w_{2,n,l-1},...,w_{N(l-2),n,l-1}}\rbrace {w1,n,l−1,w2,n,l−1,...,wN(l−2),n,l−1},偏置为 b n , l − 1 b_{n,l-1} bn,l−1。经过放射变换后的到 z n , l z_{n,l} zn,l,再经过激活函数得到 y n , l y_{n,l} yn,l。第l层输出为 N l N_{l} Nl个。 在我们前面一篇文章《YOLO中LOSS函数的计算》中,我们对二分类交叉熵损失函数和平方差损失函数进行求导,证明两种损失函数具有一致性。这里为了方便计算假设LOSS函数为 L O S S = − 1 2 ∑ n = 1 N ( l ) , l = L ( y n , l ′ − y n , l ) 2 LOSS = -\frac{1}{2}\sum_{n=1}^{N(l),l=L}(y_{n,l}^{\prime}-y_{n,l})^{2} LOSS=−21n=1∑N(l),l=L(yn,l′−yn,l)2 其中, y n , l ′ y_{n,l}^{\prime} yn,l′表示真值,为了使推导更具有普遍性,这个LOSS函数并不特指回归还是分类。同时,为了方便后续YOLO源码分析,我们令 d e l t a = y n , l ′ − y n , l delta = y_{n,l}^{\prime}-y_{n,l} delta=yn,l′−yn,l,则LOSS函数如下 L O S S = − 1 2 ∑ n = 1 N ( l ) , l = L d e l t a n , l 2 LOSS = -\frac{1}{2}\sum_{n=1}^{N(l),l=L}delta_{n,l}^{2} LOSS=−21n=1∑N(l),l=Ldeltan,l2 接下来要做的事就是求导。我们前面说了,求导就是求针对输出的导数和求权重的导数,这两个求导交替进行。按照一般的思路,我们这里从头开始,最后归纳出普遍的求导公式。 首先,第 L L L层针对输出值 y n , L y_{n,L} yn,L的导数为 ∂ L O S S ∂ y n , l = − d e l t a n , l ∂ d e l t a n , l ∂ y n , l = d e l t a n , l \frac{\partial{LOSS}}{\partial{y_{n,l}}} = -delta_{n,l}\frac{\partial{delta_{n,l}}}{\partial{y_{n,l}}} = delta_{n,l} ∂yn,l∂LOSS=−deltan,l∂yn,l∂deltan,l=deltan,l 第 L L L层第 n n n个神经元,针对权重 w n ( L − 1 ) , n ( L ) , L w_{n(L-1),n(L),L} wn(L−1),n(L),L的导数为
∂ L O S S ∂ w n ( L − 1 ) , n ( L ) , L = ∂ L O S S ∂ y n ( L ) , L ∂ y n ( L ) , L ∂ z n ( L ) , L ∂ z n ( L ) , L ∂ w n ( L − 1 ) , n ( L ) , L = ∂ y n ( L ) , L ∂ z n ( L ) , L d e l t a n ( L ) , L y n ( L − 1 ) , L − 1 \frac{\partial{LOSS}}{\partial{w_{n(L-1),n(L),L}}} = \frac{\partial{LOSS}}{\partial{y_{n(L),L}}}\frac{\partial{y_{n(L),L}}}{\partial{z_{n(L),L}}}\frac{\partial{z_{n(L),L}}}{\partial{w_{n(L-1),n(L),L}}} = \frac{\partial{y_{n(L),L}}}{\partial{z_{n(L),L}}}delta_{n(L),L}y_{n(L-1),L-1} ∂wn(L−1),n(L),L∂LOSS=∂yn(L),L∂LOSS∂zn(L),L∂yn(L),L∂wn(L−1),n(L),L∂zn(L),L=∂zn(L),L∂yn(L),Ldeltan(L),Lyn(L−1),L−1
∂ L O S S ∂ b n ( L ) , L = ∂ L O S S ∂ y n ( L ) , L ∂ y n ( L ) , L ∂ z n ( L ) , L ∂ z n ( L ) , L ∂ b n ( L ) , L = ∂ y n ( L ) , L ∂ z n ( L ) , L d e l t a n ( L ) , L \frac{\partial{LOSS}}{\partial{b_{n(L),L}}} = \frac{\partial{LOSS}}{\partial{y_{n(L),L}}}\frac{\partial{y_{n(L),L}}}{\partial{z_{n(L),L}}}\frac{\partial{z_{n(L),L}}}{\partial{b_{n(L),L}}} = \frac{\partial{y_{n(L),L}}}{\partial{z_{n(L),L}}}delta_{n(L),L} ∂bn(L),L∂LOSS=∂yn(L),L∂LOSS∂zn(L),L∂yn(L),L∂bn(L),L∂zn(L),L=∂zn(L),L∂yn(L),Ldeltan(L),L
注意,这里为方便区分不同神经元下标,给每个 n n n加了一个 ( L ) (L) (L)进行标记。针对 ∂ y n ( L ) , L ∂ z n ( L ) , L \frac{\partial{y_{n(L),L}}}{\partial{z_{n(L),L}}} ∂zn(L),L∂yn(L),L,要看具体使用了那些类型的激活函数,在YOLO中最常用的是ReLU(linear_activate(float x))和sigmoid(logistic_activate(float x))。 如果使用ReLU, ∂ y n ( L ) , L ∂ z n ( L ) , L = 1 \frac{\partial{y_{n(L),L}}}{\partial{z_{n(L),L}}} = 1 ∂zn(L),L∂yn(L),L=1,那么 ∂ L O S S ∂ w n ( L − 1 ) , n ( L ) , L = d e l t a n ( L ) , L y n ( L − 1 ) , L − 1 \frac{\partial{LOSS}}{\partial{w_{n(L-1),n(L),L}}} = delta_{n(L),L}y_{n(L-1),L-1} ∂wn(L−1),n(L),L∂LOSS=deltan(L),Lyn(L−1),L−1 ∂ L O S S ∂ b n ( L ) , L = d e l t a n ( L ) , L \frac{\partial{LOSS}}{\partial{b_{n(L),L}}}= delta_{n(L),L} ∂bn(L),L∂LOSS=deltan(L),L
如果使用sigmoid, ∂ y n ( L ) , L ∂ z n ( L ) , L = ( 1 − z n ( L ) , L ) z n ( L ) , L \frac{\partial{y_{n(L),L}}}{\partial{z_{n(L),L}}} = (1 - z_{n(L),L}) z_{n(L),L} ∂zn(L),L∂yn(L),L=(1−zn(L),L)zn(L),L,那么 ∂ L O S S ∂ w n ( L − 1 ) , n ( L ) , L = d e l t a n ( L ) , L y n ( L − 1 ) , L − 1 ( 1 − z n ( L ) , L ) z n ( L ) , L \frac{\partial{LOSS}}{\partial{w_{n(L-1),n(L),L}}} = delta_{n(L),L}y_{n(L-1),L-1}(1 - z_{n(L),L}) z_{n(L),L} ∂wn(L−1),n(L),L∂LOSS=deltan(L),Lyn(L−1),L−1(1−zn(L),L)zn(L),L ∂ L O S S ∂ b n ( L ) , L = d e l t a n ( L ) , L ( 1 − z n ( L ) , L ) z n ( L ) , L \frac{\partial{LOSS}}{\partial{b_{n(L),L}}}= delta_{n(L),L}(1 - z_{n(L),L}) z_{n(L),L} ∂bn(L),L∂LOSS=deltan(L),L(1−zn(L),L)zn(L),L
YOLOv3中卷积模块自带ReLU激活函数,YOLO层中计算位置偏置和分类时使用了sigmoid函数,但YOLO层并未使用 ∂ y n ( L ) , L ∂ z n ( L ) , L = ( 1 − z n ( L ) , L ) z n ( L ) , L \frac{\partial{y_{n(L),L}}}{\partial{z_{n(L),L}}} = (1 - z_{n(L),L}) z_{n(L),L} ∂zn(L),L∂yn(L),L=(1−zn(L),L)zn(L),L这个环节,YOLO层是一个目标检测层,认为计算的误差可以直接传递。本人认为计算位置偏置使用sigmoid函数主要目的还是为了将偏置控制再0到1之间,至于训练出来是不是1作者并不关心,因为这里是回归而不是分类。其实如果是为了控制再0到1之间还可以使用sin,cos函数等,反向传播不考虑sigmoid函数,也许归回会慢一点,但是总体并不影响。对于分类问题,作者反向传播时候使用的是交叉熵,已经考虑进去了,读者可以查看《YOLO中LOSS函数的计算》。作者直接使用delta,也是考虑可以将delta直接传递到前一层直接使用了。
下面我们接着推导第L-1层。首先先推导LOSS函数对$ y_{n(L-1),L-1 $的偏导。 ∂ L O S S ∂ y N ( L − 1 ) , L − 1 = ∑ n ( L ) = 1 N ( L ) ∂ L O S S ∂ y n ( L ) , L ∂ y n ( L ) , L ∂ z n ( L ) , L ∂ z n ( L ) , L ∂ y n ( L − 1 ) , L − 1 \frac{\partial{LOSS}}{\partial{y_{N(L-1),L-1}}} = \sum_{n(L)=1}^{N(L)}{\frac{\partial{LOSS}}{\partial{y_{n(L),L}}}\frac{\partial{y_{n(L),L}}}{\partial{z_{n(L),L}}}} \frac{\partial{z_{n(L),L}}}{\partial{y_{n(L-1),L-1}}} ∂yN(L−1),L−1∂LOSS=n(L)=1∑N(L)∂yn(L),L∂LOSS∂zn(L),L∂yn(L),L∂yn(L−1),L−1∂zn(L),L 这里,因为 y n ( L − 1 ) , L − 1 y_{n(L-1),L-1} yn(L−1),L−1参与了每个 z n ( L ) , L z_{n(L),L} zn(L),L计算,所以需要一个累加计算。现在计算 ∂ z n ( L ) , L ∂ y n ( L − 1 ) , L − 1 \frac{\partial{z_{n(L),L}}}{\partial{y_{n(L-1),L-1}}} ∂yn(L−1),L−1∂zn(L),L ∂ z n ( L ) , L ∂ y n ( L − 1 ) , L − 1 = ∂ ( ∑ n ( L − 1 ) = 1 N ( L − 1 ) y n ( L − 1 ) , L − 1 w n ( L − 1 ) , n ( L ) , L + b n ( L ) , L ) ∂ y n ( L − 1 ) , L − 1 = w n ( L − 1 ) , n ( L ) , L \frac{\partial{z_{n(L),L}}}{\partial{y_{n(L-1),L-1}}} = \frac{\partial{(\sum_{n(L-1)=1}^{N(L-1)}{y_{n(L-1),L-1}w_{n(L-1),n(L),L}}+b_{n(L),L})}}{\partial{y_{n(L-1),L-1}}} =w_{n(L-1),n(L),L} ∂yn(L−1),L−1∂zn(L),L=∂yn(L−1),L−1∂(∑n(L−1)=1N(L−1)yn(L−1),L−1wn(L−1),n(L),L+bn(L),L)=wn(L−1),n(L),L 因此 ∂ L O S S ∂ y N ( L − 1 ) , L − 1 = ∑ n ( L ) = 1 N ( L ) ∂ y n ( L ) , L ∂ z n ( L ) , L d e l t a n ( L ) , L w n ( L − 1 ) , n ( L ) , L \frac{\partial{LOSS}}{\partial{y_{N(L-1),L-1}}} = \sum_{n(L)=1}^{N(L)}{\frac{\partial{y_{n(L),L}}}{\partial{z_{n(L),L}}}delta_{n(L),L}w_{n(L-1),n(L),L}} ∂yN(L−1),L−1∂LOSS=n(L)=1∑N(L)∂zn(L),L∂yn(L),Ldeltan(L),Lwn(L−1),n(L),L 为了更清楚的理解求导过程,这里我们不展开 ∂ y n ( L ) , L ∂ z n ( L ) , L \frac{\partial{y_{n(L),L}}}{\partial{z_{n(L),L}}} ∂zn(L),L∂yn(L),L,完成对 y n ( L − 1 ) , L − 1 y_{n(L-1),L-1} yn(L−1),L−1求导,我们开始对 w n ( L − 2 ) , n ( L − 1 ) , L − 1 w_{n(L-2),n(L-1),L-1} wn(L−2),n(L−1),L−1求导 ∂ L O S S ∂ w n ( L − 2 ) , n ( L − 1 ) , L − 1 = ∂ L O S S ∂ y N ( L − 1 ) , L − 1 ∂ y N ( L − 1 ) , L − 1 ∂ z n ( L − 1 ) , L − 1 ∂ z n ( L − 1 ) , L − 1 ∂ w n ( L − 2 ) , n ( L − 1 ) , L − 1 = y n ( L − 2 ) , L − 2 ∂ y N ( L − 1 ) , L − 1 ∂ z n ( L − 1 ) , L − 1 ∑ n ( L ) = 1 N ( L ) ∂ y n ( L ) , L ∂ z n ( L ) , L d e l t a n ( L ) , L w n ( L − 1 ) , n ( L ) , L \frac{\partial{LOSS}}{\partial{w_{n(L-2),n(L-1),L-1}}} =\frac{\partial{LOSS}}{\partial{y_{N(L-1),L-1}}}\frac{\partial{y_{N(L-1),L-1}}}{\partial{z_{n(L-1),L-1}}}\frac{\partial{z_{n(L-1),L-1}}}{\partial{w_{n(L-2),n(L-1),L-1}}}\\ = y_{n(L-2),L-2}\frac{\partial{y_{N(L-1),L-1}}}{\partial{z_{n(L-1),L-1}}}\sum_{n(L)=1}^{N(L)}{\frac{\partial{y_{n(L),L}}}{\partial{z_{n(L),L}}}delta_{n(L),L}w_{n(L-1),n(L),L}} ∂wn(L−2),n(L−1),L−1∂LOSS=∂yN(L−1),L−1∂LOSS∂zn(L−1),L−1∂yN(L−1),L−1∂wn(L−2),n(L−1),L−1∂zn(L−1),L−1=yn(L−2),L−2∂zn(L−1),L−1∂yN(L−1),L−1n(L)=1∑N(L)∂zn(L),L∂yn(L),Ldeltan(L),Lwn(L−1),n(L),L ∂ L O S S ∂ b n ( L − 1 ) , L − 1 = ∂ L O S S ∂ y N ( L − 1 ) , L − 1 ∂ y N ( L − 1 ) , L − 1 ∂ z n ( L − 1 ) , L − 1 ∂ z n ( L − 1 ) , L − 1 ∂ b n ( L − 1 ) , L − 1 = ∂ y N ( L − 1 ) , L − 1 ∂ z n ( L − 1 ) , L − 1 ∑ n ( L ) = 1 N ( L ) ∂ y n ( L ) , L ∂ z n ( L ) , L d e l t a n ( L ) , L w n ( L − 1 ) , n ( L ) , L \frac{\partial{LOSS}}{\partial{b_{n(L-1),L-1}}} =\frac{\partial{LOSS}}{\partial{y_{N(L-1),L-1}}}\frac{\partial{y_{N(L-1),L-1}}}{\partial{z_{n(L-1),L-1}}}\frac{\partial{z_{n(L-1),L-1}}}{\partial{b_{n(L-1),L-1}}}\\ = \frac{\partial{y_{N(L-1),L-1}}}{\partial{z_{n(L-1),L-1}}}\sum_{n(L)=1}^{N(L)}{\frac{\partial{y_{n(L),L}}}{\partial{z_{n(L),L}}}delta_{n(L),L}w_{n(L-1),n(L),L}} ∂bn(L−1),L−1∂LOSS=∂yN(L−1),L−1∂LOSS∂zn(L−1),L−1∂yN(L−1),L−1∂bn(L−1),L−1∂zn(L−1),L−1=∂zn(L−1),L−1∂yN(L−1),L−1n(L)=1∑N(L)∂zn(L),L∂yn(L),Ldeltan(L),Lwn(L−1),n(L),L 下面我们将 L L L换成 l l l,给出一个更加普遍的计算公式: 求对 y N ( l − 1 ) , l − 1 y_{N(l-1),l-1} yN(l−1),l−1的导数 ∂ L O S S ∂ y N ( l − 1 ) , l − 1 = ∑ n ( l ) = 1 N ( l ) ∂ L O S S ∂ y n ( l ) , l ∂ y n ( l ) , l ∂ z n ( l ) , l w n ( l − 1 ) , n ( l ) , l \frac{\partial{LOSS}}{\partial{y_{N(l-1),l-1}}} = \sum_{n(l)=1}^{N(l)}{\frac{\partial{LOSS}}{\partial{y_{n(l),l}}}\frac{\partial{y_{n(l),l}}}{\partial{z_{n(l),l}}}w_{n(l-1),n(l),l}} ∂yN(l−1),l−1∂LOSS=n(l)=1∑N(l)∂yn(l),l∂LOSS∂zn(l),l∂yn(l),lwn(l−1),n(l),l 求对 w N ( l − 2 ) , N ( l − 1 ) , l − 1 w_{N(l-2),N(l-1),l-1} wN(l−2),N(l−1),l−1的导数 ∂ L O S S ∂ w n ( l − 2 ) , n ( l − 1 ) , l − 1 = ∂ L O S S ∂ y N ( l − 1 ) , l − 1 ∂ y N ( l − 1 ) , l − 1 ∂ z n ( l − 1 ) , l − 1 ∂ z n ( l − 1 ) , l − 1 ∂ w n ( l − 2 ) , n ( l − 1 ) , l − 1 = y n ( l − 2 ) , l − 2 ∂ y N ( l − 1 ) , l − 1 ∂ z n ( l − 1 ) , l − 1 ∂ L O S S ∂ y N ( l − 1 ) , l − 1 \frac{\partial{LOSS}}{\partial{w_{n(l-2),n(l-1),l-1}}} =\frac{\partial{LOSS}}{\partial{y_{N(l-1),l-1}}}\frac{\partial{y_{N(l-1),l-1}}}{\partial{z_{n(l-1),l-1}}}\frac{\partial{z_{n(l-1),l-1}}}{\partial{w_{n(l-2),n(l-1),l-1}}}\\ = y_{n(l-2),l-2}\frac{\partial{y_{N(l-1),l-1}}}{\partial{z_{n(l-1),l-1}}}\frac{\partial{LOSS}}{\partial{y_{N(l-1),l-1}}} ∂wn(l−2),n(l−1),l−1∂LOSS=∂yN(l−1),l−1∂LOSS∂zn(l−1),l−1∂yN(l−1),l−1∂wn(l−2),n(l−1),l−1∂zn(l−1),l−1=yn(l−2),l−2∂zn(l−1),l−1∂yN(l−1),l−1∂yN(l−1),l−1∂LOSS 求对 b N ( l − 1 ) , l − 1 b_{N(l-1),l-1} bN(l−1),l−1的导数 ∂ L O S S ∂ b n ( l − 1 ) , l − 1 = ∂ L O S S ∂ y N ( l − 1 ) , l − 1 ∂ y N ( l − 1 ) , l − 1 ∂ z n ( l − 1 ) , l − 1 ∂ z n ( l − 1 ) , l − 1 ∂ b n ( l − 1 ) , l − 1 = ∂ y N ( l − 1 ) , l − 1 ∂ z n ( l − 1 ) , l − 1 ∂ L O S S ∂ y N ( l − 1 ) , l − 1 \frac{\partial{LOSS}}{\partial{b_{n(l-1),l-1}}} =\frac{\partial{LOSS}}{\partial{y_{N(l-1),l-1}}}\frac{\partial{y_{N(l-1),l-1}}}{\partial{z_{n(l-1),l-1}}}\frac{\partial{z_{n(l-1),l-1}}}{\partial{b_{n(l-1),l-1}}}\\ = \frac{\partial{y_{N(l-1),l-1}}}{\partial{z_{n(l-1),l-1}}}\frac{\partial{LOSS}}{\partial{y_{N(l-1),l-1}}} ∂bn(l−1),l−1∂LOSS=∂yN(l−1),l−1∂LOSS∂zn(l−1),l−1∂yN(l−1),l−1∂bn(l−1),l−1∂zn(l−1),l−1=∂zn(l−1),l−1∂yN(l−1),l−1∂yN(l−1),l−1∂LOSS 推导完毕! 结果中 ∂ L O S S ∂ y N ( l − 1 ) , l − 1 \frac{\partial{LOSS}}{\partial{y_{N(l-1),l-1}}} ∂yN(l−1),l−1∂LOSS从上一层计算的结果中带入,再YOLOv3中为l.delta的传播。 ∂ y N ( l − 1 ) , l − 1 ∂ z n ( l − 1 ) , l − 1 \frac{\partial{y_{N(l-1),l-1}}}{\partial{z_{n(l-1),l-1}}} ∂zn(l−1),l−1∂yN(l−1),l−1根据不同的激活公式带入即可。 有了这个推导,我们就可以一点一点分析YOLOv3源码。因为还涉及到feature map卷积计算中的重排和GEMM,内容较多,我们放在下一篇中分析。
