深度学习笔记

本篇文章是深度学习的一个学习记录 qwq,主要用来记录深度学习的相关知识,也可以探测 Nickel 的摸鱼情况。

本文是根据 b 站上的课程 https://www.bilibili.com/video/av58647159 进行学习后结合网上的一些其他资料以及 Nickel 所学的知识所记录的笔记。

下文中如果我们用 \(p\) 表示一个点,那么 \(\mathbf{p}\) 就表示其对应的向量,\(p_i\) 就是该向量第 \(i\) 个分量。


1.基本概念

概念学习:通过数据训练求出目标函数 \(\mathbf{f}(\mathbf{x})\) 的近似(模型)。

概念:即 \(\operatorname{dom}(\mathbf{f})\)

目标概念:即目标函数。

训练/测试集:用来进行训练/测试的数据集。

数据:如果一个给定的二元组 \(\langle \mathbf{x}, \mathbf{y} \rangle\) 满足 \(\mathbf{x} \in \operatorname{dom}(\mathbf{f}), \mathbf{y} \in \operatorname{codom}(\mathbf{f})\)\(\mathbf{f}(\mathbf{x}) = \mathbf{y}\) 则称为数据。其中 \(\mathbf{y}\) 称为标记

特点向量(feature vector):满足 \(\mathbf{x} \in \operatorname{dom}(\mathbf{f})\) 的向量 \(\mathbf{x}\)

分类:如果 \(\operatorname{codom}(\mathbf{f})\) 是有限集,那么就叫做分类。

回归:如果 \(\operatorname{codom}(\mathbf{f})\) 是无限集,那么就叫做回归。

有/无/半监督学习:训练集有/无/一部分有类别标记。

深度学习框架

  1. 把数据拆分为训练集和测试集
  2. 用训练集的特点向量来训练算法
  3. 用学习后生成的模型运用在测试集上来评估模型

机器学习中分类和预测算法的评估:

  • 准确率
  • 速度
  • 强壮性(对数据集样本误差的相容性和可推广性)
  • 可规模性
  • 可解释性

2. 决策树算法

2.1 信息与信息熵

在一个古典概型的随机实验 \(E\) 的概率空间 \(\langle \Omega, \mathcal{F}, P(A) \rangle\) 中。定义非空事件 \(A\,(A \in \mathcal{F})\)信息\(-\log_2(P(A))\)

信息的意义就在于,假设我们需要确定一个基本事件 \(B\),但是我们只知道基本事件 \(B\) 是事件 \(A\) 的子集,那么我们可以通过这个条件将可能为答案的基本事件的集合缩小为原来的 \(\frac{1}{2}\) 几次幂。

设可以缩小为 \(\frac{1}{2}\)\(k\) 次幂,则根据古典概型,有:

\[\left(\frac{1}{2}\right)^k = P(A) \Rightarrow k = -\log_2(P(A)) \]

即得到信息的定义。信息的单位为 bit。这样定义的好处是,可以使得一些概率较为小的事件变得明显,且信息的加法可以和概率的乘法相对应。

我们通过离散随机变量 \(X\) 来描述随机实验 \(E\) 的一些特性。由于离散随机变量是关于事件的函数,所以我们可以认为如果两个事件对应的函数值相同时,离散随机变量描述了这两个事件共同的一个性质,也即离散随机变量通过给不同事件映射不同函数值构成了事件集的一个划分,划分中的每个集合内的事件都有共同的一种性质。

在实际应用中,我们通过实验在大多数情况下可能不能观测到最终结果具体是哪个基本事件,而只能观测到结果具有哪些性质,然后根据性质判断最终结果可能具体是哪个基本事件。我们总是希望通过实验观测到的性质,使得我们得到的信息尽可能多。也就是说,我们可能需要通过调整性质的划分标准等方式,使得我们平均得到的信息量仅可能。而考虑具体方法之前,我们需要先定义“平均得到的信息量”是什么,不难发现可以仿照概率论中期望的定义,于是就有了信息熵。

我们定义离散随机变量 \(X\)信息熵 \(H(X)\) 为其每一种取值的信息的期望,即:

\[H(X) = -\sum_{i} p_i \log_2{p_i} \]

信息熵可以衡量对于这个随机实验 \(E\),我们期望得到的信息数量的大小。

2.2 决策树具体算法

2.2.0 决策树实例

现在一名电脑销售商希望知道买电脑的人有哪些特点,于是做了一些调查,得到了以下数据:

image

然后我们就可以根据这些数据画出一个决策树:

image

其中树上的每一个非叶结点都代表一个在属性上的测试,每个分支代表一个属性其与其孩子结点不同的边代表的是该属性不同的状态,每个树叶结点代表类或类分布。在这个例子中,我们希望看符合这样特性的人倾向于买或者不买。

2.2.1 ID3 算法

如果决策树结点内需要填的属性和类已经明确,那么我们需要确定决策树的形态。我们采用增量构造的方式,即一开始只有一个根节点和各个类的分支,然后依次添加一个属性,最终建出决策树。当然我们希望最终树的形态尽可能“平均”,即希望最终树建成后信息量最大的叶结点的信息尽可能小。那么结合上文其实就是相当于我们希望叶节点将基本事件划分的细一些,即平均得到的信息量尽可能小,即叶节点对样本集构成的划分信息熵仅可能小,形式化的讲,设 \(D\) 为样本集(或某个样本子集),\(C_i\) 为第 \(i\) 个类(样本集 \(D\) 对应结点的第 \(i\) 个子结点)对应的样本子集,则样本(子)集的信息熵定义为:

