监督学习是目前最常见的机器学习类型。给定一组样本(通常由人工标注),它可以学会将
输入数据映射到已知目标[也叫标注(annotation)]。
虽然监督学习主要包括分类和回归,但还有更多的奇特变体,主要包括如下几种。
序列生成(sequence generation)。给定一张图像,预测描述图像的文字。序列生成有时可以被重新表示为一系列分类问题,比如反复预测序列中的单词或标记。
语法树预测(syntax tree prediction)。给定一个句子,预测其分解生成的语法树。
目标检测(object detection)。给定一张图像,在图中特定目标的周围画一个边界框。这个问题也可以表示为分类问题(给定多个候选边界框,对每个框内的目标进行分类)或分类与回归联合问题(用向量回归来预测边界框的坐标)。
图像分割(image segmentation)。给定一张图像,在特定物体上画一个像素级的掩模(mask)。
降维(dimensionality reduction)和聚类(clustering)都是众所周知的无监督学习方法。
自监督学习是监督学习的一个特例,它与众不同,值得单独归为一类。自监督学习是没有人工标注的标签的监督学习,你可以将它看作没有人类参与的监督学习。
标签仍然存在(因为总要有什么东西来监督学习过程),但它们是从输入数据中生成的,通常是使用启发式算法生成的。
举个例子,自编码器(autoencoder)是有名的自监督学习的例子,其生成的目标就是未经修改的输入。同样,给定视频中过去的帧来预测下一帧,或者给定文本中前面的词来预测下一个词,都是自监督学习的例子[这两个例子也属于时序监督学习(temporally supervised learning),即用未来的输入数据作为监督]。
注意,监督学习、自监督学习和无监督学习之间的区别有时很模糊,这三个类别更像是没有明确界限的连续体。
分类和回归术语表
样本(sample)或输入(input):进入模型的数据点。
预测(prediction)或输出(output):从模型出来的结果。
目标(target):真实值。对于外部数据源,理想情况下,模型应该能够预测出目标。
预测误差(prediction error)或损失值(loss value):模型预测与目标之间的距离。
类别(class):分类问题中供选择的一组标签。例如,对猫狗图像进行分类时,“狗”和“猫”就是两个类别。
标签(label):分类问题中类别标注的具体例子。比如,如果 1234 号图像被标注为包含类别“狗”,那么“狗”就是 1234 号图像的标签。
真值(ground-truth)或标注(annotation):数据集的所有目标,通常由人工收集。
二分类(binary classification):一种分类任务,每个输入样本都应被划分到两个互斥的类别中。
多分类(multiclass classification):一种分类任务,每个输入样本都应被划分到两个以上的类别中,比如手写数字分类。
多标签分类(multilabel classification):一种分类任务,每个输入样本都可以分配多个标签。举个例子,如果一幅图像里可能既有猫又有狗,那么应该同时标注“猫”标签和“狗”标签。每幅图像的标签个数通常是可变的。
标量回归(scalar regression):目标是连续标量值的任务。预测房价就是一个很好的例子,不同的目标价格形成一个连续的空间。
向量回归(vector regression):目标是一组连续值(比如一个连续向量)的任务。如果对多个值(比如图像边界框的坐标)进行回归,那就是向量回归。
小批量(mini-batch)或批量(batch):模型同时处理的一小部分样本(样本数通常为 8~128)。样本数通常取 2 的幂,这样便于 GPU 上的内存分配。训练时,小批量用来为模型权重计算一次梯度下降更新。
评估模型的重点是将数据划分为三个集合:训练集、验证集和测试集。在训练数据上训练模型,在验证数据上评估模型。一旦找到了最佳参数,就在测试数据上最后测试一次。
你可能会问,为什么不是两个集合:一个训练集和一个测试集?在训练集上训练模型,然后在测试集上评估模型。这样简单得多!
原因在于开发模型时总是需要调节模型配置,比如选择层数或每层大小[这叫作模型的超参数(hyperparameter),以便与模型参数(即权重)区分开]。这个调节过程需要使用模型在验证数据上的性能作为反馈信号。这个调节过程本质上就是一种学习:在某个参数空间中寻找良好的模型配置。
因此,如果基于模型在验证集上的性能来调节模型配置,会很快导致模型在验证集上过拟合,即使你并没有在验证集上直接训练模型也会如此。
造成这一现象的关键在于信息泄露(information leak)。每次基于模型在验证集上的性能来调节模型超参数,都会有一些关于验证数据的信息泄露到模型中。如果对每个参数只调节一次,那么泄露的信息很少,验证集仍然可以可靠地评估模型。但如果你多次重复这一过程(运行一次实验,在验证集上评估,然后据此修改模型),那么将会有越来越多的关于验证集的信息泄露到模型中。
书中提到的三种验证方法:
1. 简单的留出验证
2.K折验证
3. 带有打乱数据的重复 K 折验证
如果可用的数据相对较少,而你又需要尽可能精确地评估模型,那么可以选择带有打乱数据的重复 K 折验证(iterated K-fold validation with shuffling)。我发现这种方法在 Kaggle 竞赛中
特别有用。具体做法是多次使用 K 折验证,在每次将数据划分为 K 个分区之前都先将数据打乱。
最终分数是每次 K 折验证分数的平均值。注意,这种方法一共要训练和评估 P×K 个模型(P
是重复次数),计算代价很大。
4.2.2 评估模型的注意事项
选择模型评估方法时,需要注意以下几点。
数据代表性(data representativeness)。你希望训练集和测试集都能够代表当前数据。例
如,你想要对数字图像进行分类,而图像样本是按类别排序的,如果你将前 80% 作为训
练集,剩余 20% 作为测试集,那么会导致训练集中只包含类别 0~7,而测试集中只包含
类别 8~9。这个错误看起来很可笑,却很常见。因此,在将数据划分为训练集和测试集
之前,通常应该随机打乱数据。
时间箭头(the arrow of time)。如果想要根据过去预测未来(比如明天的天气、股票走势
等),那么在划分数据前你不应该随机打乱数据,因为这么做会造成时间泄露(temporal
leak):你的模型将在未来数据上得到有效训练。在这种情况下,你应该始终确保测试集
中所有数据的时间都晚于训练集数据。
数据冗余(redundancy in your data)。如果数据中的某些数据点出现了两次(这在现实中
的数据里十分常见),那么打乱数据并划分成训练集和验证集会导致训练集和验证集之
间的数据冗余。从效果上来看,你是在部分训练数据上评估模型,这是极其糟糕的!一
定要确保训练集和验证集之间没有交集。
4.3.1 神经网络的数据预处理
数据预处理的目的是使原始数据更适于用神经网络处理,包括向量化、标准化、处理缺失值和特征提取。
1. 向量化
神经网络的所有输入和目标都必须是浮点数张量(在特定情况下可以是整数张量)。无论处理什么数据(声音、图像还是文本),都必须首先将其转换为张量,这一步叫作数据向量化(data vectorization)。例如,在前面两个文本分类的例子中,开始时文本都表示为整数列表(代表单词序列),然后我们用 one-hot 编码将其转换为 float32 格式的张量。在手写数字分类和预
测房价的例子中,数据已经是向量形式,所以可以跳过这一步。
2. 值标准化
在手写数字分类的例子中,开始时图像数据被编码为 0~255 范围内的整数,表示灰度值。将这一数据输入网络之前,你需要将其转换为 float32 格式并除以 255,这样就得到 0~1 范围内的浮点数。同样,预测房价时,开始时特征有各种不同的取值范围,有些特征是较小的浮点数,有些特征是相对较大的整数。将这一数据输入网络之前,你需要对每个特征分别做标准化,使
其均值为 0、标准差为 1。
一般来说,将取值相对较大的数据(比如多位整数,比网络权重的初始值大很多)或异质数据(heterogeneous data,比如数据的一个特征在 0~1 范围内,另一个特征在 100~200 范围内)输入到神经网络中是不安全的。这么做可能导致较大的梯度更新,进而导致网络无法收敛。为了让网络的学习变得更容易,输入数据应该具有以下特征。
取值较小:大部分值都应该在 0~1 范围内。
同质性(homogenous):所有特征的取值都应该在大致相同的范围内。
此外,下面这种更严格的标准化方法也很常见,而且很有用,虽然不一定总是必需的(例如,
对于数字分类问题就不需要这么做)。
将每个特征分别标准化,使其平均值为 0。
将每个特征分别标准化,使其标准差为 1。
这对于 Numpy 数组很容易实现。
3. 处理缺失值
你的数据中有时可能会有缺失值。例如在房价的例子中,第一个特征(数据中索引编号为0 的列)是人均犯罪率。
如果不是所有样本都具有这个特征的话,怎么办?那样你的训练数据或测试数据将会有缺失值。
一般来说,对于神经网络,将缺失值设置为 0 是安全的,只要 0 不是一个有意义的值。
网络能够从数据中学到 0 意味着缺失数据,并且会忽略这个值。
注意,如果测试数据中可能有缺失值,而网络是在没有缺失值的数据上训练的,那么网络不可能学会忽略缺失值。在这种情况下,你应该人为生成一些有缺失项的训练样本:多次复制一些训练样本,然后删除测试数据中可能缺失的某些特征。
深度学习出现之前,特征工程曾经非常重要,因为经典的浅层算法没有足够大的假设空间来自己学习有用的表示。
幸运的是,对于现代深度学习,大部分特征工程都是不需要的,因为神经网络能够从原始
数据中自动提取有用的特征。这是否意味着,只要使用深度神经网络,就无须担心特征工程呢?
并不是这样,原因有两点。
良好的特征仍然可以让你用更少的资源更优雅地解决问题。例如,使用卷积神经网络来
读取钟面上的时间是非常可笑的。
良好的特征可以让你用更少的数据解决问题。深度学习模型自主学习特征的能力依赖于
大量的训练数据。如果只有很少的样本,那么特征的信息价值就变得非常重要。
表 4-1 为模型选择正确的最后一层**和损失函数
| 问题类型 | 最后一层** | 损失函数 |
| 二分类问题 | sigmoid | binary_crossentropy |
| 多分类、单标签问题 | softmax | categorical_crossentropy |
| 多分类、多标签问题 | sigmoid | binary_crossentropy |
| 回归到任意值 | 无 | mse |
| 回归到 0~1 范围内的值 | sigmoid | mse 或 binary_crossentropy |