🔎大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎
📝个人主页-Sonhhxg_柒的博客_CSDN博客 📃
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
📣系列专栏 - 机器学习【ML】 自然语言处理【NLP】 深度学习【DL】
🖍foreword
✔说明⇢本人讲解主要包括Python、机器学习(ML)、深度学习(DL)、自然语言处理(NLP)等内容。
如果你对这个系列感兴趣的话,可以关注订阅哟👋
文章目录
介绍
问题定义
银行业的深度学习
探索数据集
数据准备
建立模型
用于分类任务的人工神经网络
一个好的架构
PyTorch 自定义模块
练习 3.01:使用自定义模块定义模型的架构
定义损失函数和训练模型
活动 3.01:构建人工神经网络
处理欠拟合或过拟合模型
错误分析
练习 3.02:进行误差分析
活动三.02:提高模型的性能
部署您的模型
保存和加载模型
用于 C++ 生产的 PyTorch
构建 API
练习 3.03:创建 Web API
活动3.03:利用你的模型
概括
在本章中,我们将通过银行业中的一个真实示例来解决分类数据问题。您将学习如何使用 PyTorch 的自定义模块来定义网络架构和训练模型。您还将探索错误分析的概念,以提高模型的性能。最后,您将研究部署模型的不同方法,以便将来使用它。到本章结束时,您将对这个过程有一个深刻的理解,这样您就可以使用PyTorch 中的深度神经网络( DNN )开发端到端的分类数据问题解决方案。
介绍
在上一章中,我们了解了 DNN 的构建块并回顾了三种最常见架构的特征。此外,我们还学习了如何使用 DNN 解决回归问题。
在本章中,我们将使用 DNN 来解决分类任务,其目标是从一系列选项中预测结果。
使用此类模型的领域之一是银行业。这主要是因为他们需要根据人口统计数据预测未来的行为,以及确保长期盈利能力的主要目标。银行业的一些用途包括评估贷款申请、信用卡批准、股票市场价格预测以及通过分析行为检测欺诈。
本章将重点介绍使用深度人工神经网络( ANN ) 解决分类银行问题,遵循获得有效模型所需的所有步骤:数据探索、数据准备、架构定义和模型训练、模型微调、误差分析,最后部署最终模型。
问题定义
定义问题与构建模型或提高准确性同样重要。这是因为,虽然您可以使用最强大的算法并使用最先进的方法来改进其结果,但如果您解决了错误的问题或使用了错误的数据,这可能毫无意义。
学习如何深入思考以了解可以做什么和不能做什么,以及如何完成可以完成的事情,这一点至关重要。考虑到当我们学习应用机器学习或深度学习算法时,大多数课程中出现的问题总是定义明确,除了训练模型和提高其性能外不需要进一步分析,这一点尤为重要。另一方面,在现实生活中,问题往往扑朔迷离,数据往往杂乱无章。
在本节中,您将了解一些根据组织需求和手头数据定义问题的最佳实践。
为此,您需要遵循以下步骤:
- 了解问题的内容、原因和方式。
- 分析手头的数据以确定我们模型的一些关键参数,例如要执行的学习任务的类型、必要的准备工作以及性能指标的定义。
- 执行数据准备以降低将偏差引入模型的可能性。
银行业的深度学习
银行和金融实体每天处理大量信息,这些信息是必需的,这样他们才能做出重要决策,这些决策不仅会影响他们自己组织的未来,也会影响数百万信任他们的人的未来。
这些决策每秒都会做出,早在 1990 年代,银行业的人们过去常常依靠专家系统来编写基于规则的程序;也就是说,程序根据人类专家的知识来制定一套要遵循的规则。毫不奇怪,此类程序存在不足,因为它们需要预先对所有信息或可能的场景进行编程,这使得它们在处理不确定性和高度变化的市场时效率低下。
随着技术的改进,银行业一直在引领向更专业的系统过渡,这些系统利用统计模型来帮助做出此类决策。此外,由于银行需要同时考虑自身和客户的盈利能力,因此在不断跟上技术改进的众多行业中,它们被认为是值得注意的。
如今,随着医疗保健市场的发展,银行业和金融业正在推动神经网络市场的发展。这主要是由于神经网络通过使用大量先前数据来预测未来行为来处理不确定性的能力。考虑到人脑无法分析如此大量的数据,这是基于人类专家知识的系统无法实现的。
此处简要介绍和解释了银行和金融服务中使用深度学习的一些领域:
- 贷款申请评估:银行根据不同因素向客户发放贷款,包括人口统计信息、信用记录等。他们在此过程中的主要目标是最大限度地减少将拖欠贷款的客户数量(将失败率降至最低),从而最大限度地提高通过已发放贷款获得的回报。
神经网络用于帮助做出是否授予贷款的决定。他们通常使用以前未能偿还贷款的贷款申请人以及按时支付贷款的贷款申请人的数据进行培训。创建模型后,想法是将新申请人的数据输入模型,以便预测他们是否会偿还贷款,考虑到模型的重点应该是减少错误的数量正数(模型预测的客户会拖欠贷款,但实际上并没有)。
业内众所周知,神经网络的故障率低于依赖人类专业知识的传统方法。
- 欺诈检测:欺诈检测对于银行和金融提供商至关重要,考虑到技术的进步,尽管这些技术使我们的生活更轻松,但也让我们面临更大的金融风险。
该领域使用神经网络,特别是 CNN,进行字符和图像识别,以检测字符图像中隐藏和抽象的模式,以确定用户是否受到欺诈。
- 信用卡客户选择:为了长期保持盈利,信用卡提供商需要找到合适的客户。例如,向信用卡需求有限的客户(即不会使用它的客户)批准信用卡将导致信用卡收入较低。
另一方面,信用卡发行商也有兴趣预测客户是否会在下一次付款时违约。这将有助于发卡机构提前了解将被违约的资金数量,以便他们为保持盈利做好准备。
使用持有一张或多张信用卡的客户的历史数据对网络进行训练。目标是创建能够确定新客户是否会充分使用信用卡的模型,以便收入将取代成本,以及能够预测支付行为的模型。
笔记
本章的其余部分将重点解决与信用卡使用有关的数据问题。要下载将要使用的数据集,请转到UCI Machine Learning Repository: default of credit card clients Data Set,单击数据文件夹链接,然后下载.xls文件. 该数据集也可在本书的 GitHub 存储库中找到,网址为GitHub - PacktWorkshops/The-Deep-Learning-with-PyTorch-Workshop。
探索数据集
在接下来的部分中,我们将专注于使用信用卡客户违约( DCCC ) 数据集解决与信用卡支付相关的分类任务,该数据集之前是从 UC Irvine Repository 站点下载的。
本节背后的主要思想是清楚地说明数据问题的内容、原因和方式,这将有助于确定研究目的和评估指标。此外,我们将详细分析手头的数据,以确定数据准备过程中所需的一些步骤(例如,将定性特征转换为数字表示)。
首先,让我们定义是什么、为什么以及如何。考虑到应该这样做以确定组织的真正需求:
内容:建立一个能够确定客户是否会拖欠即将到来的付款的模型。
原因:为了能够预测下个月收到的付款金额(货币)。这将帮助公司确定当月的支出策略,并允许他们定义要对每个客户执行的操作,以确保未来支付账单的人能够支付账单,并提高那些将支付账单的客户的付款概率。默认。
方法:使用包含人口统计信息、信用记录和之前拖欠和未拖欠付款的客户的账单报表的历史数据来训练模型。在对输入数据进行训练后,该模型应该能够确定客户是否可能拖欠下一笔付款。
考虑到这一点,目标特征似乎应该是一个说明客户是否会在下一次付款时违约的特征,这需要一个二元结果(是/否)。这意味着要开发的学习任务是分类任务,因此损失函数应该是能够测量此类学习差异的函数(例如,交叉熵函数,如前一章所述) .
明确定义问题后,您需要确定最终模型的优先级。这意味着确定所有输出类是否同等重要。例如,一个测量肺部肿块是否恶性的模型应该主要关注最小化假阴性(模型预测没有恶性肿块的患者,但肿块实际上是恶性的),而建立用于识别手写字符的模型不应该专注于一个特定的角色,而是最大化其在平等识别所有角色方面的表现。
考虑到这一点,以及为什么声明中的解释,信用卡客户违约数据集模型的优先级应该是最大化模型的整体性能,而不优先考虑任何类标签。这主要是因为为什么声明声明研究的主要目的应该是更好地了解银行将收到的钱,以及对可能拖欠付款的客户采取某些行动(例如例如,提出将债务分成较小的付款),以及对那些不会违约的人采取不同的行动(例如,提供福利作为对行为良好客户的奖励)。
据此,本案例研究中使用的性能指标是准确性,其重点是最大化正确分类的实例。这是指任何类别标签的正确分类实例与实例总数的比率。
下表包含对数据集中存在的每个特征的简要说明,这有助于确定它们与研究目的的相关性,以及确定需要执行的一些准备任务:
图 3.1:DCCC 数据集特征的描述
图 3.2:DCCC 数据集特征的描述(续)
考虑到这些信息,可以得出结论,在 25 个特征(包括目标特征)中,有两个需要从数据集中删除,因为它们被认为与研究目的无关。请记住,与本研究无关的特征可能与其他研究相关。例如,一项关于私密卫生产品主题的研究可能会将性别特征视为相关。
而且,所有的特征都是定量的,这意味着它们的值不需要转换;我们需要做的就是重新缩放它们。目标特征也被转换成它的数字表示,其中下一次付款拖欠的客户用 1 表示,而没有拖欠付款的客户用 0 表示。
数据准备
尽管在这方面有一些好的做法,但没有一套固定的步骤可以用来准备(预处理)您的数据集以开发深度学习解决方案,而且大多数时候,要采取的步骤取决于手头的数据、要使用的算法以及研究的其他特征。
笔记
本节将介绍准备 DCCC 数据集的过程,并附有简要说明。随意打开 Jupyter Notebook 并复制此过程,考虑到这将是后续活动的起点。
尽管如此,在开始训练模型之前,必须处理一些关键方面。其中大部分你已经从上一章中了解到,它们将应用于当前数据集,并增加了目标特征中类不平衡的修正:
- 看一下数据:使用Pandas读取数据集后,打印数据集的头部。这有助于确保加载了正确的数据集。此外,它还用于提供准备后转换数据集的证据。
笔记
为了能够使用 Pandas 读取 Excel 文件,请确保您已在计算机或虚拟环境中安装xlrd。要安装xlrd,您需要在 Anaconda 提示符下运行conda install -c anaconda xlrd。
以下是用于使用pandas读取 Excel 文件并打印出数据集头部的片段:
import pandas as pd data = pd.read_excel("default of credit card clients.xls", \ skiprows=1) data.head()
我们使用skiprows参数删除 Excel 文件的第一行,这是不相关的,因为它包含第二组标题。
执行代码,得到如下结果:
图 3.3:DCCC 数据集的头部
数据集的形状是30000行25列,可以使用下面一行代码得到:
print("rows:",data.shape[0]," columns:", data.shape[1])
- 删除不相关的特征:通过对每个特征进行分析,可以确定应从数据集中删除其中两个特征,因为它们与研究目的无关:
data_clean = data.drop(columns=["ID", "SEX"]) data_clean.head()
生成的数据集应包含 23 列而不是原始的 25 列,如以下屏幕截图所示:
图 3.4:去除无关特征后的 DCCC 数据集头部
- 检查缺失值:接下来,是时候检查数据集是否缺失任何值,如果是,则计算它们代表每个特征的百分比,这可以使用以下代码行完成:
total = data_clean.isnull().sum() percent = (data_clean.isnull().sum()\ /data_clean.isnull().count()*100) pd.concat([total, percent], axis=1, \ keys=['Total', 'Percent']).transpose()
第一行对数据集的每个特征执行缺失值求和。接下来,我们计算每个特征缺失值的参与度。最后,我们连接之前计算的两个值,在表格中显示结果。结果如下:
图 3.5:DCCC 数据集中缺失值的计数
根据这些结果,可以说数据集没有丢失任何值,因此这里不需要进一步操作。
- 检查异常值:正如我们在第 2 章神经网络的构建块中提到的,有几种方法可以检查异常值。然而,在本书中,我们将坚持使用标准差方法,其中与平均值相差三个标准差的值将被视为异常值。使用以下代码,可以从每个特征中识别异常值并计算它们代表整个值集的比例:
outliers = {} for i in range(data_clean.shape[1]): min_t = data_clean[data_clean.columns[i]].mean() \ - (3 * data_clean[data_clean.columns[i]].std()) max_t = data_clean[data_clean.columns[i]].mean() \ + (3 * data_clean[data_clean.columns[i]].std()) count = 0 for j in data_clean[data_clean.columns[i]]: if j < min_t or j > max_t: count += 1 percentage = count/data_clean.shape[0] outliers[data_clean.columns[i]] = "%.3f" % percentage print(outliers)
这会生成一个包含每个特征名称作为键的字典,其值表示该特征的异常值比例。从这些结果中,可以观察到包含更多异常值的特征是BILL_AMT1和BILL_AMT4,每个特征的参与度占总实例的 2.3%。
这意味着不需要采取进一步的行动,因为异常值对每个特征的参与度太低,因此它们不太可能对最终模型产生影响。
- Check for class imbalance:当目标特征中的类标签没有被平等地表示时,就会发生类不平衡;例如,一个数据集包含 90% 的客户在下次付款时没有违约,而 10% 的客户违约,这被认为是不平衡的。
有几种方法可以处理类不平衡,这里解释了其中的一些:
收集更多数据:虽然这并不总是一条可用的路线,但它可能有助于平衡类别或允许删除过多的类别,而不会严重减少数据集。
改变性能指标:一些指标,如准确性,不利于衡量不平衡数据集的性能。反过来,建议使用分类问题的精度或召回率等指标来衡量性能。
重新采样数据集:这需要修改数据集以平衡类。这可以通过两种不同的方式完成:在代表性不足的类中添加实例副本(称为过采样)或删除过度代表性类的实例(称为欠采样)。
可以通过简单地计算目标特征中每个类的出现次数来检测类不平衡,如下所示:
target = data_clean["default payment next month"] yes = target[target == 1].count() no = target[target == 0].count() print("yes %: " + str(yes/len(target)*100) + " - no %: " \ + str(no/len(target)*100))
从前面的代码中,可以得出拖欠付款的客户数量占数据集的 22.12% 的结论。这些结果也可以使用以下代码行显示在图中:
import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(10,5)) plt.bar("yes", yes) plt.bar("no", no) ax.set_yticks([yes,no]) plt.xticks(fontsize=15) plt.yticks(fontsize=15) plt.show()
这导致下图:
图 3.6:目标特征的类数
为了解决这个问题,并且鉴于没有更多的数据要添加,性能指标实际上是准确性,因此有必要进行数据重采样。
以下是对数据集执行过采样的代码片段,随机创建代表性不足的类的重复行:
data_yes = data_clean[data_clean["default payment next month"] == 1]
data_no = data_clean[data_clean["default payment next month"] == 0]
over_sampling = data_yes.sample(no, replace=True, random_state = 0)
data_resampled = pd.concat([data_no, over_sampling], axis=0)
首先,我们将每个类标签的数据分离到独立的 DataFrame 中。接下来,我们使用 Pandas 的sample()函数构建一个新的 DataFrame,其中包含与代表过多的类的 DataFrame 一样多的代表不足类的重复实例。
笔记
请记住,sample()函数的第一个参数 ( no ) 指的是先前计算的过度代表类中的项目数。
最后,使用concat()函数将过度表示类的 DataFrame 与新创建的相同大小的 DataFrame 拼接起来,以创建最终的数据集以供后续步骤使用。
使用新创建的数据集,可以再次计算每个类标签在整个数据集中的目标特征的参与度,现在应该反映出具有相同参与度的两个类标签具有相同代表性的数据集。此时,数据集的最终形状应等于 (46728, 23)。
- 从目标中拆分特征:我们将数据集拆分为特征矩阵和目标矩阵,以避免重新缩放目标值:
data_resampled = data_resampled.reset_index(drop=True) X = data_resampled.drop(columns=["default payment next month"]) y = data_resampled ["default payment next month"]
- 重新缩放数据:最后,我们重新缩放特征矩阵的值以避免给模型引入偏差:
X = (X - X.min())/(X.max() - X.min()) X.head()
前面几行代码的结果如下:
图 3.7:归一化后的特征矩阵
笔记
考虑到婚姻和教育都是顺序特征,这意味着它们遵循顺序或等级;选择重新缩放方法时,请确保保持顺序。
为了便于为即将到来的活动使用准备好的数据集,特征 ( X ) 和目标 ( y ) 矩阵将连接到一个 Pandas DataFrame 中,并使用以下代码将其保存到 CSV 文件中:
final_data = pd.concat([X, y], axis=1)
final_data.to_csv("dccc_prepared.csv", index=False)
执行上述步骤后,DCCC 数据集已转换并准备好(在新的 CSV 文件中)用于训练模型,这将在下一节中进行说明。
建立模型
一旦定义了问题并且探索和准备了手头的数据,就该定义模型了。网络的架构定义、层的类型、损失函数等应该在前面的分析之后处理。这主要是因为机器学习没有“一刀切”的方法,深度学习更没有。
回归任务需要与分类任务不同的方法,聚类、计算机视觉和机器翻译也是如此。在下一节中,您将了解构建用于解决分类任务的模型的关键特征,以及如何获得“良好”架构的解释,以及如何以及何时在 PyTorch 中使用自定义模块.
用于分类任务的人工神经网络
正如第 2 章神经网络构建块中的活动 2.02 “为回归问题开发深度学习解决方案”中所见,为回归任务构建的神经网络使用输出作为连续值,这就是为什么输出层没有激活函数,并且只有一个输出节点(实际值),例如根据房屋和社区的特征预测房价的模型。
鉴于此,要衡量与此类模型相关的性能,您应该计算 ground truth 与预测值之间的差异,即,例如计算 125.3(预测)和 126.38(ground truth)之间的距离. 正如我们之前提到的,有很多方法可以衡量这种差异,均方误差( MSE ) 或其他变体均方根误差( RMSE ) 是最常用的指标。
与此相反,分类任务的输出是属于每个输出标签或类的一组特定输入特征的概率,这是使用 sigmoid(用于二元分类)或 softmax(用于多类分类)完成的)激活函数。对于二元分类任务,输出层应包含一个(对于 sigmoid)或两个(对于 softmax)输出节点,而对于多类分类任务,输出层应等于类标签的数量。
这种计算属于每个输出类的输入特征的可能性的能力,再加上argmax函数,将检索具有更高概率的类作为最终预测。
笔记
Python 中的argmax函数是一个能够返回沿轴的最大值索引的函数。
考虑到这一点,模型的性能应该取决于实例是否已被分类到正确的类标签,而不是与测量两个值之间的距离有关——因此使用不同的损失函数(交叉熵是最常用的)用于训练分类问题的神经网络,以及使用不同的性能指标,例如准确度、精确度和召回率。
一个好的架构
正如本章所解释的那样,了解手头的数据问题对于确定神经网络的一般拓扑结构非常重要。同样,常规分类问题不需要计算机视觉所需的相同网络架构。
一旦修改和准备好数据,考虑到在确定隐藏层的数量或每层中的单元数量方面没有正确答案,最好的方法是从初始架构开始(可以改进以提高性能)。
这一点很重要,因为有大量参数需要调整,有时很难做出承诺并开始开发解决方案。但是,考虑到这一点,在训练神经网络时,一旦训练和测试了初始架构,就有多种方法可以确定需要改进的地方。事实上,将数据集划分为三个子集的全部原因是允许使用一组训练数据集,使用另一组测量和微调模型,最后使用以前没有使用过的最终子集。
考虑到所有这些,将解释以下一组约定和经验法则,以帮助定义 ANN 初始架构的决策过程:
- 输入层:这很简单;只有一个输入层,其单元数取决于训练数据的形状。具体来说,输入层中的单元数应等于输入数据包含的特征数。
- 隐藏层:隐藏层的数量可能会有所不同。ANN 可以有一个隐藏层、多个隐藏层或没有隐藏层。要选择正确的号码,请务必考虑以下因素:
数据问题越简单,所需的隐藏层就越少。请记住,线性可分的简单数据问题应该只有一个隐藏层。另一方面,更复杂的数据问题可以而且应该使用许多隐藏层来解决(但不限于)。
隐藏单元的数量应介于输入层单元数和输出层单元数之间。
- 输出层:同样,任何 ANN 只有一个输出层。它包含的单元数量取决于要开发的学习任务以及数据问题。对于回归任务,只有一个单元,即预测值。然而,对于分类问题,考虑到模型的输出应该是属于每个类标签的一组特征的概率,单元的数量应该等于可用的类标签的数量。
- 其他参数:其他参数应保留其默认值,以便首次配置网络。这主要是因为在考虑可能表现相同或更差但需要更多资源的更复杂的近似值之前,先针对数据问题测试最简单的模型始终是一种很好的做法。
一旦定义了初始架构,就可以训练和测量模型的性能以进行进一步的分析,这很可能会导致网络架构或其他参数值的变化,例如变化在学习率或增加正则化项。
PyTorch 自定义模块
自定义模块由 PyTorch 的开发团队创建,作为一种为用户提供更多灵活性的方式。与我们在前几章中探讨的顺序容器相反,只要希望构建更复杂的模型架构,或者只要您希望进一步控制每一层中发生的计算,就应该使用自定义模块。
这并不意味着自定义模块方法只能用于此类场景。相反,一旦您学会了使用这两种方法,在选择哪一种(Sequential容器或自定义模块)用于不太复杂的数据问题时就是一个偏好问题。
例如,使用Sequential容器定义的两层神经网络的以下代码片段:
import torch
import torch.nn as nn
model = nn.Sequential(nn.Linear(D_i, D_h), \
nn.ReLU(), \
nn.Linear(D_h, D_o), \
nn.Softmax())
这里,D_i是指输入维度(输入数据中的特征),D_h是指隐藏维度(隐藏层中的节点数),D_o是指输出维度。
使用自定义模块,可以构建等效的网络架构,如下所示:
import torch
import torch.nn as nn
import torch.nn.functional as F
class Classifier(torch.nn.Module):
def __init__(self, D_i, D_h, D_o):
super(Classifier, self).__init__()
self.linear1 = torch.nn.Linear(D_i, D_h)
self.linear2 = torch.nn.Linear(D_h, D_o)
def forward(self, x):
z = F.relu(self.linear1(x))
o = F.softmax(self.linear2(z))
return o
可以看出,类的初始化方法内部定义了一个输入层和一个输出层。接下来,定义了执行计算的附加方法。
笔记
对于本章中的练习和活动,您需要安装 Python 3.7、Jupyter 6.0、Matplotlib 3.1、PyTorch 1.3、NumPy 1.17、scikit-learn 0.21、Pandas 0.25 和 Flask 1.1。
练习 3.01:使用自定义模块定义模型的架构
使用前面解释的理论,我们将使用自定义模块的语法定义模型的架构:
- 打开 Jupyter Notebook 并导入所需的库:
import torch import torch.nn as nn import torch.nn.functional as F
- 为输入、隐藏和输出维度定义必要的变量。分别将它们设置为10、5和2:
D_i = 10 D_h = 5 D_o = 2
- 使用 PyTorch 的自定义模块,创建一个名为Classifier的类并定义模型的架构,使其具有两个线性层——第一个层后跟ReLU激活函数,第二个层后跟Softmax激活函数:
class Classifier(torch.nn.Module): def __init__(self, D_i, D_h, D_o): super(Classifier, self).__init__() self.linear1 = torch.nn.Linear(D_i, D_h) self.linear2 = torch.nn.Linear(D_h, D_o) def forward(self, x): z = F.relu(self.linear1(x)) o = F.softmax(self.linear2(z)) return o
- 实例化该类并为其提供我们在步骤 2中创建的三个变量。打印模型:
model = Classifier(D_i, D_h, D_o) print(model)
打印语句的输出应如下所示:
Classifier( (linear1): Linear(in_features=10, out_features=5, bias=True) (linear2): Linear(in_features=5, out_features=2, bias=True) )
这样,您就成功地使用 PyTorch 的自定义模块构建了一个神经网络架构。现在,您可以继续了解训练深度学习模型的过程。
定义损失函数和训练模型
值得一提的是,交叉熵损失函数要求网络的输出是原始的(在通过使用softmax激活函数获得概率之前),这就是为什么通常会找到用于分类问题的神经网络架构的原因没有输出层的激活函数。此外,为了通过这种方法进行预测,有必要在训练模型后将softmax激活函数应用于网络的输出。
另一种处理方法是对输出层使用log_softmax激活函数。这样,损失函数可以定义为负对数似然损失 ( nn.NLLLoss )。最后,可以通过从网络输出中获取指数来获得属于每个类标签的一组特征的概率。这是将在本章的活动中使用的方法。
一旦定义了模型架构,下一步就是编写负责在训练数据上训练模型的部分,以及测量其在训练集和验证集上的性能。
遵循我们讨论的这些分步说明的代码如下:
model = Classifier()
criterion = nn.NLLLoss()
optimizer = optim.Adam(model.parameters(), lr=0.005)
epochs = 10
batch_size = 100
从前面的代码片段中可以看出,第一步是定义在训练网络时将使用的所有变量。
接下来,第一个for循环用于遍历我们之前定义的时期数。
请记住,纪元指的是整个数据集通过网络架构向前和向后传递的次数。batch_size是指单个批次(数据集的一部分)中训练示例的数量。最后,迭代次数是指完成一个 epoch 所需的批次数。
第二个for循环用于遍历整个数据集的每个批次,直到完成一个纪元。在此循环内,将进行以下计算:
- 该模型在一批训练集上进行训练。这里得到一个预测。
- 损失是通过比较上一步的预测和训练集的标签(ground truth)来计算的。
- 梯度设置为零并为当前步骤再次计算。
- 网络的参数根据梯度进行更新。
- 模型在训练数据上的准确度计算如下:
获取模型预测的指数,以获得属于每个类标签的给定数据片段的概率。
使用topk()方法获取概率较高的类标签。
使用 scikit-learn 的度量部分,计算准确度、精确度或召回率。您还可以探索其他性能指标。
一旦所有批次的训练数据都被输入到模型中,梯度的计算就会被关闭,以验证当前模型在验证数据上的性能,其发生如下:
- 该模型对验证集中的数据执行预测。
- 损失函数是通过将先前的预测与验证集中的标签进行比较来计算的。
- 准确性是在验证集上计算的。要计算模型在验证集上的准确性,请使用您对训练数据进行相同计算所执行的相同步骤集:
笔记
以下代码片段不会自行运行。您将需要加载一个数据集并将其分成不同的集合,并定义和实例化一个网络架构。还需要定义损失函数和优化算法(在本章前面的部分中进行了解释)。
train_losses,dev_losses,train_acc,dev_acc= [], [], [], [] for e in range(epochs): X, y = shuffle(X_train, y_train) running_loss = 0 running_acc = 0 iterations = 0 for i in range(0, len(X), batch_size): iterations += 1 b = i + batch_size X_batch = torch.tensor(X.iloc[i:b,:].values).float() y_batch = torch.tensor(y.iloc[i:b].values) pred = model(X_batch) loss = criterion(pred, y_batch) optimizer.zero_grad() loss.backward() optimizer.step() running_loss += loss.item() ps = torch.exp(pred) top_p, top_class = ps.topk(1, dim=1) running_acc += accuracy_score(y_batch, top_class) dev_loss = 0 acc = 0 with torch.no_grad(): pred_dev = model(X_dev_torch) dev_loss = criterion(pred_dev, y_dev_torch) ps_dev = torch.exp(pred_dev) top_p, top_class_dev = ps_dev.topk(1, dim=1) acc = accuracy_score(y_dev_torch, top_class_dev) train_losses.append(running_loss/iterations) dev_losses.append(dev_loss) train_acc.append(running_acc/iterations) dev_acc.append(acc) print("Epoch: {}/{}.. ".format(e+1, epochs), \ "Training Loss: {:.3f}.. "\ .format(running_loss/iterations),\ "Validation Loss: {:.3f}.. "\ .format(dev_loss),\ "Training Accuracy: {:.3f}.. "\ .format(running_acc/iterations),\ "Validation Accuracy: {:.3f}".format(acc))
前面的代码片段将打印两组数据的损失和准确性。在接下来的活动中,我们解释的关于构建和训练 DNN 的所有概念都将付诸实践。
活动 3.01:构建人工神经网络
对于此活动,我们将使用之前准备的数据集构建一个四层模型,该模型能够确定客户是否会拖欠下一笔付款。为此,我们将使用自定义模块的方法。
让我们看看以下场景:您在一家专门为世界各地的银行提供机器/深度学习解决方案的数据科学精品店工作。他们最近为一家银行承担了一个项目,该项目希望能够预测下个月将收到或不会收到的付款。探索性数据分析团队已经为你准备好了数据集,他们要求你建立模型并计算模型的准确率。按照以下步骤完成此活动:
- 导入以下库:
import pandas as pd import numpy as np from sklearn.model_selection import train_test_split from sklearn.utils import shuffle from sklearn.metrics import accuracy_score import torch from torch import nn, optim import torch.nn.functional as F import matplotlib.pyplot as plt
笔记
即使使用种子,考虑到训练集在每个 epoch 之前都经过洗牌,此活动的确切结果也将无法重现。
- 阅读之前准备好的数据集,它应该被命名为dccc_prepared.csv。
- 将特征与目标分开。
- 使用 scikit-learn 的train_test_split函数,将数据集拆分为训练集、验证集和测试集。使用 60:20:20 的分流比。将random_state设置为0。
- 将验证集和测试集转换为张量,考虑到特征矩阵应该是 float 类型,而目标矩阵不应该。暂时不要转换训练集,因为它们将进行进一步的转换。
- 构建用于定义网络层的自定义模块类。包括一个前向函数,指定将应用于每个层的输出的激活函数。对除输出之外的所有层使用ReLU,您应该在输出层使用log_softmax。
- 实例化模型并定义训练模型所需的所有变量。将纪元数设置为50,将批量大小设置为128。使用0.001的学习率 。
- 使用训练集的数据训练网络。使用验证集来衡量性能。为此,请保存每个时期中训练集和验证集的损失和准确性。
笔记
培训过程可能需要几分钟,具体取决于您的资源。如果您希望查看培训过程的进度,添加打印语句是一种很好的做法。
- 绘制两组的损失。
- 绘制两组的准确性。
最终情节将如下所示:
图 3.8:显示集合准确性的图表
笔记
可以通过此链接找到此活动的解决方案。
您现在已经成功编写并训练了一个四层神经网络,该网络能够根据历史数据进行推理。接下来,您将学习如何提高模型的性能,以便对看不见的数据进行可靠的推理。
处理欠拟合或过拟合模型
构建深度学习解决方案不仅仅是定义架构然后使用输入数据训练模型的问题;相反,大多数人会同意这是容易的部分。创建高科技模型的艺术需要达到超越人类表现的高精度。本节将介绍错误分析的主题,错误分析通常用于诊断经过训练的模型,以发现哪些动作更有可能对模型的性能产生积极影响。
错误分析
错误分析是指对训练和验证数据集的错误率进行初步分析。然后使用此分析来确定提高模型性能的最佳行动方案。
为了进行误差分析,有必要确定贝叶斯误差(也称为不可约误差),这是可实现的最小误差。几十年前,贝叶斯误差等同于人为误差,意味着设想的最低误差水平是专家可以达到的误差水平。
如今,随着技术和算法的改进,这个价值变得越来越难以估计,因为机器能够超越人类的表现;与人类相比,我们无法衡量他们能做得更好多少,因为我们只能根据我们的能力来理解。
为了执行错误分析,最初将贝叶斯错误设置为等于人为错误是很常见的。然而,这种限制并非一成不变,研究人员认为超越人类表现也应该是最终目标。
进行错误分析的过程如下:
- 计算选择的指标来衡量模型的性能。应在训练数据集和验证数据集上计算此度量。
- 使用此度量,通过从 1 中减去先前计算的性能指标来计算每个集合的错误率。例如,采用以下等式:
图 3.9:计算模型在训练集上的错误率的方程式
- 从训练集误差A)中减去贝叶斯误差。保存差异,将用于进一步分析。
- 从验证集误差B)中减去训练集误差,并保存差值。
- 取第 3 步和第 4 步中计算的差值并使用以下规则集:
如果在步骤 3中计算的差异高于在步骤 4中计算的差异,则模型欠拟合,也称为存在高偏差。
如果第4步计算的差值大于第3步计算的差值,则模型过拟合,也称为高方差,如下图所示:
图 3.10:显示如何执行错误分析的图表
这些规则并不表示该模型可能只会遇到刚才提到的问题之一(高偏差或高方差),而是通过错误分析检测到的问题对模型的性能有更大的影响,这意味着修复它会在更大程度上提高性能。
让我们解释一下如何处理这些问题:
- 高偏差:欠拟合模型或遭受高偏差的模型是无法理解训练数据的模型,因此,它无法发现模式并与其他数据集进行泛化。这意味着该模型在任何数据集上都表现不佳。
为了减少影响模型的高偏差,建议您定义更大/更深的网络(更多隐藏层)或训练更多迭代。通过添加更多层和增加训练时间,网络有更多资源来发现描述训练数据的模式。
- 高方差:过度拟合的模型或遭受高方差的模型是难以概括训练数据的模型;它太了解训练数据的细节(这意味着通过训练过程,模型太了解训练集中的信息,这意味着它无法泛化到其他数据集),包括它的异常值. 这意味着该模型在训练数据上表现太好,但在其他数据集上表现不佳。
这通常通过向训练集添加更多数据或向损失函数添加正则化项来处理。第一种方法旨在迫使网络对数据进行泛化,而不是理解少量示例的细节。另一方面,第二种方法对具有较高权重的输入进行惩罚,以忽略异常值并平等地考虑所有值。
鉴于此,处理一种正在影响模型的条件可能会导致另一种条件出现或增加。例如,一个遭受高偏差的模型在经过处理后,可能会提高其在训练数据上的性能,但不会提高验证数据的性能,这意味着该模型将开始遭受高方差的影响,并且需要另一组补救措施要采取。
一旦模型被诊断出来并采取了必要的措施来提高性能,就应该选择最好的模型进行最终测试。这些模型中的每一个都应该用于对测试集(唯一对构建模型没有影响的集)执行预测。
考虑到这一点,可以选择最终模型作为对测试数据表现最佳的模型。这主要是因为测试数据的性能可以作为模型在未来看不见的数据集上的性能指标,这是最终目标。
练习 3.02:进行误差分析
使用我们在上一个活动中计算的准确性指标,在本活动中,我们将执行错误分析,这将帮助我们确定要在即将进行的活动中对模型执行的操作。请按照以下步骤完成此练习:
笔记
此练习不需要完成任何编码,而是需要对先前活动的结果进行分析。
- 假设贝叶斯误差为0.15,执行误差分析并对模型进行诊断:
Bayes error (BE) = 0.15 Training set error (TSE) = 1 – 0.716 = 0.284 Validation set error (VSE) = 1 – 0.71 = 0.29
用作两组精度的值(0.716和0.71 )是在活动 3.01构建 ANN的最后一次迭代期间获得的值:
High bias = TSE – BE = 0.134 High variance = VSE – TSE = 0.014
据此,该模型存在高偏差,这意味着该模型拟合不足。
- 确定提高模型准确性所需的操作。
为了提高模型的性能,可以遵循的两个行动方案是增加 epoch 的数量和增加隐藏层的数量和/或单元的数量(每层中的神经元)。
据此,可以执行一组测试以达到最佳结果。
这样,您就成功地进行了错误分析。这种方法是开发最先进的深度学习解决方案的关键,这些解决方案在未见过的数据上表现出色。
活动三.02:提高模型的性能
对于此活动,我们将实施我们在练习中定义的操作,以减少影响模型性能的高偏差。考虑以下场景:您的团队成员对您交付的工作和代码的组织方式印象深刻,但他们要求您尝试将性能提高到 80%,考虑到这是他们向客户承诺的。按照以下步骤完成此活动:
笔记
为此活动使用不同的 Jupyter Notebook。在那里,您将再次加载数据集并执行与上一个活动中类似的步骤,不同之处在于训练过程将进行多次以训练不同的架构和训练时间。
- 导入与上一个活动相同的库。
- 加载数据并从目标中拆分特征。接下来,使用 60:20:20 的拆分比将数据拆分为三个子集(训练、验证和测试)。最后,将验证集和测试集转换为 PyTorch 张量,就像您在上一个活动中所做的那样。
- 考虑到模型存在高偏差,重点应该放在增加 epoch 的数量或通过向每一层添加额外的层或单元来增加网络的大小。目标应该是使测试集的准确率接近 80%。
笔记
没有正确的方法来选择先进行哪个测试,所以要有创造性和分析性。如果模型架构中的变化减少或消除了高偏差但引入了高方差,那么请考虑,例如,保留更改但添加措施来对抗高方差。
- 绘制两组数据的损失和准确性。
- 使用性能最佳的模型,对测试集进行预测(在微调过程中不应使用)。通过计算模型在此集合上的准确性,将预测与真实情况进行比较。
预期输出:通过模型架构和此处定义的参数获得的准确度应在 80% 左右。
笔记
可以通过此链接找到此活动的解决方案。
这样,您就成功地使用错误分析改进了模型的性能。接下来,您将学习如何部署模型以便在生产环境中使用它。
部署您的模型
到目前为止,您已经学习并实践了为常规回归和分类问题构建卓越深度学习模型的关键概念和技巧。在现实生活中,模型不仅仅是为了学习目的而建立的。相反,当为研究以外的目的训练模型时,主要思想是能够在未来重用它们来对新数据进行预测,尽管模型没有被训练,但模型应该表现相似。
在小型组织中,序列化和反序列化模型的能力就足够了。然而,当模型将被大公司、用户使用,或改变一个非常重要的大型任务时,更好的做法是将模型转换为可在大多数生产环境中使用的格式(例如 API、网站、在线和离线应用程序)。
在本节中,我们将学习如何保存和加载模型,以及如何使用 PyTorch 的最新功能将我们的模型转换为高度通用的 C++ 应用程序。我们还将学习如何创建 API 以使用经过训练的模型。
保存和加载模型
正如您可能想象的那样,每次使用模型时都重新训练它是非常不切实际的,尤其是考虑到大多数深度学习模型可能需要相当长的时间来训练(取决于您的资源)。
相反,可以训练、保存和重新加载 PyTorch 中的模型,以执行进一步的训练或进行推理。考虑到将 PyTorch 模型中每一层的参数(权重和偏差)保存到state_dict字典中,可以实现这一点。
此处提供了有关如何保存和加载经过训练的模型的分步指南:
- 最初,模型的检查点将仅包含模型的参数。但是,在加载模型时,这不是唯一需要的信息。根据分类器接受的参数(即包含网络架构的类),可能需要保存更多信息,例如输入单元的数量。考虑到这一点,第一步是定义要保存的信息:
checkpoint = {"input": X_train.shape[1], \ "state_dict": model.state_dict()}
这会将输入层中的单元数保存到检查点中,这将在加载模型时派上用场。
- 使用 PyTorch 的save()函数保存模型:
torch.save(checkpoint, "checkpoint.pth")
第一个参数是指我们之前创建的字典,而第二个参数是要使用的文件名。
- 使用您选择的文本编辑器,创建一个导入 PyTorch 库并包含创建模型网络架构的类的 Python 文件。这样做是为了方便您将模型加载到一个新的工作表中,与您用于训练模型的工作表分开。
- 为了加载模型,让我们创建一个函数来执行三个主要操作:
def load_model_checkpoint(path): checkpoint = torch.load(path) model = final_model.Classifier(checkpoint["input"], \ checkpoint["output"], \ checkpoint["hidden"]) model.load_state_dict(checkpoint["state_dict"]) return model model = load_model_checkpoint("checkpoint.pth")
此函数接收保存的模型文件(检查点)的路径作为输入。首先,加载检查点。接下来,使用保存在 Python 文件中的网络架构实例化模型。这里,final_model指的是 Python 文件的名称,它应该已经导入到新的工作表中,而Classifier()指的是保存在该文件中的类的名称。该模型将具有随机初始化的参数。最后,来自检查点的参数被加载到模型中。
调用时,此函数返回经过训练的模型,现在可用于进一步训练或执行推理。
用于 C++ 生产的 PyTorch
根据框架的名称,PyTorch 的主要接口是 Python 编程语言。这主要是由于许多用户偏爱这种编程语言,这要归功于该语言在开发机器学习解决方案时的活力和易用性。
然而,在某些情况下,Python 属性变得不利。这正是为生产开发的模型的情况,其他编程语言已被证明更有用。C++ 就是这种情况,它广泛用于机器/深度学习解决方案的生产目的。
鉴于此,PyTorch 最近提出了一种简单的方法来让用户享受两全其美的好处。虽然他们继续以 Pythonic 的方式进行编程,但现在可以将您的模型序列化为可以从 C++ 加载和执行的表示,而不依赖于 Python。这种表示称为 TorchScript。
将 PyTorch 模型转换为 TorchScript 是通过 PyTorch 的即时( JIT ) 编译器模块完成的。这是通过通过torch.jit.trace()函数传递模型和示例输入来实现的,如下所示:
traced_script = torch.jit.trace(model, example)
请记住,名为model的变量应包含先前训练的模型,而名为example的变量应包含您希望提供给模型以执行预测的一组特征。这将返回一个脚本模块,可以用作常规 PyTorch 模块,如下所示:
prediction = traced_script(input)
前面的代码将返回通过模型运行输入数据获得的输出。
构建 API
应用程序编程接口( API ) 由专门创建供其他程序使用的程序组成(与网站或界面相反,后者是为供人操作而创建的)。据此,在创建用于生产环境的深度学习解决方案时会使用 API,因为它们允许通过其他方式(例如网站)访问从运行模型(例如预测)中获得的信息。
在本节中,我们将探索 Web API(一种通过 Internet 与其他程序共享信息的 API)的创建。此 API 的功能是加载先前保存的模型并根据给定的一组特征进行预测。向 API 发出 HTTP 请求的程序可以访问此预测。
关键术语解释如下:
- 超文本传输协议( HTTP ):这是在 Web 上传输数据的主要方式。它使用方法工作,这有助于确定数据传输的方式。最常用的两种方法解释如下:
POST:此方法允许您在消息正文中将数据从客户端(Web 浏览器或向 API 发出请求的平台)发送到服务器(使用该信息运行的程序)。
GET:与POST方法相反,此方法将数据作为 URL 的一部分发送,这在发送大量数据时可能不方便。
- Flask:这是一个为 Python 开发的库,允许您创建 API(以及其他)。
要使用 Flask 创建简单的 Web API,请执行以下步骤:
- 导入必要的库:
import flask from flask import request import torch import final_model
- 初始化 Flask 应用程序:
app = flask.Flask(__name__) app.config["DEBUG"] = True
DEBUG配置在开发期间设置为True ,但在生产时应设置为False。
- 加载先前训练的模型:
def load_model_checkpoint(path): checkpoint = torch.load(path) model = final_model.Classifier(checkpoint["input"]) model.load_state_dict(checkpoint["state_dict"]) return model model = load_model_checkpoint("checkpoint.pth")
- 定义可访问 API 的路由,以及可用于向 API 发送信息以执行操作的方法。此语法称为装饰器,应紧接在函数之前:
@app.route('/prediction', methods=['POST'])
- 定义执行所需操作的函数。在这种情况下,该函数将获取发送到 API 的信息并将其提供给先前加载的模型以执行预测。获得预测后,该函数应返回一个响应,该响应将显示为 API 请求的结果:
def prediction(): body = request.get_json() example = torch.tensor(body['data']).float() pred = model(example) pred = torch.exp(pred) _, top_class_test = pred.topk(1, dim=1) top_class_test = top_class_test.numpy() return {"status":"ok", "result":int(top_class_test[0][0])}
- 运行 Flask 应用程序。以下命令可以开始使用 Web API:
app.run(debug=True, use_reloader=False)
同样,调试在开发期间设置为True。use_reloader参数设置为False以允许应用程序在 Jupyter Notebook 上运行。但是,不建议从 Jupyter Notebook 运行该应用程序;这只是为了教学目的。在现实生活中,use_reloader应设置为True,应用程序应通过命令提示符实例或终端作为 Python 文件运行。
练习 3.03:创建 Web API
使用 Flask,我们将创建一个 Web API,它会在调用时接收一些数据,并返回一段将在浏览器中显示的文本。请按照以下步骤完成此练习:
- 在 Jupyter Notebook 中,导入所需的库:
import flask from flask import request
- 初始化 Flask 应用程序:
app = flask.Flask(__name__) app.config["DEBUG"] = True
- 定义 API 的路由,使其成为/<name>。将方法设置为GET。接下来,定义一个函数,它接受一个参数 ( name ) 并返回一个字符串,该字符串包含一个带有单词HELLO的h1标记,后跟函数接收的参数:
@app.route('/<name>', methods=['GET']) def hello(name): return "<h1>HELLO {}</h1>".format(name.upper())
- 运行Flask应用程序:
app.run(debug=True, use_reloader=False)
前一行代码的输出如下所示:
图 3.11:执行代码后的警告
它包含几个警告,指定正在运行的 Flask 应用程序的条件,以及一行包含类似于此 URL 的文本:
http://127.0.0.1:5000/
- 将 URL 复制到浏览器中,然后是您的姓名,如下所示:
http://127.0.0.1:5000/your_name
按Enter 键,应会加载一个简单的网站,该网站应类似于以下内容:
图 3.12:向 API 执行请求的结果
这样,您就成功地创建了一个 Web API。通过允许模型与用户之间的轻松通信,这种能力将是您能够在生产环境中使用模型的关键。在下一个活动中,您将把您在本章中学到的部署模型的不同概念付诸实践。
活动3.03:利用你的模型
对于本活动,保存您在上一个活动中创建的模型。而且,保存的模型会加载到新的notebook中使用。接下来,我们会将模型转换为可在 C++ 上执行的序列化表示,并创建一个 Flask API。让我们看看以下场景:每个人都对您改进模型的承诺以及模型的最终版本非常满意,因此他们要求您保存模型并将其转换为可用于构建模型的格式为客户在线申请。按照以下步骤完成此活动:
笔记
此活动将使用三个 Jupyter 笔记本。首先,我们将使用与之前活动相同的笔记本来保存最终模型。接下来,我们将打开一个新笔记本,用于加载保存的模型。最后,第三个笔记本将用于创建 API。
- 打开您用于活动 3.02的 Jupyter Notebook ,提高模型的性能。
- 复制包含最佳性能模型架构的类并将其保存在 Python 文件中。确保导入 PyTorch 所需的库和模块。将其命名为final_model.py。
- 在 Jupyter Notebook 中,保存性能最好的模型。确保保存与输入单元有关的信息以及模型的参数。将其命名为checkpoint.pth。
- 打开一个新的 Jupyter Notebook。
- 导入 PyTorch,以及我们在步骤 2中创建的 Python 文件。
- 创建一个加载模型的函数。
- 通过将以下张量输入模型来执行预测:
torch.tensor([[0.0606, 0.5000, 0.3333, 0.4828, 0.4000, 0.4000, 0.4000, 0.4000, 0.4000, 0.4000, 0.1651, 0.0869, 0.0980, 0.1825, 0.1054, 0.2807, 0.0016, 0.0000, 0.0033, 0.0027, 0.0031, 0.0021]]).float()
- 使用 JIT 模块转换模型。
- 通过将步骤 7中的张量输入到模型的跟踪脚本中来执行预测。
- 打开一个新的 Jupyter Notebook 并导入使用 Flask 创建 API 所需的库,以及加载已保存模型的库。
- 初始化 Flask 应用程序。
- 定义一个函数来加载保存的模型并实例化模型。
- 定义 API 的路由,使其成为/prediction和方法,使其成为POST。然后,定义将接收POST数据并将其提供给模型以执行预测的函数。
- 运行 Flask 应用程序。
应用程序运行后将如下所示:
图 3.13:应用程序运行后的屏幕截图
笔记
可以通过此链接找到此活动的解决方案。
概括
在涵盖了前几章的大部分理论知识之后,本章通过一个真实案例研究来巩固我们的知识。这个想法是鼓励通过动手实践来学习。
本章首先解释了深度学习对需要准确性的广泛行业的影响。推动深度学习增长的主要行业之一是银行业和金融业,此类算法被用于贷款申请评估、欺诈检测以及过去决策评估以预测未来行为等领域,主要是由于算法在这些方面取代人类表现的能力。
本章使用了一家台湾银行的真实数据集,目的是预测客户是否会拖欠付款。本章通过解释定义任何数据问题的内容、原因和方式的重要性,以及分析手头的数据以充分利用它的重要性,开始制定解决方案。
一旦根据问题定义准备好数据,我们就会探索定义“好”架构的想法。尽管可以考虑一些经验法则,但主要的收获是构建一个初始架构而不想太多,以便获得一些可用于执行错误分析以提高模型性能的结果。
错误分析的想法需要分析模型在训练集和验证集上的错误率,以确定模型是否更容易受到高偏差或高方差的影响。然后使用对模型的诊断来改变模型的架构和一些学习参数,这将导致性能的提高。
最后,我们探索了三种主要方法来利用性能最佳的模型。第一种方法包括保存模型,然后将其重新加载到任何编码平台,以便我们可以继续训练或执行推理。第二种方法主要用于将模型投入生产,它是通过使用 PyTorch 的 JIT 模块实现的,该模块创建可在 C++ 上运行的模型的序列化表示。最后,第三种方法包括创建一个可以被其他程序访问的 API,以便它可以向模型发送信息或从模型接收信息。
在下一章中,我们将专注于使用 CNN 解决图像分类任务。