本教程介绍如何在 Android 应用中使用 Qualcomm 提供的 TFLiteHelpers 类实现 TensorFlow Lite(TFLite)模型推理,特别针对 Qualcomm 设备上的 NPU 加速(如 QNN Delegate 的 HTP 后端)。以 SuperResolution 类为例,展示图像超分辨率模型推理的实现。
1. 前提条件
硬件:支持 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)。
1.1 依赖配置
在 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 本地库(如下 .so 文件)放置在 jniLibs 目录中。
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
2. 关键步骤
2.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 文件并计算哈希
}
2.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)。
2.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);
}
说明:这些处理器负责准备输入/输出缓冲区,以适配模型的具体数据类型要求。
2.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 用于处理多输入/输出模型,并可以用于记录推理时间。
2.5 释放资源
在推理结束后,必须关闭解释器和所有代理以释放系统资源。
@Override
public void close() {
if (tfLiteInterpreter != null) {
tfLiteInterpreter.close();
}
if (tfLiteDelegateStore != null) {
for (Delegate delegate : tfLiteDelegateStore.values()) {
delegate.close();
}
}
}
说明:此步骤对于防止内存泄漏和正确释放 NPU 等硬件资源至关重要。
3. 使用示例
在 Android Activity 中,可以按照以下方式实例化并调用推理类:
// 1. 实例化推理类
SuperResolution superRes = new SuperResolution(this, "model.tflite");
// 2. 加载输入图像
Bitmap inputImage = /* 从图库或相机加载图像 */;
// 3. 执行推理
Bitmap outputImage = superRes.generateUpscaledImage(inputImage);
// 4. 显示结果并释放资源
imageView.setImageBitmap(outputImage);
superRes.close();
4. 故障排查
模型加载失败:检查 assets 中的文件路径是否正确,以及文件是否已损坏。
代理初始化失败:验证设备是否支持 QNN_NPU,并检查 qtld-release.aar 和所有相关的 .so 本地库是否已正确加载。
性能问题:使用 tfLiteInterpreter.getLastNativeInferenceDurationNanoseconds() 监控推理时间,并尝试调整代理优先级以优化性能。
总结:本教程基于 Qualcomm 的 TFLiteHelpers 类,提供了一套经过优化的 QNN Delegate 配置流程,特别适合需要硬件加速的图像处理任务。请参考 Qualcomm 官方文档以进一步定制代理选项。