机器学习的基本功,熟能生巧。 本文提到向量,默认是指列向量。
机器学习那些公式中的符号,无外乎标量,向量,矩阵这三种。
所谓求导,无非就是3乘3九种形式。此处请心中默数标对标,标对向,标对矩,向对标,向对向,向对矩,矩对标,矩对向,矩对矩。
这九种形式中。机器学习中常用的就是标量对向量,标量对矩阵求导,最多再加一个向量对向量。 为啥?
因为机器学习中,最后的损失函数是标量,模型参数大多是矩阵和向量。通过梯度下降更新模型就要求损失函数这个标量对矩阵或向量的导数。
至于向量对向量求导,可以作为知识扩充,因为向量对向量求导,实际上是矩阵对矩阵求导的特殊情况。
标量对向量求导,标量对矩阵求导,本质上就是标量对向量或矩阵中的每个标量元素求导,然后按某种约定排列成向量或矩阵。
向量$y$对向量$x$求导,本质上就是向量$y$中每个标量对向量$x$中的每个标量元素求导,然后按某种约定排列成矩阵。
只要认清矩阵求导本质跟多元函数求偏导是一样的,无非就是多了一个约定的排列,就没什么怕的。
来来来,我们看个例子。 假设$y$是向量,维度为$m$,$x$是向量,维度为$n$。二者之间有函数关系$y=f(x)$。
那么$y$对$x$求导,就是$m \times n$个标量对标量求导。其中一个可以表示成$\frac{\partial y_i}{\partial x_j}$。
要排列成矩阵,比较自然的有两种方式:
1、排列成$m \times n$的矩阵。 \(\frac{\partial y}{\partial x} = \begin{bmatrix} \frac{\partial y_1}{\partial x_1} & \frac{\partial y_1}{\partial x_2} & \cdots & \frac{\partial y_1}{\partial x_n} \\ \frac{\partial y_2}{\partial x_1} & \frac{\partial y_2}{\partial x_2} & \cdots & \frac{\partial y_2}{\partial x_n} \\ \vdots & \vdots & \ddots & \vdots \\ \frac{\partial y_m}{\partial x_1} & \frac{\partial y_m}{\partial x_2} & \cdots & \frac{\partial y_m}{\partial x_n} \end{bmatrix}\)
2、排列成$n \times m$的矩阵。 \(\frac{\partial y}{\partial x} = \begin{bmatrix} \frac{\partial y_1}{\partial x_1} & \frac{\partial y_2}{\partial x_1} & \cdots & \frac{\partial y_m}{\partial x_1} \\ \frac{\partial y_1}{\partial x_2} & \frac{\partial y_2}{\partial x_2} & \cdots & \frac{\partial y_m}{\partial x_2} \\ \vdots & \vdots & \ddots & \vdots \\ \frac{\partial y_1}{\partial x_n} & \frac{\partial y_2}{\partial x_n} & \cdots & \frac{\partial y_m}{\partial x_n} \end{bmatrix}\)
两种排列方式的矩阵互为转置矩阵。
第一种排列方式叫分子布局,也叫雅可比矩阵。 为啥说是分子布局呢,因为排列成的矩阵第一个维度,即行的维度,是分子向量$y$的维度。
第二种排列方式叫分母布局,也叫梯度矩阵。 为啥说是分母布局呢,因为排列成的矩阵第一个维度,即行的维度,是分母向量$x$的维度。
现在比较难受的来了,看论文公式推导时,我怎么知道是分子布局还是分母布局呢?有时候也没有标明维度。
你看你上面两个矩阵等式的左边,都是$\frac{\partial y}{\partial x}$。
这个确实是比较蛋疼。
给大家三条锦囊:
1、看说明
文章说明了什么布局的,按文章说的,别杠。
2、看领域
如果是机器学习领域,一般使用混合布局:
标量对向量、矩阵的导数,使用分母布局。
向量、矩阵对标量的导数,使用分子布局。
向量对向量的导数,使用分子布局。
这条约定,不如上面两条约定那么硬,但是一般可以先按照分子布局理解,如果理解不了,再看看是不是分母布局。
3、看符号
$\frac{\partial y^T}{\partial x}$是分母布局,
$\frac{\partial y}{\partial x^T}$是分子布局。
口号就是:分子转置是分母布局,分母转置是分子布局。哎,就是这么溜,奇变偶不变,符号看象限。
这个很奇怪,竟然用转置符号来区分布局?
别杠,记住就行了。
我还是忍不住想问,这个转置符号,为啥是$\partial y^T$,而不是$(\partial y)^T$?
其实都可以的,二者没有区别。
向量对向量求导的排列搞清楚了,标量对向量、对矩阵的导数排列就简单了。分母布局跟向量或矩阵排列一样,分子布局转置一下。
下面将会介绍三种求矩阵导数的方法。每种各有优劣,最后会说明一下具体怎么选择。
既然矩阵求导就是一堆标量求导然后排列,那么,可以将矩阵求导拆成标量求导,然后排列。 这就是定义法。
例1:
$y = x^T A x$
$y$是标量,$x$是$n$维向量,$A$是$n \times n$方阵。我们来求$y$对$x$的导数。首先,根据布局知识,用分母布局的话,结果一定是$n$维列向量。提前确定这个结果,有助于我们后续验证。
看到例1,是不是有种翻开了数学课本的感觉?哈哈。没有什么问题是一个例子解决不了的,如果有,那就两个。
展开$x^T A x$:
$x^T A x = \sum_{i=1}^n \sum_{j=1}^nx_i A_{ij} x_j$
我们取出其中包含$x_k$的项。
$\sum_{j=1}^nx_k A_{kj} x_j + \sum_{i=1}^n x_i A_{ik} x_k$
显然 $\frac{\partial y}{\partial x_k} = \sum_{j=1}^n A_{kj} x_j + \sum_{i=1}^n A_{ik} x_i$
此时,我们将上面式子翻译成自然语言:
y对$x_k$的偏导数,等于$A$的第$k$行乘以$x$,加上$A$的第$k$列乘以$x$,也即转置后的A的第$k$行乘以$x$。
那么,可以得到:
$\frac{\partial y}{\partial x} = A^T x + A x$
标量对向量求导有四个基本法则,方便我们进行化简,这里列出。
1、线性法则
$\frac{\partial (c_1f(x) + c_2g(x))}{\partial x} = c_1 \frac{\partial f(x)}{\partial x} + c_2 \frac{\partial g(x)}{\partial x}$
2、乘法法则
$\frac{\partial (f(x) g(x))}{\partial x} = \frac{\partial f(x)}{\partial x} g(x) + f(x) \frac{\partial g(x)}{\partial x}$
3、除法法则
$\frac{\partial (f(x) / g(x))}{\partial x} = \frac{\frac{\partial f(x)}{\partial x} g(x) - f(x) \frac{\partial g(x)}{\partial x}}{g(x)^2}$
4、常量法则
$\frac{\partial c}{\partial x} = 0$
注意:
以上$f$,$g$函数都必须是实值函数。法则仅适用于标量对向量求导。
请注意,本方法仅适用于标量对向量,标量对矩阵的求导。切记!切记!
我们知道标量的微分和导数有如下关系:
$df = f^\prime(x) dx$
这个法则可以推广到向量和矩阵。
$df = (\frac{\partial f}{\partial x})^T dx$
$df = tr((\frac{\partial f}{\partial X})^T dX)$
上面的公式中的$f$是实值函数,$x$是向量,$X$是矩阵,矩阵和向量的导数采用分母布局。
tr是迹函数,也就是对角线上元素的和。
初次接触这个公式:$df = tr((\frac{\partial f}{\partial X})^T dX)$ ,可能会有点懵逼。
没关系,我们举一个例子即可。
设$X$是$3 \times 2$矩阵。即: \(X = \begin{bmatrix} x_{11} & x_{12} \\ x_{21} & x_{22} \\ x_{31} & x_{32} \end{bmatrix}\)
则$dX$是$3 \times 2$矩阵。即: \(dX = \begin{bmatrix} dx_{11} & dx_{12} \\ dx_{21} & dx_{22} \\ dx_{31} & dx_{32} \end{bmatrix}\)
$\frac{\partial f}{\partial X}$是$3 \times 2$矩阵。即: \(\frac{\partial f}{\partial X} = \begin{bmatrix} \frac{\partial f}{\partial x_{11}} & \frac{\partial f}{\partial x_{12}} \\ \frac{\partial f}{\partial x_{21}} & \frac{\partial f}{\partial x_{22}} \\ \frac{\partial f}{\partial x_{31}} & \frac{\partial f}{\partial x_{32}} \end{bmatrix}\)
这里,我们使用的是分母布局。
$(\frac{\partial f}{\partial X})^T$是$2 \times 3$矩阵。即: \((\frac{\partial f}{\partial X})^T = \begin{bmatrix} \frac{\partial f}{\partial x_{11}} & \frac{\partial f}{\partial x_{21}} & \frac{\partial f}{\partial x_{31}} \\ \frac{\partial f}{\partial x_{12}} & \frac{\partial f}{\partial x_{22}} & \frac{\partial f}{\partial x_{32}} \end{bmatrix}\)
$(\frac{\partial f}{\partial X})^T dX$是$2 \times 2$矩阵。即: \((\frac{\partial f}{\partial X})^T dX = \begin{bmatrix} \frac{\partial f}{\partial x_{11}} dx_{11} + \frac{\partial f}{\partial x_{21}} dx_{21} + \frac{\partial f}{\partial x_{31}} dx_{31} & \cdots \\ \cdots & \frac{\partial f}{\partial x_{12}} dx_{12} + \frac{\partial f}{\partial x_{22}} dx_{22} + \frac{\partial f}{\partial x_{32}} dx_{32} \\ \end{bmatrix}\)
显然,该矩阵的迹是: \(tr((\frac{\partial f}{\partial X})^T dX) = \frac{\partial f}{\partial x_{11}} dx_{11} + \frac{\partial f}{\partial x_{21}} dx_{21} + \frac{\partial f}{\partial x_{31}} dx_{31} + \frac{\partial f}{\partial x_{12}} dx_{12} + \frac{\partial f}{\partial x_{22}} dx_{22} + \frac{\partial f}{\partial x_{32}} dx_{32}\)
这正是$df$的表达式。
上面的公式是通过观察得来的一个结果,不是推导出来的。
不要想太多,记住就行。
这里矩阵$X$不必是方阵,稍微留心就可以发现。举的例子也刻意选了非方阵。
上面的公式给了我们什么启发呢?
如果我们能通过推导$df$,将其变形成$tr(U^T dX)$的形式,那么,$\frac{\partial f}{\partial X}$就是$U$。
这就是矩阵微分求导的精髓。
为了能做到这一点。我们需要矩阵微分的一些运算法则和迹的一些运算法则。
矩阵微分的运算法则:
1、加减法则:
$d(X \pm Y) = dX \pm dY$
2、乘法法则:
$d(XY) = (dX)Y + X(dY)$
3、转置法则:
$d(X^T) = (dX)^T$
4、微分的迹:
$d(tr(X)) = tr(dX)$
5、微分哈达玛积:
$d(X \odot Y) = dX \odot Y + X \odot dY$
6、逐元素求导:
$d \sigma(X) =\sigma’(X) \odot dX$
7、微分逆:
$d(X^{-1}) = -X^{-1} dX X^{-1}$
8、微分行列式:
$d\vert X \vert = \vert X \vert tr(X^{-1} dX)$
9、常量的微分:
$d(c) = 0$
迹的运算法则:
1、迹的加减:
$tr(A \pm B) = tr(A) \pm tr(B)$
2、迹的交换律:
$tr(AB) = tr(BA)$
需要满足$A$和$B^T$的维度相同。
3、迹的转置:
$tr(A^T) = tr(A)$
4、迹的迹:
$tr(A) = tr(A^T)$
5、标量的迹:
$tr(c) = c$
6、矩阵乘法和迹交换:
$tr((A\odot B)^T C) = tr(A^T (B\odot C))$
法则有了。
咱们来看个例子。
$y = x^T A x$
$y$是标量,$x$是$n$维向量,$A$是$n \times n$矩阵。我们来求$y$对$A$的导数。
第一步加微分:
$dy = d(x^T A x)$
第二步利用矩阵微分运算法则和迹运算法则: 因为是求对$A$的导数,所以$A$是自变量,$x$是常量。
\[\begin{aligned} dy &= d(x^T A x) \\ &=x^T dA x + x^T A dx + dx^T A x \\ &=x^T dA x \\ &=tr(x^T dA x ) \\ &=tr(dA x x^T) \\ &=tr(x x^T dA) \end{aligned}\]据此,可以得到:
$\frac{\partial y}{\partial A} = x x^T$
还是上面的例子,我们来求$y$对$x$的导数。
第一步加微分:
$dy = d(x^T A x)$
第二步利用矩阵微分运算法则和迹运算法则:
因为$x$是自变量,$A$是常量。
\[\begin{aligned} dy &= d(x^T A x) \\ &=d(x^T) A x + x^T A d(x) \\ &=tr(d(x^T) A x) + tr(x^T A dx) \\ &=tr((Ax)^T dx) + tr(x^T A dx) \\ &=tr(x^T A^T dx) + tr(x^T A dx) \\ &=tr(x^T (A^T + A) dx) \\ \end{aligned}\]据此,可以得到:
$\frac{\partial y}{\partial x} = (A^T + A)x$
和之前按照定义法得到的结果一致。
如果对上面的运算有卡壳的地方,可以对照微分和迹的运算法则仔细推敲一下。
当自变量和因变量有多层的依赖关系时,使用链式法则可以简化求导过程。
我们知道标量对标量求导中,链式法则如下:
设$y = f(x)$,$x = g(z)$,则$y = f(g(z))$。
则$y$对$z$的导数为:
$\frac{\partial y}{\partial z} = \frac{\partial y}{\partial x} \frac{\partial x}{\partial z}$
但是对应到矩阵求导。这个链式法则略复杂。我们先直接给出三个结论,然后就其中比较复杂的结论给个解释。
设$x\rightarrow y\rightarrow z$,其中的$x,y,z$都是向量。则$z$对$x$的导数为:
$\frac{\partial z}{\partial x} = \frac{\partial z}{\partial y} \frac{\partial y}{\partial x}$
这里要注意的是,整个依赖链中,都要是向量,如果中间加入一个矩阵,该链式法则就失灵了。
比如这种情况。
$x\rightarrow A\rightarrow y\rightarrow z$
提醒一下,上面的约定排列一节,我们说机器学习中,通常会使用混合布局。该条法则就是个实际的例子。 该法则中,标量对向量导数我们用分母布局,向量对向量导数我们用分子布局。
这个法则,在机器学习中更加常用。因为我们的损失函数是标量。此时上面的向量对向量的链式法则,是没办法用的。
我们希望向量对向量的链式法则在这种情况下仍然有效。但是很遗憾,并不行。
设$x\rightarrow y\rightarrow z$,其中的$x$是m维向量,$y$是n维向量,$z$是标量。如果按照向量对向量的链式法则,$z$对$x$的导数为:
$\frac{\partial z}{\partial x} = \frac{\partial z}{\partial y} \frac{\partial y}{\partial x}$
$\frac{\partial z}{\partial x}$是$m \times 1$矩阵
$\frac{\partial z}{\partial y}$是$n \times 1$矩阵,$\frac{\partial y}{\partial x}$是$n \times m$矩阵,二者没办法相乘。
细心观察一下,如果能把标量求导的部分做一个转置,就正确了。
$(\frac{\partial z}{\partial x})^T = (\frac{\partial z}{\partial y})^T \frac{\partial y}{\partial x}$
也就是说,标量对向量求导的链式法则,只需要把标量求导的部分做一个转置就行,最后得到的结果,就是标量对向量的导数的转置,只要再转置一下就是我们想要的结果。
对于$x\rightarrow y_1 \rightarrow y_2 \rightarrow \cdots \rightarrow y_n \rightarrow z$,标量对向量的链式法则为:
$(\frac{\partial z}{\partial x})^T = (\frac{\partial z}{\partial y_n})^T (\frac{\partial y_n}{\partial y_{n-1}}) \cdots (\frac{\partial y_2}{\partial y_1}) (\frac{\partial y_1}{\partial x})$
这是标量对向量求导的链式法则的第一种形式。
这种形式的好处是好记。只要在记得所有标量求导上加一个转置即可。不方便的地方在于求出的并不直接是导数,而是转置后的导数。
所以,就有了第二种形式,我们直接把结果写成导数的形式。
$\frac{\partial z}{\partial x} = (\frac{\partial y_n}{\partial y_{n-1}} \cdots \frac{\partial y_2}{\partial y_1} \frac{\partial y_1}{\partial x})^T \frac{\partial z}{\partial y_n}$
下面,我们用个例子,最典型的就是最小二乘法。
$l = (X\theta - y)^T (X\theta - y)$
设$X\theta - y = e$,则$l = e^T e$
则$l$对$\theta$的导数为:
$\frac{\partial l}{\partial \theta} = (\frac{\partial e}{\partial \theta})^T\frac{\partial l}{\partial e}$
这是完全套上面的链式法则得来的。
$\frac{\partial e}{\partial \theta} = X$
$\frac{\partial l}{\partial e} = 2e$
上面两个结论,可以使用定义法推导出来。
所以:
$\frac{\partial l}{\partial \theta} = 2X^T (X\theta - y)$
标量对矩阵的链式法则,并不存在。这个真的让人沮丧。因为在深度学习中,这种情况非常常见。
但是有两个好消息:
1、我们可以用pytorch,jax这些框架,自动求导。
2、对一些简单的线性组合,还是有几个结论用的。
$z = f(Y), Y = AX + B \rightarrow \frac{\partial z}{\partial X} = A^T \frac{\partial z}{\partial Y}$
$z = f(Y), Y = XA + B \rightarrow \frac{\partial z}{\partial X} = \frac{\partial z}{\partial Y}A^T$
$z=f(y), y = Ax+b \rightarrow \frac{\partial z}{\partial x} = A^T \frac{\partial z}{\partial y}$
$z = f(y), y = Xa + b \rightarrow \frac{\partial z}{\partial X} = \frac{\partial z}{\partial y} a^T$
遇到矩阵求导时,
第一,定下来求导类型。就是开头提到的九种。
第二,定下来求导布局,就是开头提到的两种。如果是机器学习领域,建议使用本文提的混合布局约定。
第三,看看能不能用矩阵微分。
第四,看看能不能用链式求导。
第五,如果以上都行不通,就使用定义法。
实际中,可能要几种方法综合使用,熟能生巧,多练就好。