\[H(D) = -\sum_{i} \frac{\left\vert C_i \right\vert}{\left\vert D \right\vert} \log_2{\frac{\left\vert C_i \right\vert}{\left\vert D \right\vert}} \]

为了衡量“平均”,我们通过定义信息获取量(Information Gain)来解决这个问题。我们称一个属性 \(A\) 的信息获取量为插入这个属性前的信息熵与插入后的信息熵的差值。然后我们对于每一个未插入决策树的属性都进行试插入,试插入后信息获取量最大的属性即为我们当前这次需要插入的属性。为了更方便计算属性 \(A\) 插入后的信息熵,我们给出条件熵的概念,即若设 \(D_i\) 表明属性 \(A\) 取第 \(i\) 个值时的样本子集为 \(D_i\),而 \(D_{ij}\) 则为 \(D_{i}\) 中第 \(j\) 个类对应的样本子集,取属性 \(A\) 对于数据集的条件熵 \(H(D | A)\) 为:

\[H(D | A) = \sum_{i} \frac{\left\vert D_i \right\vert}{\left\vert D \right\vert} H(D_i) = -\sum_{i} \frac{\left\vert D_i \right\vert}{\left\vert D \right\vert} \sum_{j} \frac{\left\vert D_{ij} \right\vert}{\left\vert D_i \right\vert} \log_2{\frac{\left\vert D_{ij} \right\vert}{\left\vert D_i \right\vert}} \]

则对于属性 \(A\) 的信息获取量,我们可以定义为:

\[Gain(D, A) = H(D) - H(D | A) \]

将实例中的情况以这样的方式处理,发现属性 age 的信息获取量最大,所以第一步先将其插入决策树中:

img

发现 middle_aged 这个分支对应的结点的类均为 yes,不需要再进行分类,所以该结点就直接变为叶子结点。而对于另两个分支,仍需进行分类,递归进入两个子树进行处理即可。

递归终止条件也较为显然,即给定结点的所有样本属于同一类,或者没有剩余属性可以用于划分样本(这时需要以多数类创建一个树叶),那么递归终止。

ID3 的缺点:

  • ID3 没有剪枝策略,使得对应容易过拟合;
  • 信息增益准则对可取值数目较多的特征有所偏好;
  • 只可以处理离散分布的特征;
  • 不能处理数据集中一些数据的一些特征的值缺失的情况。

针对 ID3 的一些缺点,我们可以考虑对算法进行一些调整。

首先我们考虑如何处理值连续分布的特征。由于样本集 \(D\) 是有限集,所有值连续分布的特征的取值最多有 \(\left\vert D \right\vert\) 种。假设有 \(n\) 种取值,那么我们将这些取值从小到大排序,我们可以将这 \(n\) 种取值划分为两个非空集合 \(A, B\),其中 \(A\) 集合中的值均小于 \(B\) 集合中的值。显然只有 \(n - 1\) 种划分方式,我们只需取信息增益最大的划分方式即可。

再考虑解决一些数据的一些特征的值缺失的情况如何解决。首先我们在计算某个特征的信息增益的时候,先忽略缺失此特征的样本,从而计算出某种特征的信息增益。

形式化的讲,考虑我们设样本集中所有无缺失值的数据所占的集合为 \(\overset{\sim}{D}\) 的占总样本集 \(D\) 的比例为 \(\rho\),那么我们可以先将信息获取量的定义更改为:

\[\rho = \dfrac{\vert \overset{\sim}{D} \vert}{\left\vert D \right\vert} \\ Gain(D, A) = \rho \times (H(\overset{\sim}{D}) - H(\overset{\sim}{D} | A)) \]

然后在划分的时候我们将缺失作为划分标准的特征的数据同时划分到所有子结点。但是这样的简单划分肯定是不行的,我们对于每个样本 \(x\) 引入一个权重 \(w_x\),定义样本子集 \(D\) 的权重 \(w_{D}\)\(D\) 内所有样本权重之和。我们可以考虑根据每个样本子集的权重与样本集的总权重的比值来调整这些有缺失值数据的权重,相当于我们将该数据按照一定比例分成几部分。当然为了适应引入的权重,所以我们需要再次更改样本集的信息熵、条件熵、信息增益的定义。

首先我们更改样本(子)集的信息熵的定义为:

\[H(D) = - \sum_{i} \frac{w_{C_i}}{w_D} \log_2{\frac{w_{C_i}}{w_{D}}} \]

而更改条件熵定义为:

\[H(D | A) = \sum_{i} \frac{w_{D_i}}{w_D} H(D_i) = -\sum_{i} \frac{w_{D_i}}{w_D} \sum_{j} \frac{w_{D_{ij}}}{w_{D_i}} \log_2{\frac{w_{D_{ij}}}{w_{D_i}}} \]

进而更改信息增益的定义为:

\[\rho = \dfrac{w_{\overset{\sim}{D}}}{w_{D}} \\ Gain(D, A) = \rho \times (H(\overset{\sim}{D}) - H(\overset{\sim}{D} | A)) \]

