机器学习中的矩阵、向量求导

写在前面

本文的目标读者是想快速掌握矩阵、向量求导法则的学习者,主要面向矩阵、向量求导在机器学习中的应用。因此,本教程而非一份严格的数学教材,而是希望帮助读者尽快熟悉相关的求导方法并在实践中应用。在介绍向量求导公式时,本教程中会出现少量证明,但这些证明都很简单,其目的是辅助公式的记忆、提供向量导数计算的实例,请读者不要跳过。另外,本教程假定读者熟悉一元函数的求导。

所谓矩阵求导,本质上只不过是多元函数求导,仅仅是把函数的自变量以及求导的结果排列成了矩阵的形式,方便表达与计算而已。类似地,复合函数的求导法则本质上也是多元函数求导的链式法则,只是将结果整理成了矩阵的形式。从原理上讲,可以对矩阵的每个分量逐元素地求导,得到最终结果;但是这样做太繁琐,极其容易出错,因此推导并记住一些常用的结论在实践中是非常必要的。

矩阵求导本身有很多争议,例如:

  • 对于求导结果是否需要转置?
    • 不同教材对此处理的结果不一样,这属于不同的 Layout Convention。本文以不转置为准,即求导结果与原矩阵/向量同型,术语叫 Mixed Layout。
  • 矩阵对向量、向量对矩阵、矩阵对矩阵求导的结果是什么?
    • 最自然的结果当然是把结果定义成三维乃至四维张量,但是这并不好算。也有一些绕弯的解决办法(例如把矩阵抻成一个向量等),但是这些方案都不完美(例如复合函数求导的链式法则无法用矩阵乘法简洁地表达等)。在本教程中,我们认为,这三种情形下导数没有定义。凡是遇到这种情况,都通过其他手段来绕过,后面会有具体的示例。

因此,本教程的符号体系有可能与其他书籍或讲义不一致,求导结果也可能不一致(例如相差一次矩阵转置,或者是结果矩阵是否平铺成向量等),使用者需自行注意。另外,本教程中有很多笔者自己的评论,例如关于变形的技巧、如何记忆公式、如何理解其他的教程中给出的和本教程中形式不同的结果等。

文中如有错漏,请联系 [email protected],我会尽快订正。

符号表示

变量使用规范

  • 标量用普通小写字母或希腊字母表示,例如
  • 向量用粗体小写字母表示,例如 ,其元素记作 (注意这里 没有加粗。加粗的小写字母加下标,例如 等,表示这是两个不同的向量)。向量默认为列向量,行向量需要用列向量的转置表示,例如 等
  • 矩阵用大写字母表示,如 等,其元素记作 (注意这里 用的是小写字母。大写字母加下标,例如 等,表示不同的常数矩阵)
  • 字母表中靠前的字母(如 等)表示常量, 或字母表中靠后的字母(如 等)等表示变量或函数
  • 有特殊说明的除外

导数符号

  • 若 是关于 的函数,则 对 的导数记作 或 ;若待求导的变量比较明确,也可以省略下标记作
  • 上一条中的 和 可以指代任意维度的变量

导数定义

