机器学习基本原理

归纳

我们的思维认识世界有两个重要途径——演绎deduction和归纳induction。演绎是从已知前提出发进行逻辑推断的过程,归纳则是将一些观测或者信息推广至一般化的过程。可以看到,“从已知前提出发”是要进行演绎的必须条件,一个没有任何知识的大脑要进行演绎也怕是难为无米之炊。也就是说,演绎这种方式并不会直接告诉你我们知道什么,而是如果我们知道什么、那么可以知道什么。

这样的话,我们是否可以将这个世界的知识编码进机器,让机器通过逻辑推理规则来演绎,以此来达成人工智能(artificial intelligence, AI)?历史上人们对此有过一些尝试,但难度可想而知,由人来把知识总结出来再教给机器是一件多么机械而棘手的事。例如,俗语云“只可意会不可言传”,这说明人类知识很多是隐性的难以精确形式化的,又如,人类大量的知识是有难度的,人类理解尚且费劲,还要手把手“教会”机器,对人的要求极高,此外还有在大规模知识库上进行逻辑推理的计算开销问题,等等。

最终不出意外地,这种硬编码知识的知识库方法最终逐渐淡出人们视野。这启发我们,机器想要智能,我们可以考虑让它有自己获取知识的能力——这样思路就由deduction转移到了induction。我们可以提供给机器足够的样例,让其从样例中进行“归纳”,这就是世人所称的机器学习(machine learning, ML)。“学习”这一名字非常贴切,我们人类从一无所知,到略有所知,正是靠着学习这一过程。如今正值大数据时代,“提供足够的样例”很多时候也不再是件难事。

从数据中学习,这似与统计学的目的不谋而合。百科全书可以找到“统计学是收集和分析数据的科学和艺术”的说法。宽泛地说,机器学习就是在做着统计的事,但如果不那么宽泛地看,机器学习里的统计血液是很淡薄的,这方面的原因有很多方面,这里暂时只谈其中几个。首先最明显的一个,ML的主要驱动力是提升结果指标,统计学则通常关注模型的理解。现代ML甚至接受表现优异的“黑箱模型”,也就是几乎不能理解为什么能这么优异的复杂模型;另一方面,传统统计学为了能更好地理解建立的模型,首先建立的模型就不会太复杂,这是当下所有的数学理论工具匮乏的缘故,然后再在这个不太复杂的模型上研究它的统计性质,如无偏性一致性等等。现代ML与传统统计的这种差异,直接导致了ML其关注落地、关注架构创新的浓重工程色彩,以及统计的关注推断方法改进、推导更多理论性质的浓重理论研究色彩。

然后我们从数据的角度来看二者的差异。传统统计是“出身贫寒”的,一般面对的都是“小数据”,大量来源于数据获取成本高昂、样本量有限的地方,例如医学试验、社会调查,在这种情况下,需要关注如何用更有效的方式收集数据,由此催生两个统计分支:抽样理论、试验设计。但现代ML“出身优渥”,身处“大数据”时代,现代社会每天每时每刻都在产生巨量的数据,很多时候数据是廉价的,于是重点变为了如何从中挖掘知识。大数据甚至可以大到无法使用上所有的数据,虽然还不能说“弱水三千却只能取一瓢饮”,但也是十分夸张了。

机器学习的分类

回到机器学习本身,现在问,如何机器学习?更具体地说,机器如何处理数据?一般地,我们会将数据集的每个样本\boldsymbol x都用一系列特征(feature) x_i (i=1,2,\dots)来表示。然后习惯上对ML有如下三种分类。有时,学习的目标是学习出每个\boldsymbol x与其对应的一个目标,或者称标签(label) y之间的关系,这种叫做监督学习(supervised learning),例如当y取值是一些类别时,这个任务就是分类(classification),当y取值是连续的实值时,这个任务就是回归(regression)。有时,学习的目标是学习出\boldsymbol x一些普遍的结构规律,这种叫做无监督学习(unsupervised learning),例如在给定一些\boldsymbol x的基础上,我们希望机器在学习后能举一反三,生成和它们类似的新\boldsymbol x。有时,我们要根据这些数据进行决策、行动,机器就在一个动态的环境中学习,通过与环境的互动获取经验,从而变得更为“智能”——从之前的历史信息中学习,得出接下来的最优行动。这种叫做强化学习(reinforcement learning)。这些就是人们对机器学习的三个经典分类。