每一次我们将一个缺失作为划分标准的特征的数据 \(x\) 划分到了一个结点对应的样本子集 \(D_i\),我们就要更新数据 \(x\) 的权重 \(w_x\),则我们可以考虑将其更新为 \(\dfrac{w_{D_i}}{w_D} w_x\)。不难发现这样操作后 \(w_D\) 的值是不变的。如果我们对于每个数据 \(x\) 的权重都置初值 \(w_x = 1\),那么若样本集中没有缺失值的数据,通过改进的定义所计算得到的信息增益就和未做任何改进之前的计算结果相同。故通常我们就将 \(w_x\) 置初值为 1。

2.2.2 C4.5 算法

由于 ID3 没有剪枝,而且根据信息获取量作为划分标准,使得出现数据过拟合和划分时对可取值数目较多的特征有更多偏好。所以我们考虑引入新的划分标准:信息增益率和剪枝。

我们定义属性 \(A\)信息增益率为:

\[GainRatio(D, A) = \dfrac{Gain(D, A)}{H(D, A)} \\ H(D, A) = -\sum_{i} \frac{\left\vert D_i \right\vert}{\left\vert D \right\vert} \log_2{\frac{\left\vert D_i \right\vert}{\left\vert D \right\vert}} \]

其中 \(H(D, A)\) 被称为属性 \(A\) 的固有值。不难发现如果我们将类 \(C\) 也看作是一种特征,则有 \(H(D, C) = H(D)\)。当然我们也可以将其按照前文的讨论改进成可以处理有缺失值的数据集的形式。

由于信息增益率对应可取值较少的特征有偏好,我们可以用这一特点来削弱信息增益对可取值较多的特征有偏好的问题。我们采取一种启发式的方法,即每次取信息增益不低于平均值的特征中,信息增益率最高的特征作为本次插入决策树的特征。

接下来考虑防止过拟合的剪枝策略。即考虑如果决策树将数据集分类分的过细,那么可能会导致结果与训练集过于符合,使得决策树的强壮性较弱。

  • 预剪枝

在结点划分前来确定是否继续增长,及早停止增长叫做预剪枝。

一个最简单的方法是一个结点内的结点数目如果低于某一阈值就停止对该节点划分。但是我们可以考虑效果更好的方法:我们将原来的样本集分为训练集和验证集。我们使用训练集上的数据生成决策树,每当我们使用上面准则计算出应该向决策树中插入的特征后,我们就用验证集的数据看一看划分后决策树的输出结果准确率是否有所提升。如果没有,那么就不再插入该特征,生成新分支,反之亦然。

  • 后剪枝

在已经生成的决策树上进行剪枝,叫做后剪枝。

C4.5 采取的是悲观剪枝方法。同样将样本集划分为训练集和验证集,自底向上对于每一个非叶节点,判断如果将其变为一个叶结点,在验证集上的正确率会不会升高,如果会,则将其变为叶结点,并递归进入其父节点进行判断。否则继续考虑其他未考虑的较深的非叶结点。

C4.5 的缺点:

  • C4.5 使用的熵模型需要离散化时需要排序算法,在数据集较大的时候,可能需要过大的额外空间;
  • 对于预剪枝,由于树没有完全建成,可能会带来欠拟合的风险;
  • 对于后剪枝,需要大量额外的时间空间开销。

2.2.3 CART 算法

ID3 和 C4.5 算法由于生成的决策树是多分支的决策树,所以划分较为细、结点较多,不适合大规模的应用,而 CART 的算法正好可以修复这个问题。

首先 C4.5 和 ID3 算法在计算信息熵的时候,需要运用到对数运算,由于现代计算机实现对数运算是通过迭代和泰勒展开计算达到一个比较好的精度,但是由于需要大量浮点数运算,所以时间花费较大。所以我们考虑直接对对数函数进行泰勒展开,变对数运算为多项式运算,即考虑 \(\ln(x) = x - 1 + o(x - 1)\),那么我们可以仿照信息熵的定义,定义样本(子)集 \(D\)基尼系数为:

\[Gini(D) = -\sum_{i} \frac{\left\vert C_i \right\vert}{\left\vert D \right\vert} \left(\frac{\left\vert C_i \right\vert}{\left\vert D \right\vert} - 1\right) = 1 - \sum_{i} \left(\frac{\left\vert C_i \right\vert}{\left\vert D \right\vert}\right)^2 \]

和上文定义信息熵时一样,\(C_i\) 为第 \(i\) 个类(样本集 \(D\) 对应结点的第 \(i\) 个子结点)对应的样本子集。

由于 ID3 和 C4.5 算法生成的决策树为多叉树,需要消耗大量时间的同时也有过拟合的风险,而 CART 算法为了规避这一风险,每一次插入新特征时,只生成两个分支,最终生成一棵二叉树。由于只生成两个分支,所以对于一次插入要插入的特征 \(A\),我们只需根据特征 \(A\) 将数据集分成两个互不相交的数据子集,然后将这两个子集分别放入两个分支。下面考虑如何根据特征 \(A\) 将数据集划分为两个数据子集。

  • 对于离散的特征 \(A\),我们可以针对特征 \(A\) 的某个值 \(a\) 对数据集进行划分,即将数据集划分为特征 \(A\) 的值为 \(a\) 的数据和特征 \(A\) 的值不为 \(a\) 的数据。

  • 对于连续的特征 \(A\),我们可以选择特征 \(A\) 值域中的一个值 \(a\),从而将数据集划分为特征 \(A\) 的值不大于 \(a\) 的数据和特征 \(A\) 的值大于 \(a\) 的数据。