以前一节规定的符号为基础,根据函数值和自变量的类型,本文对求导结果及其维度进行如下约定:

  • 矩阵/向量值函数对实数的导数
    • 要点:求导结果与函数值同型,且每个元素就是函数值的相应分量对自变量 求导
    • 若函数 ,则 也是一个 维矩阵,且 。导数也可记作 或 。
    • 由于向量是矩阵的特殊情形,根据上面的定义也可以得到函数值为列向量时的定义:若有函数 ,则 也是一个 维列向量,且 。若函数值为行向量 ,则相应的求导结果 也是行向量。
    • 注:本文开头即说明过,变量为向量时仅仅是将其看作多个实数,无所谓行向量与列向量之分。这里规定结果形如行向量或列向量,仅仅为了把公式用矩阵相乘的方式表示出来,进而与其他部分进行矩阵运算。下同。
  • 实值函数对矩阵/向量的导数
    • 要点:求导结果与自变量同型,且每个元素就是 对自变量的相应分量求导
    • 这是最重要的一个类别,因为机器学习里一般都是求标量损失函数对向量/矩阵参数的导数
    • 若函数,则 也是一个 维矩阵,且 。导数也可使用劈形算子记作 。
    • 由于向量是矩阵的特殊情形,根据上面的定义也可以得到自变量为列向量时的定义:若函数 ,则 也是一个 维列向量,且 。若自变量是行向量 ,则结果 也是行向量。
  • 向量值函数对向量的导数(雅克比矩阵
    • 若函数 ,则 是一个 维矩阵,且 。用劈形算子表示时可记作 。
    • 注:如前所述,本教程仅仅是把变量都看成多个实数,无所谓行与列之分,因此在表述从向量 到 的雅克比矩阵时,不区分 或者 到底是行向量还是列向量(正都是根据 个实数计算出 个实数),统一用 表示,维度也都是 。有些教程可能会区分行对列、列对列、行对行、列对行几种不同情形的求导,认为其中有些结果相差一个转置,有些组合不能求导等等。本教程则认为上述各种情形的求导结果都相同,就是雅克比矩阵。
    • 特别地,若 退化成标量 ,则 到 的雅克比矩阵 是一个行向量,是梯度(列向量)的转置,即 。注意这里使用的记号:左边 加粗,是把它看做一个长度为 1 的向量,表示求向量 到向量 的雅克比矩阵;右边 为普通字体,表示实函数 对向量 的导数。
  • 关于劈形算子 和 Hessian 矩阵的补充
    • 劈形算子和偏导数两种记号大体上是相同的,只不过在涉及到变量分量的推导过程(例如用链式法则推神经网络的BP算法)中,偏导数那一套符号更加常用;而劈形算子的优势是书写简单,在对传统的机器学习模型的目标函数求导时,劈形算子有时更常用。
    • 对于一个实函数 ,其梯度记为 ,也可记作 ,是一个 维向量。Hessian矩阵是一个 的矩阵,记为 ,其中 。根据上述定义可以发现,Hessian 矩阵其实是 到 的雅克比矩阵,因此 不光是一个形式记号,而是可以用 来计算。
      • 注:某些教材区分对行向量和列向量求导,认为 Hessian 矩阵是先对行向量 求导,再对列向量 求导(或者反过来),因此写作 (或者 )。
    • 对于一个实函数 ,其梯度规定为 维矩阵 ,Hessian矩阵不作定义。

对上述约定的理解

  • 对于实值函数 ,上面的导数定义符合转置关系,即 和 互为转置
    • (其中 代表任意维度的向量或矩阵)
  • 函数增量的线性主部与自变量增量的关系
    • 实值函数对矩阵的导数
        • 此式用到的技巧非常重要:两个同型矩阵对应元素相乘再求和时常用上面第二个等式转化为迹,从而简化公式表达和运算
        • 从另一个角度讲,这是矩阵导数的另一种定义。即:对于函数 ,若存在矩阵,使得 时( 为任意范数),成立 ,则定义
        • 矩阵乘积的迹是一个线性算子。事实上,如果有两个同型矩阵 ,他们的内积即定义为 。容易验证矩阵内积是向量内积的推广(定义都是对应元素相乘再求和)
    • 实值函数对向量的导数
        • 上式右边是向量内积
    • 向量值函数对向量的导数
        • 此式即为重积分换元时用于坐标变换的Jacobian矩阵。

变量多次出现的求导法则

若某个变量在函数表达式中多次出现,可以单独计算函数对自变量的每一次出现的导数,再把结果加起来。

这条规则很重要,尤其是在推导某些共享变量的模型的导数时很有用,例如 autoencoder with tied weights(编码和解码部分的权重矩阵互为转置的自动编码器)和卷积神经网络(同一个 feature map 中卷积核的权重在整张图不同位置共享)等。

举例(本例中 是标量,但该规则对向量和矩阵也是成立的):假设函数表达式是 ,可以先把三个 看成三个不同的变量,即把 的表达式看成 ,然后分别计算 ,,和 ,最后总的导数就是这三项加起来:,此时再把 的下标抹掉并化简,就得到 。熟悉这个过程之后,可以省掉添加下标再移除的过程。

如果用计算图(computation graph,描述变量间依赖关系的示意图,后面会举例)的语言来描述本条法则,就是:若变量 有多条影响函数 的值的路径,则计算 时需要对每条路经求导最后再加和。 如果想更多地了解计算图和反向传播,推荐阅读 Colah 君的文章。其中详细讲述了计算图如何工作,不仅讲反向传播还讲了前向传播(前向传播对于目前的机器学习算法来说似乎没有太大的用处,但是对于加深计算图的理解很有帮助。RNN 曾经有一种学习算法叫 RTRL 就是基于前向传播的,不过近年来不流行了,被 BPTT 取代了)。

有了上面的基础,我们就可以推导 Batch normalization(以下简称 BN)的求导公式了。 BN 的计算过程为:

机器学习中的矩阵、向量求导_第1张图片
image.png

其中 是批的大小, 到 分别是 个不同样本对于某个神经元的输入, 是这个批的总的损失函数,所有变量都是标量。求导的第一步是画出变量依赖图,如下所示(根据左边的变量可以计算出右边的变量,如果为了强调,也可以在边上添加从左向右的箭头):

机器学习中的矩阵、向量求导_第2张图片
image.png

左侧,右上,右下分别是三种不同的画法

  • 左边的图是把所有变量 都画了出来,比较清楚,如果想不清楚变量之间是如何相互依赖的,这样画可以帮助梳理思路

  • 右上是我自创的一种方法,借鉴了概率图模型中的盘记号(plate notation),把带下标的变量用一个框框起来,在框的右下角指明重复次数;右下不是完整的计算图,仅仅是其中一个局部,是为了说明在有些资料绘制的计算图中,相同的变量(如本例中的 )只出现一次,从而图中会出现环

    • 在这种表示法中,如果要求 ,需要对 和 这两条路径求导的结果做加和
  • 这几种计算图的表示法没有本质区别,读者也可以尝试其他可能的画法,自己看着舒服就行

BN 原论文中给出了反向传播的公式,不过这里我们不妨试着自己手算一遍,加深对计算图的理解。下面的计算暂时不涉及向量/矩阵的求导,只是正常的多元函数求偏导,读者可以放心自己动手算:

  • 影响损失函数只有唯一的路径
    • 根据链式法则,得到:。
  • 影响损失函数有 条路径:, 都是一条路径,需要对这些路径分别求导再加和
  • 的计算与之类似,结果为 。
  • 影响损失函数的路径也有 条:
    • 此处忽略中间变量 ,直接把 看成的 函数
    • 据此有 \dfrac{\partial l}{\partial \sigma_B^2} = \sum_i \dfrac{\partial l}{\partial \hat{x}_i} \dfrac{\partial \hat{x}_i}{\partial \sigma_B^2} = \sum_i \dfrac{\partial l}{\partial \hat{x}_i} \cdot -\dfrac{1}{2}(x_i - \mu_B)(\sigma_B^2+\epsilon)^{-3/2}。注意求导的时候把 当成一个整体,想象这就是一个字母,而不要把它想成标准差的平方。
  • 影响 共有 条路径:(分别对应于右上图中较短和较长的路径)
    • 所以
    • 又因为 ,上式可以化简为
  • 影响损失函数有 条路径:
    • \begin{align*} \dfrac{\partial l}{\partial x_i} & = & \dfrac{\partial l}{\partial \hat{x}_i} \dfrac{\partial \hat{x}_i}{\partial x_i} + \dfrac{\partial l}{\partial \sigma_B^2} \dfrac{\partial \sigma_B^2}{\partial x_i} + \dfrac{\partial l}{\partial \mu_B} \dfrac{\partial \mu_B}{\partial x_i} \\ & = & \sum_i \dfrac{\partial l}{\partial \hat{x}_i} \dfrac{1}{\sqrt{\sigma_B^2+\epsilon}} + \dfrac{\partial l}{\partial \sigma_B^2} \dfrac{2}{m}(x_i - \mu_B) + \dfrac{\partial l}{\partial \mu_B} \dfrac{1}{m} \end{align*}

常用公式

向量求导的链式法则

  • 易发现雅克比矩阵的传递性:若多个向量的依赖关系为 ,则:。
    • 证明:只需逐元素求导即可。,即 的 元等于矩阵 的 行 和 矩阵 的第 列的内积,这正是矩阵乘法的定义。
    • 注:将两项乘积的和转化成向量内积或矩阵相乘来处理,是很常用的技巧。
  • 雅克比矩阵的传递性可以很容易地推广到多层中间变量的情形,采用数学归纳法证明即可。
  • 若中间变量都是向量,但最后的结果变量是一个实数,例如变量依赖关系形如 ,则:
    • 由雅克比矩阵的传递性知:。再根据 退化为实数时雅克比矩阵和函数导数的关系,有:。以上三式相结合,可以得到如下链式法则:
    • 此公式是把导数视为行向量(即以 和 的形式)给出的。如果需要把导数视为列向量,只需将公式两边同时转置即可
    • 上述结果显然也可以推广到任意多层复合的情形(可用于 RNN 的 BPTT 的推导)
  • 作为特例,若中间只经过一次复合 ,求导公式如下:
    • ,或写作
    • 进一步地,假如 和 维度相同且 仅由 计算出,则易知 是对角阵,上面的公式可以化简为:,其中 表示取对角矩阵 的对角线上的元素组成列向量, 表示两个向量逐元素相乘。由于最终的结果是两个向量逐元素相乘,所以也可以交换一下两项相乘的顺序,写成:。
      • 上述公式的另一种推导方式是直接根据导数的定义逐分量地计算:(此式为上式的分量形式)
    • 这种 仅依赖 而与其他 无关的情形在神经网络中很常见,包括但不限于
      • 逐元素地应用激活函数:
      • 现代 RNN 单元中的门限操作(以 LSTM 为例):
  • 记忆方法:只需记住结果是一堆雅克比矩阵的乘积,相乘的顺序根据维度相容原则调整即可(假设每个中间变量的维度都不一样,看怎么摆能把雅克比矩阵的维度摆成矩阵乘法规则允许的形式。只要把矩阵维度倒腾顺了,公式也就对了。)
  • 注:网络上各种资料质量参差不齐,在其他教程中时常会见到向量对矩阵求导的表达式。例如介绍 RNN 的梯度消失问题的文章中,经常会见到 \dfrac{\partial l}{\partial W} = \dfrac{\partial l}{\partial \boldsymbol{h}_T} \dfrac{\partial \boldsymbol{h}_T}{\partial \boldsymbol{h}_{T-1}} \cdots \dfrac{\partial \boldsymbol{h}_{i+1}}{\partial \boldsymbol{h}_i} \dfrac{\partial \boldsymbol{h}_i}{\partial W} 这种式子。如果文中出现这个式子是定性的,只是为了说明链式法则中出现了很多连乘项导致了梯度消失,那么读者也只需定性地理解即可。如果文中出现这个式子是定量的,是为了推导反向传播的公式,那么笔者建议读者用如下两种方式之一理解:
    • 其一是把 理解成一种简写形式:先把 抻成一个向量,然后公式中的每一个雅克比矩阵就都可以计算了,最后再把结果向量重新整理成 的同型矩阵。但是这种方法非常复杂,因为把 抻成向量以后目标函数关于 的表达式就变了,很难推导 这个雅克比矩阵。一个具体的算例见 Optimizing RNN performance 一文中最后的推导
      • 如果你不打算熟练掌握这种方法,只浏览一下看看大意即可。相信我,如果你学了本文中的方法,你不会再想用这种把矩阵抻开的方法求导的
    • 其二是把最后一项分母中的 理解成矩阵 中的任一个元素 ,从而上述表达式中的每一项都有定义,从而该表达式可以顺利计算。但是这也很麻烦,因为得到的结果不是直接关于 的表达式,而是关于它的分量的,最后还要合并起来
    • 其他理解方式,基本上都是作者自己就没弄懂瞎糊弄读者的

实值函数对向量求导

  • 未作特殊说明即为对变量 求导

  • 一个基本的雅克比矩阵(由定义易得):

    • 特别地,
  • 向量内积的求导法则

    • 注:内积是一个实数,因此本节相当于实数对向量求导,结果是与自变量同型的向量。

      • 证明:
      • 证明一(直接计算):
      • 证明二(变量多次出现的求导法则):\nabla(\boldsymbol{x}^T\boldsymbol{x}) = \nabla_{\boldsymbol{x}}(\boldsymbol{x}_c^T\boldsymbol{x}) + \nabla_{\boldsymbol{x}}(\boldsymbol{x}^T\boldsymbol{x}_c) = 2\nabla_{\boldsymbol{x}}(\boldsymbol{x}_c^T\boldsymbol{x}) = 2\boldsymbol{x}_c = 2\boldsymbol{x},其中 表示将 的此次出现不视作自变量,而是视作与 无关的常数,下同。
      • 证明(变量多次出现的求导法则):\begin{align*} LHS & = & \nabla (\boldsymbol{x}_c^TA\boldsymbol{x}) + \nabla (\boldsymbol{x}^TA\boldsymbol{x}_c) \\ & = & \nabla ((A^T\boldsymbol{x}_c)^T\boldsymbol{x}) + \nabla ((A\boldsymbol{x}_c)^T\boldsymbol{x}) \\ & = & A^T\boldsymbol{x}_c + A\boldsymbol{x}_c \\ & = & RHS \end{align*}
      • 若 是对称矩阵,即 ,上式右边还可以进一步化简为
    • 向量函数内积的求导法则

      • 若 ,则

      • 证明(变量多次出现的求导法则 + 一次复合的求导法则):

向量数乘求导公式

    • 说明:向量对向量求导,结果是一个雅克比矩阵,形状为 的维度乘 的维度

    • 推导:,两边逐分量对比一下便知等式成立。

    • 记忆:按两个标量函数相乘的求导法则记,再注意一下维度相容原理即可。另外注意,等式左边 是向量的数乘(若 为行向量也可视作矩阵乘法);右边 是矩阵的数乘。

矩阵迹求导

  • 未作特殊说明求导变量即为 。由于迹是一个实数,所以相当于实数对矩阵求导,结果是和 同型的矩阵。
  • 先回顾一下迹的基本性质:
    • 线性性质:
    • 转置不变性:
    • 轮换不变性:
      • 特别地,
      • 注意,轮换不变性不等于交换性。例如:,但是一般情况下 。
  • 基本公式:
    • 证明:这其实就是矩阵导数的另一种定义。也可以用逐分量求导验证。
    • 根据此式容易得到另一个式子:
  • 迹方法的核心公式
    • 推导(变量多次出现的求导法则。其中 表示将 的此次出现视作常数):
    • 这个公式非常重要,在推导最小二乘解等多个问题上都会遇到。公式的名字是我瞎起的。
  • 其他与矩阵迹有关的公式
    • 大部分都是上述核心公式的简单推论,不必强记,用的时候顺手推就行
      • 推导:
      • 注:将实数看作是 1*1 矩阵的迹是很常用的技巧。
      • 推导:,然后套迹方法的核心公式
      • 推导:将左式的括号相乘展开,然后用前几个公式计算结果并化简
      • 推导同上,只需注意到 即可。特别地,(此式也可逐元素求导直接验证)

矩阵求导的链式法则

  • 设 ,则:
    • ,或简写为
    • 关于维度的说明: 是矩阵,中间变量 也是矩阵(未必与 同型),最终结果 是实数。因此求导结果是和 同型的矩阵。
    • 注:此式似乎用的不多,毕竟这仅仅是对 这一个分量求导的结果,很难直接得到对 求导的结果。而且这个式子只是最基础的多元函数复合的链式法则而已,没有得到什么特别有趣或者重要的结论。
  • 设 ,则: (等式右边是实数和矩阵的数乘)
    • 关于维度的说明: 分别是矩阵、实数、实数,因此相当于实数对矩阵求导,结果是与 同型的矩阵。
    • 证明是显然的,逐元素求导验证即可:。
  • 线性变换的导数
    • 设有 及线性映射 (因此 ),则:
      • 推导:,而 ( 是 Kronecker 符号,两个角标相等时为1,否则为0),将后式代入前式,得:,即矩阵 的第 行 和矩阵 的第 列的内积。
    • 记忆方法:先做线性变换再求导就等于先求导再做线性变换。剩下的细节(如左乘还是右乘等)根据维度相容原则倒腾即可
    • 向量的线性变换是矩阵线性变化的退化情形,即:
      • 若 ,则
      • 向量的线性变换还可以求二阶导:
      • 推导:记 ,则 LHS = \nabla_{\boldsymbol{x}} (\nabla_{\boldsymbol{x}} \;f(A\boldsymbol{x}+\boldsymbol{b})) = \nabla_\boldsymbol{x} \boldsymbol{w} = \dfrac{\partial \boldsymbol{w}}{\partial \boldsymbol{u}} \dfrac{\partial \boldsymbol{u}}{\partial \boldsymbol{y}} \dfrac{\partial \boldsymbol{y}}{\partial \boldsymbol{x}}= A^T (\nabla^2_\boldsymbol{y} f) A
    • 由于线性变换很常用,这里不妨把给 右乘一个矩阵时的公式一并给出,以便查阅
      • 设有及线性映射 (因此 ),则:
      • 证明:将 和 分别视为自变量和中间变量,则:。于是
    • 注:在多层感知机神经网络中,经常有形如 的依赖关系。其中 是神经网络某一层的输入, 是该层的参数, 是经过变换后预备输入给下一层的值, 是最终的损失函数。根据上述线性变换的求导公式,立即可以得到 BP 算法的核心步骤: 。
      • 另:标准的 BP 算法通常将 定义为变量

行列式和逆矩阵求导

  • 这一部分在机器学习中遇到的不多(毕竟常见的情况是求一个标量损失函数对其他变量的导数),不是特别重要,不过偶尔在凸优化里会碰到一些。这里收集整理这几个式子主要是为了资料完整、查阅方便。以下假定 是可逆方阵。
  • 行列式的求导公式( Jacobi's Fomula):
      • 实数对实数求导,结果也是实数
      • 其中 是 的伴随矩阵,因此有时此式也写作
      • 这一条证明起来比较难,大致过程是用逐元素求导 + 伴随矩阵的性质推导,可以参考相应的维基页面
    • 两种特殊情形
      • 取 即得:
      • 将上式的结果组装成一个矩阵,得:
        • 左边是实数对矩阵求导,结果为和 同型的矩阵
    • 自变量和函数值都是实数,求导结果也是实数
    • 推导:根据最基本的一元函数复合的求导法则即可。令 ,则:
    • 矩阵对实数求导,结果是和 同型的矩阵(也是和 同型的矩阵)
    • 推导:恒等式 两边同时对 求导,得 ,移项即得

常见技巧及注意事项

  • 实数在与一堆矩阵、向量作数乘时可以随意移动位置。
  • 实数乘行向量时,向量数乘与矩阵乘法( 矩阵和 矩阵相乘)的规则是一致的。
  • 遇到相同下标求和就联想到矩阵乘法的定义,即。特别地,一维下标求和联想到向量内积,二维下标求和联想到迹 ( 应为同型矩阵)。
    • 如果在一个求和式中,待求和项不是实数而是矩阵的乘积,不要想着展开求和式,而要进一步按照上面的思路,看成分块矩阵的相乘!
  • 向量的模长平方(或实数的平方和)转化为内积运算:。矩阵的 F 范数的平方转化为迹运算:。
  • 多个矩阵相乘时,多用矩阵迹的求导公式转化、循环移动各项。
  • 实数可以看成 矩阵的迹!
  • 需要用到向量(或矩阵)对矩阵求导的情形,要么把矩阵按列拆开转化成向量对向量求导(本文后面的算例 PRML (3.33) 说明了这种方法怎么用),要么套用线性变换的求导公式(常见于神经网络的反向传播过程)。

算例

线性方程组 的最小二乘解

  • 即求解

  • 方法一:展开括号,再使用几个常用公式化简即可:

  • \begin{align*} \nabla_\boldsymbol{x} \frac{1}{2}||A\boldsymbol{x}-\boldsymbol{b}||^2_2 & = & \frac{1}{2}\nabla_\boldsymbol{x} (A\boldsymbol{x}-\boldsymbol{b})^T(A\boldsymbol{x}-\boldsymbol{b}) \\ & = & \frac{1}{2}\nabla_\boldsymbol{x}(\boldsymbol{x}^TA^TA\boldsymbol{x} - \boldsymbol{b}^TA\boldsymbol{x} - \boldsymbol{x}^TA^T\boldsymbol{b} + \boldsymbol{b}^T\boldsymbol{b}) \\ & = & \frac{1}{2}\left(\nabla_\boldsymbol{x}(\boldsymbol{x}^TA^TA\boldsymbol{x}) - 2\nabla_\boldsymbol{x}(\boldsymbol{b}^TA\boldsymbol{x}) + \nabla_\boldsymbol{x}(\boldsymbol{b}^T\boldsymbol{b}) \right)\\ & = & A^TA\boldsymbol{x} - A^T\boldsymbol{b} + \boldsymbol{0} \\ & = & A^T(A\boldsymbol{x}-\boldsymbol{b}) \end{align*}

  • 方法二:使用线性变换的求导公式 :

  • \begin{align*} \nabla_\boldsymbol{x} \frac{1}{2}||A\boldsymbol{x}-\boldsymbol{b}||^2_2 & = & \frac{1}{2}A^T\nabla_{A\boldsymbol{x}-\boldsymbol{b}} ||A\boldsymbol{x}-\boldsymbol{b}||^2_2 \\ & = & \frac{1}{2}A^T(2(A\boldsymbol{x}-\boldsymbol{b})) \\ & = & A^T(A\boldsymbol{x}-\boldsymbol{b}) \end{align*}

  • 令导数等于零,再给方程两边同时左乘 ,移项即得:

    • 这里假定方程组是超定的,即 列满秩且行数大于列数,因此上述逆矩阵存在
    • 补:如果方程组欠定但是是一致的,那么 是方程 的二范数最小的解,其中 是矩阵 的 Moore–Penrose 广义逆。

F范数的求导公式推导

  • 先转化为迹,再裂项,最后通过恰当的轮换,用迹方法的核心公式处理。

\begin{align*} \nabla ||XA^T-B||_F^2 & = & \nabla tr((XA^T-B)^T(XA^T-B)) \\ & = & \nabla tr(AX^TXA^T - B^TXA^T - AX^TB + B^TB) \\ & = & \nabla tr(AX^TXA^T) - 2tr(AX^TB) + tr(B^TB)\\ & = & 2tr(XA^TAX^TI) - 2tr(X^TBA) + O \\ & = & 2(I^TX(A^TA)^T + IX(A^TA)) - 2BA \\ & = & 2XA^TA - 2BA \\ & = & 2(XA^T-B)A \end{align*}

PRML (3.33)求导

  • 题目:求 关于 的导数

  • 说明:上面的 的结果应当是一个向量,是指对 的每个分量应用函数

  • 方法一:用矩阵的 F 范数推导

  • \begin{align*} \nabla f & = & \nabla \left(-\dfrac{\beta}{2} \sum_n ||\mathbf{t}_n - W^T\phi(\mathbf{x}_n)||^2_2 \right) \\ & = & -\dfrac{\beta}{2} \nabla ||T^T - W^T\Phi^T||_F^2 \\ & = & -\dfrac{\beta}{2} \nabla ||T - \Phi W||_F^2 \\ & = & -\dfrac{\beta}{2} \nabla ||\Phi W - T||_F^2 \\ & = & -\dfrac{\beta}{2} \Phi^T (2(\Phi W - T)) \\ & = & -\beta\Phi^T (\Phi W - T) \end{align*}

    • 上述几步的依据分别是:
      • 将若干个列向量拼成一个矩阵,因此它们的二范数平方和就等于大矩阵的 F 范数的平方
      • 矩阵转置不改变其 F 范数
      • 矩阵数乘 -1 不改变其 F 范数
      • 线性变换的求导公式 + F 范数的求导公式
      • 实数在和矩阵作数乘时位置可以任意移动
    • 有了导数,再另导数等于零,即得 的最大似然解:
  • 方法二: 将向量二范数的平方用内积代替,然后逐项展开,最后利用分块矩阵相乘消掉求和号

  • \begin{align*} \nabla f & = & \nabla \left(-\dfrac{\beta}{2} \sum_n ||\boldsymbol{t}_n - W^T\phi(\boldsymbol{x}_n)||^2_2 \right) \\ & = & -\dfrac{\beta}{2}\nabla \left(\sum_n (\boldsymbol{t}_n - W^T\phi(\boldsymbol{x}_n))^T(\boldsymbol{t}_n - W^T\phi(\boldsymbol{x}_n)) \right) \\ & = & -\dfrac{\beta}{2}\sum_n \left\{\nabla(\boldsymbol{t}_n^T\boldsymbol{t}_n) -2\nabla(\phi(\boldsymbol{x}_n)^TW\boldsymbol{t}_n) + \nabla(\phi(\boldsymbol{x}_n)^TWW^T\phi(\boldsymbol{x}_n))\right\} \\ & = & -\dfrac{\beta}{2}\sum_n \left\{O - 2\phi(\boldsymbol{x}_n)\boldsymbol{t}_n^T + \nabla(WIW^T\phi(\boldsymbol{x}_n)\phi(\boldsymbol{x}_n)^T)\right\}\\ & = & -\dfrac{\beta}{2}\sum_n \left\{- 2\phi(\boldsymbol{x}_n)\boldsymbol{t}_n^T + (\phi(\boldsymbol{x}_n)\phi(\boldsymbol{x}_n)^T)^T W I^T + (\phi(\boldsymbol{x}_n)\phi(\boldsymbol{x}_n)^T) W I\right\} \\ & = & -\dfrac{\beta}{2}\sum_n \left\{- 2\phi(\boldsymbol{x}_n)\boldsymbol{t}_n^T + 2\phi(\boldsymbol{x}_n)\phi(\boldsymbol{x}_n)^TWI\right\} \\ & = & -\beta\sum_n \left\{-\phi(\boldsymbol{x}_n)\boldsymbol{t}_n^T + \phi(\boldsymbol{x}_n)\phi(\boldsymbol{x}_n)^TW\right\} \\ & = & -\beta\sum_n \boldsymbol{\phi(\boldsymbol{x}_n)}\left\{-\boldsymbol{t}_n^T + \phi(\boldsymbol{x}_n)^TW\right\} \\ & = & -\beta\Phi^T (\Phi W - T) \end{align*}

    • 这种方法虽然比较繁琐,但是更具有一般性

    • 最后一步化简的思考过程是把对 求和视为两个分块矩阵的乘积:

      • 第一个分块矩阵共 个块,且第 个分量是 。因此第一个矩阵是

      • 第二个分块矩阵共 个块,且第 个分量是 。因此,第二个矩阵是:

      • \begin{align*} \\ \left( \begin{matrix} -\boldsymbol{t}_1^T + \phi(\boldsymbol{x}_1)^TW \\ -\boldsymbol{t}_2^T + \phi(\boldsymbol{x}_2)^TW \\ \vdots \\ -\boldsymbol{t}_N^T + \phi(\boldsymbol{x}_n)^TW \end{matrix} \right) & = & \left( \begin{matrix} \phi(\boldsymbol{x}_1)^TW \\ \phi(\boldsymbol{x}_2)^TW \\ \vdots \\ \phi(\boldsymbol{x}_n)^TW \end{matrix} \right) -\left( \begin{matrix} \boldsymbol{t}_1^T \\ \boldsymbol{t}_2^T \\ \vdots \\ \boldsymbol{t}_N^T \end{matrix} \right) \\ & = & \left( \begin{matrix} \phi(\boldsymbol{x}_1)^T \\ \phi(\boldsymbol{x}_2)^T \\ \vdots \\ \phi(\boldsymbol{x}_n)^T \end{matrix} \right)W -\left( \begin{matrix} \boldsymbol{t}_1^T \\ \boldsymbol{t}_2^T \\ \vdots \\ \boldsymbol{t}_N^T \end{matrix} \right) \\ & = & \Phi W - T \end{align*}

        • 注意上述第二个等号的推导过程也是一个分块矩阵乘法:前一项是两个分块矩阵的乘积,两个分块矩阵分别由 和 个块组成

学习仿射变换

  • 假设有 对样本点 ,需要学习一个仿射变换 ,使得变换后整个数据集上的拟合误差最小(这里不需要 和 维度相同)。即求解

    • 该问题的实际应用例如:用两种语言的单语语料各自训练了一份词向量,现在已知两种语言的一些词对互为翻译,希望将两种语言的词向量空间对齐。
  • 和前两道题目类似,本题唯一的不同之处是多了一个偏置项 。同理,本题也有两种做法,一种是把范数符号内的每个向量凑成大矩阵统一求;另一种是直接带着求和号求导,最后用分块矩阵乘法的观点把结果整合成矩阵形式。

  • 这里主要想讲的是如何处理“复制”的问题

    • 例如,在神经网络中,如果要对一个 batch 一起计算,需要在中间的隐层里把相同的偏置项加到 batch 里每个样本的隐层状态上;再比如在计算 Batch Norm 时,要给每个样本都减去当前 batch 的均值。
    • 解决办法就是乘全 1 向量!
      • 用一个长为 的全 1 行向量右乘 ,就相当于把它复制 份拼在一起
      • 有时会看到给输入 加一维常数特征 1,其实就等价于这里的偏置项右乘全 1 向量的操作
      • 这个技巧不妨直接记住,就不用每次都用分块矩阵慢慢凑了
机器学习中的矩阵、向量求导_第3张图片
image.png
  • 即每行对应一个特征,每列对应一个样本

  • 然后求导就很简单了

MLP 的反向传播

  • 以经典的 MNIST 手写数字分类问题为例,假设我们使用一个单个隐层的多层感知机来预测当前图像的类别。首先把输入图像拉伸成 维的向量 ,然后通过线性变换使其变成 的隐层向量 ,使用 sigmoid 函数进行激活得到 ;再经过一次线性变换变成维度是 的向量 ,最后用 softmax 函数预测每一个数字的概率 ,用交叉熵损失函数计算预测结果和真实结果 (one-hot 向量)之间的误差 。

  • 写成数学公式即为:

  • \begin{align*} l(W^{(1)},W^{(2)},b^{(1)}, b^{(2)}) & = & -\boldsymbol{y}^T \ln \boldsymbol{a}^{(2)} \\ \boldsymbol{a}^{(2)} & = & g(\boldsymbol{z}^{(2)}) \\ \boldsymbol{z}^{(2)} & = & W^{(2)}\boldsymbol{a}^{(1)} + \boldsymbol{b}^{(2)} \\ \boldsymbol{a}^{(1)} & = & h(\boldsymbol{z}^{(1)}) \\ \boldsymbol{z}^{(1)} & = & W^{(1)}\boldsymbol{x} + \boldsymbol{b}^{(1)} \end{align*}

    • 其中各个变量的维度是:\boldsymbol{x}\in \mathbb{R}^{n}, \boldsymbol{z}^{(1)}, \boldsymbol{b}^{(1)}, \boldsymbol{a}^{(1)} \in \mathbb{R}^p, \boldsymbol{z}^{(2)},\boldsymbol{b}^{(2)}, \boldsymbol{a}^{(2)}, \boldsymbol{y} \in \mathbb{R}^q, W^{(1)}\in\mathbb{R}^{p\times n}, W^{(2)}\in\mathbb{R}^{q\times p}
    • 激活函数 为 sigmoid 函数, 为 softmax 函数
  • 一层一层往前算:

    • ,其中分数线表示逐分量相除

      • 此式通过逐元素求导即可得到
      • 在 BP 算法中,通常将损失函数 对每一层激活前的值 的导数定义为变量

        • 在 MLP 的语境下, 为向量,与本文其他部分的符号表示略有出入
      • 注意:对于任意一种激活函数和损失函数的搭配,只要它们是分片可导的,就能按照这里的流程反向传播,计算出网络里每个参数的导数。但是如果损失函数和激活函数的搭配选得好,反向传播的求导公式形式就会非常简洁。例如本例中使用 softmax 激活 + 多类交叉熵损失函数,经过化简后最后一层的 变量形如“模型预测值 - 真值”。这个结论最好直接记住。这种搭配在广义线性模型(Generalized Linear Model)里被称作 canonical link function,详见 PRML 4.3.6 节或其他经典统计学/机器学习教材。正是因为 canonical link function 的存在,有些 BP 算法的流程里会直接写最后一层的 (模型输出值减真值),然后往前传播。就本例而言,这个结果的推导过程如下:

      • 令 (逐元素求指数),则 ,其中 表示对 的各个分量求和,结果是一个标量。于是可以用向量数乘的求导公式计算 :

      • \begin{split} \dfrac{\partial \boldsymbol a^{(2)}}{\partial \boldsymbol{u}} & = \boldsymbol{u} \dfrac{\partial \left(1/\sum\boldsymbol{u}\right)}{\partial \boldsymbol{u}^T} + \dfrac{1}{\sum\boldsymbol{u}}\dfrac{\partial \boldsymbol{u}}{\partial \boldsymbol{u}}\\ & =\boldsymbol{u} \cdot-\dfrac{1}{\left(\sum\boldsymbol{u}\right)^2}\boldsymbol{1}^T + \dfrac{1}{\sum\boldsymbol{u}} I \\ & = -\dfrac{1}{\left(\sum\boldsymbol{u}\right)^2} \boldsymbol{u}\boldsymbol{1}^T + \dfrac{1}{\sum\boldsymbol{u}} I \end{split}

        • 其中 是和 同型的全 1 向量, 是 的单位阵
      • 易见

        • 表示将括号里的向量变成一个对角矩阵,跟之前提到的 互为逆运算
      • 于是可得 softmax 函数的雅克比矩阵为:

      • \begin{split} \dfrac{\partial \boldsymbol{a}^{(2)}}{\partial \boldsymbol{z}^{(2)}} & = \dfrac{\partial \boldsymbol{a}^{(2)}}{\partial \boldsymbol{u}} \dfrac{\partial \boldsymbol{u}}{\partial \boldsymbol{z}^{(2)}} \\ & = \left[ -\dfrac{1}{\left(\sum\boldsymbol{u}\right)^2} \boldsymbol{u}\boldsymbol{1}^T + \dfrac{1}{\sum\boldsymbol{u}} I \right] \text{diag}(\boldsymbol{u}) \\ & = -\dfrac{1}{\left(\sum\boldsymbol{u}\right)^2} \boldsymbol{u}\boldsymbol{u}^T + \dfrac{1}{\sum\boldsymbol{u}} \text{diag}(\boldsymbol{u}) \\ & = -\dfrac{\boldsymbol{u}}{\sum\boldsymbol{u}} \left(\dfrac{\boldsymbol{u}}{\sum\boldsymbol{u}}\right)^T + \dfrac{1}{\sum\boldsymbol{u}} \text{diag}(\boldsymbol{u}) \\ & = -\boldsymbol{a}^{(2)} {\boldsymbol{a}^{(2)}}^T + \text{diag}(\boldsymbol{a}^{(2)}) \end{split}

      • 所以

      • \begin{split} \delta^{(2)} & = \left(\dfrac{\partial \boldsymbol{a}^{(2)}}{\partial \boldsymbol{z}^{(2)}}\right)^T \dfrac{\partial l}{\partial \boldsymbol{a}^{(2)}} \\ & = \left[ -\boldsymbol{a}^{(2)} {\boldsymbol{a}^{(2)}}^T + \text{diag}(\boldsymbol{a}^{(2)})\right]^T \left(- \dfrac{\boldsymbol{y}}{\boldsymbol{a}^{(2)}}\right) \\ & = -\boldsymbol{a}^{(2)} {\boldsymbol{a}^{(2)}}^T \cdot \left(-\dfrac{\boldsymbol{y}}{\boldsymbol{a}^{(2)}}\right) + \text{diag}(\boldsymbol{a}^{(2)}) \cdot \left(-\dfrac{\boldsymbol{y}}{\boldsymbol{a}^{(2)}}\right) \\ & = \boldsymbol{a}^{(2)} \sum \boldsymbol{y} - \boldsymbol{y} \\ & = \boldsymbol{a}^{(2)} - \boldsymbol{y} \end{split}

      • 注意上述推导仅用到了 这一性质,而没有利用 one-hot 分布这一信息。因此该结果对于任意目标概率分布 都是成立的。

    • 算出 之后,剩下的推导就比较按部就班了。使用线性变换的求导公式立即得到:

    • 再往前推一层:

        • 此式对任意激活函数都成立
        • 若激活函数 为 sigmoid 函数,则其导数为 ,于是
        • 事实上 sigmoid 函数也是 softmax 函数的特例:由 变形可得,,即 相当于对二维向量 做 softmax,然后取第一维的结果。另外也容易验证, 函数的导数表达式和 softmax 函数的雅克比矩阵的左上角 元的表达式是相容的。
    • 继续反向传播到第一层的参数:

  • 补:其他常用的 canonical link function 搭配及推导过程

    • 约定用 分别表示神经网络最后一层激活前的值、激活后的值、真值
    • 二分类中使用 sigmoid 激活函数 + 交叉熵损失函数
      • 推导:若 ,则:
    • 回归问题里使用恒等激活函数 + 最小二乘损失函数
      • 推导:若 ,则:

RNN 的梯度消失/爆炸问题

  • 通常 RNN 的状态方程的更新定义为 ( 表示一个逐元素的激活函数,例如 等),而这里我们采用 Pascanu 等人的论文 On the difficulty of training Recurrent Neural Networks 中的定义,即认为 (这两种方程其实是等价的,只是前一种表述把隐层状态定义成激活后的值,后一种表述把隐层状态定义成激活前的值,前述论文中的脚注里也有说明。这里采用后一种方式,是因为它稍微好算一点)。

  • 展开后的网络结构示意图参见 CS224d-lecture8 中的 Slide 14,这里截图展示如下:

    机器学习中的矩阵、向量求导_第4张图片
    image.png

    • 读者可以根据这个 slides 来梳理思路,了解 RNN 做反向传播的大体流程(当然也可以直接看本文后面的推导),但是这个 slides 中的计算有错,具体的计算结果慎看,小心把自己搞混!
  • 现在我们来计算损失函数 对循环连接的权重矩阵 的导数:假设每一时间步都有一个误差 (例如建立一个语言模型,每一步都要预测下一个词的概率分布,与语料库里的真实值计算交叉熵),总的误差等于每一步的误差加起来:,因此 (对一元函数来说,和的导数等于导数的和。根据多元函数偏导数的定义,很容易推广到多元函数上,进而推广到矩阵求导上)。

  • 考虑到矩阵 出现了多次,计算 需要计算 对 的每一次出现的导数,然后再求和。若用 表示 与 之间的转移矩阵 ,则 。其中第二个等号用到的是线性变换的求导公式(类似标准 BP 算法的核心步骤)

  • 然后根据雅克比矩阵的运算规则计算损失函数对隐层的导数

    • 先计算 \dfrac {\partial \boldsymbol{h}_{i+1}}{\partial \boldsymbol{h}_{i}} = \dfrac {\partial \boldsymbol{h}_{i+1}}{\partial f(\boldsymbol{h}_{i})} \dfrac {\partial f(\boldsymbol{h}_{i})}{\partial \boldsymbol{h}_{i}}= W \text{diag}(f'(\boldsymbol{h}_{i}))
      • Stanford 的讲义和前述论文中,均认为 ,这一点应该是错的,矩阵 不应该被转置,根据雅克比矩阵的定义写一个梯度检查的程序即可快速验证这一点。不过这个小错误不影响 RNN 梯度消失/爆炸现象的论证。
    • 根据多次复合的向量求导法则,得: \begin{align*} \dfrac{\partial l_t}{\partial \boldsymbol{h}^T_k} & = & \dfrac{\partial l_t}{\partial \boldsymbol{h}^T_t} \dfrac{\partial \boldsymbol{h}_{t}}{\partial \boldsymbol{h}_{t-1}} \cdots \dfrac{\partial \boldsymbol{h}_{k+1}}{\partial \boldsymbol{h}_{k}} \\ & = & \dfrac{\partial l_t}{\partial \boldsymbol{h}^T_t} W \text{diag}(f'(\boldsymbol{h}_{t-1})) \cdots W \text{diag}(f'(\boldsymbol{h}_{k})) \end{align*}
    • 将此式两边转置,再代入 中,就能得到最终结果。类似地,\dfrac{\partial l_t}{\partial \boldsymbol{b}} = \dfrac{\partial l_t}{\partial \boldsymbol{h}_t}, \dfrac{\partial l_t}{\partial U} = \dfrac{\partial l_t}{\partial \boldsymbol{h}_t}\boldsymbol{x}_t^T, \dfrac{\partial l_t}{\partial \boldsymbol{x}_t} = U^T\dfrac{\partial l_t}{\partial \boldsymbol{h}_t},这就是 vanilla RNN 的 BPTT 的公式。中间很多个隐层之间的雅克比相乘那一部分也可以用求积符号来书写,不过展开写更清楚一些。
  • 注:实践中具体计算梯度的时候,一般还是先定义一组类似于 BP 神经网络中的 的变量,使用循环逐层进行计算。这里只是为了展示向量求导的方法,强行把每一步的结果都展开了。

Autoencoder with Tied-weight

  • 求函数 对 的导数,其中 是逐元素求 Sigmoid。

  • 根据变量多次出现的求导法则计算即可( 的含义是将 此次出现视作常数):

  • 为方便计算,定义如下几个中间变量:

  • 上式右边第一项计算如下:

  • \begin{align*} \nabla_W \, l(\boldsymbol{b}_2 + W^T \sigma(W_c\boldsymbol{x} + \boldsymbol{b}_1)) & = & \left(\nabla_{W^T} l(\boldsymbol{b}_2 + W^T \sigma(W_c\boldsymbol{x} + \boldsymbol{b}_1))\right)^T \\ & = & \left(\nabla_{\boldsymbol{t}} l(\boldsymbol{t}) \; \cdot \sigma(W_c\boldsymbol{x} + \boldsymbol{b}_1)^T \right)^T \\ & = & \sigma(W_c\boldsymbol{x} + \boldsymbol{b}_1) (\nabla_{\boldsymbol{t}} l(\boldsymbol{t}))^T \end{align*}

  • 第二项计算如下:

  • \begin{align*} \nabla_W \, l(\boldsymbol{b}_2 + W_c^T \sigma(W\boldsymbol{x} + \boldsymbol{b}_1)) & = & \nabla_{\boldsymbol{u}} l(\boldsymbol{b}_2 + W_c^T \sigma(\boldsymbol{u})) \; \boldsymbol{x}^T \\ & = & (\nabla_{\boldsymbol{u}^T} l(\boldsymbol{b}_2 + W_c^T \sigma(\boldsymbol{u})))^T \; \boldsymbol{x}^T \\ & = & \left(\nabla_{\boldsymbol{t}^T} l(\boldsymbol{t}) \dfrac{\partial \boldsymbol{t}}{\partial \boldsymbol{v}} \dfrac{\partial \boldsymbol{v}}{\partial \boldsymbol{u}} \right)^T \boldsymbol{x}^T \\ & = & \left(\nabla_{\boldsymbol{t}^T} l(\boldsymbol{t})W_c^T \text{diag} (\sigma'(\boldsymbol{u}))\right)^T \boldsymbol{x}^T \\ & = & \text{diag}(\sigma'(\boldsymbol{u}))W_c\nabla_{\boldsymbol{t}} l(\boldsymbol{t}) \boldsymbol{x}^T \end{align*}

  • 其中第三个等号是多步复合函数求导的公式

  • 最终结果就是将以上两项合并起来,并去掉所有 中的下标,从略。

完整PDF

  1. https://www.mlpod.com/wp-content/uploads/2018/01/matrixvectorderivativesformachinelearning.pdf

你可能感兴趣的:(机器学习中的矩阵、向量求导)