《动手学深度学习》—— Chapter 2 预备知识 2.4&2.5&2.6&2.7

文章介绍了微积分在机器学习中的应用,包括模型优化和泛化,详细阐述了导数的概念及其几何意义,并给出了Python中配置绘图函数的示例。接着讨论了亚导数和梯度的概念,以及如何在向量和多变量函数中扩展导数。自动微分部分解释了正向累积和反向传递两种模式,以及如何在PyTorch中实现自动求导。最后,文章简要介绍了概率论的基础知识,包括随机变量、联合概率、条件概率和贝叶斯定理,以及期望和方差的计算。
摘要由CSDN通过智能技术生成

2.4 微积分

可以将拟合模型的任务分解为两个关键问题:

  • 优化(optimization):用模型拟合观测数据的过程;
  • 泛化(generalization):数学原理和实践者的智慧,能够指导我们生成出有效性超出用于训练的数据集本身的模型。
2.4.1 标量导数

导数实际上就是极限,其几何意义就是切线的斜率,可以看作在某点的瞬时变化率。
给定! y = f ( x ) y=f(x) y=f(x),其中 x x x y y y分别是函数 f f f的自变量和因变量。一下表达式是等价的:
f ′ ( x ) = y ′ = d y d x = d f d x = d d x f ( x ) = D f ( x ) = D x f ( x ) , f'(x)=y'=\dfrac{dy}{dx}=\dfrac{df}{dx}=\dfrac d{dx}f(x)=Df(x)=D_xf(x),\quad f(x)=y=dxdy=dxdf=dxdf(x)=Df(x)=Dxf(x),
常用函数求导规则及求导法则:

y y y a a a x n x^n xn e x e^x ex l o g ( x ) log(x) log(x) u + v u+v u+v u v uv uv y = f ( u ) , u = g ( x ) y=f(u),u=g(x) y=f(u),u=g(x)
d y d x \dfrac{dy}{dx} dxdy0 n x n − 1 nx^{n-1} nxn1 e x e^x ex 1 x \frac{1}{x} x1 d u d x + d v d x \dfrac{du}{dx}+\dfrac{dv}{dx} dxdu+dxdv d u d x v + d v d x u \dfrac{du}{dx}v+\dfrac{dv}{dx}u dxduv+dxdvu d y d u d u d x \dfrac{dy}{du}\dfrac{du}{dx} dudydxdu链式法则

其中 a a a为标量; u , v u,v u,v为关于 x x x的函数。

书中关于Python配置matplotlib生成图形的属性所定义的几个函数:
其中注释#@save是一个特殊的标记,会将对应的函数、类或语句保存在d2l包中

def use_svg_display():  #@save
    """使用svg格式在Jupyter中显示绘图"""
    backend_inline.set_matplotlib_formats('svg')
def set_figsize(figsize=(3.5, 2.5)):  #@save
    """设置matplotlib的图表大小"""
    use_svg_display()
    d2l.plt.rcParams['figure.figsize'] = figsize 
#可以直接使用d2l.plt,是因为导入语句 from matplotlib import pyplot as plt已标记为保存到d2l包中。
#@save
def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
    """设置matplotlib的轴"""
    axes.set_xlabel(xlabel)
    axes.set_ylabel(ylabel)
    axes.set_xscale(xscale)
    axes.set_yscale(yscale)
    axes.set_xlim(xlim)
    axes.set_ylim(ylim)
    if legend:
        axes.legend(legend)
    axes.grid()
