flutter-tflite icon indicating copy to clipboard operation
flutter-tflite copied to clipboard

Failed to load dynamic library 'libtensorflowlite_jni.so':

Open JoseGeorges8 opened this issue 1 year ago • 20 comments

  • Trying to run in an Android Physical Device.
  • The code is very similar if not identical to one of the example apps.

This line fails:

interpreter = await Interpreter.fromAsset(modelPath);

With the following error:

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: 
Invalid argument(s): Failed to load dynamic library 'libtensorflowlite_jni.so': dlopen failed: cannot locate symbol "strtod_l" referenced by "/data/app/com.pdl.tflite_poc-2/lib/arm64/libtensorflowlite_jni.so"...

Pubspect dependencies

  tflite_flutter: ^0.10.0
  image_picker: ^0.8.7+5
  image: ^4.0.17

The entire code is this here:

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:image/image.dart' as img;
import 'package:tflite_flutter/tflite_flutter.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  static const modelPath = 'assets/model.tflite';
  static const labelsPath = 'assets/labels.txt';

  late final Interpreter interpreter;
  late final List<String> labels;

  Tensor? inputTensor;
  Tensor? outputTensor;

  final imagePicker = ImagePicker();
  String? imagePath;
  img.Image? image;

  Map<String, int>? classification;

  @override
  void initState() {
    super.initState();
    _loadModel();
    _loadLabels();
  }

  // Clean old results when press some take picture button
  void _cleanResult() {
    imagePath = null;
    image = null;
    classification = null;
    setState(() {});
  }

  Future<void> _takePic() async {
    _cleanResult();
    final result = await imagePicker.pickImage(
      source: ImageSource.camera,
    );

    imagePath = result?.path;
    setState(() {});
    _processImage();
  }

  // Load model
  Future<void> _loadModel() async {

    interpreter = await Interpreter.fromAsset(modelPath);
    final options = InterpreterOptions();

    // Use XNNPACK Delegate
    if (Platform.isAndroid) {
      options.addDelegate(XNNPackDelegate());
    }

    // Load model from assets
    interpreter = await Interpreter.fromAsset(modelPath);
    // Get tensor input shape [1, 224, 224, 3]
    inputTensor = interpreter.getInputTensors().first;
    // Get tensor output shape [1, 1001]
    outputTensor = interpreter.getOutputTensors().first;
    setState(() {});

    print('Interpreter loaded successfully');
  }

  // Load labels from assets
  Future<void> _loadLabels() async {
    final labelTxt = await rootBundle.loadString(labelsPath);
    labels = labelTxt.split('\n');
  }

  // Process picked image
  Future<void> _processImage() async {
    if (imagePath != null) {
      // Read image bytes from file
      final imageData = File(imagePath!).readAsBytesSync();

      // Decode image using package:image/image.dart (https://pub.dev/image)
      image = img.decodeImage(imageData);
      setState(() {});

      // Resize image for model input (Mobilenet use [224, 224])
      final imageInput = img.copyResize(
        image!,
        width: 224,
        height: 224,
      );

      // Get image matrix representation [224, 224, 3]
      final imageMatrix = List.generate(
        imageInput.height,
        (y) => List.generate(
          imageInput.width,
          (x) {
            final pixel = imageInput.getPixel(x, y);
            return [pixel.r, pixel.g, pixel.b];
          },
        ),
      );

      // Run model inference
      _runInference(imageMatrix);
    }
  }

  // Run inference
  Future<void> _runInference(
    List<List<List<num>>> imageMatrix,
  ) async {
    // Set tensor input [1, 224, 224, 3]
    final input = [imageMatrix];
    // Set tensor output [1, 1001]
    final output = [List<int>.filled(1001, 0)];

    // Run inference
    interpreter.run(input, output);

    // Get first output tensor
    final result = output.first;

    // Set classification map {label: points}
    classification = <String, int>{};

    for (var i = 0; i < result.length; i++) {
      if (result[i] != 0) {
        // Set label: points
        classification![labels[i]] = result[i];
      }
    }

    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Center(
          child: Column(
            children: [
              Expanded(
                  child: Stack(
                alignment: Alignment.center,
                children: [
                  if (imagePath != null) Image.file(File(imagePath!)),
                  Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            const Row(),
                            // Show model information
                            Text(
                              'Input: (shape: ${inputTensor?.shape} type: ${inputTensor?.type})',
                            ),
                            Text(
                              'Output: (shape: ${outputTensor?.shape} type: ${outputTensor?.type})',
                            ),
                            const SizedBox(height: 8),
                            // Show picked image information
                            if (image != null) ...[
                              Text('Num channels: ${image?.numChannels}'),
                              Text(
                                  'Bits per channel: ${image?.bitsPerChannel}'),
                              Text('Height: ${image?.height}'),
                              Text('Width: ${image?.width}'),
                            ],
                            const SizedBox(height: 24),
                            // Show classification result
                            Expanded(
                              child: SingleChildScrollView(
                                child: Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  mainAxisAlignment: MainAxisAlignment.end,
                                  children: [
                                    if (classification != null)
                                      ...(classification!.entries.toList()
                                            ..sort(
                                              (a, b) =>
                                                  a.value.compareTo(b.value),
                                            ))
                                          .reversed
                                          .map(
                                            (e) => Container(
                                              padding: const EdgeInsets.all(8),
                                              color: Colors.orange
                                                  .withOpacity(0.3),
                                              child: Row(
                                                children: [
                                                  Text('${e.key}: ${e.value}'),
                                                ],
                                              ),
                                            ),
                                          ),
                                  ],
                                ),
                              ),
                            ),
                          ],
                        ),
                      ],
                    ),
                  ),
                ],
              )),
            ],
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _takePic,
        child: const Icon(
          Icons.camera_alt,
          size: 64,
        ),
      ),
    );
  }
}