这种分类只是习惯上的分类,监督学习和无监督学习之间的界限就是模糊的。例如要无监督地学习p(\boldsymbol x),我们可以拆分成监督学习的问题:
p(\boldsymbol x)=\prod p(x_i|x_1,\dots,x_{i-1}),逐步学习监督模型p(x_i|x_1,\dots,x_{i-1});另一方面要监督学习p(y|\boldsymbol x),可以先无监督学习p(\boldsymbol x,y),再得到p(y|\boldsymbol x)=\frac{p(\boldsymbol x,y)}{\sum\nolimits_{y'} p(\boldsymbol x,y')}.
现在可以看一个简单的示例。假设我们要教会一个小孩什么是等边三角形,但小孩不理解它的定义,我们用大量的图形实例来演示,以帮助其学习这一概念。在看过大量等边三角形和非等边三角形的图形后,小孩终于理解了,首先,图形必须是三角形,边数不对的必不是等边三角形;在此基础上,如果三边一样长,那么就是等边三角形。在这个过程中,小孩就学习到了一个简单的决策树模型,边数和边长就是要考虑的特征,首先通过边数判断,然后通过边长判断,得出图形是否为等边三角形的分类。

现在还可以进一步解释传统统计和机器学习的差异。前面说到监督学习包含分类和回归,回归分析是统计学的一个历史悠久的分支,现在在高中也要学单变量的回归分析。但是在传统统计里分类的重要性远远不如回归,这或许是因为传统统计对线性回归有着一套能合理处理最小二乘的线性代数的数学工具,在此出发也引申出了广义线性模型等更多回归模型,回归领域不断壮大,而分类在传统统计里仅有多元统计分析里的判别分析可以做。但现代AI的核心应用都在分类问题,ML的关注重点反而在分类。把问题离散化了,似乎对问题分析大为不利,但在实操层面却是简单了,因为这相当于把试卷上的解答题变成了选择题。一个题目给你的自由度越大,通常来说就会越难:判断题只有两个选项,选择题有多个选项,解答题更是要自行论述,它们的难度就是递增的(当然现实中的考试会平衡题型的难度,不过这与现在的比喻无关)。解答题对知识技能的要求更高,选择题则有排除法这种特殊技巧,也就意味着允许对某些特定细节模糊化。在实际中,大量问题的重点其实是把类分好就行了,而不是一个代表有多确定分类结果的数。

量化

“一门科学只有在成功地运用数学时,才算达到了真正完善的地步。”这句名言不无道理。要运用数学,量化是基础性的重要一环。对数据的量化,意味着有机会应用微积分、线性代数、概率统计等十八般数学武艺,现代计算机在数值计算上也是算力惊人。另一方面,量化意味着对问题的一种规范化。以下棋为例,棋手下棋要对形势有一个判断,例如当前己方“占优”,或是“大劣”,然后目标是下出“最好”的一步棋。但是对机器而言,什么叫“占优”、“大劣”?下的棋怎么样才称得上“最好”?在现代棋类AI里,这些都进行了数值上的量化,从而变成可供计算的数学问题。与之相对,人类棋手就不会这么数值化,而是依赖棋感、经验等来搜索出好棋。

很常见的一个情形是想要应用一个机器学习模型,但只接受数值特征,在手上有离散特征或者说分类特征时就要手动数值化了。如果这个特征本来就有顺序可言,比如疾病的无症状、轻症状、重症状,就可以将特征编码为0,1,\dots。在sklearn.preprocessing里,对应的是OrdinalEncoder。如果没有顺序关系,那么可用独热编码(one-hot encoder),将这特征编码为0{-}1特征,里面只有一个1,其余为0。例如性别为“男”、“女”时,分别编码为(1,0),(0,1)。在sklearn.preprocessing里,对应的是OneHotEncoder

泛化

为了衡量学习的效果,也需要确定用以衡量的定量的准则。对于一些任务,有一些简单的准则可供使用,例如分类里,分类准确率就是常用的可选项,再如强化学习以行动累积的回报作为衡量准则。对于某些任务,尤其是无监督学习任务,准则的选用则没有那么显然。准则一旦选定后,就可以定量地计算机器在数据集上的表现,要学习的目标也就量化成待最大化或最小化的目标函数,这就变成了一个最优化问题。

