TensorFlow Lite 的 GPU 代理

使用图形处理单元 (GPU) 运行机器学习 (ML) 模型可以显著提高模型的性能以及支持机器学习的应用的用户体验。借助 TensorFlow Lite,您可以通过称为代理的硬件驱动程序来使用 GPU 和其他专用处理器。使 TensorFlow Lite 机器学习应用能够使用 GPU 可带来以下好处:

  • 速度 - GPU 专为大规模并行工作负载的高吞吐量而构建。这种设计使其非常适合深度神经网络,深度神经网络由大量运算符组成,每个运算符处理可以并行处理的输入张量,这通常可以缩短延迟时间。理想情况下,在 GPU 上运行模型可能会足够快,以支持以前无法实现的实时应用。
  • 高能效 - GPU 以非常高效且经过优化的方式执行机器学习计算,通常与在 CPU 上运行的同一任务相比,消耗的电量更少,产生的热量更少。

本文档简要介绍了 TensorFlow Lite 对 GPU 的支持,以及 GPU 处理器的一些高级用途。如需详细了解如何在特定平台上实现 GPU 支持,请参阅以下指南:

GPU ML 操作支持

TensorFlow Lite GPU 代理可以加速的 TensorFlow ML 操作(即操作)存在一些限制。该委托支持 16 位和 32 位浮点精度的以下操作:

  • ADD
  • AVERAGE_POOL_2D
  • CONCATENATION
  • CONV_2D
  • DEPTHWISE_CONV_2D v1-2
  • EXP
  • FULLY_CONNECTED
  • LOGICAL_AND
  • LOGISTIC
  • LSTM v2 (Basic LSTM only)
  • MAX_POOL_2D
  • MAXIMUM
  • MINIMUM
  • MUL
  • PAD
  • PRELU
  • RELU
  • RELU6
  • RESHAPE
  • RESIZE_BILINEAR v1-3
  • SOFTMAX
  • STRIDED_SLICE
  • SUB
  • TRANSPOSE_CONV

默认情况下,只有版本 1 支持所有操作。启用量化支持会启用相应的版本,例如 ADD v2。

排查 GPU 支持问题

如果 GPU 代理不支持某些操作,框架将仅在 GPU 上运行图的一部分,而在 CPU 上运行图的其余部分。由于 CPU/GPU 同步的成本较高,因此与整个网络单独在 CPU 上运行相比,这样的拆分执行模式通常会导致性能下降。在这种情况下,应用会生成警告,例如:

WARNING: op code #42 cannot be handled by this delegate.

此类失败没有回调,因为这不是实际的运行时失败。使用 GPU 委托测试模型的执行情况时,您应该会收到这些警告的提醒。如果出现大量此类警告,则可能表示您的模型并非最适合用于 GPU 加速,可能需要重构模型。

示例模型

以下示例模型旨在通过 TensorFlow Lite 利用 GPU 加速功能,供您参考和测试:

针对 GPU 进行优化

在使用 TensorFlow Lite GPU 代理在 GPU 硬件上运行模型时,以下技巧可帮助您获得更好的性能:

  • 重塑操作 - 某些在 CPU 上快速执行的操作可能会给移动设备上的 GPU 带来较高的开销。调整形状的操作(包括 BATCH_TO_SPACESPACE_TO_BATCHSPACE_TO_DEPTH 等)的运行成本特别高。您应该仔细检查重塑操作的使用,并考虑其可能仅用于探索数据或模型的早期迭代。移除它们可以显著提升性能。

  • 图片数据通道 - 在 GPU 上,张量数据会拆分为 4 个通道,因此,对形状为 [B,H,W,5] 的张量执行计算时,对形状为 [B,H,W,8] 的张量执行大致相同,但比 [B,H,W,4] 差很多。如果您使用的相机硬件支持 RGBA 图像帧,馈送该 4 通道输入的速度明显更快,因为这可以避免从 3 通道 RGB 复制到 4 通道 RGBX 的内存。

  • 针对移动设备进行了优化的模型 - 为获得最佳性能,您应该考虑使用针对移动设备优化的网络架构重新训练分类器。针对设备端推断进行优化可以充分利用移动硬件功能,从而显著缩短延迟时间和功耗。

高级 GPU 支持

您还可以使用其他高级技术进行 GPU 处理,进一步提高模型的性能(包括量化和序列化)。以下部分更详细地介绍了这些方法。

使用量化模型

本部分介绍 GPU 代理如何加速 8 位量化模型,具体包括:

为了优化性能,请使用同时具有浮点输入和输出张量的模型。

具体是怎么运作的?

由于 GPU 后端仅支持浮点执行,因此我们通过为其提供原始模型的“浮点视图”来运行量化模型。概括来讲,这包括以下步骤:

  • 常量张量(例如权重/偏差)在进入 GPU 内存时会被去量化一次。为 TensorFlow Lite 启用该 delegate 后,就会执行此操作。

  • GPU 程序的输入和输出(如果进行 8 位量化)会针对每次推理分别进行去量化和量化。此操作是使用 TensorFlow Lite 的优化内核在 CPU 上完成的。

  • 在运算之间插入量化模拟器以模拟量化行为。对于操作期望激活遵循量化期间学到的边界的模型来说,此方法很必要。

如需了解如何使用 GPU 代理启用此功能,请参阅以下内容:

通过序列化缩短初始化时间

借助 GPU 代理功能,您可以从预编译的内核代码和模型数据(已序列化并保存在先前的运行中)加载。此方法可避免重新编译,并且可以将启动时间缩短高达 90%。通过交换磁盘空间来节省时间,可以实现这一改进。您可以通过一些配置选项来启用此功能,如以下代码示例所示:

C++

    TfLiteGpuDelegateOptionsV2 options = TfLiteGpuDelegateOptionsV2Default();
    options.experimental_flags |= TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_SERIALIZATION;
    options.serialization_dir = kTmpDir;
    options.model_token = kModelToken;

    auto* delegate = TfLiteGpuDelegateV2Create(options);
    if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;
      

Java

    GpuDelegate delegate = new GpuDelegate(
      new GpuDelegate.Options().setSerializationParams(
        /* serializationDir= */ serializationDir,
        /* modelToken= */ modelToken));

    Interpreter.Options options = (new Interpreter.Options()).addDelegate(delegate);
      

使用序列化功能时,请确保您的代码符合以下实现规则:

  • 将序列化数据存储在其他应用无法访问的目录中。在 Android 设备上,使用 getCodeCacheDir(),它指向当前应用不公开的位置。
  • 对于特定型号的设备,模型令牌必须是唯一的。您可以使用 farmhash::Fingerprint64 等库根据模型数据生成指纹,从而计算模型令牌。