使用 TFLiteHelpers 类实现 TFLite 模型推理(8750)

本教程介绍如何在 Android 应用中使用 Qualcomm 提供的 TFLiteHelpers 类实现 TensorFlow Lite(TFLite)模型推理,特别针对 Qualcomm 设备上的 NPU 加速(如 QNN Delegate 的 HTP 后端)。以 SuperResolution 类为例,展示图像超分辨率模型推理的实现。

前提条件

  • 硬件:支持 QNN SDK 的 Qualcomm Snapdragon 芯片(如 Snapdragon 8 Gen 1 或更新型号)。

  • 模型:TFLite 模型(.tflite,4D 张量 [1, H, W, 3],数据类型 UINT8 或 FLOAT32)。

  • Android 环境:应用需访问 Context、Assets、nativeLibraryDir 和 cacheDir。

  • QNN SDK:从 Qualcomm 开发者网络获取 QNN SDK,包含本地库(如 libQnn*.so)。

依赖配置

在 build.gradle 中添加以下依赖以支持 TFLite 和 QNN Delegate:

dependencies {
    implementation 'androidx.appcompat:appcompat:1.7.0'
    implementation 'com.google.android.material:material:1.12.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    api 'org.tensorflow:tensorflow-lite:2.16.1'
    api 'org.tensorflow:tensorflow-lite-support:0.4.4'
    implementation 'org.tensorflow:tensorflow-lite-gpu:2.16.1'
    implementation 'org.tensorflow:tensorflow-lite-gpu-api:2.16.1'
    implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin:0.4.4'
    implementation files('libs/qtld-release.aar')

}


说明

  • tensorflow-lite 和 tensorflow-lite-support 用于核心 TFLite 功能和图像处理。

  • tensorflow-lite-gpu* 支持 GPU 代理(可选,作为 NPU 回退)。

  • qtld-release.aar 包含 Qualcomm QNN Delegate 实现,需从 Qualcomm 获取。

  • 确保 QNN 本地库(如 libQnn*.so)放置在 jniLibs 目录或通过 nativeLibraryDir 加载,目录如下:

libgpu_delegate_plugin.so

libann_delegate jni.so

libQnnDsp.so

libQnnDspV66Skel.so

libQnnDspV66Stub.so

libQnnGpu.so

libQnnHtp.so

lib QnnHtpPrepare.so

lib QnnHtpV68Skel.so

lib QnnHtpV68Stub.so

lib QnnHtpV69Skel.so

lib QnnHtpV69Stub.so

lib QnnHtp V73Skel.so

lib QnHtpV73Stub.so

lib QnnHtp V75Skel.so

libQnnHtpV75Stub.so

libQnnHtp V79Skel.so

lib QnnHtp V79Stub.so

libQnnSystem.so

libQnnTFLite Delegate.so

libtensorflowlite_gpu_jni.so

libtensorflowlite jni.so

关键步骤

1. 加载模型

使用 TFLiteHelpers.loadModelFile 从 assets 加载模型,生成哈希用于缓存。

import android.content.Context;
import android.util.Pair;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.security.NoSuchAlgorithmException;

private Pair<MappedByteBuffer, String> loadModel(Context context, String modelPath) throws IOException, NoSuchAlgorithmException {
    return TFLiteHelpers.loadModelFile(context.getAssets(), modelPath); // 加载 .tflite 文件并计算哈希
}

说明:哈希用于 QNN Delegate 缓存,减少模型编译时间。

2. 创建解释器和代理

使用 TFLiteHelpers.CreateInterpreterAndDelegatesFromOptions 创建解释器,优先使用 QNN_NPU 代理,GPU 和 CPU 作为回退。

import com.quicinc.tflite.TFLiteHelpers;
import org.tensorflow.lite.Interpreter;
import org.tensorflow.lite.Delegate;
import java.util.Map;

private void initInterpreter(Context context, MappedByteBuffer modelBuffer, String modelHash, TFLiteHelpers.DelegateType[][] delegatePriorityOrder) {
    Pair<Interpreter, Map<TFLiteHelpers.DelegateType, Delegate>> result = TFLiteHelpers.CreateInterpreterAndDelegatesFromOptions(
        modelBuffer, // 模型缓冲区
        delegatePriorityOrder, // 代理优先级,例如 {{QNN_NPU, GPUv2}}
        4, // CPU 线程数
        context.getApplicationInfo().nativeLibraryDir, // 本地库目录
        context.getCacheDir().getAbsolutePath(), // 缓存目录
        modelHash // 模型标识
    );
    tfLiteInterpreter = result.first; // 解释器
    tfLiteDelegateStore = result.second; // 代理映射
}

说明:QNN_NPU 优先分配兼容操作,需验证输入/输出张量(4D,批次 1,通道 3,UINT8/FP32)。

3. 设置输入/输出处理器

配置图像处理器,处理数据类型转换和归一化。

import org.tensorflow.lite.support.image.ImageProcessor;
import org.tensorflow.lite.support.image.TensorImage;
import org.tensorflow.lite.support.tensorbuffer.TensorBuffer;
import org.tensorflow.lite.DataType;

private void setupProcessors(int[] inputShape, DataType inputType, int[] outputShape, DataType outputType) {
    inputImageProcessor = new ImageProcessor.Builder().add(new NormalizeOp(0.0f, 255.0f)).build(); // 输入归一化
    outputImageProcessor = new ImageProcessor.Builder()
        .add(new NormalizeOp(0.0f, 1 / 255.0f))
        .add(new CastOp(DataType.UINT8))
        .build(); // 输出反归一化并转为 UINT8
    outputBuffer = TensorBuffer.createFixedSize(outputShape, outputType);
    outputBindings = new HashMap<>();
    outputBindings.put(0, outputBuffer.getBuffer());
    outputImage = new TensorImage(outputType);
    outputImage.load(outputBuffer, ColorSpaceType.RGB);
}

说明:处理器准备输入/输出缓冲区,适配模型数据类型。

4. 运行推理

执行推理,处理输入并获取输出。

import android.graphics.Bitmap;
import java.nio.ByteBuffer;

public Bitmap generateUpscaledImage(Bitmap image) {
    ByteBuffer[] inputs = preprocess(image); // 预处理
    outputBuffer.getBuffer().clear();
    tfLiteInterpreter.runForMultipleInputsOutputs(inputs, outputBindings); // 推理
    return postprocess(); // 后处理
}

说明:runForMultipleInputsOutputs 处理多输入/输出,记录推理时间。

5. 释放资源

关闭解释器和代理,释放资源。

@Override
public void close() {
    tfLiteInterpreter.close();
    for (Delegate delegate : tfLiteDelegateStore.values()) {
        delegate.close();
    }
}

说明:防止内存泄漏,释放 NPU 资源。


使用示例

在 Android Activity 中调用:

SuperResolution superRes = new SuperResolution(this, "model.tflite");
Bitmap inputImage = /* 加载输入图像 */;
Bitmap outputImage = superRes.generateUpscaledImage(inputImage);
superRes.close();

故障排查

  • 模型加载失败:检查 assets 中的文件路径。

  • 代理初始化失败:验证 QNN_NPU 支持,检查 qtld-release.aar 和本地库。

  • 性能问题:使用 tfLiteInterpreter.getLastNativeInferenceDurationNanoseconds() 监控推理时间,调整代理优先级。

说明:本教程基于 Qualcomm 的 TFLiteHelpers 类,优化了 QNN Delegate 配置,适合图像处理任务。参考 Qualcomm 文档以进一步定制代理选项。