Are there any set of installation instructions I didn't follow? I read something about an install.sh file I need to run to install dynamic libraries, but that didn't help as it seems like the libraries that added weren't what it was looking for. This is the file that I found which seems to be from the deprecated library.

Any help is appreciate it!!

JoseGeorges8 avatar May 31 '23 14:05 JoseGeorges8

+1

cimplesid avatar Jun 09 '23 06:06 cimplesid

So there shouldn't need to be an install script or anything like that now - the .so files are 'baked in' to the latest version of TFLite on Android. There's also a new sample for image classification that I just merged in that gets rid of needing to place your model files directly in the sample and is using a model with metadata labels instead of txt labels, so that might help you out as well.

Other than that, I'm honestly not sure :( I just ran on 10.1 without any issues, so hopefully it might even be resolved by now?

PaulTR avatar Jun 27 '23 18:06 PaulTR

I am getting this error in some devices(Galaxy S6) and some devices I am not getting this error

DSMalaviya avatar Jun 28 '23 19:06 DSMalaviya

@DSMalaviya Are you still seeing this issue with the latest version of TFLite? Also with a clean sample or MVP version of an app?

PaulTR avatar Jul 13 '23 19:07 PaulTR

@DSMalaviya Are you still seeing this issue with the latest version of TFLite? Also with a clean sample or MVP version of an app?

Yes in newer devices I am not getting error. But for older devices(Android 7 or 6) I am getting this error

DSMalaviya avatar Jul 17 '23 13:07 DSMalaviya

Just tested a newer device and seems like version 0.10.1 works for me as well (android 11)

JoseGeorges8 avatar Aug 15 '23 19:08 JoseGeorges8

I need this working on Android 6 and higher, but on Android 6 it gives me this exact error. I have tested it on Android 10 and it works. Any suggestions? I'm also happy to contribute if it is needed.

gianlucasama avatar Sep 09 '23 14:09 gianlucasama

It would be nice if this problem with older Android versions could be corrected.

In the meantime, it seems critical to me to specify in the README.md which Android version this tflite_flutter package is compatible with. Right now, no indication is given: https://pub.dev/packages/tflite_flutter

