Windows ML 性能和内存
在本文中,我们将介绍如何在使用 Windows 机器学习时管理应用程序的性能。
线程处理和并发
从运行时公开的每个对象都是敏捷对象,这意味着可以从任何线程访问这些对象。 有关敏捷对象的详细信息,请参阅 C++/WinRT 中的敏捷对象。
你将使用的一个关键对象是 LearningModelSession。 从任何线程调用此对象都始终是安全的。
对于 GPU 会话:对象将锁定并同步并发调用。 如果需要并发,则需要创建多个会话才能实现它。
对于 CPU 会话:对象不会锁定并且允许在单个会话上进行并发调用。 你必须负责管理自己的状态、缓冲区和绑定对象。
应注意并度量方案目标。 新式 GPU 体系结构的工作方式不同于 CPU。 例如,如果低延迟是目标,那么你可能想要管理如何使用管道(而非并发)来计划跨 CPU 和 GPU 引擎的工作。 有关多引擎同步的这篇文章是理想的入门文章。 如果吞吐量是目标(例如,每次尽可能多地处理映像),通常需要使用多个线程和并发来使 CPU 饱和。
当涉及到线程处理和并发时,需要运行试验并测量运行时间。 性能将基于目标和方案大幅变化。
内存利用率
LearningModel 和 LearningModelSession 的每个实例在内存中都有一个模型副本。 如果使用小模型,你可能不在意这一点,但如果使用非常大的模型,则这一点会变得很重要。
若要释放内存,请在模型或会话上调用 Dispose。 不要直接删除它们,因为某些语言会执行延迟垃圾回收。
LearningModel 在内存中保留一份副本,以便能够创建新的会话。 释放 LearningModel 时,所有现有会话会继续运行。 但是,你将再也无法通过该 LearningModel 实例创建新会话。 对于大型模型,可以先创建模型和会话,然后释放模型。 如果对所有 Evaluate 调用使用单个会话,你就会在内存中拥有一个大型模型副本。
Float16 支持
为了提高性能并降低模型的内存占用量,可以使用 ONNXMLTools 将模型转换为 float16。
转换后,所有权重和输入都是 float16。 下面介绍如何使用 float16 输入和输出:
-
- 建议用法。
- 将颜色转换并张量化为 float16。
- 支持 bgr8 和 8 位图像格式,此类格式可在不丢失数据的情况下安全地转换为 float16。
-
- 高级路径。
- 将 float32 强制转换为 float16。
- 如果是图像,则可以安全地进行强制转换,因为 bgr8 较小并且适合。
- 如果不是图像,则 Bind 会失败,需改为传入 TensorFloat16Bit。
-
- 高级路径。
- 需要转换为 float16,并将输入作为 float32 传递,后者会被强制转换为 float16。
注意
大多数情况下,运算符仍执行 32 位数学运算。 溢出的风险较小,结果将截断为 float16。 但是,如果硬件播发 float16 支持,则运行时会利用它。
预处理输入数据
实际上,WinML 会执行一些预处理步骤,使处理输入数据更简单且更高效。 例如,给定的输入图像可以是各种颜色格式和形状,并且可能不同于模型的预期。 WinML 会对图像执行转换,对其进行匹配,降低开发人员的负荷。
WinML 还利用整个硬件堆栈(CPU、GPU 等)为特定设备和方案提供最有效的转换。
但在某些情况下,可能需要手动将输入数据张量化,因为你有一些特定的要求。 例如,你可能不希望对图像使用 VideoFrame,或者要将像素值从范围 0-255 规范化为范围 0-1。 在这些情况下,可以对数据执行你自己的自定义张量化操作。 如需此方面的示例,请参阅 Custom Tensorization Sample(自定义张量化示例)。
注意
使用以下资源可获取有关 Windows ML 的帮助:
- 若要提出或回答有关 Windows ML 的技术问题,请在 Stack Overflow 上使用 windows-machine-learning 标记。
- 若要报告 bug,请在 GitHub 上提交问题。