【转载】维数相容+矩阵求导

作者:李飞腾链接:https://zhuanlan.zhihu.com/p/22473137
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。如果能二秒内在脑袋里解出下面的问题,本文便结束了。
已知:

J=(Xw-y)^T(Xw-y)=||Xw-y||^2
J=(Xw-y)^T(Xw-y)=||Xw-y||^2
,其中
X\in R^{m \times n}, w \in R^{n \times 1}, y \in R^{m \times 1}
X\in R^{m \times n}, w \in R^{n \times 1}, y \in R^{m \times 1}

求:
\frac{\partial J}{\partial X}
\frac{\partial J}{\partial X}
 \frac{\partial J}{\partial w}
\frac{\partial J}{\partial w}
 \frac{\partial J}{\partial y}
\frac{\partial J}{\partial y}

到这里,请耐心看完下面的公式推导,无需长久心里建设。
首先,反向传播的数学原理是“求导的链式法则” :
f
f
g
g
x
x
的可导函数,则
(f \circ g)'(x) = f'(g(x))g'(x)
(f \circ g)'(x) = f'(g(x))g'(x)

接下来介绍
矩阵、向量求导的维数相容原则
利用维数相容原则快速推导反向传播
编程实现前向传播、反向传播
卷积神经网络的反向传播

快速矩阵、向量求导
这一节展示如何使用链式法则、转置、组合等技巧来快速完成对矩阵、向量的求导
一个原则维数相容,实质是多元微分基本知识,没有在课本中找到下列内容,维数相容原则是我个人总结:
维数相容原则:通过前后换序、转置 使求导结果满足矩阵乘法且结果维数满足下式:
如果

x\in R^{m\times n}
x\in R^{m\times n}
 f(x)\in R^1
f(x)\in R^1
,那么
\frac{\partial f(x)}{\partial x} \in R^{m\times n}
\frac{\partial f(x)}{\partial x} \in R^{m\times n}

利用维数相容原则解上例:
step1:把所有参数当做实数来求导,
J=(Xw-y)^2
J=(Xw-y)^2

依据链式法则有
\frac{\partial J}{\partial X}=2(Xw-y)w
\frac{\partial J}{\partial X}=2(Xw-y)w
\frac{\partial J}{\partial w}=2(Xw-y)X
\frac{\partial J}{\partial w}=2(Xw-y)X
\frac{\partial J}{\partial y}=-2(Xw-y)
\frac{\partial J}{\partial y}=-2(Xw-y)

可以看出除了
\frac{\partial J}{\partial y}=-2(Xw-y)
\frac{\partial J}{\partial y}=-2(Xw-y)
\frac{\partial J}{\partial X}
\frac{\partial J}{\partial X}
\frac{\partial J}{\partial w}
\frac{\partial J}{\partial w}
的求导结果在维数上连矩阵乘法都不能满足。
step2:根据step1的求导结果,依据维数相容原则做调整:前后换序、转置
依据维数相容原则
\frac{\partial J}{\partial X} \in R^{m \times n}
\frac{\partial J}{\partial X} \in R^{m \times n}
,但
\frac{\partial J}{\partial X} \in R^{m \times n} = 2(Xw-y)w
\frac{\partial J}{\partial X} \in R^{m \times n} = 2(Xw-y)w
(Xw-y)\in R^{m \times 1}
(Xw-y)\in R^{m \times 1}
w \in R^{n \times 1}
w \in R^{n \times 1}
,自然得调整为
\frac{\partial J}{\partial X}=2(Xw-y)w^T
\frac{\partial J}{\partial X}=2(Xw-y)w^T

同理:
\frac{\partial J}{\partial w} \in R^{n \times 1}
\frac{\partial J}{\partial w} \in R^{n \times 1}
,但
\frac{\partial J}{\partial w} \in R^{n \times 1} = 2(Xw-y)X
\frac{\partial J}{\partial w} \in R^{n \times 1} = 2(Xw-y)X
(Xw-y) \in R^{m \times 1}
(Xw-y) \in R^{m \times 1}
X \in R^{m \times n}
X \in R^{m \times n}
,那么通过换序、转置我们可以得到维数相容的结果
2X^T(Xw-y)
2X^T(Xw-y)

对于矩阵、向量求导:
“当做一维实数使用链式法则求导,然后做维数相容调整,使之符合矩阵乘法原则且维数相容”是快速准确的策略;
“对单个元素求导、再整理成矩阵形式”这种方式整理是困难的、过程是缓慢的,结果是易出错的(不信你试试)。

如何证明经过维数相容原则调整后的结果是正确的呢?直觉!简单就是美...快速反向传播

神经网络的反向传播求得“各层”参数