Is this Android 8+, 9+? Which API level?

andynewman10 avatar Sep 23 '23 12:09 andynewman10

Based on my tests, tflite_flutter requires API level 26 or higher (Android 8.x or later). Previous OS versions trigger the exception Failed to load dynamic library 'libtensorflowlite_jni.so', since strtod_l is not shipped with these systems.

andynewman10 avatar Oct 08 '23 13:10 andynewman10

Based on my tests, tflite_flutter requires API level 26 or higher (Android 8.x or later). Previous OS versions trigger the exception Failed to load dynamic library 'libtensorflowlite_jni.so', since strtod_l is not shipped with these systems.

Done https://github.com/tensorflow/flutter-tflite/pull/154

PaulTR avatar Oct 08 '23 15:10 PaulTR

This is great - I believe you also need to change the minSdkVersion field in https://github.com/tensorflow/flutter-tflite/blob/main/android/build.gradle and specify

minSdkVersion 26

This way, Flutter projects targeting lower OS versions will not build.

I would be more than happy to recompile libtensorflowlite_jni.so, do some testing and see how the strtod_l error can be fixed. It is probably very (even extremely) easy to avoid using this specific function and instead use something else. I already raised this point on another issue but did not get any answer. I do need some pointers to get started, since this seems quite tricky :(

andynewman10 avatar Oct 08 '23 16:10 andynewman10

Alright sorry for the delay, it's Monday now and I'm back at my computer for the day :) I'll up that minSdkVersion this morning and publish the plugin again. I'm not actually sure if we need to recompile a .so file - we're using the gradle dependency for TFLite in Android rather than including the compiled versions of TFLite in the plugin (https://github.com/tensorflow/flutter-tflite/blob/main/android/build.gradle#L66C3-L66C3). If this is a bug in core TFLite, I think the raised issue there is the correct way about it. I'll ping around to see if anyone can check into it, but I can't make any promises with priorities and work already allocated for the quarter :(

PaulTR avatar Oct 09 '23 14:10 PaulTR

Hi Paul, I investigated this a bit more.

It turns out the Gradle dependency you're using is the first version of Tensorflow Lite for Android that exhibits the incompatibility with Android versions lower than 8.

If you change the version to 2.11.0, it indeed works! You're currently using version 2.12.0. I also tried versions 2.13.0 and 2.14.0, and they all fail. It seems a problem was introduced between versions 2.11.0 and 2.12.0.

Compatibility with older Android versions is important, IMHO. I believe you should strongly consider updating your Gradle file to reflect the following change (and change the minSdkVersion value back to 21):

dependencies {
    def tflite_version = "2.12.0" // change to 2.11.0 to get rid of the libtensorflowlite_jni.so issue on Android 5/6/7
    
    implementation("org.tensorflow:tensorflow-lite:${tflite_version}")
    implementation("org.tensorflow:tensorflow-lite-gpu:${tflite_version}")
}

According to the following comment by @pjpratik , quote :

https://github.com/tensorflow/tensorflow/issues/61951#issuecomment-1738540853

Have you tried compiling the libtensorflowlite_jni.so for amr64 with the the latest TF 2.13 and nightly pull and still observe the same error?

I take it that the incompatibility is NOT desired. It is there, but it is unfortunate and was not intended.

I strongly believe this should be fixed by the Tensorflow team and in the mean time, you should consider using 2.11.0.

(Note that pytorch_lite flutter had a minSdkVersion of 24, and they recently made it 21 to support the largest range of devices)

Cc @sushreebarsa

andynewman10 avatar Oct 10 '23 08:10 andynewman10

Hi Paul, I investigated this a bit more.

It turns out the Gradle dependency you're using is the first version of Tensorflow Lite for Android that exhibits the incompatibility with Android versions lower than 8.

If you change the version to 2.11.0, it indeed works! You're currently using version 2.12.0. I also tried versions 2.13.0 and 2.14.0, and they all fail. It seems a problem was introduced between versions 2.11.0 and 2.12.0.

