Apple神经网络引擎详解

即使您可以MLModelConfiguration告诉 Core ML 您对使用 CPU / GPU / ANE 的偏好是什么,但没有 API 可以在运行时询问它当前在哪个硬件上运行模型。

Core ML 还可以将您的模型分成多个部分,并使用不同的处理器运行每个部分。因此它可能在同一个推理过程中同时使用 ANE和CPU 或 GPU。

H11ANEServicesThread

当您的应用程序在设备上运行时,按下调试器中的暂停按钮。如果有一个名为H11ANEServicesThread的线程,那么 Core ML 至少在模型的某些部分使用了神经引擎。

尝试computeUnits

ChangeMLModelConfiguration的computeUnits选项从.all到.cpuAndGPU和.cpuOnly。

如果你的模型的性能.all并不比其他选项快多少,Core ML 可能只对模型的一部分使用 ANE——或者根本不使用。

断点

确定哪个处理器 Core ML 正在运行模型的一种方法是设置一个符号断点并放入调试器。

想知道您的模型是否在 ANE 上运行?设置一个断点-[_ANEModel program](重要:拼写完全一样,前面有破折号。)如果这个断点被击中,Core ML 正在使用 ANE。

但是...... Core ML 可能决定在 ANE 上运行您的模型的一部分,而在 GPU 或 CPU 上运行其余部分。仅仅因为您的应用程序成功-[_ANEModel program]并不意味着整个模型都在 ANE 上运行。为了确保,您需要设置其他几个断点。

Core ML 使用在私有 Espresso 框架中实现的三种不同“引擎”:

ANE — Espresso::ANERuntimeEngine

GPU — Espresso::MPSEngine and Espresso::MetalLowmemEngine

CPU — Espresso::BNNSEngine

运行模型时,它可以在这些引擎之间切换。通过查看调试器的堆栈跟踪中出现的引擎名称,您可以看到当前正在使用哪个引擎/处理器。

要确定模型(也)是否在 GPU 或 CPU 上运行,可以使用以下符号断点:

Espresso::MPSEngine::context::__launch_kernel

Espresso::BNNSEngine::convolution_kernel::__launch

Espresso::elementwise_kernel_cpu::__launch

寻找哪些符号?

上述符号可能会在 iOS 版本之间发生变化。要查找可用于断点的其他可能符号,请在设备或模拟器上运行您的应用程序并进入调试器。在调试器提示符处键入以下内容:

(lldb) image list Espresso

这将打印私有 Espresso 框架的路径,如下所示(在您的机器上会有所不同):

/Users/matthijs/Library/Developer/Xcode/iOS DeviceSupport/13.3 (17C54) arm64e/Symbols/System/Library/PrivateFrameworks/Espresso.framework/Espresso

接下来,执行以下操作:

(lldb) image dump symtab 'put-the-path-here'

这会从 Espresso 框架中转储整个符号表。您应该能够在其中找到一些有趣的符号。:-)

如果所有其他方法都失败,请使用以下断点之一并使用调试器手动单步执行代码:

Espresso::layer::__launch

Espresso::net::__forward

如果你最终得到一个函数,例如Espresso::elementwise_kernel_cpu::__launch,这是一个很好的提示,表明你现在正在 CPU 上运行。

仪器时间分析器

如果您不确定要设置哪些断点,或者您想了解模型不同部分的速度有多快,请使用Time Profiler工具运行您的应用程序。

我建议制作一个新的空应用程序。循环调用您的 Core ML 模型 100 次左右。

使用 Time Profiler 模板在 Instruments 中运行应用程序并打开调用树。

提示:按住 Option 键单击项目可展开其下方的所有内容。这将为您节省大量点击。

找到符号-[MLNeuralNetworkEngine predictionFromFeatures:...]。右键单击它,选择Focus on subtree。

现在您将看到在模型执行期间被调用的所有函数,以及它们相对占用的时间。这些函数的名称将为模型的执行位置提供很好的线索,您也可以将它们用作断点。

使用 ANE 时,还会调用-[_ANEClient evaluateWithModel...]. 这似乎可以衡量在 ANE 上运行模型所需的时间。