效果衡量

基准测试工具

LiteRT 基准测试工具目前可衡量和计算以下重要性能指标的统计信息:

  • 初始化时间
  • 预热状态的推理时间
  • 稳态的推理时间
  • 初始化期间的内存用量
  • 总体内存用量

基准比较工具以 Android 和 iOS 基准比较应用以及预构建的命令行二进制文件的形式提供,它们都共享相同的核心性能测量逻辑。请注意,由于运行时环境不同,可用的选项和输出格式略有不同。

预构建的基准二进制文件(使用 CompiledModel API)

您可以通过两种方式将基准测试工具与 Android 搭配使用。一种是原生基准二进制文件(基于 CompiledModel API),另一种是 Android 基准应用(基于 Interpreter API)。LiteRT 基准测试工具以内置二进制文件 benchmark_model 的形式提供。您可以在 Linux、macOS、Windows、Raspberry Pi、嵌入式设备和启用了 GPU 加速的 Android 设备上通过 shell 命令行执行此工具。

下载或构建二进制文件

通过点击以下链接下载每晚预构建的命令行二进制文件:

您还可以在计算机上从源代码构建基准二进制文件。

bazel build -c opt //litert/tools:benchmark_model

如需使用 Android NDK 工具链进行构建,您需要先按照此指南设置构建环境,或使用此指南中所述的 Docker 映像。

bazel build -c opt --config=android_arm64 \
  //litert/tools:benchmark_model

运行基准测试

如需在计算机上运行基准,请从 shell 中执行二进制文件。

path/to/downloaded_or_built/benchmark_model \
  --graph=your_model.tflite \
  --num_threads=4

您可以将之前提到的同一组参数与预构建的命令行二进制文件搭配使用。

GPU 加速器

这些预构建的二进制文件包含新的 LiteRT GPU 加速器。它支持由 Vulkan (Linux)、Metal (MacOS) 和 Direct3D (Windows) 提供支持的 OpenCL 和 WebGPU。

如需使用 GPU 加速器,请传递标志 --use_gpu=true

分析模型操作

基准模型二进制文件还可用于分析模型操作,并获取每个运算符的执行时间。为此,请在调用期间向 benchmark_model 传递标志 --use_profiler=true

Android 基准测试应用(使用 Interpreter API)

我们还提供了一个基于 v1 Interpreter API 的 Android 基准测试应用。这样可以更好地衡量模型在 Android 应用中的表现。不过,基准测试工具得出的数字与在实际应用中使用模型运行推理时得出的数字仍会略有不同。

此 Android 基准测试应用没有界面。使用 adb 命令安装并运行该工具,然后使用 adb logcat 命令检索结果。

下载或构建应用

使用以下链接下载每晚预构建的 Android 基准测试应用:

对于通过 Flex 委托支持 TF 操作的 Android 基准测试应用,请使用以下链接:

您还可以按照这些说明从源代码构建应用。

准备基准

在运行基准测试应用之前,请按如下方式安装该应用并将模型文件推送到设备:

adb install -r -d -g android_aarch64_benchmark_model.apk
adb push your_model.tflite /data/local/tmp

运行基准测试

adb shell am start -S \
  -n org.tensorflow.lite.benchmark/.BenchmarkModelActivity \
  --es args '"--graph=/data/local/tmp/your_model.tflite \
              --num_threads=4"'

graph 是必需参数。

  • graphstring
    TFLite 模型文件的路径。

