机器学习基础
本章涵盖了以下主题:
[if !supportLists]· [endif]分类和回归之外的其他类型的问题;
[if !supportLists]· [endif]评估问题,理解过拟合、欠拟合,以及解决这些问题的技巧;
[if !supportLists]· [endif]为深度学习准备数据。
请记住,在本章中讨论的大多数技术都是机器学习和深度学习通用的,一部分用于解决过拟合问题的技术(如dropout)除外。
4.1 三类机器学习问题
在之前的所有例子中,尝试解决的是分类(预测猫或狗)或回归(预测用户在平台上花费的平均时间)问题。所有这些都是有监督学习的例子,目的是找到训练样例和目标之间的映射关系,并用来预测未知数据。
有监督学习只是机器学习的一部分,机器学习也有其他不同的部分。以下是3种不同类型的机器学习:
[if !supportLists]· [endif]有监督学习;
[if !supportLists]· [endif]无监督学习;
[if !supportLists]· [endif]强化学习。
下面详细讲解各种算法。
4.1.1 有监督学习
在深度学习和机器学习领域中,大多数成功用例都属于有监督学习。本书中所涵盖的大多数例子也都是有监督学习的一部分。来看看有监督学习的一些常见的例子。
[if !supportLists]· [endif]分类问题:狗和猫的分类。
[if !supportLists]· [endif]回归问题:预测股票价格、板球比赛成绩等。
[if !supportLists]· [endif]图像分割:进行像素级分类。对于自动汽车驾驶来说,从摄像机拍摄的照片中,识别出每个像素属于什么物体是很重要的。这些像素可以是汽车、行人、树、公共汽车等。
[if !supportLists]· [endif]语音识别:OK Google、Alexa和Siri都是语音识别的例子。
[if !supportLists]· [endif]语言翻译:从一种语言翻译成另一种语言。
4.1.2 无监督学习
在没有标签数据的情况时,可以通过可视化和压缩来帮助无监督学习技术理解数据。两种常用的无监督学习技术是:
[if !supportLists]· [endif]聚类;
[if !supportLists]· [endif]降维。
聚类有助于将所有相似的数据点组合在一起。降维有助于减少维数,从而可视化高维数据,并找到任何隐藏的模式。
4.1.3 强化学习
强化学习是最不流行的机器学习范畴。在真实世界中没有发现它的成功用例。然而,近年来有了些改变,来自Google的DeepMind团队成功地构建了基于强化学习的系统,并且在AlphaGo比赛中赢得世界冠军。计算机可以在比赛中击败人类的这种技术上的进展,曾被认为需要花费数十年时间才能实现。然而,使用深度学习和强化学习却可以这么快就达到目标,比任何人所预见的都要快。这些技术已经可以看到早期的成功,但可能需要几年时间才能成为主流。
在本书中,我们将主要关注有监督的技术和一些特定于深度学习的无监督技术,例如用于创建特定风格图片的生成网络:风格迁移(style transfer)和生成对抗网络(generative adversarial network)。
4.2 机器学习术语
前面几章出现了大量的术语,如果大家刚入门机器学习或深度学习领域,这些术语看起来会比较生疏。这里将列出机器学习中常用的多数术语,这些通常也在深度学习文献中使用。
[if !supportLists]· [endif]样本(sample)或输入(input)或数据点(data point):训练集中特定的实例。我们在上一章中看到的图像分类问题,每个图像都可以被称为样本、输入或数据点。
[if !supportLists]· [endif]预测(prediction)或输出(output):由算法生成的值称为输出。例如,在先前的例子中,我们的算法对特定图像预测的结果为0,而0是给定的猫的标签,所以数字0就是我们的预测或输出。
[if !supportLists]· [endif]目标(target)或标签(label):图像实际标注的标签。
[if !supportLists]· [endif]损失值(loss value)或预测误差(prediction error):预测值与实际值之间的差距。数值越小,准确率越高。
[if !supportLists]· [endif]类别(classes):给定数据集的一组可能的值或标签。在前一章的例子中有猫和狗两种类别。
[if !supportLists]· [endif]二分类(binary classification):将输入实例归类为两个互斥类别中的其中一个的分类任务。
[if !supportLists]· [endif]多类别分类(multi-class classification):将输入实例归类为两个以上的不同类别的分类任务。
[if !supportLists]· [endif]多标签分类(multi-label classification):一个输入实例可以用多个标签来标记。例如根据提供的食物不同来标记餐馆,如意大利菜、墨西哥菜和印度菜。另一个常见的例子是图片中的对象检测,它使用算法识别出图片中的不同对象。
[if !supportLists]· [endif]标量回归(scalar regression):每个输入数据点都与一个标量质量(scalar quality)相关联,该标量质量是数值型的。这样的例子有预测房价、股票价格和板球得分等。
[if !supportLists]· [endif]向量回归(vector regression):算法需要预测不止一个标量质量。一个很好的例子当你试图识别图片中鱼的位置边界框时。为了预测边界框,您的算法需要预测表示正方形边缘的4个标量。
[if !supportLists]· [endif]批(batch):大多数情况下,我们在称为批的输入样本集上训练我们的算法。取决于GPU的内存,批尺寸一般从2~256不等,权重也在每个批次上进行更新,因此算法往往比在单个样例上训练时学习的更快。
[if !supportLists]· [endif]轮数:在整个数据集上运行一遍算法称为一个Epoch。通常要训练(更新权重)几个Epoch。
4.3 评估机器学习模型
在上一章中介绍的图像分类示例中,我们将数据分成两个不同的部分,一个用于训练,一个用于验证。使用单独的数据集来测试算法的性能是一种很好的做法,因为在训练集上测试算法可能无法让用户获得算法真正的泛化能力。在大多数现实世界的用例中,基于验证的准确率,我们经常以不同方式来调整算法,例如添加更多的层或不同的层,或者使用不同的技术,这些将在本章的后面部分进行介绍。因此,选择基于验证数据集来调整算法的可能性更高。以这种方式训练的算法往往在训练数据集和验证数据集上表现良好,但当应用到未知的数据时可能会失败。验证数据集上的信息泄露会影响到对算法的调整。
为了避免信息泄露并改进泛化的问题,通常的做法是将数据集分成3个不同的部分,即训练、验证和测试数据集。我们在训练集和验证集上训练算法并调优所有超参数。最后,当完成整个训练时,在测试数据集上对算法进行测试。我们讨论过有两种类型的参数。一种是在算法内使用的参数或权重,通过优化器或反向传播进行调优。另一种是称为超参数(hyper parameter)的参数,这些参数控制着网络中所用层的数量、学习率以及通常改变架构(这种改变经常是手动调整的)的其他类型的参数。
特定的算法在训练集中表现非常优越,但在验证集或测试集上却表现不佳的现象称为过拟合(overfitting),或者说算法缺乏泛化的能力。存在一种相反的现象,即算法在训练集上的表现不佳,这种现象称为欠拟合(underfitting)。后面将学习可以帮助解决过拟合和欠拟合问题的不同策略。
在了解过拟合和欠拟合之前,先看看可用于拆分数据集的各种策略。
4.3.1 训练、验证和测试集的拆分
将数据划分成3个部分——训练、验证和测试数据集是最佳实践。使用保留(holdout)数据集的最佳方法如下所示。
1.在训练数据集上训练算法。
2.在验证数据集上进行超参数调优。
3.迭代执行前两个步骤,直到达到预期的性能。
4.在冻结算法和超参数后,在测试数据集上进行评估。
应避免只将数据划分成两部分,因为这可能导致信息泄露。在相同的数据集上进行训练和测试是绝对不不允许的,这将无法保证算法的泛化能力。将数据分割成训练集和验证集有3种常用的保留策略,它们是:
[if !supportLists]· [endif]简单保留验证;
[if !supportLists]· [endif]K折验证;
[if !supportLists]· [endif]迭代K折验证。
1.简单保留验证
划分一定比例的数据作为测试数据集。留出多大比例的数据可能是和特定问题相关的,并且很大程度上依赖于可用的数据量。特别是对于计算机视觉和自然语言处理领域中的问题,收集标签数据可能非常昂贵,因此留出30%的测试数据(比例相当大)可能会使算法学习起来非常困难,因为用于训练的数据很少。因此,需要根据数据的可用性,谨慎地选择划分比例。测试数据拆分后,在冻结算法及其超参数前,要保持数据的隔离。为了给问题选择最佳超参数,请选择单独的验证数据集。为了避免过拟合,通常将可用数据划分成3个不同的集合,如图4.1所示。
上一章使用了图4.1的简单实现来创建验证数据集,实现的快照如下:
图4.1
这是最简单的保留策略之一,通常在开始时使用。在小型数据集上使用这种划分策略有一个弊端,验证数据集或测试数据集中的现有数据可能不具有统计代表性。在划分数据前混洗数据即可以轻松意识到这一点。如果得到的结果不一致,那么需要使用更好的方法。为了避免这个问题,我们最后通常使用K折(K-fold)验证或迭代K折(iterated k-fold)验证。
2.K折验证
留出一定比例的数据用于测试,然后将整个数据集分成K个数据包,其中K可以是任意数值,通常从2到10不等。在任意给定的迭代中,选取一个包作为验证数据集,并用其余的数据包训练算法。最后的评分通常是在K个包上获得的所有评分的平均值。图4.2所示为一个K折验证的实现,其中K为4;也就是说,数据划分成4部分(称为4折验证)。
使用K折验证数据集时,要注意的一个关键问题是它的代价非常昂贵,因为需要在数据集的不同部分上运行该算法数次,这对于计算密集型算法来说是非常昂贵的,特别是在计算机视觉算法领域。有时候,训练算法可以花费从几分钟到几天的时间。所以,请谨慎地使用这项技术。
3.带混洗的K折验证
为了使算法变得复杂和健壮,可以在每次创建保留的验证数据集时混洗数据。当小幅度的性能提升提升可能会对业务产生巨大影响时,这种做法是有益的。如果我们的情况是快速构建和部署算法,并且可以接受百分之几的性能差异,那么这种方法可能并不值得。所有这一切都取决于试图要解决的问题,以及对准确率的要求。
图4.2
在拆分数据时可能需要考虑其他一些事情,例如:
[if !supportLists]· [endif]数据代表性;
[if !supportLists]· [endif]时间敏感性;
[if !supportLists]· [endif]数据冗余。
1.数据代表性
在上一章中的例子中,我们把图像分类为狗或者猫。假设有这样一个场景,所有的图像已被排序,其中前60%的图像是狗,其余的是猫。如果选择前面的80%作为训练数据集,其余的作为验证集来分割这个数据集,那么验证数据集将无法代表数据集的真实性,因为它只包含猫的图像。因此,在这些情况下,应该注意通过在分割或进行分层抽样之前对数据进行混洗来实现数据的良好混合。分层抽样是指从每个类别中提取数据点来创建验证和测试数据集。
2.时间敏感性
让我们以股价预测为例。我们有从1月到12月的数据。在这种情况下,如果进行混洗或分层抽样,那么最终将会造成信息的泄露,因为价格很可能是时间敏感的。因此,创建验证数据集时应采用不会引起信息泄露的方式。本例中,选择12月的数据作为验证数据集可能更合理。实际的股价预测用例比这要复杂得多,因此在选择验证分割时,特定领域的知识也会发挥作用。
3.数据冗余
重复数据是很常见的。需要注意的是,在训练、验证和测试集中存在的数据应该是唯一的。如果有重复,那么模型可能无法很好地泛化未知数据。
4.4 数据预处理与特征工程
我们已经了解了使用不同的方法来划分数据集并构建评估策略。在大多数情况下,接收到的数据可能并不是训练算法立即可用的格式。本节将介绍一些预处理技术和特征工程技术。虽然大部分的特征工程技术都是针对特定领域的,特别是计算机视觉和文本处理领域,但还是有一些通用的特征工程技术,这将在本章中讨论。
神经网络的数据预处理是一个使数据更适合于深度学习算法训练的过程。以下是一些常用的数据预处理步骤:
[if !supportLists]· [endif]向量化;
[if !supportLists]· [endif]归一化;
[if !supportLists]· [endif]缺失值;
[if !supportLists]· [endif]特征提取。
4.4.1 向量化
数据通常表现为各种格式,如文本、声音、图像和视频。首先要做的就是把数据转换成PyTorch张量。在前面的例子中,使用tourchvision的工具函数将Python图形库(Python Imaging Library,PIL)的图片转换成张量对象,尽管PyTorchtorchvision库抽取出了大部分的复杂度。在第7章中处理递归神经网络(Recurrent Neural Network,RNN)时,将了解如何把文本数据转换成PyTorch张量。对于涉及结构化数据的问题,数据已经以向量化的格式存在,我们需要做的就是把它们转换成PyTorch张量。
4.4.2 值归一化
在将数据传递到任何机器学习算法或深度学习算法之前,将特征归一化是一种通用实践。它有助于更快地训练算法并达到更高的性能。归一化是指,将特定特征的数据表示成均值为0、标准差为1的数据的过程。
在上一章所描述的狗猫分类的例子中,使用了ImageNet数据集中已有的均值和标准差来归一化数据。我们选择ImageNet数据集的均值和标准差的原因,是因为使用的ReNet模型的权重是在ImageNet上进行预训练的。通常的做法是将每个像素值除以255,使得所有值都在0和1之间,尤其是在不使用预训练权重的情况下。
归一化也适用于涉及结构化数据的问题。假设我们正在研究房价预测问题,可能存在不同规模的不同特征。例如,到最近的机场的距离和房子的屋龄是具备不同度量的变量或特征。将它们与神经网络一起使用可以防止梯度收敛。简单来说,损失可能不会像预期的那样下降。因此,在对算法进行训练之前,应该谨慎地将归一化应用到任何类型的数据上。为了使算法或模型性能更好,应确保数据遵循以下规则。
[if !supportLists]· [endif]取较小的值:通常取值在0和1之间。
[if !supportLists]· [endif]相同值域:确保所有特征都在同一数据范围内。
4.4.3 处理缺失值
缺失值在现实世界的机器学习问题中是很常见的。从之前预测房价的例子来看,房屋屋龄的某些信息可能会丢失。通常用不可能出现的数字替换缺失值是安全的。算法将能够识别模式。还有其他技术可用于处理更特定领域的缺失值。
4.4.4 特征工程
特征工程是利用特定问题的领域知识来创建可以传递给模型的新变量或特征的过程。为了更好地理解,来看一个销售预测的问题。假设我们有促销日期、假期、竞争者的开始日期、与竞争对手的距离以及特定日期的销售情况。在现实世界中,有数以百计的特征可以用来预测店铺的价格,可能有一些信息在预测销售方面很重要。一些重要的特征或衍生价值是:
[if !supportLists]· [endif]知道下一次促销的日期;
[if !supportLists]· [endif]距离下一个假期还有多少天;
[if !supportLists]· [endif]竞争对手的业务开放天数。
还有许多这样的特征可以从领域知识中提取出来。对于任何机器学习算法或深度学习算法,算法自动提取这种类别的特征都是相当具有挑战性的。对于某些领域,特别是在计算机视觉和文本领域,现代深度学习算法有助于我们摆脱特征工程。除了这些领域,良好的特征工程对下述方面也总是有益的。
[if !supportLists]· [endif]用较少的计算资源就可以更快地解决问题。
[if !supportLists]· [endif]深度学习算法可以使用大量数据自己学习出特征,不再使用手动的特征工程。所以,如果你注重数据,可以专注于构建良好的特征工程。
4.5 过拟合与欠拟合
理解过拟合和欠拟合是成功构建机器学习和深度学习模型的关键。在本章的开头,我们简要地描述了什么是过拟合和欠拟合,这里将详细解释过拟合和欠拟合的概念,以及如何解决过拟合和欠拟合问题。
过拟合或不泛化,是机器学习和深度学习中的一类常见问题。当特定的算法在训练数据集上执行得很好,但在未知数据或验证和测试数据集上表现不佳时,就说算法过拟合了。这种情况的发生主要是因为算法过于特定于训练集而造成的。简单来说,我们可以理解为该算法找出了一种方法来记忆数据集,使其在训练数据集上表现得很好,但无法对未知数据执行。有不同的技术可以用来避免算法的过拟合。这些技术是:
[if !supportLists]· [endif]获取更多数据;
[if !supportLists]· [endif]缩小网络规模;
[if !supportLists]· [endif]应用权重正则化;
[if !supportLists]· [endif]应用dropout。
4.5.1 获取更多数据
如果能够获得更多的用于算法训练的数据,则可以通过关注一般模式而不是特定于小数据点的模式来帮助算法避免过拟合。在某些情况下,获取更多标签数据可能是一项挑战。
有一些技术,如数据增强,可用于在计算机视觉相关的问题中生成更多的训练数据。数据增强是一种让用户通过执行不同的操作,如旋转、裁剪和生成更多数据,来轻微调整图像的技术。在对行业知识足够了解时,如果获取实际数据的成本很高,也可以创建人造数据。当无法获得更多数据时,还有其他方法可以帮助避免过拟合。让我们看看这些方法。
4.5.2 缩小网络规模
网络的大小通常是指网络中使用的层数或权重参数的数量。在上一章中的图像分类例子中,我们使用了一个ResNet模型,它包含具有不同层的18个组成模块。PyTorch中的torchvision库具有不同大小的ResNet模型,从18个块开始,最多可达152个块。比如说,如果我们使用具有152个块的ResNet模型导致了过拟合,那么可以尝试使用101个块或50个块的ResNet。在构建的自定义架构中,可以简单地去除一些中间线性层,从而阻止我们的PyTorch模型记忆训练数据集。让我们来看一个示例代码片段,它演示了缩小网络规模的确切含义:
上面的架构有3个线性层,假设它在训练数据上过拟合了,让我们重新创建更低容量的架构:
上面的架构只有两个线性层,减少了容量后,潜在地避免了训练数据集的过拟合问题。
4.5.3 应用权重正则化
有助于解决过拟合或泛化问题的关键原则之一是建立更简单的模型。一种构建简单模型的技术是通过减小模型大小来降低架构的复杂性。另一个重要的事情是确保不会采用更大的网络权重值。当模型的权重较大时,正则化通过惩罚模型来提供对网络的约束。每当模型使用较大的权重值时,正则化开始启动并增加损失值,从而惩罚模型。有两种类型的可能的正则化方案,如下所示。
[if !supportLists]· [endif]L1正则化:权重系数的绝对值之和被添加到成本中。它通常称为权重的L1范数。
[if !supportLists]· [endif]L2正则化:所有权重系数的平方和被添加到成本中。它通常称为权重的L2范数。
PyTorch提供了一种使用L2正则化的简单方法,就是通过在优化器中启用weight_decay参数:
默认情况下,权重衰减参数设置为0。可以尝试不同的权重衰减值;一个较小的值,比如1e-5大多时候都是有效的。
4.5.4 应用dropout
dropout是深度学习中最常用和最强大的正则化技术之一,由多伦多大学的Hinton和他的学生开发。dropout在训练期间被应用到模型的中间层。让我们看一下如何在生成10个值的线性层的输出上应用dropout(见图4.3)。
图4.3所示为dropout阈值设置为0.2并应用于线性层时发生的情况。它随机地屏蔽或归零20%的数据,这样模型将不依赖于一组特定的权重或模式,从而不会导致过拟合。让我们来看另一个例子,在这里使用一个阈值为0.5的dropout(见图4.4)。
图4.3
图4.4
通常dropout的阈值在0.2~0.5的范围内,并且dropout可以应用在不同的层。dropout仅在训练期间使用,在测试期间,输出值使用与dropout相等的因子缩小。PyTroch允许将dropout作为一层,从而使它更容易使用。下面的代码片段展示了如何在PyTorch中使用一个dropout层:
dropout层接受一个名为training的参数,它需要在训练阶段设置为True,而在验证阶段或测试阶段时设置为False。
4.5.5 欠拟合
当模型明显在训练数据集上表现不佳时,模型可能无法学习出任何模式。当模型无法拟合的时候,通常的做法是获取更多的数据来训练算法。另一种方法是通过增加层数或增加模型所使用的权重或参数的数量,来提高模型的复杂度。通常在实际过拟合数据集之前,最好不要使用上述的任何正则化技术。
4.6 机器学习项目的工作流
在本节中,我们通过将问题描述、评估、特征工程和避免过拟合结合起来,形成一个可用于解决任何机器学习问题的解决方案框架。
4.6.1 问题定义与数据集创建
为了定义问题,我们需要两件重要的事情,即输入数据和问题类型。
我们的输入数据和对应标签是什么?比如说,我们希望根据顾客提供的评论基于提供的特色菜式对餐馆进行分类,区别意大利菜、墨西哥菜、中国菜和印度菜等。要开始处理这类问题,需要手动将训练数据标注为可能的类别之一,然后才可以对算法进行训练。在此阶段,数据可用性往往是一个具有挑战性的因素。
识别问题的类型将有助于确定它是二分类、多分类、标量回归(房屋定价)还是向量回归(边界框)。有时,我们可能不得不使用一些无监督的技术,如聚类和降维。一旦识别出问题类型,就更容易确定应该使用什么样的架构、损失函数和优化器。
在获得了输入并确定了问题的类型后,就可以开始使用以下假设来构建模型:
[if !supportLists]· [endif]数据中隐藏的模式有助于将输入映射到输出;
[if !supportLists]· [endif]我们拥有的数据足以让模型进行学习。
作为机器学习的实践者,我们需要理解的是可能无法仅用一些输入数据和目标数据来构建模型。下面以股票价格预测为例。假设有代表历史价格、历史表现和竞争细节的特征,但仍然不能建立一个有意义的模型来预测股票价格,因为股票价格实际上可能受到各种其他因素的影响,比如国内外政治环境、自然因素,以及输入数据可能无法表示的许多其他因素。因此,任何机器学习或深度学习模型都无法识别出模式。因此,请基于领域仔细挑选可以成为目标变量的真实指标的特征。所有这些都可能是模型不拟合的原因。
机器学习还有另一个重要的假设。未来或未知的数据将接近历史数据所描述的模式。有时,模型失败的原因可能是历史数据中不存在模式,或者模型训练的数据未涵盖某些季节性或模式。
4.6.2 成功的衡量标准
成功的衡量标准将直接取决于业务目标。例如,当试图预测风车何时会发生下一次机器故障时,我们会对模型能够预测到故障的次数更感兴趣。简单地使用准确率可能是错误的度量,因为大多数时候模型在机器不出现故障时预测都正确,因为这是最常见的输出。假设得到了98%的准确率,但模型每次预测故障时都是错误的,这样的模型在现实世界中可能没有任何用处。选择正确的成功度量标准对于业务问题至关重要。通常,这类问题具有不平衡的数据集。
对于平衡分类问题,其中所有的类别都具有相似的准确率,ROC和AUC是常见的度量。对于不平衡的数据集,可以使用查准率(precision)和查全率(recall)。对于排名问题,可以使用平均精度均值(Mean Average Precision,MAP)。
4.6.3 评估协议
决定好如何评估当前的进展后,重要的事情就是如何评估数据集。可以从评估进展的3种不同方式中进行选择。
[if !supportLists]· [endif]保留验证集:这是最常用的,尤其是当有足够的数据时。
[if !supportLists]· [endif]K折交叉验证:当数据有限时,这个策略有助于对数据的不同部分进行评估,从而有助于更好地了解性能。
[if !supportLists]· [endif]迭代K折验证:想进一步提升模型的性能时,这种方法会有所帮助。
4.6.4 准备数据
通过向量化将不同格式的可用数据转换成张量,并确保所有特征进行了伸缩和归一化处理。
4.6.5 模型基线
创建一个非常简单的模型来打破基线分数。在之前的狗猫分类示例中,基线准确度应该是0.5,我们的简单模型应该能够超过这个分数。如果无法超过基线分数,则输入数据可能不包含进行必要预测所需的必要信息。记住,不要在这一步引入任何正则化或dropout。
要使模型工作,必须要做出3个重要的选择。
[if !supportLists]· [endif]最后一层的选择:对于回归问题,应该是生成标量值作为输出的线性层。对于向量回归问题,应是生成多个标量输出的相同线性层。对于边界框问题,输出的是4个值。对于二分类问题,通常使用sigmoid,对于多类别分类问题,则为softmax。
[if !supportLists]· [endif]损失函数的选择:问题的类型将有助于决定损失函数。对于回归问题,如预测房价,我们使用均方误差(Mean Squared Error,MSE),对于分类问题,使用分类交叉熵。
[if !supportLists]· [endif]优化:选择正确的优化算法及其中的一些超参数是相当棘手的,我们可以通过试验找出。对于大多数用例,Adam或RMSprop优化算法效果更好。下面将介绍一些可用于学习率选择的技巧。
下面总结一下在深度学习算法中,网络的最后一层将使用什么样的损失函数和激活函数(见表4.1)。
表4.1
问题类型激活函数损失函数
二分类sigmoidnn.CrossEntropyLoss()
多类别分类softmaxnn.CrossEntropyLoss()
多标签分类sigmoidnn.CrossEntropyLoss()
回归无MSE
向量回归无MSE
4.6.6 大到过拟合的模型
一旦模型具有了足够的容量来超越基线分数,就要增加基线容量。增加架构能力的一些简单技巧如下:
[if !supportLists]· [endif]为现有架构中添加更多层;
[if !supportLists]· [endif]为已存在的层加入更多权重;
[if !supportLists]· [endif]训练更多轮数。
我们通常将模型训练足够的轮数,当训练准确率还在提高但验证准确性却停止增加并且可能开始下降时停止训练,这就是模型开始过拟合的地方。到达这个阶段后,就需要应用正则化技术。
请记住,层的数量、大小和训练轮数可能会因问题而异。较小的架构可以用于简单的分类问题,但是对于面部识别等复杂问题,模型架构要有足够的表示能力,并且模型要比简单的分类问题训练更长的时间。
4.6.7 应用正则化
找到最佳的方法来调整模型或算法是过程中最棘手的部分之一,因为有很多参数需要调整。可对下面这些用于正则化模型的参数进行调整。
[if !supportLists]· [endif]添加dropout:这可能很复杂,因为可以在不同的层之间添加,并且找到最佳位置通常是通过试验来完成的。要添加的dropout百分比也很棘手,因为它纯粹依赖于我们试图解决的问题的描述。从较小的数值开始(如0.2),通常是最佳实践。
[if !supportLists]· [endif]尝试不同的架构:可以尝试不同的架构、激活函数、层数、权重,或层的参数。
[if !supportLists]· [endif]添加L1或L2正则化:可以使用正则化中的任何一个。
[if !supportLists]· [endif]尝试不同的学习率:在这里有不同的技术可以使用,本章后面部分将讨论。
[if !supportLists]· [endif]添加更多特征或更多数据:可以通过获取更多的数据或增强数据来实现。
我们将使用验证数据集来调整所有上述的超参数。在不断地迭代和调整超参数的同时,可能会遇到数据泄露的问题。因此,应确保有用于测试的保留数据。如果模型在测试数据集上的性能相比训练集和验证集要好,那么我们的模型很有可能在未知的数据上表现良好。但是,如果模型在测试数据上表现不佳,但是在验证和训练数据上表现很好,那么验证数据很可能不是对真实世界数据集的良好表示。在这样的情况下,可以使用K折验证或迭代K折验证数据集。
4.6.8 学习率选择策略
找到合适的学习率来训练模型是一个还在进行中的研究领域,并且已经取得了很多进展。PyTorch提供了一些调整学习率的技术,它们由torch.optim.lr_sheduler包提供。我们将探讨PyTorch提供的一些动态选择学习率的技术。
[if !supportLists]· [endif]StepLR:这个调度器有两个重要的参数。第一个参数是步长,它表示学习率多少轮改变一次,第二个参数是gamma,它决定学习率必须改变多少。对学习率0.01来说,在步长10和gamma为0.1的情况下,学习率每10轮以gamma的倍数变化。也就是说,对于前10轮,学习率变为0.001,并且在接下来的10轮,变成0.0001。下面的代码解释了StepLR的实现。
[if !supportLists]· [endif]MultiStepLR:MultiStepLR与StepLR的工作方式类似,只不过步长不是规则间断的,步长以列表的形式给出。例如,给出的步长列表为10、15、30,并且对于每个步长,学习率要乘上gamma值。下面的代码演示了MultiStepLR的实现。
[if !supportLists]· [endif]ExponentialLR:每一轮都将学习率乘上gamma值。
[if !supportLists]· [endif]ReduceLROnPlateau:这是常用的学习率策略之一。应用本策略时,当特定的度量指标,如训练损失、验证损失或准确率不再变化时,学习率就会改变。通用实践是将学习率的原始值降低为原来的1/2~1/10。