#@save
def plot(X, Y=None, xlabel=None, ylabel=None, legend=None, xlim=None,
         ylim=None, xscale='linear', yscale='linear',
         fmts=('-', 'm--', 'g-.', 'r:'), figsize=(3.5, 2.5), axes=None):
    """绘制数据点"""
    if legend is None:
        legend = []

    set_figsize(figsize)
    axes = axes if axes else d2l.plt.gca()

    # 如果X有一个轴,输出True
    def has_one_axis(X):
        return (hasattr(X, "ndim") and X.ndim == 1 or isinstance(X, list)
                and not hasattr(X[0], "__len__"))

    if has_one_axis(X):
        X = [X]
    if Y is None:
        X, Y = [[]] * len(X), X
    elif has_one_axis(Y):
        Y = [Y]
    if len(X) != len(Y):
        X = X * len(Y)
    axes.cla()
    for x, y, fmt in zip(X, Y, fmts):
        if len(x):
            axes.plot(x, y, fmt)
        else:
            axes.plot(y, fmt)
    set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend)

画图示例:绘制函数 u = f ( x ) = 3 x 2 − 4 x u=f(x)=3x^2-4x u=f(x)=3x24x及其在 x = 1 x=1 x=1处的切线 y = 2 x − 3 y=2x-3 y=2x3, 其中系数2是切线的斜率。

x = np.arange(0, 3, 0.1)
plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)'])

image.png