W
W
b
b
的导数,使用梯度下降(一阶GD、SGD,二阶LBFGS、共轭梯度等)优化目标函数。
接下来,展示不使用下标的记法(
W_{ij}
W_{ij}
,
b_i
b_i
or
b_j
b_j
)直接对
W
W
b
b
求导
,反向传播是链式法则维数相容原则的完美体现,对每一层参数的求导利用上一层的中间结果完成。
这里的标号,参考UFLDL教程 - Ufldl
前向传播:
z^{(l+1)}=W^{(l)}a^{(l)}+b^{(l)}
z^{(l+1)}=W^{(l)}a^{(l)}+b^{(l)}
(公式1)
a^{(l+1)} =f(z^{(l+1)})
a^{(l+1)} =f(z^{(l+1)})
(公式2)
z^{(l)}
z^{(l)}
为第
l
l
层的中间结果,
a^{(l)}
a^{(l)}
为第
l
l
层的激活值,其中第
l+1
l+1
层包含元素:输入
a^{(l)}
a^{(l)}
,参数
W^{(l)}
W^{(l)}
b^{(l)}
b^{(l)}
,激活函数
f()
f()
,中间结果
z^{(l+1)}
z^{(l+1)}
,输出
a^{(l+1)}
a^{(l+1)}

设神经网络的损失函数为
J(W,b) \in R^1
J(W,b) \in R^1
(这里不给出具体公式,可以是交叉熵、MSE等),根据链式法则有:
\bigtriangledown_{W^{(l)}}J(W,b)=\frac{\partial J(W,b)}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial W^{(l)}}=\delta ^{(l+1)}(a ^{(l)})^T
\bigtriangledown_{W^{(l)}}J(W,b)=\frac{\partial J(W,b)}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial W^{(l)}}=\delta ^{(l+1)}(a ^{(l)})^T
\bigtriangledown_{b^{(l)}}J(W,b)=\frac{\partial J(W,b)}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial b^{(l)}}=\delta ^{(l+1)}
\bigtriangledown_{b^{(l)}}J(W,b)=\frac{\partial J(W,b)}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial b^{(l)}}=\delta ^{(l+1)}
这里记
\frac{\partial J(W,b)}{\partial z^{(l+1)}}=\delta ^{(l+1)}
\frac{\partial J(W,b)}{\partial z^{(l+1)}}=\delta ^{(l+1)}
,其中
\frac{\partial z^{(l+1)}}{\partial W^{(l)}}=a ^{(l)}
\frac{\partial z^{(l+1)}}{\partial W^{(l)}}=a ^{(l)}
\frac{\partial z^{(l+1)}}{\partial b^{(l)}}= 1
\frac{\partial z^{(l+1)}}{\partial b^{(l)}}= 1
可由 公式1 得出,
a ^{(l)}
a ^{(l)}
加转置符号
(a ^{(l)})^{T}
(a ^{(l)})^{T}
是根据
维数相容原则
作出的调整。
如何求
\delta ^{(l)}=\frac{\partial J(W,b)}{\partial z^{(l)}}
\delta ^{(l)}=\frac{\partial J(W,b)}{\partial z^{(l)}}
? 可使用如下递推(需根据维数相容原则作出调整):
\delta ^{(l)}=\frac{\partial J}{\partial z^{(l)}}=\frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial a^{(l)}} \frac{\partial a^{(l)}}{\partial z^{(l)}}= ((W^{(l)})^{T}\delta ^{(l+1)}) \cdot f'(z^{(l)})
\delta ^{(l)}=\frac{\partial J}{\partial z^{(l)}}=\frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial a^{(l)}} \frac{\partial a^{(l)}}{\partial z^{(l)}}= ((W^{(l)})^{T}\delta ^{(l+1)}) \cdot f'(z^{(l)})
其中
\frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial a^{(l)}} = (W^{(l)})^T \delta ^{(l+1)}
\frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial a^{(l)}} = (W^{(l)})^T \delta ^{(l+1)}
\frac{\partial a^{(l)}}{\partial z^{(l)}} = f'(z^{(l)})
\frac{\partial a^{(l)}}{\partial z^{(l)}} = f'(z^{(l)})

那么我们可以从最顶层逐层往下,便可以递推求得每一层的
\delta ^{(l)} = \frac{\partial J(W,b)}{\partial z^{(l)}}
\delta ^{(l)} = \frac{\partial J(W,b)}{\partial z^{(l)}}