Compatibility with older Android versions is important, IMHO. I believe you should strongly consider updating your Gradle file to reflect the following change (and change the minSdkVersion value back to 21):

dependencies {
    def tflite_version = "2.12.0" // change to 2.11.0 to get rid of the libtensorflowlite_jni.so issue on Android 5/6/7
    
    implementation("org.tensorflow:tensorflow-lite:${tflite_version}")
    implementation("org.tensorflow:tensorflow-lite-gpu:${tflite_version}")
}

According to the following comment by @pjpratik , quote :

tensorflow/tensorflow#61951 (comment)

Have you tried compiling the libtensorflowlite_jni.so for amr64 with the the latest TF 2.13 and nightly pull and still observe the same error?

I take it that the incompatibility is NOT desired. It is there, but it is unfortunate and was not intended.

I strongly believe this should be fixed by the Tensorflow team and in the mean time, you should consider using 2.11.0.

(Note that pytorch_lite flutter had a minSdkVersion of 24, and they recently made it 21 to support the largest range of devices)

Cc @sushreebarsa

I would be very interested in this to be reverted to sdk version 21. Any news on this fix?

Thanks, Arno

arnoschn avatar Nov 07 '23 07:11 arnoschn

It seems like this is due to this plugin using tf lite 2.12 which introduced this compatibility problem reference. Anyone interested in a quick fix can use my fork with tf lite 2.11 where this should not happen.

tflite_flutter:
    git:
      url: https://github.com/CaptainDario/flutter-tflite

CaptainDario avatar Jan 12 '24 21:01 CaptainDario

I recently got the same error in Android 10, which is weird. Did anyone else experienced the same? As in, this error replicating in android 7+?

saurabhkumar8112 avatar Apr 05 '24 17:04 saurabhkumar8112

So there shouldn't need to be an install script or anything like that now - the .so files are 'baked in' to the latest version of TFLite on Android. There's also a new sample for image classification that I just merged in that gets rid of needing to place your model files directly in the sample and is using a model with metadata labels instead of txt labels, so that might help you out as well.

Other than that, I'm honestly not sure :( I just ran on 10.1 without any issues, so hopefully it might even be resolved by now?

Hi Paul. I recently tried this example without making any changes. I executed sh ./scripts/download_model.sh and utilized the resulting model. Do you believe this code will still function if I substitute the model and labels with ones I created in Google Teachable Machine, without altering the code itself? Or would I need to modify some code, such as incorporating metadata as you mentioned? I attempted to use my model, but I'm unable to view the stats now.

I exported my model to TensorFlow Lite floating point. Being new to this, I hope someone can offer assistance. Thanks.

this is my model

zyrridian avatar May 11 '24 02:05 zyrridian

It depends on the model, but you may need to make some changes to reflect input tensor size and the like. I'm not actually sure how metadata baked into the model works with this library off hand (it's been a bit since I took some time to play with it), so yeah that'd be another thing to take into consideration.

On Fri, May 10, 2024, 8:05 PM Rezky Aditia Fauzan @.***> wrote:

So there shouldn't need to be an install script or anything like that now

  • the .so files are 'baked in' to the latest version of TFLite on Android. There's also a new sample for image classification that I just merged in that gets rid of needing to place your model files directly in the sample and is using a model with metadata labels instead of txt labels, so that might help you out as well.

Other than that, I'm honestly not sure :( I just ran on 10.1 without any issues, so hopefully it might even be resolved by now?

Hi Paul. I recently tried this example https://github.com/tensorflow/flutter-tflite/tree/main/example/live_object_detection_ssd_mobilenet without making any changes. I executed sh ./scripts/download_model.sh and utilized the resulting model. Do you believe this code will still function if I substitute the model and labels with ones I created in Google Teachable Machine, without altering the code itself? Or would I need to modify some code, such as incorporating metadata as you mentioned? I attempted to use my model, but I'm unable to view the stats now.

I exported my model to TensorFlow Lite floating point. Being new to this, I hope someone can offer assistance. Thanks.