我们会希望机器在给定的一些样本进行训练(train)后,机器能在给定样本之外的数据里也能有良好的表现,也就是“泛化”(generalization)。数据集会被分为训练集和测试集,测试集就是用来测试(test)、评估机器的“泛化”表现。一般把大部分数据用于训练,小部分用于测试。

要很好地泛化,我们需要对数据的采集,或者说数据的生成,有一定的要求,最常见的就是假设所有数据都是独立同分布的(i.i.d.),我们记这个分布为p_{\mathrm{data}}。很多时候这是一种非常行之有效的假定。独立,意味着数据生成时认为它们互不干涉,一个不包含另外任一个的信息;同分布,表明数据都有同一个母体,从而可以得到这个母体的知识。IID时,由于都是对同一概率分布p_{\mathrm{data}}的期望,训练集上的期望表现等于测试集上的期望表现,于是训练得好时就代表有了好的泛化。

过拟合、欠拟合

在实际的训练中,我们不知道总体分布p_{\mathrm {data}},计算的只是在训练集上的样本的“经验分布”的表现,这就导致了训练集上的效果和所想目标的泛化效果之间产生了一定差异。当训练集表现很好而测试集很差时,这就是所说的“过拟合”(overfitting)现象。这是因为机器除了学普遍的p_{\mathrm{data}}上的规律外,还将随机性导致的样本独有的特性也学习进去了。例如判断一个人是否为程序员,如果因为见过的几个程序员恰好都穿格子衫而认为格子衫是程序员必要条件,那就闹了“过拟合”的笑话了。与过拟合相对的是欠拟合(underfitting),表现为训练集上的表现很差,模型尚未能很好地拟合数据。

形式化地说,如果训练集的数据确定的经验分布为\widehat p_{\mathrm {data}},那么我们想要优化的目标函数和实际优化的目标函数分别为
L=\mathbb E_{\mathbf x\sim p_{\mathrm {data}}}[l(\mathbf x)],\quad \widehat L=\mathbb E_{\mathbf x\sim \widehat p_{\mathrm {data}}}[l(\mathbf x)]=\frac1n\sum_{i=1}^n l(\boldsymbol x_i),其中l(\mathbf x)表示\mathbf x的优异衡量(不妨设这是个要最小化的损失函数),\{\boldsymbol x _ i\} _ {i=1}^n表示训练集。学习得到的模型最小化了\widehat L,而当优化后的\widehat L与目标L相去甚远时,过拟合就发生了。另一方面,我们知道\widehat p_{\mathrm{data}}一致地收敛于p_{\mathrm{data}},那么
\widehat L\to L,\quad n\to\infty.因而训练集样本量n越大,过拟合越不易发生。学习也就越好。

正则化

过拟合与欠拟合,与我们选用的模型的复杂度直接相关。复杂模型意味着它更容易把不想学到的东西也学进去。例如一个用带噪音微扰的二次函数生成10个样本,我们可以用一个九次函数模型完美拟合样本,但由于选用模型的复杂度太高,在这10个样本点之外的点拟合效果可以相当的差,如果把图像画出来看,就发现图像迅速“走样”,跟一开始设计的二次函数相去甚远;类似地,只用一次函数拟合,显然“欠拟合”了,这是个不能满足拟合需要的过于简单的模型。

一种控制模型复杂度的办法就是让我们可选的模型不能太多,亦即,控制假设空间(hypothesis space)的规模。九次函数可选的就比二次函数多太多了。

再例如,机器学习常用正则化(regularization)的方法控制模型复杂度。我们可以给损失函数加一个叫做正则化项的惩罚项。例如,回归问题中假设我们选用参数为\boldsymbol\theta的参数模型,要使得目标损失函数——训练集的均方误差\mathrm{MSE}(X_{\mathrm{train}};\boldsymbol\theta)——尽可能小。L2正则化则修改了目标函数,为
L(\boldsymbol\theta)=\mathrm{MSE}(X_{\mathrm{train}};\boldsymbol\theta)+\frac\lambda2\boldsymbol\theta^\mathsf T\boldsymbol\theta.其中\lambda是事先选好的数,除以2仅是习惯上为了推导的方便。第二项即是正则项,它使得训练出的模型偏好于L2范数较小的。新的损失函数表明,训练得到的模型并不只单纯只追求小MSE,也要有小的参数。通过调整\lambda的值,来达成这两方面的权衡。

