flutter-tflite
flutter-tflite copied to clipboard
Exception has occurred. _TypeError (type 'List<double>' is not a subtype of type 'List<List<double>
hi! im trying to create a Object detection application using this repo https://github.com/tensorflow/flutter-tflite. i tried to use my custom model and it gave me a output shape error
Invalid argument(s): Output object shape mismatch, interpreter returned output of shape: [1, 10] while shape of output provided as argument in run is: [1, 10, 4]
i tried to follow the suggestion from #134
At example live object detection in file detector_service.dart we have
final output = { 0: [List<List<num>>.filled(10, List<num>.filled(4, 0))], 1: [List<num>.filled(10, 0)], 2: [List<num>.filled(10, 0)], 3: [0.0], };
It doesn't always fit. In my case, it worked with :final output = { 0: [List<num>.filled(10, 0)], 1: [List<List<num>>.filled(10, List<num>.filled(4, 0))], 2: [0.0], 3: [List<num>.filled(10, 0)], };
If we go to Kaggle in Outputs, we will find the right order.
final output = { 0: [List<num>.filled(10, 0)], 1: [List<List<num>>.filled(10, List<num>.filled(4, 0))], 2: [0.0], 3: [List<num>.filled(10, 0)], };
and right now im facing this error
Exception has occurred.
_TypeError (type 'List<double>' is not a subtype of type 'List<List<double>>' in type cast) on line 91
do you have any suggestions on how i can solve this problem?
here is the code https://paste.ofcode.org/4raUUvjbfPPcjZNSQ5Gk6J
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 3.16.5, on Microsoft Windows [Version 10.0.22621.2715], locale en-PH)
[√] Windows Version (Installed version of Windows is version 10 or higher)
[√] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.8.3)
[√] Android Studio (version 2022.3)
[√] Connected device (4 available)
[√] Network resources
• No issues found!
@occasionalcode I would say that the output’s tensors you have are in wrong order. To check for the correct tensors order you can definitely check the name of your model on Kaggle. If you still cannot find your model, please upload your tflite file on Netron. Those two ways will help you reveal the output layer with the correct tensor order. My guess is that 0’s type should be List<List< double >> . That is all the hints so far I can give you. If you have more questions, please let me know!
If you add the line
debugPrint(outputTensors.toString());
just after the line var outputTensors = getOutputTensors();
in the interpreter.dart file for the function runForMultipleInputs then you will see what is returned as outputs. In the case of the ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8 model the result is:
flutter: [Tensor{_tensor: Pointer: address=0x10bcb5450, name: StatefulPartitionedCall:1, type: float32, shape: [1, 10], data: 40}, Tensor{_tensor: Pointer: address=0x10bcb5370, name: StatefulPartitionedCall:3, type: float32, shape: [1, 10, 4], data: 160}, Tensor{_tensor: Pointer: address=0x10bcb54c0, name: StatefulPartitionedCall:0, type: float32, shape: [1], data: 4}, Tensor{_tensor: Pointer: address=0x10bcb53e0, name: StatefulPartitionedCall:2, type: float32, shape: [1, 10], data: 40}]
You can see the StatefulPartitionedCalls are not returned in order but instead are returned in the order 1,3,0,2. If you drop that particular model into Netron , you see what those stateflulPartitionCalls actually are; 0: is for the number of detected boxes 1: is for the scores of the detected boxes 2: is for the categories of the detected boxes 3: is for the locations of the detected boxes
as such final output = { 0: [List<num>.filled(10, 0)], 1: [List<List<num>>.filled(10, List<num>.filled(4, 0))], 2: [0.0], 3: [List<num>.filled(10, 0)], };
as outlined in the above comment by occasionalcode is indeed the correct order for final output tensors...
but you are not quite done yet... as the class _DetectorServer within the detector_service.dart file still needs modifications because of the altered order of outputs. Specifically
final scores = output.elementAt(2).first as List<double>;
needs to change to
final scores = output.elementAt(0).first as List<double>;
and
final locationsRaw = output.first.first as List<List<double>>;
need to change to
final locationsRaw = output.elementAt(1).first as List<List<double>>;
and
final numberOfDetectionsRaw = output.last.first as double;
needs to change to
final numberOfDetectionsRaw = output.elementAt(2).first as double;
and
final classesRaw = output.elementAt(1).first as List<double>;
needs to change to
final classesRaw = output.elementAt(3).first as List<double>;
It wasn't until I made these changes that my custom tflite model would actually detect anything.
If you add the line
debugPrint(outputTensors.toString());
just after the linevar outputTensors = getOutputTensors();
in the interpreter.dart file for the function runForMultipleInputs then you will see what is returned as outputs. In the case of the ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8 model the result is:flutter: [Tensor{_tensor: Pointer: address=0x10bcb5450, name: StatefulPartitionedCall:1, type: float32, shape: [1, 10], data: 40}, Tensor{_tensor: Pointer: address=0x10bcb5370, name: StatefulPartitionedCall:3, type: float32, shape: [1, 10, 4], data: 160}, Tensor{_tensor: Pointer: address=0x10bcb54c0, name: StatefulPartitionedCall:0, type: float32, shape: [1], data: 4}, Tensor{_tensor: Pointer: address=0x10bcb53e0, name: StatefulPartitionedCall:2, type: float32, shape: [1, 10], data: 40}]
You can see the StatefulPartitionedCalls are not returned in order but instead are returned in the order 1,3,0,2. If you drop that particular model into Netron , you see what those stateflulPartitionCalls actually are; 0: is for the number of detected boxes 1: is for the scores of the detected boxes 2: is for the categories of the detected boxes 3: is for the locations of the detected boxes
as such
final output = { 0: [List<num>.filled(10, 0)], 1: [List<List<num>>.filled(10, List<num>.filled(4, 0))], 2: [0.0], 3: [List<num>.filled(10, 0)], };
as outlined in the above comment by occasionalcode is indeed the correct order for final output tensors... but you are not quite done yet... as the class _DetectorServer within the detector_service.dart file still needs modifications because of the altered order of outputs. Specificallyfinal scores = output.elementAt(2).first as List<double>;
needs to change tofinal scores = output.elementAt(0).first as List<double>;
andfinal locationsRaw = output.first.first as List<List<double>>;
need to change tofinal locationsRaw = output.elementAt(1).first as List<List<double>>;
andfinal numberOfDetectionsRaw = output.last.first as double;
needs to change tofinal numberOfDetectionsRaw = output.elementAt(2).first as double;
andfinal classesRaw = output.elementAt(1).first as List<double>;
needs to change tofinal classesRaw = output.elementAt(3).first as List<double>;
It wasn't until I made these changes that my custom tflite model would actually detect anything.
it works for me, thanks!