您可以指定更多可选参数来运行基准测试。

  • num_threadsint(默认值=1)
    用于运行 TFLite 解释器的线程数。
  • use_gpubool(默认值为 false)
    使用 GPU 委托
  • use_xnnpackbool(默认值=false
    使用 XNNPACK 委托

根据您使用的设备,其中某些选项可能无法使用或不起作用。如需了解更多可使用基准测试应用运行的性能参数,请参阅参数

使用 logcat 命令查看结果:

adb logcat | grep "Inference timings"

基准测试结果的报告方式如下:

... tflite  : Inference timings in us: Init: 5685, First inference: 18535, Warmup (avg): 14462.3, Inference (avg): 14575.2

iOS 基准应用

如需在 iOS 设备上运行基准测试,您需要从源代码构建应用。将 LiteRT 模型文件放在源代码树的 benchmark_data 目录中,并修改 benchmark_params.json 文件。这些文件会打包到应用中,应用会从该目录读取数据。如需详细说明,请访问 iOS 基准测试应用

知名模型的性能基准

本部分列出了在一些 Android 和 iOS 设备上运行知名模型时的 LiteRT 性能基准。

Android 性能基准

这些性能基准数字是使用原生基准二进制文件生成的。

对于 Android 基准,CPU 亲和性设置为使用设备上的大核心,以减少方差(请参阅详情)。

本教程假定模型已下载并解压缩到 /data/local/tmp/tflite_models 目录。基准二进制文件是使用这些说明构建的,并假定位于 /data/local/tmp 目录中。

如需运行基准测试,请执行以下操作:

adb shell /data/local/tmp/benchmark_model \
  --num_threads=4 \
  --graph=/data/local/tmp/tflite_models/${GRAPH} \
  --warmup_runs=1 \
  --num_runs=50

如需使用 GPU 委托运行,请设置 --use_gpu=true

以下性能值是在 Android 10 上测得的。

模型名称 设备 CPU,4 个线程 GPU
Mobilenet_1.0_224(float) Pixel 3 23.9 毫秒 6.45 毫秒
Pixel 4 14.0 毫秒 9.0 毫秒
Mobilenet_1.0_224(量化) Pixel 3 13.4 毫秒 ---
Pixel 4 5.0 毫秒 ---
NASNet Mobile Pixel 3 56 毫秒 ---
Pixel 4 34.5 毫秒 ---
SqueezeNet Pixel 3 35.8 毫秒 9.5 毫秒
Pixel 4 23.9 毫秒 11.1 毫秒
Inception_ResNet_V2 Pixel 3 422 毫秒 99.8 毫秒
Pixel 4 272.6 毫秒 87.2 毫秒
Inception_V4 Pixel 3 486 毫秒 93 毫秒
Pixel 4 324.1 毫秒 97.6 毫秒

iOS 性能基准

这些性能基准数字是使用 iOS 基准测试应用生成的。

为了运行 iOS 基准测试,基准测试应用经过修改,包含相应的型号,并且 benchmark_params.json 经过修改,将 num_threads 设置为 2。为了使用 GPU 代理,还向 benchmark_params.json 添加了 "use_gpu" : "1""gpu_wait_type" : "aggressive" 选项。

模型名称 设备 CPU,2 个线程 GPU
Mobilenet_1.0_224(float) iPhone XS 14.8 毫秒 3.4 毫秒
Mobilenet_1.0_224(量化) iPhone XS 11 毫秒 ---
NASNet Mobile iPhone XS 30.4 毫秒 ---
SqueezeNet iPhone XS 21.1 毫秒 15.5 毫秒
Inception_ResNet_V2 iPhone XS 261.1 毫秒 45.7 毫秒
Inception_V4 iPhone XS 309 毫秒 54.4 毫秒

跟踪 LiteRT 内部

在 Android 中跟踪 LiteRT 内部

Android 应用的 LiteRT 解释器的内部事件可由 Android 跟踪工具捕获。它们与 Android Trace API 的事件相同,因此从 Java/Kotlin 代码捕获的事件会与 LiteRT 内部事件一起显示。

以下是一些事件示例:

  • 运算符调用
  • 通过委托修改图
  • 张量分配

在各种轨迹捕获选项中,本指南将介绍 Android Studio CPU 性能分析器和 System Tracing 应用。如需了解其他选项,请参阅 Perfetto 命令行工具Systrace 命令行工具

在 Java 代码中添加跟踪事件

这是图片分类示例应用中的一个代码段。LiteRT 解释器在 recognizeImage/runInference 部分运行。此步骤是可选的,但有助于了解推理调用是在何处进行的。

  Trace.beginSection("recognizeImage");
  ...
  // Runs the inference call.
  Trace.beginSection("runInference");
  tflite.run(inputImageBuffer.getBuffer(), outputProbabilityBuffer.getBuffer().rewind());
  Trace.endSection();
  ...
  Trace.endSection();

启用 LiteRT 跟踪

如需启用 LiteRT 轨迹记录,请在启动 Android 应用之前将 Android 系统属性 debug.tflite.trace 设置为 1。

adb shell setprop debug.tflite.trace 1

如果在初始化 LiteRT 解释器时已设置此属性,则会跟踪来自解释器的关键事件(例如,运算符调用)。

捕获所有轨迹后,将属性值设置为 0 以停用轨迹记录。

adb shell setprop debug.tflite.trace 0

Android Studio CPU 性能分析器

按照以下步骤,使用 Android Studio CPU 性能剖析器捕获轨迹:

  1. 从顶部菜单中依次选择 Run > Profile 'app'

  2. 在性能分析器窗口显示时,点击 CPU 时间轴上的任意位置。

  3. 在 CPU 性能分析模式中选择“跟踪系统调用”。

    选择“跟踪系统调用”

  4. 按下“录制”按钮。

  5. 按“停止”按钮。

  6. 调查跟踪结果。

    Android Studio 轨迹

在此示例中,您可以看到线程中的事件层次结构和每个运算符时间的统计信息,还可以看到整个应用在线程之间的数据流。

“系统跟踪”应用

按照系统跟踪应用中详述的步骤,在不使用 Android Studio 的情况下捕获轨迹。

在此示例中,系统捕获了相同的 TFLite 事件,并根据 Android 设备的版本将其保存为 Perfetto 或 Systrace 格式。捕获的轨迹文件可在 Perfetto 界面中打开。

Perfetto 轨迹文件

在 iOS 中跟踪 LiteRT 内部

iOS 应用的 LiteRT 解释器的内部事件可由 Xcode 随附的 Instruments 工具捕获。它们是 iOS signpost 事件,因此从 Swift/Objective-C 代码捕获的事件会与 LiteRT 内部事件一起显示。

以下是一些事件示例:

  • 运算符调用
  • 通过委托修改图
  • 张量分配

启用 LiteRT 跟踪

按照以下步骤设置环境变量 debug.tflite.trace

  1. 在 Xcode 的顶部菜单中,依次选择 Product > Scheme > Edit Scheme...

  2. 点击左侧窗格中的“个人资料”。

  3. 取消选中“使用 Run 操作的实参和环境变量”复选框。

  4. 在“环境变量”部分下添加 debug.tflite.trace

    设置环境变量

如果您想在分析 iOS 应用时排除 LiteRT 事件,请移除环境变量以停用跟踪。

XCode Instruments

请按以下步骤捕获轨迹:

  1. 从 Xcode 的顶部菜单中依次选择 Product > Profile

  2. 在启动 Instruments 工具时,点击分析模板中的 Logging

  3. 按“开始”按钮。

  4. 按“停止”按钮。

  5. 点击“os_signpost”以展开“操作系统日志记录”子系统项。

  6. 点击“org.tensorflow.lite”操作系统日志记录子系统。

  7. 调查跟踪结果。

    Xcode Instruments 轨迹

在此示例中,您可以查看每个操作员时间的事件层次结构和统计信息。

使用轨迹数据

借助跟踪记录数据,您可以识别性能瓶颈。

以下是一些您可从分析器中获得的洞见示例,以及可用于提升性能的潜在解决方案:

  • 如果可用 CPU 核心数小于推理线程数,CPU 调度开销可能会导致性能不佳。您可以重新安排应用中其他占用大量 CPU 的任务,以避免与模型推理重叠,也可以调整解释器线程数。
  • 如果运算符未完全委托,则模型图的某些部分会在 CPU 上执行,而不是在预期的硬件加速器上执行。您可以将不受支持的运算符替换为类似的受支持运算符。