在做机器学习任务的时候,需要学会用代码快速查看模型的内存占用情况。原因很简单,硬件资源有限,单个机器学习模块不应该占用系统所有的内存,这在边缘计算场景下尤为重要。例如,您编写了一个很棒的机器学习程序,或者构建了一个不错的神经网络模型,然后想要将该模型部署到某个Web服务或RESTAPI上。或者,您可能基于来自工厂传感器的数据流开发了一个模型,并计划将其部署在其中一台工业计算机上。此时,您的模型可能是在硬件上运行的数百个模型之一,因此您必须了解内存使用峰值。否则,多个模型同时达到内存使用峰值,可能导致系统崩溃。因此,弄清楚代码运行时的内存配置文件(动态量)非常重要。这与模型的大小和压缩无关,它可能是您事先保存在磁盘上的特殊对象,例如Scikit-learnJoblibdump、PythonPickledump、TensorFlowHFD5等Scalene:ANo-FrillsMemory/CPU/GPUProfiler首先要说的是Scalene,这是大学开发的用于Python的高性能CPU和内存分析器马萨诸塞州。它的GitHub页面是这样描述的:“Scalene是一个用于Python的高性能CPU、GPU和内存分析器,它可以做许多其他Python分析器不能做的事情,提供比其他分析器快几个数量级的详细信息”Installit'saPython包,所以按照通常的方式安装它:pipinstallscalene这适用于Linux操作系统,作者没有在Windows10上测试它。从CLI或在JupyterNotebook中使用Scalene非常简单:scalene它也是可以使用魔术命令在JupyterNotebook中使用它:%load_extscalene输出示例下面是一个输出示例。稍后将更深入地研究这一点。这些是Scalene的一些很酷的特性:行和函数:报告有关整个函数和每一行代码的信息;线程:支持Python线程;多处理:支持使用多处理库;Python与本机代码(例如库)的时间;SystemTime:区分系统时间(如休眠或执行I/O操作);GPU:报告在NvidiaGPU上使用的时间(如果有);ReplicationAmount:报告每秒复制的数据量;泄漏检测:自动查明可能导致内存泄漏的线路。ML代码具体示例让我们看一下Scalene的内存配置标准机器学习代码。将Scikit-learn库用于三个模型,并利用其全面的数据生成功能来创建数据集。比较了两种不同类型的ML模型:多元线性回归模型;具有相同数据集的深度神经网络模型。使用标准导入和两个变量NUM_FEATURES和NUM_SMPLES对线性回归模型进行一些实验。此处未显示数据生成和模型拟合代码,它们非常标准。作者将拟合模型保存为pickleddump,并将其与测试CSV文件一起加载以进行推理。为清楚起见,在Scalene执行和报告环境循环中运行所有内容。运行命令时:$scalenelinearmodel.py--html>>linearmodel-scalene.html得到这些结果作为输出。请注意,此处使用了--html标志并将输出通过管道传输到HTML文件以便于报告。令人惊讶的是,内存占用几乎完全由外部I/O(例如Pandas和Scikit-learn估算器加载)主导,少量测试数据被写入磁盘上的CSV文件。实际的ML建模、Numpy、Pandas操作和推理,所有这些都不会影响内存。我们可以扩展数据集大小(行数)和模型复杂性(特征数量),并运行相同的内存配置文件来记录各种操作在内存消耗方面的表现。结果显示在这里。此处,X轴表示一组特征/数据点。请注意,该图描绘的是百分比,而不是绝对值,显示了各种类型操作的相对重要性。从这些实验得出的结论是,Scikit-learn线性回归估计非常高效,不会为实际模型拟合或推理消耗大量内存。但就代码而言,它确实有固定的内存占用,加载时会消耗大量内存。但是,随着数据大小和模型复杂性的增加,总体代码占用空间会减少。如果您使用这样的模型,您可能需要关注数据文件I/O,优化您的代码以获得更好的内存性能。深度神经网络呢?如果我们对具有2个隐藏层(每个隐藏层中有50个神经元)的神经网络进行类似的实验,结果如下所示。代码地址:https://github.com/tirthajyoti/Machine-Learning-with-Python/blob/master/Memory-profiling/Scalene/mlp.py不同于线性回归模型,神经网络模型是在training/fitting步骤消耗大量内存。但由于特征数量少,数据量大,拟合占用内存较少。此外,可以试验各种架构和超参数,并记录内存使用情况,以得出合适的设置。重现性说明如果使用相同的代码重现实验,由于硬件、磁盘/CPU/GPU/内存类型不同,结果可能会有很大差异。一些关键建议最好在专注于单个任务的代码中编写小功能;保持一些变量自由,例如特征和数据点的数量,以最少的更改运行相同的代码,在数据/模型缩放时检查内存配置文件;如果您将一种ML算法与另一种算法进行比较,请使整体代码结构和流程尽可能相同,以减少混淆。最好只更改估算器类并比较内存配置文件;数据和模型I/O(导入语句、模型持久化在磁盘上)在内存占用方面可能出奇地占主导地位,具体取决于建模场景,优化时不要忽略这些;出于同样的原因,考虑比较来自多个实现/包(例如Keras、PyTorch、Scikitlearn)的相同算法的内存配置文件。如果内存优化是主要目标,那么你必须找到一个占用最少内存并能令人满意地完成工作的实现,即使它在功能或性能方面不是最优的;如果数据I/O成为瓶颈,探索更快的选项或其他存储类型,例如用parquet文件和ApacheArrow存储替换PandasCSV。可以看看这篇文章:《How fast is reading Parquet file (with Arrow) vs. CSV with Pandas?》https://towardsdatascience.com/how-fast-is-reading-parquet-file-with-arrow-vs-csv-with-pandas-2f8095722e94Scalene可以做的其他事情在这篇文章中,只讨论了一小部分内存分析,重点是形式化的机器学习建模代码。事实上ScaleneCLI还有其他选项可以利用:只分析CPU时间,不分析内存;仅使用非零内存以减少资源消耗;指定CPU和内存分配的最小阈值;设置CPU采样率;.最终验证(可选)在资源较少的情况下,您最好托管一个验证环境/服务器,它将采用给定的建模代码(如果已开发)并通过这样的内存分析器运行它以创建运行时统计信息。如果模型代码通过了预先确定的内存占用标准,则只接受模型代码以进行进一步部署。总结在本文中,我们讨论了内存分配对机器学习代码的重要性。我们需要让它更好地部署在服务和机器上,让平台或工程团队更容易使用。分析内存还可以让我们找到针对特定数据或算法的更有效优化。祝您成功使用这些工具和技术进行机器学习部署。