超参数、交叉验证

像上面的\lambda这样,要提前给定的数,称作超参数(hyperparameter)。超参数的选取一般并不容易,因而一般会从训练集中进一步划分出一份验证(validation)集,用以选取超参数,这个过程即是“调参”(parameter tuning)。由于测试集不能用于模型选择,自然也不能用于超参数的选取。

对于测试集,一般占比比较小(相对于训练集),可能会出现\frac1{n _ {\mathrm{test}}}\sum _ {j}l(\boldsymbol x _ {j})\mathbb E _ {\mathbf x\sim p _ {\mathrm {data}}}[l(\mathbf x)]有较大相差的情况。因而为了更准确地估计泛化误差,可以考虑采用交叉验证(cross-validation)的方法。k折交叉验证是将数据集划分为k个子集,每次用一个子集作为测试集,其余作为训练集,这样就可以用k次平均的测试误差来估计泛化误差。

算法

当我们有了数据集及其划分,再根据评估准则确定一个目标函数(一般是取为要最小化的损失函数),以及选定假设空间之后,就可以执行学习算法了。一个经典的机器学习算法核心步骤如下:

0. 得到训练集和测试集、确定损失函数、假设空间;train_test_splitsklearn.metrics
1. 构建一个初始模型;
2. 对损失函数进行优化。.fit()

优化完毕后输出的模型就可以在测试集上评估泛化效果了。.predict()

from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

X_train, X_test, y_train, y_test = train_test_split(...)
model = ...

model.fit(X_train, y_train)
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)

举例来说,优化的一个经典算法是随机梯度下降(stochastic gradient descent, SGD)。计算损失函数对一些参数的梯度,数据集较大时只在一部分样本上计算来估计,按这个梯度进行参数更新,从而得到优化。

一般我们可以将机器学习的模型分为参数模型和非参数模型,其区别相当于参数统计与非参数统计。粗略地说,如果我们建立的模型数学形式已知,而只包含固定个数的有限个未知的参数,那么这个模型就可以说是参数模型;否则,就是非参数模型。

首先来看参数模型,设模型形式为p _ {\mathrm{model}}(\mathbf x;\boldsymbol \theta),表示我们对数据生成分布的估计。我们有n个数据x _ 1,\dots,x _ n\sim p _ {\mathrm{data}}(\mathbf x)。要估计\boldsymbol \theta时,统计领域里习惯划分出两个派别:频率派和贝叶斯派。

极大似然估计

假设我们的建模是合适的,我们先视数据生成分布中的\boldsymbol \theta为固定的实值参数,那么似然函数就可以写作p _ {\mathrm{model}}(X;\boldsymbol \theta)=\prod _ i p _ {\mathrm{model}}(\boldsymbol x _ i;\boldsymbol \theta),那么\boldsymbol \theta极大似然估计(maximum likelihood estimation, MLE)就是
\boldsymbol \theta _ {\mathrm{MLE}}=\operatorname*{\arg\max} _ {\boldsymbol \theta}\sum _ {i=1}^n\ln p(\boldsymbol x _ i;\boldsymbol \theta).习惯上,我们会取对数从而便于计算,这样就不用计算n个概率的乘积了。

MLE是极为常用的估计方法,因为它可以说是渐进最优的。如果\hat {\boldsymbol \theta}满足\hat{\boldsymbol \theta}-\boldsymbol \theta\stackrel d\to N(\boldsymbol 0,V),那么“渐近方差越小”,我们就认为这个\hat {\boldsymbol \theta}越好。当n充分大时,\hat {\boldsymbol \theta}几乎是无偏估计,由Cramér-Rao不等式,方差有下界I(\boldsymbol \theta)^{-1},即Fisher信息的逆。那么,如果渐进分布的V恰为I(\boldsymbol \theta)^{-1},那么该\hat {\boldsymbol \theta}自然是最好的。MLE的性质恰好就是它满足这个渐进分布,因而可说是渐进最优的。(非严格分析)

