LiteRT 的 GPU 代理

使用图形处理单元 (GPU) 运行机器学习 (ML) 模型可以显著提升模型的性能,并改善启用 ML 的应用的用户体验。LiteRT 通过称为委托的硬件驱动程序来使用 GPU 和其他专用处理器。在 LiteRT ML 应用中启用 GPU 可带来以下好处:

  • 速度 - GPU 专为大规模并行工作负载的高吞吐量而打造。这种设计使它们非常适合深度神经网络,后者包含大量运算符,每个运算符处理的输入张量都可以并行处理,这通常会降低延迟。在最佳情况下,在 GPU 上运行模型可能足够快,从而实现以前无法实现的实时应用。
  • 能效 - GPU 以非常高效且优化的方式执行机器学习计算,与在 CPU 上运行相同任务相比,通常消耗更少的电量并产生更少的热量。

本文档简要介绍了 LiteRT 中的 GPU 支持,以及 GPU 处理器的部分高级用途。如需更具体地了解如何在特定平台上实现 GPU 支持,请参阅以下指南:

GPU ML 操作支持

LiteRT GPU 代理可加速的 TensorFlow 机器学习操作(简称“op”)存在一些限制。该委托支持以下运算,精度为 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 加速,可能需要重构模型。

示例模型

以下示例模型旨在利用 LiteRT 实现 GPU 加速,可供参考和测试:

针对 GPU 进行优化

以下技巧可帮助您在使用 LiteRT GPU 委托在 GPU 硬件上运行模型时获得更好的性能:

  • 重塑操作 - 在 CPU 上快速执行的某些操作在移动设备上可能会对 GPU 造成高昂的开销。重塑操作的运行成本尤其高,包括 BATCH_TO_SPACESPACE_TO_BATCHSPACE_TO_DEPTH 等。您应仔细检查 reshape 操作的使用情况,并考虑这些操作可能仅用于探索数据或模型的早期迭代。移除这些关键字可以显著提升效果。

  • 图片数据通道 - 在 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 内存中。当为 LiteRT 启用委托时,会发生此操作。

  • 如果 GPU 程序的输入和输出是 8 位量化,则在每次推理时都会进行反量化和量化(分别)。此操作在 CPU 上使用 LiteRT 的优化内核完成。

  • 在运算之间插入量化模拟器,以模拟量化行为。对于以下模型,此方法是必需的:在这些模型中,操作员希望激活遵循在量化期间学习的界限。

如需了解如何通过 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 等库,通过从模型数据生成指纹来计算模型令牌。