注意:
\frac{\partial a^{(l)}}{\partial z^{(l)}} = f'(z^{(l)})
\frac{\partial a^{(l)}}{\partial z^{(l)}} = f'(z^{(l)})
是逐维求导,在公式中是点乘的形式。
反向传播整个流程如下

  1. 进行前向传播计算,利用前向传播公式,得到隐藏层和输出层 的激活值。
  2. 对输出层(第
    l
    l

    层),计算残差:


    \delta ^{(l)} =\frac{\partial J(W,b)}{\partial z^{(l)}}
    \delta ^{(l)} =\frac{\partial J(W,b)}{\partial z^{(l)}}
    (不同损失函数,结果不同,这里不给出具体形式)
  3. 对于
    l-1, l-2 , ... , 2
    l-1, l-2 , ... , 2
    的隐藏层,计算:
    \delta ^{(l)}=\frac{\partial J}{\partial z^{(l)}}=\frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial a^{(l)}}\frac{\partial a^{(l)}}{\partial z^{(l)}}=((W^{(l)})^{T}\delta ^{(l+1)}) \cdot f'(z^{(l)})
    \delta ^{(l)}=\frac{\partial J}{\partial z^{(l)}}=\frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial a^{(l)}}\frac{\partial a^{(l)}}{\partial z^{(l)}}=((W^{(l)})^{T}\delta ^{(l+1)}) \cdot f'(z^{(l)})
    4) 计算各层参数
    W^{(l)}
    W^{(l)}
    b^{(l)}
    b^{(l)}
    偏导数:
    \bigtriangledown_{W^{(l)}}J(W,b)=\frac{\partial J(W,b)}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial W^{(l)}}=\delta ^{(l+1)}(a ^{(l)})^T
    \bigtriangledown_{W^{(l)}}J(W,b)=\frac{\partial J(W,b)}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial W^{(l)}}=\delta ^{(l+1)}(a ^{(l)})^T
    \bigtriangledown_{b^{(l)}}J(W,b)=\frac{\partial J(W,b)}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial b^{(l)}}=\delta ^{(l+1)}
    \bigtriangledown_{b^{(l)}}J(W,b)=\frac{\partial J(W,b)}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial b^{(l)}}=\delta ^{(l+1)}
    编程实现
    大部分开源library(如:caffe,Kaldi/src/{nnet1,nnet2})的实现通常把
    W^{(l)}
    W^{(l)}
    b^{(l)}
    b^{(l)}
    作为一个layer,激活函数
    f()
    f()
    作为一个layer(如:sigmoid、relu、softplus、softmax)。
    反向传播时分清楚该层的输入、输出即能正确编程实现,如:
    z^{(l+1)}=W^{(l)}a^{(l)}+b^{(l)}
    z^{(l+1)}=W^{(l)}a^{(l)}+b^{(l)}
    (公式1)
    a^{(l+1)} =f(z^{(l+1)})
    a^{(l+1)} =f(z^{(l+1)})
    (公式2)
    (1)式AffineTransform/FullConnected层,以下是伪代码:
    注: out_diff =
     \frac{\partial J}{\partial z^{(l+1)}}
    \frac{\partial J}{\partial z^{(l+1)}}
    是上一层(Softmax 或 Sigmoid/ReLU的 in_diff)已经求得:
    in_diff = \frac{\partial J}{\partial a^{(l)}} = \frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial a^{(l)}} = W^T * out_diff
    in_diff = \frac{\partial J}{\partial a^{(l)}} = \frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial a^{(l)}} = W^T * out_diff
    (公式 1-1)
    W_diff =\frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial W^{(l)}} = out_diff * in^T
    W_diff =\frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial W^{(l)}} = out_diff * in^T
    (公式 1-2)
    b_diff =\frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial b^{(l)}} = out_diff * 1
    b_diff =\frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial b^{(l)}} = out_diff * 1
    (公式 1-3)
    (2)式激活函数层(以Sigmoid为例)
    注:out_diff =
    \frac{\partial J}{\partial a^{(l+1)}}
    \frac{\partial J}{\partial a^{(l+1)}}
    是上一层AffineTransform的in_diff,已经求得,
    in_diff = \frac{\partial J}{\partial z^{(l+1)}} = \frac{\partial J}{\partial a^{(l+1)}} \frac{\partial a^{(l+1)}}{\partial z^{(l+1)}} = out_diff \cdot out \cdot (1-out)
    in_diff = \frac{\partial J}{\partial z^{(l+1)}} = \frac{\partial J}{\partial a^{(l+1)}} \frac{\partial a^{(l+1)}}{\partial z^{(l+1)}} = out_diff \cdot out \cdot (1-out)
    在实际编程实现时,in、out可能是矩阵(通常以一行存储一个输入向量,矩阵的行数就是batch_size),那么上面的C++代码就要做出变化(改变前后顺序、转置,把函数参数的Vector换成Matrix,此时Matrix out_diff 每一行就要存储对应一个Vector的diff,在update的时候要做这个batch的加和,这个加和可以通过矩阵相乘out_diffinput(适当的转置)得到。
    如果熟悉SVD分解的过程,通过SVD逆过程就可以轻松理解这种通过乘积来做加和的技巧。
    丢掉那些下标记法吧!
    卷积层求导
    卷积怎么求导呢?实际上卷积可以通过矩阵乘法来实现(是否旋转无所谓的,对称处理,caffe里面是不是有image2col),当然也可以使用FFT在频率域做加法。
    那么既然通过矩阵乘法,
    维数相容原则*仍然可以运用,CNN求导比DNN复杂一些,要做些累加的操作。具体怎么做还要看编程时选择怎样的策略、数据结构
    快速矩阵、向量求导之维数相容大法已成
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容