2.4.2 亚导数
  • 将导数拓展到不可微的函数,例如
    ∂ ∣ x ∣ ∂ x = { 1 if  x > 0 − 1 if  x < 0 a if  x = 0 , a ∈ [ − 1 , 1 ] \dfrac{\partial\left|x\right|}{\partial x}=\begin{cases}1&\text{if }x>0\\ -1&\text{if }{x<0}\\ a&\text{if }{x=0},\quad a\in[-1,1]\end{cases} xx= 11aif x>0if x<0if x=0,a[1,1]

    ∂ ∂ x max ⁡ ( x , 0 ) = { 1 if  x > 0 0 if  x < 0 a if  x = 0 , a ∈ [ 0 , 1 ] \dfrac{\partial}{\partial x}\max(x,0)=\begin{cases}1&\text{if }x>0\\ 0&\text{if }x<0\\ a&\text{if }x=0,&a\in[0,1]\end{cases} xmax(x,0)= 10aif x>0if x<0if x=0,a[0,1]

2.4.3 梯度
  • 将导数拓展到向量,广义定义是分三种情况:函数或自变量分别或同时为向量的情况;

  • 通常数学中的定义是:一个多元函数对其所有变量的偏导数,
    ∇ x f ( x ) = [ ∂ f ( x ) ∂ x 1 , ∂ f ( x ) ∂ x 2 , … , ∂ f ( x ) ∂ x n ] ⊤ ; \nabla_{\mathbf{x}}f(\mathbf{x})=\left[\dfrac{\partial f(\mathbf{x})}{\partial x_1},\dfrac{\partial{f(\mathbf{x})}}{\partial{x_2}},\ldots,\dfrac{\partial{f({\mathbf{x}})}}{\partial{x_n}}\right]^{\top}; xf(x)=[x1f(x),x2f(x),,xnf(x)];

  • 梯度向量的方向指向函数值增加最快的方向,其大小表示函数值增加的速率;

梯度大小: ∣ ∇ f ( x , y ) ∣ = ( ∂ f ∂ x ) 2 + ( ∂ f ∂ y ) 2 , 梯度方向: θ ( x , y ) = tan ⁡ − 1 ( ∂ f ∂ y ∂ f ∂ x ) . \text{梯度大小:}|\nabla f(x,y)| = \sqrt{\left(\frac{\partial f}{\partial x}\right)^2 + \left(\frac{\partial f}{\partial y}\right)^2},\quad \text{梯度方向:}\theta(x,y) = \tan^{-1}\left(\frac{\frac{\partial f}{\partial y}}{\frac{\partial f}{\partial x}}\right). 梯度大小:∣∇f(x,y)=(xf)2+(yf)2 ,梯度方向:θ(x,y)=tan1(xfyf).

y y y a a a a u au au ∑ ( x ) \sum (x) (x) ∣ x ∣ 2 |x|^2 x2 u + v u+v u+v u v uv uv < u , v > <u,v> <u,v>
d y d x \dfrac{dy}{d\mathbf{x}} dxdy 0 T \mathbf{0}^T 0T a ∂ u ∂ x a\frac{\partial u}{\partial \mathbf{x}} axu 1 T \mathbf{1}^T 1T 2 x T 2\mathbf{x}^T 2xT ∂ u ∂ x + ∂ v ∂ x \dfrac{\partial u}{\partial \mathbf{x}}+\dfrac{\partial v}{\partial \mathbf{x}} xu+xv ∂ u ∂ x v + ∂ v ∂ x u \dfrac{\partial u}{\partial \mathbf{x}}v+\dfrac{\partial v}{\partial \mathbf{x}}u xuv+xvu u T ∂ v ∂ x + v T ∂ u ∂ x \mathbf{u}^T\dfrac{\partial \mathbf{v}}{\partial \mathbf{x}}+\mathbf{v}^T\dfrac{\partial \mathbf{u}}{\partial \mathbf{x}} uTxv+vTxu

注意: d y d x \dfrac{dy}{d\mathbf{x}} dxdy向量, d y d x \dfrac{d\mathbf{y}}{dx} dxdy向量。这个被称为分子布局符号,反过来的版本叫分母布局符号

y \mathbf{y} y a \mathbf{a} a x \mathbf{x} x A x A\mathbf{x} Ax x T A \mathbf{x}^TA xTA a u a\mathbf{u} au A u A\mathbf{u} Au u + v \mathbf{u}+\mathbf{v} u+v
d y d x \dfrac{d\mathbf{y}}{d\mathbf{x}} dxdy 0 \mathbf{0} 0 I \mathbf{I} I A A A A T A^T AT a ∂ u ∂ x a\frac{\partial \mathbf{u}}{\partial \mathbf{x}} axu A ∂ u ∂ x A\dfrac{\partial \mathbf{u}}{\partial \mathbf{x}} Axu ∂ u ∂ x + ∂ v ∂ x \dfrac{\partial u}{\partial \mathbf{x}}+\dfrac{\partial v}{\partial \mathbf{x}} xu+xv

其中, I \mathbf{I} I为Identical矩阵。

2.4.5 总结

image.png
个人记忆方法:因为这是分子布局符号,所以导数的前几维的大小要与对应分子 y y y的维度大小一致。而分母 x x x的维度大小要调换个位置。

2.5 自动微分

2.5.1 理论
  • 深度学习框架中用于加快求导;自动求导计算一个函数在指定值上的导数。与数学符号求导以及数值方法求导不同。
  • 实际中,根据设计好的模型,系统会构建一个计算图(computational graph), 来跟踪计算是哪些数据通过哪些操作组合起来产生输出。 自动微分使系统能够随后反向传播梯度。 这里,反向传播(backpropagate)意味着跟踪整个计算图,填充关于每个参数的偏导数。
  • 计算图:
    • 将代码分解成操作子
    • 将计算表示成一个无环图

image.png

  • 显示构造:Tensorflow/Theano/MXNet
  • 隐式构造:Pytorch/MXNet
  • 自动求导的两种模式:正向累积、反向传递
    • 链式法则: ∂ y ∂ x = ∂ y ∂ u n ∂ u n ∂ u n − 1 . . . ∂ u 2 ∂ u 1 ∂ u 1 ∂ x \frac{\partial y}{\partial x}=\frac{\partial y}{\partial u_n}\frac{\partial u_n}{\partial u_{n-1}}...\frac{\partial u_2}{\partial u_1}\frac{\partial u_1}{\partial x} xy=unyun1un...u1u2xu1
    • 正向累积: ∂ y ∂ x = ∂ y ∂ u n ( ∂ u n ∂ u n − 1 ( ⋯ ( ∂ u 2 ∂ u 1 ∂ u 1 ∂ x ) ) ) \begin{aligned}\frac{\partial y}{\partial x}=\frac{\partial y}{\partial u_n}\left(\frac{\partial u_n}{\partial u_{n-1}}\left(\cdots\left(\frac{\partial u_2}{\partial u_1}\frac{\partial u_1}{\partial x}\right)\right)\right)\end{aligned} xy=uny(un1un((u1u2xu1)))
      • (从右到左、从前到后)(计算图中是从下到上)需要存储中间结果
    • 反向传递(反向累积): ∂ y ∂ x = ∂ y ∂ u n ( ∂ u n ∂ u n − 1 ( ⋯ ( ∂ u 2 ∂ u 1 ∂ u 1 ∂ x ) ) ) \begin{aligned}\frac{\partial y}{\partial x}=\frac{\partial y}{\partial u_n}\left(\frac{\partial u_n}{\partial u_{n-1}}\left(\cdots\left(\frac{\partial u_2}{\partial u_1}\frac{\partial u_1}{\partial x}\right)\right)\right)\end{aligned} xy=uny(un1un((u1u2xu1)))
      • (从左到右,从后到前)(计算图中是从上到下)
      • 需要去除计算图中不必要的枝
      • 一般对于输入数据会先正向计算结果,再反向计算梯度,正向计算时会保存所有的中间变量
      • 复杂度:
        • 计算复杂度: O ( n ) O(n) O(n) n n n是操作子个数;正反向代价类似
        • 内存复杂度: O ( n ) O(n) O(n),因为需要存储正向的所有中间结果(深度学习耗GPU资源的根源)
        • 与正向累积对比:
          • 计算复杂度: O ( n ) O(n) O(n),计算一个变量的梯度
          • 内存复杂度: O ( 1 ) O(1) O(1),因为需要存储正向的所有中间结果
    • image.png
2.5.2 一个例子
  1. 假设我们想对函数 y = 2 x T x y=2\mathbf{x}^T\mathbf{x} y=2xTx关于列向量 x \mathbf{x} x求导。 首先,我们创建变量x并为其分配一个初始值。
import torch

x = torch.arange(4.0)
x

x.requires_grad_(True)  # 表示需要开放区域来存储梯度
#等价于x=torch.arange(4.0,requires_grad=True)
x.grad  # 存储关于x的梯度,默认值是None 
y = 2 * torch.dot(x, x) #y的表达式
y

注释:grad_fn=<MulBackward0>表示该张量是由哪个计算图节点计算得来的,以便在反向传播时构建计算图。其中,MulBackward0表示该张量是通过一个乘法操作计算得来的,并且是计算图中的第一个反向传播节点(即从后往前数的第0个节点)。在PyTorch中,每个张量都有一个grad_fn属性,用于记录该张量是如何计算得来的。对于用户创建的张量,其grad_fn属性为None。

  1. 接下来,通过调用反向传播函数来自动计算y关于x每个分量的梯度,并打印这些梯度。
y.backward()
x.grad

注释:backward()用于计算张量的梯度。该梯度会被存储在张量的.grad属性中。一般在深度学习中,在计算梯度之前,我们需要先定义一个损失函数,然后将该损失函数作为参数传递给backward()函数。

  1. 现在计算x的另一个函数
# 在默认情况下,PyTorch会累积梯度,我们需要清除之前的值
x.grad.zero_()
y = x.sum()
y.backward()
x.grad
2.5.3 非标量变量的反向传播

由于在深度学习中,一般是对损失函数的进行反向传递,而损失函数一般是标量,因此不是计算微分矩阵,而是单独计算批量中每个样本的偏导数之

# 对非标量调用backward需要传入一个gradient参数,该参数指定微分函数关于self的梯度。
# 本例只想求偏导数的和,所以传递一个1的梯度是合适的
x.grad.zero_()
y = x * x # y为一个矩阵
# 等价于y.backward(torch.ones(len(x)))
y.sum().backward() # y.sum()后为标量
x.grad
2.5.4 分离计算

由于某种原因,希望将y视为一个常数, 并且只考虑到x在y被计算后发挥的作用

x.grad.zero_()
y = x * x
u = y.detach() # 分离y来返回一个新变量u,将u作为常数处理
z = u * x

z.sum().backward()
x.grad == u

由于记录了y的计算结果,我们可以随后在y上调用反向传播, 得到y=x*x关于的x的导数,即2*x。

x.grad.zero_()
y.sum().backward()
x.grad == 2 * x
2.5.5 Python控制流的梯度计算

复杂的Python控制流也能进行自动求导

def f(a):
    b = a * 2
    while b.norm() < 1000:
        b = b * 2
    if b.sum() > 0:
        c = b
    else:
        c = 100 * b
    return c

a = torch.randn(size=(), requires_grad=True)
d = f(a)
d.backward()

2.6 概率

2.6.1 基本概率论
  1. 概率论公理
  • **抽样(sampling):**从概率分布中抽取样本的过程。
  • 在处理骰子掷出时,我们将集合 S = { 1 , 2 , 3 , 4 , 5 , 6 } \mathcal{S}=\{1,2,3,4,5,6\} S={1,2,3,4,5,6}称为样本空间(sample space)结果空间(outcome space), 其中每个元素都是结果(outcome)
  • **事件(event)**是一组给定样本空间的随机结果。 例如,“看到5”( { 5 } \{5\} {5})是掷出骰子的有效事件。
  • 概率(probability):将集合映射到真实值的函数。 在给定的样本空间 S \mathcal{S} S中,事件A的概率, 表示为 P ( A ) P(A) P(A)满足以下属性:
    • 非负性: P ( A ) ≥ 0 P(A)\geq 0 P(A)0
    • P ( S ) ≥ 0 P(S)\geq 0 P(S)0,整个样本空间的概率为1;
    • P ( ⋃ i = 1 ∞ A i ) = ∑ i = 1 ∞ P ( A i ) P(\bigcup_{i=1}^\infty{A}_i)=\sum_{i=1}^{\infty}P({A}_i) P(i=1Ai)=i=1P(Ai),其中 A i A_i Ai互斥。
  1. 随机变量
  • 考虑一个随机变量(random variable) X \mathbf{X} X,其值在掷骰子的样本空间 S = { 1 , 2 , 3 , 4 , 5 , 6 } \mathcal{S}=\{1,2,3,4,5,6\} S={1,2,3,4,5,6}中。可将事件“看到一个5”表示为 { X = 5 } \{\mathbf{X}=5\} {X=5} X = 5 \mathbf{X}=5 X=5,其概率表示为 P ( { X = 5 } ) P(\{\mathbf{X}=5\}) P({X=5}) P ( X = 5 ) P(\mathbf{X}=5) P(X=5)
  • 为了简化符号,一方面,我们可以将 P ( X ) P(\mathbf{X}) P(X)表示为随机变量 X \mathbf{X} X上的分布(distribution): 分布告诉我们获得某一值的概率。 X \mathbf{X} X可以用具体数取代,也可以显示 X \mathbf{X} X的可取范围。
2.6.2 处理多个随机变量
  1. 联合概率(joint probability)
  • P ( A = a , B = b ) P(A=a,B=b) P(A=a,B=b) P ( A , B ) P(A,B) P(A,B)(紧凑表示法);
  • 含义:给定任意值a和b, P ( A = a ) P(A=a) P(A=a) P ( B = b ) P(B=b) P(B=b)同时满足的概率;
  • P ( A = a , B = b ) ≤ P ( A = a ) P(A=a,B=b)\leq P(A=a) P(A=a,B=b)P(A=a) P ( A = a , B = b ) ≤ P ( A = a ) P(A=a,B=b)\leq P(A=a) P(A=a,B=b)P(A=a)
  1. 条件概率(conditional probability)
  • P ( B = b ∣ A = a ) = P ( A = a , B = b ) P ( A = a ) P(B=b\mid A=a)=\frac{P(A=a,B=b)}{P(A=a)} P(B=bA=a)=P(A=a)P(A=a,B=b)
  • 含义: A = a A=a A=a已发生时, B = b B=b B=b的概率。
  1. 贝叶斯定理(Bayes’ theorem)
  • 乘法法则(multiplication rule): P ( A , B ) = P ( B ∣ A ) P ( A ) P(A,B)=P(B\mid A)P(A) P(A,B)=P(BA)P(A) P ( A , B ) = P ( A ∣ B ) P ( B ) P(A,B)=P(A \mid B)P(B) P(A,B)=P(AB)P(B);
  • 假设 P ( B = b ) > 0 P(B=b)>0 P(B=b)>0 P ( A ∣ B ) = P ( B ∣ A ) P ( A ) P ( B ) P(A\mid B)=\dfrac{P(B\mid A)P(A)}{P(B)} P(AB)=P(B)P(BA)P(A)
  1. 边际化
  • 求和法则(sum rule): P ( B ) = ∑ A P ( A , B ) P(B)=\sum_A P(A,B) P(B)=AP(A,B);
  • 上述公式也被称为边际化,边际化结果的概率或分布称为边际概率(marginal probability)边际分布(marginal distribution) P ( A ∣ B ) = P ( A ) P(A\mid B)=P(A) P(AB)=P(A);
  1. 独立性
  • 如果两个随机变量 A A A B B B独立的,意味着事件 A A A的发生跟 B B B事件的发生无关。表示为 A ⊥ B A\perp B AB;
  • 两个随机变量是独立的,当且仅当两个随机变量的联合分布是其各自分布的乘积。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-svkOtok4-1680445654846)(null#card=math&code=P(A,B)]=P(A)P(B)&id=IShhX);
  • 反之则称为依赖
  • 两个随机变量 A A A B B B条件独立的,当且仅当 P ( A , B ∣ C ) = P ( A ∣ C ) P ( B ∣ C ) P(A,B\mid C)=P(A\mid C)P(B\mid C) P(A,BC)=P(AC)P(BC)。表示 A ⊥ B ∣ C A\perp B\mid C ABC
2.6.3 期望和方差
  • 期望(expectation,或平均值(average))

    • E [ X ] = ∑ x x P ( X = x ) ; E[X]=\sum_x xP(X=x); E[X]=xxP(X=x);
    • E x ∼ P [ f ( x ) ] = ∑ x f ( x ) P ( x ) . E_{x\sim P}[f(x)]=\sum_x f(x)P(x). ExP[f(x)]=xf(x)P(x).
  • 方差

    • Var ⁡ [ X ] = E [ ( X − E [ X ] ) 2 ] = E [ X 2 ] − E [ X ] 2 \operatorname{Var}[X]=E\left[(X-E[X])^2\right]=E[X^2]-E[X]^2 Var[X]=E[(XE[X])2]=E[X2]E[X]2;
    • Var ⁡ [ f ( x ) ] = E [ ( f ( x ) − E [ f ( x ) ] ) 2 ] \operatorname{Var}[f(x)]=E\Big[(f(x)-E[f(x)])^2\Big] Var[f(x)]=E[(f(x)E[f(x)])2];
    • 方差的平方根被称为标准差(standard deviation)

2.7 查阅文档

  1. 查找模块中所有函数和类

dir():了解模块中可以调用哪些函数和类

import torch

print(dir(torch.distributions)) # 查询随机数生成模块中的所有属性

PS:通常可以忽略以__(双下划线)开始和结束的函数——Python中的特殊对象, 或以单个_(单下划线)开始的函数——通常是内部函数。

  1. 查找特定函数和类的用法
  • help():了解给定函数或类更具体的使用说明
help(torch.ones) # 查看张量ones函数的用法
  • 在Jupyter记事本中,可用?指令在另一个浏览器窗口中显示文档。 例如,list?指令将创建与help(list)指令几乎相同的内容,并在新的浏览器窗口中显示它。 此外,如果我们使用两个问号,如list??,将显示实现该函数的Python代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值