在学习深度学习的过程中,很多次遇到了矩阵求导的问题,发现网上很多教程写的不是很好理解,记录自己的浅薄认知.
(矩阵求导有分子转置(和分子行数一样)和分母转置(和分母行数一样)两种,两种结果互为转置。本篇介绍的不太一样,因为很多教程也是混杂的(太难蚌了)。
符号
标量:\(x\)
向量:\(\mathbf{x}\) ()
矩阵:\(X\)
逐点乘积:\(\odot\)()
矩阵的迹:\(tr(X)\)
加入有两个矩阵\(A_{m\times n},B_{m\times n}\),其中一个转置乘以另一个得到矩阵\(C\),该矩阵的迹为两个矩阵对应位置的元素相乘并相加 ,可以理解为向量的点积在矩阵上的推广,即:
\[ \begin{align*} \text{tr}\left( AB^T \right) &= a_{11}b_{11} + a_{12}b_{12} + \cdots + a_{1n}b_{1n} \\ &+ a_{21}b_{21} + a_{22}b_{22} + \cdots + a_{2n}b_{2n} \\ &+ \cdots \\ &+ a_{m1}b_{m1} + a_{m2}b_{m2} + \cdots + a_{mn}b_{mn} \\ \end{align*} \]
矩阵微分规律
梯度矩阵里的微分:
假设\(A\)矩阵维度列表为\([a_1,a_2,...,a_n]\)
假设\(B\)矩阵维度列表为\([b_1,b_2,...,b_{m}]\)
\(A\)矩阵对\(B\)矩阵求偏导的结果\(C\),维度上相当于\(A\)矩阵维度列表和\(B\)矩阵维度列表连接起来
即\(C\)矩阵维度列表为\([a_1,a_2,...,a_n,b_1,b_2,...,b_{m}]\)
根据维度信息也能很方便的推导各个元素的含义,即为\(A\)矩阵的每个元素对\(B\)矩阵的每个元素求一个偏导。
当然,高维的矩阵微分应用场景有限,我们很少需要求一个矩阵关于另一个矩阵的偏导。因此这个规律可能因为博主实践较少有误。
在深度学习的场景中,一般是标量对矩阵求导,因此主要介绍标量对矩阵微分的情况。
一般对于向量,默认为列向量,\(\mathbf{x}=[x_1,x_2,...,x_n]^{T}\),我们有标量函数\(f(\mathbf{x})\),那么对应的梯度为
\[ \frac{\partial f}{\partial \mathbf{x}}=[\frac{\partial f}{\partial x_1},\frac{\partial f}{\partial x_2},..\frac{\partial f}{\partial x_n}]^\top \]
根据这个公式我们可以发现,这个梯度向量的每个元素都是函数对该元素的偏导。
因此,我们有,
\[ \partial f = (\frac{\partial f}{\partial \mathbf{x}})^\top \partial \mathbf{x} \]
对于标量对向量到梯度来说,在左边乘以其梯度的转置就可以对应得到目标的微分。
对于矩阵来说,逐点乘积\(\odot\)然后对应位置求和应该是更广泛的规律。但向量是特殊的,逐点乘积求和和转置相乘的结果是一样的。
对于函数值为标量,变量为二维矩阵的情况,函数值的微分是梯度矩阵和变量矩阵的转置乘积的迹。
\[ df(X)=tr((\frac{df(X)}{dX})^\top \cdot X) \]
雅可比矩阵
雅可比矩阵指的是向量对于向量的微分,假如我们有:
\[ F:R^{N}\to R^{M} ,\mathbf{y}=F(\mathbf{x}) \]
那么雅克比矩阵为,
\[ J_{F:\mathrm{x\to y}}= \left[ \begin {array}{c c c} \frac{\partial y_1}{\partial x_1}&&\frac{\partial y_1}{\partial x_N}\\ &&\\ \frac{\partial y_M}{\partial x_1}&&\frac{\partial y_M}{\partial x_N}\\ \end{array} \right] \]
其中第\(i\)行是\(y_i\)关于\(\mathbf{x}\)的微分的转置。
我们有一阶泰勒展开式:
\[ F({\bf{x}}+d{\bf{x}})=F({\bf{x}})+J_{F:x \to y}d{\bf{x}}+o(\|d{\bf{x}}\,\|). \]
Hessian
在向量微积分中,Hessian 矩阵用于表示标量关于向量的二阶偏导数。
假如我们有
\[ f(\mathbf{x}) : \mathbb{R}^N \to \mathbb{R} \]
那么我们有,
\[ H_{x \to f} = \frac{d^2 f}{dx \, dx^\top} = \left[ \frac{\partial f}{\partial x_i \partial x_j} \right] \]
通过定义也可以看出,Hessian 矩阵可以写成一阶导数构成的向量关于自变量的雅可比矩阵。
令\(f\)关于变量的一阶梯度为,
\[ \mathbf{a}(\mathbf{x}) = \left[ \frac{\partial f}{\partial x_i} \right] \]
那么hessian矩阵还可以写为,
\[ H_{x \to f} = \frac{d\mathbf{a}}{d\mathbf{x}} = \left[ \frac{d a_i}{d x_j} \right] = \left[ \frac{\partial f}{\partial x_i \partial x_j} \right] \]
对应的,我们也能得到二阶泰勒展开式,
\[ f(\mathbf{x} + d\mathbf{x}) = f(\mathbf{x}) + \mathbf{a}^\top d\mathbf{x} + \frac{1}{2} d\mathbf{x}^\top H_{x \to f} \, d\mathbf{x} + o(\|d\mathbf{x}\|^2) \]
这里的二次项的推导方式为:
\[ \begin{align*} &\frac{1}{2}(\partial \mathbf{a})^\top\partial \mathbf{x} \\ =&\frac{1}{2}((\frac{\partial \mathbf{a}}{\partial \mathbf{x}})^\top \partial \mathbf{x})^\top\partial \mathbf{x} \\ =&\frac{1}{2} d\mathbf{x}^\top \frac{\partial \mathbf{a}}{\partial \mathbf{x}} \ d\mathbf{x} \\ =&\frac{1}{2} d\mathbf{x}^\top H_{x \to f} d\mathbf{x} \\ \end{align*} \]
根据这个例子我们也能很容易总结规律并且推广到更多公式。(从定义出发推导式子,向量乘以自己的梯度转置获得目标的微分)
链式表达式
假设我们有,
\[ \begin{align*} y &= f(g(h(x))) \\ q &= h(x) \\ k &= g(q) \\ y &= f(k) \end{align*} \]
我们希望得到
\[ \begin{align*} &\partial y \\ =& (\frac{\partial y}{\partial k})^\top \partial k \\ =& (\frac{\partial y}{\partial k})^\top (\frac{\partial k}{\partial q})^\top \partial q \\ =& (\frac{\partial y}{\partial k})^\top (\frac{\partial k}{\partial q})^\top (\frac{\partial q}{\partial x})^\top \partial x \\ =& (\frac{\partial q}{\partial x} \frac{\partial k}{\partial q} \frac{\partial y}{\partial k})^\top \partial x \\ \end{align*} \]
所以我们有
\[ \frac{\partial y}{\partial x} = \frac{\partial q}{\partial x} \frac{\partial k}{\partial q} \frac{\partial y}{\partial k} \]
这个推导前置条件只有:向量左乘其梯度的转置就可以对应得到目标的微分。
别的布局的推导方式也类似。
在数学公式的推导中,链式法则的记忆要点为:能乘维数对就对(可能维度信息其实就包含了部分信息)。
行向量偏导形式
有一种操作把矩阵变成按列堆栈向量化\(vec\),然后进行处理,就可以利用部分在低维中的规律进行计算:
\[ vec(X)=[x_{11},x_{21},..,x_{12},x_{22},...,x_{1n},x_{2n},...,x_{nm}]^T \]
更多介绍阅读矩阵论、弗罗贝尼乌斯内积、克罗内克积等相关资料。
因为博主也不会,只是计算机系的,在深度学习里不会用到所有的数学知识。
合适做法
合适的做法还是对于矩阵的每个元素单独看梯度和贡献,然后根据指标的变化来总结公式。
比如,计算\(x_{ij}\)是如何影响\(y_{ik}\)的,然后总结梯度公式。
示例1:
\[ Y=X*A,而X \in R^{n \times p}, A \in R^{p \times m},Y \in R^{n \times m},l为标量 \\ 已知\frac{\partial l}{\partial Y},求\frac{\partial l}{\partial X} \\ 计算x_{ik}的贡献,有 \frac{\partial l}{\partial x_{ik}}=\sum_{j}a_{kj}\frac{\partial l}{\partial y_{ij}} \\ 根据维度信息(i在左侧,k在右侧)总结,得到\frac{\partial l}{\partial X}=\frac{\partial l}{\partial Y}A^T \]
tip:由于一维向量很多时候会被写为列向量,所以有的教程理解不是很方便,但如果接触过pytorch框架,会方便理解很多.