我们先来讨论离散的特征。对于离散的特征,我们可以仿照条件熵的定义,定义数据集按照特征 \(A\) 的值为 \(a\)(或者不大于 \(a\))的标准划分的基尼系数为:

\[Gini(D, x_A = a) = \frac{\left\vert D_1 \right\vert}{\left\vert D \right\vert} Gini(D_1) + \frac{\left\vert D_2 \right\vert}{\left\vert D \right\vert} Gini(D_2) \]

其中 \(x_A = a\) 即为按照特征 \(A\) 的值为 \(a\) 的标准对数据集 \(D\) 进行划分, \(D_1, D_2\) 则为按照上述划分方式划分成的两个数据子集。

考虑信息增益准则 \(Gain(D, A) = H(D) - H(D | A)\),发现对于同一次插入,对于不同的属性 \(A\),公式中 \(H(D)\) 是不变的,所以我们其实只需关注 \(H(D | A)\) 的大小即可。所以对应到 CART 算法,我们只需针对每个特征的每个值都计算出按照它们为标准划分的基尼系数,其中基尼系数最小的划分方案即为我们最终生成新分支的划分方案。然后和之前的算法一样,进入子树递归处理。

再考虑连续的特征。按照上面的讨论,假设我们选择的值为 \(a\),将数据集划分为两个集合 \(D_1, D_2\)。设样本 \(\mathbf{{x}}\) 属性 \(A\) 的值为 \(x_{A}\),对应的类(输出值)为 \(x_{r}\),定义误差平方和为:

\[\sum_{\mathbf{{x}} \in D_1} (x_{r} - c_1)^2 + \sum_{\mathbf{{x}} \in D_2} (x_{r} - c_2)^2 \]

其中 \(D_1\) 即为 \(D\) 中所有满足 \(x_{A} \le a\) 的数据组成的集合,而 \(D_2\) 即为 \(D\) 中不在 \(D_1\) 中的其他数据组成的集合。\(c_1, c_2\) 分别为数据集 \(D_1, D_2\) 所有数据的输出值的平均值。上文中的 \(a\) 称为决策点。

在构建决策树时,每次我们需要找到误差平方和最小的属性 \(A\) 和决策点 \(a\),然后生成两个新的分支。然后进入子树递归处理即可。

3. KNN 算法和 K-means 算法

3.1 KNN 算法

和决策树一样,KNN 算法也是一种分类算法。它是根据已经分好类的数据集 \(S\),来预测未分类数据可能会被归到哪一类。

对于一个未分类数据 \({\mathbf{x}_u}\),我们希望知道它和哪一类的数据更“相似”,为了量化这个相似性,我们希望定义相似度,但是我们发现我们不好定义相似度,所以我们反过来定义两个数据 \({\mathbf{x}}, {\mathbf{y}}\)不相似度\(\lvert {\mathbf{x}} - {\mathbf{y}} \rvert^2\),即为两个向量间的距离的平方,这里的距离我们取的是欧几里得距离。

那么本算法的流程即为,我们设定一个阈值 \(k\),考虑对于一个未分类数据 \({\mathbf{x}_u}\),设与其不相似度最小的前 \(k\) 数据的组成的集合为 \(T\),则在 \(T\) 中出现次数最多的类别即为我们预测的标准。

img

如上图,与 \({\mathbf{x}_u}\) 不相似度最小的前 5 个中,多数数据属于 \(\omega_1\),所以最终 \({\mathbf{x}_u}\) 被预测为属于 \(\omega_1\)

我们可以通过将数据集分为训练集和验证集,找到一个正确率较高,较为合适的 \(k\) 值。

3.2 k-means 算法

k-means 算法也是一种分类算法,全称 \(k\) 均值聚类算法。它是一种无监督式学习,即给定一些数据,通过这个算法可以给这些数据分为 \(k\) 类。

即我们需要将由 \(n\) 维空间中的点组成的数据集 \(S\) 按照某些方式分为彼此不相交的 \(k\) 个子集 \(S_1, S_2, \cdots, S_k\),且 \(S = \bigcup_{i = 1}^{k} S_i\)。我们希望每个子集中的点之间尽可能相似。为了衡量每个子集中的点的相似度,从而评价我们做出的分类是否合适,我们在这里需要选取一种方法来量化。

我们的方法是选取空间内 \(k\) 个点 \(c_1, c_2, \cdots, c_k\) 作为中心,由上文我们定义两个点 \(x, y\) 的不相似度为两个点的欧几里得距离,记作 \(\Delta(x, y)\),我们根据这 \(k\) 个中心对 \(S\) 集合内的点进行划分。即对于一个点 \(x\),它属于集合 \(S_i\) 当且仅当 \(\Delta(x, c_i) = \min_{j = 1}^k \Delta(x, c_j)\)。即每个点都找到距离其最近的中心进行归属,如果有多个最近中心,我们需要按照统一的规则特判,譬如我们不会改变一个点的所归属的集合除非找到了一个严格更近的中心。我们将这个规则叫做最近中心准则

