IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 动手学深度学习笔记(一) -> 正文阅读

[人工智能]动手学深度学习笔记(一)

矩阵计算


1. 标量导数

一般的标量导数表示切线的斜率

2. 亚导数

将导数拓展到不可微的函数。在函数的不可导点,将导数(斜率)取为一个范围内的任意值。

如,对于函数:
y = ∣ x ∣ y=|x| y=x

其导数可以记为:
? ∣ x ∣ ? x = { 1 i f ? x > 0 ? 1 i f ? x < 0 a i f ? x = 0 , a ∈ [ ? 1 , 1 ] \frac{\partial |x|}{\partial x}= \begin{cases} 1 & if\ x>0 \\ -1 & if\ x<0 \\ a & if\ x=0,a\in [-1,1] \end{cases} ?x?x?=??????1?1a?if?x>0if?x<0if?x=0,a[?1,1]?

函数 max ? ( x , 0 ) \max{(x,0)} max(x,0) 的导数可以记为:
? max ? ( x , 0 ) ? x = { 1 i f ? x > 0 0 i f ? x < 0 a i f ? x = 0 , a ∈ [ ? 1 , 1 ] \frac{\partial \max{(x,0)}}{\partial x}= \begin{cases} 1 & if\ x>0 \\ 0 & if\ x<0 \\ a & if\ x=0,a\in [-1,1] \end{cases} ?x?max(x,0)?=??????10a?if?x>0if?x<0if?x=0,a[?1,1]?

3. 梯度

导数在向量的拓展。

\quad 标量 x x x向量 x \boldsymbol{x} x
标量 y y y ? y ? x ( 标 量 ) \frac{\partial y}{\partial x}(标量) ?x?y? ? y ? x ( 行 向 量 ) \frac{\partial y}{\partial \boldsymbol{x}}(行向量) ?x?y?
向量 y \boldsymbol{y} y ? y ? x ( 列 向 量 ) \frac{\partial \boldsymbol{y}}{\partial x}(列向量) ?x?y? ? y ? x ( 矩 阵 ) \frac{\partial \boldsymbol{y}}{\partial \boldsymbol{x}}(矩阵) ?x?y?
  1. y y y 是标量, x = [ x 1 x 2 ? x n ] \boldsymbol{x}=\left[\begin{matrix} x_1 \\ x_2 \\\vdots \\x_n \end{matrix}\right] x=??????x1?x2??xn???????? 是向量,梯度按照如下方法计算,标量相对于一个列向量的导数是一个行向量(分子布局法),所以下面的计算都要转置。
    ? y ? x = [ ? y ? x 1 , ? y ? x 2 , ? ? , ? y ? x n ] \frac{\partial y}{\partial \boldsymbol{x}} = \left[\begin{matrix} \dfrac{\partial y}{\partial x_1}, & \dfrac{\partial y}{\partial x_2}, & \cdots, & \dfrac{\partial y}{\partial x_n} \end{matrix}\right] ?x?y?=[?x1??y?,??x2??y?,??,??xn??y??]

    如,对于 y = x 1 2 + 2 x 2 2 y=x_1^2 + 2x_2^2 y=x12?+2x22?,梯度 ? y ? x = [ 2 x 1 , 4 x 2 ] \frac{\partial y}{\partial{\boldsymbol{x}}}=\left[\begin{matrix}2x_1,4x_2\end{matrix}\right] ?x?y?=[2x1?,4x2??]

    一些梯度的计算:

    y s u m ( x ) sum(\boldsymbol{x}) sum(x) ∥ x ∥ 2 \|x\|^2 x2 ? u , v ? \langle \boldsymbol{u},\boldsymbol{v}\rangle ?u,v?
    ? y ? x \dfrac{\partial y}{\partial{\boldsymbol{x}}} ?x?y? 1 T \boldsymbol{1}^T 1T 2 x T 2\boldsymbol{x}^T 2xT u T ? v ? x + v T ? u ? x \boldsymbol{u}^T\frac{\partial \boldsymbol{v}}{\partial \boldsymbol{x}}+\boldsymbol{v}^T\frac{\partial \boldsymbol{u}}{\partial \boldsymbol{x}} uT?x?v?+vT?x?u?
  2. y = [ y 1 y 2 ? y m ] \boldsymbol{y}=\left[\begin{matrix} y_1 \\ y_2 \\\vdots \\y_m \end{matrix}\right] y=??????y1?y2??ym???????? 是矩阵, x x x 是一个标量,计算梯度的方式如下,得到的是一个列向量(分子布局法)。
    ? y ? x = [ ? y 1 ? x ? y 2 ? x ? ? y m ? x ] \frac{\partial \boldsymbol{y}}{\partial x}= \left[\begin{matrix} \dfrac{\partial y_1}{\partial x} \\ \dfrac{\partial y_2}{\partial x} \\ \vdots \\ \dfrac{\partial y_m}{\partial x} \end{matrix}\right] ?x?y?=???????????x?y1???x?y2????x?ym?????????????

  3. 对于向量 x = [ x 1 x 2 ? x n ] \boldsymbol{x}=\left[\begin{matrix} x_1 \\ x_2 \\\vdots \\x_n \end{matrix}\right] x=??????x1?x2??xn???????? 与向量 y = [ y 1 y 2 ? y m ] \boldsymbol{y}=\left[\begin{matrix} y_1 \\ y_2 \\\vdots \\y_m \end{matrix}\right] y=??????y1?y2??ym????????,其求梯度的方式如下,最终得到一个矩阵。
    ? y ? x = [ ? y 1 ? x ? y 2 ? x ? ? y m ? x ] = [ ? y 1 ? x 1 , ? y 1 ? x 2 , ? ? , ? y 1 ? x n ? y 2 ? x 1 , ? y 2 ? x 2 , ? ? , ? y 2 ? x n ? ? y m ? x 1 , ? y m ? x 2 , ? ? , ? y m ? x n ] \frac{\partial \boldsymbol{y}}{\partial \boldsymbol{x}}= \left[\begin{matrix} \dfrac{\partial y_1}{\partial \boldsymbol{x}} \\ \dfrac{\partial y_2}{\partial \boldsymbol{x}} \\ \vdots \\ \dfrac{\partial y_m}{\partial \boldsymbol{x}} \end{matrix}\right]= \left[\begin{matrix} \dfrac{\partial y_1}{\partial x_1}, & \dfrac{\partial y_1}{\partial x_2}, & \cdots, & \dfrac{\partial y_1}{\partial x_n} \\ \dfrac{\partial y_2}{\partial x_1}, & \dfrac{\partial y_2}{\partial x_2}, & \cdots, & \dfrac{\partial y_2}{\partial x_n} \\ &\vdots && \\ \dfrac{\partial y_m}{\partial x_1}, & \dfrac{\partial y_m}{\partial x_2}, & \cdots, & \dfrac{\partial y_m}{\partial x_n} \end{matrix}\right] ?x?y?=???????????x?y1???x?y2????x?ym?????????????=????????????x1??y1??,?x1??y2??,?x1??ym??,??x2??y1??,?x2??y2??,??x2??ym??,??,?,?,??xn??y1???xn??y2???xn??ym??????????????

y \boldsymbol{y} y x \boldsymbol{x} x A x \boldsymbol{Ax} Ax x T A \boldsymbol{x}^T\boldsymbol{A} xTA a u a\boldsymbol{u} au A u \boldsymbol{Au} Au
? y ? x \dfrac{\partial \boldsymbol{y}}{\partial{\boldsymbol{x}}} ?x?y? I \boldsymbol{I} I A \boldsymbol{A} A A T \boldsymbol{A}^T AT a ? u ? x a\dfrac{\partial \boldsymbol{u}}{\partial \boldsymbol{x}} a?x?u? A ? u ? x \boldsymbol{A}\dfrac{\partial \boldsymbol{u}}{\partial \boldsymbol{x}} A?x?u?
  • a a a a \boldsymbol{a} a A \boldsymbol{A} A 中都不包含 x \boldsymbol{x} x

相关链接:

  1. 矩阵求导的本质与分子布局、分母布局的本质(矩阵求导——本质篇)
  2. 矩阵求导公式的数学推导(矩阵求导——基础篇)
  3. 矩阵求导公式的数学推导(矩阵求导——进阶篇)

4. 向量链式法则

  • 标量的链式法则:

    y = f ( u ) , u = g ( x ) y=f(u),u=g(x) y=f(u),u=g(x),则 y y y 相对于 x x x 的导数可以表示为:
    ? y ? x = ? y ? u ? u ? x \frac{\partial y}{\partial x}=\frac{\partial y}{\partial u}\frac{\partial u}{\partial x} ?x?y?=?u?y??x?u?

  • 向量的链式求导法则:

    类型求导
    y y y 是标量, u u u 是标量, x \boldsymbol{x} x 是向量 ? y ? x ( 1 , n ) = ? y ? u ( 1 , ) ? u ? x ( 1 , n ) \underset{(1,n)}{\dfrac{\partial y}{\partial \boldsymbol{x}}}= \underset{(1,)}{\dfrac{\partial y}{\partial u}} \underset{(1,n)}{\dfrac{\partial u}{\partial \boldsymbol{x}}} (1,n)?x?y??=(1,)?u?y??(1,n)?x?u??
    y y y 是标量, u \boldsymbol{u} u 是向量, x \boldsymbol{x} x 是向量 ? y ? x ( 1 , n ) = ? y ? u ( 1 , k ) ? u ? x ( k , n ) \underset{(1,n)}{\dfrac{\partial y}{\partial \boldsymbol{x}}}= \underset{(1,k)}{\dfrac{\partial y}{\partial \boldsymbol{u}}} \underset{(k,n)}{\dfrac{\partial \boldsymbol{u}}{\partial \boldsymbol{x}}} (1,n)?x?y??=(1,k)?u?y??(k,n)?x?u??
    y \boldsymbol{y} y 是向量, u \boldsymbol{u} u 是向量, x \boldsymbol{x} x 是向量 ? y ? x ( m , n ) = ? y ? u ( 1 , k ) ? u ? x ( k , n ) \underset{(m,n)}{\dfrac{\partial \boldsymbol{y}}{\partial \boldsymbol{x}}}= \underset{(1,k)}{\dfrac{\partial \boldsymbol{y}}{\partial \boldsymbol{u}}} \underset{(k,n)}{\dfrac{\partial \boldsymbol{u}}{\partial \boldsymbol{x}}} (m,n)?x?y??=(1,k)?u?y??(k,n)?x?u??

例子:

  • 对于一个表达式 z = ( ? x , w ? ? y ) 2 z=(\langle \boldsymbol{x},\boldsymbol{w}\rangle - y)^2 z=(?x,w??y)2,其中 x , w ∈ R n , y ∈ R \boldsymbol{x},\boldsymbol{w}\in \mathbb{R}^n,y\in\mathbb{R} x,wRn,yR,计算 ? z ? w \dfrac{\partial z}{\partial \boldsymbol{w}} ?w?z? 的过程如下:

    1. 首先将其中的变量求导,记 a = ? x , w ? , b = a ? y , z = b 2 a=\langle \boldsymbol{x},\boldsymbol{w}\rangle,\quad b=a-y,\quad z=b^2 a=?x,w?,b=a?y,z=b2

    2. 使用链式求导对每个中间变量求导
      ? z ? w = ? z ? b ? b ? a ? a ? w = ? b 2 ? b ? ( a ? y ) ? a ? ? x , w ? ? w = 2 b ? 1 ? x T = 2 ( ? x , w ? ? y ) x T \begin{aligned} \dfrac{\partial z}{\partial \boldsymbol{w}} & = \dfrac{\partial z}{\partial b}\dfrac{\partial b}{\partial a}\dfrac{\partial a}{\partial \boldsymbol{w}} \\ & = \dfrac{\partial b^2}{\partial b}\dfrac{\partial (a-y)}{\partial a}\dfrac{\partial \langle \boldsymbol{x},\boldsymbol{w}\rangle}{\partial \boldsymbol{w}} \\ & = 2b \cdot 1 \cdot \boldsymbol{x}^T \\ & = 2(\langle \boldsymbol{x},\boldsymbol{w}\rangle -y)\boldsymbol{x}^T \end{aligned} ?w?z??=?b?z??a?b??w?a?=?b?b2??a?(a?y)??w??x,w??=2b?1?xT=2(?x,w??y)xT?

5. 自动求导

自动求导是计算一个函数在指定值上的导数,即对于一个 y = f ( x ) y=f(x) y=f(x) 的表达式,对于某一个 x = c x=c x=c f ′ ( c ) f'(c) f(c) 的值是什么。

自动求导是根据计算图进行详细计算的,也就是给定一个表达式:

  1. 首先将该表达式分解成一个一个的操作子
  2. 使用操作子就可以将整个表达式表示为一个无环图

如,对于上面例子的表达式, z = ( ? x , w ? ? y ) 2 z=(\langle \boldsymbol{x},\boldsymbol{w}\rangle - y)^2 z=(?x,w??y)2 a , b , z a,b,z a,b,z 就算单个的计算子,它们可以构成如下的计算图,其中每个圈表示一个表达式或输入。
在这里插入图片描述

构造出计算图后,根据链式求导法则:
? y ? x = ? y ? u n ? u n ? u n ? 1 ? ? u 2 ? u 1 ? u 1 ? x \dfrac{\partial y}{\partial x}=\dfrac{\partial y}{\partial u_n}\dfrac{\partial u_n}{\partial u_{n-1}}\cdots\dfrac{\partial u_2}{\partial u_{1}}\dfrac{\partial u_1}{\partial x} ?x?y?=?un??y??un?1??un????u1??u2???x?u1??

可以通过如下两种方式实现自动求导:

  1. 正向累积。先计算 ? u 1 ? x \dfrac{\partial u_1}{\partial x} ?x?u1?? ,再计算 ? u 2 ? u 1 \dfrac{\partial u_2}{\partial u_1} ?u1??u2??,之后依次向前计算
    ? y ? x = ? y ? u n ( ? u n ? u n ? 1 ( ? ( ? u 2 ? u 1 ? u 1 ? x ) ) ) \dfrac{\partial y}{\partial x}= \dfrac{\partial y}{\partial u_n} \left(\dfrac{\partial u_n}{\partial u_{n-1}} \left(\cdots \left(\dfrac{\partial u_2}{\partial u_{1}} \dfrac{\partial u_1}{\partial x} \right)\right)\right) ?x?y?=?un??y?(?un?1??un??(?(?u1??u2???x?u1??)))

    正向累计可以根据计算图,从下向上依次计算每个结点相对于下一个参数的导数。

  2. 反向累积(反向传播)。先计算 ? y ? u n \dfrac{\partial y}{\partial u_n} ?un??y? ,再计算 ? u n ? u n ? 1 \dfrac{\partial u_n}{\partial u_{n-1}} ?un?1??un??,之后依次向后计算。
    ? y ? x = ( ( ( ? y ? u n ? u n ? u n ? 1 ) ? ? ) ? u 2 ? u 1 ) ? u 1 ? x \dfrac{\partial y}{\partial x}=\left(\left( \left(\dfrac{\partial y}{\partial u_n} \dfrac{\partial u_n}{\partial u_{n-1}}\right) \cdots\right) \dfrac{\partial u_2}{\partial u_{1}}\right) \dfrac{\partial u_1}{\partial x} ?x?y?=(((?un??y??un?1??un??)?)?u1??u2??)?x?u1??

    反向累积需要根据计算图从上向下依次求导,求导过程中需要将正向计算中的结果拿来构成每个结点的求导结果并保存为中间结果。如下所示:
    在这里插入图片描述

  • 反向累积中,计算复杂度为 O ( n ) O(n) O(n),内存复杂度为 O ( n ) O(n) O(n),因为要存储正向的所有中间结果,所以更加耗费资源。
  • 正向累积中,计算一个变量的时间复杂度为 O ( n ) O(n) O(n)(即从下向上扫一遍),对于多个变量的计算会使计算复杂度非常大。内存复杂度为 O ( 1 ) O(1) O(1),不需要保存中间的结果。

6. PyTorch 自动求导

  • 若要计算 y = 2 x T x y=2\mathbf{x}^T\mathbf{x} y=2xTx 关于行向量 x \mathbf{x} x 的导数,可以通过如下步骤。

    1. 构造 x \mathbf{x} x 向量,并指定在 x.grad 中保存计算出来的梯度

      # 1. 先创建 x ,再指定 x 可以求导
      >>> x = torch.arange(4.0)
      >>> x
      tensor([0., 1., 2., 3.])
      >>> x.requires_grad_(True)
      tensor([0., 1., 2., 3.], requires_grad=True)
      >>> x.grad     #默认为 None
      
      # 2. 在创建 x 同时指定 x 可以求导
      >>> x = torch.arange(4.0, requires_grad=True)
      >>> x
      tensor([0., 1., 2., 3.], requires_grad=True)
      >>> x.grad     #默认为 None
      
    2. 利用 x \mathbf{x} x 计算 y y y

      >>> y = 2 * torch.dot(x,x)           #计算内积
      >>> y
      tensor(28., grad_fn=<MulBackward0>)  #grad_fn 保存 y 的运算信息,表明 y 是由 x 构建的
      >>> y.grad_fn
      <MulBackward0 object at 0x00000211287EEFD0>
      
    3. 调用反向传播函数 y.backward() 自动计算 y y y 关于 x \mathbf{x} x 每个分量的梯度

      >>> y.backward()
      >>> x.grad
      tensor([ 0.,  4.,  8., 12.])
      
      >>> x.grad == 4 * x
      tensor([True, True, True, True])
      

    其计算的本质就是构造出 y = f ( x ) y=f(x) y=f(x) 的表达式,上式为 y = 2 ( x 1 2 + x 2 2 + x 3 2 + x 4 2 ) y=2(x_1^2 + x_2^2 + x_3^2 + x_4^2) y=2(x12?+x22?+x32?+x42?) ,之后将向量 x \boldsymbol{x} x 中的每个值都带入计算,得到 x = [ x 1 , x 2 , ? ? , x n ] \boldsymbol{x}=\left[\begin{matrix}x_1,x_2,\cdots,x_n\end{matrix}\right] x=[x1?,x2?,?,xn??] 中每个位置的变量对应的求导公式 y ′ = f ′ ( x ) = [ f ′ ( x 1 ) , f ′ ( x 2 ) , ? ? , f ′ ( x n ) ] = [ 4 x 1 2 , 4 x 2 2 , 4 x 3 2 , 4 x 4 2 ] y'=f'(\boldsymbol{x})=\left[\begin{matrix}f'(x_1),f'(x_2),\cdots,f'(x_n)\end{matrix}\right]=\left[\begin{matrix} 4x_1^2,4x_2^2,4x_3^2,4x_4^2\end{matrix}\right] y=f(x)=[f(x1?),f(x2?),?,f(xn?)?]=[4x12?,4x22?,4x32?,4x42??],再将值带入对应位置。

  • 下面展示了计算 x x x 的累加和的梯度

    在默认情况下,PyTorch 会 累加梯度,使用 x.grad.zero_() 可以清除之前的值

    >>> x.grad.zero_()
    tensor([0., 0., 0., 0.])
    >>> x.grad
    tensor([0., 0., 0., 0.])
    
    >>> y = x.sum()
    >>> y.backward()
    >>> x.grad
    tensor([1., 1., 1., 1.])
    
  • 使用 y.backward() 计算梯度时必须保证 y 是一个标量,在数学上是不允许对非标量求导的,如下所示,一般情况下我们首先对 y 求和,求和之后是一个标量,再进行求导。

    >>> x.grad.zero_()
    >>> y = x *x
    >>> y.backward()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "D:\Applications\Anaconda\lib\site-packages\torch\tensor.py", line 221, in backward
        torch.autograd.backward(self, gradient, retain_graph, create_graph)
      File "D:\Applications\Anaconda\lib\site-packages\torch\autograd\__init__.py", line 126, in backward
        grad_tensors_ = _make_grads(tensors, grad_tensors_)
      File "D:\Applications\Anaconda\lib\site-packages\torch\autograd\__init__.py", line 50, in _make_grads
        raise RuntimeError("grad can be implicitly created only for scalar outputs")
    RuntimeError: grad can be implicitly created only for scalar outputs
    
    >>> y.sum().backward()
    >>> x.grad
    tensor([0., 2., 4., 6.])
    
  • 将某些计算移动到记录的计算图之外,即通过 y.detach() 命令使得中间变量 y y y 成为一个常数,对于包含 y y y 的表达式,当计算梯度时候会将 y y y 视为常数

    #1. 对 y 执行 detach()
    >>> x.grad.zero_()
    tensor([0., 0., 0., 0.])
    >>> y = x * x
    >>> u = y.detach()
    >>> z = u * x
    >>> z.sum().backward()
    
    >>> x.grad == u
    tensor([True, True, True, True])
    >>> x.grad
    tensor([0., 1., 4., 9.])
    
    #2. 不对 y 执行 detach()
    >>> x.grad.zero_()
    tensor([0., 0., 0., 0.])
    >>> y = x * x
    >>> z = y * x
    >>> z.sum().backward()
    >>> x.grad
    tensor([ 0.,  3., 12., 27.])
    
    #3. 因为 y 是 x 的函数,所以直接对 y 进行梯度求解没有影响,但是不能对 u 求导
    >>> x.grad.zero_()
    tensor([0., 0., 0., 0.])
    >>> y.sum().backward()
    >>> x.grad
    tensor([0., 2., 4., 6.])
    
    >>> u.sum().backward()
    RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
    
  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-07-31 16:38:15  更:2021-07-31 16:38:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/2 10:29:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码