第2至第6章探讨了深度学习(DL)技术背后的核心工作原理,并包括了一些简化的技术实现,便于理解。理解不同神经网络(NN)如何工作的细节是很重要的。原因之一是,当任何神经网络模型出现问题时,你可以识别出根本原因并加以解决。这些章节还展示了深度学习架构在解决不同类型的现实问题时的灵活性。那么,究竟有哪些问题呢?我们又该如何在不同情况下有效地训练一个深度学习模型呢?
在本章中,我们将尝试回答这两个问题,专门针对监督式深度学习,但我们将在下一章中回答相同的问题,针对无监督深度学习。本章将涵盖以下主题:
- 探索监督式使用案例和问题类型
- 为基础问题类型实现神经网络层
- 有效训练监督式深度学习模型
- 探索实现和改进基于监督式深度学习的解决方案的通用技术
- 分析监督式深度学习中的多任务范式
技术要求
本章包括一些在Python编程语言中的实际实现。要完成本章,您需要一台计算机,并安装以下库:
- pytorch
- catalyst==22.04
- numpy
- scikit-learn
您可以在GitHub上的以下地址找到本章的代码文件:GitHub 链接
探索监督式使用案例和问题类型
监督式学习需要标注数据。标签、目标和真实值指的都是同一件事。提供的标签本质上监督了机器学习(ML)模型的学习过程,并为深度学习(DL)模型生成梯度并更新自身提供了所需的反馈。标签可以有许多不同的形式。它们可以是连续的数值格式、类别格式、文本格式、多重类别格式、图像格式、视频格式、音频格式和多目标格式。所有这些都可以归类为以下监督式问题类型之一:
-
二分类:当目标数据为类别数据,且只有两个唯一值时。
-
多分类:当目标数据为类别数据,且有超过两个唯一值时。
-
回归:当目标数据为连续的数值数据时。
-
多目标/多问题:
- 多标签:当目标数据中有多个二分类标签与单条数据行关联时。
- 多回归:当目标数据中有多个回归目标与单条数据行关联时。
- 多问题:在单一数据集中,可能存在多个目标与单条数据行关联,或存在一系列顺序性的多问题,通过不同的数据集学习多个模型。
-
监督式表示学习:可以有许多形式,主要目标是根据输入数据学习有意义的数据表示。学习到的表示结果可以随后用于许多目的,包括迁移学习(TL)以及实现推荐系统。
这些问题的定义本身可能很难理解。为了更好地理解这些不同的问题,我们将查看一组可以利用深度学习技术的广泛使用案例。基于之前提到的问题,以下表格列出了它们的使用案例:
| 问题类型 | 监督式深度学习模型使用案例 |
|---|---|
| 二分类 | - 使用超声影像预测婴儿性别 - 使用图像数据预测半导体芯片的质量拒绝情况 - 使用可能包含文本、图像、文档、音频或任何数据的电子邮件数据预测垃圾邮件 |
| 多分类 | - 文档数据主题分类 - 仇恨/有害言论或文本分类 - 一般的图像物体分类 - 文本或语音数据的情感预测 |
| 回归 | - 广告点击率(CTR)预测,使用图像或文本或两者 - 使用面部图像预测人类年龄 - 使用图像预测GPS位置 |
| 多目标 | - 文本主题分类:多标签,单一文本数据行中可以有多个主题 - 图像物体检测:一个多目标问题,由多个回归目标和多分类组成。首先,通过图像的边界框作为多个回归目标,单一的x和y数值坐标,以及其宽度和高度作为两个额外目标,形成矩形形状的边界框。接下来,使用该边界框提取裁剪后的图像进行多分类,以预测物体的类型 - 图像分割:一种多标签问题,其中每个像素将作为二分类目标 |
| 监督式表示学习 | - 面部识别的面部特征表示 - 使用K近邻(KNN)进行说话人识别的音频表示 - 使用分类嵌入表示类别,每个类别在分类特征列中持有一个特征向量。这是一种可学习的神经网络层类型,作为查找表,它可以减少高基数类别数据的特征维度,与基本的独热编码相比,但保持相近的性能 |
二分类、多分类和回归问题的处理相对直接。然而,多目标类型问题则设置较为复杂,需要根据问题的性质进行更多的架构设计。多目标任务也可以是直接的,例如多标签或多回归问题。这类任务属于更广泛的多任务解决方案的范畴,将在本章的“探索实现和改进基于深度学习的解决方案的通用技术”部分进一步讨论。
接下来,我们将实现基础问题的基本神经网络层,包括二分类、多分类和回归问题。
为基础问题类型实现神经网络层
在第2至第7章中,虽然介绍了许多类型的神经网络(NN)层,但核心层对于问题类型的应用要么没有使用,要么没有解释。在这里,我们将逐一解释它们,以帮助更清晰地理解和掌握直觉。
实现二分类层
二分类指的是类别数据的两种选择。需要注意的是,这并不一定意味着原始数据中的类别严格按照“真/假”或“正/负”进行划分。两种选项可以以任何可能的格式存在,比如字符串、数字或符号。然而,需要注意的是,神经网络只能生成数值输出。这意味着目标本身必须以数值形式表示,其中最优的数值是0和1的二进制值。这意味着,用于训练的目标数据列,若只包含两个唯一值,必须经过预处理,映射为0或1。
通常,有两种方法来定义神经网络中的二分类输出。第一种方法是使用一个大小为1的线性层。第二种方法是使用一个大小为2的线性层。两者在任务质量指标上没有显著差异,但方法一占用的存储空间和内存稍微少一些,所以可以选择始终使用这种方法。方法一的输出将通过sigmoid层被限制在0和1之间。对于方法二,输出需要传递到softmax层,以确保两个输出的概率加和为1。两种方法通常都可以使用交叉熵进行优化。交叉熵也称为对数损失。对数损失通过对数尺度衡量预测概率与真实标签之间的差异,这种尺度对错误预测的惩罚更为严重,强调了模型将高概率分配给正确类别、将低概率分配给错误类别的重要性。
将方法一的层转换为实际的PyTorch代码,将使用torch的nn模块如下:
from torch import nn
final_fc_layer = nn.Sequential(
nn.Linear(10, 1),
nn.Sigmoid(), # Sigmoid instead of Softmax for binary classification
)
接下来,我们将实现多分类层。
实现多分类层
多分类意味着数据包含多个类别,类别数大于二,从而与二分类区分开来。同样地,在多分类中,原始数据可以采用任何可能的格式,并且必须经过预处理,将原始类别转换为从0开始的有序数字。然而,这些有序数字并不表示实际的排序,它们也不包含神经网络可以利用的顺序信息。多分类问题的输出线性层需要配置与唯一类别数相同数量的神经元。类似地,在输出线性层之后,需要应用softmax层,以确保最终输出的概率加和为1。交叉熵也在这里作为标准损失函数。在推理阶段,概率最高的类别索引将作为预测类别。将多分类预测层转换为PyTorch代码,对于一个100类的多分类问题,且10个logits的实现如下:
final_fc_layer = nn.Sequential(
nn.Linear(10, 100),
nn.Softmax(dim=1),
)
多分类中的另一个子问题是类别是有序的。这类子问题和任务被称为有序分类。也就是说,类别之间有递增的关系。普通的多分类层策略将有序类别作为平等关系处理,这并不是最优的。有一种更好的策略是利用基于多标签分类任务的技术,这是一个多二分类任务。
假设我们有五个有序类别,简化表示为1到5的数字。在实际情况中,这些可以由任何类别数据表示。在神经网络中,将为此情况使用五个二分类头,其中类别将按升序顺序分配给相应的头。神经网络的原始预测结果将以一种方式进行处理,最终预测的有序类别将由最远连续的正二分类预测的位置决定。一旦出现负预测,其右侧的其他预测头将被忽略。图8.1通过模拟五个二分类头的输出预测结果来展示这一策略:
学习过程将像往常一样,使用交叉熵损失函数来处理多个二分类目标。此外,可以使用一些不依赖于概率的强大度量标准来监控每个epoch的性能,例如召回率或精度。顺序编码方法使得模型能够学习目标之间的顺序关系。
接下来,我们将深入讨论回归层的实现。
实现回归层
回归意味着一个单一的数值目标和预测。在神经网络中,回归可以通过简单地使用一个大小为1的线性层来实现,这样就能得到一个无界的单一数值输出,而无需任何激活层。将该层转换为实际的PyTorch代码,使用torch的nn模块如下:
final_fc_layer = nn.Linear(10, 1)
均方误差(MSE)是这里的标准损失函数,用于作为优化的误差。然而,未加界限的数值预测的一个风险是值可能会偏离可接受的范围。如果已知一个界限范围,其中一种可以在神经网络中强制执行的方法是使用像最小最大缩放(min-max scaling)这样的缩放方法,将目标值映射到已知的边界范围。一旦使用了最小最大缩放,目标值将落在0和1之间。与目标值的缩放一起,边界可以通过使用sigmoid层来强制执行,sigmoid层也可以将激活值缩放到0和1之间。在推理阶段,预测值可以通过逆缩放将0到1之间的值映射到之前指定的已知最小值和最大值范围。
未加界限的方法通过允许外推,提供了一定形式的泛化,而加界限的方法则允许在神经网络中加入已知偏差。这两种方法各有优缺点,因此选择方法需要根据具体情况进行评估。
接下来,我们将深入实现表示层的内容。
实现表示层
大多数方法集中于不同数据模态之间的架构交互,或优化表示特征的训练方法。这些主题将在下一个主题中进一步讨论。一个真正代表表示层的关键层类型是嵌入层(embedding layer)。嵌入是将类别数据类型映射为可学习向量的一种层结构。通过这个层,每个类别将能够学习到一种能够对指定目标进行良好表现的表示方法。该方法可以用于将文本中的单词令牌转换为更具代表性的特征,或者直接作为独热编码的替代方案。类别嵌入使得可以自动化类别数据类型的特征工程过程。独热编码生成的编码强制所有类别与每个其他类别之间保持相同的距离,而类别嵌入则允许根据其与目标变量的交互以及如果有额外数据时与其他数据的交互来获得合适的距离。
然而,类别嵌入并不是所有机器学习使用案例的“灵丹妙药”,即使它们在训练后与实际的神经网络模型解耦并仅作为特征化器使用。它们有时在一般情况下会比独热编码表现得更好,而其他时候则可能表现得比独热编码差。尽管如此,这个方法仍然是对任何输入包含类别数据的数据集进行实验的一个关键方法。
有效训练监督式深度学习模型
在第1章《深度学习生命周期》中,强调了机器学习项目具有周期性的生命周期。换句话说,在项目的整个生命周期中,很多迭代过程会不断进行。为了有效训练监督式深度学习模型,应该根据不同的条件采取许多通用的方向,但在所有问题中,最为突出的是合适的工具。这个工具更常被称为机器学习操作(MLOps)。一个好的深度学习MLOps系统易于使用,并为数据集和模型实验提供版本控制方法、可视化方法、便捷使用深度学习库(如pytorch、keras与tensorflow结合)的方式、易于部署、易于使用不同指标进行模型比较、便捷的模型调优、良好的模型训练监控可视化,最后还能够提供关于进展的反馈(这可以通过消息和通知的形式发送警报)。如果没有真正简化整个过程的先进工具可用,您可以专注于使模型发挥良好效果的关键部分,而不是处理基础设施问题,例如协调将模型保存到不同文件夹中,像DataRobot这样付费工具,然后是开源工具如MLflow、Kubeflow或Metaflow,这些将是下一个最佳的替代方案。一旦选择了工具,训练深度学习模型将变得轻松自如。我们将以MLflow为例,展示一些深度学习模型训练中的有效方法,以下是几个步骤:
- 数据准备
- 配置和调优深度学习超参数
- 执行、可视化、跟踪和比较实验
此外,在本话题结束前,我们还将探讨构建模型时的一些额外技巧。
让我们详细探讨每个步骤。
准备数据进行深度学习训练
数据是任何机器学习模型的核心。数据最终决定了模型的可实现性能、最终训练模型的质量以及最终训练模型的有效性。在第1章《深度学习生命周期》中,我们探讨了使数据集能够适应深度学习的要求,以及获取数据时需要的特性,结合探索性数据分析(EDA)来验证因果关系和有效性。那里的总体思路是识别并添加对目标产生因果影响的额外特征和数据模态。在本节中,我们将更深入地探讨将数据转换为适合深度学习训练的状态的关键步骤,列举如下:
- 数据划分
- 数据表示
- 数据增强
深度学习训练数据划分
我们要讨论的第一步是数据划分。为训练、验证和测试模型制定一个良好的数据划分策略对于获得表现良好的模型至关重要。训练数据集将严格用于训练。验证数据集将严格用于在训练过程中验证模型。在深度学习中,验证数据集通常用作指导信号,指示何时停止训练或提取最优的模型权重,使用外部数据而非训练数据。如果验证数据会影响模型的学习过程并带来偏差,从而导致对训练数据以外的验证数据的过拟合,那么测试数据集将是最终用于验证训练模型泛化能力的数据集。测试数据集也被称为保留数据集。为了更好地防止过拟合并确保模型的泛化能力,验证数据集可以仅在模型训练完成后被使用一次,而不是在每个epoch中都用于验证。这一策略要求从原始训练集创建一个更小的内部验证集。下图展示了两种不同的策略:
这个数据划分过程称为交叉验证。前面的图展示了仅使用单一划分设置的简单交叉验证策略。这可能会导致模型的性能指标偏向于某个特定的划分设置。结果的划分可能具有某种固有的分布或特性,使得模型在该划分上表现特别好或特别差。当这种情况发生时,在部署阶段对性能的预期不匹配将带来更多的操作问题。为了安全地消除这种偏差的可能性,通常使用k折交叉验证来报告更全面的验证得分,从而更好地反映模型在实际环境中的表现。为了执行这种划分方法,从原始数据集中移除一个单一的测试集,然后在不同顺序的k折交叉验证训练和验证划分上平均计算验证得分。这个过程在图8.3中得到了更好的可视化展示:
最后,为了进行性能测试报告和部署目的,模型要么在训练和验证数据集的合并数据上重新训练,要么直接提取在第一次折叠中训练的模型进行部署。
请记住,分层划分是将数据拆分为上述三部分的推荐策略。这意味着数据将根据与数据集相关的标签大致均匀地分为三部分。这确保没有标签会在任何一个分区中被遗漏,否则可能导致信息错误。以二分类为例,假设数据集被随机划分为训练、验证和测试三个部分,并且大小是预先指定的。由于每一行数据被随机分配到三个分区中的一个,因此有可能某个分区只包含来自两个二元标签中的一个标签。由于验证或测试分区通常数据较少,它们更可能面临这个问题。假设模型错误地训练为仅预测单一标签。如果该标签恰好是仅存在于验证和测试集中的标签,ML学习者可能会错误地认为模型表现极好,但实际上它是无用的。你永远不知道何时会在进行完全随机分区时运气不好,所以尽可能使用分层随机划分! 此处描述的数据分区策略只构建了一个模型,在模型部署时将用于推理模式。当最终模型的推理运行时是一个关注点,并且希望模型更快而非精度提升时,这个策略是标准选项。当可以用运行时换取一些精度时,可以使用另一种称为k折交叉验证集成的策略。这是一种在许多ML竞赛中被广泛提倡的方法,尤其是在Kaggle等平台的竞赛中。该方法使用前面描述的k折交叉验证,但实际上使用k个在交叉验证期间训练的模型,并对k个模型的预测结果进行集成。一个叫做混合的集成方法将模型的预测结果进行汇总,几乎总是能提高单个模型的精度指标。这个过程可以看作是一种方法,它利用每个k模型的最佳思想和专业知识,使最终结果作为一个综合体变得更好。这个综合体可以简单地是k个预测的平均值或中位数。 在继续介绍下一个方法之前的最后一个提示是,比较实验中模型时要确保分区匹配。通常,在不同的数据分区策略和数据分区下分别开发的两个模型之间会发生信息错误。即使其中一个模型在性能上明显优于另一个,也没有任何意义,不会得出有意义的比较。 接下来,我们将深入探讨不同数据模态的表示组件。
用于训练深度学习模型的不同数据模态表示
到目前为止,我们已经讨论了数值、类别、文本、音频、图像和视频模态的使用。这些是跨多个行业最常用的模态。表示不同的数据模态是一个复杂的话题,因为除了常见的模态外,还有许多罕见的数据模态。罕见模态的例子包括化学公式(文本数据的一种特殊结构形式)、文档数据(另一种具有复杂位置性信息的文本数据)和图数据。在本节中,我们将仅讨论常见的非结构化模态的表示,以确保内容对读者的相关性。数值和类别数据被视为结构化数据,并且在之前的章节中已经得到了充分的讨论。现在让我们开始讨论文本数据模态。
用于监督深度学习的文本数据表示
文本数据表示在近年来得到了极大的改进。以下列出了一些相关方法:
-
词频-逆文档频率(TF-IDF)与N-gram:这里的术语通过N-gram实现。N-gram是相邻的n个文本字符序列。N-gram是通过一种叫做标记化的方法生成的。标记化可以是低级的表示(如单个字符),也可以是更高级的表示(如单词)。一旦表示为N-gram,就可以使用以下公式计算TF-IDF:
TF-IDF=term frequency×inverse
词频只是单行数据的计数数组。逆文档频率通过以下公式计算:
这种表示是从文本中提取有用信息的高效且轻量的方式,其中稀有单词具有较高的值,而像“the”和“and”这样的常见词会被抑制。TF-IDF的输出可以直接输入到简单的多层感知机(MLP)或任何机器学习模型中以生成预测模型。在较简单的应用中,这种表示已经足够达到良好的性能指标。然而,在需要解码复杂交互的复杂应用中,它的表现会较差。
-
词/标记嵌入:词嵌入可以从头开始训练,也可以从更大的数据集预训练。预训练的嵌入可以是监督方式或无监督方式训练的,通常是在较大的数据集上进行训练。然而,嵌入方法在训练、评估和测试阶段面临标记不匹配的问题。这意味着在查找嵌入表之前,必须对特定文本标记进行大量预处理。这个现象在评估和测试阶段被称为“超出词汇(OOV)”。在训练阶段,相同单词的不同变体会有各自的含义,这在学习和资源空间利用上效率低下。实际上,方法如词干化、词形还原、小写转换和已知词对替换被应用以缓解OOV问题,但这个问题无法完全解决。这些词嵌入可以与递归神经网络(RNN)或变换器模型配对使用。
-
基于子词的标记化:这一系列方法试图解决标记不匹配问题以及大词汇表的标记大小问题。子词可能听起来不直观,因为我们通常用完整单词来理解文本的意义。这些算法仅在无法识别或被视为稀有的单词时进行子词标记化。对于常见的单词,它们会保持完整的单词标记。此类方法的例子包括字节对编码(BPE)、WordPiece和SentencePiece。我们将简要介绍这些方法:
- BPE标记化:BPE将文本视为字符,并在训练过程中迭代地将最常见的连续字符组合起来。迭代的次数决定了何时停止组合最常见字符的训练迭代。这种形式允许稀有单词保持为子词标记,而常见单词被组合成一个标记。这种表示方法特别用于生成预训练变换器(GPT)模型。然而,这种表示存在一个问题,就是可能会有多种方式来编码一个特定的单词。
- WordPiece:WordPiece通过利用语言模型来选择最有可能组合成一对标记,改进了BPE。这为编码特定单词时的选择提供了一种智能的选择。这种算法被BERT和ELECTRA等模型使用。
- SentencePiece:SentencePiece是一种优化BPE等基础标记化工具生成的标记的方法。它使用一些组件,如使用一种Unicode文本转换形式以确保不存在语言相关逻辑,并使用一种叫做子词正则化的方法,执行一种子词标记组增强(按概率和随机选择一个从前k个预测的子词标记中分组)的形式来解决多种表示问题。这个算法被XLNet和ALBERT等模型广泛使用。
文本数据在深度学习中被表示为标记。这也意味着标记的数量会有严格限制,以便NN模型能够用正确的参数进行初始化。根据用例的需求选择合理的标记大小限制,以便获得良好的模型性能。由于大小限制会影响模型大小,请确保模型的大小不会超出推理运行时要求。
在缺失文本数据的情况下(这种情况在现实世界的多模态数据中可能发生),使用空字符串作为填充方法是最自然的做法。在后台,这些模型通常会使用全零来表示文本数组。
现在我们简要介绍了监督文本数据的表示方法,接下来我们将探讨监督音频数据的表示方法。
表示音频数据用于深度学习
音频数据是时间序列数据,通常由一个或两个值数组组成,其中每个值代表特定时间戳下的单个音频数据。音频数据可以以简单的归一化形式表示,也可以表示为被称为“声谱图”的二维数据,或者使用梅尔频率倒谱系数(MFCCs)。
声谱图是短时傅里叶变换(STFT)过程的输出,能够将原始音频数据分解为不同频率范围内的信号。原始音频数据包含了来自任何音频频率的混合音频信号。通过将音频数据分解为频率-信号表示,使得机器学习算法在识别关键模式时拥有更多的自由度。在大多数音频应用中,基于声谱图的模型表现通常要优于直接使用原始音频数据。声谱图以二维格式存在,这意味着它可以被当作图像处理,并且可以输入到基于图像的模型中,如残差网络(ResNets)和视觉变换器(ViTs)。然而,也有一些模型能够利用未经处理的原始音频数据,例如wav2vec 2.0,这是一种基于变换器的模型。
STFT过程有一些超参数,会影响最终的表示。以下是这些超参数的总结,以及如何正确设置它们的建议:
- 采样率:指定在应用STFT之前使用的每秒样本数(赫兹/Hz)。音频数据可能以不同的采样率进行录制,为了建立模型,这些数据需要通过重采样算法统一为单一的采样率。最常用的采样率是16,000 Hz。由于该值会影响模型的大小和运行时,因此在没有精度性能需求的情况下,不要随意增加它。
- STFT窗口长度:每个窗口大小将负责固定时长和特定位置的数据。每个窗口会针对一系列频率生成一个值。此参数的典型值为4096或2048。如果有严格的预测分辨率要求,可以根据需要配置此参数。这一参数同样会影响模型大小。
- 窗口步幅:类似于卷积层的过滤步幅,通常没有太多重要的调优方法。使用窗口长度的10%左右作为步幅,通常是一个不错的设置。
- 是否使用梅尔尺度:梅尔尺度是音频信号频率的对数变换,基本上是模拟人类感知音频的方式。它使高频变化的重要性较低,而低频变化的重要性较高。涉及需要人类判断的情况时,可以使用此方法来提高精度。
对于空的音频行,可以通过填充一个预生成的随机噪声音频或使用相同长度的零数组来处理,这在多模态数据集中效果良好。
现在,我们简要介绍了监督音频数据的表示方法,接下来我们将探讨监督图像和视频数据的表示方法。
表示图像和视频数据用于深度学习
图像数据在这里不需要过多介绍,因为我们已经使用它们进行了几次教程。关键是在输入到神经网络模型(如卷积神经网络(CNN))之前进行某种形式的归一化,神经网络将提取出良好的表示。变换器也在图像任务中与CNN竞争激烈,并且可以用来提取代表性特征并直接进行任务预测。需要注意的是,除非图像的分辨率对识别某些模式至关重要,否则通常使用较小的图像分辨率会更有效。虽然人眼可能无法在较小的分辨率下识别某些模式,但计算机仍然能够识别。图像分辨率影响训练的运行时间、生产环境中模型的运行时间,有时还会影响模型的大小(尤其是变换器),因此应谨慎选择。
视频数据是图像数据的扩展形式,其中多个图像按顺序排列形成视频。这意味着视频数据是一种序列数据,类似于文本数据,但没有绝对的时间戳信息。每个连续的图像称为一帧。视频可以具有不同的帧率,通常为每秒24帧、30帧或48帧(FPS),但通常可以是任何帧数。对于计算机视觉(CV)应用,确保设置较低的FPS,以便根据用例减少处理负载。例如,唇读的用例对FPS的要求低于要求模型判断一个人是否在跑步的任务。在帧分辨率方面,图像分辨率的相同指导原则适用于视频。一旦视频属性确定,就必须学习并提取代表性特征。目前的最先进(SoTA)特征是通过与图像任务相似的模型提取的。例如,3D卷积神经网络(3D CNN)和3D变换器。
然而,这两种数据类型存在交集,即通过视频数据提取的图像数据。对于这种类型的图像数据,可以减少预测模型做出错误预测的概率。机器学习模型并不是完美的预测器,因此,任何减少错误预测(如假阳性或假阴性)而不影响真实预测的机会,都应该加以考虑。可以考虑使用来自OpenCV库的手动图像处理技术,在模型接受图像输入之前执行任何预处理步骤。例如,可以在将视频数组输入深度学习模型之前,使用OpenCV中的运动检测技术进行初步条件检查。因为大多数视频数据的应用需要运动来识别,所以如果没有任何运动,预测任何内容都没有意义。这也减少了从多个未改变的视频帧进行预测时可能发生的假预测。OpenCV中的运动检测器通过检测像素值的变化来工作,无需使用概率模型,因此它是一个更可靠的运动指示器。
现在我们已经讨论了不同数据模态的表示方法,接下来让我们进入数据增强的话题。
增强数据以训练更好的深度学习模型
数据增强在深度学习中被广泛应用,目的是提高训练模型的泛化能力,并提升模型的性能指标。通过考虑数据增强所带来的独特变化,模型能够在验证、测试和推理阶段关注这些变化,从而适应外部数据的变化。自然地,这也会减少模型对特定模式的过度依赖,并能够从足够大的数据集中获得更多的好处。数据增强增加了训练数据的量,从而增加了训练数据中模式的变化。这个过程通常是在每次训练迭代中随机且单独地在内存中进行的。这样可以确保训练过程中没有对额外数据变化的限制,并且避免了额外存储的需求。然而,你不能随便地对某一特定模态的所有已知增强方法都使用。以下是你可以对数据进行增强的不同类型:
- 图像:通过对比度限制自适应直方图均衡(CLAHE)锐化图像、色调和饱和度变化、色彩通道洗牌、对比度变化、亮度变化、水平/垂直翻转、灰度转换、模糊处理、图像遮罩、mixup(图像及其标签的加权组合)、cutmix(mixup,但仅通过原始图像的随机补丁进行)、以及更多。你可以在 github.com/albumentati… 上查看超过70种增强方法!
- 文本:同义词替换、回译(将文本翻译成另一种语言,然后再翻译回原始语言)等。
- 视频:视频mixup(与图像mixup相同,但用于视频)、所有适用于图像的增强方法。
- 音频:随机白噪声、随机粉噪声、回声、时间拉伸、回采样(类似回译,但改变采样率)、随机STFT窗口类型、随机遮罩、随机带通噪声、从随机选定的真实音频片段添加噪声(你可以从YouTube或许可的公开音频数据集中获取)。这些可以通过librosa库访问。
选择使用的增强类型需要了解你在部署模型时可能面临的预期环境。错误的选择会给模型增加噪声,可能会在训练过程中混淆模型,导致性能下降。好的选择通常围绕着估计在实际环境中可能发生的变化。例如,假设有一个制造用例,目标是部署一个基于图像的模型,通过摄像头传感器预测传送带上的产品特性,以进行分拣。如果你可以假设摄像头在所有设置中几乎完美地保持直视机器,那么使用图像旋转增强可能就不太聪明。即便你希望使用这种增强,旋转的变化也应该保持在较小的范围内,例如不超过10度的变化。如果摄像头无法提供灰度图像,那么灰度增强也可能是不直观的。
这就是训练有效模型的数据准备阶段的总结。接下来,我们将深入探讨工作流程中的模型训练阶段。
配置和调整深度学习超参数
超参数配置和调整在有效训练深度学习模型中起着至关重要的作用。它们控制模型的学习过程,能够显著影响模型的性能、泛化能力和收敛速度。本节我们将讨论一些关键超参数及其对训练深度学习模型的影响。
对于训练每个神经网络模型,最常见的超参数配置是其训练轮次(epochs)、提前停止轮次(early stopping epochs)和学习率(learning rate)。这三个参数被认为是一组形成学习计划的超参数。曾经有一些著名的学习计划,专注于以最少的时间获取最佳模型。然而,这些方法通常依赖于对模型收敛所需总轮次的初步估计。依赖这种估计的方法较为脆弱,且它们的配置策略难以从一个问题转移到另一个问题。这里,我们将专注于使用验证数据集来跟踪模型达到最佳性能所需的轮次数。
提前停止轮次是一个控制训练到多少轮次后停止的参数。这种策略意味着,可以将轮次超参数设置为无限大或者一个非常大的数字,以便找到在验证数据集上表现最好的模型。提前停止通过动态地根据验证数据集减少训练轮次,避免了过度训练。通过保存验证数据集上表现最好的模型权重,当模型提前停止时,你可以加载这些最佳权重。典型的提前停止轮次是10轮。
关于学习率,有两种常见的实践方法,通常表现良好。一种是立即使用较大的学习率(例如0.1),然后逐渐降低学习率。学习率的渐进衰减可以通过监控验证得分,当验证得分在3到5个epoch内没有改善时,按百分比减少学习率。第二种方法是先使用较小的学习率作为热身阶段,初始化神经网络的基础权重,然后再使用方法一。在学习的初始阶段,由于模型处于随机状态,学习过程可能非常不稳定,损失值似乎没有朝着正确的方向改善。使用热身有助于初始化模型,以便在后续阶段可以稳定地减少损失。需要注意的是,如果使用预训练的权重来初始化模型,通常不需要热身,因为模型已经处于稳定状态,尤其是当预训练权重来自类似数据集时。
批量大小是训练深度学习模型中的另一个关键超参数,因为它决定了在优化过程中每次更新模型权重时使用的训练样本数。批量大小的选择会显著影响模型的训练速度、内存需求和收敛速度。较小的批量大小(如16或32)能更准确地估计梯度,从而导致更稳定的收敛,但可能需要更多的训练迭代,并且由于计算并行性较低,训练速度较慢。另一方面,较大的批量大小(如128或256)增加了并行计算的程度,加快了训练过程并减少了内存需求,但可能导致梯度估计不够准确,从而导致收敛不稳定。在实际应用中,进行批量大小的实验非常重要,以找到在特定问题中平衡训练速度和收敛稳定性之间的最佳批量大小。此外,现代深度学习框架通常支持自适应批量大小技术,它可以在训练过程中自动调整批量大小,以优化学习过程。
我们在这里讨论的基础策略是稳健的,并且通常能够在牺牲一些额外训练时间的情况下获得最佳的模型表现。值得注意的是,正则化方法、优化器和不同的激活函数在第二章《设计深度学习架构》中已经涵盖,我建议你参考该章节以获取更多关于这些主题的信息。
尽管对于这些超参数的配置可以有手动策略,但在优化模型的性能指标时,总是有进一步调整超参数的空间。常见的调整方法有网格搜索、随机搜索或通过更智能的搜索机制进行调整。网格搜索,或称为暴力搜索,探索并验证所有指定超参数值的可能组合,通过交叉验证来识别给定问题的最佳配置。对于更智能的调整方法,请回顾第七章《深度神经架构搜索》以获取更多见解。此外,由于模型评估指标有助于这一超参数调整过程,我们将在第十章《探索模型评估方法》中深入探讨这一点。
超参数调整的核心依赖于通过迭代执行、可视化、跟踪和比较建模实验的过程和工作流程,每个配置都是一个建模实验的一部分。这将引导我们进入下一个话题——深入探讨如何有效地训练深度学习模型的实际工作流程。
执行、可视化、跟踪和比较实验
有效执行机器学习项目的关键是快速迭代实验。在任何机器学习项目中,都需要大量的探索工作,无论是在项目的初始阶段以评估用例的可行性,还是在后期阶段以提高模型的性能。当这一探索过程能够得到优化时,失败的事情可以迅速失败,而可行的事情则可以迅速成功。机器学习项目中的失败是非常常见的。一旦我们意识到这一点并快速失败,就可以利用恢复的时间来处理更有价值的用例。一个好的MLOps平台将帮助我们有效且高效地执行、可视化、跟踪和比较实验。
让我们通过使用MLflow MLOps平台的Iris数据集和一个MLP模型来进行一个实际示例。我们还将使用Catalyst库,尽管它主要集中在提供常见的PyTorch深度学习模型训练工具,它也是一个部分的MLOps平台。由于Catalyst提供了大部分模型版本控制和模型存储机制,我们只会在MLflow中使用跟踪功能。这个示例的步骤如下:
首先,我们导入所有必要的库:
import json
import os
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from catalyst import dl, utils
from catalyst.contrib.datasets import MNIST
from sklearn import datasets
from sklearn.metrics import log_loss
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from torch import nn as nn
from torch import optim
from torch.utils.data import DataLoader
from torch.utils.data import TensorDataset
from catalyst.loggers.mlflow import MLflowLogger
接下来,由于我们将使用基于PyTorch的MLP,我们将在PyTorch中再次设置随机种子:
torch.manual_seed(0)
我们将使用的实践数据集是Iris数据集。该数据集包含了不同种类的鸢尾花的花瓣和萼片长度。我们现在加载这个数据集:
iris = datasets.load_iris()
iris_input_dataset = iris['data']
target = torch.from_numpy(iris['target'])
缩放是一种正则化方法,可以减少记忆化并减少偏差。我们在这里进行一个简单的最小值和最大值缩放:
scaler = MinMaxScaler()
scaler.fit(iris_input_dataset)
iris_input_dataset = torch.from_numpy(scaler.transform(iris_input_dataset)).float()
为了训练模型,我们需要一个合适的交叉验证策略来验证模型的有效性和性能。我们将使用77%的数据进行训练,33%的数据进行验证。让我们为交叉验证准备数据:
X_train, X_test, y_train, y_test = train_test_split(iris_input_dataset, target, test_size=0.33, random_state=42)
接下来,我们需要使用以NumPy格式准备的数据来为交叉验证准备数据加载器:
training_dataset = TensorDataset(X_train, y_train)
validation_dataset = TensorDataset(X_test, y_test)
train_loader = DataLoader(training_dataset, batch_size=10, num_workers=1)
valid_loader = DataLoader(validation_dataset, batch_size=10, num_workers=1)
loaders = {"train": train_loader, "valid": valid_loader}
由于这是一个三分类问题,我们将使用PyTorch中的交叉熵损失:
criterion = nn.CrossEntropyLoss()
我们将在这个项目中使用PyTorch的高级封装库Catalyst。为了在Catalyst中训练一个模型,我们必须定义一个模型训练器类实例,称为runner:
runner = dl.SupervisedRunner(
input_key="features", output_key="logits", target_key="targets", loss_key="loss"
)
我们将使用MLP模型,该模型的构造类允许我们指定输入数据大小、隐藏层配置和输出数据大小。隐藏层配置是一个层大小的列表,既指定了层的数量,又指定了每一层的层大小。假设我们想随机获取20种不同的隐藏层配置,找出在验证集上表现最好的配置。首先,让我们定义一个方法来随机生成配置:
def get_random_configurations(
number_of_configurations, rng
):
layer_configurations = []
for _ in range(number_of_configurations):
layer_configuration = []
number_of_hidden_layers = rng.randint(low=1, high=6)
for _ in range(number_of_hidden_layers):
layer_configuration.append(rng.randint(low=2, high=100))
layer_configurations.append(layer_configuration)
layer_configurations = np.array(layer_configurations)
return layer_configurations
然后,我们定义一个方法来训练和评估不同的MLP配置:
def train_and_evaluate_mlp(
trial_number, layer_configuration, epochs,
):
其中,trial_number用于区分不同的实验。除了隐藏层配置外,我们还可以配置要运行的epoch数量。在这个方法中,我们将根据传入的隐藏层配置创建一个MLP模型实例:
model = MLP(
input_layer_size=iris_input_dataset.shape[1],
layer_configuration=layer_configuration,
output_layer_size=len(np.unique(target)),
)
我们将使用Adam优化器进行梯度下降,并设置检查点目录:
optimizer = optim.Adam(model.parameters(), lr=0.02)
checkpoint_logdir = "experiments"
接下来,我们将定义Catalyst中用于以MLflow格式记录实验的MLflow Logger助手类。在这个设置中,我们记录训练和验证日志损失的均值和标准差:
loggers = {
"mlflow": MLflowLogger(
experiment="test_exp", run="test_run"
)
}
最后,我们将启动训练过程,并训练指定数量的epoch:
runner.train(
model=model,
hparams=hparams,
criterion=criterion,
optimizer=optimizer,
loaders=loaders,
num_epochs=epochs,
callbacks=[
dl.CheckpointCallback(
logdir=checkpoint_logdir,
loader_key="valid",
metric_key="loss",
mode="model",
)
],
logdir="./logs",
valid_loader="valid",
valid_metric="loss",
minimize_valid_metric=True,
verbose=verbose,
loggers=loggers
)
作为最后一步代码,我们将循环遍历每个随机生成的隐藏层配置,执行训练和评估过程:
for layer_config in layer_configurations:
train_and_evaluate_mlp(
trial_number,
layer_config,
epochs=10,
load_on_stage_start=False
)
现在,我们需要启动MLflow服务器服务。我们可以通过在命令行中运行以下命令来实现,在与包含上述代码的目录相同的目录中运行:
mlflow server --backend-store-uri mlruns
运行该命令后,应该在同一目录下包含一个名为.catalyst的文件,该文件指示Catalyst启用MLflow支持。此文件应包含以下内容:
[catalyst]
cv_required = false
mlflow_required = true
ml_required = true
neptune_required = false
optuna_required = false
执行命令后,打开HTTP网站链接,你应该能够看到MLflow的界面,如图8.4所示。
界面展示了一种方便的方式,可以可视化不同实验之间的性能差异,同时显示所使用的参数。数值指标值可以进行排序,以获得在验证集上表现最好的模型,如图中所示。准备数据和训练模型的过程需要在不同的设置或实验之间进行迭代比较。通过量化指标与实验参数的结合,实验可以更客观地进行比较。当这些指标通过代码自动在界面中以可视化方式显示,而不是手动插入Excel或Google表格时,这使得整个过程更加可靠和有组织。此外,如果点击进入任何一个实验,你将能够交互式地查看每个epoch的损失曲线,如图8.5所示。
在确保迭代速度的同时,还需要正确组织和跟踪为模型生成的所有工件。这意味着你需要对模型、数据集以及任何影响最终模型输出的关键组件进行版本控制。工件可以是模型权重、性能报告、性能图、嵌入可视化和损失可视化图表等。显然,这项任务可以通过手动编码来完成。然而,当实验数量增多时,组织模型内置实验的工件会变得混乱。任何自定义文件、图表和指标都可以与每个实验记录关联,并在MLflow界面中查看。实验可以通过使用不同的模型、不同的数据集、不同的特征化方法、不同的模型超参数或相同数据集的不同样本大小来区分。此外,模型还可以直接存储在MLflow的模型注册表中,这允许MLflow直接部署模型。
探索构建模型的技巧
这些实践内容作为示例,展示了像MLflow这样的MLOps平台如何通过编程和可视化方式简化构建和选择合适模型的过程。尽管MLOps非常强大并帮助高效训练模型,但MLOps平台并不能为你处理所有事情,有一些关键组件在模型被正确利用并开始进行预测之前必须要处理。这些组件如下:
- 预测一致性验证测试:这是一个确保同一训练模型在相同数据上做出的预测一致的测试。如果一个模型的逻辑不确定性,其预测是无法被利用的。这将在第10章《探索模型评估方法》中进一步讨论。
- 模型训练实验的可复现性:可复现性是ML工程师必须承担的责任。这意味着我们必须确保一个模型能够通过使用训练时所用的配置,第二次确定性地复现出来。由于机器学习生命周期是一个迭代的循环过程,当需要使用新数据重新训练模型时,可以再次大致获得相同的性能。确保可复现性的技巧是确保所有需要随机数据生成的组件都被确定性地设置了种子。种子确保随机数生成器生成确定性的随机数。在PyTorch中,可以通过以下代码全局设置:
import torch
import random
import numpy as np
torch.manual_seed(0)
random.seed(seed)
np.random.seed(seed)
在TensorFlow和Keras中,可以通过以下代码全局设置:
import tensorflow as tf
tf.keras.utils.set_random_seed(seed)
此方法自动设置随机和NumPy库的种子。这些全局设置可以帮助为未显式设置随机数生成器种子的层设置随机种子。
实验中的最后一条建议是在项目开始时创建一个基准。基准是可能的最简单版本的解决方案。该解决方案甚至可以是一个非深度学习模型,使用简单的特征。拥有一个基准可以帮助确保你所添加的任何改进或复杂性都是通过性能监控得以验证的。避免为了增加复杂性而增加不必要的内容。记住,机器学习项目的价值不在于过程有多复杂,而在于从中能提取出什么结果。
接下来,我们将深入探讨可以用来实现和改进使用深度学习的解决方案的实际技术。
探索实现和改进监督深度学习解决方案的通用技术
注意到在本章早些时候,我们聚焦于基于问题类型的用例,而非问题本身。解决方案通过解决并处理这些问题来工作。深度学习(DL)和机器学习(ML)通常是解决与人员配备困难以及自动化日常任务相关问题的良好工具。此外,计算机中的机器学习模型可以比普通人更快地处理数据,从而大大提高响应时间,并使任何过程的扩展更加高效。在许多情况下,机器学习模型可以帮助提高过程的准确性和效率。有时,它们改善了现有过程,其他时候,它们使得以前无法实现的过程成为可能。然而,单个深度学习模型可能足以解决问题,也可能不够。让我们举个例子,说明一个可以通过单一深度学习模型足够解决的问题。
考虑一个用例,使用深度学习模型预测婴儿的性别,通过超声波影像来实现。传统上,医生会基于超声波影像对母体内婴儿的性别进行可视化分析,既在实时过程中,也在离线分析后,最终提供他们的性别预测。根据之前的经验和知识,医生在解读性别时会有不同的能力和准确性。当婴儿出现异常时,问题可能会变得更加复杂。潜在的问题可能是,经验丰富且能力强的医生稀缺且招聘成本高。如果我们有一个可以自动解读超声波影像来确定性别的系统,它将不仅为真实医生的判断提供有效辅助,或者作为一种更便宜的替代方案来取代他们。相同的类比也可以应用于识别任何高级影像结果中的疾病或症状,如X光图像。
这个例子将深度学习模型视为解决方案的一部分,并展示了一个单一深度学习模型足以获得所需输出的解决方案。这是一个涉及人员问题的例子,但并不是侧重于效率方面的。在某些用例中,需要以某种形式解释驱动模型做出预测的原因。换句话说,你需要解释模型做出决策的依据。为了协助医生,指出哪些模式和在哪些位置对决策有所贡献,比单纯的决策本身更为有用,因为医生可以利用这些额外的信息来做出自己的判断。这将在第11章《解释神经网络预测》中进行详细介绍。
抛开解释不谈,并非所有问题的解决方案都能仅通过单一的机器学习或深度学习模型来完成。有时,深度学习模型必须与一般的机器学习方法结合使用,而在其他情况下,多个深度学习模型必须结合使用。在某些特殊情况下,必须对中间数据进行特殊处理和准备,然后才能将其传递给管道中的下一个任务。在处理此类问题时,创建和构建逻辑管道是至关重要的。让我们举一个需要多个数据集、多个深度学习模型,并构建任务管道的问题和解决方案的例子。
考虑一个问题,即找出刚刚抢劫银行的罪犯。通过使用部署在城市中的监控摄像头,如果你已经识别出抢劫犯的面部,你可以使用人脸检测和识别解决方案。下图展示了该问题的一个示例解决方案任务管道:
面部检测是一个图像对象检测过程,其中有一个图像边界框回归器和一个二元分类器,用于预测该边界框是否为面部。代表性的面部特征提取利用了一个深度学习模型,可以通过监督表示学习方法进行训练,目的是优化面部特征在不同个体面部特征中的区分效果。接下来,需要一个单独的任务来构建犯罪者面部特征的数据库,这些数据将传递给KNN机器学习算法,通过查询从城市中部署的闭路电视摄像头获得的面部特征来找到匹配的面部ID。这个解决方案展示了需要将一个解决方案拆分为多个组件,以获得最终的目标——找到犯罪者。
上面的例子是一个更大范式的一部分,叫做多任务学习和多任务问题。多任务范式是一个话题集合,不仅在深度学习(DL)中,而且通过深度学习实现起来更为可行,它允许在机器学习领域获得更大的进展。在接下来的话题中,我们将深入探讨多任务范式。
分解监督深度学习中的多任务范式
多任务是一个范式,涵盖了一个广泛的任务范围,涉及对多个问题执行机器学习模型,同时结合各自的数据集以实现某一目标。这个范式通常基于两个原因构建:
- 实现更好的预测性能和泛化能力。
- 将复杂的目标分解为较小的任务,这些任务可以通过不同的机器学习模型直接解决。这重申了前面话题中提到的观点。
让我们深入探讨四种多任务技术,从多任务管道开始。
多任务管道
这种多任务系统的变体围绕着实现那些无法通过单一机器学习模型直接解决的解决方案展开。将高度复杂的任务分解为更小的任务,可以通过多个机器学习模型处理不同的小任务来实现解决方案。这些任务可以是顺序的或并行的,通常形成一个有向无环图(DAG)样的管道,类似于图8.6所示的示例。
然而,这并不意味着任务必须仅限于机器学习模型。不同产业和企业的问题可以有多种形式,而灵活地分配所需组件来生成解决方案是从机器学习技术中提取价值的关键。例如,如果在分解较大任务后需要人工监督来完成某个任务,不要犹豫,应该将其与机器学习模型结合使用,以实现价值。让我们通过另一个使用多任务管道来创建解决方案的用例——推荐系统来进一步说明。首先,我们需要执行监督学习或无监督学习以进行特征提取。第二,使用提取的特征创建一个数据库,用于匹配提取的查询特征。第三,从数据库中获取前k个最接近的数据,并应用回归模型预测前k数据的排名,以进行精细调整和高性能排序。
接下来,我们将探索另一种多任务执行范式,称为迁移学习(TL) 。
迁移学习(TL)
迁移学习(TL)是一种技术,涉及将一个任务中学到的知识应用到另一个任务中。其核心原因可以是以下之一:
- 提高指标性能。
- 减少网络达到收敛状态所需的epoch数量。
- 允许更稳定的学习轨迹。在其他情况下,当初始学习过程不稳定时,网络收敛所需的时间会更长。然而,在某些情况下,当网络没有稳定的基础来开始学习时,网络根本无法收敛。迁移学习可以帮助那些最初无法学习任何东西的模型达到收敛状态。
- 增强泛化能力,减少过拟合的可能性。当第二个任务仅涉及实际数据群体中的一个小子集的变化时,来自第一个任务的知识(涵盖更广泛变化范围的任务)有助于防止狭隘的忽视。
具体来说,深度学习中的迁移学习是通过使用从第一个任务中学到的网络参数来进行的。这些参数包括与网络相关的所有权重和偏置。可以将这些参数用作初始化步骤,而不是通常的随机初始化参数,这些被称为预训练权重。使用预训练权重进行网络学习的过程称为微调。此外,网络参数还可以选择完全冻结,仅作为特征提取组件,为另一个监督学习算法提供特征。
有几种自动化策略,专注于通过微调来提高结果。然而,这些方法并非灵丹妙药,执行起来可能需要很长时间。实践中,使用迁移学习获得更好的性能的策略是,通过评估两个任务的迁移性来选择要训练的层数。表8.2展示了一种基于任务相似性和第二任务数据集大小来决定迁移学习策略的简易方法:
| 数据集大小 | 小 | 大 |
|---|---|---|
| 任务相似性 | 低 | 按常规训练整个网络。 |
| 高 | 冻结所有基础网络参数,添加额外的线性预测层,只训练此线性层。 |
表8.2 – 深度迁移学习(DTL)策略指南
为了清晰起见,假设“大的”数据集至少包含10,000个示例。任务的迁移性/相似性需要人类直觉,具体情况需要逐个评估。在本指南中,我们假设大数据集意味着一个具有大变化的数据集,能够充分代表人群。然而,表中未呈现的一个隐藏组件是第一个任务数据集的大小。迁移学习在任务相似性高、第二个任务数据集大小小、并且第一个任务数据集较大的情况下效果最好。第一个数据集的大小通常也限制了可使用的神经网络大小。如果第一个数据集的大小较小,最佳的模型通常是较小的模型。当迁移学习非常有益时,即使第二个数据集的大小是中等或大的,较小的模型仍然能够超越较大的模型。在这种复杂的情况下,需要进行平衡,以获得理想的模型。
迁移学习中的一个突出问题是灾难性遗忘。这是一个现象,当网络在训练新任务时,性能会退化到早期任务的水平。如果先前任务的性能不重要,可以忽略这个问题。实际上,如果需要保持先前任务的性能,可以按照以下步骤进行操作:
- 使用统一的指标,处理第一个任务和第二个任务的性能,同时在第一个任务的验证数据集上进行验证。
- 将第一个任务和第二个任务的数据集结合起来,将其作为一个单独的模型训练。如果目标彼此不相关,则使用不同的全连接层预测头。
最后,还有一种流行的迁移学习技术,称为知识蒸馏。这种方法涉及两个模型,其中一个预训练的教师模型用于将其知识传递给学生模型。通常,教师模型是一个较大的模型,能够学习更准确的信息,但运行时较慢;而学生模型是一个较小的模型,能够在运行时保持合理的速度。该方法通过在基础交叉熵损失的基础上,使用一个额外的相似性损失来蒸馏知识,通常是在教师和学生模型的logit层输出之间进行。这种方法鼓励学生模型生成与教师模型类似的特征。该技术通常用于获得一个比没有知识蒸馏时更小且更准确的模型,从而使部署基础设施变得更便宜。这个技术将在第13章《探索偏见和公平性》中作为减轻偏见的关键技术进行实际介绍。
接下来,我们将深入探讨另一种多任务执行类型,称为多目标学习。
多目标学习
多目标学习是一种多任务处理过程,涉及同时训练不同目标。不同的目标会将网络的学习轨迹引导向不同的路径。多目标学习可以进一步分解为以下几种选项:
-
相同输出上的多个损失函数。
-
多个目标,由独立的神经网络预测头分别处理,每个预测头有各自的损失。这可以进一步分为以下几类:
- 具有实际影响和用途的多个目标。
- 一个或多个主要目标和一个或多个辅助目标。辅助目标与其自身的损失(称为辅助损失)配对。
除了选项2(A)外,其他选项(即1和2(B))主要用于提高度量性能。度量可以是简单的准确率或对数损失,也可以是更复杂的,例如对少数类别的偏倚程度。一个更简单、直接的多目标学习示例是多标签目标类型。多标签是指多个标签可以与单个数据行相关联。这意味着设置将是多个二分类目标,属于2(A)的情况。
多个目标及其关联的损失意味着在学习过程中可能会出现梯度冲突的问题。这种现象通常被称为负迁移。负迁移的一个极端例子是,当两个损失的梯度在大小相等且方向完全相反时,它们会相互抵消。这将阻塞模型的学习过程,导致模型永远无法收敛。实际上,这个问题可能发生在较小的尺度上,减缓收敛速度,或者更糟糕的是,导致巨大的波动,使得学习变得困难。不幸的是,除了理解模型学习不良背后的原因外,没有任何灵丹妙药来缓解这个问题。通常需要通过迭代实验来找出如何平衡这些损失,以鼓励稳定的学习过程。
接下来,我们将深入探讨多模态神经网络训练。
多模态神经网络训练
多模态神经网络(Multimodal NNs)是一种多任务系统,在这种系统中,负责不同模态的网络在同一任务中沿着完全不同的路径进行学习。处理神经网络中的多模态性的一种常见方法是在初始阶段为不同的数据模态分配不同的神经块。神经块包含每个模态特定的网络。然后,使用一系列中间全连接层和输出全连接层将不同模态的神经块合并在一起。图8.7展示了这一过程:
利用多模态的想法是,额外的数据输入可以帮助识别更全面的模式,从而提高整体的度量性能。然而,在实际操作中,如果没有仔细处理训练过程,通常情况并非如此。不同的模态存在完全不同的分布,并且以不同的速率和不同的路径进行学习。将单一的全局优化策略应用于所有数据模态,可能会导致次优结果。一种常见且有效的策略如下:
- 预训练单独的模态神经块(单模态)并使用临时预测输出层,直到达到一定的收敛程度。
- 移除临时预测输出层,并按照常规方式训练多模态神经网络,使用从单模态训练过程中预训练的权重。 除此之外,冻结单模态训练神经网络的权重,仅训练多模态聚合全连接层预测头也是一个有效的策略。还有许多更复杂的策略可以用来解决这个问题,但超出了本书的讨论范围。
总结
在本章中,我们探讨了监督式深度学习,包括它可以解决的各种问题类型以及实现和训练深度学习模型的技术。监督式深度学习涉及使用带标签的数据训练模型,以便对新数据进行预测。我们还涵盖了多种监督学习用例,涉及不同的问题类型,包括二分类、多分类、回归、多任务和表示学习。本章还介绍了有效训练深度学习模型的技术,包括正则化和超参数调整,并通过使用流行的深度学习框架在Python编程语言中提供了实际实现。
监督式深度学习可以应用于广泛的实际应用场景,如图像分类、自然语言处理(NLP)和语音识别。通过本章提供的知识,你应该能够识别监督学习的应用,并有效地训练深度学习模型。
在下一章中,我们将探讨深度学习的无监督学习。