4. 检测异常
首先,我们可以检测到模型里的缺陷。或许我们不能修正它们,但是至少可以检测出来。如果能检测到模型里的某个异常,那么就可以寻求用户的帮助,或者可以采取一些我们认为比机器学习到的更安全的措施。
比如,我们可以监测预测类别的分布。试想一下,我们在做手写字符的识别系统,在英语里,我们知道字符是有一定分布频率的:最常见的英语字符是E,第二常见的是T,等等。我们可以观察一下模型的分类器的结果,对比预测的分布,如果两者相差很大,那么很可能是出了问题。
另一种方法是马尔科夫决策过程。举个例子,如果我们正在玩游戏,并希望达到某个目标,那么我们玩的时间越长,离达成目标的距离就越近。
比如,这是我们的预期价值函数,是解决问题的步骤。通常情况下,我们在玩游戏或者按计划执行时是在朝上走的,最大限度地让价值最大化。当然,当我们做的不好时,可以看到有些曲线的轨迹并不是朝上走,看起来就像我们脱离了轨道,这或许意味着我们的模型存在一些问题。
另外一件可以做的事就是监测辅助规律。Hermansky 写过一篇很有意思的论文,是关于语音识别里的未知的未知。在做语音识别时,你可以为不同的频段,比如低频、中频、高频,训练单独的识别器。在自然语言中,你发出的两个音节之间是有时间间隔的,因此我们可以监控这些间隔时长。如果我们发现分类器给出的分布结果和我预期的差别很大,那么就可以探测哪个地方出了问题。
Hermansky 提出了一个解决方案:弄清楚哪些频段其实是噪音,因为在给定的环境中,有一些类型的噪音源其实是集中在某一个频段的。
另外一个例子要追溯到1992年的一个自动驾驶汽车项目。当时这个系统很简单,只有一个车道保持系统和一个自动转向系统,是用神经网络做的。在这个神经网络里,有一个摄像头用来拍摄道路、树木等,然后这些信息会通过4 个隐藏单元用来预测转向指令。此外,这4 个隐藏单元对输入的图片进行重构,这样就可以比较原始图片和重构后图片之间的差异,如果两者之间的差异较大,那么这个转向命令就是不可信的。
在这一想法中,相同的隐藏层要完成两项任务,因此我们可以监测这些隐藏单元。如果重构后的图片差异很大,那么这些隐藏单元的这项任务完成的并不好,这也就意味着在预测转向命令这一任务上,这些隐藏单元可能也做的很差。
我们可以做的另外一件事就是观察异常情况。如上图所示,我们的训练样本的分布是Ptrain,通过这些训练样本,训练出分类器。我们的测试样本的分布则是Ptest。如果训练样本的分布和测试样本的分布相同,那么系统的准确性就能得到保障。但是通常情况下,测试样本和训练样本的分布是不一样的,在这种情况下应该怎样做?
当然,你肯定听说过领域适应(Domain Adoption)和迁移学习。我要讲的可能是稍微简单一点的问题,仅仅只需要检测测试数据是否与训练数据不同,这个例子是基于我在计算机视觉领域的一项研究工作。此前,我曾参加过一个生态学的项目。当时我们想要衡量美国淡水河流的健康程度,于是环保部门派了一些人去收集这些河流里的昆虫标本,将昆虫的分布状态作为判断河流健康程度的标准。
我们要做的是建立一个计算机视觉系统,来对这些昆虫进行分类,那些户外的工作人员收集了29 种昆虫作为训练的数据集。后来,我们利用这些数据训练一个监督学习系统,而且运行结果也不错。但是,很快发现,有的测试数据并不是这29 类中的一种,有可能是其他的昆虫,或者小石头、叶片、垃圾等。我们要怎样做?
此前我们曾做过很多关于异常检测的工作,这里的方法很简单,就是在系统里加一个异常检测器,它主要用来负责检测新图片。如果这张图片与训练数据中的图片看起来很陌生,它就会给定一个“异常分数”,如果这个分数超过某个阈值,那么系统就会“拒绝”这张图片;如果低于这个阈值,那么就可以放行,进入到下一步——分类器。
这里是一个初步的研究,我们训练分类器的时候只用了两个类别的数据,但是实际的测试数据包括26 类。
实际上,还有很多其他的尝试,其中一些可能比我们现在的要好。比如Open Category Classification 、Change-Point Detection、Covariate Shift Correction、Domain Adaptation,它们都是和这些问题相关的。