如何使用 AssetManager 和 Play Asset Delivery 在 Java 中加载 tflite 模型?

问题描述

我有一个超过 200MB 的 .tflite 模型文件。由于它增加了 apk 的 150MB 最大大小,我不得不使用 Play Asset Delivery (PAD) 将其捆绑在应用程序包中。

我遵循了提到的 here: 指南,并且能够构建我的 .aab 文件。我已将我的 asst 添加install-time,因此我不必检查其可用性,它应该与应用程序一起安装。

但似乎无法访问我的 tflite 文件

我可以使用以下方法完美地从资产文件夹加载模型:

private MappedByteBuffer loadModelFile() throws Exception {
        AssetFileDescriptor fileDescriptor = this.getAssets().openFd("model.tflite");
        FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
        FileChannel fileChannel = inputStream.getChannel();
        long startOffset = fileDescriptor.getStartOffset();
        long declaredLength = fileDescriptor.getDeclaredLength();
        return fileChannel.map(FileChannel.MapMode.READ_ONLY,startOffset,declaredLength);
    }

但这不适用于 PAD,因为我们需要使用 AssetManager,如 here 所述。

所以我重写了上面的函数来使用AssetManager

Context context = createPackageContext("com.companyname.packagename",0);
            AssetManager assetManager = context.getAssets();

private MappedByteBuffer loadModelFile(AssetManager assetManager,String modelPath) throws IOException {
        AssetFileDescriptor fileDescriptor = assetManager.openFd("model.tflite");
        FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
        FileChannel fileChannel = inputStream.getChannel();
        long startOffset = fileDescriptor.getStartOffset();
        long declaredLength = fileDescriptor.getDeclaredLength();
        return fileChannel.map(FileChannel.MapMode.READ_ONLY,declaredLength);
    }

但它似乎没有加载模型。与 interpreter.run() 方法一样,我收到错误

java.lang.NullPointerException: 尝试调用方法 'void org.tensorflow.lite.Interpreter.run(java.lang.Object,java.lang.Object)' 在一个空对象引用上

这表明模型未加载。

这种情况下模型的路径不同吗?我将如何加载 tflite 模型?

解决方法

所以事实证明我上面的函数是使用 AssetManager 加载 tflite 模型的正确方法。

Context context = createPackageContext("com.companyname.packagename",0);
            AssetManager assetManager = context.getAssets();

private MappedByteBuffer loadModelFile(AssetManager assetManager,String modelPath) throws IOException {
        AssetFileDescriptor fileDescriptor = assetManager.openFd("model.tflite");
        FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
        FileChannel fileChannel = inputStream.getChannel();
        long startOffset = fileDescriptor.getStartOffset();
        long declaredLength = fileDescriptor.getDeclaredLength();
        return fileChannel.map(FileChannel.MapMode.READ_ONLY,startOffset,declaredLength);
    }

未加载模型的原因是,在使用 Play Asset Delivery 时,install-time 资产只有在从 Play 商店下载的 Play 捆绑包中安装后才能使用。

由于 install-time 资产就像普通资产一样,因此资产的位置保持不变。