有了以上的讨论,我们可以考虑形式化的表示这个问题。我们可以考虑一个函数 \(f(S, C)\),其中 \(S\) 是数据集,\(C\)\(k\) 个中心组成的序列。而我们的目标是最小化 \(f(S, C)\),即:

\[\begin{aligned} f(S, C) &= \sum_{x \in S} \min_{i = 1}^k \Delta(x, c_i) \\ &= \sum_{i = 1}^k \sum_{x \in S_i} \Delta(x, c_i) \end{aligned} \]

其中第二行的 \(S_i\) 是根据 \(C\) 中的中心根据上文所述的最近中心准则定义的。要求解 \(f(S, C)\) 最小值是一个 NP-hard 问题。但是我们可以通过近似算法找到一个局部最小值。

在介绍近似算法之前,我们定义一个给定数据集合 \(S_i\) 的重心 \(c_i\) 为:

\[{\mathbf{c}_i} = \frac{1}{\left\vert S_i \right\vert} \sum_{x \in S_i} {\mathbf{x}} \]

现在我们来证明对于 \(S_i\) 来说,重心 \(c_i\) 即为可以使得

\[\sum_{x \in S_i} \Delta(x, c_i) \]

最小。

我们考虑如果我们要使上式最小,不妨把它当成一个关于 \(c_i\) 的函数,那么:

\[\begin{aligned} \sum_{x \in S_i} \Delta(x, c_i) &= \sum_{x \in S_i} \sum_{j = 1}^n (x_j - c_{i, j})^2 \\ &= \sum_{x \in S_i} \sum_{j = 1}^n (x_j^2 - 2 x_j c_{i,j} + c_{i, j}^2) \\ &= \sum_{j = 1}^n \left(\sum_{x \in S_i} x_j^2 - 2 \sum_{x \in S_i} x_j c_{i, j} + \left\vert S_i \right\vert c_{i, j}^2 \right) \end{aligned} \]

我们可以考虑如果对于每一个 \(j\),式子

\[\sum_{x \in S_i} x_j^2 - 2 \sum_{x \in S_i} x_j c_{i, j} + \left\vert S_i \right\vert c_{i, j}^2 \]

都可以同时达到最小值,那么它们的和也可以达到最小值。而不难发现这个式子是关于 \(c_{i, j}\) 的二次函数,当且仅当 \(c_{i, j} = \frac{1}{\left\vert S_i \right\vert} \sum_{x \in S_i} x_j\) 时,\(c_{i, j}\) 取得最小值。那么如果对于每个 \(j\) 上式都取到了最小值,那么显然有

\[{\mathbf{c}_i} = \frac{1}{\left\vert S_i \right\vert} \sum_{x \in S_i} {\mathbf{x}} \]

成立。进而结论得证。

然后我们在说明 \(f(S, C)\) 最小当且仅当每一个点 \(x \in S\) 都找到了一个对应的集合 \(S_i\) 使得 \(\Delta(x, c_i)\) 最小。

这个其实是显然的,因为我们发现任意的点只会对 \(f(S, C)\) 贡献一次。

我们在这里给出一个近似算法,算法的输入就是一个数据集合 \(S\) 和一个正整数 \(k\)

算法流程如下:

  1. 首先随机生成 \(k\) 个点 \(c_1, c_2, \cdots, c_k\) 作为初始的中心,将 \(S\) 中所有点先划分到 \(S_1\)
  2. 使用最近中心准则重新将所有数据点划分到新的集合。即如果一个点 \(x\) 当前在 \(S_i\) 中,但是如果当前 \(c_j\,(i \neq j)\) 距离 \(x\) 最近,那么 \(x\) 就应被重新划分到 \(S_j\) 中。
  3. 如果第 2 步没有使得任何点改变其归属的集合,那么就终止算法,返回当前分类的结果。否则去到第 4 步。
  4. 根据当前划分的结果 \(S_1, S_2, \cdots, S_k\),计算每个非空集合的重心作为这个集合新的中心。然后返回第 2 步。

显然由于只有 \(k^n\) 种划分方法,这个算法一定会终止。而且由于刚才的证明,重新计算重心作为新的中心一定不会使 \(f(S, C)\) 变大。而由于我们不希望这个算法迭代太多次,在应用中,我们会在每次执行算法的第二步调整后,计算调整前后答案减小的比率,如果该比率小于某个预先确定的阈值,那么终止算法。如果假设整个算法会迭代 \(T\) 次,那么整个算法的时间复杂度为 \(O(Tnk \left\vert S \right\vert)\)

4 梯度下降法

4.1 多元线性回归

4.1.0 简介

有一类著名的回归问题是多元线性回归问题,它的问题模型是给定 \(m\) 个由一个 \(n\) 维变量的输入(其中第 \(i\) 个向量为 \(\mathbf{x}^{(i)}\),注意 \((i)\) 不是表示 \(i\) 次幂的意思,而是标号) 和一个值(其中第 \(i\) 个输出为 \(y^{(i)}\))的输出组成的数据,希望找到一个 \(m\) 元函数 \(h_{\theta}({\mathbf{x}}) = \theta_0 + \sum_{i = 1}^{n} \theta_i x_i\) 使得代价函数 \(J(\mathbf{\theta}) = \frac{1}{2m} \sum_{i = 1}^m (h_{\theta}(\mathbf{x}^{(i)}) - y^{(i)})^2\) 最小。

