tensorflow / flutter-tflite

Apache License 2.0
551 stars 129 forks source link

Failed to load dynamic library 'libtensorflowlite_jni.so': #73

Open JoseGeorges8 opened 1 year ago

JoseGeorges8 commented 1 year ago

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!!

cimplesid commented 1 year ago

+1

PaulTR commented 1 year ago

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?

DSMalaviya commented 1 year ago

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

PaulTR commented 1 year ago

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

DSMalaviya commented 1 year ago

@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

JoseGeorges8 commented 1 year ago

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

gianlucasama commented 1 year ago

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.

andynewman10 commented 1 year ago

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 commented 1 year ago

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.

PaulTR commented 1 year ago

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

andynewman10 commented 1 year ago

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 :(

PaulTR commented 1 year ago

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 :(

andynewman10 commented 1 year ago

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

arnoschn commented 1 year ago

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

CaptainDario commented 10 months ago

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
saurabhkumar8112 commented 7 months ago

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+?

zyrridian commented 6 months ago

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

PaulTR commented 6 months ago

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: @.***>

md-rifatkhan commented 6 months ago

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 commented 6 months ago

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

fergushenderson commented 2 weeks ago

FYI, the underlying issue of libtensorflowlite_jni.so not supporting devices with Android version < 8.0 (i.e. Android API level < 26) was addressed in TensorFlow 2.16.1, which supports minSdkLevel 21, like TensorFlow 2.11 did.