还有一种理解MLE的方式是MLE最小化了p _ {\mathrm{model}}和经验分布\hat p _ {\mathrm{data}}之间的KL散度:
\begin{aligned}
\operatorname*{\arg\min} _ {\boldsymbol \theta}D _ {\mathrm{KL}}(\hat p _ {\mathrm{data}}\|p _ {\mathrm{model}})&=\operatorname*{\arg\min} _ {\boldsymbol \theta}{-}\mathbb E _ {\mathbf x\sim \hat p _ {\mathrm{data}}}\Big[\ln\frac{p _ {\mathrm{model}}(\mathbf x)}{\hat p _ {\mathrm{data}}(\mathbf x)}\Big]\\
&=\operatorname*{\arg\max} _ {\boldsymbol \theta}\mathbb E _ {\mathbf x\sim \hat p _ {\mathrm{data}}}\ln p _ {\mathrm{model}}(\mathbf x)\\
&=\boldsymbol \theta _ {\mathrm{MLE}}.
\end{aligned}

Bayes估计

现在我们换到Bayesian的思路。这种思路首先将我们对\boldsymbol \theta的所有认识归结到一个分布,称作先验分布(prior distribution)中,设为p(\boldsymbol \theta)。然后用数据来更新对\boldsymbol \theta的认识,由贝叶斯定理,这个过程可写作
p(\boldsymbol \theta|X )\propto p(\boldsymbol \theta)p(X|\boldsymbol \theta).这个p(\boldsymbol \theta|X)就叫后验分布(posterior distribution)。

Bayes估计会使用整个后验分布来作为\boldsymbol \theta的估计,而不是仅采用一个点估计,这是与MLE的重大区别之一。例如对新数据\mathbf x的预测,Bayes估计为
p(\boldsymbol x|X)\boldsymbol =\int p(\boldsymbol x|\boldsymbol \theta)p(\boldsymbol \theta|X)\, \mathrm d\boldsymbol \theta.
尽管如此,对于点估计的需求还是非常常见的。一种方案是在后验分布中取最大后验估计MAP (maximum a posteriori),此即选择使得后验概率最大的\boldsymbol \theta
\boldsymbol \theta _ {\mathrm{MAP}}=\operatorname*{\arg\max} _ {\boldsymbol \theta}p(\boldsymbol \theta|X).另一种理解MAP的方式是MAP最小化了后验期望损失:
\operatorname*{\arg\min} _ {\boldsymbol \theta}\int (1-\delta(\hat{\boldsymbol \theta}-\boldsymbol \theta))p(\boldsymbol \theta|X)\, \mathrm d\boldsymbol \theta=\operatorname*{\arg\min} _ {\boldsymbol \theta}[1-p(\hat{\boldsymbol \theta}|X)].其中\delta(\cdot)表示Dirac delta函数。类似地,当损失函数从1-\delta(\hat{\boldsymbol \theta}-\boldsymbol \theta)换为其它函数时,得到其它点估计,例如取(\hat{\boldsymbol \theta}-\boldsymbol \theta)^2时即为后验均值\mathbb E[{\boldsymbol \theta}|X]

非参数模型

非参数模型对数据结构的假设更少,因而提供了较高的灵活性。

举例来说,监督学习里,k近邻法、核方法、支持向量机(SVM)、基于树的方法、集成的方法,都是很经典的非参数模型。我们通常需要一个相似度度量,或者一个距离度量,模型则依赖新样本\boldsymbol x与诸训练集数据\boldsymbol x _ i的相似度或距离构建。在这个度量的基础上构建模型,最简单、最基础的构建例如投票(对分类),以及平均(对回归),在此基础上的复杂构建则可以得到高级的模型。集成学习则可以将多个模型进行恰当的结合,以得到比单个模型更好的集成模型。

再如,无监督学习里,核密度估计(KDE)、主成分分析(PCA)、聚类分析都是十分经典的。后两者都可以看作是对数据的尽可能好的压缩,PCA是把数据的诸多特征只用很少量的主成分来表示,聚类分析则可以看作是把每个样本压缩到了cluster的index上。事实上,它们也需要一个相似度度量或距离度量(很多时候是默认的欧氏距离度量)。

深度学习、强化学习

深度学习、强化学习是机器学习下比较大的流行分支。可参看如下二文:

深度学习现代概述

强化学习基础概览


评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注