显然这个模型的实际意义就是找到一条 \(n\) 维空间上的直线,使得其距离给定的 \(m\) 个点的平均距离最近。(其中神奇的参数设置,比如说为什么式子分母是 \(2m\) 这样的问题,其实是为后面计算梯度提供便利)

如果我们重新定义 \(\mathbf{x}^{(i)}\),即让 \(x^{(i)}_{j}\)\(j > 0\) 时保持不变,新定义 \(x^{(i)}_{0} = 1\),那么 \(h_{\theta}(\mathbf{x}^{(i)})\) 可以写为:

\[h_{\theta}({\mathbf{x}}) = \sum_{i = 1}^n \theta_i x_i = \mathbf{\theta}^{\mathbf{T}} \mathbf{x} = {\mathbf{\theta}} \cdot \mathbf{{x}} \]

4.1.1 梯度下降

我们现在要最小化代价函数 \(J({\mathbf{\theta}})\),不难发现其是一个多元函数。我们知道在多元函数中,函数的梯度的反方向是函数下降最快的方向,所以我们可以考虑先随机一个 \({\mathbf{\theta}}\),从该向量指向的点开始,求函数在该点的梯度 \(\nabla J |_{{\mathbf{\theta}}}\) ,然后沿梯度方向走一小步,即走到 \({\mathbf{\theta}} - \alpha \nabla J |_{{\mathbf{\theta}}}\),然后继续求梯度,再沿新的位置的梯度的反方向走一小步,不断迭代,直到达到梯度为 0 的点,这时不难发现我们就找到了一个代价函数的局部最小值。

关于影响步长的参数 \(\alpha\),我们称其为学习率

而显然在多元线性回归问题中,我们可以直接使用复合函数求导法则,不难发现 \(J({\mathbf{\theta}})\) 的偏导极具规律性,即 \(\frac{\partial J}{\partial \theta_j} = \frac{1}{m} \sum_{i = 1}^m (h_{\theta}(\mathbf{x}^{(i)}) - y^{(i)}) x^{(i)}_{j}\),求出了偏导就求出了梯度,然后我们就可以使用梯度下降来找到多元线性回归的一个局部最优解。

4.1.2 特征缩放与学习率的选取

在使用梯度下降法解决实际问题的时候,我们可能会遇到参数取值范围差距过大而导致每个分量的变化对代价函数值下降后的影响不一样。而我们的学习率是一定的,就相当于我们忽视了每个分量在这方面的差异性。这最终导致了我们可能会因为学习率过大,而走一些曲折的路线。

假设我们的代价函数是二元函数,那么我们可以通过下面的等高线图看出特征缩放前后,梯度下降法所迭代的步数是有所下降的。

img

而缩放的原则也就是将所有变量的范围尽可能化至一个数量级,但是如果单纯的为了将变量范围化至一个数量级,可能会因为除法出现精度误差,乘法导致数值过大等等问题。

下面我们需要考虑学习率如何选取,学习率如果选取过小,那么梯度下降算法收敛的速度就会过慢。如果学习率选取过大,那么由于步长过大,可能会导致代价函数永远不会收敛。

我们可以通过画出在给定学习率下,代价函数的最小值随迭代次数增加的变化图像来判断这一点。显然我们基本上在实验中最多还是通过经验来选取学习率,一般来讲,我们一开始选取一个较小的学习率,比如 0.001,然后每次将学习率扩大三倍,并且画出所有学习率下,代价函数的最小值随迭代次数增加的变化图像,通过对比选取最优的学习率。

4.1.3 非线性回归

如果仅仅用一条直线拟合数据不能满足我们的要求,我们需要用非线性函数来拟合数据。

假设我们要拟合用的函数模型为 \(h_{\theta}({\mathbf{x}}) = \theta_0 + \theta_1 x_1 + \theta_2 x_2^2 + \theta_3 x_3^3\)

我们可以通过令 \(z_1 = x_1, z_2 = x_2^2, z_3 = x_3^3\),将其转化为一个多元线性回归问题。这样我们就可以不止用一条直线去拟合数据了。

4.1.4 正规方程法

在多元线性回归问题中,我们可以使用矩阵 \(X = [\mathbf{x}^{(1)}, \mathbf{x}^{(2)}, \cdots, \mathbf{x}^{(m)}]^{\mathbf{T}}\) 来表示数据集的所有输入,用向量 \({\mathbf{y}} = [y^{(1)}, y^{(2)}, \cdots, y^{(m)}]^{\mathbf{T}}\) 来表示数据集的输出。

即:

\[X = \begin{bmatrix} x^{(1)}_{0} & x^{(1)}_{1} & \cdots & x^{(1)}_{n} \\ x^{(2)}_{0} & x^{(2)}_{1} & \cdots & x^{(2)}_{n} \\ \vdots & \vdots & \ddots & \vdots \\ x^{(m)}_{0} & x^{(m)}_{1} & \cdots & x^{(m)}_{n} \end{bmatrix} \\ {\mathbf{y}} = \begin{bmatrix} y^{(1)} \\ y^{(2)} \\ \vdots \\ y^{(m)} \end{bmatrix} \]

