《动手学深度学习》学习笔记 Ch.2 - 预备知识 (2.4-2.7)
2.4. 微积分
我们可以将拟合模型的任务分解为两个关键问题:
- 优化(optimization):用模型拟合观测数据的过程;
- 泛化(generalization):数学原理和实践者的智慧,能够指导我们生成出有效性超出用于训练的数据集本身的模型。
2.4.1. 导数和微分
假设我们有一个函数$f:R^n→R$,其输入和输出都是标量。 如果ff的导数存在,这个极限被定义为
$$
f’(x) = \lim_{h \to 0} \frac{f(x+h) - f(x)}{h}
$$
如果$f’(a)$存在,则称$f$在$a$处是可微(differentiable)的。如果$f$在一个区间内的每个数上都是可微的,则此函数在此区间中是可微的。 我们可以将 (2.4.1)中的导数$f′(x)$解释为$f(x)$相对于$x$的瞬时(instantaneous)变化率。 所谓的瞬时变化率是基于$x$中的变化$h$,且$h$接近$0$。
给定$y=f(x)$,其中$x$和$y$分别是函数$f$的自变量和因变量。以下表达式是等价的:
$$
f’(x) = y’ = \frac{dy}{dx} = \frac{df}{dx} = = \frac{d}{dx}f(x) = Df(x) = D_xf(x)
$$
为了微分一个由一些常见函数组成的函数,下面的一些法则方便使用。 假设函数$f$和$g$都是可微的,$C$是一个常数,则:
- 常数相乘法则
$$
\frac{d}{dx}|Cf(x)| = C\frac{d}{dx}f(x)
$$
- 加法法则
$$
\frac{d}{dx}|f(x) + g(x)| = \frac{d}{dx}f(x) + \frac{d}{dx}g(x)
$$
- 乘法法则
$$
\frac{d}{dx}|f(x)g(x)| = f(x)\frac{d}{dx}|g(x)| + g(x)\frac{d}{dx}|f(x)|
$$
- 除法法则
$$
\frac{d}{dx}[\frac{f(x)}{g(x)}] = \frac{g(x)\frac{d}{dx}|f(x)| - f(x) \frac{d}{dx}|g(x)| }{ |g(x)|^2 }
$$
2.4.2. 偏导数
到目前为止,我们只讨论了仅含一个变量的函数的微分。 在深度学习中,函数通常依赖于许多变量。 因此,我们需要将微分的思想推广到多元函数(multivariate function)上。
设$y=f(x_1,x_2,…,x_n)$是一个具有$n$个变量的函数。 $y$关于第$i$个参数$x_i$的偏导数(partial derivative)为:
$$
\frac{\partial y}{\partial x_i} = \lim_{h \to 0} \frac{f(x_1, …, x_{i-1}, x_i+h, x_{i+1},…,x_n) - f(x_1, …, x_i, …, x_n)}{h}
$$
为了计算$\frac{\partial y}{\partial x_i} $, 我们可以简单地将$x_1,…,x_{i−1},x_{i+1},…,x_n$看作常数, 并计算$y$关于$x_i$的导数。 对于偏导数的表示,以下是等价的:
$$
\frac{\partial y}{\partial x_i} = \frac{\partial f}{\partial x_i} = f_{x_i} = f_i = D_if = D_{x_i}f
$$
2.4.3. 梯度
我们可以连结一个多元函数对其所有变量的偏导数,以得到该函数的梯度(gradient)向量。 具体而言,设函数$f:R^n→R$的输入是 一个$n$维向量$x=[x_1,x_2,…,x_n]^T$,并且输出是一个标量。 函数$f(x)$相对于$x$的梯度是一个包含$n$个偏导数的向量:
$$
\nabla _xf(x) = [\frac{\partial f(x)}{\partial x_1},\frac{\partial f(x)}{\partial x_2}, …, \frac{\partial f(x)}{\partial x_n}]^T
$$
其中$∇_xf(x)$通常在没有歧义时被$∇f(x)$取代。
假设$x$为$n$维向量,在微分多元函数时经常使用以下规则:
- 对于所有$A∈R^{m×n}$,都有$∇_xAx=A^T$
- 对于所有$A∈R^{n×m}$,都有$∇_xx^TA=A$
- 对于所有$A∈R^{n×n}$,都有$∇_xx^TAx=(A+A^T)x$
- $∇_x||x||^2=∇_xx^Tx=2x$
同样,对于任何矩阵$X$,都有$∇_X∥X∥^2_F=2X$。 正如我们之后将看到的,梯度对于设计深度学习中的优化算法有很大用处。
2.4.4. 链式法则
在深度学习中,多元函数通常是复合(composite)的, 所以我们可能没法应用上述任何规则来微分这些函数。 幸运的是,链式法则使我们能够微分复合函数。
假设函数$y=f(u)$和$u=g(x)$都是可微的,根据链式法则:
$$
\frac{\mathrm{d} y}{\mathrm{d} x} = \frac{\mathrm{d} y}{\mathrm{d} u} \frac{\mathrm{d} u}{\mathrm{d} x}
$$
假设可微分函数$y$有变量$u_1,u_2,…,u_m$,其中每个可微分函数$u_i$都有变量$x_1,x_2,…,x_n$。 注意,$y$是$x_1,x_2,…,x_n$的函数。 对于任意$i=1,2,…,n$,链式法则给出:
$$
\frac{\mathrm{d} y}{\mathrm{d} x_i} = \frac{\mathrm{d} y}{\mathrm{d} u_1} \frac{\mathrm{d} u_1}{\mathrm{d} x_i}+ \frac{\mathrm{d} y}{\mathrm{d} u_2} \frac{\mathrm{d} u_2}{\mathrm{d} x_i} + … + \frac{\mathrm{d} y}{\mathrm{d} u_m} \frac{\mathrm{d} u_m}{\mathrm{d} x_i}
$$
2.4.5. 小结
- 微分和积分是微积分的两个分支,前者可以应用于深度学习中的优化问题。
- 导数可以被解释为函数相对于其变量的瞬时变化率,它也是函数曲线的切线的斜率。
- 梯度是一个向量,其分量是多变量函数相对于其所有变量的偏导数。
- 链式法则使我们能够微分复合函数。
2.5. 自动微分
深度学习框架通过自动计算导数,即自动微分(automatic differentiation)来加快求导。
实际中,根据我们设计的模型,系统会构建一个计算图(computational graph), 来跟踪计算是哪些数据通过哪些操作组合起来产生输出。 自动微分使系统能够随后反向传播梯度。 这里,反向传播(backpropagate)意味着跟踪整个计算图,填充关于每个参数的偏导数。
2.5.1. 一个简单的例子
作为一个演示例子,假设我们想对函数$y=2x^Tx$关于列向量$x$求导。
首先,我们创建变量x
并为其分配一个初始值。
1 |
|
在我们计算$y$关于$x$的梯度之前,我们需要一个地方来存储梯度。
重要的是,我们不会在每次对一个参数求导时都分配新的内存。 因为我们经常会成千上万次地更新相同的参数,每次都分配新的内存可能很快就会将内存耗尽。
1 |
|
x
是一个长度为4的向量,计算x
和x
的点积,得到了我们赋值给y
的标量输出。 接下来,我们通过调用反向传播函数来自动计算y
关于x
每个分量的梯度,并打印这些梯度。
1 |
|
函数$y=2x^Tx$关于$x$的梯度应为$4x$。 让我们快速验证这个梯度是否计算正确。
1 |
|
现在让我们计算x
的另一个函数。
1 |
|
2.5.2. 非标量变量的反向传播
当y
不是标量时,向量y
关于向量x
的导数的最自然解释是一个矩阵。 对于高阶和高维的y
和x
,求导的结果可以是一个高阶张量。
1 |
|
2.5.3. 分离计算
有时,我们希望将某些计算移动到记录的计算图之外。 例如,假设y
是作为x
的函数计算的,而z
则是作为y
和x
的函数计算的。 想象一下,我们想计算z
关于x
的梯度,但由于某种原因,我们希望将y
视为一个常数, 并且只考虑到x
在y
被计算后发挥的作用。
在这里,我们可以分离y
来返回一个新变量u
,该变量与y
具有相同的值, 但丢弃计算图中如何计算y
的任何信息。
1 |
|
由于记录了y
的计算结果,我们可以随后在y
上调用反向传播, 得到y=x*x
关于的x
的导数,即2*x
。
1 |
|
2.5.4. Python控制流的梯度计算
(个人理解是:Pytorch在自动微分的应用是,一个数学函数可以由Python的函数来定义)
使用自动微分的一个好处是: 即使构建函数的计算图需要通过Python控制流(例如,条件、循环或任意函数调用),我们仍然可以计算得到的变量的梯度。 在下面的代码中,while
循环的迭代次数和if
语句的结果都取决于输入a
的值。
1 |
|
让我们计算梯度。
1 |
|
我们现在可以分析上面定义的f
函数。 请注意,它在其输入a
中是分段线性的。 换言之,对于任何a
,存在某个常量标量k
,使得f(a)=k*a
,其中k
的值取决于输入a
。 因此,我们可以用d/a
验证梯度是否正确。
1 |
|
2.5.5. 小结
- 深度学习框架可以自动计算导数:我们首先将梯度附加到想要对其计算偏导数的变量上。然后我们记录目标值的计算,执行它的反向传播函数,并访问得到的梯度。
2.6. 概率
2.6.1. 基本概率论
对于每个骰子,我们将观察到$\lbrace 1,…,6 \rbrace$中的一个值。对于每个值,一种自然的方法是将它出现的次数除以投掷的总次数, 即此事件(event)概率的估计值。 大数定律(law of large numbers)告诉我们: 随着投掷次数的增加,这个估计值会越来越接近真实的潜在概率。
在统计学中,我们把从概率分布中抽取样本的过程称为抽样(sampling)。 笼统来说,可以把分布(distribution)看作是对事件的概率分配, 稍后我们将给出的更正式定义。 将概率分配给一些离散选择的分布称为多项分布(multinomial distribution)。
2.6.1.1. 概率论公理
在处理骰子掷出时,我们将集合$S=\lbrace 1,2,3,4,5,6 \rbrace$称为样本空间(sample space)或结果空间(outcome space), 其中每个元素都是结果(outcome)。 事件(event)是一组给定样本空间的随机结果。
概率(probability)可以被认为是将集合映射到真实值的函数。 在给定的样本空间$S$中,事件$A$的概率, 表示为$P(A)$,满足以下属性:
- 对于任意事件$A$,其概率从不会是负数,即$P(A)≥0$;
- 整个样本空间的概率为$1$,即$P(S)=1$;
- 对于互斥(mutually exclusive)事件(对于所有$i≠j$都有$A_i∩A_j=∅$)的任意一个可数序列$A1,A2,…$,序列中任意一个事件发生的概率等于它们各自发生的概率之和,即$P(⋃^∞_{i=1}A_i)=∑^∞_{i=1}P(A_i) $。
以上也是概率论的公理,由科尔莫戈罗夫于1933年提出。有了这个公理系统,我们可以避免任何关于随机性的哲学争论; 相反,我们可以用数学语言严格地推理。 例如,假设事件$A_1$为整个样本空间, 且当所有$i>1$时的$A_i=∅$, 那么我们可以证明$P(∅)=0$,即不可能发生事件的概率是0。
2.6.1.2. 随机变量
在我们掷骰子的随机实验中,我们引入了随机变量(random variable)的概念。随机变量几乎可以是任何数量,并且它可以在随机实验的一组可能性中取一个值。 考虑一个随机变量$X$,其值在掷骰子的样本空间$S=\left{ 1,2,3,4,5,6 \rbrace$中。 我们可以将事件“看到一个$5$”表示为$\left{X=5\right}$或$(X=5)$, 其概率表示为$P\left{X=5\right}$或$P(X=5)$。
2.6.2. 处理多个随机变量
2.6.2.1. 联合概率
联合概率(joint probability)$P(A=a,B=b)$。 给定任意值$a$和$b$,联合概率可以回答:$A=a$和$B=b$同时满足的概率是多少?
2.6.2.2. 条件概率
联合概率的不等式带给我们一个有趣的比率: $0≤\frac{P(A=a,B=b)}{P(A=a)}≤1$。 我们称这个比率为条件概率(conditional probability), 并用$P(B=b∣A=a)$表示它:它是$B=b$的概率,前提是$A=a$已发生。
2.6.2.3. 贝叶斯定理
使用条件概率的定义,我们可以得出统计学中最有用的方程之一: Bayes定理(Bayes’ theorem)。 根据乘法法则(multiplication rule )可得到$P(A,B)=P(B∣A)P(A)$。 根据对称性,可得到$P(A,B)=P(A∣B)P(B)$。 假设$P(B)>0$,求解其中一个条件变量,我们得到
$$
P(A|B) = \frac{P(B|A)P(A)}{P(B)}
$$
请注意,这里我们使用紧凑的表示法: 其中$P(A,B)$是一个联合分布(joint distribution), $P(A∣B)$是一个条件分布(conditional distribution)。 这种分布可以在给定值$A=a,B=b$上进行求值。
2.6.2.4. 边际化
为了能进行事件概率求和,我们需要求和法则(sum rule), 即$B$的概率相当于计算$A$的所有可能选择,并将所有选择的联合概率聚合在一起:
$$
P(B) = \sum_{A}P(A,B)
$$
这也称为边际化(marginalization)。 边际化结果的概率或分布称为边际概率(marginal probability) 或边际分布(marginal distribution)。
2.6.2.5. 独立性
另一个有用属性是依赖(dependence)与独立(independence)。 如果两个随机变量$A$和$B$是独立的,意味着事件AA的发生跟BB事件的发生无关。 在这种情况下,统计学家通常将这一点表述为$A⊥B$。 根据贝叶斯定理,马上就能同样得到$P(A∣B)=P(A)$。
2.6.2.6. 应用
是一个计算题的例子,略
2.6.3. 期望和方差
为了概括概率分布的关键特征,我们需要一些测量方法。 一个随机变量XX的期望(expectation,或平均值(average))表示为
$$
E|X| = \sum_{x}xP(X=x)
$$
当函数$f(x)$的输入是从分布$P$中抽取的随机变量时,$f(x)$的期望值为
$$
E_{x∼P}[f(x)]=\sum_{x}f(x)P(x).
$$
在许多情况下,我们希望衡量随机变量$X$与其期望值的偏置。这可以通过方差来量化
$$
Var[X]=E[(X−E[X])^2]=E[X^2]−E[X]^2.
$$
方差的平方根被称为标准差(standard deviation)。 随机变量函数的方差衡量的是:当从该随机变量分布中采样不同值$x$时, 函数值偏离该函数的期望的程度:
$$
Var[f(x)]=E[(f(x)−E[f(x)])^2].
$$
2.6.4. 小结
- 我们可以从概率分布中采样。
- 我们可以使用联合分布、条件分布、Bayes定理、边缘化和独立性假设来分析多个随机变量。
- 期望和方差为概率分布的关键特征的概括提供了实用的度量形式。
2.7. 查阅文档
由于本书篇幅限制,我们不可能介绍每一个PyTorch函数和类(你可能也不希望我们这样做)。 API文档、其他教程和示例提供了本书之外的大量文档。 在本节中,我们为你提供了一些查看PyTorch API的指导。
2.7.1. 查找模块中的所有函数和类
为了知道模块中可以调用哪些函数和类,我们调用dir
函数。 例如,我们可以查询随机数生成模块中的所有属性:
1 |
|
通常,我们可以忽略以“__
”(双下划线)开始和结束的函数(它们是Python中的特殊对象), 或以单个“_
”(单下划线)开始的函数(它们通常是内部函数)。 根据剩余的函数名或属性名,我们可能会猜测这个模块提供了各种生成随机数的方法, 包括从均匀分布(uniform
)、正态分布(normal
)和多项分布(multinomial
)中采样。
2.7.2. 查找特定函数和类的用法
有关如何使用给定函数或类的更具体说明,我们可以调用help
函数。 例如,我们来查看张量ones
函数的用法。
1 |
|
在Jupyter记事本中,我们可以使用?
指令在另一个浏览器窗口中显示文档。 例如,list?
指令将创建与help(list)
指令几乎相同的内容,并在新的浏览器窗口中显示它。 此外,如果我们使用两个问号,如list??
,将显示实现该函数的Python代码。
2.7.3. 小结
- 官方文档提供了本书之外的大量描述和示例。
- 我们可以通过调用
dir
和help
函数或在Jupyter记事本中使用?
和??
查看API的用法文档。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!
如果觉得文章内容不错,还请大力支持哦~