模型所需的计算、存储和输入/输出系统将决定将模型投入生产并在整个生命周期内维护它的成本。在本章中,我们将介绍一些重要的技术,这些技术可以帮助我们管理模型的资源需求。我们将重点关注三个关键领域,这些领域是优化传统机器学习和生成AI(GenAI)模型的主要方法:
- 降维
- 模型参数量化和模型图修剪
- 知识蒸馏,用于捕捉大型模型中的知识
降维:维度对性能的影响
我们首先讨论维度及其如何影响模型的性能和资源需求。
在不久之前,数据生成和在某种程度上,数据存储的成本远高于今天的成本。当时,许多领域专家在设计实验和特征转换之前会仔细考虑要测量哪些特征或变量。因此,数据集通常预期设计得很好,并且可能只包含少量相关特征。
今天,数据科学更多的是关于端到端的整合。生成和存储数据变得更加快速、简单且低成本。因此,人们倾向于测量他们能获取的所有数据,并包括越来越复杂的特征转换。结果,数据集往往是高维的,包含大量特征,但每个特征在分析数据时的相关性并不总是清晰的。
在深入讨论之前,让我们先讨论一个关于神经网络的常见误解。许多开发者正确地认为,当他们训练神经网络模型时,模型本身作为训练过程的一部分,将学习忽略那些不提供预测信息的特征,通过将它们的权重减少到零或接近零。虽然这是对的,但结果并不是一个高效的模型。
当运行推理生成预测时,模型的大部分可能会“关闭”,但那些未使用的部分仍然存在。它们占用了空间,并且在模型服务器遍历计算图时,仍然消耗计算资源。
这些不需要的特征还可能给数据引入不必要的噪声,往往会降低模型性能。事实上,高维度甚至可能导致过拟合。并且在模型本身之外,每增加一个特征,仍然需要系统和基础设施来收集数据、存储数据并管理更新,这增加了整个系统的成本和复杂性。这包括监控数据问题,并在出现问题时修复它们。这些成本会持续到你部署的产品或服务的生命周期,这可能长达几年。
有一些技术可以优化权重为零或接近零的模型。但通常来说,你不应该把所有的特征都丢给模型,并依赖你的训练过程来决定哪些特征实际上是有用的。
在机器学习中,高维数据是一个常见的挑战。例如,跟踪每个购物者的60个不同指标会导致一个60维空间。分析50 × 50像素的灰度图像涉及2,500个维度,而RGB图像则有7,500个维度,每个像素的颜色通道贡献一个维度。
一些特征表示方法,例如独热编码,在处理高维空间中的文本时存在问题,因为它们往往产生非常稀疏的表示,不易扩展。一种克服这个问题的方法是使用嵌入层,它对句子进行标记化,并为每个词分配一个浮动值。这将生成更强大的向量表示,尊重给定句子中单词的时间和顺序。这个表示可以在训练过程中自动学习。
示例:使用Keras进行词嵌入
让我们看一个使用Keras进行词嵌入的具体示例。首先,我们将使用高维嵌入训练一个模型。然后,我们将减少嵌入维度,重新训练模型,并将其准确性与高维版本进行比较:
!pip install -U "jax[cpu]" -f https://storage.googleapis.com/jax-releases/libtpu_releases.html
!pip install --upgrade keras
import numpy as np
import os
os.environ["KERAS_BACKEND"] = "jax"
import keras
from keras.datasets import reuters
from keras.preprocessing import sequence
from keras.utils import to_categorical
from keras import layers
num_words = 1000
print(f'Keras version: {keras.__version__}\n\n')
(reuters_train_x, reuters_train_y), (reuters_test_x, reuters_test_y) = reuters.load_data(num_words=num_words)
n_labels = np.unique(reuters_train_y).shape[0]
reuters_train_y = to_categorical(reuters_train_y, 46)
reuters_test_y = to_categorical(reuters_test_y, 46)
Reuters新闻数据集包含11,228个标注了46个主题的新闻。文档已经以每个单词通过一个整数(其在数据集中的总体频率)进行编码。在加载数据集时,我们指定了将使用的单词数(1,000),因此最不常见的单词被视为未知。
接下来,我们进一步预处理数据,以便为模型训练做好准备。首先,以下代码将目标向量*_y转换为类别变量,适用于训练和测试。接下来,代码将输入文本*_x分割成20个单词的文本序列:
reuters_train_x = sequence.pad_sequences(reuters_train_x, maxlen=20)
reuters_test_x = sequence.pad_sequences(reuters_test_x, maxlen=20)
接下来是构建网络,这是下一个合乎逻辑的步骤。在这里,我们选择使用数据中的所有维度嵌入1,000个单词的词汇。最后一层是密集层,维度为46,因为目标变量是一个46维的类别向量。
在模型结构准备好后,让我们通过指定损失函数、优化器和输出指标来编译模型。对于这个问题,自然的选择是类别交叉熵损失、RMSprop优化和准确性作为指标:
model1 = keras.Sequential(
[
layers.Embedding(num_words, 1000),
layers.Flatten(),
layers.Dense(256),
layers.Dropout(0.25),
layers.Activation('relu'),
layers.Dense(46),
layers.Activation('softmax')
]
)
model1.compile(loss="categorical_crossentropy", optimizer="rmsprop",
metrics=["accuracy"])
我们准备开始实际的模型拟合。我们将指定验证集、批量大小和训练的epoch数。我们还将为TensorBoard添加一个回调:
tensorboard_callback = keras.callbacks.TensorBoard(log_dir="./logs_model1")
model_1 = model1.fit(reuters_train_x, reuters_train_y,
validation_data=(reuters_test_x, reuters_test_y),
batch_size=128, epochs=20, verbose=1,
callbacks=[tensorboard_callback])
现在,让我们使用TensorBoard绘制结果。注意,这段代码在Colab笔记本中运行:
# 加载TensorBoard笔记本扩展
%load_ext tensorboard
# 打开嵌入式TensorBoard查看器
%tensorboard --logdir ./logs_model1
图6-1显示了训练准确性和损失随着训练epoch数的变化。请注意,在大约两个epoch后,我们的训练集结果显示出显著更高的准确率和更低的损失,相比之下验证集的结果较差。这清楚地表明,模型正在严重过拟合。这可能是由于使用了数据的所有维度,因此模型捕捉到训练集中的细微差别,这些差别无法很好地推广到其他数据。
让我们尝试减少维度,看看这会如何影响模型的性能。我们将把1,000个单词的词汇嵌入到6个维度,而不是在图6-1中使用的1,000个维度。这大约是按四次方根的比例减少。除此之外,模型保持不变:
model2 = keras.Sequential(
[
layers.Embedding(num_words, 10),
layers.Flatten(),
layers.Dense(256),
layers.Dropout(0.25),
layers.Activation('relu'),
layers.Dense(46),
layers.Activation('softmax')
]
)
model2.compile(loss="categorical_crossentropy", optimizer="rmsprop",
metrics=["accuracy"])
tensorboard_callback = keras.callbacks.TensorBoard(log_dir="./logs_model2")
model_2 = model2.fit(reuters_train_x, reuters_train_y,
validation_data=(reuters_test_x, reuters_test_y),
batch_size=128, epochs=20, verbose=1,
callbacks=[tensorboard_callback])
# 打开嵌入式TensorBoard查看器
%tensorboard --logdir ./logs_model2
图6-2显示,尽管可能仍有一些过拟合,但通过这一改变,模型的表现明显优于1,000维版本。
维度灾难
让我们来谈谈维度灾难,及其在构建模型时为什么是一个非常重要的话题。
许多常见的机器学习任务,如分割和聚类,都依赖于计算观测之间的距离。例如,监督分类通过计算观测之间的距离来分配类别。K最近邻算法就是这种方式的一个例子。支持向量机(SVM)通过基于观测之间的距离来投影观测数据,通常使用核函数进行投影。另一个例子是推荐系统,它使用基于距离的相似性度量来计算用户与商品属性向量之间的距离。也可以使用其他形式的距离度量。最常见的距离度量之一是欧几里得距离,它是多维超空间中两点之间的线性距离。对于二维向量,欧几里得距离的计算公式为:
但为什么距离如此重要呢?让我们看看在高维空间中度量距离的一些问题。
你可能会想,数据的高维性为什么会是一个问题。在极端情况下,当我们有的特征(维度)比观测值还要多时,我们的模型很容易出现严重的过拟合。但在更普遍的情况下,当我们有太多特征时,观测值变得更难聚类。维度的过多可能导致一种情况,在这种情况下,所有数据点看起来都差不多,彼此间的距离几乎一样远。这对于依赖距离度量的聚类算法是一个重大挑战;它使所有观测值看起来都相似,从而阻碍了有意义聚类的创建。这一现象被称为维度灾难,它导致随着维度的增加,数据点之间的差异性减小。从本质上讲,随着维度增加,点与点之间的距离趋向于集中,这导致在高维空间中处理数据时出现意外的结果。
维度灾难这个术语最早由理查德·贝尔曼在1961年的《自适应控制过程:引导游览》(普林斯顿大学出版社)一书中提出,用来描述高维空间中数据的不直观行为。它主要影响我们理解和使用距离与体积的能力。维度灾难有两个关键含义:
- 机器学习擅长高维分析:机器学习算法在处理高维数据方面具有明显的优势。它们能够有效地揭示在包含大量维度的数据集中存在的模式,即使这些维度之间有复杂的关系。
- 增加维度需要更多资源:随着维度的增加,构建有效模型所需的计算能力和训练数据也会增加。
因此,尽管有时我们倾向于尽可能添加更多特征,但添加更多特征很容易带来问题。这可能包括冗余或无关的特征出现在数据中。此外,当特征无法为我们的模型提供预测能力时,它们会引入噪声。更重要的是,更多的特征使得数据的解释和可视化变得更困难。最后,更多的特征意味着更多的数据,因此你需要更多的存储空间和处理能力来处理这些数据。最终,维度的增加通常意味着我们的模型变得效率更低。
当我们在使模型性能提升时遇到问题时,通常会试图添加更多的特征。但随着特征的增加,我们会达到一个临界点,此时模型的性能会下降,如图6-3所示。
图6-3展示了分类器的性能随着维度数的增加而提高,直到达到最佳特征数量为止。在这一点之后,当训练样本数量固定时,增加更多的维度会导致性能逐渐下降。
让我们探讨另一个与维度相关的问题,以便更好地理解这种行为的原因。
增加维度增加特征空间的体积
数据集的维度数(特征数量)的增加意味着每个训练样本的特征向量中有更多的条目。例如,在欧几里得空间和欧几里得距离度量的情况下,每增加一个维度,都会向和中添加一个非负的项。这趋向于增加距离度量,随着特征的增加,样本之间的距离变得更大。
换句话说,随着给定训练样本数量下特征数量的增加,特征空间变得越来越稀疏,训练样本之间的距离增大。由于这一点,较低的数据密度需要更多的训练样本,以保持样本之间的平均距离相同。也很重要的一点是,新增的样本与样本中已经存在的样本应当具有显著的差异。
随着数据点之间距离的增加,监督学习变得更加具有挑战性,因为对于新实例的预测不太可能受到相似训练样本的启发。随着更多特征的增加,特征空间快速扩展,这使得有效的泛化变得越来越困难。模型的方差也随之增加,从而提高了对高维空间中的噪声进行过拟合的风险。在实践中,特征也往往是相关的,或者变化不大。基于这些原因,需要进行维度减少。
目标是尽可能保留最多的预测信息,使用尽可能少的特征,使模型尽可能高效。
不论使用哪种建模方法,增加维度还有另一个问题,特别是在分类任务中。休斯效应(Hughes effect)是一种现象,表现为随着特征数量的增加,分类性能的改善,直到达到一个合适的最优点,这时特征数量恰到好处。正如图6-3所示,在保持训练集大小不变的情况下,增加更多特征会降低分类器的性能。
在分类任务中,目标是找到一个区分两个或多个类别的函数。你可以通过在空间中搜索超平面来分隔这些类别。维度越多,在训练过程中越容易找到一个超平面,但与此同时,当对未见数据进行泛化时,匹配这种性能就变得更加困难。而且,如果你的训练数据量较少,你就越不确定自己是否找到了区分这些类别的重要维度。
维度减少
不幸的是,关于一个ML问题理想的特征数量,没有“一刀切”的答案。最佳特征数量取决于多个因素,包括训练数据的体量、数据中的变异性、决策边界的复杂性以及所使用的特定模型。
维度减少与特征选择之间是有关联的,因为你在模型输入中包含的特征数量对模型的总体维度有很大影响。从本质上讲,你希望拥有足够的数据、最优的特征、这些特征值的足够多样性,以及这些特征中包含足够的预测信息,以最大化模型的性能,同时尽可能简化它。
因此,在预处理特征集以创建新特征集时,保留尽可能多的预测信息是很重要的。如果没有预测信息,世界上再多的数据也无法帮助模型学习。这些信息还需要以有助于模型学习的形式呈现。
在ML中,获得最佳结果通常依赖于实践者在设计有效特征方面的专业知识。这个方面的ML工程学涉及一定的艺术性;特征重要性和选择工具只能提供关于现有特征的客观见解。你通常需要手动创建这些特征。这需要大量时间处理实际样本数据,并思考问题的潜在形式、数据中的结构以及如何最好地为预测建模算法表达它们。
三种方法
基本上,有三种不同的方式来选择合适的特征。这是在进行任何特征工程之前,用于改善所选特征的方式。
第一种方法是手动特征选择,通常基于领域知识和/或对类似模型在相似领域中的先前经验。
第二种方法是应用特征选择算法,这里有很多种算法。特征选择试图通过创建特征的搜索空间并尝试确定满足标准的最佳特征集来分析数据,这些标准通常是你想要的特征数量或你希望训练的模型。维度减少也可以进行,通常与特征选择独立讨论。
第三种方法是算法化的维度减少,它试图将特征从它们定义的空间投影到一个低维空间。主成分分析(PCA)是最常用的例子。通过在低维空间中表示数据,维度减少了。然而,这通常也意味着你对数据的不同维度的直观理解丧失了,人工很难解释一个特定的例子代表了什么。
这些方法不是互相排斥的,在许多情况下,你最终会使用它们的某种组合。你在特定情况下决定使用哪些方法,是ML工程艺术的一部分。作为经验法则,最好从简单开始,只有在需要时才逐步增加复杂性,并且只有在这样做能持续改善结果时才增加复杂性。
算法化的维度减少
有几种算法可以用于进行维度减少。首先,让我们构建一些关于线性维度减少的直觉。在这种方法中,你将n维数据线性投影到一个更小的k维子空间。这里,k通常远小于n。我们可以将原始数据投影到无限多的维度子空间。那么,应该选择哪个子空间呢?
为了理解如何选择子空间,我们先回顾一下如何将数据投影到一条线上。首先,假设这些例子是存在于高维空间中的向量。可视化它们将揭示很多关于数据分布的信息,尽管我们人类只能一次看到有限的维度。
相反,我们需要将数据投影到低维度。这种投影被称为嵌入。在极端情况下,如果我们只想要一个维度,我们会计算一个数字来描述每个例子。将数据减少到一个维度的好处是,数字和例子可以在一条线上排序,这很容易可视化。然而,在实践中,我们很少会只想要一个维度用于训练模型的数据。
回到子空间问题,选择这些k维子空间有几种方法。例如,对于分类任务,我们通常希望最大化类别之间的分离。线性判别分析(LDA)通常在这方面表现良好。对于回归,我们希望最大化投影数据与输出之间的相关性,部分最小二乘法(PLS)表现良好。最后,在无监督任务中,我们通常希望尽可能保留大部分方差。PCA是最广泛使用的技术来做到这一点。
主成分分析(PCA)
PCA(主成分分析)之所以被称为主成分分析,是因为它学习数据的“主成分”。这些主成分是样本变异性最大的方向,如图6-4所示,表示为虚线。PCA对齐坐标轴的正是这些主成分。
PCA可以在scikit-learn和TF Transform中使用,尤其在使用TFX的生产管道中非常有用。
PCA是一种无监督方法,通过原始特征的线性组合来构建新的特征。它通过两个步骤来实现维度减少,首先进行去相关过程,保持原始维度数量。在这个第一步中,PCA将数据点旋转,使其与坐标轴对齐,并通过将均值移到零点来进行中心化。
PCA的目标是找到一个低维度的空间,将数据投影到这个空间上,以最小化平方投影误差——换句话说,就是最小化每个点到其投影位置的距离的平方。这样做的结果是最大化投影数据的方差。初始的主成分代表了投影方向,它使得投影数据中的方差最大化。随后,第二主成分被确定为与第一个主成分垂直的投影方向,同时最大化投影数据中的剩余方差。
我们不会在这里详细讨论PCA的工作原理,但如果你感兴趣,有很多很好的资源可以进一步了解。PCA是一种实用且有效的技术,以其快速性和易于实现而闻名。这使得可以方便地比较应用PCA和不应用PCA时算法的性能。此外,PCA还有许多适应性和扩展,如核PCA和稀疏PCA,用来解决特定的挑战。然而,生成的主成分通常不容易解释,这在解释性至关重要的场景中可能是一个重大缺点。此外,你仍然需要手动确定或调整累计解释方差的阈值。
PCA在高维度中可视化观察值的聚类时特别有用,尤其是在你仍然在探索数据时。例如,你可能有理由相信数据本质上是低秩的,这意味着数据有很多属性,但只有少数几个属性通过线性关联大致决定了其他属性。PCA可以帮助你验证这一理论。
量化和剪枝
模型优化是另一个重点领域,可以进一步优化性能和资源需求。目标是创建尽可能高效且准确的模型,以在最小成本下实现最高性能。让我们来看一下两种先进技术:量化和剪枝。我们首先讨论一些与移动设备、物联网(IoT)和嵌入式应用相关的问题。
移动、物联网、边缘计算和类似应用
机器学习(ML)正在越来越多地融入更多设备和产品中。这包括移动和物联网应用的快速增长,包括遍布从农田到铁路轨道的各类设备。企业正在利用这些设备生成的数据来训练机器学习模型,以改善其业务流程、产品和服务。甚至数字广告商在移动端的支出已超过桌面端。如今,已经有数十亿台移动和边缘计算设备,而且这个数字将在未来十年继续快速增长。
量化
量化是一个将模型转换为功能上等效的表示的过程,使用具有较低精度的参数和计算,意味着使用更少的比特位。这个技术可以提高模型的执行速度和效率,但可能导致模型整体准确性的下降。
量化的好处和过程
让我们通过类比来更好地理解这一点。想象一下图像。如你所知,一张图片是一个像素网格,每个像素有一定的比特位。如果你试图将真实世界的连续色谱缩减为离散颜色,你就是在进行量化或近似图像。从本质上讲,量化减少了表示信息所需的比特数。然而,你可能会注意到,随着你将可能的颜色减少到某个点之后,图像的质量可能会下降。一般来说,量化总是会减少模型的准确性,因此量化的好处和因其带来的准确性损失之间存在权衡。
神经网络由激活节点、它们的相互连接、分配给每个连接的权重参数和偏差项组成。在量化的背景下,主要关注的是量化这些权重参数以及在激活节点内执行的计算。
神经网络模型通常占用大量存储空间,主要由于大量的模型参数(与神经连接相关的权重),这些权重在一个模型中可能有数百万甚至数十亿个。这些参数作为浮动点数,不能通过常规的压缩方法(如压缩文件)轻松压缩,除非模型的密度降低。
然而,模型参数也可以量化,将它们从浮动点转换为整数值。这不仅减少了模型的大小,而且通常可以加速推理,因为整数运算通常比浮动点运算要快。甚至将16位浮动点模型量化到4位整数已被证明可以获得可接受的结果。
量化本质上会丢失一些信息。然而,给定层内的权重和激活值通常聚集在一个窄小、可预测的范围内。这使我们可以在一个较小的、预定的范围内分配有限的比特位(例如,–3到+3),从而优化精度。准确估计这个范围至关重要。正确执行时,量化会导致最小的精度损失,通常对输出的影响是可以忽略的。
量化的最直接动机是缩小文件大小和内存需求。尤其对于移动应用来说,将一个200MB的模型存储在手机上仅为了运行一个应用是不可行的。因此,压缩高精度模型是必要的。
另一个量化的理由是,通过仅使用低精度的输入和输出来执行推理计算,从而最小化所需的计算资源。虽然这要更具挑战性,需要在整个计算过程中做出修改,但它可以带来巨大的好处。例如,它可以帮助你更快速地运行模型,并减少功耗,这在移动设备上尤其重要。它甚至为许多嵌入式系统打开了大门,这些系统无法高效地运行浮动点代码,从而使得许多物联网应用成为可能。
然而,优化有时会影响模型的准确性,这是在应用开发过程中需要考虑的因素。这些准确性变化是特定于你优化的模型和数据的,并且很难预见。一般来说,优化模型大小或延迟时,模型的准确性会有所下降。根据你的应用需求,这种影响可能或可能不会影响用户体验。在极少数情况下,某些模型实际上可能会因优化过程而提高准确性。
你将需要在模型的准确性和复杂性之间做出权衡。如果任务需要高准确性,你可能需要一个大而复杂的模型。对于那些要求较低精度的任务,使用一个较小、较简单的模型会更好,因为它不仅占用更少的磁盘空间和内存,而且通常会更快、更节能。因此,一旦选择了适合任务的候选模型,最好进行性能分析和基准测试。
MobileNets
MobileNets是一系列架构,能够在设备端延迟和ImageNet分类准确度之间实现最先进的平衡。Google Research的一项研究展示了如何通过仅使用整数量化来进一步优化常见硬件上的平衡。论文的作者对MobileNet架构进行了基准测试,使用不同深度的乘法器和分辨率,在三种类型的高通核心上对ImageNet进行测试。图6-5展示了Snapdragon 835芯片的结果。可以看到,对于任何给定的准确度水平,8位版本的模型的延迟时间(运行时间)比浮动点版本的延迟时间更低(向左移动)。
算术操作在减少位深度的情况下执行时,通常会更快,前提是硬件支持它。尽管现代CPU在浮动点和整数计算之间的性能差距已大大缩小,但涉及32位浮动点数的操作通常仍然比8位整数操作慢。
从32位转换到8位,我们通常可以获得加速,并将内存需求减少4倍。更小的模型占用更少的存储空间,便于在带宽较小的环境中共享,也更容易进行更新。较低的位深度还意味着我们可以将更多的数据压缩到相同的缓存和寄存器中,这使得构建具有更好缓存能力的应用成为可能,从而减少功耗并提高速度。
浮动点运算较为复杂,这就是为什么微控制器和一些超低功耗嵌入式设备(如无人机、手表或物联网设备)可能不总是支持浮动点运算的原因。另一方面,整数运算总是可用的。
训练后量化
量化神经网络的最直接方法是先用全精度训练它,然后再将权重量化为定点值。这称为训练后量化。量化可以在训练过程中(量化感知训练)进行,也可以在模型训练完成后进行(训练后量化)。我们先来看训练后量化。
训练后量化的目标是减小已经训练好的模型的大小,旨在提高CPU和硬件加速器的延迟,理想情况下不显著影响模型的准确度。例如,当您将预训练的浮动点TensorFlow模型转换为TensorFlow Lite(TF Lite)格式时,您可以轻松地对其进行量化。
基本上,训练后量化的作用是将权重从浮动点数转换为整数,效率地进行量化。通过这样做,通常可以获得高达三倍的延迟降低,而不会对准确度产生重大影响。使用TF Lite的默认优化策略,转换器会尽最大努力应用训练后量化,同时优化模型的大小和延迟。这是推荐的做法,但您也可以自定义这种行为。
有几种训练后量化的选择。表6-1总结了这些选择及其带来的好处。
表6-1. 训练后量化技术及其好处
| 技术 | 好处 |
|---|---|
| 动态范围量化 | 4倍小,速度提升2倍到3倍 |
| 完全整数量化 | 4倍小,速度提升超过3倍 |
| Float16量化 | 2倍小,支持GPU加速 |
如果您希望获得较好的加速效果,例如两到三倍更快并且模型体积减半,您可以考虑动态范围量化。在动态范围量化中,推理时权重从8位转换为浮动点数,并使用浮动点内核计算激活。这个转换只需执行一次,并且会被缓存以减少延迟。这种优化提供了接近完全定点推理的延迟。
使用动态范围量化,您可以减小模型的大小和/或延迟。但它也有一个限制,因为它要求推理过程使用浮动点数进行。这个方法可能并不总是理想的,因为一些硬件加速器只支持整数运算(例如,Edge TPU)。
另一方面,如果您想进一步提升模型性能,完全整数量化或Float16量化可能会提供更快的性能。特别是当您计划使用GPU时,Float16特别有用。
TF Lite优化工具包还支持完全整数量化。这使得用户可以将已训练的浮动点模型完全量化为只使用8位带符号整数,从而使定点硬件加速器能够运行这些模型。当针对更大的CPU改进或定点加速器时,这通常是更好的选择。
完全整数量化的工作原理是收集校准数据,通过在一小部分输入上进行推理来确定将模型转换为整数量化模型所需的正确缩放参数。
训练后量化可能会导致准确度的损失,尤其是对于较小的网络,但这种损失通常是微不足道的。好的一面是,通过使用低精度进行最重的计算,并用较高精度处理最敏感的计算,通常可以显著提高执行速度,同时几乎没有准确度的损失。
特定网络的预训练完全量化模型也可以在TF Lite模型库中找到。验证量化模型的准确度非常重要,以确保任何准确度的下降在可接受的范围内。TF Lite包括一个评估模型准确度的工具。
量化感知训练
如果后训练量化带来的准确度损失过大,可以考虑使用量化感知训练。然而,这需要在模型训练期间进行修改,添加虚拟量化节点。
量化感知训练(QAT)是在模型训练过程中应用量化。其核心思想是,在训练的前向传递过程中模拟低精度推理计算。通过引入模拟量化节点,通常在实际推理时由于量化而发生的四舍五入效应将在前向传递中得到复制。目的是微调权重,以补偿精度损失。因此,如果这些模拟量化节点被插入到预期会发生量化的模型图中的特定位置(例如,在卷积层处),那么在前向传递过程中,浮动值会被四舍五入到指定的级别,从而模拟量化效应。
这种方法将量化误差作为噪声引入训练过程中,将其视为优化算法要最小化的整体损失的一部分。因此,模型学习到的参数会对量化更具鲁棒性。在量化感知训练中,您首先以标准方式构建模型,然后使用TensorFlow模型优化工具包的API使其具备量化感知能力。然后,您使用量化仿真操作来训练这个模型,得到一个完全量化的模型,该模型仅使用整数进行操作。
结果比较
表6-2展示了几种模型的准确度损失情况。这将帮助您了解在自己模型中可能出现的情况。
表6-2. 比较后训练量化与量化感知训练后的准确度结果
| 模型 | Top-1准确度(原始) | Top-1准确度(后训练量化) | Top-1准确度(量化感知训练) |
|---|---|---|---|
| Mobilenet-v1-1-224 | 0.709 | 0.657 | 0.70 |
| Mobilenet-v2-1-224 | 0.719 | 0.637 | 0.709 |
| Inception_v3 | 0.78 | 0.772 | 0.775 |
| Resnet_v2_101 | 0.770 | 0.768 | N/A |
表6-3展示了几种模型的延迟变化。请记住,延迟越低越好。
表6-3. 比较后训练量化与量化感知训练后的延迟(毫秒)
| 模型 | 延迟(原始)(毫秒) | 延迟(后训练量化)(毫秒) | 延迟(量化感知训练)(毫秒) |
|---|---|---|---|
| Mobilenet-v1-1-224 | 124 | 112 | 64 |
| Mobilenet-v2-1-224 | 89 | 98 | 54 |
| Inception_v3 | 1130 | 845 | 543 |
| Resnet_v2_101 | 3973 | 2868 | N/A |
表6-4比较了模型大小。后训练量化和量化感知训练大致给出了相同的大小减少。再次提醒,数值越低越好。
表6-4. 比较量化后的模型大小
| 模型 | 原始大小(MB) | 优化后的大小(MB) |
|---|---|---|
| Mobilenet-v1-1-224 | 16.9 | 4.3 |
| Mobilenet-v2-1-224 | 14 | 3.6 |
| Inception_v3 | 95.7 | 23.9 |
| Resnet_v2_101 | 178.3 | 44.9 |
示例:使用TF Lite量化模型
TensorFlow生态系统提供了多种库,用于将模型导出到不同平台,如移动设备或Web浏览器。通常这些设备有硬件限制;例如,移动设备的可用内存有限。
TensorFlow允许通过TF Lite库优化机器学习模型以适应这些设备。使用TF Lite进行优化时有一些注意事项。例如,并非所有TensorFlow操作都可以转换为TF Lite。但支持的操作列表正在不断增长。
您可以使用TensorFlow Serving部署转换为TF Lite的模型,我们将在第20章中展示如何进行。
使用TF Lite优化TensorFlow模型
在撰写本文时,TF Lite支持以下模型格式:
- TensorFlow的SavedModel格式
- Keras模型
- TensorFlow的具体函数
- JAX模型
TF Lite提供了多种优化选项和工具。您可以通过命令行工具或Python库将模型转换为TF Lite格式。起点始终是您训练并导出的机器学习模型,且格式应在上面列出的其中之一。
在以下示例中,我们加载一个Keras模型:
import tensorflow as tf
model = tf.keras.models.load_model("model.h5")
接下来,我们创建一个转换器对象,在其中包含所有优化参数:
converter = tf.lite.TFLiteConverter.from_keras_model(model)
创建转换器对象后,我们可以定义优化参数。这些参数可以是优化目标、支持的TensorFlow操作,或者输入/输出类型:
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.int8 # 或 tf.uint8
converter.inference_output_type = tf.int8 # 或 tf.uint8
定义完所有参数后,我们可以通过调用converter.convert()来转换模型,然后保存返回的对象:
tflite_quantized_model = converter.convert()
with open('your_quantized_model.tflite', 'wb') as f:
f.write(tflite_quantized_model)
现在我们可以使用量化后的模型,可以通过将your_quantized_model.tflite集成到移动应用程序中,或者通过TensorFlow Serving来使用它(我们将在第11章中详细讨论)。
优化选项
旧版TF Lite文档提供了两个优化选项:
- OPTIMIZE_FOR_SIZE
- OPTIMIZE_FOR_LATENCY
这两个选项已经被弃用,现在被一个新的优化选项取代:EXPERIMENTAL_SPARSITY。此选项检查模型参数的稀疏性模式,并根据需要优化模型的大小和延迟。它可以与DEFAULT选项一起使用:
converter.optimizations = [
tf.lite.Optimize.DEFAULT,
tf.lite.EXPERIMENTAL_SPARSITY]
tflite_model = converter.convert()
如果您的模型包含TF Lite在导出时不支持的TensorFlow操作,转换步骤将失败并显示错误消息。您可以启用一组额外的TensorFlow操作供转换过程使用。然而,这会使您的TF Lite模型的大小增加大约30 MB。以下代码片段演示了如何在执行转换器之前启用额外的TensorFlow操作:
converter.target_spec.supported_ops = [
tf.lite.OpsSet.TFLITE_BUILTINS,
tf.lite.OpsSet.SELECT_TF_OPS]
tflite_model = converter.convert()
如果您的模型转换仍然失败,原因是某个TensorFlow操作不被支持,您可以向TensorFlow社区报告。社区正在积极增加TF Lite支持的操作数量,并欢迎大家对未来希望添加到TF Lite中的操作提出建议。您可以通过GitHub中的TF Lite Op Request表单提名TensorFlow操作。
剪枝
提高模型效率的另一种方法是移除那些对产生准确结果没有实质性贡献的模型部分,这就是所谓的剪枝。
随着机器学习模型被应用到嵌入式设备(如手机)中,压缩神经网络变得越来越重要。在深度学习中,剪枝是一种受到生物学启发的概念,模仿了大脑中神经元的某些行为。剪枝旨在通过去除冗余连接,减少神经网络的计算复杂性,从而减少参数数量,并可能提高推理速度。
网络通常像图6-6左边的示意图那样。这里,每个层中的神经元都与前一层有连接,但这意味着我们需要将大量的浮点数相乘。
理想情况下,我们希望将每个神经元仅连接到少数其他神经元,从而减少一些乘法运算的次数,如果我们能够在不损失太多精度的情况下做到这一点。这就是剪枝的动机。
连接稀疏性长期以来是神经科学研究的一个基础原则,因为这是新皮层的重要观察之一。无论你在哪里观察大脑,神经元的活动总是稀疏的。然而,常见的神经网络架构有许多参数,通常并不是稀疏的。例如,ResNet50 就有近2500万个连接。这意味着在训练过程中,我们需要调整2500万个权重。至少可以说,这是一项相对昂贵的工作。因此,我们需要找到某种方法来解决这个问题。
神经网络稀疏性的故事始于剪枝,这是通过压缩减少神经网络规模的一种方式。在硬件受限的情况下,比如在嵌入式设备或智能手机中,速度和大小可能决定一个模型的成败。而且,更复杂的模型更容易过拟合。因此,从某种意义上讲,限制搜索空间也可以起到正则化的作用。然而,这并不是一件简单的任务,因为减少模型的容量也可能导致精度的损失。所以,像许多其他领域一样,复杂性与性能之间有着微妙的平衡。
关于神经网络稀疏性的第一篇重要论文可以追溯到1990年。由Yann Le Cun、John S. Denker和Sara A. Solla撰写的论文名为《Optimal Brain Damage》。当时,训练后的神经网络压缩模型已经是一种流行的方法。剪枝主要是通过使用幅度作为显著性近似值来确定不太有用的连接——其直觉是,幅度较小的权重对输出的影响较小,因此如果被剪枝,它们对模型结果的影响也较小。
这是一种迭代的剪枝方法。第一步是训练模型。接着,估算每个权重的显著性,显著性定义为对权重施加扰动后,损失函数的变化程度。变化越小,权重对训练的影响越小。最后,作者删除了显著性最低的权重(相当于将它们设为零),然后重新训练剪枝后的模型。
这种方法的一大挑战在于,剪枝后的网络重新训练时,结果变得更加困难。这个问题的解决方案后来得到了提出,这一发现被称为“彩票票据假说”。
彩票票据假说
中大奖的概率非常低。例如,如果你在玩Powerball彩票,每张票中奖的概率是大约1/300万。如果你买了N张票,你中奖的概率是多少?
对于N张票,我们的概率是(1 - p)^N。从这个公式可以得出,至少有一张票中奖的概率就是其补集。那么,这与神经网络有什么关系呢?在训练之前,模型的权重是随机初始化的。是否有可能存在一个随机初始化的网络子网络,恰好赢得了初始化的彩票?
一些研究者开始调查这个问题并尝试回答这个问题。特别是Frankle和Carbin在2019年发现,训练后对这些新剪枝网络进行微调是不必要的。事实上,他们展示了最好的方法是将权重重置为最初的值,然后重新训练整个网络。这将导致比原始密集模型和剪枝后加微调的模型更高的准确性。
这一发现促使Frankle和Carbin提出了一个最初被认为是疯狂的想法,但现在已经被广泛接受——即过参数化的密集网络包含几个稀疏的子网络,它们的性能各异,其中一个子网络就是“中奖票”,它比其他所有子网络表现更好。
然而,这种方法也有显著的局限性。例如,它在更大规模的问题和架构上表现不佳。在原始论文中,作者表示,对于更复杂的数据集,如ImageNet,以及更深的架构,如ResNet,该方法无法识别出初始化彩票的赢家。一般来说,获得好的稀疏性-精度平衡是一个困难的问题。到目前为止,这是一个非常活跃的研究领域,最前沿的技术还在不断进步。
TensorFlow中的剪枝
TensorFlow包括一个基于Keras的权重剪枝API,采用一种简单且广泛适用的算法,旨在训练过程中根据权重的大小迭代地移除连接。基本上,指定一个最终的目标稀疏性,并设置一个计划来执行剪枝。
在训练过程中,将安排执行一个剪枝例程,移除具有最低权重的、接近零的连接,直到达到当前的稀疏性目标。每次剪枝例程执行时,都会重新计算当前的稀疏性目标,从0%开始,直到通过平滑的逐步增加函数,在剪枝计划的末尾达到最终目标稀疏性。
就像计划一样,逐步增加函数可以根据需要进行调整。例如,在某些情况下,可能方便在某个步骤后开始训练程序,当某些收敛水平已经达成,或者在总训练步骤数之前提前结束剪枝,以便在最终目标稀疏性水平上进一步微调系统。
随着训练的进行,稀疏性逐渐增加,因此你需要知道何时停止。这意味着在训练程序结束时,剪枝后的Keras层对应的张量将包含在剪枝位置的零,依据该层的最终稀疏性目标。
剪枝的一个直接好处是磁盘压缩。这是因为稀疏张量是可压缩的。因此,通过对剪枝后的TensorFlow检查点或转换后的TF Lite模型应用简单的文件压缩,我们可以减少模型的存储和/或传输大小。在某些情况下,甚至可以在利用整数精度效率的CPU和ML加速器上获得速度提升。此外,通过多个实验,我们发现权重剪枝与量化兼容,产生复合效益。
知识蒸馏
到目前为止,我们讨论了优化模型实现的方式,以提高其效率。但你也可以尝试捕捉或“蒸馏”一个模型所学到的知识,转化为一个更高效或更紧凑的模型,这种方法被称为知识蒸馏。
教师模型和学生模型
随着模型试图捕捉更多的信息或知识以学习复杂任务,它们往往变得越来越大和复杂。更大、更复杂的模型需要更多的计算资源来生成预测,这在任何形式的部署中都是一个劣势,尤其是在计算资源有限的移动部署中。
但是,如果我们能够更高效地表达或表示这些学习,我们或许能够创建出比这些更大、更复杂模型更小的等效模型,如图6-7所示。
例如,考虑图6-7中展示的GoogLeNet。今天,它被认为是一个相对较小或中等大小的网络,但即便如此,它仍然足够深且复杂,以至于在页面上很难完全展示。它之所以如此深,正是因为它能够表达特征之间复杂的关系,这也是许多应用所需的能力。但它的规模也足够大,以至于在许多生产环境中部署它是困难或不可能的,包括移动电话和边缘设备。
那么,你能否兼得两全之美,将一个像GoogLeNet这样的复杂模型中的知识,压缩到一个更小、更高效的模型中呢?
这就是知识蒸馏的目标。与我们之前讨论的量化和剪枝优化网络实现不同,知识蒸馏的目的是创建一个更高效的模型,它能够捕捉到与更复杂模型相同的知识。如果需要,进一步的优化可以应用于结果。
知识蒸馏是一种训练小型模型以模仿更大模型,甚至是模型集成的方法。它首先通过训练一个复杂的模型或模型集成,达到高精度。如图6-8所示,然后使用该模型作为“教师”,来训练较简单的“学生”模型,学生模型将成为实际部署到生产环境中的模型。这个教师网络可以是固定的,也可以是共同优化的,甚至可以用来同时训练多个不同大小的学生模型。
知识蒸馏技术
在模型蒸馏中,教师模型和学生模型的训练目标函数是不同的:
- 教师模型首先使用标准的目标函数进行训练,旨在最大化模型的准确性(或类似的度量)。这就是常规的模型训练过程。
- 学生模型则寻求可转移的知识,因此,它使用一个目标函数,旨在匹配教师模型预测的概率分布。
需要注意的是,学生模型不仅仅是模仿教师模型的预测结果,而是内化这些预测的概率。这些概率作为“软标签”,传达了比预测本身更丰富的教师模型的知识。
知识蒸馏通过最小化损失函数,将知识从教师模型转移到学生模型。在此过程中,目标是教师模型预测的类别概率分布。通常,教师模型的logits作为最终softmax层的输入,因为它们提供了关于每个样本所有目标类别的附加信息。然而,实际情况是,这种分布通常会极力偏向正确的类别,而其他类别的概率则微不足道。因此,它可能并没有提供比数据集中已经存在的真实标签更多的信息。
为了克服这个局限性,Hinton、Vinyals和Dean引入了softmax温度的概念。通过在教师和学生的目标函数中增加温度参数,可以增强教师模型概率分布的“柔软性”,公式如下:
在此公式中,类别i的概率P由logits z计算得出,T表示温度参数。当T等于1时,你得到标准的softmax函数。然而,随着T的增加,softmax函数产生的概率分布变得更加“柔软”,从而揭示教师模型认为哪些类别与预测类别相似。这些细微的信息被称为“黑暗知识”,它在蒸馏过程中被转移到学生模型中,学生模型的目标是复制这些软标签或软logits。
有几种技术用于训练学生模型以匹配教师模型的软标签。一种方法是使用标准目标函数训练学生模型,该目标函数同时利用教师模型的logits和目标标签。这两个目标函数在反向传播过程中被加权并组合起来。另一种常见的方法是使用Kullback-Leibler(K-L)散度等度量来比较学生模型的预测分布和教师模型的预测分布。
在计算与教师软标签的损失函数时,使用相同的温度值T来计算学生模型logits的softmax。这个损失称为蒸馏损失。作者们还发现了另一个有趣的现象。事实证明,蒸馏后的模型不仅能够生成教师的软标签,还能生成正确的标签。这意味着你可以计算学生预测的类别概率与真实标签之间的“标准”损失。这些标准标签称为硬标签或硬目标。这个损失就是学生损失。因此,当你计算学生的概率时,softmax温度被设置为1:
在这种方法中,知识蒸馏是通过结合两个损失函数来完成的,其中α的取值在0和1之间。这里,LHL_HLH 是硬标签的交叉熵损失,LKLL_{KL}LKL 是教师logits的K-L散度损失。在进行大量数据增强时,由于对数据应用了强扰动,你可能无法信任原始的硬标签。
这里的K-L散度是度量两个概率分布之间差异的指标。你希望这两个概率分布尽可能接近,因此目标是使学生预测的类别分布尽可能接近教师模型的分布。
应用知识蒸馏的初步定量结果令人鼓舞。Hinton等人在自动语音识别任务中训练了10个不同的模型,并保持与基准相同的架构和训练过程。当时,深度神经网络用于自动语音识别,以映射特征的短期时间上下文。这些模型使用不同的随机权重值进行初始化,以确保训练模型的多样性,从而使它们的集成预测轻松超过单个模型的预测。为了保证训练模型的多样性,他们使用不同的随机初始化权重,并认为在结果上变化训练数据对结果影响不大,因此采用了一个更简单的策略,即比较集成模型和单个模型。
在蒸馏过程中,他们尝试了不同的softmax温度值,例如1、2、5和10。同时,他们对硬目标的交叉熵使用了相对权重0.5。
表6-5显示,蒸馏确实能从训练集中提取比单纯使用硬标签训练单个模型更多的有用信息。
表6-5. 比较蒸馏模型的准确率和字错误率
| 模型 | 准确率 | 字错误率 |
|---|---|---|
| 基准模型 | 58.9% | 10.9% |
| 10倍集成模型 | 61.1% | 10.7% |
| 蒸馏单一模型 | 60.8% | 10.7% |
将单一基准模型与10倍集成模型进行比较时,我们可以看到准确率有所提高。接着,将集成模型与蒸馏模型进行比较,我们发现准确率的提升中有超过80%的部分被成功地转移到单个蒸馏模型上。集成模型在23,000词的测试集上仅提供了适度的字错误率改进,这可能是由于目标函数的不匹配。然而,集成模型在字错误率上的减少成功转移到了蒸馏模型上。这证明了他们的模型蒸馏策略是有效的,并且可以将多个模型的集成压缩成一个模型,该模型的表现明显优于直接从相同数据训练的相同大小的模型。
这个测试是在研究知识蒸馏时进行的。然而,在实际应用中,人们更倾向于部署一种“低资源”模型,能够提供接近最先进结果,但更小、更快。Hugging Face开发了DistilBERT,这是BERT模型的精简版本,通过减少40%的参数并提升60%的速度,仍能保持BERT在GLUE语言理解基准上的97%的性能。基本上,它是BERT的一个更小版本,去除了通常用于下一个句子分类任务的token类型嵌入和池化层。为了创建DistilBERT,Hugging Face的研究人员将知识蒸馏应用于BERT(因此命名为DistilBERT)。他们保持了其余架构不变,同时减少了层数。
TMKD:为问答任务蒸馏知识
让我们来看一下如何为问答任务蒸馏知识。将这些复杂的模型应用于实际的商业场景时,由于模型参数的庞大数量,变得非常具有挑战性。传统的模型压缩方法通常在压缩过程中会遭遇信息丢失,导致压缩后的模型表现不如原始模型。
为了应对这一挑战,微软的研究人员提出了一种两阶段多教师知识蒸馏(TMKD)方法,应用于Web问答系统。在这种方法中,研究人员首先开发一个通用的问答蒸馏任务,用于学生模型的预训练,然后在下游任务(如Web问答任务)上进一步通过多教师知识蒸馏对这个预训练的学生模型进行微调。这样做可以有效减少单个教师模型的过拟合偏差,并将更多的通用知识转移给学生模型。
到目前为止,介绍的基本知识蒸馏方法被称为1对1模型,因为一个教师将知识转移给一个学生。尽管这种方法可以有效减少参数数量和模型推理的时间,但由于在知识蒸馏过程中会丢失信息,学生模型的表现有时并不与教师模型相当。
这一点正是微软研究人员创建不同方法的动力,这种方法被称为m对m集成模型,结合了集成和知识蒸馏。这种方法首先训练多个教师模型。这些模型可以是BERT、GPT或其他同样强大的模型,每个教师模型具有不同的超参数。接着,为每个教师模型训练一个学生模型。最后,将不同教师训练出的学生模型进行集成,生成最终结果。通过这种技术,您为每个教师模型准备并训练一个特定的学习目标。不同的学生模型具有不同的泛化能力,并且它们在不同的方式上对训练数据进行过拟合,从而实现接近教师模型的表现。
TMKD优于各种最新的基准,并已应用于实际商业场景。由于这里使用了集成方法,这些压缩模型受益于大规模数据,能够很好地学习特征表示。实验结果表明,TMKD可以显著超越基准方法,甚至在模型推理速度大幅加快的情况下,取得与原始教师模型相当的结果(见图6-9)。
作者在多个数据集上进行了实验,使用公开的且规模较大的基准,以验证该方法的有效性。为了支持这些说法,我们逐一来看TMKD的优势。TMKD的一个独特之处在于,它使用多教师蒸馏任务来进行学生模型的预训练,从而提升模型性能。为了分析预训练的影响,作者评估了两个模型。
第一个模型(TKD)是一个三层BERT模型,首先在CommQA数据集上使用基础的知识蒸馏预训练进行训练,然后仅使用一个教师针对每个任务进行微调。第二个模型是传统的知识蒸馏模型,也是相同的模型,但没有进行蒸馏预训练阶段。通过利用大规模的无监督问答对进行蒸馏预训练,TKD表现出了显著的提升。
TMKD的另一个好处是它提供了一个统一的框架,可以从多个教师模型中共同学习。为此,作者比较了多教师蒸馏与单教师蒸馏的影响,使用了两个模型——MKD,一个三层BERT模型,通过多教师蒸馏进行训练,且没有预训练阶段;以及KD,一个三层BERT模型,通过单教师蒸馏进行训练,目标是从教师模型的平均得分中学习。MKD在大多数任务中优于KD,表明多教师蒸馏方法可以帮助学生模型学习到更多的通用知识,融合来自不同教师的知识。
最后,作者对TKD、MKD和TMKD进行了比较。如图6-9所示,TMKD在所有数据集上显著优于TKD和MKD,这验证了两个阶段——蒸馏预训练和多教师微调——的互补性影响。
通过蒸馏EfficientNets来增加鲁棒性
在另一个例子中,谷歌大脑和卡内基梅隆大学的研究人员采用了一种名为“noisy student”的半监督学习方法来训练模型。在这种方法中,知识蒸馏过程是迭代的。它使用了经典的教师-学生范式的变体,但在这里,学生模型在参数数量上故意比教师模型大。这样做是为了让模型能够提高对噪声标签的鲁棒性,而不是采用传统的知识蒸馏模式。
该方法的工作原理是,首先使用标记图像训练一个EfficientNet作为教师模型,然后利用教师模型生成伪标签,应用于更多的未标记图像。随后,他们使用标记图像和伪标签图像训练一个更大的EfficientNet模型作为学生模型,并多次重复这个过程;学生模型被提升为教师角色,以重新标记未标记数据并训练新的学生模型。该方法的一个重要元素是,在学生模型的训练过程中,确保使用dropout、随机深度(stochastic depth)和通过RandAugment进行的数据增强来向模型中添加噪声。这种噪声使得学生模型在学习伪标签时更加困难。向学生模型添加噪声确保了任务对于学生来说更加困难(因此命名为“noisy student”),并且模型不会仅仅学习教师模型的知识。值得注意的是,在生成伪标签时,教师模型不会被加噪,以确保其准确性不受任何改变。
整个循环通过用优化后的学生网络替换教师模型来结束。
为了比较noisy student训练的结果,作者使用了EfficientNets作为基线模型。图6-10显示了不同大小的EfficientNet模型以及一些著名的最先进模型作为对比。请注意,标记为NoisyStudentEfficientNet-B7的结果。一个关键因素是数据集在不同类别之间是平衡的,这提高了训练效果,特别是对于较小的模型。这些结果表明,知识蒸馏不仅仅限于创建像DistilBERT这样的小型模型,还可以通过noisy student训练来增强一个已经非常优秀的模型的鲁棒性。
正如我们在本讨论中所看到的,知识蒸馏是一种可以用来提高模型效率的重要技术。教师-学生方法是使用蒸馏的最常见方式,我们通过一些示例了解了如何通过这种方式提高模型效率。
总结
模型所需的计算、存储和I/O系统将决定将模型投入生产并在其整个生命周期内维护的成本。本章讨论了一些重要的技术,帮助我们管理模型的资源需求,包括减少数据集的维度、量化和剪枝模型以及使用知识蒸馏训练一个较小的模型,该模型捕获了较大模型中的知识。
我们在本章中讨论的方法专门针对机器学习,但我们也应该记住,改善效率和降低任何生产软件部署成本的方式有很多。这些包括为生产系统的各个组件编写和部署更高效、可扩展的代码,以及实现更高效的基础设施和扩展设计。由于本书主要集中在机器学习,而不是软件或系统工程,因此我们在此不会讨论这些内容,但这并不意味着你应该忽视它们。始终记住,生产机器学习系统仍然是一个生产软件和硬件系统,因此这些学科中的所有知识仍然适用。