javaandroidassetstensorflow-liteandroid-assetmanager

how to load a tflite model in Java using AssetManager and Play Asset Delivery?


I have a .tflite model file that is over 200MB in size. As it increases the 150MB max size for an apk I had to bundle in in an app bundle using Play Asset Delivery (PAD).

I followed the guide mentioned here: and was able to build my .aab file. I have added my asst as install-time, so I do not have to check for its availability, it should be installed with the app.

But cannot seem to access my tflite file.

I am able to load the model from the assets folder perfectly using:

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);
    }

but this does not work with PAD as we are required to use AssetManager, as explained here.

So I rewrote the above function to use 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, startOffset, declaredLength);
    }

But it does not appear to load the model. As on the interpreter.run() method, I get the error:

java.lang.NullPointerException: Attempt to invoke virtual method 'void org.tensorflow.lite.Interpreter.run(java.lang.Object, java.lang.Object)' on a null object reference

which suggests that the model was not loaded.

Is the path of the model different in this case? How would I load a tflite model?


Solution

  • So it turns out the function I have above is the correct way to load a tflite model using 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, startOffset, declaredLength);
        }
    

    The reason it was not loading the model was because when using Play Asset Delivery, the install-time assets only become available to use after being installed from the downloaded play bundle from play store.

    As install-time assets act like just normal assets, the location of the asset stays the same.