那么多元线性回归的问题就是找到方程 \(X \mathbf{\theta} = \mathbf{y}\) 的近似解。

我们可以通过投影矩阵相关理论,得到最终最优的 \({\mathbf{\theta}}\) 为:

\[\hat{\mathbf{\theta}} = (X^{\mathbf{T}} X)^{-1} X^{\mathbf{T}} {\mathbf{y}} \]

\(n, m\) 比较小的时候,我们可以直接带公式算出最优的 \({\mathbf{\theta}}\)

我们可以对比梯度下降和正规方程的优略:

梯度下降需要选择学习率,需要迭代计算,但是对于 \(n\) 非常大的情况表现很好。

正规方程不需要选择参数和迭代,但是需要计算矩阵乘法需要 \(O(n^3)\),时间复杂度较高,在 \(n\) 较大时就需要花费过多时间。

在使用正规方程法的时候,我们可能会遇到 \(X^{\mathbf{T}} X\) 不可逆的情况。这通常发生在两个特征之间是线性关系和特征过多的情况,我们这时候需要删除一些特征或者使用正则化方法。

4.2 Logistic 回归

4.2.0 简介

在多元线性回归模型中,我们用来拟合结果的函数是 \(h_{\theta}(\mathbf{x}) = \mathbf{\theta}^{\mathbf{T}} \mathbf{x}\),但是这个函数过于简单,可能在复杂的例子上表现效果不好,所以我们要引入一些特殊的模型。

我们这里介绍的 logistic 回归,正是用到了这样一种特殊的函数,即 sigmoid 函数 \(\sigma(z) = \frac{1}{1 + e^{-z}}\)

所以我们重新令 \(h_{\theta}(\mathbf{x}) = \sigma(\mathbf{\theta}^{\mathbf{T}} \mathbf{x})\),此时我们就找到了一个新的拟合函数。

其实我们的回归的方法也可以用作分类,也即我们可以将我们的拟合函数的值域限定在 \([0, 1]\),这样 \(h_{\theta}(\mathbf{x})\) 就表明的是 \(x\) 这个特征在给定的参数 \(\theta\) 的条件下属于正类的概率。我们可以设定一个阈值 \(C\),比如 0.5,属于正类的概率小于 \(C\) 的点都归为负类,剩下的点归为正类。这样就做到了分类。

而且我们不难发现,\(\sigma(z)\) 是一个单调递增的函数,且 \(\sigma(0) = 0.5\),如果我们设置的阈值 \(C = 0.5\),那么我们会知道当 \(\mathbf{\theta}^\mathbf{T} \mathbf{x} \ge 0\) 的点就是我们最终分类被归到正类的点。而 \(\mathbf{\theta}^\mathbf{T} \mathbf{x} = 0\) 会将空间花费成两个区域,使得在区域内的点均为被划分到正类的点,区域外的点均为被划分到负类的点。

4.2.1 代价函数

我们已经知道多元线性回归的代价函数为:

\[J({\mathbf{\theta}}) = \frac{1}{m} \sum_{i = 1}^m \frac{1}{2} (h_{\theta}(\mathbf{x}^{(i)}) - y^{(i)})^2 \]

观察它的形式,我们如果定义样本中每一个值的代价为:\(\operatorname{Cost}(h_{\theta}(\mathbf{x}), y)\),那么我们可以将代价函数推广为:

\[J(\mathbf{\theta}) = \frac{1}{m} \sum_{i = 1}^m \operatorname{Cost}(h_{\theta}(\mathbf{x}^{(i)}), y) \]

若我们令 \(\operatorname{Cost}(h_{\theta}(\mathbf{x}), y) = \frac{1}{2} (h_{\theta}(\mathbf{x}) - y)^2\),那么就得到了多元线性回归的代价函数。这就是我们对于代价函数的推广。

然而对于 Logistic 回归,我们不能简单直接照搬多元线性回归的代价函数。这是因为我们的函数模型 \(h_{\theta}(\mathbf{x})\) 外层复合函数为 \(\sigma(z)\) 函数,直接使用原先的代价函数会使得其拐点过多,有许多极值点,如果使用梯度下降时很容易走入局部最小值。

所以我们需要新的代价函数,我们使用对数函数来充当代价函数(具体为什么是对数函数,我们可以通过最大似然估计的理论解释),即:

\[\operatorname{Cost}(h_{\theta}(\mathbf{x}), y) = \begin{cases} -\ln(h_{\theta}(\mathbf{x})), & y = 1 \\ -\ln(1 - h_{\theta}(\mathbf{x})), & y = 0 \end{cases} \]

不难发现这样设置代价函数,在分类算法决策正确时,代价函数的值为 0,如果决策错误,代价函数的值会趋于正无穷。而且由于对数函数是单调的,最终代价函数没有极值点,使得梯度下降不会陷入局部最优。以上两点,保证了我们可以最终训练出比较好的模型。