this is my model https://github.com/tensorflow/flutter-tflite/files/15281286/converted_tflite.zip

— Reply to this email directly, view it on GitHub https://github.com/tensorflow/flutter-tflite/issues/73#issuecomment-2105453875, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAR2C37B26LVSAVFS3I6WVDZBV4GBAVCNFSM6AAAAAAYVSV65KVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCMBVGQ2TGOBXGU . You are receiving this because you commented.Message ID: @.***>

PaulTR avatar May 11 '24 02:05 PaulTR

Any way to fix? Got same error on Android 11, I'm using -

  tflite_flutter: ^0.9.0
  tflite_flutter_helper:
    git:
      url: https://github.com/pnyompen/tflite_flutter_helper.git
      ref: 43e87d4b9627539266dc20250beb35bf36320dce
  image_picker: ^0.8.4+11
  path_provider: ^2.0.9
  image: ^4.0.17
  gallery_saver: ^2.3.2
  juxtapose: ^1.2.0
E/flutter (16533): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Invalid argument(s): Failed to load dynamic library 'libtensorflowlite_c.so': dlopen failed: library "libtensorflowlite_c.so" not found
E/flutter (16533): #0      _open (dart:ffi-patch/ffi_dynamic_library_patch.dart:11:43)
E/flutter (16533): #1      new DynamicLibrary.open (dart:ffi-patch/ffi_dynamic_library_patch.dart:22:12)
E/flutter (16533): #2      tflitelib.<anonymous closure> (package:tflite_flutter/src/bindings/dlib.dart:47:27)
E/flutter (16533): #3      tflitelib (package:tflite_flutter/src/bindings/dlib.dart:54:2)
E/flutter (16533): #4      tflitelib (package:tflite_flutter/src/bindings/dlib.dart)
E/flutter (16533): #5      tfLiteModelCreateFromBuffer (package:tflite_flutter/src/bindings/model.dart:25:35)
E/flutter (16533): #6      tfLiteModelCreateFromBuffer (package:tflite_flutter/src/bindings/model.dart)
E/flutter (16533): #7      new Model.fromBuffer (package:tflite_flutter/src/model.dart:51:19)
E/flutter (16533): #8      new Interpreter.fromBuffer (package:tflite_flutter/src/interpreter.dart:108:25)
E/flutter (16533): #9      Interpreter.fromAsset (package:tflite_flutter/src/interpreter.dart:127:24)
E/flutter (16533): <asynchronous suspension>
E/flutter (16533): #10     Upscaler.upscale (package:dependencytest/services/upscaler.dart:30:31)
E/flutter (16533): <asynchronous suspension>
E/flutter (16533): #11     _HomePageState.upscaleImage (package:dependencytest/view/pages/homepage.dart:37:16)
E/flutter (16533): <asynchronous suspension>

app/build.gradle:

plugins {
    id "com.android.application"
    id "kotlin-android"
    id "dev.flutter.flutter-gradle-plugin"
}

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

android {
    namespace "com.example.dependencytest"
    compileSdk 34
    ndkVersion flutter.ndkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    aaptOptions {
        noCompress 'tflite'
        noCompress 'lite'
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.dependencytest"
        // You can update the following values to match your application needs.
        // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
        minSdkVersion 26
        targetSdkVersion 34
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName

        multiDexEnabled true
    }

    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }
}

flutter {
    source '../..'
}

dependencies {
    def tflite_version = "2.12.0" // change to 2.11.0 to get rid of the libtensorflowlite_jni.so issue on Android 5/6/7

    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.7.10"
    implementation("org.tensorflow:tensorflow-lite:${tflite_version}")
    implementation("org.tensorflow:tensorflow-lite-gpu:${tflite_version}")
}

md-rifatkhan avatar May 14 '24 10:05 md-rifatkhan

This one fixed for me, run bat file it will work for android too, https://stackoverflow.com/a/72302811/20943549

md-rifatkhan avatar May 14 '24 10:05 md-rifatkhan