显然我们这里将代价函数写成了分段函数的形式,不利于我们最终的计算,现在考虑简化其形式。不难发现,由于 \(y\) 的值只能是 0 或 1,所以我们可以加入乘积因子,代替函数分段,即将其写为:

\[\operatorname{Cost}(h_{\theta}(\mathbf{x}), y) = -y \ln(h_{\theta}(\mathbf{x})) - (1 - y) \ln(1 - h_{\theta}(\mathbf{x})) \]

进而总体的代价函数 \(J(\theta)\)

\[\begin{aligned} J(\theta) &= \frac{1}{m} \sum_{i = 1}^m \operatorname{Cost}(h_{\theta}(\mathbf{x}^{(i)}), y) \\ &= - \frac{1}{m} \sum_{i = 1}^m y^{(i)} \ln(h_{\theta}(\mathbf{x}^{(i)})) + (1 - y^{(i)}) \ln(1 - h_{\theta}(\mathbf{x}^{(i)})) \end{aligned} \]

接下来我们要使用梯度下降法来求其最小值,然而我们在求 \(\nabla J\) 的时候,我们会惊奇的发现:

\[\frac{\partial J}{\partial \theta_j} = \frac{1}{m} \sum_{i = 1}^m (h_{\theta}({\mathbf{x}_i}) - y^{(i)}) x^{(i)}_{j} \]

这个代价函数的梯度形式和多元线性回归的梯度形式一模一样!尽管我们的函数模型有所变化。

4.2.2 多元分类

我们之前只介绍了将数据分为两类的分类问题,我们现在来介绍多元分类。即如果我们的目标是将物品分为 \(k\) 类,那么我们可以对于每一类,训练一个分类模型,即对于第 \(i\) 类,训练一个函数 \(h_{\theta}^{(i)}(\mathbf{x})\) 表明某个点归属于第 \(i\) 类的概率(严格来说,已经不算是严格意义上的概率了),我们只需要训练 \(k\) 个二元分类模型即可。

当最终判断某个点的归属的时候,我们就取模型函数值最大的那一类作为该点归属即可。

4.3 正则化

4.3.0 过拟合问题

当我们使用多元线性回归时,我们可能会因为我们数据维数过多且出现了一些相关性较小的变量,导致最终拟合的曲线过于符合数据集,使得其泛用性下降,如下图右侧图像出现的情况。我们将这种情况称为过拟合

img

为了解决这个问题,我们会将代价函数重新写成如下形式:

\[J(\mathbf{\theta}) = \frac{1}{m} \bigg[ \sum_{i = 1}^m \operatorname{Cost}(h_{\theta}(\mathbf{x}^{(i)}), y) + \frac{\lambda}{2} \sum_{j = 1}^{n} \theta_j^2 \bigg] \]

不难发现后面那一项是为了防止某一项 \(\theta_j\) 过大,导致某些相关性较小的项被我们过分看重,最终出现过拟合。

当然我们这里其实使用的是 \(\mathbf{\theta}\) \(l_2\) 范数的平方当作了我们的正则项。

4.3.1 线性回归和 Logistic 回归正则化

根据前面我们说明的理由,我们在线性回归模型中,应用正则化,则:

\[J({\mathbf{\theta}}) = \frac{1}{2m} \bigg[ \sum_{i = 1}^m (h_{\theta}(\mathbf{x}^{(i)}) - y^{(i)})^2 + \lambda \sum_{j = 1}^{n} \theta_j^2 \bigg] \]

那么在求解 \(\nabla J\) 时,我们发现显然除了 \(\frac{\partial x}{\partial \theta_0}\) 不受影响外,其他都偏导受影响。

所以当 \(j > 0\) 时,根据求导法则,有:

\[\frac{\partial J}{\partial \theta_j} = \frac{1}{m} \bigg[ \sum_{i = 1}^m (h_{\theta}(\mathbf{x}^{(i)}) - y^{(i)}) x^{(i)}_{j} + \lambda \theta_j \bigg] \]

考虑到每次迭代我们都是令 \(\mathbf{\theta} + \alpha \nabla J |_{\mathbf{\theta}}\),那么对于 \(j > 0\) 时,我们就有:

\[\theta_j \leftarrow \theta_j - \alpha \frac{1}{m} \bigg[ \sum_{i = 1}^m (h_{\theta}(\mathbf{x}^{(i)}) - y^{(i)}) x^{(i)}_{j} + \lambda \theta_j \bigg] \]

整理一下我们就可以得到:

\[\theta_j \leftarrow \bigg(1 - \alpha \frac{\lambda}{m} \bigg) \theta_j - \alpha \frac{1}{m} \sum_{i = 1}^m (h_{\theta}(\mathbf{x}^{(i)}) - y^{(i)}) x^{(i)}_{j} \]

而由于 Logistic 回归与线性回归的代价函数在求导后相同,故正则化之后,它们的梯度下降式子也同样是相同的。

我们可以通过微积分的矩阵求导证明,如果我们使用正规方程法实现多元线性回归的正则化,那么就有:

\[\theta = (X^{\mathbf{T}}X + \lambda I)^{-1} X^{\mathbf{T}} \mathbf{y} \]

注意这里我们也给 \(\theta_0\) 加入了惩罚项。

posted @ 2022-10-18 22:28  Nickel_Angel  阅读(122)  评论(0编辑  收藏  举报