diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..14452af --- /dev/null +++ b/.editorconfig @@ -0,0 +1,3 @@ +[*.md] +indent_style = space +markdown_list_style = asterisk diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 1cc1843..80b63eb 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -3,3 +3,21 @@ - When using a third-party action (one not hosted in a Google-managed org), a fixed version of the action MUST be used by [specifying a specific commit](https://help.github.com/en/github/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#jobsjob_idstepsuses), rather than a branch like "main", or a tagged release, which can be overwritten by any maintainer of the action. - Docker and [GitHub runner](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources) images should always be run at a fixed version rather than "latest". - If an action is granted additional GitHub access (by being passed the GITHUB_TOKEN variable), all main development branches (typically, "main") must use [branch protection](https://help.github.com/en/github/administering-a-repository/about-protected-branches) with "Require pull request reviews before merging" enabled and/or "Restrict who can push to matching branches" limited to repository admins. + +## Publishing to pub.dev + +The `publish.yml` workflow publishes `tflite_core` when a `v` tag is pushed. It checks that the tag matches the package version, runs formatting, analysis, tests, and a pub.dev dry run, then publishes using GitHub Actions OIDC trusted publishing. No pub.dev token is stored in GitHub secrets. + +Before using the workflow for releases: + +1. Set up and verify the `kmmhanan.com` publisher on pub.dev. +2. Publish the first `tflite_core` version manually from a signed-in user account with `flutter pub publish`. Pub does not currently allow the first version of a new package to be published directly to a verified publisher. +3. Transfer the package from your user account to the `kmmhanan.com` publisher in the package's pub.dev admin page. This transfer is irreversible. +4. Enable GitHub Actions automated publishing from the package's **Admin** page. Use repository `kmmhanan/tflite-core` and tag pattern `v{{version}}`. +5. For later versions, update the package version and changelog, then push a matching version tag. For example, with `version: 0.12.6` in `pubspec.yaml`, push `v0.12.6`. + +The GitHub repository and tag pattern are configured on pub.dev; no workflow filename, GitHub secret, pub.dev API key, or GitHub environment is required for this workflow. See the [pub.dev automated publishing guide](https://dart.dev/tools/pub/automated-publishing). + +To create a GitHub Release and trigger the publish workflow manually, run **Actions → Create release → Run workflow** on the `main` branch. It reads the version from `pubspec.yaml`, creates and pushes the corresponding `v` tag, then creates a GitHub Release with generated notes. The tag push triggers `publish.yml`. + +This workflow uses a repository secret named `RELEASE_TOKEN` so pushing its tag triggers other workflows (GitHub suppresses those triggers when using the default `GITHUB_TOKEN`). Create a fine-grained personal access token scoped to this repository with **Contents: Read and write**, then add it under **Settings → Secrets and variables → Actions**. The token does not authenticate to pub.dev; pub.dev publishing still uses OIDC trusted publishing. Only trusted users should be able to run this release workflow. diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml new file mode 100644 index 0000000..42acd19 --- /dev/null +++ b/.github/workflows/create-release.yml @@ -0,0 +1,113 @@ +name: Create Release +run-name: Create Release for v${{ inputs.version }} + +on: + workflow_dispatch: + inputs: + version: + description: Package version from pubspec.yaml, without the v prefix + required: true + type: string + +permissions: + contents: write + +concurrency: + group: create-release + cancel-in-progress: false + +jobs: + release: + runs-on: ubuntu-24.04 + steps: + - name: Require main branch + if: github.ref != 'refs/heads/main' + run: | + echo "Run this workflow from the main branch." + exit 1 + + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab + with: + ref: main + token: ${{ secrets.RELEASE_TOKEN }} + fetch-depth: 0 + + - name: Validate release version + id: version + shell: bash + env: + RELEASE_VERSION: ${{ inputs.version }} + run: | + package_name=$(sed -n 's/^name: *//p' pubspec.yaml | tr -d "\"'") + package_version=$(sed -n 's/^version: *//p' pubspec.yaml | tr -d "\"'") + if [[ "$package_name" != "tflite_core" ]]; then + echo "Expected package name 'tflite_core', got '$package_name'." + exit 1 + fi + if [[ ! "$package_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+([+-][0-9A-Za-z.-]+)?$ ]]; then + echo "Invalid package version: '$package_version'." + exit 1 + fi + if [[ "$RELEASE_VERSION" != "$package_version" ]]; then + echo "Requested version '$RELEASE_VERSION' does not match pubspec.yaml version '$package_version'." + exit 1 + fi + version_gt() { + local candidate="${1%%+*}" + local previous="${2%%+*}" + local candidate_prerelease="" + local previous_prerelease="" + if [[ "$candidate" == *-* ]]; then + candidate_prerelease="${candidate#*-}" + candidate="${candidate%%-*}" + fi + if [[ "$previous" == *-* ]]; then + previous_prerelease="${previous#*-}" + previous="${previous%%-*}" + fi + local candidate_major candidate_minor candidate_patch + local previous_major previous_minor previous_patch + IFS=. read -r candidate_major candidate_minor candidate_patch <<< "$candidate" + IFS=. read -r previous_major previous_minor previous_patch <<< "$previous" + if ((10#$candidate_major != 10#$previous_major)); then + ((10#$candidate_major > 10#$previous_major)) + return + fi + if ((10#$candidate_minor != 10#$previous_minor)); then + ((10#$candidate_minor > 10#$previous_minor)) + return + fi + if ((10#$candidate_patch != 10#$previous_patch)); then + ((10#$candidate_patch > 10#$previous_patch)) + return + fi + [[ -n "$previous_prerelease" && -z "$candidate_prerelease" ]] + } + tag="v$package_version" + latest_version=$(git tag --list 'v[0-9]*' --sort=-version:refname | head -n 1 | sed 's/^v//') + if [[ -n "$latest_version" ]]; then + if ! version_gt "$package_version" "$latest_version"; then + echo "Skipping release: '$package_version' is not newer than the latest release '$latest_version'." + echo "release=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + fi + echo "release=true" >> "$GITHUB_OUTPUT" + echo "tag=$tag" >> "$GITHUB_OUTPUT" + + - name: Create and push version tag + if: steps.version.outputs.release == 'true' + env: + RELEASE_TAG: ${{ steps.version.outputs.tag }} + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git tag -a "$RELEASE_TAG" -m "Release $RELEASE_TAG" + git push origin "$RELEASE_TAG" + + - name: Create GitHub Release + if: steps.version.outputs.release == 'true' + env: + GH_TOKEN: ${{ secrets.RELEASE_TOKEN }} + RELEASE_TAG: ${{ steps.version.outputs.tag }} + run: gh release create "$RELEASE_TAG" --verify-tag --title "tflite_core $RELEASE_TAG" --generate-notes diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..f7b6f51 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,109 @@ +name: Publish to pub.dev +run-name: ${{ github.ref_name }} + +on: + push: + tags: + - 'v*' + +permissions: + contents: read + id-token: write + +concurrency: + group: publish-${{ github.ref }} + cancel-in-progress: false + +jobs: + publish: + runs-on: macos-15 + steps: + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab + with: + fetch-depth: 0 + + - name: Verify release tag + id: version + shell: bash + run: | + package_version=$(sed -n 's/^version: *//p' pubspec.yaml | tr -d "\"'") + if [[ -z "$package_version" || "$GITHUB_REF_NAME" != "v$package_version" ]]; then + echo "Release tag '$GITHUB_REF_NAME' must match pubspec.yaml version 'v$package_version'." + exit 1 + fi + version_gt() { + local candidate="${1%%+*}" + local previous="${2%%+*}" + local candidate_prerelease="" + local previous_prerelease="" + if [[ "$candidate" == *-* ]]; then + candidate_prerelease="${candidate#*-}" + candidate="${candidate%%-*}" + fi + if [[ "$previous" == *-* ]]; then + previous_prerelease="${previous#*-}" + previous="${previous%%-*}" + fi + local candidate_major candidate_minor candidate_patch + local previous_major previous_minor previous_patch + IFS=. read -r candidate_major candidate_minor candidate_patch <<< "$candidate" + IFS=. read -r previous_major previous_minor previous_patch <<< "$previous" + if ((10#$candidate_major != 10#$previous_major)); then + ((10#$candidate_major > 10#$previous_major)) + return + fi + if ((10#$candidate_minor != 10#$previous_minor)); then + ((10#$candidate_minor > 10#$previous_minor)) + return + fi + if ((10#$candidate_patch != 10#$previous_patch)); then + ((10#$candidate_patch > 10#$previous_patch)) + return + fi + [[ -n "$previous_prerelease" && -z "$candidate_prerelease" ]] + } + latest_version=$(git tag --list 'v[0-9]*' --sort=-version:refname | grep -Fxv "$GITHUB_REF_NAME" | head -n 1 | sed 's/^v//') + if [[ -n "$latest_version" ]]; then + if ! version_gt "$package_version" "$latest_version"; then + echo "Skipping publish: '$package_version' is not newer than the latest release '$latest_version'." + echo "publish=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + fi + echo "publish=true" >> "$GITHUB_OUTPUT" + + - uses: subosito/flutter-action@48cafc24713cca54bbe03cdc3a423187d413aafa + if: steps.version.outputs.publish == 'true' + with: + channel: stable + cache: true + cache-key: flutter-:os:-:channel:-:version:-:arch:- + + - uses: dart-lang/setup-dart@23b5a66dd43e5c8366051dd2dde53e89fa2ef1ea + if: steps.version.outputs.publish == 'true' + with: + problem-matcher: false + + - name: Install dependencies + if: steps.version.outputs.publish == 'true' + run: flutter pub get + + - name: Verify formatting + if: steps.version.outputs.publish == 'true' + run: dart format --output=none --set-exit-if-changed lib test + + - name: Analyze + if: steps.version.outputs.publish == 'true' + run: flutter analyze lib test + + - name: Test + if: steps.version.outputs.publish == 'true' + run: flutter test + + - name: Validate package + if: steps.version.outputs.publish == 'true' + run: flutter pub publish --dry-run + + - name: Publish to pub.dev + if: steps.version.outputs.publish == 'true' + run: flutter pub publish --force diff --git a/.gitignore b/.gitignore index 593d1f6..8cce5dd 100644 --- a/.gitignore +++ b/.gitignore @@ -84,6 +84,28 @@ example/object_detection_ssd_mobilenet/assets/models/ssd_mobilenet.tflite **/assets/models/!README **/assets/models/.gitkeep +# Keep checked-in example assets visible to pub's package validation. +!example/audio_classification/assets/models/ +!example/image_classification_mobilenet/assets/models/ +!example/live_object_detection_ssd_mobilenet/assets/models/ +!example/object_detection_ssd_mobilenet/assets/models/ +!example/reinforcement_learning/assets/models/ +!example/style_transfer/assets/models/ +!example/super_resolution_esrgan/assets/models/ +!example/text_classification/assets/models/ +!example/audio_classification/assets/models/README.md +!example/audio_classification/assets/models/yamnet.tflite +!example/audio_classification/assets/models/yamnet_label_list.txt +!example/image_classification_mobilenet/assets/models/README.md +!example/image_classification_mobilenet/assets/models/labels.txt +!example/image_classification_mobilenet/assets/models/mobilenet_quant.tflite +!example/live_object_detection_ssd_mobilenet/assets/models/README.md +!example/object_detection_ssd_mobilenet/assets/models/README.md +!example/reinforcement_learning/assets/models/README.md +!example/style_transfer/assets/models/README.md +!example/super_resolution_esrgan/assets/models/README.md +!example/text_classification/assets/models/README.md + # FVM Version Cache .fvm/ .fvmrc diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3f6bfc7 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,46 @@ +{ + "editor.formatOnSave": false, + "cSpell.words": [ + "ARCHS", + "argmax", + "codesign", + "DCMAKE", + "dlsym", + "dyld", + "esrgan", + "ffigen", + "FMWK", + "Garg", + "initialising", + "iphonesimulator", + "jank", + "kewlbear", + "libtensorflowlite", + "lipo", + "logit", + "logits", + "mobilenet", + "NNAPI", + "otool", + "podspec", + "probs", + "pthreadpool", + "pubspec", + "Relu", + "Rfft", + "Rsqrt", + "RTLD", + "Schyler", + "Softmax", + "statefulness", + "Strided", + "Svdf", + "tflite", + "TFLM", + "xcconfig", + "xcframework", + "XCFW", + "XFWK", + "xnnpack" + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f49aa90..3dd7057 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,37 @@ +## 0.12.11 (October 16, 2026) +- Restored the standard versioned macOS framework layout, with `Info.plist` under `Versions/A/Resources` as required by Xcode. +- Moved the macOS framework `Info.plist` to the framework root; corrected to the required versioned location in 0.12.13. +- Rebuilt the macOS framework using a flat layout without versioned symlinks. + +## 0.12.10 (October 16, 2026) +- Fixed iOS and macOS Swift Package Manager integration by exporting the `tflite-core` product required by Flutter's generated plugin package. + +## 0.12.9 (October 16, 2026) +- Expanded public API documentation and added a package example. +- Fixed half-precision float byte decoding and added a regression test. + +## 0.12.8 (October 16, 2026) +- Renamed the public Dart entrypoints and platform package files to use the `tflite_core` name. +- Updated example imports, platform package references, and documentation to match the new package name. + +## 0.12.7 (October 16, 2026) +- Example references updated. + +## 0.12.6 (October 15, 2026) +- Package documentation updated. + +## 0.12.5 (October 15, 2026) +- **NEW IDENTITY**: This package converted from "tflite_flutter" to "tflite_core". + +## 0.12.4 (July 30, 2026) +- **Critical**: Resolved Flutter Kotlin Gradle Plugin (KGP) deprecated warning. + +## 0.12.3 (June 6, 2026) +- **Critical**: Resolved Flutter Kotlin capability issues causing build failures. +- **Critical**: Added full Swift Package Manager (SPM) support for iOS/macOS plugins. +- Verified support for Flutter `3.44.0` across Android and iOS. + + ## 0.12.1 (October 28, 2025) * **CRITICAL FIX**: Properly implement Android 16KB page size support * Migrated from TensorFlow Lite 2.12.0 to Google AI Edge LiteRT 1.4.0 @@ -23,7 +57,7 @@ * Various bug fixes ## 0.10.0 (May 22, 2023) -* Use ffi for binding to iOS dependencies. Use the ios/tflite_flutter.podspec file to specify tensorflow lite library version. Dependencies are automatically downloaded without user intervention (no need for releases/download folder) +* Use ffi for binding to iOS dependencies. Use the ios/tflite_core.podspec file to specify tensorflow lite library version. Dependencies are automatically downloaded without user intervention (no need for releases/download folder) * Use ffi for binding with Android dependencies. Use the android/build.gradle file to specify tensorflow lite library version. Dependencies are automatically downloaded without user intervention (no need for releases/download folder) * Use ffigen to generate the binding code in dart * Enable delegates in text_classification example diff --git a/README.md b/README.md index 0d3bd90..5544460 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@


- +

@@ -9,11 +9,11 @@ Platform - - + Pub Package - + Docs @@ -23,18 +23,14 @@ ## Announcement -Update: 26 April, 2023 +Update: 16 October, 2026 -This repo is a TensorFlow managed fork of the [tflite_flutter_plugin](https://github.com/am15h/tflite_flutter_plugin) project by the amazing Amish Garg. The goal of this project is to support our Flutter community in creating machine-learning backed apps with the TensorFlow Lite framework. +Originally created by PaulTR as [tflite_flutter_plugin](https://github.com/am15h/tflite_flutter_plugin), the project later continued as `tflite_flutter` and is now `tflite_core`, maintained by [KmmHanan](https://github.com/kmmhanan). The goal remains to support the Flutter community in creating machine-learning-backed apps with TensorFlow Lite. -This project is currently a work-in-progress as we update it to create a working plugin that meets the latest and greatest Flutter and TensorFlow Lite standards. That said, *pull requests and contributions are more than welcome* and will be reviewed by TensorFlow or Flutter team members. We thank you for your understanding as we make progress on this update. +The project continues to evolve to meet current Flutter and TensorFlow Lite standards. Pull requests and contributions are welcome. Feel free to reach out to us by posting in the issues or discussion areas. -Thanks! - -- PaulTR - ## Overview TensorFlow Lite Flutter plugin provides a flexible and fast solution for accessing TensorFlow Lite interpreter and performing inference. The API is similar to the TFLite Java and Swift APIs. It directly binds to TFLite C API making it efficient (low-latency). Offers acceleration support using NNAPI, GPU delegates on Android, Metal and CoreML delegates on iOS, and XNNPack delegate on Desktop platforms. @@ -130,19 +126,19 @@ install( ## TFLite Flutter Helper Library -The helper library has been deprecated. New development underway for a replacement at . Current timeline is to have wide support by the end of August, 2023. +The helper library has been deprecated. New development is underway for a replacement at [Google's Flutter MediaPipe project](https://github.com/google/flutter-mediapipe). The current timeline is to have wide support by the end of August, 2023. ## Import ```dart -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; ``` ## Usage instructions ### Import the libraries -In the dependency section of `pubspec.yaml` file, add `tflite_flutter: ^0.10.1` (adjust the version accordingly based on the latest release) +In the dependency section of `pubspec.yaml` file, add `tflite_core: ^0.12.5` (adjust the version accordingly based on the latest release) ### Creating the Interpreter @@ -178,7 +174,7 @@ Refer to the documentation for info on creating interpreter from buffer or file. - **For multiple inputs and outputs** - Use `void runForMultipleInputs(List inputs, Map outputs)`. + Use `runForMultipleInputs` with a list of inputs and a map from output indexes to output values. ```dart var input0 = [1.23]; diff --git a/analysis_options.yaml b/analysis_options.yaml index 86bb455..5fd31d3 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -25,6 +25,19 @@ linter: constant_identifier_names: false # avoid_print: false # Uncomment to disable the `avoid_print` rule # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +formatter: + page_width: 100 + trailing_commas: preserve + analyzer: + exclude: + - example/** + - build/** + - android/** + - ios/** + - windows/** + - macos/** + - linux/** # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options diff --git a/android/build.gradle b/android/build.gradle index f664466..75f68af 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -12,6 +12,7 @@ buildscript { dependencies { // The Android Gradle Plugin knows how to build native code with the NDK. classpath 'com.android.tools.build:gradle:8.6.1' + classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.20' } } @@ -39,14 +40,7 @@ android { externalNativeBuild { // cmake { // path "../src/CMakeLists.txt" - - // // The default CMake version for the Android Gradle Plugin is 3.10.2. - // // https://developer.android.com/studio/projects/install-ndk#vanilla_cmake - // // - // // The Flutter tooling requires that developers have CMake 3.10 or later - // // installed. You should not increase this version, as doing so will cause - // // the plugin to fail to compile for some customers of the plugin. - // // version "3.10.2" + // version "3.10.2" // } } @@ -57,14 +51,19 @@ android { defaultConfig { minSdkVersion 19 - } } +kotlin { + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11 + } +} dependencies { def litert_version = "1.4.0" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.20" implementation("com.google.ai.edge.litert:litert:${litert_version}") implementation("com.google.ai.edge.litert:litert-gpu:${litert_version}") -} +} \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle index e34b994..6d889b9 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1 +1 @@ -rootProject.name = 'tflite_flutter' +rootProject.name = 'tflite_core' diff --git a/doc/tflite_flutter_cover.png b/doc/tflite_core_cover.png similarity index 100% rename from doc/tflite_flutter_cover.png rename to doc/tflite_core_cover.png diff --git a/example/audio_classification/lib/helper/audio_classification_helper.dart b/example/audio_classification/lib/helper/audio_classification_helper.dart index 6cf8829..15ec4a3 100644 --- a/example/audio_classification/lib/helper/audio_classification_helper.dart +++ b/example/audio_classification/lib/helper/audio_classification_helper.dart @@ -18,7 +18,7 @@ import 'dart:developer'; import 'dart:typed_data'; import 'package:flutter/services.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; class AudioClassificationHelper { static const _modelPath = 'assets/models/yamnet.tflite'; diff --git a/example/audio_classification/linux/flutter/generated_plugins.cmake b/example/audio_classification/linux/flutter/generated_plugins.cmake index cf3f2cb..6002230 100644 --- a/example/audio_classification/linux/flutter/generated_plugins.cmake +++ b/example/audio_classification/linux/flutter/generated_plugins.cmake @@ -6,7 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/audio_classification/pubspec.yaml b/example/audio_classification/pubspec.yaml index 50bc5a8..89bdefe 100644 --- a/example/audio_classification/pubspec.yaml +++ b/example/audio_classification/pubspec.yaml @@ -30,7 +30,7 @@ environment: dependencies: flutter: sdk: flutter - tflite_flutter: + tflite_core: path: ../../ # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. diff --git a/example/audio_classification/windows/flutter/generated_plugins.cmake b/example/audio_classification/windows/flutter/generated_plugins.cmake index 6ac6cfe..4b6fc0a 100644 --- a/example/audio_classification/windows/flutter/generated_plugins.cmake +++ b/example/audio_classification/windows/flutter/generated_plugins.cmake @@ -6,7 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/bertqa/lib/ml/qa_client.dart b/example/bertqa/lib/ml/qa_client.dart index 4a11088..4d313d2 100644 --- a/example/bertqa/lib/ml/qa_client.dart +++ b/example/bertqa/lib/ml/qa_client.dart @@ -18,7 +18,7 @@ import 'dart:collection'; import 'dart:developer'; import 'package:flutter/services.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; import 'feature.dart'; import 'feature_convert.dart'; diff --git a/example/bertqa/pubspec.yaml b/example/bertqa/pubspec.yaml index a376084..0921e65 100644 --- a/example/bertqa/pubspec.yaml +++ b/example/bertqa/pubspec.yaml @@ -30,7 +30,7 @@ environment: dependencies: flutter: sdk: flutter - tflite_flutter: + tflite_core: path: ../../ # The following adds the Cupertino Icons font to your application. diff --git a/example/digit_classification/lib/helper/digit_classifier_helper.dart b/example/digit_classification/lib/helper/digit_classifier_helper.dart index 0dde2c4..0c8487e 100644 --- a/example/digit_classification/lib/helper/digit_classifier_helper.dart +++ b/example/digit_classification/lib/helper/digit_classifier_helper.dart @@ -15,7 +15,7 @@ */ import 'package:flutter/services.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; import 'package:image/image.dart' as img; class DigitClassifierHelper { diff --git a/example/digit_classification/pubspec.yaml b/example/digit_classification/pubspec.yaml index 8a0aa0b..d852f1b 100644 --- a/example/digit_classification/pubspec.yaml +++ b/example/digit_classification/pubspec.yaml @@ -30,7 +30,7 @@ environment: dependencies: flutter: sdk: flutter - tflite_flutter: + tflite_core: path: ../../ image: 4.0.17 diff --git a/example/example.dart b/example/example.dart new file mode 100644 index 0000000..c8b817f --- /dev/null +++ b/example/example.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; +import 'package:tflite_core/tflite_core.dart'; + +Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + + // Add a float32 model with input shape [1, 5] and output shape [1, 2] + // to assets/model.tflite and declare it in the Flutter app's pubspec.yaml. + final interpreter = await Interpreter.fromAsset('assets/model.tflite'); + try { + final input = [ + [1.23, 6.54, 7.81, 3.21, 2.22] + ]; + final output = List.filled(2, 0).reshape([1, 2]); + + interpreter.run(input, output); + debugPrint(output.toString()); + } finally { + interpreter.close(); + } +} diff --git a/example/gesture_classification/lib/helper/gesture_classification_helper.dart b/example/gesture_classification/lib/helper/gesture_classification_helper.dart index 8d24d5e..9d806ce 100644 --- a/example/gesture_classification/lib/helper/gesture_classification_helper.dart +++ b/example/gesture_classification/lib/helper/gesture_classification_helper.dart @@ -18,7 +18,7 @@ import 'dart:isolate'; import 'package:camera/camera.dart'; import 'package:flutter/services.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; import 'isolate_inference.dart'; class GestureClassificationHelper { diff --git a/example/gesture_classification/lib/helper/isolate_inference.dart b/example/gesture_classification/lib/helper/isolate_inference.dart index 84fb09f..0e25825 100644 --- a/example/gesture_classification/lib/helper/isolate_inference.dart +++ b/example/gesture_classification/lib/helper/isolate_inference.dart @@ -19,7 +19,7 @@ import 'dart:isolate'; import 'package:camera/camera.dart'; import 'package:image/image.dart' as image_lib; import 'package:gesture_classification/image_utils.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; class IsolateInference { static const String _debugName = "TFLITE_INFERENCE"; diff --git a/example/gesture_classification/pubspec.yaml b/example/gesture_classification/pubspec.yaml index 21e52f2..ffcc0c1 100644 --- a/example/gesture_classification/pubspec.yaml +++ b/example/gesture_classification/pubspec.yaml @@ -32,7 +32,7 @@ dependencies: sdk: flutter image: ^4.0.17 camera: ^0.10.5+2 - tflite_flutter: + tflite_core: path: ../../ diff --git a/example/image_classification_mobilenet/lib/helper/image_classification_helper.dart b/example/image_classification_mobilenet/lib/helper/image_classification_helper.dart index 625c765..3f3d144 100644 --- a/example/image_classification_mobilenet/lib/helper/image_classification_helper.dart +++ b/example/image_classification_mobilenet/lib/helper/image_classification_helper.dart @@ -21,7 +21,7 @@ import 'dart:isolate'; import 'package:camera/camera.dart'; import 'package:flutter/services.dart'; import 'package:image/image.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; import 'isolate_inference.dart'; diff --git a/example/image_classification_mobilenet/lib/helper/isolate_inference.dart b/example/image_classification_mobilenet/lib/helper/isolate_inference.dart index 53867c4..bb0ac92 100644 --- a/example/image_classification_mobilenet/lib/helper/isolate_inference.dart +++ b/example/image_classification_mobilenet/lib/helper/isolate_inference.dart @@ -19,7 +19,7 @@ import 'dart:isolate'; import 'package:camera/camera.dart'; import 'package:image/image.dart' as image_lib; import 'package:image_classification_mobilenet/image_utils.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; class IsolateInference { static const String _debugName = "TFLITE_INFERENCE"; diff --git a/example/image_classification_mobilenet/linux/flutter/generated_plugins.cmake b/example/image_classification_mobilenet/linux/flutter/generated_plugins.cmake index 3a71460..cf9bcb5 100644 --- a/example/image_classification_mobilenet/linux/flutter/generated_plugins.cmake +++ b/example/image_classification_mobilenet/linux/flutter/generated_plugins.cmake @@ -7,7 +7,8 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + jni + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/image_classification_mobilenet/pubspec.yaml b/example/image_classification_mobilenet/pubspec.yaml index 9b2a9f2..5953819 100644 --- a/example/image_classification_mobilenet/pubspec.yaml +++ b/example/image_classification_mobilenet/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: path: ^1.8.3 path_provider: ^2.0.15 image_picker: ^0.8.8 - tflite_flutter: + tflite_core: path: ../../ dev_dependencies: diff --git a/example/image_classification_mobilenet/windows/flutter/generated_plugins.cmake b/example/image_classification_mobilenet/windows/flutter/generated_plugins.cmake index 00cdb12..8326b89 100644 --- a/example/image_classification_mobilenet/windows/flutter/generated_plugins.cmake +++ b/example/image_classification_mobilenet/windows/flutter/generated_plugins.cmake @@ -7,7 +7,8 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + jni + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/image_segmentation/lib/helper/image_segmentation_helper.dart b/example/image_segmentation/lib/helper/image_segmentation_helper.dart index 8419917..35ef7d1 100644 --- a/example/image_segmentation/lib/helper/image_segmentation_helper.dart +++ b/example/image_segmentation/lib/helper/image_segmentation_helper.dart @@ -17,7 +17,7 @@ import 'package:camera/camera.dart'; import 'package:flutter/services.dart'; import 'package:image_segmentation/helper/isolate_inference.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; import 'dart:isolate'; class ImageSegmentationHelper { diff --git a/example/image_segmentation/lib/helper/isolate_inference.dart b/example/image_segmentation/lib/helper/isolate_inference.dart index 63aee66..b2d7179 100644 --- a/example/image_segmentation/lib/helper/isolate_inference.dart +++ b/example/image_segmentation/lib/helper/isolate_inference.dart @@ -18,7 +18,7 @@ import 'dart:io'; import 'dart:isolate'; import 'package:camera/camera.dart'; import 'package:image/image.dart' as image_lib; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; import '../image_utils.dart'; diff --git a/example/image_segmentation/pubspec.yaml b/example/image_segmentation/pubspec.yaml index 731d2b5..b86134b 100644 --- a/example/image_segmentation/pubspec.yaml +++ b/example/image_segmentation/pubspec.yaml @@ -30,7 +30,7 @@ environment: dependencies: flutter: sdk: flutter - tflite_flutter: + tflite_core: path: ../../ image: ^4.0.17 camera: ^0.10.5+2 diff --git a/example/integration_test/README.md b/example/integration_test/README.md new file mode 100644 index 0000000..80b3e0e --- /dev/null +++ b/example/integration_test/README.md @@ -0,0 +1,9 @@ +## How to use this Integration Test + +- Install the package `tflite_core: ^0.12.7`, +- First copy this `integration_test` folder into flutter project root. + +- Run this command into your project ROOT (iOS/MacOS) +```bash +flutter test integration_test/tflite_linking_test.dart -d +``` \ No newline at end of file diff --git a/example/integration_test/tflite_linking_test.dart b/example/integration_test/tflite_linking_test.dart new file mode 100644 index 0000000..0230c40 --- /dev/null +++ b/example/integration_test/tflite_linking_test.dart @@ -0,0 +1,121 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:tflite_core/tflite_core.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + // ── Interpreter creation ─────────────────────────────────────────────────── + // If TensorFlowLiteC.xcframework is not linked by SPM, every test here + // throws: dlsym(RTLD_DEFAULT): symbol not found for 'TfLiteModelCreate' + // All 6 tests passing confirms the SPM Package.swift fix is working. + + group('TFLite interpreter', () { + testWidgets('loads from asset model without crashing', (tester) async { + await tester.pumpWidget(const MaterialApp(home: SizedBox.shrink())); + + Interpreter? interpreter; + Object? error; + try { + interpreter = await Interpreter.fromAsset( + 'assets/model/nlu_model.tflite', + ); + } catch (e) { + error = e; + } + + expect(error, isNull, reason: 'Interpreter.fromAsset threw: $error'); + expect(interpreter, isNotNull); + interpreter?.close(); + }); + + testWidgets('input and output tensors are accessible', (tester) async { + await tester.pumpWidget(const MaterialApp(home: SizedBox.shrink())); + + final interpreter = await Interpreter.fromAsset( + 'assets/model/nlu_model.tflite', + ); + expect(interpreter.getInputTensors(), isNotEmpty); + expect(interpreter.getOutputTensors(), isNotEmpty); + interpreter.close(); + }); + + testWidgets('input tensor has expected shape [1, 16]', (tester) async { + await tester.pumpWidget(const MaterialApp(home: SizedBox.shrink())); + + final interpreter = await Interpreter.fromAsset( + 'assets/model/nlu_model.tflite', + ); + final shape = interpreter.getInputTensor(0).shape; + expect(shape.length, 2); + expect(shape[0], 1); + expect(shape[1], 16); + interpreter.close(); + }); + + testWidgets('output tensor count matches model (2 outputs)', (tester) async { + await tester.pumpWidget(const MaterialApp(home: SizedBox.shrink())); + + final interpreter = await Interpreter.fromAsset( + 'assets/model/nlu_model.tflite', + ); + expect(interpreter.getOutputTensors().length, 2); + interpreter.close(); + }); + + testWidgets('runs inference without throwing', (tester) async { + await tester.pumpWidget(const MaterialApp(home: SizedBox.shrink())); + + final interpreter = await Interpreter.fromAsset( + 'assets/model/nlu_model.tflite', + ); + + const maxLen = 16; + const numIntents = 11; + const numEntities = 15; + + final input = [List.filled(maxLen, 0)]; + final intentOut = List.filled(numIntents, 0.0).reshape([1, numIntents]); + final entityOut = List.filled(maxLen * numEntities, 0.0).reshape([1, maxLen, numEntities]); + + Object? error; + try { + interpreter.runForMultipleInputs( + [input], + {0: intentOut, 1: entityOut}, + ); + } catch (e) { + error = e; + } + + expect(error, isNull, reason: 'runForMultipleInputs threw: $error'); + + final intentProbs = (intentOut[0] as List).cast(); + expect(intentProbs.length, numIntents); + expect( + intentProbs.any((v) => v != 0.0), + isTrue, + reason: 'Intent output is all zeros — inference may not have run', + ); + + interpreter.close(); + }); + }); + + // ── Memory management ────────────────────────────────────────────────────── + + group('Interpreter memory management', () { + testWidgets('multiple open/close cycles do not crash', (tester) async { + await tester.pumpWidget(const MaterialApp(home: SizedBox.shrink())); + + for (var i = 0; i < 3; i++) { + final interpreter = await Interpreter.fromAsset( + 'assets/model/nlu_model.tflite', + ); + interpreter.close(); + } + expect(true, isTrue); + }); + }); +} diff --git a/example/live_object_detection_ssd_mobilenet/README.md b/example/live_object_detection_ssd_mobilenet/README.md index 5c8ed98..d40d788 100644 --- a/example/live_object_detection_ssd_mobilenet/README.md +++ b/example/live_object_detection_ssd_mobilenet/README.md @@ -8,7 +8,7 @@ Live object detection example following [this](https://www.tensorflow.org/lite/e ## Overview -This application is a simple demonstration of the [tflite_flutter](https://pub.dev/packages/tflite_flutter) package. +This application is a simple demonstration of the [tflite_core](https://pub.dev/packages/tflite_core) package. Object detection applies on an image stream from camera (portrait mode only for the showcase purpose). All expensive and heavy operations are performed in a separate background isolate. diff --git a/example/live_object_detection_ssd_mobilenet/lib/service/detector_service.dart b/example/live_object_detection_ssd_mobilenet/lib/service/detector_service.dart index 2c89f79..4f3f22a 100644 --- a/example/live_object_detection_ssd_mobilenet/lib/service/detector_service.dart +++ b/example/live_object_detection_ssd_mobilenet/lib/service/detector_service.dart @@ -12,7 +12,7 @@ import 'package:flutter/services.dart'; import 'package:image/image.dart' as image_lib; import 'package:live_object_detection_ssd_mobilenet/models/recognition.dart'; import 'package:live_object_detection_ssd_mobilenet/utils/image_utils.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; /////////////////////////////////////////////////////////////////////////////// // **WARNING:** This is not production code and is only intended to be used for diff --git a/example/live_object_detection_ssd_mobilenet/linux/flutter/generated_plugins.cmake b/example/live_object_detection_ssd_mobilenet/linux/flutter/generated_plugins.cmake index 3a71460..cf9bcb5 100644 --- a/example/live_object_detection_ssd_mobilenet/linux/flutter/generated_plugins.cmake +++ b/example/live_object_detection_ssd_mobilenet/linux/flutter/generated_plugins.cmake @@ -7,7 +7,8 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + jni + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/live_object_detection_ssd_mobilenet/pubspec.yaml b/example/live_object_detection_ssd_mobilenet/pubspec.yaml index 0442639..890cbcf 100644 --- a/example/live_object_detection_ssd_mobilenet/pubspec.yaml +++ b/example/live_object_detection_ssd_mobilenet/pubspec.yaml @@ -34,7 +34,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.5 - tflite_flutter: + tflite_core: path: ../../ camera: ^0.10.5+2 image: ^4.0.17 diff --git a/example/live_object_detection_ssd_mobilenet/windows/flutter/generated_plugins.cmake b/example/live_object_detection_ssd_mobilenet/windows/flutter/generated_plugins.cmake index 00cdb12..8326b89 100644 --- a/example/live_object_detection_ssd_mobilenet/windows/flutter/generated_plugins.cmake +++ b/example/live_object_detection_ssd_mobilenet/windows/flutter/generated_plugins.cmake @@ -7,7 +7,8 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + jni + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/object_detection_ssd_mobilenet/README.md b/example/object_detection_ssd_mobilenet/README.md index 55b5363..45feead 100644 --- a/example/object_detection_ssd_mobilenet/README.md +++ b/example/object_detection_ssd_mobilenet/README.md @@ -9,7 +9,7 @@ A object detection example following [this](https://www.tensorflow.org/lite/exam ## Overview -This application is a simple demonstration of the [tflite_flutter](https://pub.dev/packages/tflite_flutter) package. +This application is a simple demonstration of the [tflite_core](https://pub.dev/packages/tflite_core) package. After taking a photo or choosing an image from your gallery, the app takes a short period of time before displaying the image with the detected objects on the screen. diff --git a/example/object_detection_ssd_mobilenet/lib/object_detection.dart b/example/object_detection_ssd_mobilenet/lib/object_detection.dart index 73e653c..09eeaa1 100644 --- a/example/object_detection_ssd_mobilenet/lib/object_detection.dart +++ b/example/object_detection_ssd_mobilenet/lib/object_detection.dart @@ -17,7 +17,7 @@ import 'dart:developer'; import 'dart:io'; import 'package:flutter/services.dart'; import 'package:image/image.dart' as img; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; class ObjectDetection { static const String _modelPath = 'assets/models/ssd_mobilenet.tflite'; diff --git a/example/object_detection_ssd_mobilenet/linux/flutter/generated_plugins.cmake b/example/object_detection_ssd_mobilenet/linux/flutter/generated_plugins.cmake index 3a71460..163c995 100644 --- a/example/object_detection_ssd_mobilenet/linux/flutter/generated_plugins.cmake +++ b/example/object_detection_ssd_mobilenet/linux/flutter/generated_plugins.cmake @@ -7,7 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/object_detection_ssd_mobilenet/pubspec.yaml b/example/object_detection_ssd_mobilenet/pubspec.yaml index f26a427..c623bdb 100644 --- a/example/object_detection_ssd_mobilenet/pubspec.yaml +++ b/example/object_detection_ssd_mobilenet/pubspec.yaml @@ -34,7 +34,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 - tflite_flutter: + tflite_core: path: ../../ image_picker: ^0.8.8 image: ^4.0.17 diff --git a/example/object_detection_ssd_mobilenet/windows/flutter/generated_plugins.cmake b/example/object_detection_ssd_mobilenet/windows/flutter/generated_plugins.cmake index 00cdb12..03a1d9c 100644 --- a/example/object_detection_ssd_mobilenet/windows/flutter/generated_plugins.cmake +++ b/example/object_detection_ssd_mobilenet/windows/flutter/generated_plugins.cmake @@ -7,7 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/object_detection_ssd_mobilenet_v2/README.md b/example/object_detection_ssd_mobilenet_v2/README.md index 8faa8d3..1d7610a 100644 --- a/example/object_detection_ssd_mobilenet_v2/README.md +++ b/example/object_detection_ssd_mobilenet_v2/README.md @@ -9,7 +9,7 @@ A object detection example following [this](https://www.tensorflow.org/lite/exam ## Overview -This application is a simple demonstration of the [tflite_flutter](https://pub.dev/packages/tflite_flutter) package. +This application is a simple demonstration of the [tflite_core](https://pub.dev/packages/tflite_core) package. After taking a photo or choosing an image from your gallery, the app takes a short period of time before displaying the image with the detected objects on the screen. diff --git a/example/object_detection_ssd_mobilenet_v2/lib/object_detection.dart b/example/object_detection_ssd_mobilenet_v2/lib/object_detection.dart index fb6cff9..59376a5 100644 --- a/example/object_detection_ssd_mobilenet_v2/lib/object_detection.dart +++ b/example/object_detection_ssd_mobilenet_v2/lib/object_detection.dart @@ -2,7 +2,7 @@ import 'dart:developer'; import 'dart:io'; import 'package:flutter/services.dart'; import 'package:image/image.dart' as img; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; class ObjectDetection { static const String _modelPath = 'assets/custom_ssd_mobilenet_v2.tflite'; diff --git a/example/object_detection_ssd_mobilenet_v2/linux/flutter/generated_plugins.cmake b/example/object_detection_ssd_mobilenet_v2/linux/flutter/generated_plugins.cmake index 3a71460..163c995 100644 --- a/example/object_detection_ssd_mobilenet_v2/linux/flutter/generated_plugins.cmake +++ b/example/object_detection_ssd_mobilenet_v2/linux/flutter/generated_plugins.cmake @@ -7,7 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/object_detection_ssd_mobilenet_v2/pubspec.yaml b/example/object_detection_ssd_mobilenet_v2/pubspec.yaml index f08fe00..643d849 100644 --- a/example/object_detection_ssd_mobilenet_v2/pubspec.yaml +++ b/example/object_detection_ssd_mobilenet_v2/pubspec.yaml @@ -34,7 +34,8 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 - tflite_flutter: ^0.11.0 + tflite_core: + path: ../../ image_picker: ^0.8.8 image: ^4.0.17 diff --git a/example/object_detection_ssd_mobilenet_v2/windows/flutter/generated_plugins.cmake b/example/object_detection_ssd_mobilenet_v2/windows/flutter/generated_plugins.cmake index 00cdb12..03a1d9c 100644 --- a/example/object_detection_ssd_mobilenet_v2/windows/flutter/generated_plugins.cmake +++ b/example/object_detection_ssd_mobilenet_v2/windows/flutter/generated_plugins.cmake @@ -7,7 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/pose_estimation/lib/helper/isolate_inference.dart b/example/pose_estimation/lib/helper/isolate_inference.dart index 32de5d9..0bed06c 100644 --- a/example/pose_estimation/lib/helper/isolate_inference.dart +++ b/example/pose_estimation/lib/helper/isolate_inference.dart @@ -20,7 +20,7 @@ import 'dart:math'; import 'dart:ui'; import 'package:camera/camera.dart'; import 'package:image/image.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; import '../image_utils.dart'; import '../models/body_part.dart'; diff --git a/example/pose_estimation/lib/helper/pose_estimation_helper.dart b/example/pose_estimation/lib/helper/pose_estimation_helper.dart index 41649e7..c1f0397 100644 --- a/example/pose_estimation/lib/helper/pose_estimation_helper.dart +++ b/example/pose_estimation/lib/helper/pose_estimation_helper.dart @@ -18,7 +18,7 @@ import 'dart:isolate'; import 'package:camera/camera.dart'; import 'package:pose_estimation/models/person.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; import 'isolate_inference.dart'; diff --git a/example/pose_estimation/pubspec.yaml b/example/pose_estimation/pubspec.yaml index 81bb24b..5056f3c 100644 --- a/example/pose_estimation/pubspec.yaml +++ b/example/pose_estimation/pubspec.yaml @@ -30,7 +30,7 @@ environment: dependencies: flutter: sdk: flutter - tflite_flutter: + tflite_core: path: ../../ image: ^4.0.17 camera: ^0.10.5+2 diff --git a/example/reinforcement_learning/lib/game_agent.dart b/example/reinforcement_learning/lib/game_agent.dart index e13c41d..e145ae7 100644 --- a/example/reinforcement_learning/lib/game_agent.dart +++ b/example/reinforcement_learning/lib/game_agent.dart @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; class PolicyGradientAgent { final _boardSize = 8; diff --git a/example/reinforcement_learning/pubspec.yaml b/example/reinforcement_learning/pubspec.yaml index bb88513..c5eda88 100644 --- a/example/reinforcement_learning/pubspec.yaml +++ b/example/reinforcement_learning/pubspec.yaml @@ -1,5 +1,5 @@ name: tflite_flutter_plugin_rl_example -description: Demonstrates how to use the tflite_flutter_plugin plugin. +description: Demonstrates how to use the tflite_core plugin. publish_to: "none" version: 1.0.0+1 @@ -11,7 +11,7 @@ dependencies: flutter: sdk: flutter - tflite_flutter: + tflite_core: path: ../../ path_provider: ^2.0.1 # The following adds the Cupertino Icons font to your application. diff --git a/example/style_transfer/.gitignore b/example/style_transfer/.gitignore index 987013f..dee5289 100644 --- a/example/style_transfer/.gitignore +++ b/example/style_transfer/.gitignore @@ -44,4 +44,6 @@ app.*.map.json /android/app/release # ignore tf lite models -assets/models/** \ No newline at end of file +assets/models/** +!assets/models/ +!assets/models/README.md \ No newline at end of file diff --git a/example/style_transfer/lib/main.dart b/example/style_transfer/lib/main.dart index 67136cd..4e47b5a 100644 --- a/example/style_transfer/lib/main.dart +++ b/example/style_transfer/lib/main.dart @@ -20,7 +20,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:image/image.dart' as img; import 'package:image_picker/image_picker.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; void main() { runApp(const App()); diff --git a/example/style_transfer/linux/flutter/generated_plugins.cmake b/example/style_transfer/linux/flutter/generated_plugins.cmake index 3a71460..163c995 100644 --- a/example/style_transfer/linux/flutter/generated_plugins.cmake +++ b/example/style_transfer/linux/flutter/generated_plugins.cmake @@ -7,7 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/style_transfer/pubspec.yaml b/example/style_transfer/pubspec.yaml index 3bebd0a..1c639bc 100644 --- a/example/style_transfer/pubspec.yaml +++ b/example/style_transfer/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: sdk: flutter image: ^4.0.17 image_picker: ^0.8.8 - tflite_flutter: + tflite_core: path: ../../ dev_dependencies: diff --git a/example/style_transfer/windows/flutter/generated_plugins.cmake b/example/style_transfer/windows/flutter/generated_plugins.cmake index 00cdb12..03a1d9c 100644 --- a/example/style_transfer/windows/flutter/generated_plugins.cmake +++ b/example/style_transfer/windows/flutter/generated_plugins.cmake @@ -7,7 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/super_resolution_esrgan/.gitignore b/example/super_resolution_esrgan/.gitignore index 52de8b4..365c689 100644 --- a/example/super_resolution_esrgan/.gitignore +++ b/example/super_resolution_esrgan/.gitignore @@ -44,4 +44,6 @@ app.*.map.json /android/app/release # ignore model files -assets/models/** \ No newline at end of file +assets/models/** +!assets/models/ +!assets/models/README.md \ No newline at end of file diff --git a/example/super_resolution_esrgan/lib/main.dart b/example/super_resolution_esrgan/lib/main.dart index 9964e2d..cfcc1a2 100644 --- a/example/super_resolution_esrgan/lib/main.dart +++ b/example/super_resolution_esrgan/lib/main.dart @@ -19,7 +19,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:image/image.dart' as img; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; void main() { runApp(const App()); diff --git a/example/super_resolution_esrgan/linux/flutter/generated_plugins.cmake b/example/super_resolution_esrgan/linux/flutter/generated_plugins.cmake index cf3f2cb..6002230 100644 --- a/example/super_resolution_esrgan/linux/flutter/generated_plugins.cmake +++ b/example/super_resolution_esrgan/linux/flutter/generated_plugins.cmake @@ -6,7 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/super_resolution_esrgan/pubspec.yaml b/example/super_resolution_esrgan/pubspec.yaml index 7a6c6a6..e6eac16 100644 --- a/example/super_resolution_esrgan/pubspec.yaml +++ b/example/super_resolution_esrgan/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: flutter: sdk: flutter image: ^4.0.17 - tflite_flutter: + tflite_core: path: ../../ dev_dependencies: diff --git a/example/super_resolution_esrgan/windows/flutter/generated_plugins.cmake b/example/super_resolution_esrgan/windows/flutter/generated_plugins.cmake index 6ac6cfe..4b6fc0a 100644 --- a/example/super_resolution_esrgan/windows/flutter/generated_plugins.cmake +++ b/example/super_resolution_esrgan/windows/flutter/generated_plugins.cmake @@ -6,7 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/text_classification/.gitignore b/example/text_classification/.gitignore index ac29f5c..996716c 100644 --- a/example/text_classification/.gitignore +++ b/example/text_classification/.gitignore @@ -44,4 +44,6 @@ app.*.map.json /android/app/release # model files -assets/models/** \ No newline at end of file +assets/models/** +!assets/models/ +!assets/models/README.md \ No newline at end of file diff --git a/example/text_classification/README.md b/example/text_classification/README.md index f81d924..5fec19a 100644 --- a/example/text_classification/README.md +++ b/example/text_classification/README.md @@ -6,7 +6,7 @@ ## Overview -This basic Text Classification app demonstrates the usage of tflite_flutter_plugin. +This basic Text Classification app demonstrates the usage of tflite_core. ![DEMO GIF](demo.gif) diff --git a/example/text_classification/integration_test/tflite_flutter_test.dart b/example/text_classification/integration_test/tflite_core_test.dart similarity index 99% rename from example/text_classification/integration_test/tflite_flutter_test.dart rename to example/text_classification/integration_test/tflite_core_test.dart index 73b18f5..2799971 100644 --- a/example/text_classification/integration_test/tflite_flutter_test.dart +++ b/example/text_classification/integration_test/tflite_core_test.dart @@ -23,7 +23,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:tflite_flutter/tflite_flutter.dart' as tfl; +import 'package:tflite_core/tflite_core.dart' as tfl; const dataFileName = 'permute_uint8.tflite'; const missingFileName = 'missing.tflite'; @@ -34,7 +34,7 @@ const int64FileName = 'int64.bin'; const multiInputFileName = 'multi_add.bin'; const addFileName = 'add.bin'; -//flutter drive --driver=test_driver/integration_test.dart --target=integration_test/tflite_flutter_test.dart +//flutter drive --driver=test_driver/integration_test.dart --target=integration_test/tflite_core_test.dart void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); diff --git a/example/text_classification/lib/classifier.dart b/example/text_classification/lib/classifier.dart index 447c76c..25fea94 100644 --- a/example/text_classification/lib/classifier.dart +++ b/example/text_classification/lib/classifier.dart @@ -18,8 +18,8 @@ import 'package:flutter/foundation.dart'; import 'dart:io'; import 'package:flutter/services.dart'; -// Import tflite_flutter -import 'package:tflite_flutter/tflite_flutter.dart'; +// Import tflite_core +import 'package:tflite_core/tflite_core.dart'; class Classifier { // name of the model file diff --git a/example/text_classification/linux/flutter/generated_plugins.cmake b/example/text_classification/linux/flutter/generated_plugins.cmake index cf3f2cb..2c16934 100644 --- a/example/text_classification/linux/flutter/generated_plugins.cmake +++ b/example/text_classification/linux/flutter/generated_plugins.cmake @@ -6,7 +6,8 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + jni + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/example/text_classification/pubspec.yaml b/example/text_classification/pubspec.yaml index c3ab61d..cab8c3c 100644 --- a/example/text_classification/pubspec.yaml +++ b/example/text_classification/pubspec.yaml @@ -1,5 +1,5 @@ name: tflite_flutter_plugin_example -description: Demonstrates how to use the tflite_flutter_plugin plugin. +description: Demonstrates how to use the tflite_core plugin. publish_to: "none" version: 1.0.0+1 @@ -11,7 +11,7 @@ dependencies: flutter: sdk: flutter - tflite_flutter: + tflite_core: path: ../../ path_provider: ^2.0.1 # The following adds the Cupertino Icons font to your application. diff --git a/example/text_classification/windows/flutter/generated_plugins.cmake b/example/text_classification/windows/flutter/generated_plugins.cmake index 6ac6cfe..548bcaa 100644 --- a/example/text_classification/windows/flutter/generated_plugins.cmake +++ b/example/text_classification/windows/flutter/generated_plugins.cmake @@ -6,7 +6,8 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - tflite_flutter + jni + tflite_core ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/ios/tflite_flutter.podspec b/ios/tflite_core.podspec similarity index 89% rename from ios/tflite_flutter.podspec rename to ios/tflite_core.podspec index 7facc61..794a5ba 100644 --- a/ios/tflite_flutter.podspec +++ b/ios/tflite_core.podspec @@ -1,9 +1,9 @@ # # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint tflite_flutter.podspec` to validate before publishing. +# Run `pod lib lint tflite_core.podspec` to validate before publishing. # Pod::Spec.new do |s| - s.name = 'tflite_flutter' + s.name = 'tflite_core' s.version = '0.0.1' s.summary = 'TensorFlow Lite plugin for Flutter apps.' s.description = <<-DESC @@ -18,7 +18,7 @@ TensorFlow Lite plugin for Flutter apps. # paths, so Classes contains a forwarder C file that relatively imports # `../src/*` so that the C sources can be shared among all target platforms. s.source = { :path => '.' } - # s.source_files = 'Classes/**/*' + s.source_files = 'tflite_core/Sources/**/*' s.dependency 'Flutter' diff --git a/ios/Assets/.gitkeep b/ios/tflite_core/Assets/.gitkeep similarity index 100% rename from ios/Assets/.gitkeep rename to ios/tflite_core/Assets/.gitkeep diff --git a/ios/tflite_core/Package.swift b/ios/tflite_core/Package.swift new file mode 100644 index 0000000..ef92d7c --- /dev/null +++ b/ios/tflite_core/Package.swift @@ -0,0 +1,27 @@ +// swift-tools-version: 5.9 +import PackageDescription + +let package = Package( + name: "tflite_core", + platforms: [ + .iOS("11.0"), + ], + products: [ + .library(name: "tflite-core", targets: ["tflite_core"]), + .library(name: "tflite_core", targets: ["tflite_core"]), + .library(name: "tflite-flutter", targets: ["tflite_core"]), + ], + targets: [ + .binaryTarget( + name: "TensorFlowLiteC", + url: "https://github.com/kewlbear/TensorFlowLiteC/releases/download/0.0.20240626/TensorFlowLiteC.xcframework.zip", + checksum: "3b527a7be16aa02f0900deb40d1561df839fdce96cf2d1aaa80388b5c28e2ac3" + ), + .target( + name: "tflite_core", + dependencies: ["TensorFlowLiteC"], + path: "Sources", + publicHeadersPath: "." + ), + ] +) \ No newline at end of file diff --git a/ios/Classes/TfliteFlutterPlugin.swift b/ios/tflite_core/Sources/TfliteFlutterPlugin.swift similarity index 100% rename from ios/Classes/TfliteFlutterPlugin.swift rename to ios/tflite_core/Sources/TfliteFlutterPlugin.swift diff --git a/lib/src/bindings/bindings.dart b/lib/src/bindings/bindings.dart index da94d87..b4c4a3b 100644 --- a/lib/src/bindings/bindings.dart +++ b/lib/src/bindings/bindings.dart @@ -17,7 +17,7 @@ import 'dart:ffi'; import 'dart:io'; -import 'package:tflite_flutter/src/bindings/tensorflow_lite_bindings_generated.dart'; +import 'package:tflite_core/src/bindings/tensorflow_lite_bindings_generated.dart'; final DynamicLibrary _dylib = () { if (Platform.isAndroid) { @@ -29,8 +29,22 @@ final DynamicLibrary _dylib = () { } if (Platform.isMacOS) { - return DynamicLibrary.open( - '${Directory(Platform.resolvedExecutable).parent.parent.path}/resources/libtensorflowlite_c-mac.dylib'); + // When linked via SPM (binaryTarget xcframework), the dynamic framework is + // loaded by dyld at launch and its symbols are resolvable via process(). + // When linked via CocoaPods (vendored .dylib), the library is NOT in the + // dyld image list at startup, so we must open it by its bundled path. + // Try process() first (SPM); fall back to the CocoaPods .dylib path. + try { + final lib = DynamicLibrary.process(); + // Probe for a known TFLite symbol to confirm it was actually linked in. + lib.lookup('TfLiteModelCreate'); + return lib; + } catch (_) { + // CocoaPods path: Flutter embeds the .dylib at + // .app/Contents/resources/libtensorflowlite_c-mac.dylib + return DynamicLibrary.open( + '${Directory(Platform.resolvedExecutable).parent.parent.path}/resources/libtensorflowlite_c-mac.dylib'); + } } if (Platform.isLinux) { diff --git a/lib/src/bindings/tensorflow_lite_bindings_generated.dart b/lib/src/bindings/tensorflow_lite_bindings_generated.dart index ac69f58..1847230 100644 --- a/lib/src/bindings/tensorflow_lite_bindings_generated.dart +++ b/lib/src/bindings/tensorflow_lite_bindings_generated.dart @@ -14,17 +14,14 @@ import 'dart:ffi' as ffi; /// class TensorFlowLiteBindings { /// Holds the symbol lookup function. - final ffi.Pointer Function(String symbolName) - _lookup; + final ffi.Pointer Function(String symbolName) _lookup; /// The symbols are looked up in [dynamicLibrary]. - TensorFlowLiteBindings(ffi.DynamicLibrary dynamicLibrary) - : _lookup = dynamicLibrary.lookup; + TensorFlowLiteBindings(ffi.DynamicLibrary dynamicLibrary) : _lookup = dynamicLibrary.lookup; /// The symbols are looked up with [lookup]. TensorFlowLiteBindings.fromLookup( - ffi.Pointer Function(String symbolName) - lookup) + ffi.Pointer Function(String symbolName) lookup) : _lookup = lookup; /// -------------------------------------------------------------------------- @@ -35,10 +32,8 @@ class TensorFlowLiteBindings { } late final _TfLiteVersionPtr = - _lookup Function()>>( - 'TfLiteVersion'); - late final _TfLiteVersion = - _TfLiteVersionPtr.asFunction Function()>(); + _lookup Function()>>('TfLiteVersion'); + late final _TfLiteVersion = _TfLiteVersionPtr.asFunction Function()>(); /// Returns a model from the provided buffer, or null on failure. /// @@ -58,9 +53,8 @@ class TensorFlowLiteBindings { } late final _TfLiteModelCreatePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Size)>>('TfLiteModelCreate'); + ffi.NativeFunction Function(ffi.Pointer, ffi.Size)>>( + 'TfLiteModelCreate'); late final _TfLiteModelCreate = _TfLiteModelCreatePtr.asFunction< ffi.Pointer Function(ffi.Pointer, int)>(); @@ -77,12 +71,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteModelCreateFromFilePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('TfLiteModelCreateFromFile'); - late final _TfLiteModelCreateFromFile = _TfLiteModelCreateFromFilePtr - .asFunction Function(ffi.Pointer)>(); + late final _TfLiteModelCreateFromFilePtr = + _lookup Function(ffi.Pointer)>>( + 'TfLiteModelCreateFromFile'); + late final _TfLiteModelCreateFromFile = _TfLiteModelCreateFromFilePtr.asFunction< + ffi.Pointer Function(ffi.Pointer)>(); /// Destroys the model instance. void TfLiteModelDelete( @@ -94,10 +87,9 @@ class TensorFlowLiteBindings { } late final _TfLiteModelDeletePtr = - _lookup)>>( - 'TfLiteModelDelete'); - late final _TfLiteModelDelete = _TfLiteModelDeletePtr.asFunction< - void Function(ffi.Pointer)>(); + _lookup)>>('TfLiteModelDelete'); + late final _TfLiteModelDelete = + _TfLiteModelDeletePtr.asFunction)>(); /// Returns a new TfLiteRegistrationExternal instance. /// @@ -120,13 +112,9 @@ class TensorFlowLiteBindings { late final _TfLiteRegistrationExternalCreatePtr = _lookup< ffi.NativeFunction< ffi.Pointer Function( - ffi.Int32, - ffi.Pointer, - ffi.Int)>>('TfLiteRegistrationExternalCreate'); - late final _TfLiteRegistrationExternalCreate = - _TfLiteRegistrationExternalCreatePtr.asFunction< - ffi.Pointer Function( - int, ffi.Pointer, int)>(); + ffi.Int32, ffi.Pointer, ffi.Int)>>('TfLiteRegistrationExternalCreate'); + late final _TfLiteRegistrationExternalCreate = _TfLiteRegistrationExternalCreatePtr.asFunction< + ffi.Pointer Function(int, ffi.Pointer, int)>(); /// Return the builtin op code of the provided external 'registration'. /// @@ -139,10 +127,9 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteRegistrationExternalGetBuiltInCodePtr = _lookup< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer)>>( - 'TfLiteRegistrationExternalGetBuiltInCode'); + late final _TfLiteRegistrationExternalGetBuiltInCodePtr = + _lookup)>>( + 'TfLiteRegistrationExternalGetBuiltInCode'); late final _TfLiteRegistrationExternalGetBuiltInCode = _TfLiteRegistrationExternalGetBuiltInCodePtr.asFunction< int Function(ffi.Pointer)>(); @@ -157,13 +144,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteRegistrationExternalDeletePtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer)>>( - 'TfLiteRegistrationExternalDelete'); - late final _TfLiteRegistrationExternalDelete = - _TfLiteRegistrationExternalDeletePtr.asFunction< - void Function(ffi.Pointer)>(); + late final _TfLiteRegistrationExternalDeletePtr = + _lookup)>>( + 'TfLiteRegistrationExternalDelete'); + late final _TfLiteRegistrationExternalDelete = _TfLiteRegistrationExternalDeletePtr.asFunction< + void Function(ffi.Pointer)>(); /// Sets the initialization callback for the registration. /// @@ -174,10 +159,8 @@ class TensorFlowLiteBindings { ffi.Pointer registration, ffi.Pointer< ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer context, - ffi.Pointer buffer, - ffi.Size length)>> + ffi.Pointer Function(ffi.Pointer context, + ffi.Pointer buffer, ffi.Size length)>> init, ) { return _TfLiteRegistrationExternalSetInit( @@ -187,26 +170,22 @@ class TensorFlowLiteBindings { } late final _TfLiteRegistrationExternalSetInitPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer, - ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer context, - ffi.Pointer buffer, - ffi.Size length)>>)>>( - 'TfLiteRegistrationExternalSetInit'); - late final _TfLiteRegistrationExternalSetInit = - _TfLiteRegistrationExternalSetInitPtr.asFunction< - void Function( + ffi.NativeFunction< + ffi.Void Function( ffi.Pointer, ffi.Pointer< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer context, ffi.Pointer buffer, - ffi.Size length)>>)>(); + ffi.Size length)>>)>>('TfLiteRegistrationExternalSetInit'); + late final _TfLiteRegistrationExternalSetInit = _TfLiteRegistrationExternalSetInitPtr.asFunction< + void Function( + ffi.Pointer, + ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function(ffi.Pointer context, + ffi.Pointer buffer, ffi.Size length)>>)>(); /// Sets the deallocation callback for the registration. /// @@ -219,8 +198,8 @@ class TensorFlowLiteBindings { ffi.Pointer registration, ffi.Pointer< ffi.NativeFunction< - ffi.Void Function(ffi.Pointer context, - ffi.Pointer data)>> + ffi.Void Function( + ffi.Pointer context, ffi.Pointer data)>> free, ) { return _TfLiteRegistrationExternalSetFree( @@ -230,24 +209,20 @@ class TensorFlowLiteBindings { } late final _TfLiteRegistrationExternalSetFreePtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer, - ffi.Pointer< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer context, - ffi.Pointer data)>>)>>( - 'TfLiteRegistrationExternalSetFree'); - late final _TfLiteRegistrationExternalSetFree = - _TfLiteRegistrationExternalSetFreePtr.asFunction< - void Function( + ffi.NativeFunction< + ffi.Void Function( ffi.Pointer, ffi.Pointer< ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer context, - ffi.Pointer data)>>)>(); + ffi.Void Function(ffi.Pointer context, + ffi.Pointer data)>>)>>('TfLiteRegistrationExternalSetFree'); + late final _TfLiteRegistrationExternalSetFree = _TfLiteRegistrationExternalSetFreePtr.asFunction< + void Function( + ffi.Pointer, + ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer context, ffi.Pointer data)>>)>(); /// Sets the preparation callback for the registration. /// @@ -258,8 +233,8 @@ class TensorFlowLiteBindings { ffi.Pointer registration, ffi.Pointer< ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer context, - ffi.Pointer node)>> + ffi.Int32 Function( + ffi.Pointer context, ffi.Pointer node)>> prepare, ) { return _TfLiteRegistrationExternalSetPrepare( @@ -274,8 +249,7 @@ class TensorFlowLiteBindings { ffi.Pointer, ffi.Pointer< ffi.NativeFunction< - ffi.Int32 Function( - ffi.Pointer context, + ffi.Int32 Function(ffi.Pointer context, ffi.Pointer node)>>)>>( 'TfLiteRegistrationExternalSetPrepare'); late final _TfLiteRegistrationExternalSetPrepare = @@ -284,8 +258,7 @@ class TensorFlowLiteBindings { ffi.Pointer, ffi.Pointer< ffi.NativeFunction< - ffi.Int32 Function( - ffi.Pointer context, + ffi.Int32 Function(ffi.Pointer context, ffi.Pointer node)>>)>(); /// Sets the invocation callback for the registration. @@ -297,8 +270,8 @@ class TensorFlowLiteBindings { ffi.Pointer registration, ffi.Pointer< ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer context, - ffi.Pointer node)>> + ffi.Int32 Function( + ffi.Pointer context, ffi.Pointer node)>> invoke, ) { return _TfLiteRegistrationExternalSetInvoke( @@ -313,8 +286,7 @@ class TensorFlowLiteBindings { ffi.Pointer, ffi.Pointer< ffi.NativeFunction< - ffi.Int32 Function( - ffi.Pointer context, + ffi.Int32 Function(ffi.Pointer context, ffi.Pointer node)>>)>>( 'TfLiteRegistrationExternalSetInvoke'); late final _TfLiteRegistrationExternalSetInvoke = @@ -323,8 +295,7 @@ class TensorFlowLiteBindings { ffi.Pointer, ffi.Pointer< ffi.NativeFunction< - ffi.Int32 Function( - ffi.Pointer context, + ffi.Int32 Function(ffi.Pointer context, ffi.Pointer node)>>)>(); /// Returns a new interpreter options instances. @@ -332,12 +303,11 @@ class TensorFlowLiteBindings { return _TfLiteInterpreterOptionsCreate(); } - late final _TfLiteInterpreterOptionsCreatePtr = _lookup< - ffi.NativeFunction Function()>>( - 'TfLiteInterpreterOptionsCreate'); - late final _TfLiteInterpreterOptionsCreate = - _TfLiteInterpreterOptionsCreatePtr.asFunction< - ffi.Pointer Function()>(); + late final _TfLiteInterpreterOptionsCreatePtr = + _lookup Function()>>( + 'TfLiteInterpreterOptionsCreate'); + late final _TfLiteInterpreterOptionsCreate = _TfLiteInterpreterOptionsCreatePtr.asFunction< + ffi.Pointer Function()>(); /// Destroys the interpreter options instance. void TfLiteInterpreterOptionsDelete( @@ -348,13 +318,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteInterpreterOptionsDeletePtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer)>>( - 'TfLiteInterpreterOptionsDelete'); - late final _TfLiteInterpreterOptionsDelete = - _TfLiteInterpreterOptionsDeletePtr.asFunction< - void Function(ffi.Pointer)>(); + late final _TfLiteInterpreterOptionsDeletePtr = + _lookup)>>( + 'TfLiteInterpreterOptionsDelete'); + late final _TfLiteInterpreterOptionsDelete = _TfLiteInterpreterOptionsDeletePtr.asFunction< + void Function(ffi.Pointer)>(); /// Sets the number of CPU threads to use for the interpreter. void TfLiteInterpreterOptionsSetNumThreads( @@ -368,12 +336,10 @@ class TensorFlowLiteBindings { } late final _TfLiteInterpreterOptionsSetNumThreadsPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Int32)>>('TfLiteInterpreterOptionsSetNumThreads'); - late final _TfLiteInterpreterOptionsSetNumThreads = - _TfLiteInterpreterOptionsSetNumThreadsPtr.asFunction< - void Function(ffi.Pointer, int)>(); + ffi.NativeFunction, ffi.Int32)>>( + 'TfLiteInterpreterOptionsSetNumThreads'); + late final _TfLiteInterpreterOptionsSetNumThreads = _TfLiteInterpreterOptionsSetNumThreadsPtr + .asFunction, int)>(); /// Adds a delegate to be applied during `TfLiteInterpreter` creation. /// @@ -393,14 +359,12 @@ class TensorFlowLiteBindings { } late final _TfLiteInterpreterOptionsAddDelegatePtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Pointer)>>( - 'TfLiteInterpreterOptionsAddDelegate'); + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer, + ffi.Pointer)>>('TfLiteInterpreterOptionsAddDelegate'); late final _TfLiteInterpreterOptionsAddDelegate = _TfLiteInterpreterOptionsAddDelegatePtr.asFunction< - void Function(ffi.Pointer, - ffi.Pointer)>(); + void Function(ffi.Pointer, ffi.Pointer)>(); /// Adds an opaque delegate to be applied during `TfLiteInterpreter` creation. /// @@ -421,13 +385,13 @@ class TensorFlowLiteBindings { late final _TfLiteInterpreterOptionsAddOpaqueDelegatePtr = _lookup< ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Pointer)>>( + ffi.Void Function( + ffi.Pointer, ffi.Pointer)>>( 'TfLiteInterpreterOptionsAddOpaqueDelegate'); late final _TfLiteInterpreterOptionsAddOpaqueDelegate = _TfLiteInterpreterOptionsAddOpaqueDelegatePtr.asFunction< - void Function(ffi.Pointer, - ffi.Pointer)>(); + void Function( + ffi.Pointer, ffi.Pointer)>(); /// Sets a custom error reporter for interpreter execution. /// @@ -439,8 +403,8 @@ class TensorFlowLiteBindings { ffi.Pointer options, ffi.Pointer< ffi.NativeFunction< - ffi.Void Function(ffi.Pointer user_data, - ffi.Pointer format, va_list args)>> + ffi.Void Function( + ffi.Pointer user_data, ffi.Pointer format, va_list args)>> reporter, ffi.Pointer user_data, ) { @@ -452,15 +416,14 @@ class TensorFlowLiteBindings { } late final _TfLiteInterpreterOptionsSetErrorReporterPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer, - ffi.Pointer< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer user_data, - ffi.Pointer format, va_list args)>>, - ffi.Pointer)>>( - 'TfLiteInterpreterOptionsSetErrorReporter'); + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer user_data, + ffi.Pointer format, va_list args)>>, + ffi.Pointer)>>('TfLiteInterpreterOptionsSetErrorReporter'); late final _TfLiteInterpreterOptionsSetErrorReporter = _TfLiteInterpreterOptionsSetErrorReporterPtr.asFunction< void Function( @@ -495,13 +458,13 @@ class TensorFlowLiteBindings { late final _TfLiteInterpreterOptionsAddRegistrationExternalPtr = _lookup< ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Pointer)>>( + ffi.Void Function( + ffi.Pointer, ffi.Pointer)>>( 'TfLiteInterpreterOptionsAddRegistrationExternal'); late final _TfLiteInterpreterOptionsAddRegistrationExternal = _TfLiteInterpreterOptionsAddRegistrationExternalPtr.asFunction< - void Function(ffi.Pointer, - ffi.Pointer)>(); + void Function( + ffi.Pointer, ffi.Pointer)>(); /// Returns a new interpreter using the provided model and options, or null on /// failure. @@ -532,10 +495,9 @@ class TensorFlowLiteBindings { } late final _TfLiteInterpreterCreatePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>( - 'TfLiteInterpreterCreate'); + ffi.NativeFunction< + ffi.Pointer Function(ffi.Pointer, + ffi.Pointer)>>('TfLiteInterpreterCreate'); late final _TfLiteInterpreterCreate = _TfLiteInterpreterCreatePtr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -549,12 +511,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteInterpreterDeletePtr = _lookup< - ffi - .NativeFunction)>>( - 'TfLiteInterpreterDelete'); - late final _TfLiteInterpreterDelete = _TfLiteInterpreterDeletePtr.asFunction< - void Function(ffi.Pointer)>(); + late final _TfLiteInterpreterDeletePtr = + _lookup)>>( + 'TfLiteInterpreterDelete'); + late final _TfLiteInterpreterDelete = + _TfLiteInterpreterDeletePtr.asFunction)>(); /// Returns the number of input tensors associated with the model. int TfLiteInterpreterGetInputTensorCount( @@ -565,13 +526,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteInterpreterGetInputTensorCountPtr = _lookup< - ffi - .NativeFunction)>>( - 'TfLiteInterpreterGetInputTensorCount'); - late final _TfLiteInterpreterGetInputTensorCount = - _TfLiteInterpreterGetInputTensorCountPtr.asFunction< - int Function(ffi.Pointer)>(); + late final _TfLiteInterpreterGetInputTensorCountPtr = + _lookup)>>( + 'TfLiteInterpreterGetInputTensorCount'); + late final _TfLiteInterpreterGetInputTensorCount = _TfLiteInterpreterGetInputTensorCountPtr + .asFunction)>(); /// Returns the tensor associated with the input index. /// REQUIRES: 0 <= input_index < TfLiteInterpreterGetInputTensorCount(tensor) @@ -587,12 +546,10 @@ class TensorFlowLiteBindings { late final _TfLiteInterpreterGetInputTensorPtr = _lookup< ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Int32)>>('TfLiteInterpreterGetInputTensor'); - late final _TfLiteInterpreterGetInputTensor = - _TfLiteInterpreterGetInputTensorPtr.asFunction< ffi.Pointer Function( - ffi.Pointer, int)>(); + ffi.Pointer, ffi.Int32)>>('TfLiteInterpreterGetInputTensor'); + late final _TfLiteInterpreterGetInputTensor = _TfLiteInterpreterGetInputTensorPtr.asFunction< + ffi.Pointer Function(ffi.Pointer, int)>(); /// Resizes the specified input tensor. /// @@ -619,15 +576,10 @@ class TensorFlowLiteBindings { late final _TfLiteInterpreterResizeInputTensorPtr = _lookup< ffi.NativeFunction< - ffi.Int32 Function( - ffi.Pointer, - ffi.Int32, - ffi.Pointer, + ffi.Int32 Function(ffi.Pointer, ffi.Int32, ffi.Pointer, ffi.Int32)>>('TfLiteInterpreterResizeInputTensor'); - late final _TfLiteInterpreterResizeInputTensor = - _TfLiteInterpreterResizeInputTensorPtr.asFunction< - int Function(ffi.Pointer, int, - ffi.Pointer, int)>(); + late final _TfLiteInterpreterResizeInputTensor = _TfLiteInterpreterResizeInputTensorPtr + .asFunction, int, ffi.Pointer, int)>(); /// Updates allocations for all tensors, resizing dependent tensors using the /// specified input tensor dimensionality. @@ -642,13 +594,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteInterpreterAllocateTensorsPtr = _lookup< - ffi - .NativeFunction)>>( - 'TfLiteInterpreterAllocateTensors'); - late final _TfLiteInterpreterAllocateTensors = - _TfLiteInterpreterAllocateTensorsPtr.asFunction< - int Function(ffi.Pointer)>(); + late final _TfLiteInterpreterAllocateTensorsPtr = + _lookup)>>( + 'TfLiteInterpreterAllocateTensors'); + late final _TfLiteInterpreterAllocateTensors = _TfLiteInterpreterAllocateTensorsPtr.asFunction< + int Function(ffi.Pointer)>(); /// Runs inference for the loaded graph. /// @@ -687,12 +637,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteInterpreterInvokePtr = _lookup< - ffi - .NativeFunction)>>( - 'TfLiteInterpreterInvoke'); - late final _TfLiteInterpreterInvoke = _TfLiteInterpreterInvokePtr.asFunction< - int Function(ffi.Pointer)>(); + late final _TfLiteInterpreterInvokePtr = + _lookup)>>( + 'TfLiteInterpreterInvoke'); + late final _TfLiteInterpreterInvoke = + _TfLiteInterpreterInvokePtr.asFunction)>(); /// Returns the number of output tensors associated with the model. int TfLiteInterpreterGetOutputTensorCount( @@ -703,13 +652,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteInterpreterGetOutputTensorCountPtr = _lookup< - ffi - .NativeFunction)>>( - 'TfLiteInterpreterGetOutputTensorCount'); - late final _TfLiteInterpreterGetOutputTensorCount = - _TfLiteInterpreterGetOutputTensorCountPtr.asFunction< - int Function(ffi.Pointer)>(); + late final _TfLiteInterpreterGetOutputTensorCountPtr = + _lookup)>>( + 'TfLiteInterpreterGetOutputTensorCount'); + late final _TfLiteInterpreterGetOutputTensorCount = _TfLiteInterpreterGetOutputTensorCountPtr + .asFunction)>(); /// Returns the tensor associated with the output index. /// REQUIRES: 0 <= output_index < TfLiteInterpreterGetOutputTensorCount(tensor) @@ -730,12 +677,10 @@ class TensorFlowLiteBindings { late final _TfLiteInterpreterGetOutputTensorPtr = _lookup< ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Int32)>>('TfLiteInterpreterGetOutputTensor'); - late final _TfLiteInterpreterGetOutputTensor = - _TfLiteInterpreterGetOutputTensorPtr.asFunction< ffi.Pointer Function( - ffi.Pointer, int)>(); + ffi.Pointer, ffi.Int32)>>('TfLiteInterpreterGetOutputTensor'); + late final _TfLiteInterpreterGetOutputTensor = _TfLiteInterpreterGetOutputTensorPtr.asFunction< + ffi.Pointer Function(ffi.Pointer, int)>(); /// Returns the type of a tensor element. int TfLiteTensorType( @@ -746,11 +691,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteTensorTypePtr = _lookup< - ffi.NativeFunction)>>( - 'TfLiteTensorType'); - late final _TfLiteTensorType = _TfLiteTensorTypePtr.asFunction< - int Function(ffi.Pointer)>(); + late final _TfLiteTensorTypePtr = + _lookup)>>( + 'TfLiteTensorType'); + late final _TfLiteTensorType = + _TfLiteTensorTypePtr.asFunction)>(); /// Returns the number of dimensions that the tensor has. int TfLiteTensorNumDims( @@ -761,11 +706,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteTensorNumDimsPtr = _lookup< - ffi.NativeFunction)>>( - 'TfLiteTensorNumDims'); - late final _TfLiteTensorNumDims = _TfLiteTensorNumDimsPtr.asFunction< - int Function(ffi.Pointer)>(); + late final _TfLiteTensorNumDimsPtr = + _lookup)>>( + 'TfLiteTensorNumDims'); + late final _TfLiteTensorNumDims = + _TfLiteTensorNumDimsPtr.asFunction)>(); /// Returns the length of the tensor in the "dim_index" dimension. /// REQUIRES: 0 <= dim_index < TFLiteTensorNumDims(tensor) @@ -779,12 +724,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteTensorDimPtr = _lookup< - ffi.NativeFunction< - ffi.Int32 Function( - ffi.Pointer, ffi.Int32)>>('TfLiteTensorDim'); - late final _TfLiteTensorDim = _TfLiteTensorDimPtr.asFunction< - int Function(ffi.Pointer, int)>(); + late final _TfLiteTensorDimPtr = + _lookup, ffi.Int32)>>( + 'TfLiteTensorDim'); + late final _TfLiteTensorDim = + _TfLiteTensorDimPtr.asFunction, int)>(); /// Returns the size of the underlying data in bytes. int TfLiteTensorByteSize( @@ -798,8 +742,8 @@ class TensorFlowLiteBindings { late final _TfLiteTensorByteSizePtr = _lookup)>>( 'TfLiteTensorByteSize'); - late final _TfLiteTensorByteSize = _TfLiteTensorByteSizePtr.asFunction< - int Function(ffi.Pointer)>(); + late final _TfLiteTensorByteSize = + _TfLiteTensorByteSizePtr.asFunction)>(); /// Returns a pointer to the underlying data buffer. /// @@ -815,12 +759,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteTensorDataPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('TfLiteTensorData'); - late final _TfLiteTensorData = _TfLiteTensorDataPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); + late final _TfLiteTensorDataPtr = + _lookup Function(ffi.Pointer)>>( + 'TfLiteTensorData'); + late final _TfLiteTensorData = + _TfLiteTensorDataPtr.asFunction Function(ffi.Pointer)>(); /// Returns the (null-terminated) name of the tensor. ffi.Pointer TfLiteTensorName( @@ -831,12 +774,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteTensorNamePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('TfLiteTensorName'); - late final _TfLiteTensorName = _TfLiteTensorNamePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); + late final _TfLiteTensorNamePtr = + _lookup Function(ffi.Pointer)>>( + 'TfLiteTensorName'); + late final _TfLiteTensorName = + _TfLiteTensorNamePtr.asFunction Function(ffi.Pointer)>(); /// Returns the parameters for asymmetric quantization. The quantization /// parameters are only valid when the tensor type is `kTfLiteUInt8` and the @@ -850,13 +792,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteTensorQuantizationParamsPtr = _lookup< - ffi.NativeFunction< - TfLiteQuantizationParams Function( - ffi.Pointer)>>('TfLiteTensorQuantizationParams'); - late final _TfLiteTensorQuantizationParams = - _TfLiteTensorQuantizationParamsPtr.asFunction< - TfLiteQuantizationParams Function(ffi.Pointer)>(); + late final _TfLiteTensorQuantizationParamsPtr = + _lookup)>>( + 'TfLiteTensorQuantizationParams'); + late final _TfLiteTensorQuantizationParams = _TfLiteTensorQuantizationParamsPtr.asFunction< + TfLiteQuantizationParams Function(ffi.Pointer)>(); /// Copies from the provided input buffer into the tensor's buffer. /// REQUIRES: input_data_size == TfLiteTensorByteSize(tensor) @@ -876,10 +816,8 @@ class TensorFlowLiteBindings { ffi.NativeFunction< ffi.Int32 Function(ffi.Pointer, ffi.Pointer, ffi.Size)>>('TfLiteTensorCopyFromBuffer'); - late final _TfLiteTensorCopyFromBuffer = - _TfLiteTensorCopyFromBufferPtr.asFunction< - int Function( - ffi.Pointer, ffi.Pointer, int)>(); + late final _TfLiteTensorCopyFromBuffer = _TfLiteTensorCopyFromBufferPtr.asFunction< + int Function(ffi.Pointer, ffi.Pointer, int)>(); /// Copies to the provided output buffer from the tensor's buffer. /// REQUIRES: output_data_size == TfLiteTensorByteSize(tensor) @@ -899,10 +837,8 @@ class TensorFlowLiteBindings { ffi.NativeFunction< ffi.Int32 Function(ffi.Pointer, ffi.Pointer, ffi.Size)>>('TfLiteTensorCopyToBuffer'); - late final _TfLiteTensorCopyToBuffer = - _TfLiteTensorCopyToBufferPtr.asFunction< - int Function( - ffi.Pointer, ffi.Pointer, int)>(); + late final _TfLiteTensorCopyToBuffer = _TfLiteTensorCopyToBufferPtr.asFunction< + int Function(ffi.Pointer, ffi.Pointer, int)>(); /// -------------------------------------------------------------------------- /// Resets all variable tensors to zero. @@ -916,13 +852,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteInterpreterResetVariableTensorsPtr = _lookup< - ffi - .NativeFunction)>>( - 'TfLiteInterpreterResetVariableTensors'); - late final _TfLiteInterpreterResetVariableTensors = - _TfLiteInterpreterResetVariableTensorsPtr.asFunction< - int Function(ffi.Pointer)>(); + late final _TfLiteInterpreterResetVariableTensorsPtr = + _lookup)>>( + 'TfLiteInterpreterResetVariableTensors'); + late final _TfLiteInterpreterResetVariableTensors = _TfLiteInterpreterResetVariableTensorsPtr + .asFunction)>(); /// Adds an op registration for a builtin operator. /// @@ -964,8 +898,8 @@ class TensorFlowLiteBindings { ffi.Int32)>>('TfLiteInterpreterOptionsAddBuiltinOp'); late final _TfLiteInterpreterOptionsAddBuiltinOp = _TfLiteInterpreterOptionsAddBuiltinOpPtr.asFunction< - void Function(ffi.Pointer, int, - ffi.Pointer, int, int)>(); + void Function(ffi.Pointer, int, ffi.Pointer, + int, int)>(); /// Adds an op registration for a custom operator. /// @@ -1010,12 +944,8 @@ class TensorFlowLiteBindings { ffi.Int32)>>('TfLiteInterpreterOptionsAddCustomOp'); late final _TfLiteInterpreterOptionsAddCustomOp = _TfLiteInterpreterOptionsAddCustomOpPtr.asFunction< - void Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - int, - int)>(); + void Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer, int, int)>(); /// Registers callbacks for resolving builtin or custom operators. /// @@ -1038,16 +968,12 @@ class TensorFlowLiteBindings { ffi.Pointer< ffi.NativeFunction< ffi.Pointer Function( - ffi.Pointer user_data, - ffi.Int32 op, - ffi.Int version)>> + ffi.Pointer user_data, ffi.Int32 op, ffi.Int version)>> find_builtin_op, ffi.Pointer< ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer user_data, - ffi.Pointer custom_op, - ffi.Int version)>> + ffi.Pointer Function(ffi.Pointer user_data, + ffi.Pointer custom_op, ffi.Int version)>> find_custom_op, ffi.Pointer op_resolver_user_data, ) { @@ -1066,15 +992,11 @@ class TensorFlowLiteBindings { ffi.Pointer< ffi.NativeFunction< ffi.Pointer Function( - ffi.Pointer user_data, - ffi.Int32 op, - ffi.Int version)>>, + ffi.Pointer user_data, ffi.Int32 op, ffi.Int version)>>, ffi.Pointer< ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer user_data, - ffi.Pointer custom_op, - ffi.Int version)>>, + ffi.Pointer Function(ffi.Pointer user_data, + ffi.Pointer custom_op, ffi.Int version)>>, ffi.Pointer)>>('TfLiteInterpreterOptionsSetOpResolver'); late final _TfLiteInterpreterOptionsSetOpResolver = _TfLiteInterpreterOptionsSetOpResolverPtr.asFunction< @@ -1083,15 +1005,11 @@ class TensorFlowLiteBindings { ffi.Pointer< ffi.NativeFunction< ffi.Pointer Function( - ffi.Pointer user_data, - ffi.Int32 op, - ffi.Int version)>>, + ffi.Pointer user_data, ffi.Int32 op, ffi.Int version)>>, ffi.Pointer< ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer user_data, - ffi.Pointer custom_op, - ffi.Int version)>>, + ffi.Pointer Function(ffi.Pointer user_data, + ffi.Pointer custom_op, ffi.Int version)>>, ffi.Pointer)>(); /// \private @@ -1104,16 +1022,12 @@ class TensorFlowLiteBindings { ffi.Pointer< ffi.NativeFunction< ffi.Pointer Function( - ffi.Pointer user_data, - ffi.Int32 op, - ffi.Int version)>> + ffi.Pointer user_data, ffi.Int32 op, ffi.Int version)>> find_builtin_op_v1, ffi.Pointer< ffi.NativeFunction< ffi.Pointer Function( - ffi.Pointer user_data, - ffi.Pointer op, - ffi.Int version)>> + ffi.Pointer user_data, ffi.Pointer op, ffi.Int version)>> find_custom_op_v1, ffi.Pointer op_resolver_user_data, ) { @@ -1126,23 +1040,18 @@ class TensorFlowLiteBindings { } late final _TfLiteInterpreterOptionsSetOpResolverV1Ptr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer, - ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer user_data, - ffi.Int32 op, - ffi.Int version)>>, - ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer user_data, - ffi.Pointer op, - ffi.Int version)>>, - ffi.Pointer)>>( - 'TfLiteInterpreterOptionsSetOpResolverV1'); + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer user_data, ffi.Int32 op, ffi.Int version)>>, + ffi.Pointer< + ffi.NativeFunction< + ffi.Pointer Function(ffi.Pointer user_data, + ffi.Pointer op, ffi.Int version)>>, + ffi.Pointer)>>('TfLiteInterpreterOptionsSetOpResolverV1'); late final _TfLiteInterpreterOptionsSetOpResolverV1 = _TfLiteInterpreterOptionsSetOpResolverV1Ptr.asFunction< void Function( @@ -1150,15 +1059,11 @@ class TensorFlowLiteBindings { ffi.Pointer< ffi.NativeFunction< ffi.Pointer Function( - ffi.Pointer user_data, - ffi.Int32 op, - ffi.Int version)>>, + ffi.Pointer user_data, ffi.Int32 op, ffi.Int version)>>, ffi.Pointer< ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer user_data, - ffi.Pointer op, - ffi.Int version)>>, + ffi.Pointer Function(ffi.Pointer user_data, + ffi.Pointer op, ffi.Int version)>>, ffi.Pointer)>(); /// Returns a new interpreter using the provided model and options, or null on @@ -1191,14 +1096,13 @@ class TensorFlowLiteBindings { } late final _TfLiteInterpreterCreateWithSelectedOpsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>( - 'TfLiteInterpreterCreateWithSelectedOps'); + ffi.NativeFunction< + ffi.Pointer Function(ffi.Pointer, + ffi.Pointer)>>('TfLiteInterpreterCreateWithSelectedOps'); late final _TfLiteInterpreterCreateWithSelectedOps = _TfLiteInterpreterCreateWithSelectedOpsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>(); + ffi.Pointer Function( + ffi.Pointer, ffi.Pointer)>(); /// Enable or disable the NN API delegate for the interpreter (true to enable). /// @@ -1214,12 +1118,10 @@ class TensorFlowLiteBindings { } late final _TfLiteInterpreterOptionsSetUseNNAPIPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Bool)>>('TfLiteInterpreterOptionsSetUseNNAPI'); - late final _TfLiteInterpreterOptionsSetUseNNAPI = - _TfLiteInterpreterOptionsSetUseNNAPIPtr.asFunction< - void Function(ffi.Pointer, bool)>(); + ffi.NativeFunction, ffi.Bool)>>( + 'TfLiteInterpreterOptionsSetUseNNAPI'); + late final _TfLiteInterpreterOptionsSetUseNNAPI = _TfLiteInterpreterOptionsSetUseNNAPIPtr + .asFunction, bool)>(); /// Enable or disable CPU fallback for the interpreter (true to enable). /// If enabled, TfLiteInterpreterInvoke will do automatic fallback from @@ -1256,9 +1158,8 @@ class TensorFlowLiteBindings { } late final _TfLiteInterpreterOptionsSetEnableDelegateFallbackPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Bool)>>('TfLiteInterpreterOptionsSetEnableDelegateFallback'); + ffi.NativeFunction, ffi.Bool)>>( + 'TfLiteInterpreterOptionsSetEnableDelegateFallback'); late final _TfLiteInterpreterOptionsSetEnableDelegateFallback = _TfLiteInterpreterOptionsSetEnableDelegateFallbackPtr.asFunction< void Function(ffi.Pointer, bool)>(); @@ -1281,13 +1182,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteSetAllowBufferHandleOutputPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Bool)>>('TfLiteSetAllowBufferHandleOutput'); - late final _TfLiteSetAllowBufferHandleOutput = - _TfLiteSetAllowBufferHandleOutputPtr.asFunction< - void Function(ffi.Pointer, bool)>(); + late final _TfLiteSetAllowBufferHandleOutputPtr = + _lookup, ffi.Bool)>>( + 'TfLiteSetAllowBufferHandleOutput'); + late final _TfLiteSetAllowBufferHandleOutput = _TfLiteSetAllowBufferHandleOutputPtr.asFunction< + void Function(ffi.Pointer, bool)>(); /// Allow a delegate to look at the graph and modify the graph to handle /// parts of the graph themselves. After this is called, the graph may @@ -1313,14 +1212,12 @@ class TensorFlowLiteBindings { } late final _TfLiteInterpreterModifyGraphWithDelegatePtr = _lookup< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer, - ffi.Pointer)>>( - 'TfLiteInterpreterModifyGraphWithDelegate'); + ffi.NativeFunction< + ffi.Int32 Function(ffi.Pointer, + ffi.Pointer)>>('TfLiteInterpreterModifyGraphWithDelegate'); late final _TfLiteInterpreterModifyGraphWithDelegate = _TfLiteInterpreterModifyGraphWithDelegatePtr.asFunction< - int Function( - ffi.Pointer, ffi.Pointer)>(); + int Function(ffi.Pointer, ffi.Pointer)>(); /// Returns the tensor index corresponding to the input tensor /// @@ -1335,13 +1232,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteInterpreterGetInputTensorIndexPtr = _lookup< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer, - ffi.Int32)>>('TfLiteInterpreterGetInputTensorIndex'); - late final _TfLiteInterpreterGetInputTensorIndex = - _TfLiteInterpreterGetInputTensorIndexPtr.asFunction< - int Function(ffi.Pointer, int)>(); + late final _TfLiteInterpreterGetInputTensorIndexPtr = + _lookup, ffi.Int32)>>( + 'TfLiteInterpreterGetInputTensorIndex'); + late final _TfLiteInterpreterGetInputTensorIndex = _TfLiteInterpreterGetInputTensorIndexPtr + .asFunction, int)>(); /// Returns the tensor index corresponding to the output tensor /// @@ -1356,13 +1251,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteInterpreterGetOutputTensorIndexPtr = _lookup< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer, - ffi.Int32)>>('TfLiteInterpreterGetOutputTensorIndex'); - late final _TfLiteInterpreterGetOutputTensorIndex = - _TfLiteInterpreterGetOutputTensorIndexPtr.asFunction< - int Function(ffi.Pointer, int)>(); + late final _TfLiteInterpreterGetOutputTensorIndexPtr = + _lookup, ffi.Int32)>>( + 'TfLiteInterpreterGetOutputTensorIndex'); + late final _TfLiteInterpreterGetOutputTensorIndex = _TfLiteInterpreterGetOutputTensorIndexPtr + .asFunction, int)>(); /// Returns the number of signatures defined in the model. /// @@ -1375,13 +1268,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteInterpreterGetSignatureCountPtr = _lookup< - ffi - .NativeFunction)>>( - 'TfLiteInterpreterGetSignatureCount'); - late final _TfLiteInterpreterGetSignatureCount = - _TfLiteInterpreterGetSignatureCountPtr.asFunction< - int Function(ffi.Pointer)>(); + late final _TfLiteInterpreterGetSignatureCountPtr = + _lookup)>>( + 'TfLiteInterpreterGetSignatureCount'); + late final _TfLiteInterpreterGetSignatureCount = _TfLiteInterpreterGetSignatureCountPtr + .asFunction)>(); /// Returns the key of the Nth signature in the model, where N is specified as /// `signature_index`. @@ -1402,12 +1293,10 @@ class TensorFlowLiteBindings { late final _TfLiteInterpreterGetSignatureKeyPtr = _lookup< ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Int32)>>('TfLiteInterpreterGetSignatureKey'); - late final _TfLiteInterpreterGetSignatureKey = - _TfLiteInterpreterGetSignatureKeyPtr.asFunction< ffi.Pointer Function( - ffi.Pointer, int)>(); + ffi.Pointer, ffi.Int32)>>('TfLiteInterpreterGetSignatureKey'); + late final _TfLiteInterpreterGetSignatureKey = _TfLiteInterpreterGetSignatureKeyPtr.asFunction< + ffi.Pointer Function(ffi.Pointer, int)>(); /// Returns a new signature runner using the provided interpreter and signature /// key, or nullptr on failure. @@ -1431,8 +1320,7 @@ class TensorFlowLiteBindings { late final _TfLiteInterpreterGetSignatureRunnerPtr = _lookup< ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, + ffi.Pointer Function(ffi.Pointer, ffi.Pointer)>>('TfLiteInterpreterGetSignatureRunner'); late final _TfLiteInterpreterGetSignatureRunner = _TfLiteInterpreterGetSignatureRunnerPtr.asFunction< @@ -1450,13 +1338,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteSignatureRunnerGetInputCountPtr = _lookup< - ffi.NativeFunction< - ffi.Size Function(ffi.Pointer)>>( - 'TfLiteSignatureRunnerGetInputCount'); - late final _TfLiteSignatureRunnerGetInputCount = - _TfLiteSignatureRunnerGetInputCountPtr.asFunction< - int Function(ffi.Pointer)>(); + late final _TfLiteSignatureRunnerGetInputCountPtr = + _lookup)>>( + 'TfLiteSignatureRunnerGetInputCount'); + late final _TfLiteSignatureRunnerGetInputCount = _TfLiteSignatureRunnerGetInputCountPtr + .asFunction)>(); /// Returns the (null-terminated) name of the Nth input in a signature, where N /// is specified as `input_index`. @@ -1477,12 +1363,10 @@ class TensorFlowLiteBindings { late final _TfLiteSignatureRunnerGetInputNamePtr = _lookup< ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Int32)>>('TfLiteSignatureRunnerGetInputName'); - late final _TfLiteSignatureRunnerGetInputName = - _TfLiteSignatureRunnerGetInputNamePtr.asFunction< ffi.Pointer Function( - ffi.Pointer, int)>(); + ffi.Pointer, ffi.Int32)>>('TfLiteSignatureRunnerGetInputName'); + late final _TfLiteSignatureRunnerGetInputName = _TfLiteSignatureRunnerGetInputNamePtr.asFunction< + ffi.Pointer Function(ffi.Pointer, int)>(); /// Resizes the input tensor identified as `input_name` to be the dimensions /// specified by `input_dims` and `input_dims_size`. Only unknown dimensions can @@ -1518,15 +1402,12 @@ class TensorFlowLiteBindings { late final _TfLiteSignatureRunnerResizeInputTensorPtr = _lookup< ffi.NativeFunction< - ffi.Int32 Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Int32)>>('TfLiteSignatureRunnerResizeInputTensor'); + ffi.Int32 Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer, ffi.Int32)>>('TfLiteSignatureRunnerResizeInputTensor'); late final _TfLiteSignatureRunnerResizeInputTensor = _TfLiteSignatureRunnerResizeInputTensorPtr.asFunction< - int Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer, int)>(); + int Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer, int)>(); /// Updates allocations for tensors associated with a signature and resizes /// dependent tensors using the specified input tensor dimensionality. @@ -1542,13 +1423,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteSignatureRunnerAllocateTensorsPtr = _lookup< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer)>>( - 'TfLiteSignatureRunnerAllocateTensors'); - late final _TfLiteSignatureRunnerAllocateTensors = - _TfLiteSignatureRunnerAllocateTensorsPtr.asFunction< - int Function(ffi.Pointer)>(); + late final _TfLiteSignatureRunnerAllocateTensorsPtr = + _lookup)>>( + 'TfLiteSignatureRunnerAllocateTensors'); + late final _TfLiteSignatureRunnerAllocateTensors = _TfLiteSignatureRunnerAllocateTensorsPtr + .asFunction)>(); /// Returns the input tensor identified by `input_name` in the given signature. /// Returns nullptr if the given name is not valid. @@ -1592,12 +1471,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteSignatureRunnerInvokePtr = _lookup< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer)>>( - 'TfLiteSignatureRunnerInvoke'); - late final _TfLiteSignatureRunnerInvoke = _TfLiteSignatureRunnerInvokePtr - .asFunction)>(); + late final _TfLiteSignatureRunnerInvokePtr = + _lookup)>>( + 'TfLiteSignatureRunnerInvoke'); + late final _TfLiteSignatureRunnerInvoke = _TfLiteSignatureRunnerInvokePtr.asFunction< + int Function(ffi.Pointer)>(); /// Returns the number of output tensors associated with the signature. /// @@ -1610,13 +1488,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteSignatureRunnerGetOutputCountPtr = _lookup< - ffi.NativeFunction< - ffi.Size Function(ffi.Pointer)>>( - 'TfLiteSignatureRunnerGetOutputCount'); - late final _TfLiteSignatureRunnerGetOutputCount = - _TfLiteSignatureRunnerGetOutputCountPtr.asFunction< - int Function(ffi.Pointer)>(); + late final _TfLiteSignatureRunnerGetOutputCountPtr = + _lookup)>>( + 'TfLiteSignatureRunnerGetOutputCount'); + late final _TfLiteSignatureRunnerGetOutputCount = _TfLiteSignatureRunnerGetOutputCountPtr + .asFunction)>(); /// Returns the (null-terminated) name of the Nth output in a signature, where /// N is specified as `output_index`. @@ -1639,10 +1515,8 @@ class TensorFlowLiteBindings { ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Int32)>>('TfLiteSignatureRunnerGetOutputName'); - late final _TfLiteSignatureRunnerGetOutputName = - _TfLiteSignatureRunnerGetOutputNamePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, int)>(); + late final _TfLiteSignatureRunnerGetOutputName = _TfLiteSignatureRunnerGetOutputNamePtr + .asFunction Function(ffi.Pointer, int)>(); /// Returns the output tensor identified by `output_name` in the given /// signature. Returns nullptr if the given name is not valid. @@ -1681,12 +1555,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteSignatureRunnerDeletePtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer)>>( - 'TfLiteSignatureRunnerDelete'); - late final _TfLiteSignatureRunnerDelete = _TfLiteSignatureRunnerDeletePtr - .asFunction)>(); + late final _TfLiteSignatureRunnerDeletePtr = + _lookup)>>( + 'TfLiteSignatureRunnerDelete'); + late final _TfLiteSignatureRunnerDelete = _TfLiteSignatureRunnerDeletePtr.asFunction< + void Function(ffi.Pointer)>(); /// Return a delegate that uses CoreML for ops execution. /// Must outlive the interpreter. @@ -1699,14 +1572,11 @@ class TensorFlowLiteBindings { } late final _TfLiteCoreMlDelegateCreatePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>( - 'TfLiteCoreMlDelegateCreate'); - late final _TfLiteCoreMlDelegateCreate = - _TfLiteCoreMlDelegateCreatePtr.asFunction< + ffi.NativeFunction< ffi.Pointer Function( - ffi.Pointer)>(); + ffi.Pointer)>>('TfLiteCoreMlDelegateCreate'); + late final _TfLiteCoreMlDelegateCreate = _TfLiteCoreMlDelegateCreatePtr.asFunction< + ffi.Pointer Function(ffi.Pointer)>(); /// Do any needed cleanup and delete 'delegate'. void TfLiteCoreMlDelegateDelete( @@ -1717,11 +1587,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteCoreMlDelegateDeletePtr = _lookup< - ffi.NativeFunction)>>( - 'TfLiteCoreMlDelegateDelete'); - late final _TfLiteCoreMlDelegateDelete = _TfLiteCoreMlDelegateDeletePtr - .asFunction)>(); + late final _TfLiteCoreMlDelegateDeletePtr = + _lookup)>>( + 'TfLiteCoreMlDelegateDelete'); + late final _TfLiteCoreMlDelegateDelete = + _TfLiteCoreMlDelegateDeletePtr.asFunction)>(); /// Populates TFLGpuDelegateOptions as follows: /// allow_precision_loss = false; @@ -1732,10 +1602,9 @@ class TensorFlowLiteBindings { } late final _TFLGpuDelegateOptionsDefaultPtr = - _lookup>( - 'TFLGpuDelegateOptionsDefault'); - late final _TFLGpuDelegateOptionsDefault = _TFLGpuDelegateOptionsDefaultPtr - .asFunction(); + _lookup>('TFLGpuDelegateOptionsDefault'); + late final _TFLGpuDelegateOptionsDefault = + _TFLGpuDelegateOptionsDefaultPtr.asFunction(); /// Creates a new delegate instance that need to be destroyed with /// `TFLDeleteTfLiteGpuDelegate` when delegate is no longer used by TFLite. @@ -1755,8 +1624,7 @@ class TensorFlowLiteBindings { ffi.Pointer Function( ffi.Pointer)>>('TFLGpuDelegateCreate'); late final _TFLGpuDelegateCreate = _TFLGpuDelegateCreatePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer)>(); + ffi.Pointer Function(ffi.Pointer)>(); /// Destroys a delegate created with `TFLGpuDelegateCreate` call. void TFLGpuDelegateDelete( @@ -1767,11 +1635,11 @@ class TensorFlowLiteBindings { ); } - late final _TFLGpuDelegateDeletePtr = _lookup< - ffi.NativeFunction)>>( - 'TFLGpuDelegateDelete'); - late final _TFLGpuDelegateDelete = _TFLGpuDelegateDeletePtr.asFunction< - void Function(ffi.Pointer)>(); + late final _TFLGpuDelegateDeletePtr = + _lookup)>>( + 'TFLGpuDelegateDelete'); + late final _TFLGpuDelegateDelete = + _TFLGpuDelegateDeletePtr.asFunction)>(); /// Binds Metal buffer to an input or an output tensor in the initialized /// delegate. Bound buffer should have sufficient storage to accommodate all @@ -1793,13 +1661,11 @@ class TensorFlowLiteBindings { ); } - late final _TFLGpuDelegateBindMetalBufferToTensorPtr = _lookup< - ffi.NativeFunction< - ffi.Bool Function(ffi.Pointer, ffi.Int, - ffi.Int)>>('TFLGpuDelegateBindMetalBufferToTensor'); - late final _TFLGpuDelegateBindMetalBufferToTensor = - _TFLGpuDelegateBindMetalBufferToTensorPtr.asFunction< - bool Function(ffi.Pointer, int, int)>(); + late final _TFLGpuDelegateBindMetalBufferToTensorPtr = + _lookup, ffi.Int, ffi.Int)>>( + 'TFLGpuDelegateBindMetalBufferToTensor'); + late final _TFLGpuDelegateBindMetalBufferToTensor = _TFLGpuDelegateBindMetalBufferToTensorPtr + .asFunction, int, int)>(); /// Returns a structure with the default XNNPack delegate options. TfLiteXNNPackDelegateOptions TfLiteXNNPackDelegateOptionsDefault() { @@ -1810,8 +1676,7 @@ class TensorFlowLiteBindings { _lookup>( 'TfLiteXNNPackDelegateOptionsDefault'); late final _TfLiteXNNPackDelegateOptionsDefault = - _TfLiteXNNPackDelegateOptionsDefaultPtr.asFunction< - TfLiteXNNPackDelegateOptions Function()>(); + _TfLiteXNNPackDelegateOptionsDefaultPtr.asFunction(); /// Creates a new delegate instance that need to be destroyed with /// `TfLiteXNNPackDelegateDelete` when delegate is no longer used by TFLite. @@ -1827,14 +1692,11 @@ class TensorFlowLiteBindings { } late final _TfLiteXNNPackDelegateCreatePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>( - 'TfLiteXNNPackDelegateCreate'); - late final _TfLiteXNNPackDelegateCreate = - _TfLiteXNNPackDelegateCreatePtr.asFunction< + ffi.NativeFunction< ffi.Pointer Function( - ffi.Pointer)>(); + ffi.Pointer)>>('TfLiteXNNPackDelegateCreate'); + late final _TfLiteXNNPackDelegateCreate = _TfLiteXNNPackDelegateCreatePtr.asFunction< + ffi.Pointer Function(ffi.Pointer)>(); /// Performs the same task as TfLiteXNNPackDelegateCreate, with one exception. /// If the context passed contains a non-null xnnpack_threadpool field, @@ -1850,16 +1712,13 @@ class TensorFlowLiteBindings { } late final _TfLiteXNNPackDelegateCreateWithThreadpoolPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer)>>( - 'TfLiteXNNPackDelegateCreateWithThreadpool'); + ffi.NativeFunction< + ffi.Pointer Function(ffi.Pointer, + ffi.Pointer)>>('TfLiteXNNPackDelegateCreateWithThreadpool'); late final _TfLiteXNNPackDelegateCreateWithThreadpool = _TfLiteXNNPackDelegateCreateWithThreadpoolPtr.asFunction< ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer)>(); + ffi.Pointer, ffi.Pointer)>(); /// Returns the pthreadpool_t object used for parallelization in XNNPACK. /// Can return NULL if the XNNPack delegate is single-threaded. @@ -1873,13 +1732,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteXNNPackDelegateGetThreadPoolPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer)>>( - 'TfLiteXNNPackDelegateGetThreadPool'); - late final _TfLiteXNNPackDelegateGetThreadPool = - _TfLiteXNNPackDelegateGetThreadPoolPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); + late final _TfLiteXNNPackDelegateGetThreadPoolPtr = + _lookup Function(ffi.Pointer)>>( + 'TfLiteXNNPackDelegateGetThreadPool'); + late final _TfLiteXNNPackDelegateGetThreadPool = _TfLiteXNNPackDelegateGetThreadPoolPtr + .asFunction Function(ffi.Pointer)>(); /// Destroys a delegate created with `TfLiteXNNPackDelegateCreate` call. void TfLiteXNNPackDelegateDelete( @@ -1890,33 +1747,29 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteXNNPackDelegateDeletePtr = _lookup< - ffi.NativeFunction)>>( - 'TfLiteXNNPackDelegateDelete'); - late final _TfLiteXNNPackDelegateDelete = _TfLiteXNNPackDelegateDeletePtr - .asFunction)>(); + late final _TfLiteXNNPackDelegateDeletePtr = + _lookup)>>( + 'TfLiteXNNPackDelegateDelete'); + late final _TfLiteXNNPackDelegateDelete = + _TfLiteXNNPackDelegateDeletePtr.asFunction)>(); /// Creates a new weights cache that can be shared with multiple delegate /// instances. Prefer TfLiteXNNPackDelegateWeightsCacheCreateWithSize which can /// reduce memory bandwidth. - ffi.Pointer - TfLiteXNNPackDelegateWeightsCacheCreate() { + ffi.Pointer TfLiteXNNPackDelegateWeightsCacheCreate() { return _TfLiteXNNPackDelegateWeightsCacheCreate(); } - late final _TfLiteXNNPackDelegateWeightsCacheCreatePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer - Function()>>('TfLiteXNNPackDelegateWeightsCacheCreate'); - late final _TfLiteXNNPackDelegateWeightsCacheCreate = - _TfLiteXNNPackDelegateWeightsCacheCreatePtr.asFunction< - ffi.Pointer Function()>(); + late final _TfLiteXNNPackDelegateWeightsCacheCreatePtr = + _lookup Function()>>( + 'TfLiteXNNPackDelegateWeightsCacheCreate'); + late final _TfLiteXNNPackDelegateWeightsCacheCreate = _TfLiteXNNPackDelegateWeightsCacheCreatePtr + .asFunction Function()>(); /// Creates a new weights cache with a specified initial size that can be shared /// with multiple delegate instances. The weights cache can hold up to size bytes /// without growing. - ffi.Pointer - TfLiteXNNPackDelegateWeightsCacheCreateWithSize( + ffi.Pointer TfLiteXNNPackDelegateWeightsCacheCreateWithSize( int size, ) { return _TfLiteXNNPackDelegateWeightsCacheCreateWithSize( @@ -1925,9 +1778,8 @@ class TensorFlowLiteBindings { } late final _TfLiteXNNPackDelegateWeightsCacheCreateWithSizePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Size)>>('TfLiteXNNPackDelegateWeightsCacheCreateWithSize'); + ffi.NativeFunction Function(ffi.Size)>>( + 'TfLiteXNNPackDelegateWeightsCacheCreateWithSize'); late final _TfLiteXNNPackDelegateWeightsCacheCreateWithSize = _TfLiteXNNPackDelegateWeightsCacheCreateWithSizePtr.asFunction< ffi.Pointer Function(int)>(); @@ -1947,9 +1799,7 @@ class TensorFlowLiteBindings { } late final _TfLiteXNNPackDelegateWeightsCacheFinalizeSoftPtr = _lookup< - ffi.NativeFunction< - ffi.Bool Function( - ffi.Pointer)>>( + ffi.NativeFunction)>>( 'TfLiteXNNPackDelegateWeightsCacheFinalizeSoft'); late final _TfLiteXNNPackDelegateWeightsCacheFinalizeSoft = _TfLiteXNNPackDelegateWeightsCacheFinalizeSoftPtr.asFunction< @@ -1970,9 +1820,7 @@ class TensorFlowLiteBindings { } late final _TfLiteXNNPackDelegateWeightsCacheFinalizeHardPtr = _lookup< - ffi.NativeFunction< - ffi.Bool Function( - ffi.Pointer)>>( + ffi.NativeFunction)>>( 'TfLiteXNNPackDelegateWeightsCacheFinalizeHard'); late final _TfLiteXNNPackDelegateWeightsCacheFinalizeHard = _TfLiteXNNPackDelegateWeightsCacheFinalizeHardPtr.asFunction< @@ -1989,13 +1837,10 @@ class TensorFlowLiteBindings { } late final _TfLiteXNNPackDelegateWeightsCacheDeletePtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer)>>( + ffi.NativeFunction)>>( 'TfLiteXNNPackDelegateWeightsCacheDelete'); - late final _TfLiteXNNPackDelegateWeightsCacheDelete = - _TfLiteXNNPackDelegateWeightsCacheDeletePtr.asFunction< - void Function(ffi.Pointer)>(); + late final _TfLiteXNNPackDelegateWeightsCacheDelete = _TfLiteXNNPackDelegateWeightsCacheDeletePtr + .asFunction)>(); /// Creates a new delegate instance that need to be destroyed with /// TfLiteGpuDelegateV2Delete when delegate is no longer used by TFLite. @@ -2013,14 +1858,11 @@ class TensorFlowLiteBindings { } late final _TfLiteGpuDelegateV2CreatePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>( - 'TfLiteGpuDelegateV2Create'); - late final _TfLiteGpuDelegateV2Create = - _TfLiteGpuDelegateV2CreatePtr.asFunction< + ffi.NativeFunction< ffi.Pointer Function( - ffi.Pointer)>(); + ffi.Pointer)>>('TfLiteGpuDelegateV2Create'); + late final _TfLiteGpuDelegateV2Create = _TfLiteGpuDelegateV2CreatePtr.asFunction< + ffi.Pointer Function(ffi.Pointer)>(); /// Destroys a delegate created with `TfLiteGpuDelegateV2Create` call. void TfLiteGpuDelegateV2Delete( @@ -2031,11 +1873,11 @@ class TensorFlowLiteBindings { ); } - late final _TfLiteGpuDelegateV2DeletePtr = _lookup< - ffi.NativeFunction)>>( - 'TfLiteGpuDelegateV2Delete'); - late final _TfLiteGpuDelegateV2Delete = _TfLiteGpuDelegateV2DeletePtr - .asFunction)>(); + late final _TfLiteGpuDelegateV2DeletePtr = + _lookup)>>( + 'TfLiteGpuDelegateV2Delete'); + late final _TfLiteGpuDelegateV2Delete = + _TfLiteGpuDelegateV2DeletePtr.asFunction)>(); /// Populates TfLiteGpuDelegateOptionsV2 as follows: /// is_precision_loss_allowed = false @@ -2053,8 +1895,7 @@ class TensorFlowLiteBindings { _lookup>( 'TfLiteGpuDelegateOptionsV2Default'); late final _TfLiteGpuDelegateOptionsV2Default = - _TfLiteGpuDelegateOptionsV2DefaultPtr.asFunction< - TfLiteGpuDelegateOptionsV2 Function()>(); + _TfLiteGpuDelegateOptionsV2DefaultPtr.asFunction(); } final class TfLiteModel extends ffi.Opaque {} @@ -2075,8 +1916,8 @@ final class TfLiteDelegate extends ffi.Struct { /// delegated subgraphs of the original graph. external ffi.Pointer< ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer context, - ffi.Pointer delegate)>> Prepare; + ffi.Int32 Function( + ffi.Pointer context, ffi.Pointer delegate)>> Prepare; /// Copy the data from delegate buffer handle into raw memory of the given /// 'tensor'. Note that the delegate is allowed to allocate the raw bytes as @@ -2215,10 +2056,9 @@ final class TfLiteContext extends ffi.Struct { /// /// WARNING: This is an experimental interface that is subject to change. external ffi.Pointer< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer context, - ffi.Pointer> execution_plan)>> - GetExecutionPlan; + ffi.NativeFunction< + ffi.Int32 Function(ffi.Pointer context, + ffi.Pointer> execution_plan)>> GetExecutionPlan; /// An array of tensors in the interpreter context (of length `tensors_size`) external ffi.Pointer tensors; @@ -2230,44 +2070,41 @@ final class TfLiteContext extends ffi.Struct { /// NOTE: ResizeTensor takes ownership of newSize. external ffi.Pointer< ffi.NativeFunction< - ffi.Int32 Function( - ffi.Pointer, - ffi.Pointer, + ffi.Int32 Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>> ResizeTensor; /// Request that an error be reported with format string msg. external ffi.Pointer< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer, ffi.Pointer)>> ReportError; + ffi.NativeFunction, ffi.Pointer)>> + ReportError; /// Add `tensors_to_add` tensors, preserving pre-existing Tensor entries. If /// non-null, the value pointed to by `first_new_tensor_index` will be set to /// the index of the first new tensor. external ffi.Pointer< ffi.NativeFunction< - ffi.Int32 Function( - ffi.Pointer, ffi.Int, ffi.Pointer)>> + ffi.Int32 Function(ffi.Pointer, ffi.Int, ffi.Pointer)>> AddTensors; /// Get a Tensor node by node_index. /// WARNING: This is an experimental interface that is subject to change. external ffi.Pointer< - ffi.NativeFunction< - ffi.Int32 Function( - ffi.Pointer, - ffi.Int, - ffi.Pointer>, - ffi.Pointer>)>> - GetNodeAndRegistration; + ffi.NativeFunction< + ffi.Int32 Function( + ffi.Pointer, + ffi.Int, + ffi.Pointer>, + ffi.Pointer>)>> GetNodeAndRegistration; /// Replace ops with one or more stub delegate operations. This function /// does not take ownership of `nodes_to_replace`. external ffi.Pointer< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer, TfLiteRegistration, - ffi.Pointer, ffi.Pointer)>> - ReplaceNodeSubsetsWithDelegateKernels; + ffi.NativeFunction< + ffi.Int32 Function( + ffi.Pointer, + TfLiteRegistration, + ffi.Pointer, + ffi.Pointer)>> ReplaceNodeSubsetsWithDelegateKernels; /// Number of threads that are recommended to subsystems like gemmlowp and /// eigen. @@ -2277,17 +2114,18 @@ final class TfLiteContext extends ffi.Struct { /// Access external contexts by type. /// WARNING: This is an experimental interface that is subject to change. external ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Int32)>> GetExternalContext; + ffi.NativeFunction< + ffi.Pointer Function(ffi.Pointer, ffi.Int32)>> + GetExternalContext; /// Set the value of a external context. Does not take ownership of the /// pointer. /// WARNING: This is an experimental interface that is subject to change. external ffi.Pointer< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, ffi.Int32, - ffi.Pointer)>> SetExternalContext; + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer, ffi.Int32, ffi.Pointer)>> + SetExternalContext; /// Flag for allowing float16 precision for FP32 calculation. /// default: false. @@ -2305,8 +2143,7 @@ final class TfLiteContext extends ffi.Struct { /// WARNING: This is an experimental interface that is subject to change. external ffi.Pointer< ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer ctx, ffi.Size bytes)>> + ffi.Pointer Function(ffi.Pointer ctx, ffi.Size bytes)>> AllocatePersistentBuffer; /// Allocate a buffer which will be deallocated right after invoke phase. @@ -2326,17 +2163,17 @@ final class TfLiteContext extends ffi.Struct { /// GetScratchBuffer API can be used to fetch the address. /// WARNING: This is an experimental interface that is subject to change. external ffi.Pointer< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer ctx, ffi.Size bytes, - ffi.Pointer buffer_idx)>> RequestScratchBufferInArena; + ffi.NativeFunction< + ffi.Int32 Function( + ffi.Pointer ctx, ffi.Size bytes, ffi.Pointer buffer_idx)>> + RequestScratchBufferInArena; /// Get the scratch buffer pointer. /// This method is only available in Eval stage. /// WARNING: This is an experimental interface that is subject to change. external ffi.Pointer< ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer ctx, ffi.Int buffer_idx)>> + ffi.Pointer Function(ffi.Pointer ctx, ffi.Int buffer_idx)>> GetScratchBuffer; /// Resize the memory pointer of the `tensor`. This method behaves the same as @@ -2345,11 +2182,8 @@ final class TfLiteContext extends ffi.Struct { /// WARNING: This is an experimental interface that is subject to change. external ffi.Pointer< ffi.NativeFunction< - ffi.Int32 Function( - ffi.Pointer ctx, - ffi.Pointer tensor, - ffi.Int dims, - ffi.Pointer shape)>> ResizeTensorExplicit; + ffi.Int32 Function(ffi.Pointer ctx, ffi.Pointer tensor, + ffi.Int dims, ffi.Pointer shape)>> ResizeTensorExplicit; /// This method provides a preview of post-delegation partitioning. Each /// TfLiteDelegateParams in the referenced array corresponds to one instance of @@ -2372,32 +2206,28 @@ final class TfLiteContext extends ffi.Struct { /// /// WARNING: This is an experimental interface that is subject to change. external ffi.Pointer< - ffi.NativeFunction< - ffi.Int32 Function( - ffi.Pointer context, - ffi.Pointer nodes_to_replace, - ffi.Pointer> - partition_params_array, - ffi.Pointer num_partitions)>> - PreviewDelegatePartitioning; + ffi.NativeFunction< + ffi.Int32 Function( + ffi.Pointer context, + ffi.Pointer nodes_to_replace, + ffi.Pointer> partition_params_array, + ffi.Pointer num_partitions)>> PreviewDelegatePartitioning; /// Returns a TfLiteTensor struct for a given index. /// WARNING: This is an experimental interface that is subject to change. /// WARNING: This method may not be available on all platforms. external ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer context, ffi.Int tensor_idx)>> - GetTensor; + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer context, ffi.Int tensor_idx)>> GetTensor; /// Returns a TfLiteEvalTensor struct for a given index. /// WARNING: This is an experimental interface that is subject to change. /// WARNING: This method may not be available on all platforms. external ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer context, ffi.Int tensor_idx)>> - GetEvalTensor; + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer context, ffi.Int tensor_idx)>> GetEvalTensor; /// Retrieves named metadata buffer from the TFLite model. /// Returns kTfLiteOk if metadata is successfully obtained from the flatbuffer @@ -2758,9 +2588,9 @@ final class TfLiteRegistration extends ffi.Struct { /// The pointer `buffer` is the data previously returned by an init invocation. external ffi.Pointer< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer context, - ffi.Pointer buffer)>> free; + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer context, ffi.Pointer buffer)>> + free; /// prepare is called when the inputs this node depends on have been resized. /// context->ResizeTensor() can be called to request output tensors to be @@ -2769,16 +2599,16 @@ final class TfLiteRegistration extends ffi.Struct { /// /// Returns kTfLiteOk on success. external ffi.Pointer< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer context, - ffi.Pointer node)>> prepare; + ffi.NativeFunction< + ffi.Int32 Function(ffi.Pointer context, ffi.Pointer node)>> + prepare; /// Execute the node (should read node->inputs and output to node->outputs). /// Returns kTfLiteOk on success. external ffi.Pointer< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer context, - ffi.Pointer node)>> invoke; + ffi.NativeFunction< + ffi.Int32 Function(ffi.Pointer context, ffi.Pointer node)>> + invoke; /// profiling_string is called during summarization of profiling information /// in order to group executions together. Providing a value here will cause a @@ -2787,8 +2617,8 @@ final class TfLiteRegistration extends ffi.Struct { /// different calculations depending on their `user-data`. external ffi.Pointer< ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer context, - ffi.Pointer node)>> profiling_string; + ffi.Pointer Function( + ffi.Pointer context, ffi.Pointer node)>> profiling_string; /// Builtin codes. If this kernel refers to a builtin this is the code /// of the builtin. This is so we can do marshaling to other frameworks like @@ -2829,9 +2659,8 @@ final class TfLiteExternalContext extends ffi.Struct { @ffi.Int32() external int type; - external ffi.Pointer< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer context)>> Refresh; + external ffi.Pointer context)>> + Refresh; } /// The list of external context types known to TF Lite. This list exists solely @@ -3137,24 +2966,24 @@ final class TfLiteRegistration_V1 extends ffi.Struct { ffi.Pointer buffer, ffi.Size length)>> init; external ffi.Pointer< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer context, - ffi.Pointer buffer)>> free; + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer context, ffi.Pointer buffer)>> + free; external ffi.Pointer< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer context, - ffi.Pointer node)>> prepare; + ffi.NativeFunction< + ffi.Int32 Function(ffi.Pointer context, ffi.Pointer node)>> + prepare; external ffi.Pointer< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer context, - ffi.Pointer node)>> invoke; + ffi.NativeFunction< + ffi.Int32 Function(ffi.Pointer context, ffi.Pointer node)>> + invoke; external ffi.Pointer< ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer context, - ffi.Pointer node)>> profiling_string; + ffi.Pointer Function( + ffi.Pointer context, ffi.Pointer node)>> profiling_string; @ffi.Int32() external int builtin_code; diff --git a/lib/src/delegate.dart b/lib/src/delegate.dart index d69cc52..265b9d6 100644 --- a/lib/src/delegate.dart +++ b/lib/src/delegate.dart @@ -15,12 +15,12 @@ */ import 'dart:ffi'; -import 'package:tflite_flutter/src/bindings/tensorflow_lite_bindings_generated.dart'; +import 'package:tflite_core/src/bindings/tensorflow_lite_bindings_generated.dart'; abstract class Delegate { - /// Get pointer to TfLiteDelegate + /// Native delegate pointer passed to interpreter options. Pointer get base; - /// Destroys delegate instance + /// Releases the native delegate resources. void delete(); } diff --git a/lib/src/delegates/coreml_delegate.dart b/lib/src/delegates/coreml_delegate.dart index eda5519..3839113 100644 --- a/lib/src/delegates/coreml_delegate.dart +++ b/lib/src/delegates/coreml_delegate.dart @@ -17,11 +17,11 @@ import 'dart:ffi'; import 'package:ffi/ffi.dart'; import 'package:quiver/check.dart'; -import 'package:tflite_flutter/src/bindings/bindings.dart'; -import 'package:tflite_flutter/src/bindings/tensorflow_lite_bindings_generated.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/src/bindings/bindings.dart'; +import 'package:tflite_core/src/bindings/tensorflow_lite_bindings_generated.dart'; +import 'package:tflite_core/tflite_core.dart'; -/// CoreMl Delegate +/// Core ML delegate for accelerating inference on Apple platforms. class CoreMlDelegate implements Delegate { Pointer _delegate; bool _deleted = false; @@ -31,6 +31,7 @@ class CoreMlDelegate implements Delegate { CoreMlDelegate._(this._delegate); + /// Creates a Core ML delegate, optionally configured with [options]. factory CoreMlDelegate({CoreMlDelegateOptions? options}) { final delegateOptions = options ?? CoreMlDelegateOptions(); @@ -47,7 +48,7 @@ class CoreMlDelegate implements Delegate { } } -/// CoreMlDelegate Options +/// Options for configuring a Core ML delegate. class CoreMlDelegateOptions { Pointer _options; bool _deleted = false; @@ -56,9 +57,16 @@ class CoreMlDelegateOptions { CoreMlDelegateOptions._(this._options); + /// Creates Core ML options. + /// + /// [enabledDevices] selects the device class used for inference. + /// [coremlVersion] selects a Core ML version, or zero for the default. + /// [maxDelegatedPartitions] limits delegated graph partitions, or zero for + /// the default. + /// [minNodesPerPartition] is the minimum number of nodes in a partition. factory CoreMlDelegateOptions({ - int enabledDevices = TfLiteCoreMlDelegateEnabledDevices - .TfLiteCoreMlDelegateDevicesWithNeuralEngine, + int enabledDevices = + TfLiteCoreMlDelegateEnabledDevices.TfLiteCoreMlDelegateDevicesWithNeuralEngine, int coremlVersion = 0, int maxDelegatedPartitions = 0, int minNodesPerPartition = 2, @@ -74,6 +82,7 @@ class CoreMlDelegateOptions { return CoreMlDelegateOptions._(options); } + /// Releases the native options. void delete() { checkState(!_deleted, message: 'CoreMlDelegate already deleted.'); calloc.free(_options); diff --git a/lib/src/delegates/gpu_delegate.dart b/lib/src/delegates/gpu_delegate.dart index cfdb4ad..67aa89f 100644 --- a/lib/src/delegates/gpu_delegate.dart +++ b/lib/src/delegates/gpu_delegate.dart @@ -17,9 +17,9 @@ import 'dart:ffi'; import 'package:ffi/ffi.dart'; import 'package:quiver/check.dart'; -import 'package:tflite_flutter/src/bindings/bindings.dart'; -import 'package:tflite_flutter/src/bindings/tensorflow_lite_bindings_generated.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/src/bindings/bindings.dart'; +import 'package:tflite_core/src/bindings/tensorflow_lite_bindings_generated.dart'; +import 'package:tflite_core/tflite_core.dart'; /// GPU delegate for Android class GpuDelegateV2 implements Delegate { @@ -31,18 +31,18 @@ class GpuDelegateV2 implements Delegate { GpuDelegateV2._(this._delegate); - /// Creates [GpuDelegateV2] using the specified [options] - /// uses [GpuDelegateOptionsV2.defaultOptions()] if options not - /// specified. + /// Creates an Android GPU delegate using [options] when provided, or the + /// TensorFlow Lite defaults otherwise. factory GpuDelegateV2({GpuDelegateOptionsV2? options}) { if (options == null) { return GpuDelegateV2._( tfliteBindingGpu.TfLiteGpuDelegateV2Create(nullptr), ); } - return GpuDelegateV2._( - tfliteBindingGpu.TfLiteGpuDelegateV2Create(options.base)); + return GpuDelegateV2._(tfliteBindingGpu.TfLiteGpuDelegateV2Create(options.base)); } + + /// Releases the native delegate. @override void delete() { checkState(!_deleted, message: 'TfLiteGpuDelegateV2 already deleted.'); @@ -51,15 +51,16 @@ class GpuDelegateV2 implements Delegate { } } -/// GPU delegate options for Android +/// Options for configuring the Android GPU delegate. class GpuDelegateOptionsV2 { Pointer _options; bool _deleted = false; + /// Native options pointer used when creating the delegate. Pointer get base => _options; GpuDelegateOptionsV2._(this._options); - /// Creates GpuDelegateOptionsV2 with specified parameters + /// Creates GPU delegate options. /// /// [isPrecisionLossAllowed] /// When set to zero, computations are carried out in maximal possible @@ -105,16 +106,18 @@ class GpuDelegateOptionsV2 { /// delegated to the GPU. /// This limits the maximum number of partitions to be delegated. By default, /// it's set to 1 in TfLiteGpuDelegateOptionsV2Default(). + /// + /// [inferencePreference] controls the delegate's inference workload. + /// [inferencePriority1], [inferencePriority2], and [inferencePriority3] + /// specify ordered preferences for latency, precision, and memory use. + /// [experimentalFlags] selects optional GPU delegate features. factory GpuDelegateOptionsV2({ bool isPrecisionLossAllowed = false, - int inferencePreference = TfLiteGpuInferenceUsage - .TFLITE_GPU_INFERENCE_PREFERENCE_FAST_SINGLE_ANSWER, - int inferencePriority1 = - TfLiteGpuInferencePriority.TFLITE_GPU_INFERENCE_PRIORITY_MAX_PRECISION, - int inferencePriority2 = - TfLiteGpuInferencePriority.TFLITE_GPU_INFERENCE_PRIORITY_AUTO, - int inferencePriority3 = - TfLiteGpuInferencePriority.TFLITE_GPU_INFERENCE_PRIORITY_AUTO, + int inferencePreference = + TfLiteGpuInferenceUsage.TFLITE_GPU_INFERENCE_PREFERENCE_FAST_SINGLE_ANSWER, + int inferencePriority1 = TfLiteGpuInferencePriority.TFLITE_GPU_INFERENCE_PRIORITY_MAX_PRECISION, + int inferencePriority2 = TfLiteGpuInferencePriority.TFLITE_GPU_INFERENCE_PRIORITY_AUTO, + int inferencePriority3 = TfLiteGpuInferencePriority.TFLITE_GPU_INFERENCE_PRIORITY_AUTO, List experimentalFlags = const [ TfLiteGpuExperimentalFlags.TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_QUANT ], @@ -127,13 +130,13 @@ class GpuDelegateOptionsV2 { ..inference_priority1 = inferencePriority1 ..inference_priority2 = inferencePriority2 ..inference_priority3 = inferencePriority3 - ..experimental_flags = - _TfLiteGpuExperimentalFlagsUtil.getBitmask(experimentalFlags) + ..experimental_flags = _TfLiteGpuExperimentalFlagsUtil.getBitmask(experimentalFlags) ..max_delegated_partitions = maxDelegatePartitions; return GpuDelegateOptionsV2._(options); } + /// Releases the native options. void delete() { checkState(!_deleted, message: 'TfLiteGpuDelegateV2 already deleted.'); calloc.free(_options); @@ -149,8 +152,7 @@ class _TfLiteGpuExperimentalFlagsUtil { static int value(int flag) { switch (flag) { - case TfLiteGpuExperimentalFlags - .TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_QUANT: + case TfLiteGpuExperimentalFlags.TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_QUANT: return enableQuant; case TfLiteGpuExperimentalFlags.TFLITE_GPU_EXPERIMENTAL_FLAGS_CL_ONLY: return clOnly; diff --git a/lib/src/delegates/metal_delegate.dart b/lib/src/delegates/metal_delegate.dart index 8dcad75..685744a 100644 --- a/lib/src/delegates/metal_delegate.dart +++ b/lib/src/delegates/metal_delegate.dart @@ -17,9 +17,9 @@ import 'dart:ffi'; import 'package:ffi/ffi.dart'; import 'package:quiver/check.dart'; -import 'package:tflite_flutter/src/bindings/bindings.dart'; -import 'package:tflite_flutter/src/bindings/tensorflow_lite_bindings_generated.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/src/bindings/bindings.dart'; +import 'package:tflite_core/src/bindings/tensorflow_lite_bindings_generated.dart'; +import 'package:tflite_core/tflite_core.dart'; /// Metal Delegate for iOS class GpuDelegate implements Delegate { @@ -31,6 +31,7 @@ class GpuDelegate implements Delegate { GpuDelegate._(this._delegate); + /// Creates a Metal delegate, optionally configured with [options]. factory GpuDelegate({GpuDelegateOptions? options}) { if (options == null) { return GpuDelegate._( @@ -57,6 +58,11 @@ class GpuDelegateOptions { GpuDelegateOptions._(this._options); + /// Creates options for configuring a Metal delegate. + /// + /// [allowPrecisionLoss] allows lower-precision calculations where supported. + /// [waitType] controls how the delegate waits for GPU work to complete. + /// [enableQuantization] enables quantized model support. factory GpuDelegateOptions({ bool allowPrecisionLoss = false, int waitType = TFLGpuDelegateWaitType.TFLGpuDelegateWaitTypePassive, @@ -72,6 +78,7 @@ class GpuDelegateOptions { return GpuDelegateOptions._(options); } + /// Releases the native options. void delete() { checkState(!_deleted, message: 'TfLiteGpuDelegate already deleted.'); calloc.free(_options); diff --git a/lib/src/delegates/xnnpack_delegate.dart b/lib/src/delegates/xnnpack_delegate.dart index 70adaa0..787d6be 100644 --- a/lib/src/delegates/xnnpack_delegate.dart +++ b/lib/src/delegates/xnnpack_delegate.dart @@ -17,12 +17,12 @@ import 'dart:ffi'; import 'package:ffi/ffi.dart'; import 'package:quiver/check.dart'; -import 'package:tflite_flutter/src/bindings/bindings.dart'; -import 'package:tflite_flutter/src/bindings/tensorflow_lite_bindings_generated.dart'; +import 'package:tflite_core/src/bindings/bindings.dart'; +import 'package:tflite_core/src/bindings/tensorflow_lite_bindings_generated.dart'; import '../delegate.dart'; -/// XNNPack Delegate +/// XNNPACK delegate for CPU inference. class XNNPackDelegate implements Delegate { Pointer _delegate; bool _deleted = false; @@ -32,14 +32,14 @@ class XNNPackDelegate implements Delegate { XNNPackDelegate._(this._delegate); + /// Creates an XNNPACK delegate, optionally configured with [options]. factory XNNPackDelegate({XNNPackDelegateOptions? options}) { if (options == null) { return XNNPackDelegate._( tfliteBinding.TfLiteXNNPackDelegateCreate(nullptr), ); } - return XNNPackDelegate._( - tfliteBinding.TfLiteXNNPackDelegateCreate(options.base)); + return XNNPackDelegate._(tfliteBinding.TfLiteXNNPackDelegateCreate(options.base)); } @override @@ -50,7 +50,7 @@ class XNNPackDelegate implements Delegate { } } -/// XNNPackDelegate Options +/// Options for configuring an XNNPACK delegate. class XNNPackDelegateOptions { Pointer _options; bool _deleted = false; @@ -59,6 +59,7 @@ class XNNPackDelegateOptions { XNNPackDelegateOptions._(this._options); + /// Creates XNNPACK options using [numThreads] CPU threads. factory XNNPackDelegateOptions({ int numThreads = 1, }) { @@ -68,6 +69,7 @@ class XNNPackDelegateOptions { return XNNPackDelegateOptions._(options); } + /// Releases the native options. void delete() { checkState(!_deleted, message: 'XNNPackDelegate already deleted.'); calloc.free(_options); diff --git a/lib/src/interpreter.dart b/lib/src/interpreter.dart index 40b7748..cbaa549 100644 --- a/lib/src/interpreter.dart +++ b/lib/src/interpreter.dart @@ -20,8 +20,8 @@ import 'dart:io'; import 'package:ffi/ffi.dart'; import 'package:flutter/services.dart'; import 'package:quiver/check.dart'; -import 'package:tflite_flutter/src/bindings/bindings.dart'; -import 'package:tflite_flutter/src/bindings/tensorflow_lite_bindings_generated.dart'; +import 'package:tflite_core/src/bindings/bindings.dart'; +import 'package:tflite_core/src/bindings/tensorflow_lite_bindings_generated.dart'; import 'ffi/helper.dart'; import 'interpreter_options.dart'; @@ -41,22 +41,21 @@ class Interpreter { int? _inputTensorsCount; int? _outputTensorsCount; - int get lastNativeInferenceDurationMicroSeconds => - _lastNativeInferenceDurationMicroSeconds; + /// Duration of the most recent native inference, in microseconds. + int get lastNativeInferenceDurationMicroSeconds => _lastNativeInferenceDurationMicroSeconds; Interpreter._(this._interpreter) { // Allocate tensors when interpreter is created allocateTensors(); } - /// Creates interpreter from model + /// Creates an interpreter from a model. /// /// Throws [ArgumentError] is unsuccessful. factory Interpreter._create(Model model, {InterpreterOptions? options}) { final interpreter = tfliteBinding.TfLiteInterpreterCreate( model.base, options?.base ?? cast(nullptr)); - checkArgument(isNotNull(interpreter), - message: 'Unable to create interpreter.'); + checkArgument(isNotNull(interpreter), message: 'Unable to create interpreter.'); return Interpreter._(interpreter); } @@ -87,7 +86,7 @@ class Interpreter { return interpreter; } - /// Creates interpreter from a [buffer] + /// Creates an interpreter from a model [buffer]. /// /// Throws [ArgumentError] if unsuccessful. /// @@ -103,15 +102,14 @@ class Interpreter { /// return rawBytes; /// } /// ``` - factory Interpreter.fromBuffer(Uint8List buffer, - {InterpreterOptions? options}) { + factory Interpreter.fromBuffer(Uint8List buffer, {InterpreterOptions? options}) { final model = Model.fromBuffer(buffer); final interpreter = Interpreter._create(model, options: options); model.delete(); return interpreter; } - /// Creates interpreter from a [assetName] + /// Creates an interpreter from a model bundled as a Flutter asset. /// /// Place your `.tflite` file in your assets folder. /// @@ -120,24 +118,22 @@ class Interpreter { /// ```dart /// final interpreter = await tfl.Interpreter.fromAsset('assets/your_model.tflite'); /// ``` - static Future fromAsset(String assetName, - {InterpreterOptions? options}) async { + static Future fromAsset(String assetName, {InterpreterOptions? options}) async { Uint8List buffer = await _getBuffer(assetName); return Interpreter.fromBuffer(buffer, options: options); } - /// Get byte buffer + /// Loads an asset's bytes. static Future _getBuffer(String assetFileName) async { ByteData rawAssetFile = await rootBundle.load(assetFileName); final rawBytes = rawAssetFile.buffer.asUint8List(); return rawBytes; } - /// Creates interpreter from an address. + /// Creates an interpreter wrapper from a native interpreter [address]. /// /// Typically used for passing interpreter between isolates. - factory Interpreter.fromAddress(int address, - {bool allocated = false, bool deleted = false}) { + factory Interpreter.fromAddress(int address, {bool allocated = false, bool deleted = false}) { final interpreter = Pointer.fromAddress(address); return Interpreter._(interpreter) .._deleted = deleted @@ -153,26 +149,25 @@ class Interpreter { /// Updates allocations for all tensors. void allocateTensors() { - checkState(tfliteBinding.TfLiteInterpreterAllocateTensors(_interpreter) == - TfLiteStatus.kTfLiteOk); + checkState( + tfliteBinding.TfLiteInterpreterAllocateTensors(_interpreter) == TfLiteStatus.kTfLiteOk); _allocated = true; } /// Runs inference for the loaded graph. void invoke() { checkState(_allocated, message: 'Interpreter not allocated.'); - checkState(tfliteBinding.TfLiteInterpreterInvoke(_interpreter) == - TfLiteStatus.kTfLiteOk); + checkState(tfliteBinding.TfLiteInterpreterInvoke(_interpreter) == TfLiteStatus.kTfLiteOk); } - /// Run for single input and output + /// Runs inference with one [input] and copies the result into [output]. void run(Object input, Object output) { var map = {}; map[0] = output; runForMultipleInputs([input], map); } - /// Run for multiple inputs and outputs + /// Runs inference with [inputs] and copies results into [outputs]. void runForMultipleInputs(List inputs, Map outputs) { if (outputs.isEmpty) { throw ArgumentError('Input error: Outputs should not be null or empty.'); @@ -184,7 +179,7 @@ class Interpreter { } } - /// Just run inference + /// Runs inference using [inputs] without copying results into output objects. void runInference(List inputs) { if (inputs.isEmpty) { throw ArgumentError('Input error: Inputs should not be null or empty.'); @@ -222,10 +217,8 @@ class Interpreter { return _inputTensors!; } - var tensors = List.generate( - tfliteBinding.TfLiteInterpreterGetInputTensorCount(_interpreter), - (i) => Tensor( - tfliteBinding.TfLiteInterpreterGetInputTensor(_interpreter, i)), + var tensors = List.generate(tfliteBinding.TfLiteInterpreterGetInputTensorCount(_interpreter), + (i) => Tensor(tfliteBinding.TfLiteInterpreterGetInputTensor(_interpreter, i)), growable: false); return tensors; @@ -237,21 +230,20 @@ class Interpreter { return _outputTensors!; } - var tensors = List.generate( - tfliteBinding.TfLiteInterpreterGetOutputTensorCount(_interpreter), - (i) => Tensor( - tfliteBinding.TfLiteInterpreterGetOutputTensor(_interpreter, i)), + var tensors = List.generate(tfliteBinding.TfLiteInterpreterGetOutputTensorCount(_interpreter), + (i) => Tensor(tfliteBinding.TfLiteInterpreterGetOutputTensor(_interpreter, i)), growable: false); return tensors; } - /// Resize input tensor for the given tensor index. `allocateTensors` must be called again afterward. + /// Resizes the input tensor at [tensorIndex] to [shape]. + /// + /// Tensor allocation is invalidated and performed again before the next run. void resizeInputTensor(int tensorIndex, List shape) { final dimensionSize = shape.length; final dimensions = calloc(dimensionSize); - final externalTypedData = - dimensions.cast().asTypedList(dimensionSize); + final externalTypedData = dimensions.cast().asTypedList(dimensionSize); externalTypedData.setRange(0, dimensionSize, shape); final status = tfliteBinding.TfLiteInterpreterResizeInputTensor( _interpreter, tensorIndex, dimensions, dimensionSize); @@ -262,10 +254,9 @@ class Interpreter { _allocated = false; } - /// Gets the input Tensor for the provided input index. + /// Returns the input tensor at [index]. Tensor getInputTensor(int index) { - _inputTensorsCount ??= - tfliteBinding.TfLiteInterpreterGetInputTensorCount(_interpreter); + _inputTensorsCount ??= tfliteBinding.TfLiteInterpreterGetInputTensorCount(_interpreter); if (index < 0 || index >= _inputTensorsCount!) { throw ArgumentError('Invalid input Tensor index: $index'); } @@ -273,27 +264,25 @@ class Interpreter { return _inputTensors![index]; } - final inputTensor = Tensor( - tfliteBinding.TfLiteInterpreterGetInputTensor(_interpreter, index)); + final inputTensor = Tensor(tfliteBinding.TfLiteInterpreterGetInputTensor(_interpreter, index)); return inputTensor; } - /// Gets the output Tensor for the provided output index. + /// Returns the output tensor at [index]. Tensor getOutputTensor(int index) { - _outputTensorsCount ??= - tfliteBinding.TfLiteInterpreterGetOutputTensorCount(_interpreter); + _outputTensorsCount ??= tfliteBinding.TfLiteInterpreterGetOutputTensorCount(_interpreter); if (index < 0 || index >= _outputTensorsCount!) { throw ArgumentError('Invalid output Tensor index: $index'); } if (_outputTensors != null) { return _outputTensors![index]; } - final outputTensor = Tensor( - tfliteBinding.TfLiteInterpreterGetOutputTensor(_interpreter, index)); + final outputTensor = + Tensor(tfliteBinding.TfLiteInterpreterGetOutputTensor(_interpreter, index)); return outputTensor; } - /// Gets index of an input given the op name of the input. + /// Returns the index of the input tensor named [opName]. int getInputIndex(String opName) { final inputTensors = getInputTensors(); var inputTensorsIndex = {}; @@ -308,7 +297,7 @@ class Interpreter { } } - /// Gets index of an output given the op name of the output. + /// Returns the index of the output tensor named [opName]. int getOutputIndex(String opName) { final outputTensors = getOutputTensors(); var outputTensorsIndex = {}; @@ -323,18 +312,19 @@ class Interpreter { } } - // Resets all variable tensors to the defaul value + /// Resets all variable tensors to their initial values. void resetVariableTensors() { - checkState(_deleted, - message: 'Should not acces delegate after it has been closed.'); + checkState(_deleted, message: 'Should not acces delegate after it has been closed.'); tfliteBinding.TfLiteInterpreterResetVariableTensors(_interpreter); } - /// Returns the address to the interpreter + /// Native address of this interpreter, for use with [IsolateInterpreter]. int get address => _interpreter.address; + /// Whether tensors have been allocated for inference. bool get isAllocated => _allocated; + /// Whether this interpreter has been closed. bool get isDeleted => _deleted; //TODO: (JAVA) void modifyGraphWithDelegate(Delegate delegate) diff --git a/lib/src/interpreter_options.dart b/lib/src/interpreter_options.dart index cc54a76..5e44bd2 100644 --- a/lib/src/interpreter_options.dart +++ b/lib/src/interpreter_options.dart @@ -18,15 +18,16 @@ import 'dart:ffi'; import 'dart:io'; import 'package:quiver/check.dart'; -import 'package:tflite_flutter/src/bindings/bindings.dart'; -import 'package:tflite_flutter/src/bindings/tensorflow_lite_bindings_generated.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/src/bindings/bindings.dart'; +import 'package:tflite_core/src/bindings/tensorflow_lite_bindings_generated.dart'; +import 'package:tflite_core/tflite_core.dart'; /// TensorFlowLite interpreter options. class InterpreterOptions { final Pointer _options; bool _deleted = false; + /// Native options pointer used when creating an interpreter. Pointer get base => _options; InterpreterOptions._(this._options); @@ -46,8 +47,7 @@ class InterpreterOptions { set threads(int threads) => tfliteBinding.TfLiteInterpreterOptionsSetNumThreads(_options, threads); - /// TensorFlow version >= v2.2 - /// Set true to use NnApi Delegate for Android + /// Enables or disables the Android NNAPI delegate. set useNnApiForAndroid(bool useNnApi) { if (Platform.isAndroid) { tfliteBinding.TfLiteInterpreterOptionsSetUseNNAPI( @@ -57,14 +57,14 @@ class InterpreterOptions { } } - /// Set true to use Metal Delegate for iOS + /// Adds the Metal GPU delegate on iOS when enabled. set useMetalDelegateForIOS(bool useMetal) { if (Platform.isIOS) { addDelegate(GpuDelegate()); } } - /// Adds delegate to Interpreter Options + /// Adds [delegate] to the interpreter options. void addDelegate(Delegate delegate) { tfliteBinding.TfLiteInterpreterOptionsAddDelegate(_options, delegate.base); } diff --git a/lib/src/isolate_interpreter.dart b/lib/src/isolate_interpreter.dart index 8956846..88207eb 100644 --- a/lib/src/isolate_interpreter.dart +++ b/lib/src/isolate_interpreter.dart @@ -17,9 +17,9 @@ import 'dart:async'; import 'dart:isolate'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; -/// `IsolateInterpreter` allows for the execution of TensorFlow models within an isolate. +/// Runs TensorFlow Lite inference in a background isolate. class IsolateInterpreter { // Private constructor for the interpreter. IsolateInterpreter._({ @@ -28,6 +28,9 @@ class IsolateInterpreter { }); // Factory method to create an instance of the IsolateInterpreter. + /// Starts a worker isolate for the native interpreter at [address]. + /// + /// Optionally sets the isolate's [debugName]. static Future create({ required int address, String debugName = 'TfLiteInterpreterIsolate', @@ -42,7 +45,10 @@ class IsolateInterpreter { return interpreter; } + /// Native address of the interpreter used by this worker. final int address; + + /// Name assigned to the worker isolate for debugging. final String debugName; final ReceivePort _receivePort = ReceivePort(); @@ -50,11 +56,14 @@ class IsolateInterpreter { late final Isolate _isolate; // Controller to handle state changes. - final StreamController _stateChanges = - StreamController.broadcast(); + final StreamController _stateChanges = StreamController.broadcast(); late final StreamSubscription _stateSubscription; + + /// Stream of worker state changes. Stream get stateChanges => _stateChanges.stream; IsolateInterpreterState __state = IsolateInterpreterState.idle; + + /// Current state of the worker isolate. IsolateInterpreterState get state => __state; // Setter to handle state changes. @@ -102,7 +111,7 @@ class IsolateInterpreter { } } - /// Run TensorFlow model for single input and output. + /// Runs inference for a single [input] and writes the result to [output]. Future run(Object input, Object output) { var map = {}; map[0] = output; @@ -110,7 +119,7 @@ class IsolateInterpreter { return runForMultipleInputs([input], map); } - /// Run TensorFlow model for multiple inputs and outputs. + /// Runs inference for [inputs] and writes results to [outputs]. Future runForMultipleInputs( List inputs, Map outputs, @@ -150,9 +159,12 @@ class IsolateInterpreter { } } -// Represents the state of the IsolateInterpreter. +/// Lifecycle state of an [IsolateInterpreter] worker. enum IsolateInterpreterState { + /// The worker is available to run inference. idle, + + /// The worker is currently running inference. loading, } diff --git a/lib/src/model.dart b/lib/src/model.dart index 122bce0..28719c2 100644 --- a/lib/src/model.dart +++ b/lib/src/model.dart @@ -18,8 +18,8 @@ import 'dart:typed_data'; import 'package:ffi/ffi.dart'; import 'package:quiver/check.dart'; -import 'package:tflite_flutter/src/bindings/bindings.dart'; -import 'package:tflite_flutter/src/bindings/tensorflow_lite_bindings_generated.dart'; +import 'package:tflite_core/src/bindings/bindings.dart'; +import 'package:tflite_core/src/bindings/tensorflow_lite_bindings_generated.dart'; import 'ffi/helper.dart'; @@ -37,8 +37,7 @@ class Model { final cpath = path.toNativeUtf8().cast(); final model = tfliteBinding.TfLiteModelCreateFromFile(cpath); calloc.free(cpath); - checkArgument(isNotNull(model), - message: 'Unable to create model from file'); + checkArgument(isNotNull(model), message: 'Unable to create model from file'); return Model._(model); } @@ -49,8 +48,7 @@ class Model { final externalTypedData = ptr.asTypedList(size); externalTypedData.setRange(0, buffer.length, buffer); final model = tfliteBinding.TfLiteModelCreate(ptr.cast(), buffer.length); - checkArgument(isNotNull(model), - message: 'Unable to create model from buffer'); + checkArgument(isNotNull(model), message: 'Unable to create model from buffer'); return Model._(model); } diff --git a/lib/src/quanitzation_params.dart b/lib/src/quanitzation_params.dart index dc5c006..499332c 100644 --- a/lib/src/quanitzation_params.dart +++ b/lib/src/quanitzation_params.dart @@ -14,16 +14,21 @@ * limitations under the License. */ +/// Quantization scale and zero point associated with a tensor. class QuantizationParams { final double _scale; final int _zeroPoint; + /// Creates quantization parameters with [scale] and [zeroPoint]. QuantizationParams(this._scale, this._zeroPoint); + /// Scale used to map quantized values to real values. double get scale => _scale; + /// Zero point used to map quantized values to real values. int get zeroPoint => _zeroPoint; + /// Returns a string representation of these parameters. @override String toString() { return 'QuantizationParams{_scale: $_scale, _zeroPoint: $_zeroPoint}'; diff --git a/lib/src/tensor.dart b/lib/src/tensor.dart index f2f5176..3c84908 100644 --- a/lib/src/tensor.dart +++ b/lib/src/tensor.dart @@ -19,9 +19,9 @@ import 'dart:typed_data'; import 'package:ffi/ffi.dart'; import 'package:quiver/check.dart'; -import 'package:tflite_flutter/src/bindings/bindings.dart'; -import 'package:tflite_flutter/src/bindings/tensorflow_lite_bindings_generated.dart'; -import 'package:tflite_flutter/src/util/byte_conversion_utils.dart'; +import 'package:tflite_core/src/bindings/bindings.dart'; +import 'package:tflite_core/src/bindings/tensorflow_lite_bindings_generated.dart'; +import 'package:tflite_core/src/util/byte_conversion_utils.dart'; import 'package:flutter/foundation.dart'; import 'ffi/helper.dart'; @@ -30,17 +30,17 @@ import 'util/list_shape_extension.dart'; export 'bindings/tensorflow_lite_bindings_generated.dart' show TfLiteType; -/// TensorFlowLite tensor. +/// A TensorFlow Lite input or output tensor. class Tensor { final Pointer _tensor; + /// Wraps the native tensor pointer owned by an [Interpreter]. Tensor(this._tensor) { ArgumentError.checkNotNull(_tensor); } /// Name of the tensor element. - String get name => - tfliteBinding.TfLiteTensorName(_tensor).cast().toDartString(); + String get name => tfliteBinding.TfLiteTensorName(_tensor).cast().toDartString(); /// Data type of the tensor element. TensorType get type => TensorType.fromValue( @@ -49,18 +49,15 @@ class Tensor { /// Dimensions of the tensor. List get shape => List.generate( - tfliteBinding.TfLiteTensorNumDims(_tensor), - (i) => tfliteBinding.TfLiteTensorDim(_tensor, i)); + tfliteBinding.TfLiteTensorNumDims(_tensor), (i) => tfliteBinding.TfLiteTensorDim(_tensor, i)); /// Underlying data buffer as bytes. Uint8List get data { final data = cast(tfliteBinding.TfLiteTensorData(_tensor)); - return data - .asTypedList(tfliteBinding.TfLiteTensorByteSize(_tensor)) - .asUnmodifiableView(); + return data.asTypedList(tfliteBinding.TfLiteTensorByteSize(_tensor)).asUnmodifiableView(); } - /// Quantization Params associated with the model, [only Android] + /// Quantization parameters associated with this tensor. QuantizationParams get params { final ref = tfliteBinding.TfLiteTensorQuantizationParams(_tensor); return QuantizationParams(ref.scale, ref.zero_point); @@ -78,22 +75,22 @@ class Tensor { externalTypedData.setRange(0, tensorByteSize, bytes); } - /// Returns number of dimensions + /// Returns the number of dimensions in this tensor's shape. int numDimensions() { return tfliteBinding.TfLiteTensorNumDims(_tensor); } - /// Returns the size, in bytes, of the tensor data. + /// Returns the size of the tensor data in bytes. int numBytes() { return tfliteBinding.TfLiteTensorByteSize(_tensor); } - /// Returns the number of elements in a flattened (1-D) view of the tensor. + /// Returns the number of elements in this tensor. int numElements() { return computeNumElements(shape); } - /// Returns the number of elements in a flattened (1-D) view of the tensor's shape. + /// Returns the product of the dimensions in [shape]. static int computeNumElements(List shape) { int n = 1; for (var i = 0; i < shape.length; i++) { @@ -102,7 +99,7 @@ class Tensor { return n; } - /// Returns shape of an object as an int list + /// Returns the dimensions of a nested list or other object. static List computeShapeOf(Object o) { int size = computeNumDimensions(o); List dimensions = List.filled(size, 0, growable: false); @@ -110,7 +107,7 @@ class Tensor { return dimensions; } - /// Returns the number of dimensions of a multi-dimensional array, otherwise 0. + /// Returns the number of dimensions in a nested list, or zero for other values. static int computeNumDimensions(Object? o) { if (o == null || o is! List) { return 0; @@ -121,7 +118,7 @@ class Tensor { return 1 + computeNumDimensions(o.elementAt(0)); } - /// Recursively populates the shape dimensions for a given (multi-dimensional) array) + /// Populates [shape] with the dimensions of the nested list [o], starting at [dim]. static void fillShape(Object o, int dim, List? shape) { if (shape == null || dim == shape.length) { return; @@ -130,15 +127,14 @@ class Tensor { if (shape[dim] == 0) { shape[dim] = len; } else if (shape[dim] != len) { - throw ArgumentError( - 'Mismatched lengths ${shape[dim]} and $len in dimension $dim'); + throw ArgumentError('Mismatched lengths ${shape[dim]} and $len in dimension $dim'); } for (var i = 0; i < len; ++i) { fillShape(o.elementAt(0), dim + 1, shape); } } - /// Returns data type of given object + /// Returns the TensorFlow Lite data type corresponding to [o]'s leaf values. static int dataTypeOf(Object o) { while (o is List) { o = o.elementAt(0); @@ -153,10 +149,10 @@ class Tensor { } else if (c is bool) { return TfLiteType.kTfLiteBool; } - throw ArgumentError( - 'DataType error: cannot resolve DataType of ${o.runtimeType}'); + throw ArgumentError('DataType error: cannot resolve DataType of ${o.runtimeType}'); } + /// Copies [src] into this tensor, converting values to its data type. void setTo(Object src) { Uint8List bytes = _convertObjectToBytes(src); int size = bytes.length; @@ -165,8 +161,7 @@ class Tensor { final externalTypedData = ptr.asTypedList(size); externalTypedData.setRange(0, bytes.length, bytes); try { - checkState(tfliteBinding.TfLiteTensorCopyFromBuffer( - _tensor, ptr.cast(), bytes.length) == + checkState(tfliteBinding.TfLiteTensorCopyFromBuffer(_tensor, ptr.cast(), bytes.length) == TfLiteStatus.kTfLiteOk); } catch (_) { rethrow; @@ -175,14 +170,14 @@ class Tensor { } } + /// Copies this tensor's contents into [dst] and returns the copied value. Object copyTo(Object dst) { int size = tfliteBinding.TfLiteTensorByteSize(_tensor); final ptr = calloc(size); checkState(isNotNull(ptr), message: 'unallocated'); final externalTypedData = ptr.asTypedList(size); - checkState( - tfliteBinding.TfLiteTensorCopyToBuffer(_tensor, ptr.cast(), size) == - TfLiteStatus.kTfLiteOk); + checkState(tfliteBinding.TfLiteTensorCopyToBuffer(_tensor, ptr.cast(), size) == + TfLiteStatus.kTfLiteOk); // Clone the data, because once `free(ptr)`, `externalTypedData` will be // volatile final bytes = externalTypedData.sublist(0); @@ -239,6 +234,7 @@ class Tensor { } } + /// Returns the input shape when [input] differs from this tensor's shape. List? getInputShapeIfDifferent(Object? input) { if (input == null) { return null; @@ -255,35 +251,78 @@ class Tensor { return inputShape; } + /// Returns a string containing this tensor's metadata. @override String toString() { return 'Tensor{_tensor: $_tensor, name: $name, type: $type, shape: $shape, data: ${data.length}}'; } } +/// Data types supported by TensorFlow Lite tensors. enum TensorType { + /// No tensor data type is set. noType(TfLiteType.kTfLiteNoType), + + /// 32-bit floating-point values. float32(TfLiteType.kTfLiteFloat32), + + /// 32-bit signed integer values. int32(TfLiteType.kTfLiteInt32), + + /// 8-bit unsigned integer values. uint8(TfLiteType.kTfLiteUInt8), + + /// 64-bit signed integer values. int64(TfLiteType.kTfLiteInt64), + + /// String values. string(TfLiteType.kTfLiteString), + + /// Boolean values. boolean(TfLiteType.kTfLiteBool), + + /// 16-bit signed integer values. int16(TfLiteType.kTfLiteInt16), + + /// 64-bit complex values. complex64(TfLiteType.kTfLiteComplex64), + + /// 8-bit signed integer values. int8(TfLiteType.kTfLiteInt8), + + /// 16-bit floating-point values. float16(TfLiteType.kTfLiteFloat16), + + /// 64-bit floating-point values. float64(TfLiteType.kTfLiteFloat64), + + /// 128-bit complex values. complex128(TfLiteType.kTfLiteComplex128), + + /// 64-bit unsigned integer values. uint64(TfLiteType.kTfLiteUInt64), + + /// Resource handle values. resource(TfLiteType.kTfLiteResource), + + /// Variant values. variant(TfLiteType.kTfLiteVariant), + + /// 32-bit unsigned integer values. uint32(TfLiteType.kTfLiteUInt32), + + /// 16-bit unsigned integer values. uint16(TfLiteType.kTfLiteUInt16), + + /// 4-bit signed integer values. int4(TfLiteType.kTfLiteInt4); + /// Creates a tensor type from its TensorFlow Lite numeric value. const TensorType(this.value); + /// Returns the tensor type for the native [tfLiteValue]. + /// + /// Returns [TensorType.noType] if the value is not recognized. static TensorType fromValue(int tfLiteValue) { switch (tfLiteValue) { case TfLiteType.kTfLiteFloat32: @@ -327,8 +366,10 @@ enum TensorType { } } + /// The native TensorFlow Lite type value. final int value; + /// Returns the enum name. @override String toString() => name; } diff --git a/lib/src/util/byte_conversion_utils.dart b/lib/src/util/byte_conversion_utils.dart index 6ba3d25..951d71b 100644 --- a/lib/src/util/byte_conversion_utils.dart +++ b/lib/src/util/byte_conversion_utils.dart @@ -18,9 +18,11 @@ import 'dart:convert'; import 'dart:ffi'; import 'dart:typed_data'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; +/// An input value cannot be encoded using the requested tensor data type. class ByteConversionError extends ArgumentError { + /// Creates an error for [input] and the incompatible tensor type. ByteConversionError({ required this.input, required this.tensorType, @@ -28,11 +30,19 @@ class ByteConversionError extends ArgumentError { 'The input element is ${input.runtimeType} while tensor data type is $tensorType', ); + /// The value that could not be converted. final Object input; + + /// The data type expected by the tensor. final TensorType tensorType; } +/// Converts values between Dart objects and TensorFlow Lite tensor bytes. class ByteConversionUtils { + /// Encodes a supported value or nested list as tensor bytes. + /// + /// [tensorType] determines how numeric values are encoded. A [Uint8List] or + /// [ByteBuffer] is returned as bytes without numeric conversion. static Uint8List convertObjectToBytes(Object o, TensorType tensorType) { if (o is Uint8List) { return o; @@ -152,27 +162,25 @@ class ByteConversionUtils { ); } - /// Decodes a TensorFlow string to a List + /// Decodes the TensorFlow Lite string tensor buffer into its strings. static List decodeTFStrings(Uint8List bytes) { /// The decoded string List decodedStrings = []; /// get the first 32bit int representing num of strings - int numStrings = ByteData.view(bytes.sublist(0, sizeOf()).buffer) - .getInt32(0, Endian.little); + int numStrings = + ByteData.view(bytes.sublist(0, sizeOf()).buffer).getInt32(0, Endian.little); /// parse subsequent string position and sizes for (int s = 0; s < numStrings; s++) { // get current str index - int startIdx = ByteData.view(bytes - .sublist((1 + s) * sizeOf(), (2 + s) * sizeOf()) - .buffer) - .getInt32(0, Endian.little); + int startIdx = + ByteData.view(bytes.sublist((1 + s) * sizeOf(), (2 + s) * sizeOf()).buffer) + .getInt32(0, Endian.little); // get next str index, or in last case the ending byte position - int endIdx = ByteData.view(bytes - .sublist((2 + s) * sizeOf(), (3 + s) * sizeOf()) - .buffer) - .getInt32(0, Endian.little); + int endIdx = + ByteData.view(bytes.sublist((2 + s) * sizeOf(), (3 + s) * sizeOf()).buffer) + .getInt32(0, Endian.little); decodedStrings.add(utf8.decode(bytes.sublist(startIdx, endIdx))); } @@ -180,8 +188,10 @@ class ByteConversionUtils { return decodedStrings; } - static Object convertBytesToObject( - Uint8List bytes, TensorType tensorType, List shape) { + /// Decodes tensor [bytes] into an object with the given [shape]. + /// + /// The returned numeric list type is selected from [tensorType]. + static Object convertBytesToObject(Uint8List bytes, TensorType tensorType, List shape) { // stores flattened data List list = []; if (tensorType.value == TfLiteType.kTfLiteInt32) { @@ -228,10 +238,10 @@ class ByteConversionUtils { throw UnsupportedError("$tensorType is not Supported."); } + /// Encodes [value] as a little-endian IEEE 754 half-precision float. static Uint8List floatToFloat16Bytes(double value) { int float16 = _float32ToFloat16(value); - final ByteData byteDataBuffer = ByteData(2) - ..setUint16(0, float16, Endian.little); + final ByteData byteDataBuffer = ByteData(2)..setUint16(0, float16, Endian.little); return Uint8List.fromList(byteDataBuffer.buffer.asUint8List()); } @@ -258,13 +268,12 @@ class ByteConversionUtils { return sign | (exponent << 10) | roundMantissa; } + /// Decodes two little-endian half-precision float bytes to a Dart [double]. static double bytesToFloat32(Uint8List bytes) { - final ByteData byteDataBuffer = ByteData(2); - int float16 = byteDataBuffer.buffer - .asUint8List() - .buffer - .asByteData() - .getUint16(0, Endian.little); + if (bytes.length != 2) { + throw ArgumentError.value(bytes.length, 'bytes.length', 'Expected exactly 2 bytes.'); + } + final float16 = ByteData.sublistView(bytes).getUint16(0, Endian.little); return _float16ToFloat32(float16); } diff --git a/lib/src/util/list_shape_extension.dart b/lib/src/util/list_shape_extension.dart index 8afb744..6e3d232 100644 --- a/lib/src/util/list_shape_extension.dart +++ b/lib/src/util/list_shape_extension.dart @@ -14,16 +14,16 @@ * limitations under the License. */ +/// Shape, reshape, and flatten operations for nested lists. extension ListShape on List { - /// Reshape list to a another [shape] + /// Reshapes this list to [shape]. /// - /// [T] is the type of elements in list + /// [T] is the element type of the returned nested list. /// - /// Returns List if [shape.length] > 5 - /// else returns list with exact type + /// Shapes with more than five dimensions return a dynamically typed list. /// - /// Throws [ArgumentError] if number of elements for [shape] - /// mismatch with current number of elements in list + /// Throws [ArgumentError] if the shape's element count does not match this + /// list's element count. List reshape(List shape) { var dims = shape.length; var numElements = 1; @@ -52,9 +52,7 @@ extension ListShape on List { var reshapedList = flatten(); for (var i = dims - 1; i > 0; i--) { var temp = []; - for (var start = 0; - start + shape[i] <= reshapedList.length; - start += shape[i]) { + for (var start = 0; start + shape[i] <= reshapedList.length; start += shape[i]) { temp.add(reshapedList.sublist(start, start + shape[i])); } reshapedList = temp; @@ -102,10 +100,8 @@ extension ListShape on List { shape[2], (k) => List.generate( shape[3], - (l) => flatList[i * shape[1] * shape[2] * shape[3] + - j * shape[2] * shape[3] + - k * shape[3] + - l], + (l) => flatList[ + i * shape[1] * shape[2] * shape[3] + j * shape[2] * shape[3] + k * shape[3] + l], ), ), ), @@ -140,7 +136,7 @@ extension ListShape on List { return reshapedList; } - /// Get shape of the list + /// Returns the dimensions of this nested list. List get shape { if (isEmpty) { return []; @@ -154,8 +150,9 @@ extension ListShape on List { return shape; } - /// Flatten this list, [T] is element type - /// if not specified List is returned + /// Returns the elements of this nested list in a one-dimensional list. + /// + /// [T] is the element type of the returned list. List flatten() { var flat = []; forEach((e) { @@ -170,7 +167,7 @@ extension ListShape on List { return flat; } - /// Get the total number of elements in list + /// Returns the total number of elements in this list. int get computeNumElements { var n = 1; for (var i = 0; i < shape.length; i++) { diff --git a/lib/tflite_flutter.dart b/lib/tflite_core.dart similarity index 91% rename from lib/tflite_flutter.dart rename to lib/tflite_core.dart index 5737b38..88df2f6 100644 --- a/lib/tflite_flutter.dart +++ b/lib/tflite_core.dart @@ -3,10 +3,10 @@ // BSD-style license that can be found in the LICENSE file. /// TensorFlow Lite for Flutter -library tflite_flutter; +library tflite_core; import 'package:ffi/ffi.dart'; -import 'package:tflite_flutter/src/bindings/bindings.dart'; +import 'package:tflite_core/src/bindings/bindings.dart'; export 'src/delegate.dart'; export 'src/delegates/gpu_delegate.dart'; diff --git a/lib/tflite_flutter_method_channel.dart b/lib/tflite_core_method_channel.dart similarity index 76% rename from lib/tflite_flutter_method_channel.dart rename to lib/tflite_core_method_channel.dart index d307eee..c563ae1 100644 --- a/lib/tflite_flutter_method_channel.dart +++ b/lib/tflite_core_method_channel.dart @@ -1,7 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; -import 'tflite_flutter_platform_interface.dart'; +import 'tflite_core_platform_interface.dart'; /// An implementation of [TfliteFlutterPlatform] that uses method channels. class MethodChannelTfliteFlutter extends TfliteFlutterPlatform { @@ -11,8 +11,7 @@ class MethodChannelTfliteFlutter extends TfliteFlutterPlatform { @override Future getPlatformVersion() async { - final version = - await methodChannel.invokeMethod('getPlatformVersion'); + final version = await methodChannel.invokeMethod('getPlatformVersion'); return version; } } diff --git a/lib/tflite_flutter_platform_interface.dart b/lib/tflite_core_platform_interface.dart similarity index 95% rename from lib/tflite_flutter_platform_interface.dart rename to lib/tflite_core_platform_interface.dart index 74513c9..7dc5851 100644 --- a/lib/tflite_flutter_platform_interface.dart +++ b/lib/tflite_core_platform_interface.dart @@ -1,6 +1,6 @@ import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import 'tflite_flutter_method_channel.dart'; +import 'tflite_core_method_channel.dart'; abstract class TfliteFlutterPlatform extends PlatformInterface { /// Constructs a TfliteFlutterPlatform. diff --git a/macos/MACOS_SPM_SETUP.md b/macos/MACOS_SPM_SETUP.md new file mode 100644 index 0000000..6839e3b --- /dev/null +++ b/macos/MACOS_SPM_SETUP.md @@ -0,0 +1,168 @@ +# macOS SPM Setup for tflite_core + +This document explains how the macOS Swift Package Manager (SPM) integration works, +what files are involved, and what to do if something breaks. + +--- + +## How it works + +Flutter on macOS can link native libraries via either **CocoaPods** or **SPM**. +This plugin supports both. The loading path is chosen automatically at runtime in +`lib/src/bindings/bindings.dart`: + +The iOS and macOS SPM manifests export the `tflite-core` product expected by +Flutter's generated plugin package. Keep this product name in sync with the +plugin package name when updating either manifest. + +1. **SPM (primary)** — `DynamicLibrary.process()` is tried first. When Xcode links + `TensorFlowLiteCMac.xcframework` via SPM, the framework is loaded by dyld at + launch and all TFLite symbols are already in-process. + +2. **CocoaPods (fallback)** — If the symbol probe fails, the code falls back to + `DynamicLibrary.open(...)` using the `.dylib` path that CocoaPods embeds into + `.app/Contents/resources/`. + +--- + +## File overview + +``` +macos/ +├── libtensorflowlite_c-mac.dylib # Source binary (arm64 + x86_64 fat dylib) +├── rebuild_xcframework.sh # Script to rebuild + sign the xcframework +├── tflite_core.podspec # CocoaPods spec (vendors the .dylib above) +└── tflite_core/ + ├── Package.swift # SPM manifest — points to xcframework below + ├── Sources/ + │ └── TfliteFlutterPlugin.swift + └── TensorFlowLiteCMac.xcframework/ # Built from the .dylib by rebuild script + ├── Info.plist + └── macos-arm64_x86_64/ + └── TensorFlowLiteC.framework/ + ├── Headers/ # Symlink to Versions/Current/Headers + ├── Resources/ # Symlink to Versions/Current/Resources + ├── TensorFlowLiteC # Symlink to the versioned dylib binary + └── Versions/ + ├── A/ + │ ├── Headers/ + │ ├── Resources/Info.plist + │ ├── TensorFlowLiteC + │ └── _CodeSignature/ + └── Current # Symlink to A +``` + +The xcframework is **not a separate download** — it is built directly from +`libtensorflowlite_c-mac.dylib` (which lives alongside it in `macos/`) using the +script described below. + +--- + +## Rebuilding the xcframework + +You need to run this if any of the following are true: + +- `TensorFlowLiteCMac.xcframework` is missing from the repo +- You see a codesign build failure: `code object is not signed at all` +- You see a launch crash: `Library not loaded: @rpath/libtensorflowlite_c.dylib` +- You updated `libtensorflowlite_c-mac.dylib` to a newer TFLite version + +Run from the **repo root** on a Mac: + +```bash +bash macos/rebuild_xcframework.sh +``` + +The script does the following in order: + +1. Deletes any existing `TensorFlowLiteCMac.xcframework` +2. Creates the full `.framework` directory structure inside the xcframework +3. Copies `libtensorflowlite_c-mac.dylib` as the framework binary +4. **Fixes the install name** with `install_name_tool` — changes it from + `@rpath/libtensorflowlite_c.dylib` to + `@rpath/TensorFlowLiteC.framework/Versions/A/TensorFlowLiteC` + (without this, dyld cannot find the library at app launch) +5. Copies the TFLite C API headers from `src/tensorflow_lite/` +6. Writes the required `Info.plist` files +7. Creates the standard macOS versioned framework layout. macOS requires + `Info.plist` at `Versions/Current/Resources/Info.plist`; a flat framework + or a root-level `Info.plist` is rejected by Xcode. +8. **Ad-hoc signs** the binary and the bundle with `codesign --force --sign -` +9. Prints the install name and signature for verification + +Then commit the result: + +```bash +git add macos/tflite_core/TensorFlowLiteCMac.xcframework +git commit -m "rebuild: regenerate and sign TensorFlowLiteC macOS xcframework" +``` + +> **Why ad-hoc signing?** macOS requires all embedded frameworks to be signed. +> An ad-hoc signature (`-`) is accepted for development and App Store distribution — +> Xcode re-signs the framework with the app's real identity during archiving. + +--- + +## Running integration tests + +```bash +flutter test integration_test/tflite_linking_test.dart -d macos +``` + +Expected output — all 6 tests passing: + +``` +✓ Built build/macos/Build/Products/Debug/.app ++6: All tests passed! +``` + +The `Failed to foreground app` warning that may appear is harmless — it is a +UI hint from the test runner, not a test failure. + +--- + +## Updating the TFLite binary + +If you need to update to a newer TFLite version: + +1. Replace `macos/libtensorflowlite_c-mac.dylib` with the new fat binary + (must contain both `arm64` and `x86_64` slices). +2. Update `CFBundleVersion` and `CFBundleShortVersionString` in + `rebuild_xcframework.sh` to match the new version if desired. +3. Run `bash macos/rebuild_xcframework.sh` to rebuild the xcframework. +4. Commit both the `.dylib` and `TensorFlowLiteCMac.xcframework`. + +--- + +## Why not use kewlbear/TensorFlowLiteC (like iOS)? + +The iOS `Package.swift` points to a remote xcframework from +[kewlbear/TensorFlowLiteC](https://github.com/kewlbear/TensorFlowLiteC). +That xcframework is **iOS-only** — it has no macOS slice despite Swift Package +Index listing macOS as compatible (that reflects `Package.swift` having no platform +restriction, not the binary contents). + +The local `TensorFlowLiteCMac.xcframework` approach is the correct +macOS-specific solution. + +--- + +## CocoaPods users + +The `tflite_core.podspec` vendors `libtensorflowlite_c-mac.dylib` directly. +CocoaPods embeds it at `.app/Contents/resources/libtensorflowlite_c-mac.dylib`, +which is where the Dart fallback path in `bindings.dart` looks for it. + +No additional setup is required for CocoaPods users. + +--- + +## Troubleshooting + +| Error | Cause | Fix | +| ------------------------------------------------------------------------ | --------------------------------- | -------------------------------------------------------------------------- | +| `code object is not signed at all` | xcframework missing or unsigned | Run `rebuild_xcframework.sh` | +| `Library not loaded: @rpath/libtensorflowlite_c.dylib` | Wrong install name in dylib | Run `rebuild_xcframework.sh` (includes `install_name_tool` fix) | +| `no library for this platform was found` | Wrong xcframework (e.g. iOS-only) | Ensure `TensorFlowLiteCMac.xcframework` is the local one, not kewlbear's | +| `Unable to start the app on the device` | App crashed at launch | Check crash log — usually one of the above | +| `building for macOS-X, but linking with dylib built for newer version Y` | Deployment target mismatch | Update `MACOSX_DEPLOYMENT_TARGET` in Xcode to match the dylib's minimum OS | diff --git a/macos/rebuild_xcframework.sh b/macos/rebuild_xcframework.sh new file mode 100644 index 0000000..c9d5b70 --- /dev/null +++ b/macos/rebuild_xcframework.sh @@ -0,0 +1,121 @@ +#!/bin/bash +# rebuild_xcframework.sh +# Reconstructs TensorFlowLiteCMac.xcframework from libtensorflowlite_c-mac.dylib, +# then ad-hoc signs it so Xcode's codesign step accepts it. +# +# Run from the repo root: bash macos/rebuild_xcframework.sh + +set -e + +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +DYLIB="$REPO_ROOT/macos/libtensorflowlite_c-mac.dylib" +XCFW="$REPO_ROOT/macos/tflite_core/TensorFlowLiteCMac.xcframework" +FW="$XCFW/macos-arm64_x86_64/TensorFlowLiteC.framework" +HEADERS_SRC="$REPO_ROOT/src/tensorflow_lite" + +echo "→ Cleaning old xcframework..." +rm -rf "$XCFW" + +echo "→ Creating framework directory structure..." +mkdir -p "$FW/Versions/A/Headers" +mkdir -p "$FW/Versions/A/Resources" + +echo "→ Copying dylib binary..." +cp "$DYLIB" "$FW/Versions/A/TensorFlowLiteC" + +echo "→ Fixing install name..." +# The dylib was built with install name @rpath/libtensorflowlite_c.dylib +# but inside an xcframework it must be @rpath/TensorFlowLiteC.framework/Versions/A/TensorFlowLiteC +# otherwise dyld can't find it at launch. +install_name_tool \ + -id "@rpath/TensorFlowLiteC.framework/Versions/A/TensorFlowLiteC" \ + "$FW/Versions/A/TensorFlowLiteC" + +echo "→ Verifying install name..." +otool -D "$FW/Versions/A/TensorFlowLiteC" | tail -1 + +echo "→ Copying TFLite C API headers..." +cp "$HEADERS_SRC/c_api.h" "$FW/Versions/A/Headers/" +cp "$HEADERS_SRC/c_api_experimental.h" "$FW/Versions/A/Headers/" +cp "$HEADERS_SRC/c_api_types.h" "$FW/Versions/A/Headers/" +cp "$HEADERS_SRC/common.h" "$FW/Versions/A/Headers/" +cp "$HEADERS_SRC/builtin_ops.h" "$FW/Versions/A/Headers/" +cp "$HEADERS_SRC/delegate.h" "$FW/Versions/A/Headers/" +cp "$HEADERS_SRC/delegate_options.h" "$FW/Versions/A/Headers/" +cp "$HEADERS_SRC/xnnpack_delegate.h" "$FW/Versions/A/Headers/" + +echo "→ Writing framework Info.plist..." +cat > "$FW/Versions/A/Resources/Info.plist" << 'PLIST' + + + + + CFBundleIdentifier + org.tensorflow.TensorFlowLiteC + CFBundleName + TensorFlowLiteC + CFBundlePackageType + FMWK + CFBundleVersion + 2.14.0 + CFBundleShortVersionString + 2.14.0 + MinimumOSVersion + 10.11 + + +PLIST + +echo "→ Creating standard framework symlinks..." +ln -s A "$FW/Versions/Current" +ln -s Versions/Current/Headers "$FW/Headers" +ln -s Versions/Current/Resources "$FW/Resources" +ln -s Versions/Current/TensorFlowLiteC "$FW/TensorFlowLiteC" + +echo "→ Writing xcframework Info.plist..." +cat > "$XCFW/Info.plist" << 'PLIST' + + + + + AvailableLibraries + + + BinaryPath + TensorFlowLiteC.framework/Versions/A/TensorFlowLiteC + LibraryIdentifier + macos-arm64_x86_64 + LibraryPath + TensorFlowLiteC.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + macos + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + +PLIST + +echo "→ Ad-hoc signing the framework binary..." +codesign --force --sign - "$FW/Versions/A/TensorFlowLiteC" + +echo "→ Ad-hoc signing the full framework bundle..." +codesign --force --sign - "$FW" + +echo "→ Verifying signature..." +codesign -dv "$FW" 2>&1 | grep -E "Signature|Identifier" || true + +echo "" +echo "✓ Done! TensorFlowLiteCMac.xcframework rebuilt and signed." +echo "" +echo "Next steps:" +echo " git add macos/tflite_core/TensorFlowLiteCMac.xcframework" +echo " git commit -m 'rebuild: regenerate and sign TensorFlowLiteC macOS xcframework'" \ No newline at end of file diff --git a/macos/tflite_flutter.podspec b/macos/tflite_core.podspec similarity index 83% rename from macos/tflite_flutter.podspec rename to macos/tflite_core.podspec index a2d0d36..c449fb7 100644 --- a/macos/tflite_flutter.podspec +++ b/macos/tflite_core.podspec @@ -1,9 +1,9 @@ # # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint tflite_flutter.podspec` to validate before publishing. +# Run `pod lib lint tflite_core.podspec` to validate before publishing. # Pod::Spec.new do |s| - s.name = 'tflite_flutter' + s.name = 'tflite_core' s.version = '0.0.1' s.summary = 'A new Flutter plugin project.' s.description = <<-DESC @@ -15,7 +15,7 @@ A new Flutter plugin project. s.source = { :path => '.' } #s.source = { :http => 'https://github.com/CaptainDario/DaKanji-Dependencies/releases/download/v3.0.0/libtensorflowlite_c-mac.dylib.zip' } - s.source_files = 'Classes/**/*' + s.source_files = 'tflite_core/Sources/**/*' s.dependency 'FlutterMacOS' s.platform = :osx, '10.11' diff --git a/macos/tflite_core/Package.swift b/macos/tflite_core/Package.swift new file mode 100644 index 0000000..1e464c4 --- /dev/null +++ b/macos/tflite_core/Package.swift @@ -0,0 +1,30 @@ +// swift-tools-version: 5.9 +import PackageDescription + +let package = Package( + name: "tflite_core", + platforms: [ + .macOS("10.15"), + ], + products: [ + .library(name: "tflite-core", targets: ["tflite_core"]), + .library(name: "tflite_core", targets: ["tflite_core"]), + .library(name: "tflite-flutter", targets: ["tflite_core"]), + ], + targets: [ + .binaryTarget( + name: "TensorFlowLiteC", + // Local macOS xcframework (arm64 + x86_64 fat binary). + // Built from macos/libtensorflowlite_c-mac.dylib via macos/rebuild_xcframework.sh. + // Must be ad-hoc signed — run rebuild_xcframework.sh if this directory is missing + // or if you see a codesign build failure. + path: "TensorFlowLiteCMac.xcframework" + ), + .target( + name: "tflite_core", + dependencies: ["TensorFlowLiteC"], + path: "Sources", + publicHeadersPath: "." + ), + ] +) \ No newline at end of file diff --git a/macos/Classes/TfliteFlutterPlugin.swift b/macos/tflite_core/Sources/TfliteFlutterPlugin.swift similarity index 100% rename from macos/Classes/TfliteFlutterPlugin.swift rename to macos/tflite_core/Sources/TfliteFlutterPlugin.swift diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/Info.plist b/macos/tflite_core/TensorFlowLiteCMac.xcframework/Info.plist new file mode 100644 index 0000000..59a14b1 --- /dev/null +++ b/macos/tflite_core/TensorFlowLiteCMac.xcframework/Info.plist @@ -0,0 +1,28 @@ + + + + + AvailableLibraries + + + BinaryPath + TensorFlowLiteC.framework/Versions/A/TensorFlowLiteC + LibraryIdentifier + macos-arm64_x86_64 + LibraryPath + TensorFlowLiteC.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + macos + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Headers b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Headers new file mode 120000 index 0000000..a177d2a --- /dev/null +++ b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Resources b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/TensorFlowLiteC b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/TensorFlowLiteC new file mode 120000 index 0000000..3732e92 --- /dev/null +++ b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/TensorFlowLiteC @@ -0,0 +1 @@ +Versions/Current/TensorFlowLiteC \ No newline at end of file diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/builtin_ops.h b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/builtin_ops.h new file mode 100755 index 0000000..3370730 --- /dev/null +++ b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/builtin_ops.h @@ -0,0 +1,194 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#ifndef TENSORFLOW_LITE_BUILTIN_OPS_H_ +#define TENSORFLOW_LITE_BUILTIN_OPS_H_ + +// DO NOT EDIT MANUALLY: This file is automatically generated by +// `schema/builtin_ops_header/generator.cc`. + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// The enum for builtin operators. +// Note: CUSTOM, DELEGATE, and PLACEHOLDER_FOR_GREATER_OP_CODES are 3 special +// ops which are not real built-in ops. +typedef enum { + kTfLiteBuiltinAdd = 0, + kTfLiteBuiltinAveragePool2d = 1, + kTfLiteBuiltinConcatenation = 2, + kTfLiteBuiltinConv2d = 3, + kTfLiteBuiltinDepthwiseConv2d = 4, + kTfLiteBuiltinDepthToSpace = 5, + kTfLiteBuiltinDequantize = 6, + kTfLiteBuiltinEmbeddingLookup = 7, + kTfLiteBuiltinFloor = 8, + kTfLiteBuiltinFullyConnected = 9, + kTfLiteBuiltinHashtableLookup = 10, + kTfLiteBuiltinL2Normalization = 11, + kTfLiteBuiltinL2Pool2d = 12, + kTfLiteBuiltinLocalResponseNormalization = 13, + kTfLiteBuiltinLogistic = 14, + kTfLiteBuiltinLshProjection = 15, + kTfLiteBuiltinLstm = 16, + kTfLiteBuiltinMaxPool2d = 17, + kTfLiteBuiltinMul = 18, + kTfLiteBuiltinRelu = 19, + kTfLiteBuiltinReluN1To1 = 20, + kTfLiteBuiltinRelu6 = 21, + kTfLiteBuiltinReshape = 22, + kTfLiteBuiltinResizeBilinear = 23, + kTfLiteBuiltinRnn = 24, + kTfLiteBuiltinSoftmax = 25, + kTfLiteBuiltinSpaceToDepth = 26, + kTfLiteBuiltinSvdf = 27, + kTfLiteBuiltinTanh = 28, + kTfLiteBuiltinConcatEmbeddings = 29, + kTfLiteBuiltinSkipGram = 30, + kTfLiteBuiltinCall = 31, + kTfLiteBuiltinCustom = 32, + kTfLiteBuiltinEmbeddingLookupSparse = 33, + kTfLiteBuiltinPad = 34, + kTfLiteBuiltinUnidirectionalSequenceRnn = 35, + kTfLiteBuiltinGather = 36, + kTfLiteBuiltinBatchToSpaceNd = 37, + kTfLiteBuiltinSpaceToBatchNd = 38, + kTfLiteBuiltinTranspose = 39, + kTfLiteBuiltinMean = 40, + kTfLiteBuiltinSub = 41, + kTfLiteBuiltinDiv = 42, + kTfLiteBuiltinSqueeze = 43, + kTfLiteBuiltinUnidirectionalSequenceLstm = 44, + kTfLiteBuiltinStridedSlice = 45, + kTfLiteBuiltinBidirectionalSequenceRnn = 46, + kTfLiteBuiltinExp = 47, + kTfLiteBuiltinTopkV2 = 48, + kTfLiteBuiltinSplit = 49, + kTfLiteBuiltinLogSoftmax = 50, + kTfLiteBuiltinDelegate = 51, + kTfLiteBuiltinBidirectionalSequenceLstm = 52, + kTfLiteBuiltinCast = 53, + kTfLiteBuiltinPrelu = 54, + kTfLiteBuiltinMaximum = 55, + kTfLiteBuiltinArgMax = 56, + kTfLiteBuiltinMinimum = 57, + kTfLiteBuiltinLess = 58, + kTfLiteBuiltinNeg = 59, + kTfLiteBuiltinPadv2 = 60, + kTfLiteBuiltinGreater = 61, + kTfLiteBuiltinGreaterEqual = 62, + kTfLiteBuiltinLessEqual = 63, + kTfLiteBuiltinSelect = 64, + kTfLiteBuiltinSlice = 65, + kTfLiteBuiltinSin = 66, + kTfLiteBuiltinTransposeConv = 67, + kTfLiteBuiltinSparseToDense = 68, + kTfLiteBuiltinTile = 69, + kTfLiteBuiltinExpandDims = 70, + kTfLiteBuiltinEqual = 71, + kTfLiteBuiltinNotEqual = 72, + kTfLiteBuiltinLog = 73, + kTfLiteBuiltinSum = 74, + kTfLiteBuiltinSqrt = 75, + kTfLiteBuiltinRsqrt = 76, + kTfLiteBuiltinShape = 77, + kTfLiteBuiltinPow = 78, + kTfLiteBuiltinArgMin = 79, + kTfLiteBuiltinFakeQuant = 80, + kTfLiteBuiltinReduceProd = 81, + kTfLiteBuiltinReduceMax = 82, + kTfLiteBuiltinPack = 83, + kTfLiteBuiltinLogicalOr = 84, + kTfLiteBuiltinOneHot = 85, + kTfLiteBuiltinLogicalAnd = 86, + kTfLiteBuiltinLogicalNot = 87, + kTfLiteBuiltinUnpack = 88, + kTfLiteBuiltinReduceMin = 89, + kTfLiteBuiltinFloorDiv = 90, + kTfLiteBuiltinReduceAny = 91, + kTfLiteBuiltinSquare = 92, + kTfLiteBuiltinZerosLike = 93, + kTfLiteBuiltinFill = 94, + kTfLiteBuiltinFloorMod = 95, + kTfLiteBuiltinRange = 96, + kTfLiteBuiltinResizeNearestNeighbor = 97, + kTfLiteBuiltinLeakyRelu = 98, + kTfLiteBuiltinSquaredDifference = 99, + kTfLiteBuiltinMirrorPad = 100, + kTfLiteBuiltinAbs = 101, + kTfLiteBuiltinSplitV = 102, + kTfLiteBuiltinUnique = 103, + kTfLiteBuiltinCeil = 104, + kTfLiteBuiltinReverseV2 = 105, + kTfLiteBuiltinAddN = 106, + kTfLiteBuiltinGatherNd = 107, + kTfLiteBuiltinCos = 108, + kTfLiteBuiltinWhere = 109, + kTfLiteBuiltinRank = 110, + kTfLiteBuiltinElu = 111, + kTfLiteBuiltinReverseSequence = 112, + kTfLiteBuiltinMatrixDiag = 113, + kTfLiteBuiltinQuantize = 114, + kTfLiteBuiltinMatrixSetDiag = 115, + kTfLiteBuiltinRound = 116, + kTfLiteBuiltinHardSwish = 117, + kTfLiteBuiltinIf = 118, + kTfLiteBuiltinWhile = 119, + kTfLiteBuiltinNonMaxSuppressionV4 = 120, + kTfLiteBuiltinNonMaxSuppressionV5 = 121, + kTfLiteBuiltinScatterNd = 122, + kTfLiteBuiltinSelectV2 = 123, + kTfLiteBuiltinDensify = 124, + kTfLiteBuiltinSegmentSum = 125, + kTfLiteBuiltinBatchMatmul = 126, + kTfLiteBuiltinPlaceholderForGreaterOpCodes = 127, + kTfLiteBuiltinCumsum = 128, + kTfLiteBuiltinCallOnce = 129, + kTfLiteBuiltinBroadcastTo = 130, + kTfLiteBuiltinRfft2d = 131, + kTfLiteBuiltinConv3d = 132, + kTfLiteBuiltinImag = 133, + kTfLiteBuiltinReal = 134, + kTfLiteBuiltinComplexAbs = 135, + kTfLiteBuiltinHashtable = 136, + kTfLiteBuiltinHashtableFind = 137, + kTfLiteBuiltinHashtableImport = 138, + kTfLiteBuiltinHashtableSize = 139, + kTfLiteBuiltinReduceAll = 140, + kTfLiteBuiltinConv3dTranspose = 141, + kTfLiteBuiltinVarHandle = 142, + kTfLiteBuiltinReadVariable = 143, + kTfLiteBuiltinAssignVariable = 144, + kTfLiteBuiltinBroadcastArgs = 145, + kTfLiteBuiltinRandomStandardNormal = 146, + kTfLiteBuiltinBucketize = 147, + kTfLiteBuiltinRandomUniform = 148, + kTfLiteBuiltinMultinomial = 149, + kTfLiteBuiltinGelu = 150, + kTfLiteBuiltinDynamicUpdateSlice = 151, + kTfLiteBuiltinRelu0To1 = 152, + kTfLiteBuiltinUnsortedSegmentProd = 153, + kTfLiteBuiltinUnsortedSegmentMax = 154, + kTfLiteBuiltinUnsortedSegmentSum = 155, + kTfLiteBuiltinAtan2 = 156, + kTfLiteBuiltinUnsortedSegmentMin = 157, + kTfLiteBuiltinSign = 158, +} TfLiteBuiltinOperator; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus +#endif // TENSORFLOW_LITE_BUILTIN_OPS_H_ diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/c_api.h b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/c_api.h new file mode 100755 index 0000000..dc346ce --- /dev/null +++ b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/c_api.h @@ -0,0 +1,419 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ +/// WARNING: Users of TensorFlow Lite should not include this file directly, +/// but should instead include "third_party/tensorflow/lite/c/c_api.h". +/// Only the TensorFlow Lite implementation itself should include this +/// file directly. +#ifndef TENSORFLOW_LITE_CORE_C_C_API_H_ +#define TENSORFLOW_LITE_CORE_C_C_API_H_ + +#include +#include +#include + +#include "builtin_ops.h" +#include "c_api_types.h" // IWYU pragma: export + +// -------------------------------------------------------------------------- +/// C API for TensorFlow Lite. +/// +/// The API leans towards simplicity and uniformity instead of convenience, as +/// most usage will be by language-specific wrappers. It provides largely the +/// same set of functionality as that of the C++ TensorFlow Lite `Interpreter` +/// API, but is useful for shared libraries where having a stable ABI boundary +/// is important. +/// +/// Conventions: +/// * We use the prefix TfLite for everything in the API. +/// * size_t is used to represent byte sizes of objects that are +/// materialized in the address space of the calling process. +/// * int is used as an index into arrays. +/// +/// Usage: +///

+/// // Create the model and interpreter options.
+/// TfLiteModel* model = TfLiteModelCreateFromFile("/path/to/model.tflite");
+/// TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate();
+/// TfLiteInterpreterOptionsSetNumThreads(options, 2);
+///
+/// // Create the interpreter.
+/// TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options);
+///
+/// // Allocate tensors and populate the input tensor data.
+/// TfLiteInterpreterAllocateTensors(interpreter);
+/// TfLiteTensor* input_tensor =
+///     TfLiteInterpreterGetInputTensor(interpreter, 0);
+/// TfLiteTensorCopyFromBuffer(input_tensor, input.data(),
+///                            input.size() * sizeof(float));
+///
+/// // Execute inference.
+/// TfLiteInterpreterInvoke(interpreter);
+///
+/// // Extract the output tensor data.
+/// const TfLiteTensor* output_tensor =
+//      TfLiteInterpreterGetOutputTensor(interpreter, 0);
+/// TfLiteTensorCopyToBuffer(output_tensor, output.data(),
+///                          output.size() * sizeof(float));
+///
+/// // Dispose of the model and interpreter objects.
+/// TfLiteInterpreterDelete(interpreter);
+/// TfLiteInterpreterOptionsDelete(options);
+/// TfLiteModelDelete(model);
+///
+/// 
+ +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// -------------------------------------------------------------------------- +// Opaque types used by the C API. + +// TfLiteModel wraps a loaded TensorFlow Lite model. +typedef struct TfLiteModel TfLiteModel; + +// TfLiteInterpreterOptions allows customized interpreter configuration. +typedef struct TfLiteInterpreterOptions TfLiteInterpreterOptions; + +// Allows delegation of nodes to alternative backends. +typedef struct TfLiteDelegate TfLiteDelegate; + +// TfLiteInterpreter provides inference from a provided model. +typedef struct TfLiteInterpreter TfLiteInterpreter; + +// A tensor in the interpreter system which is a wrapper around a buffer of +// data including a dimensionality (or NULL if not currently defined). +typedef struct TfLiteTensor TfLiteTensor; + +// TfLiteOpaqueContext is an opaque version of TfLiteContext; +// WARNING: This is an experimental type and subject to change. +typedef struct TfLiteOpaqueContext TfLiteOpaqueContext; + +// TfLiteOpaqueNode is an opaque version of TfLiteNode; +// WARNING: This is an experimental type and subject to change. +typedef struct TfLiteOpaqueNode TfLiteOpaqueNode; + +// TfLiteRegistrationExternal is an external version of TfLiteRegistration to +// use custom op registration API. +// WARNING: This is an experimental type and subject to change. +typedef struct TfLiteRegistrationExternal TfLiteRegistrationExternal; + +// -------------------------------------------------------------------------- +// TfLiteVersion returns a string describing version information of the +// TensorFlow Lite library. TensorFlow Lite uses semantic versioning. +TFL_CAPI_EXPORT extern const char* TfLiteVersion(void); + +// Returns a model from the provided buffer, or null on failure. +// +// NOTE: The caller retains ownership of the `model_data` buffer and should +// ensure that the lifetime of the `model_data` buffer must be at least as long +// as the lifetime of the `TfLiteModel` and of any `TfLiteInterpreter` objects +// created from that `TfLiteModel`, and furthermore the contents of the +// `model_data` buffer must not be modified during that time." +TFL_CAPI_EXPORT extern TfLiteModel* TfLiteModelCreate(const void* model_data, + size_t model_size); + +// Returns a model from the provided file, or null on failure. +// +// NOTE: The file's contents must not be modified during the lifetime of the +// `TfLiteModel` or of any `TfLiteInterpreter` objects created from that +// `TfLiteModel`. +TFL_CAPI_EXPORT extern TfLiteModel* TfLiteModelCreateFromFile( + const char* model_path); + +// Destroys the model instance. +TFL_CAPI_EXPORT extern void TfLiteModelDelete(TfLiteModel* model); + +// Returns a new TfLiteRegistrationExternal instance. +// +// NOTE: The caller retains ownership and should ensure that +// the lifetime of the `TfLiteRegistrationExternal` must be at least as long as +// the lifetime of the `TfLiteInterpreter`. +// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern TfLiteRegistrationExternal* +TfLiteRegistrationExternalCreate(TfLiteBuiltinOperator builtin_code, + const char* custom_name, int version); + +// Return the builtin op code of the provided external 'registration'. +// +// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern TfLiteBuiltinOperator +TfLiteRegistrationExternalGetBuiltInCode( + const TfLiteRegistrationExternal* registration); + +// Destroys the TfLiteRegistrationExternal instance. +// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern void TfLiteRegistrationExternalDelete( + TfLiteRegistrationExternal* registration); + +// Sets the initialization callback for the registration. +// +// The callback is called to initialize the op from serialized data. +// Please refer `init` of `TfLiteRegistration` for the detail. +// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern void TfLiteRegistrationExternalSetInit( + TfLiteRegistrationExternal* registration, + void* (*init)(TfLiteOpaqueContext* context, const char* buffer, + size_t length)); + +// Sets the deallocation callback for the registration. +// +// This callback is called to deallocate the data returned by the init callback. +// The value passed in the `data` parameter is the value that was returned by +// the `init` callback. +// Please refer `free` of `TfLiteRegistration` for the detail. +// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern void TfLiteRegistrationExternalSetFree( + TfLiteRegistrationExternal* registration, + void (*free)(TfLiteOpaqueContext* context, void* data)); + +// Sets the preparation callback for the registration. +// +// The callback is called when the inputs of operator have been resized. +// Please refer `prepare` of `TfLiteRegistration` for the detail. +// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern void TfLiteRegistrationExternalSetPrepare( + TfLiteRegistrationExternal* registration, + TfLiteStatus (*prepare)(TfLiteOpaqueContext* context, + TfLiteOpaqueNode* node)); + +// Sets the invocation callback for the registration. +// +// The callback is called when the operator is executed. +// Please refer `invoke` of `TfLiteRegistration` for the detail. +// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern void TfLiteRegistrationExternalSetInvoke( + TfLiteRegistrationExternal* registration, + TfLiteStatus (*invoke)(TfLiteOpaqueContext* context, + TfLiteOpaqueNode* node)); + +// Returns a new interpreter options instances. +TFL_CAPI_EXPORT extern TfLiteInterpreterOptions* +TfLiteInterpreterOptionsCreate(); + +// Destroys the interpreter options instance. +TFL_CAPI_EXPORT extern void TfLiteInterpreterOptionsDelete( + TfLiteInterpreterOptions* options); + +// Sets the number of CPU threads to use for the interpreter. +TFL_CAPI_EXPORT extern void TfLiteInterpreterOptionsSetNumThreads( + TfLiteInterpreterOptions* options, int32_t num_threads); + +// Adds a delegate to be applied during `TfLiteInterpreter` creation. +// +// If delegate application fails, interpreter creation will also fail with an +// associated error logged. +// +// NOTE: The caller retains ownership of the delegate and should ensure that it +// remains valid for the duration of any created interpreter's lifetime. +TFL_CAPI_EXPORT extern void TfLiteInterpreterOptionsAddDelegate( + TfLiteInterpreterOptions* options, TfLiteDelegate* delegate); + +// Adds an opaque delegate to be applied during `TfLiteInterpreter` creation. +// +// If delegate application fails, interpreter creation will also fail with an +// associated error logged. +// +// NOTE: The caller retains ownership of the delegate and should ensure that it +// remains valid for the duration of any created interpreter's lifetime. +TFL_CAPI_EXPORT extern void TfLiteInterpreterOptionsAddOpaqueDelegate( + TfLiteInterpreterOptions* options, + TfLiteOpaqueDelegateStruct* opaque_delegate); + +// Sets a custom error reporter for interpreter execution. +// +// * `reporter` takes the provided `user_data` object, as well as a C-style +// format string and arg list (see also vprintf). +// * `user_data` is optional. If non-null, it is owned by the client and must +// remain valid for the duration of the interpreter lifetime. +TFL_CAPI_EXPORT extern void TfLiteInterpreterOptionsSetErrorReporter( + TfLiteInterpreterOptions* options, + void (*reporter)(void* user_data, const char* format, va_list args), + void* user_data); + +// Adds an op registration to be applied during `TfLiteInterpreter` creation. +// +// The `TfLiteRegistrationExternal` object is needed to implement custom op of +// TFLite Interpreter via C API. Calling this function ensures that any +// `TfLiteInterpreter` created with the specified `options` can execute models +// that use the custom operator specified in `registration`. +// Please refer https://www.tensorflow.org/lite/guide/ops_custom for custom op +// support. +// NOTE: The caller retains ownership of the TfLiteRegistrationExternal object +// and should ensure that it remains valid for the duration of any created +// interpreter's lifetime. +// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern void TfLiteInterpreterOptionsAddRegistrationExternal( + TfLiteInterpreterOptions* options, + TfLiteRegistrationExternal* registration); + +// Returns a new interpreter using the provided model and options, or null on +// failure. +// +// * `model` must be a valid model instance. The caller retains ownership of the +// object, and may destroy it (via TfLiteModelDelete) immediately after +// creating the interpreter. However, if the TfLiteModel was allocated with +// TfLiteModelCreate, then the `model_data` buffer that was passed to +// TfLiteModelCreate must outlive the lifetime of the TfLiteInterpreter object +// that this function returns, and must not be modified during that time; +// and if the TfLiteModel was allocated with TfLiteModelCreateFromFile, then +// the contents of the model file must not be modified during the lifetime of +// the TfLiteInterpreter object that this function returns. +// * `optional_options` may be null. The caller retains ownership of the object, +// and can safely destroy it (via TfLiteInterpreterOptionsDelete) immediately +// after creating the interpreter. +// +// NOTE: The client *must* explicitly allocate tensors before attempting to +// access input tensor data or invoke the interpreter. +TFL_CAPI_EXPORT extern TfLiteInterpreter* TfLiteInterpreterCreate( + const TfLiteModel* model, const TfLiteInterpreterOptions* optional_options); + +// Destroys the interpreter. +TFL_CAPI_EXPORT extern void TfLiteInterpreterDelete( + TfLiteInterpreter* interpreter); + +// Returns the number of input tensors associated with the model. +TFL_CAPI_EXPORT extern int32_t TfLiteInterpreterGetInputTensorCount( + const TfLiteInterpreter* interpreter); + +// Returns the tensor associated with the input index. +// REQUIRES: 0 <= input_index < TfLiteInterpreterGetInputTensorCount(tensor) +TFL_CAPI_EXPORT extern TfLiteTensor* TfLiteInterpreterGetInputTensor( + const TfLiteInterpreter* interpreter, int32_t input_index); + +// Resizes the specified input tensor. +// +// NOTE: After a resize, the client *must* explicitly allocate tensors before +// attempting to access the resized tensor data or invoke the interpreter. +// +// REQUIRES: 0 <= input_index < TfLiteInterpreterGetInputTensorCount(tensor) +// +// This function makes a copy of the input dimensions, so the client can safely +// deallocate `input_dims` immediately after this function returns. +TFL_CAPI_EXPORT extern TfLiteStatus TfLiteInterpreterResizeInputTensor( + TfLiteInterpreter* interpreter, int32_t input_index, const int* input_dims, + int32_t input_dims_size); + +// Updates allocations for all tensors, resizing dependent tensors using the +// specified input tensor dimensionality. +// +// This is a relatively expensive operation, and need only be called after +// creating the graph and/or resizing any inputs. +TFL_CAPI_EXPORT extern TfLiteStatus TfLiteInterpreterAllocateTensors( + TfLiteInterpreter* interpreter); + +// Runs inference for the loaded graph. +// +// Before calling this function, the caller should first invoke +// TfLiteInterpreterAllocateTensors() and should also set the values for the +// input tensors. After successfully calling this function, the values for the +// output tensors will be set. +// +// NOTE: It is possible that the interpreter is not in a ready state to +// evaluate (e.g., if AllocateTensors() hasn't been called, or if a +// ResizeInputTensor() has been performed without a subsequent call to +// AllocateTensors()). +// +// If the (experimental!) delegate fallback option was enabled in the +// interpreter options, then the interpreter will automatically fall back to +// not using any delegates if execution with delegates fails. For details, see +// TfLiteInterpreterOptionsSetEnableDelegateFallback in c_api_experimental.h. +// +// Returns one of the following status codes: +// - kTfLiteOk: Success. Output is valid. +// - kTfLiteDelegateError: Execution with delegates failed, due to a problem +// with the delegate(s). If fallback was not enabled, output is invalid. +// If fallback was enabled, this return value indicates that fallback +// succeeded, the output is valid, and all delegates previously applied to +// the interpreter have been undone. +// - kTfLiteApplicationError: Same as for kTfLiteDelegateError, except that +// the problem was not with the delegate itself, but rather was +// due to an incompatibility between the delegate(s) and the +// interpreter or model. +// - kTfLiteError: Unexpected/runtime failure. Output is invalid. + +TFL_CAPI_EXPORT extern TfLiteStatus TfLiteInterpreterInvoke( + TfLiteInterpreter* interpreter); + +// Returns the number of output tensors associated with the model. +TFL_CAPI_EXPORT extern int32_t TfLiteInterpreterGetOutputTensorCount( + const TfLiteInterpreter* interpreter); + +// Returns the tensor associated with the output index. +// REQUIRES: 0 <= output_index < TfLiteInterpreterGetOutputTensorCount(tensor) +// +// NOTE: The shape and underlying data buffer for output tensors may be not +// be available until after the output tensor has been both sized and allocated. +// In general, best practice is to interact with the output tensor *after* +// calling TfLiteInterpreterInvoke(). +TFL_CAPI_EXPORT extern const TfLiteTensor* TfLiteInterpreterGetOutputTensor( + const TfLiteInterpreter* interpreter, int32_t output_index); + +// -------------------------------------------------------------------------- +// TfLiteTensor wraps data associated with a graph tensor. +// +// Note that, while the TfLiteTensor struct is not currently opaque, and its +// fields can be accessed directly, these methods are still convenient for +// language bindings. In the future the tensor struct will likely be made opaque +// in the public API. + +// Returns the type of a tensor element. +TFL_CAPI_EXPORT extern TfLiteType TfLiteTensorType(const TfLiteTensor* tensor); + +// Returns the number of dimensions that the tensor has. +TFL_CAPI_EXPORT extern int32_t TfLiteTensorNumDims(const TfLiteTensor* tensor); + +// Returns the length of the tensor in the "dim_index" dimension. +// REQUIRES: 0 <= dim_index < TFLiteTensorNumDims(tensor) +TFL_CAPI_EXPORT extern int32_t TfLiteTensorDim(const TfLiteTensor* tensor, + int32_t dim_index); + +// Returns the size of the underlying data in bytes. +TFL_CAPI_EXPORT extern size_t TfLiteTensorByteSize(const TfLiteTensor* tensor); + +// Returns a pointer to the underlying data buffer. +// +// NOTE: The result may be null if tensors have not yet been allocated, e.g., +// if the Tensor has just been created or resized and `TfLiteAllocateTensors()` +// has yet to be called, or if the output tensor is dynamically sized and the +// interpreter hasn't been invoked. +TFL_CAPI_EXPORT extern void* TfLiteTensorData(const TfLiteTensor* tensor); + +// Returns the (null-terminated) name of the tensor. +TFL_CAPI_EXPORT extern const char* TfLiteTensorName(const TfLiteTensor* tensor); + +// Returns the parameters for asymmetric quantization. The quantization +// parameters are only valid when the tensor type is `kTfLiteUInt8` and the +// `scale != 0`. Quantized values can be converted back to float using: +// real_value = scale * (quantized_value - zero_point); +TFL_CAPI_EXPORT extern TfLiteQuantizationParams TfLiteTensorQuantizationParams( + const TfLiteTensor* tensor); + +// Copies from the provided input buffer into the tensor's buffer. +// REQUIRES: input_data_size == TfLiteTensorByteSize(tensor) +TFL_CAPI_EXPORT extern TfLiteStatus TfLiteTensorCopyFromBuffer( + TfLiteTensor* tensor, const void* input_data, size_t input_data_size); + +// Copies to the provided output buffer from the tensor's buffer. +// REQUIRES: output_data_size == TfLiteTensorByteSize(tensor) +TFL_CAPI_EXPORT extern TfLiteStatus TfLiteTensorCopyToBuffer( + const TfLiteTensor* output_tensor, void* output_data, + size_t output_data_size); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // TENSORFLOW_LITE_CORE_C_C_API_H_ diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/c_api_experimental.h b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/c_api_experimental.h new file mode 100755 index 0000000..3c591ce --- /dev/null +++ b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/c_api_experimental.h @@ -0,0 +1,393 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ +#ifndef TENSORFLOW_LITE_C_C_API_EXPERIMENTAL_H_ +#define TENSORFLOW_LITE_C_C_API_EXPERIMENTAL_H_ + +#include "builtin_ops.h" +#include "c_api.h" +#include "common.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// -------------------------------------------------------------------------- +// Opaque types used by the C API. + +/// TfLiteSignatureRunner is used to run inference on a signature. +/// +/// Note: A signature is used to define a computation in a TF model. A model can +/// have multiple signatures. Each signature contains three components: +/// * Signature Key: A unique string to identify a signature +/// * Inputs: A list of names, each mapped to an input tensor of a signature +/// * Outputs: A list of names, each mapped to an output tensor of a signature +/// +/// To learn more about signatures in TFLite, refer to: +/// https://www.tensorflow.org/lite/guide/signatures +/// +/// Using the TfLiteSignatureRunner, for a particular signature, you can set its +/// inputs, invoke (i.e. execute) the computation, and retrieve its outputs. +typedef struct TfLiteSignatureRunner TfLiteSignatureRunner; + +// -------------------------------------------------------------------------- +/// Resets all variable tensors to zero. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern TfLiteStatus TfLiteInterpreterResetVariableTensors( + TfLiteInterpreter* interpreter); + +/// Adds an op registration for a builtin operator. +/// +/// Op registrations are used to map ops referenced in the flatbuffer model +/// to executable function pointers (`TfLiteRegistration`s). +/// +/// NOTE: The interpreter will make a shallow copy of `registration` internally, +/// so the caller should ensure that its contents (function pointers, etc...) +/// remain valid for the duration of the interpreter's lifetime. A common +/// practice is making the provided `TfLiteRegistration` instance static. +/// +/// Code that uses this function should NOT call +/// `TfLiteInterpreterOptionsSetOpResolver` on the same options object. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT void TfLiteInterpreterOptionsAddBuiltinOp( + TfLiteInterpreterOptions* options, TfLiteBuiltinOperator op, + const TfLiteRegistration* registration, int32_t min_version, + int32_t max_version); + +/// Adds an op registration for a custom operator. +/// +/// Op registrations are used to map ops referenced in the flatbuffer model +/// to executable function pointers (`TfLiteRegistration`s). +/// +/// NOTE: The interpreter will make a shallow copy of `registration` internally, +/// so the caller should ensure that its contents (function pointers, etc...) +/// remain valid for the duration of any created interpreter's lifetime. A +/// common practice is making the provided `TfLiteRegistration` instance static. +/// +/// The lifetime of the string pointed to by `name` must be at least as long +/// as the lifetime of the `TfLiteInterpreterOptions`. +/// +/// Code that uses this function should NOT call +/// `TfLiteInterpreterOptionsSetOpResolver` on the same options object. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT void TfLiteInterpreterOptionsAddCustomOp( + TfLiteInterpreterOptions* options, const char* name, + const TfLiteRegistration* registration, int32_t min_version, + int32_t max_version); + +/// Registers callbacks for resolving builtin or custom operators. +/// +/// The `TfLiteInterpreterOptionsSetOpResolver` function provides an alternative +/// method for registering builtin ops and/or custom ops, by providing operator +/// resolver callbacks. Unlike using `TfLiteInterpreterOptionsAddBuiltinOp` +/// and/or `TfLiteInterpreterOptionsAddAddCustomOp`, these let you register all +/// the operators in a single call. +/// +/// Code that uses this function should NOT call +/// `TfLiteInterpreterOptionsAddBuiltin` or +/// `TfLiteInterpreterOptionsAddCustomOp` on the same options object. +/// +/// If `op_resolver_user_data` is non-null, its lifetime must be at least as +/// long as the lifetime of the `TfLiteInterpreterOptions`. +/// +/// WARNING: This is an experimental API and subject to change. +void TfLiteInterpreterOptionsSetOpResolver( + TfLiteInterpreterOptions* options, + const TfLiteRegistration* (*find_builtin_op)(void* user_data, + TfLiteBuiltinOperator op, + int version), + const TfLiteRegistration* (*find_custom_op)(void* user_data, + const char* custom_op, + int version), + void* op_resolver_user_data); + +/// \private +/// `TfLiteRegistration_V1` version of TfLiteInterpreterOptionsSetOpResolver. +/// +/// WARNING: This function is deprecated / not an official part of the API, is +/// only for binary backwards compatibility, and should not be called. +void TfLiteInterpreterOptionsSetOpResolverV1( + TfLiteInterpreterOptions* options, + const TfLiteRegistration_V1* (*find_builtin_op_v1)(void* user_data, + TfLiteBuiltinOperator op, + int version), + const TfLiteRegistration_V1* (*find_custom_op_v1)(void* user_data, + const char* op, + int version), + void* op_resolver_user_data); + +/// Returns a new interpreter using the provided model and options, or null on +/// failure, where the model uses only the operators explicitly added to the +/// options. This is the same as `TFLiteInterpreterCreate` from `c_api.h`, +/// except that the only operators that are supported are the ones registered +/// in `options` via calls to `TfLiteInterpreterOptionsSetOpResolver`, +/// `TfLiteInterpreterOptionsAddBuiltinOp`, and/or +/// `TfLiteInterpreterOptionsAddCustomOp`. +/// +/// * `model` must be a valid model instance. The caller retains ownership of +/// the object, and can destroy it immediately after creating the interpreter; +/// the interpreter will maintain its own reference to the underlying model +/// data. +/// * `options` should not be null. The caller retains ownership of the object, +/// and can safely destroy it immediately after creating the interpreter. +/// +/// NOTE: The client *must* explicitly allocate tensors before attempting to +/// access input tensor data or invoke the interpreter. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern TfLiteInterpreter* +TfLiteInterpreterCreateWithSelectedOps(const TfLiteModel* model, + const TfLiteInterpreterOptions* options); + +/// Enable or disable the NN API delegate for the interpreter (true to enable). +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern void TfLiteInterpreterOptionsSetUseNNAPI( + TfLiteInterpreterOptions* options, bool enable); + +/// Enable or disable CPU fallback for the interpreter (true to enable). +/// If enabled, TfLiteInterpreterInvoke will do automatic fallback from +/// executing with delegate(s) to regular execution without delegates +/// (i.e. on CPU). +/// +/// Allowing the fallback is suitable only if both of the following hold: +/// - The caller is known not to cache pointers to tensor data across +/// TfLiteInterpreterInvoke calls. +/// - The model is not stateful (no variables, no LSTMs) or the state isn't +/// needed between batches. +/// +/// When delegate fallback is enabled, TfLiteInterpreterInvoke will +/// behave as follows: +/// If one or more delegates were set in the interpreter options +/// (see TfLiteInterpreterOptionsAddDelegate), +/// AND inference fails, +/// then the interpreter will fall back to not using any delegates. +/// In that case, the previously applied delegate(s) will be automatically +/// undone, and an attempt will be made to return the interpreter to an +/// invokable state, which may invalidate previous tensor addresses, +/// and the inference will be attempted again, using input tensors with +/// the same value as previously set. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern void TfLiteInterpreterOptionsSetEnableDelegateFallback( + TfLiteInterpreterOptions* options, bool enable); + +// Set if buffer handle output is allowed. +// +/// When using hardware delegation, Interpreter will make the data of output +/// tensors available in `tensor->data` by default. If the application can +/// consume the buffer handle directly (e.g. reading output from OpenGL +/// texture), it can set this flag to false, so Interpreter won't copy the +/// data from buffer handle to CPU memory. WARNING: This is an experimental +/// API and subject to change. +TFL_CAPI_EXPORT extern void TfLiteSetAllowBufferHandleOutput( + const TfLiteInterpreter* interpreter, bool allow_buffer_handle_output); + +/// Allow a delegate to look at the graph and modify the graph to handle +/// parts of the graph themselves. After this is called, the graph may +/// contain new nodes that replace 1 more nodes. +/// 'delegate' must outlive the interpreter. +/// Use `TfLiteInterpreterOptionsAddDelegate` instead of this unless +/// absolutely required. +/// Returns one of the following three status codes: +/// 1. kTfLiteOk: Success. +/// 2. kTfLiteDelegateError: Delegation failed due to an error in the +/// delegate. The Interpreter has been restored to its pre-delegation state. +/// NOTE: This undoes all delegates previously applied to the Interpreter. +/// 3. kTfLiteError: Unexpected/runtime failure. +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern TfLiteStatus TfLiteInterpreterModifyGraphWithDelegate( + const TfLiteInterpreter* interpreter, TfLiteDelegate* delegate); + +/// Returns the tensor index corresponding to the input tensor +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern int32_t TfLiteInterpreterGetInputTensorIndex( + const TfLiteInterpreter* interpreter, int32_t input_index); + +/// Returns the tensor index corresponding to the output tensor +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern int32_t TfLiteInterpreterGetOutputTensorIndex( + const TfLiteInterpreter* interpreter, int32_t output_index); + +/// -------------------------------------------------------------------------- +/// SignatureRunner APIs +/// +/// You can run inference by either: +/// +/// (i) (recommended) using the Interpreter to initialize SignatureRunner(s) and +/// then only using SignatureRunner APIs. +/// +/// (ii) only using Interpreter APIs. +/// +/// NOTE: +/// * Only use one of the above options to run inference, i.e. avoid mixing both +/// SignatureRunner APIs and Interpreter APIs to run inference as they share +/// the same underlying data (e.g. updating an input tensor “A” retrieved +/// using the Interpreter APIs will update the state of the input tensor “B” +/// retrieved using SignatureRunner APIs, if they point to the same underlying +/// tensor in the model; as it is not possible for a user to debug this by +/// analyzing the code, it can lead to undesirable behavior). +/// * The TfLiteSignatureRunner type is conditionally thread-safe, provided that +/// no two threads attempt to simultaneously access two TfLiteSignatureRunner +/// instances that point to the same underlying signature, or access a +/// TfLiteSignatureRunner and its underlying TfLiteInterpreter, unless all +/// such simultaneous accesses are reads (rather than writes). +/// * The lifetime of a TfLiteSignatureRunner object ends when +/// TfLiteSignatureRunnerDelete() is called on it (or when the lifetime of the +/// underlying TfLiteInterpreter ends -- but you should call +/// TfLiteSignatureRunnerDelete() before that happens in order to avoid +/// resource leaks). +/// * You can only apply delegates to the interpreter (via +/// TfLiteInterpreterOptions) and not to a signature. + +/// Returns the number of signatures defined in the model. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern int32_t TfLiteInterpreterGetSignatureCount( + const TfLiteInterpreter* interpreter); + +/// Returns the key of the Nth signature in the model, where N is specified as +/// `signature_index`. +/// +/// NOTE: The lifetime of the returned key is the same as (and depends on) the +/// lifetime of `interpreter`. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern const char* TfLiteInterpreterGetSignatureKey( + const TfLiteInterpreter* interpreter, int32_t signature_index); + +/// Returns a new signature runner using the provided interpreter and signature +/// key, or nullptr on failure. +/// +/// NOTE: `signature_key` is a null-terminated C string that must match the +/// key of a signature in the interpreter's model. +/// +/// NOTE: The returned signature runner should be destroyed, by calling +/// TfLiteSignatureRunnerDelete(), before the interpreter is destroyed. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern TfLiteSignatureRunner* +TfLiteInterpreterGetSignatureRunner(const TfLiteInterpreter* interpreter, + const char* signature_key); + +/// Returns the number of inputs associated with a signature. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern size_t TfLiteSignatureRunnerGetInputCount( + const TfLiteSignatureRunner* signature_runner); + +/// Returns the (null-terminated) name of the Nth input in a signature, where N +/// is specified as `input_index`. +/// +/// NOTE: The lifetime of the returned name is the same as (and depends on) the +/// lifetime of `signature_runner`. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern const char* TfLiteSignatureRunnerGetInputName( + const TfLiteSignatureRunner* signature_runner, const int32_t input_index); + +/// Resizes the input tensor identified as `input_name` to be the dimensions +/// specified by `input_dims` and `input_dims_size`. Only unknown dimensions can +/// be resized with this function. Unknown dimensions are indicated as `-1` in +/// the `dims_signature` attribute of a TfLiteTensor. +/// +/// Returns status of failure or success. Note that this doesn't actually resize +/// any existing buffers. A call to TfLiteSignatureRunnerAllocateTensors() is +/// required to change the tensor input buffer. +/// +/// NOTE: This function is similar to TfLiteInterpreterResizeInputTensorStrict() +/// and not TfLiteInterpreterResizeInputTensor(). +/// +/// NOTE: `input_name` must match the name of an input in the signature. +/// +/// NOTE: This function makes a copy of the input dimensions, so the caller can +/// safely deallocate `input_dims` immediately after this function returns. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern TfLiteStatus TfLiteSignatureRunnerResizeInputTensor( + TfLiteSignatureRunner* signature_runner, const char* input_name, + const int* input_dims, int32_t input_dims_size); + +/// Updates allocations for tensors associated with a signature and resizes +/// dependent tensors using the specified input tensor dimensionality. +/// This is a relatively expensive operation and hence should only be called +/// after initializing the signature runner object and/or resizing any inputs. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern TfLiteStatus TfLiteSignatureRunnerAllocateTensors( + TfLiteSignatureRunner* signature_runner); + +/// Returns the input tensor identified by `input_name` in the given signature. +/// Returns nullptr if the given name is not valid. +/// +/// NOTE: The lifetime of the returned tensor is the same as (and depends on) +/// the lifetime of `signature_runner`. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern TfLiteTensor* TfLiteSignatureRunnerGetInputTensor( + TfLiteSignatureRunner* signature_runner, const char* input_name); + +/// Runs inference on a given signature. +/// +/// Before calling this function, the caller should first invoke +/// TfLiteSignatureRunnerAllocateTensors() and should also set the values for +/// the input tensors. After successfully calling this function, the values for +/// the output tensors will be set. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern TfLiteStatus TfLiteSignatureRunnerInvoke( + TfLiteSignatureRunner* signature_runner); + +/// Returns the number of output tensors associated with the signature. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern size_t TfLiteSignatureRunnerGetOutputCount( + const TfLiteSignatureRunner* signature_runner); + +/// Returns the (null-terminated) name of the Nth output in a signature, where +/// N is specified as `output_index`. +/// +/// NOTE: The lifetime of the returned name is the same as (and depends on) the +/// lifetime of `signature_runner`. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern const char* TfLiteSignatureRunnerGetOutputName( + const TfLiteSignatureRunner* signature_runner, int32_t output_index); + +/// Returns the output tensor identified by `output_name` in the given +/// signature. Returns nullptr if the given name is not valid. +/// +/// NOTE: The lifetime of the returned tensor is the same as (and depends on) +/// the lifetime of `signature_runner`. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern const TfLiteTensor* TfLiteSignatureRunnerGetOutputTensor( + const TfLiteSignatureRunner* signature_runner, const char* output_name); + +/// Destroys the signature runner. +/// +/// WARNING: This is an experimental API and subject to change. +TFL_CAPI_EXPORT extern void TfLiteSignatureRunnerDelete( + TfLiteSignatureRunner* signature_runner); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // TENSORFLOW_LITE_C_C_API_EXPERIMENTAL_H_ diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/c_api_types.h b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/c_api_types.h new file mode 100644 index 0000000..9d7668e --- /dev/null +++ b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/c_api_types.h @@ -0,0 +1,147 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +// This file declares types used by the pure C inference API defined in c_api.h, +// some of which are also used in the C++ and C kernel and interpreter APIs. + +#ifndef TENSORFLOW_LITE_C_C_API_TYPES_H_ +#define TENSORFLOW_LITE_C_C_API_TYPES_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Define TFL_CAPI_EXPORT macro to export a function properly with a shared +// library. +#ifdef SWIG +#define TFL_CAPI_EXPORT +#elif defined(TFL_STATIC_LIBRARY_BUILD) +#define TFL_CAPI_EXPORT +#else // not definded TFL_STATIC_LIBRARY_BUILD +#if defined(_WIN32) +#ifdef TFL_COMPILE_LIBRARY +#define TFL_CAPI_EXPORT __declspec(dllexport) +#else +#define TFL_CAPI_EXPORT __declspec(dllimport) +#endif // TFL_COMPILE_LIBRARY +#else +#define TFL_CAPI_EXPORT __attribute__((visibility("default"))) +#endif // _WIN32 +#endif // SWIG + +// Note that new error status values may be added in future in order to +// indicate more fine-grained internal states, therefore, applications should +// not rely on status values being members of the enum. +typedef enum TfLiteStatus { + kTfLiteOk = 0, + + // Generally referring to an error in the runtime (i.e. interpreter) + kTfLiteError = 1, + + // Generally referring to an error from a TfLiteDelegate itself. + kTfLiteDelegateError = 2, + + // Generally referring to an error in applying a delegate due to + // incompatibility between runtime and delegate, e.g., this error is returned + // when trying to apply a TF Lite delegate onto a model graph that's already + // immutable. + kTfLiteApplicationError = 3, + + // Generally referring to serialized delegate data not being found. + // See tflite::delegates::Serialization. + kTfLiteDelegateDataNotFound = 4, + + // Generally referring to data-writing issues in delegate serialization. + // See tflite::delegates::Serialization. + kTfLiteDelegateDataWriteError = 5, + + // Generally referring to data-reading issues in delegate serialization. + // See tflite::delegates::Serialization. + kTfLiteDelegateDataReadError = 6, + + // Generally referring to issues when the TF Lite model has ops that cannot be + // resolved at runtime. This could happen when the specific op is not + // registered or built with the TF Lite framework. + kTfLiteUnresolvedOps = 7, + + // Generally referring to invocation cancelled by the user. + // See `interpreter::Cancel`. + // TODO(b/194915839): Implement `interpreter::Cancel`. + // TODO(b/250636993): Cancellation triggered by `SetCancellationFunction` + // should also return this status code. + kTfLiteCancelled = 8, +} TfLiteStatus; + +// Types supported by tensor +typedef enum { + kTfLiteNoType = 0, + kTfLiteFloat32 = 1, + kTfLiteInt32 = 2, + kTfLiteUInt8 = 3, + kTfLiteInt64 = 4, + kTfLiteString = 5, + kTfLiteBool = 6, + kTfLiteInt16 = 7, + kTfLiteComplex64 = 8, + kTfLiteInt8 = 9, + kTfLiteFloat16 = 10, + kTfLiteFloat64 = 11, + kTfLiteComplex128 = 12, + kTfLiteUInt64 = 13, + kTfLiteResource = 14, + kTfLiteVariant = 15, + kTfLiteUInt32 = 16, + kTfLiteUInt16 = 17, + kTfLiteInt4 = 18, +} TfLiteType; + +// Legacy. Will be deprecated in favor of TfLiteAffineQuantization. +// If per-layer quantization is specified this field will still be populated in +// addition to TfLiteAffineQuantization. +// Parameters for asymmetric quantization. Quantized values can be converted +// back to float using: +// real_value = scale * (quantized_value - zero_point) +typedef struct TfLiteQuantizationParams { + float scale; + int32_t zero_point; +} TfLiteQuantizationParams; + +// -------------------------------------------------------------------------- +// Opaque types used by c_api.h, c_api_opaque.h and common.h. + +// TfLiteOpaqueContext is an opaque version of TfLiteContext; +typedef struct TfLiteOpaqueContext TfLiteOpaqueContext; + +// TfLiteOpaqueNode is an opaque version of TfLiteNode; +typedef struct TfLiteOpaqueNode TfLiteOpaqueNode; + +// TfLiteOpaqueTensor is an opaque version of TfLiteTensor; +typedef struct TfLiteOpaqueTensor TfLiteOpaqueTensor; + +// TfLiteOpaqueDelegateStruct: opaque version of TfLiteDelegate; allows +// delegation of nodes to alternative backends. +// +// This is an abstract type that is intended to have the same +// role as TfLiteDelegate from common.h, but without exposing the implementation +// details of how delegates are implemented. +// WARNING: This is an experimental type and subject to change. +typedef struct TfLiteOpaqueDelegateStruct TfLiteOpaqueDelegateStruct; + +#ifdef __cplusplus +} // extern C +#endif +#endif // TENSORFLOW_LITE_C_C_API_TYPES_H_ diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/common.h b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/common.h new file mode 100755 index 0000000..5bff3e1 --- /dev/null +++ b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/common.h @@ -0,0 +1,1110 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +// This file defines common C types and APIs for implementing operations, +// delegates and other constructs in TensorFlow Lite. The actual operations and +// delegates can be defined using C++, but the interface between the interpreter +// and the operations are C. +// +// Summary of abstractions +// TF_LITE_ENSURE - Self-sufficient error checking +// TfLiteStatus - Status reporting +// TfLiteIntArray - stores tensor shapes (dims), +// TfLiteContext - allows an op to access the tensors +// TfLiteTensor - tensor (a multidimensional array) +// TfLiteNode - a single node or operation +// TfLiteRegistration - the implementation of a conceptual operation. +// TfLiteDelegate - allows delegation of nodes to alternative backends. +// +// Some abstractions in this file are created and managed by Interpreter. +// +// NOTE: The order of values in these structs are "semi-ABI stable". New values +// should be added only to the end of structs and never reordered. + +#ifndef TENSORFLOW_LITE_C_COMMON_H_ +#define TENSORFLOW_LITE_C_COMMON_H_ + +#include +#include +#include + +#include "c_api_types.h" // IWYU pragma: export + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// The list of external context types known to TF Lite. This list exists solely +// to avoid conflicts and to ensure ops can share the external contexts they +// need. Access to the external contexts is controlled by one of the +// corresponding support files. +typedef enum TfLiteExternalContextType { + kTfLiteEigenContext = 0, // include eigen_support.h to use. + kTfLiteGemmLowpContext = 1, // include gemm_support.h to use. + kTfLiteEdgeTpuContext = 2, // Placeholder for Edge TPU support. + kTfLiteCpuBackendContext = 3, // include cpu_backend_context.h to use. + kTfLiteMaxExternalContexts = 4 +} TfLiteExternalContextType; + +// Forward declare so dependent structs and methods can reference these types +// prior to the struct definitions. +struct TfLiteContext; +struct TfLiteDelegate; +struct TfLiteRegistration; +struct TfLiteOpaqueDelegateStruct; +struct TfLiteOpaqueDelegateBuilder; + +// An external context is a collection of information unrelated to the TF Lite +// framework, but useful to a subset of the ops. TF Lite knows very little +// about the actual contexts, but it keeps a list of them, and is able to +// refresh them if configurations like the number of recommended threads +// change. +typedef struct TfLiteExternalContext { + TfLiteExternalContextType type; + TfLiteStatus (*Refresh)(struct TfLiteContext* context); +} TfLiteExternalContext; + +#define kTfLiteOptionalTensor (-1) + +// Fixed size list of integers. Used for dimensions and inputs/outputs tensor +// indices +typedef struct TfLiteIntArray { + int size; + +#if defined(_MSC_VER) + // Context for why this is needed is in http://b/189926408#comment21 + int data[1]; +#elif (!defined(__clang__) && defined(__GNUC__) && __GNUC__ == 6 && \ + __GNUC_MINOR__ >= 1) || \ + defined(HEXAGON) || \ + (defined(__clang__) && __clang_major__ == 7 && __clang_minor__ == 1) + // gcc 6.1+ have a bug where flexible members aren't properly handled + // https://github.com/google/re2/commit/b94b7cd42e9f02673cd748c1ac1d16db4052514c + int data[0]; +#else + int data[]; +#endif +} TfLiteIntArray; + +// Given the size (number of elements) in a TfLiteIntArray, calculate its size +// in bytes. +size_t TfLiteIntArrayGetSizeInBytes(int size); + +#ifndef TF_LITE_STATIC_MEMORY +// Create a array of a given `size` (uninitialized entries). +// This returns a pointer, that you must free using TfLiteIntArrayFree(). +TfLiteIntArray* TfLiteIntArrayCreate(int size); +#endif + +// Check if two intarrays are equal. Returns 1 if they are equal, 0 otherwise. +int TfLiteIntArrayEqual(const TfLiteIntArray* a, const TfLiteIntArray* b); + +// Check if an intarray equals an array. Returns 1 if equals, 0 otherwise. +int TfLiteIntArrayEqualsArray(const TfLiteIntArray* a, int b_size, + const int b_data[]); + +#ifndef TF_LITE_STATIC_MEMORY +// Create a copy of an array passed as `src`. +// You are expected to free memory with TfLiteIntArrayFree +TfLiteIntArray* TfLiteIntArrayCopy(const TfLiteIntArray* src); + +// Free memory of array `a`. +void TfLiteIntArrayFree(TfLiteIntArray* a); +#endif // TF_LITE_STATIC_MEMORY + +// Fixed size list of floats. Used for per-channel quantization. +typedef struct TfLiteFloatArray { + int size; +#if defined(_MSC_VER) + // Context for why this is needed is in http://b/189926408#comment21 + float data[1]; +#elif (!defined(__clang__) && defined(__GNUC__) && __GNUC__ == 6 && \ + __GNUC_MINOR__ >= 1) || \ + defined(HEXAGON) || \ + (defined(__clang__) && __clang_major__ == 7 && __clang_minor__ == 1) + // gcc 6.1+ have a bug where flexible members aren't properly handled + // https://github.com/google/re2/commit/b94b7cd42e9f02673cd748c1ac1d16db4052514c + float data[0]; +#else + float data[]; +#endif +} TfLiteFloatArray; + +// Given the size (number of elements) in a TfLiteFloatArray, calculate its size +// in bytes. +int TfLiteFloatArrayGetSizeInBytes(int size); + +#ifndef TF_LITE_STATIC_MEMORY +// Create a array of a given `size` (uninitialized entries). +// This returns a pointer, that you must free using TfLiteFloatArrayFree(). +TfLiteFloatArray* TfLiteFloatArrayCreate(int size); + +// Free memory of array `a`. +void TfLiteFloatArrayFree(TfLiteFloatArray* a); +#endif // TF_LITE_STATIC_MEMORY + +// Since we must not depend on any libraries, define a minimal subset of +// error macros while avoiding names that have pre-conceived meanings like +// assert and check. + +// Try to make all reporting calls through TF_LITE_KERNEL_LOG rather than +// calling the context->ReportError function directly, so that message strings +// can be stripped out if the binary size needs to be severely optimized. +#ifndef TF_LITE_STRIP_ERROR_STRINGS +#define TF_LITE_KERNEL_LOG(context, ...) \ + do { \ + (context)->ReportError((context), __VA_ARGS__); \ + } while (false) + +#define TF_LITE_MAYBE_KERNEL_LOG(context, ...) \ + do { \ + if ((context) != nullptr) { \ + (context)->ReportError((context), __VA_ARGS__); \ + } \ + } while (false) +#else // TF_LITE_STRIP_ERROR_STRINGS +#define ARGS_UNUSED(...) (void)sizeof(#__VA_ARGS__) +#define TF_LITE_KERNEL_LOG(context, ...) ARGS_UNUSED(__VA_ARGS__) +#define TF_LITE_MAYBE_KERNEL_LOG(context, ...) ARGS_UNUSED(__VA_ARGS__) +#endif // TF_LITE_STRIP_ERROR_STRINGS + +// Check whether value is true, and if not return kTfLiteError from +// the current function (and report the error string msg). +#define TF_LITE_ENSURE_MSG(context, value, msg) \ + do { \ + if (!(value)) { \ + TF_LITE_KERNEL_LOG((context), __FILE__ " " msg); \ + return kTfLiteError; \ + } \ + } while (0) + +// Check whether the value `a` is true, and if not return kTfLiteError from +// the current function, while also reporting the location of the error. +#define TF_LITE_ENSURE(context, a) \ + do { \ + if (!(a)) { \ + TF_LITE_KERNEL_LOG((context), "%s:%d %s was not true.", __FILE__, \ + __LINE__, #a); \ + return kTfLiteError; \ + } \ + } while (0) + +#define TF_LITE_ENSURE_STATUS(a) \ + do { \ + const TfLiteStatus s = (a); \ + if (s != kTfLiteOk) { \ + return s; \ + } \ + } while (0) + +// Check whether the value `a == b` is true, and if not return kTfLiteError from +// the current function, while also reporting the location of the error. +// `a` and `b` may be evaluated more than once, so no side effects or +// extremely expensive computations should be done. +// NOTE: Use TF_LITE_ENSURE_TYPES_EQ if comparing TfLiteTypes. +#define TF_LITE_ENSURE_EQ(context, a, b) \ + do { \ + if ((a) != (b)) { \ + TF_LITE_KERNEL_LOG((context), "%s:%d %s != %s (%d != %d)", __FILE__, \ + __LINE__, #a, #b, (a), (b)); \ + return kTfLiteError; \ + } \ + } while (0) + +#define TF_LITE_ENSURE_TYPES_EQ(context, a, b) \ + do { \ + if ((a) != (b)) { \ + TF_LITE_KERNEL_LOG((context), "%s:%d %s != %s (%s != %s)", __FILE__, \ + __LINE__, #a, #b, TfLiteTypeGetName(a), \ + TfLiteTypeGetName(b)); \ + return kTfLiteError; \ + } \ + } while (0) + +#define TF_LITE_ENSURE_NEAR(context, a, b, epsilon) \ + do { \ + auto delta = ((a) > (b)) ? ((a) - (b)) : ((b) - (a)); \ + if (delta > epsilon) { \ + TF_LITE_KERNEL_LOG((context), "%s:%d %s not near %s (%f != %f)", \ + __FILE__, __LINE__, #a, #b, static_cast(a), \ + static_cast(b)); \ + return kTfLiteError; \ + } \ + } while (0) + +#define TF_LITE_ENSURE_OK(context, status) \ + do { \ + const TfLiteStatus s = (status); \ + if ((s) != kTfLiteOk) { \ + return s; \ + } \ + } while (0) + +// Single-precision complex data type compatible with the C99 definition. +typedef struct TfLiteComplex64 { + float re, im; // real and imaginary parts, respectively. +} TfLiteComplex64; + +// Double-precision complex data type compatible with the C99 definition. +typedef struct TfLiteComplex128 { + double re, im; // real and imaginary parts, respectively. +} TfLiteComplex128; + +// Half precision data type compatible with the C99 definition. +typedef struct TfLiteFloat16 { + uint16_t data; +} TfLiteFloat16; + +// Return the name of a given type, for error reporting purposes. +const char* TfLiteTypeGetName(TfLiteType type); + +// SupportedQuantizationTypes. +typedef enum TfLiteQuantizationType { + // No quantization. + kTfLiteNoQuantization = 0, + // Affine quantization (with support for per-channel quantization). + // Corresponds to TfLiteAffineQuantization. + kTfLiteAffineQuantization = 1, +} TfLiteQuantizationType; + +// Structure specifying the quantization used by the tensor, if-any. +typedef struct TfLiteQuantization { + // The type of quantization held by params. + TfLiteQuantizationType type; + // Holds an optional reference to a quantization param structure. The actual + // type depends on the value of the `type` field (see the comment there for + // the values and corresponding types). + void* params; +} TfLiteQuantization; + +// Parameters for asymmetric quantization across a dimension (i.e per output +// channel quantization). +// quantized_dimension specifies which dimension the scales and zero_points +// correspond to. +// For a particular value in quantized_dimension, quantized values can be +// converted back to float using: +// real_value = scale * (quantized_value - zero_point) +typedef struct TfLiteAffineQuantization { + TfLiteFloatArray* scale; + TfLiteIntArray* zero_point; + int32_t quantized_dimension; +} TfLiteAffineQuantization; + +/* A union of pointers that points to memory for a given tensor. */ +typedef union TfLitePtrUnion { + /* Do not access these members directly, if possible, use + * GetTensorData(tensor) instead, otherwise only access .data, as other + * members are deprecated. */ + int32_t* i32; + uint32_t* u32; + int64_t* i64; + uint64_t* u64; + float* f; + TfLiteFloat16* f16; + double* f64; + char* raw; + const char* raw_const; + uint8_t* uint8; + bool* b; + int16_t* i16; + uint16_t* ui16; + TfLiteComplex64* c64; + TfLiteComplex128* c128; + int8_t* int8; + /* Only use this member. */ + void* data; +} TfLitePtrUnion; + +// Memory allocation strategies. +// * kTfLiteMmapRo: Read-only memory-mapped data, or data externally allocated. +// * kTfLiteArenaRw: Arena allocated with no guarantees about persistence, +// and available during eval. +// * kTfLiteArenaRwPersistent: Arena allocated but persistent across eval, and +// only available during eval. +// * kTfLiteDynamic: Allocated during eval, or for string tensors. +// * kTfLitePersistentRo: Allocated and populated during prepare. This is +// useful for tensors that can be computed during prepare and treated +// as constant inputs for downstream ops (also in prepare). +// * kTfLiteCustom: Custom memory allocation provided by the user. See +// TfLiteCustomAllocation below. +typedef enum TfLiteAllocationType { + kTfLiteMemNone = 0, + kTfLiteMmapRo, + kTfLiteArenaRw, + kTfLiteArenaRwPersistent, + kTfLiteDynamic, + kTfLitePersistentRo, + kTfLiteCustom, +} TfLiteAllocationType; + +// The delegates should use zero or positive integers to represent handles. +// -1 is reserved from unallocated status. +typedef int TfLiteBufferHandle; +enum { + kTfLiteNullBufferHandle = -1, +}; + +// Storage format of each dimension in a sparse tensor. +typedef enum TfLiteDimensionType { + kTfLiteDimDense = 0, + kTfLiteDimSparseCSR, +} TfLiteDimensionType; + +// Metadata to encode each dimension in a sparse tensor. +typedef struct TfLiteDimensionMetadata { + TfLiteDimensionType format; + int dense_size; + TfLiteIntArray* array_segments; + TfLiteIntArray* array_indices; +} TfLiteDimensionMetadata; + +// Parameters used to encode a sparse tensor. For detailed explanation of each +// field please refer to lite/schema/schema.fbs. +typedef struct TfLiteSparsity { + TfLiteIntArray* traversal_order; + TfLiteIntArray* block_map; + TfLiteDimensionMetadata* dim_metadata; + int dim_metadata_size; +} TfLiteSparsity; + +// Defines a custom memory allocation not owned by the runtime. +// `data` should be aligned to kDefaultTensorAlignment defined in +// lite/util.h. (Currently 64 bytes) +// NOTE: See Interpreter.SetCustomAllocationForTensor for details on usage. +typedef struct TfLiteCustomAllocation { + void* data; + size_t bytes; +} TfLiteCustomAllocation; + +// The flags used in `Interpreter::SetCustomAllocationForTensor`. +// Note that this is a bitmask, so the values should be 1, 2, 4, 8, ...etc. +typedef enum TfLiteCustomAllocationFlags { + kTfLiteCustomAllocationFlagsNone = 0, + // Skips checking whether allocation.data points to an aligned buffer as + // expected by the TFLite runtime. + // NOTE: Setting this flag can cause crashes when calling Invoke(). + // Use with caution. + kTfLiteCustomAllocationFlagsSkipAlignCheck = 1, +} TfLiteCustomAllocationFlags; + +// A tensor in the interpreter system which is a wrapper around a buffer of +// data including a dimensionality (or NULL if not currently defined). +#ifndef TF_LITE_STATIC_MEMORY +typedef struct TfLiteTensor { + // The data type specification for data stored in `data`. This affects + // what member of `data` union should be used. + TfLiteType type; + // A union of data pointers. The appropriate type should be used for a typed + // tensor based on `type`. + TfLitePtrUnion data; + // A pointer to a structure representing the dimensionality interpretation + // that the buffer should have. NOTE: the product of elements of `dims` + // and the element datatype size should be equal to `bytes` below. + TfLiteIntArray* dims; + // Quantization information. + TfLiteQuantizationParams params; + // How memory is mapped + // kTfLiteMmapRo: Memory mapped read only. + // i.e. weights + // kTfLiteArenaRw: Arena allocated read write memory + // (i.e. temporaries, outputs). + TfLiteAllocationType allocation_type; + // The number of bytes required to store the data of this Tensor. I.e. + // (bytes of each element) * dims[0] * ... * dims[n-1]. For example, if + // type is kTfLiteFloat32 and dims = {3, 2} then + // bytes = sizeof(float) * 3 * 2 = 4 * 3 * 2 = 24. + size_t bytes; + + // An opaque pointer to a tflite::MMapAllocation + const void* allocation; + + // Null-terminated name of this tensor. + const char* name; + + // The delegate which knows how to handle `buffer_handle`. + // WARNING: This is an experimental interface that is subject to change. + struct TfLiteDelegate* delegate; + + // An integer buffer handle that can be handled by `delegate`. + // The value is valid only when delegate is not null. + // WARNING: This is an experimental interface that is subject to change. + TfLiteBufferHandle buffer_handle; + + // If the delegate uses its own buffer (e.g. GPU memory), the delegate is + // responsible to set data_is_stale to true. + // `delegate->CopyFromBufferHandle` can be called to copy the data from + // delegate buffer. + // WARNING: This is an // experimental interface that is subject to change. + bool data_is_stale; + + // True if the tensor is a variable. + bool is_variable; + + // Quantization information. Replaces params field above. + TfLiteQuantization quantization; + + // Parameters used to encode a sparse tensor. + // This is optional. The field is NULL if a tensor is dense. + // WARNING: This is an experimental interface that is subject to change. + TfLiteSparsity* sparsity; + + // Optional. Encodes shapes with unknown dimensions with -1. This field is + // only populated when unknown dimensions exist in a read-write tensor (i.e. + // an input or output tensor). (e.g. `dims` contains [1, 1, 1, 3] and + // `dims_signature` contains [1, -1, -1, 3]). Note that this field only + // exists when TF_LITE_STATIC_MEMORY is not defined. + const TfLiteIntArray* dims_signature; +} TfLiteTensor; + +// A structure representing an instance of a node. +// This structure only exhibits the inputs, outputs, user defined data and some +// node properties (like statefulness), not other features like the type. +typedef struct TfLiteNode { + // Inputs to this node expressed as indices into the simulator's tensors. + TfLiteIntArray* inputs; + + // Outputs to this node expressed as indices into the simulator's tensors. + TfLiteIntArray* outputs; + + // intermediate tensors to this node expressed as indices into the simulator's + // tensors. + TfLiteIntArray* intermediates; + + // Temporary tensors uses during the computations. This usually contains no + // tensors, but ops are allowed to change that if they need scratch space of + // any sort. + TfLiteIntArray* temporaries; + + // Opaque data provided by the node implementer through `Registration.init`. + void* user_data; + + // Opaque data provided to the node if the node is a builtin. This is usually + // a structure defined in builtin_op_data.h + void* builtin_data; + + // Custom initial data. This is the opaque data provided in the flatbuffer. + // WARNING: This is an experimental interface that is subject to change. + const void* custom_initial_data; + int custom_initial_data_size; + + // The pointer to the delegate. This is non-null only when the node is + // created by calling `interpreter.ModifyGraphWithDelegate`. + // WARNING: This is an experimental interface that is subject to change. + struct TfLiteDelegate* delegate; + + // Whether this op might have side effect (e.g. stateful op). + bool might_have_side_effect; +} TfLiteNode; +#else // defined(TF_LITE_STATIC_MEMORY)? +// NOTE: This flag is opt-in only at compile time. +// +// Specific reduced TfLiteTensor struct for TF Micro runtime. This struct +// contains only the minimum fields required to initialize and prepare a micro +// inference graph. The fields in this struct have been ordered from +// largest-to-smallest for optimal struct sizeof. +// +// This struct does not use: +// - allocation +// - buffer_handle +// - data_is_stale +// - delegate +// - dims_signature +// - name +// - sparsity +typedef struct TfLiteTensor { + // TODO(b/155784997): Consider consolidating these quantization fields: + // Quantization information. Replaces params field above. + TfLiteQuantization quantization; + + // Quantization information. + TfLiteQuantizationParams params; + + // A union of data pointers. The appropriate type should be used for a typed + // tensor based on `type`. + TfLitePtrUnion data; + + // A pointer to a structure representing the dimensionality interpretation + // that the buffer should have. NOTE: the product of elements of `dims` + // and the element datatype size should be equal to `bytes` below. + TfLiteIntArray* dims; + + // The number of bytes required to store the data of this Tensor. I.e. + // (bytes of each element) * dims[0] * ... * dims[n-1]. For example, if + // type is kTfLiteFloat32 and dims = {3, 2} then + // bytes = sizeof(float) * 3 * 2 = 4 * 3 * 2 = 24. + size_t bytes; + + // The data type specification for data stored in `data`. This affects + // what member of `data` union should be used. + TfLiteType type; + + // How memory is mapped + // kTfLiteMmapRo: Memory mapped read only. + // i.e. weights + // kTfLiteArenaRw: Arena allocated read write memory + // (i.e. temporaries, outputs). + TfLiteAllocationType allocation_type; + + // True if the tensor is a variable. + bool is_variable; +} TfLiteTensor; + +// Specific reduced TfLiteNode struct for TF Micro runtime. This struct contains +// only the minimum fields required to represent a node. +// +// This struct does not use: +// - delegate +// - intermediates +// - temporaries +typedef struct TfLiteNode { + // Inputs to this node expressed as indices into the simulator's tensors. + TfLiteIntArray* inputs; + + // Outputs to this node expressed as indices into the simulator's tensors. + TfLiteIntArray* outputs; + + // intermediate tensors to this node expressed as indices into the simulator's + // tensors. + TfLiteIntArray* intermediates; + + // Opaque data provided by the node implementer through `Registration.init`. + void* user_data; + + // Opaque data provided to the node if the node is a builtin. This is usually + // a structure defined in builtin_op_data.h + void* builtin_data; + + // Custom initial data. This is the opaque data provided in the flatbuffer. + // WARNING: This is an experimental interface that is subject to change. + const void* custom_initial_data; + int custom_initial_data_size; +} TfLiteNode; +#endif // TF_LITE_STATIC_MEMORY + +// Light-weight tensor struct for TF Micro runtime. Provides the minimal amount +// of information required for a kernel to run during TfLiteRegistration::Eval. +// TODO(b/160955687): Move this field into TF_LITE_STATIC_MEMORY when TFLM +// builds with this flag by default internally. +typedef struct TfLiteEvalTensor { + // A union of data pointers. The appropriate type should be used for a typed + // tensor based on `type`. + TfLitePtrUnion data; + + // A pointer to a structure representing the dimensionality interpretation + // that the buffer should have. + TfLiteIntArray* dims; + + // The data type specification for data stored in `data`. This affects + // what member of `data` union should be used. + TfLiteType type; +} TfLiteEvalTensor; + +#ifndef TF_LITE_STATIC_MEMORY +// Free data memory of tensor `t`. +void TfLiteTensorDataFree(TfLiteTensor* t); + +// Free quantization data. +void TfLiteQuantizationFree(TfLiteQuantization* quantization); + +// Free sparsity parameters. +void TfLiteSparsityFree(TfLiteSparsity* sparsity); + +// Free memory of tensor `t`. +void TfLiteTensorFree(TfLiteTensor* t); + +// Set all of a tensor's fields (and free any previously allocated data). +void TfLiteTensorReset(TfLiteType type, const char* name, TfLiteIntArray* dims, + TfLiteQuantizationParams quantization, char* buffer, + size_t size, TfLiteAllocationType allocation_type, + const void* allocation, bool is_variable, + TfLiteTensor* tensor); + +// Copies the contents of 'src' in 'dst'. +// Function does nothing if either 'src' or 'dst' is passed as nullptr and +// return kTfLiteOk. +// Returns kTfLiteError if 'src' and 'dst' doesn't have matching data size. +// Note function copies contents, so it won't create new data pointer +// or change allocation type. +// All Tensor related properties will be copied from 'src' to 'dst' like +// quantization, sparsity, ... +TfLiteStatus TfLiteTensorCopy(const TfLiteTensor* src, TfLiteTensor* dst); + +// Change the size of the memory block owned by `tensor` to `num_bytes`. +// Tensors with allocation types other than kTfLiteDynamic will be ignored. +// `tensor`'s internal data buffer will be assigned a pointer +// which can safely be passed to free or realloc if `num_bytes` is zero. +// Behaviour is undefined if `tensor` is NULL. +// If `preserve_data` is true, tensor data will be unchanged in the range from +// the start of the region up to the minimum of the old and new sizes. +void TfLiteTensorResizeMaybeCopy(size_t num_bytes, TfLiteTensor* tensor, + bool preserve_data); + +// Change the size of the memory block owned by `tensor` to `num_bytes`. +// Tensors with allocation types other than kTfLiteDynamic will be ignored. +// `tensor`'s internal data buffer will be assigned a pointer +// which can safely be passed to free or realloc if `num_bytes` is zero. +// Behaviour is undefined if `tensor` is NULL. +// Tensor data will be unchanged in the range from the start of the region up to +// the minimum of the old and new sizes. +void TfLiteTensorRealloc(size_t num_bytes, TfLiteTensor* tensor); +#endif // TF_LITE_STATIC_MEMORY + +// WARNING: This is an experimental interface that is subject to change. +// +// Currently, TfLiteDelegateParams has to be allocated in a way that it's +// trivially destructable. It will be stored as `builtin_data` field in +// `TfLiteNode` of the delegate node. +// +// See also the `CreateDelegateParams` function in `interpreter.cc` details. +typedef struct TfLiteDelegateParams { + struct TfLiteDelegate* delegate; + TfLiteIntArray* nodes_to_replace; + TfLiteIntArray* input_tensors; + TfLiteIntArray* output_tensors; +} TfLiteDelegateParams; + +typedef struct TfLiteContext { + // Number of tensors in the context. + size_t tensors_size; + + // The execution plan contains a list of the node indices in execution + // order. execution_plan->size is the current number of nodes. And, + // execution_plan->data[0] is the first node that needs to be run. + // TfLiteDelegates can traverse the current execution plan by iterating + // through each member of this array and using GetNodeAndRegistration() to + // access details about a node. i.e. + // + // TfLiteIntArray* execution_plan; + // TF_LITE_ENSURE_STATUS(context->GetExecutionPlan(context, &execution_plan)); + // for (int exec_index = 0; exec_index < execution_plan->size; exec_index++) { + // int node_index = execution_plan->data[exec_index]; + // TfLiteNode* node; + // TfLiteRegistration* reg; + // context->GetNodeAndRegistration(context, node_index, &node, ®); + // } + // Note: the memory pointed by '`*execution_plan` is OWNED by TfLite runtime. + // Future calls to GetExecutionPlan invalidates earlier outputs. The following + // code snippet shows the issue of such an invocation pattern. After calling + // CheckNode, subsequent access to `plan_1st` is undefined. + // + // void CheckNode(const TfLiteNode* node) { + // ... + // TfLiteIntArray* plan_2nd; + // TF_LITE_ENSURE_STATUS(context->GetExecutionPlan(context, &plan_2nd)); + // ... + // } + // + // TfLiteIntArray* plan_1st; + // TF_LITE_ENSURE_STATUS(context->GetExecutionPlan(context, &plan_1st)); + // for (int exec_index = 0; exec_index < plan_1st->size; exec_index++) { + // int node_index = plan_1st->data[exec_index]; + // TfLiteNode* node; + // TfLiteRegistration* reg; + // context->GetNodeAndRegistration(context, node_index, &node, ®); + // CheckNode(node); + // } + // + // WARNING: This is an experimental interface that is subject to change. + TfLiteStatus (*GetExecutionPlan)(struct TfLiteContext* context, + TfLiteIntArray** execution_plan); + + // An array of tensors in the interpreter context (of length `tensors_size`) + TfLiteTensor* tensors; + + // opaque full context ptr (an opaque c++ data structure) + void* impl_; + + // Request memory pointer be resized. Updates dimensions on the tensor. + // NOTE: ResizeTensor takes ownership of newSize. + TfLiteStatus (*ResizeTensor)(struct TfLiteContext*, TfLiteTensor* tensor, + TfLiteIntArray* new_size); + // Request that an error be reported with format string msg. + void (*ReportError)(struct TfLiteContext*, const char* msg, ...); + + // Add `tensors_to_add` tensors, preserving pre-existing Tensor entries. If + // non-null, the value pointed to by `first_new_tensor_index` will be set to + // the index of the first new tensor. + TfLiteStatus (*AddTensors)(struct TfLiteContext*, int tensors_to_add, + int* first_new_tensor_index); + + // Get a Tensor node by node_index. + // WARNING: This is an experimental interface that is subject to change. + TfLiteStatus (*GetNodeAndRegistration)( + struct TfLiteContext*, int node_index, TfLiteNode** node, + struct TfLiteRegistration** registration); + + // Replace ops with one or more stub delegate operations. This function + // does not take ownership of `nodes_to_replace`. + TfLiteStatus (*ReplaceNodeSubsetsWithDelegateKernels)( + struct TfLiteContext*, struct TfLiteRegistration registration, + const TfLiteIntArray* nodes_to_replace, struct TfLiteDelegate* delegate); + + // Number of threads that are recommended to subsystems like gemmlowp and + // eigen. + int recommended_num_threads; + + // Access external contexts by type. + // WARNING: This is an experimental interface that is subject to change. + TfLiteExternalContext* (*GetExternalContext)(struct TfLiteContext*, + TfLiteExternalContextType); + // Set the value of a external context. Does not take ownership of the + // pointer. + // WARNING: This is an experimental interface that is subject to change. + void (*SetExternalContext)(struct TfLiteContext*, TfLiteExternalContextType, + TfLiteExternalContext*); + + // Flag for allowing float16 precision for FP32 calculation. + // default: false. + // WARNING: This is an experimental API and subject to change. + bool allow_fp32_relax_to_fp16; + + // Pointer to the op-level profiler, if set; nullptr otherwise. + void* profiler; + + // Allocate persistent buffer which has the same life time as the interpreter. + // Returns nullptr on failure. + // The memory is allocated from heap for TFL, and from tail in TFLM. + // This method is only available in Init or Prepare stage. + // WARNING: This is an experimental interface that is subject to change. + void* (*AllocatePersistentBuffer)(struct TfLiteContext* ctx, size_t bytes); + + // Allocate a buffer which will be deallocated right after invoke phase. + // The memory is allocated from heap in TFL, and from volatile arena in TFLM. + // This method is only available in invoke stage. + // NOTE: If possible use RequestScratchBufferInArena method to avoid memory + // allocation during inference time. + // WARNING: This is an experimental interface that is subject to change. + TfLiteStatus (*AllocateBufferForEval)(struct TfLiteContext* ctx, size_t bytes, + void** ptr); + + // Request a scratch buffer in the arena through static memory planning. + // This method is only available in Prepare stage and the buffer is allocated + // by the interpreter between Prepare and Eval stage. In Eval stage, + // GetScratchBuffer API can be used to fetch the address. + // WARNING: This is an experimental interface that is subject to change. + TfLiteStatus (*RequestScratchBufferInArena)(struct TfLiteContext* ctx, + size_t bytes, int* buffer_idx); + + // Get the scratch buffer pointer. + // This method is only available in Eval stage. + // WARNING: This is an experimental interface that is subject to change. + void* (*GetScratchBuffer)(struct TfLiteContext* ctx, int buffer_idx); + + // Resize the memory pointer of the `tensor`. This method behaves the same as + // `ResizeTensor`, except that it makes a copy of the shape array internally + // so the shape array could be deallocated right afterwards. + // WARNING: This is an experimental interface that is subject to change. + TfLiteStatus (*ResizeTensorExplicit)(struct TfLiteContext* ctx, + TfLiteTensor* tensor, int dims, + const int* shape); + + // This method provides a preview of post-delegation partitioning. Each + // TfLiteDelegateParams in the referenced array corresponds to one instance of + // the delegate kernel. + // Example usage: + // + // TfLiteIntArray* nodes_to_replace = ...; + // TfLiteDelegateParams* params_array; + // int num_partitions = 0; + // TF_LITE_ENSURE_STATUS(context->PreviewDelegatePartitioning( + // context, delegate, nodes_to_replace, ¶ms_array, &num_partitions)); + // for (int idx = 0; idx < num_partitions; idx++) { + // const auto& partition_params = params_array[idx]; + // ... + // } + // + // NOTE: The context owns the memory referenced by partition_params_array. It + // will be cleared with another call to PreviewDelegateParitioning, or after + // TfLiteDelegateParams::Prepare returns. + // + // WARNING: This is an experimental interface that is subject to change. + TfLiteStatus (*PreviewDelegatePartitioning)( + struct TfLiteContext* context, const TfLiteIntArray* nodes_to_replace, + TfLiteDelegateParams** partition_params_array, int* num_partitions); + + // Returns a TfLiteTensor struct for a given index. + // WARNING: This is an experimental interface that is subject to change. + // WARNING: This method may not be available on all platforms. + TfLiteTensor* (*GetTensor)(const struct TfLiteContext* context, + int tensor_idx); + + // Returns a TfLiteEvalTensor struct for a given index. + // WARNING: This is an experimental interface that is subject to change. + // WARNING: This method may not be available on all platforms. + TfLiteEvalTensor* (*GetEvalTensor)(const struct TfLiteContext* context, + int tensor_idx); + + // Retrieves named metadata buffer from the TFLite model. + // Returns kTfLiteOk if metadata is successfully obtained from the flatbuffer + // Model: that is, there exists a `metadata` entry with given `name` string. + // (see TFLite's schema.fbs). + // The corresponding `buffer` information is populated in `ptr` & `bytes`. + // The data from `ptr` is valid for the lifetime of the Interpreter. + // + // WARNING: This is an experimental interface that is subject to change. + TfLiteStatus (*GetModelMetadata)(const struct TfLiteContext* context, + const char* name, const char** ptr, + size_t* bytes); +} TfLiteContext; + +// `TfLiteRegistrationExternal` is an external version of `TfLiteRegistration` +// for C API which doesn't use internal types (such as `TfLiteContext`) but only +// uses stable API types (such as `TfLiteOpaqueContext`). The purpose of each +// field is the exactly the same as with `TfLiteRegistration`. +typedef struct TfLiteRegistrationExternal TfLiteRegistrationExternal; + +typedef struct TfLiteRegistration { + // Initializes the op from serialized data. + // Called only *once* for the lifetime of the op, so any one-time allocations + // should be made here (unless they depend on tensor sizes). + // + // If a built-in op: + // `buffer` is the op's params data (TfLiteLSTMParams*). + // `length` is zero. + // If custom op: + // `buffer` is the op's `custom_options`. + // `length` is the size of the buffer. + // + // Returns a type-punned (i.e. void*) opaque data (e.g. a primitive pointer + // or an instance of a struct). + // + // The returned pointer will be stored with the node in the `user_data` field, + // accessible within prepare and invoke functions below. + // NOTE: if the data is already in the desired format, simply implement this + // function to return `nullptr` and implement the free function to be a no-op. + void* (*init)(TfLiteContext* context, const char* buffer, size_t length); + + // The pointer `buffer` is the data previously returned by an init invocation. + void (*free)(TfLiteContext* context, void* buffer); + + // prepare is called when the inputs this node depends on have been resized. + // context->ResizeTensor() can be called to request output tensors to be + // resized. + // Can be called multiple times for the lifetime of the op. + // + // Returns kTfLiteOk on success. + TfLiteStatus (*prepare)(TfLiteContext* context, TfLiteNode* node); + + // Execute the node (should read node->inputs and output to node->outputs). + // Returns kTfLiteOk on success. + TfLiteStatus (*invoke)(TfLiteContext* context, TfLiteNode* node); + + // profiling_string is called during summarization of profiling information + // in order to group executions together. Providing a value here will cause a + // given op to appear multiple times is the profiling report. This is + // particularly useful for custom ops that can perform significantly + // different calculations depending on their `user-data`. + const char* (*profiling_string)(const TfLiteContext* context, + const TfLiteNode* node); + + // Builtin codes. If this kernel refers to a builtin this is the code + // of the builtin. This is so we can do marshaling to other frameworks like + // NN API. + // Note: It is the responsibility of the registration binder to set this + // properly. + int32_t builtin_code; + + // Custom op name. If the op is a builtin, this will be null. + // Note: It is the responsibility of the registration binder to set this + // properly. + // WARNING: This is an experimental interface that is subject to change. + const char* custom_name; + + // The version of the op. + // Note: It is the responsibility of the registration binder to set this + // properly. + int version; + + // The external version of `TfLiteRegistration`. Since we can't use internal + // types (such as `TfLiteContext`) for C API to maintain ABI stability. + // C API user will provide `TfLiteRegistrationExternal` to implement custom + // ops. We keep it inside of `TfLiteRegistration` and use it to route + // callbacks properly. + TfLiteRegistrationExternal* registration_external; +} TfLiteRegistration; + +// Old version of `TfLiteRegistration` to maintain binary backward +// compatibility. +// WARNING: This structure is deprecated / not an official part of the API. +// It should be only used for binary backward compatibility. +typedef struct TfLiteRegistration_V1 { + void* (*init)(TfLiteContext* context, const char* buffer, size_t length); + void (*free)(TfLiteContext* context, void* buffer); + TfLiteStatus (*prepare)(TfLiteContext* context, TfLiteNode* node); + TfLiteStatus (*invoke)(TfLiteContext* context, TfLiteNode* node); + const char* (*profiling_string)(const TfLiteContext* context, + const TfLiteNode* node); + int32_t builtin_code; + const char* custom_name; + int version; +} TfLiteRegistration_V1; + +// The flags used in `TfLiteDelegate`. Note that this is a bitmask, so the +// values should be 1, 2, 4, 8, ...etc. +typedef enum TfLiteDelegateFlags { + kTfLiteDelegateFlagsNone = 0, + // The flag is set if the delegate can handle dynamic sized tensors. + // For example, the output shape of a `Resize` op with non-constant shape + // can only be inferred when the op is invoked. + // In this case, the Delegate is responsible for calling + // `SetTensorToDynamic` to mark the tensor as a dynamic tensor, and calling + // `ResizeTensor` when invoking the op. + // + // If the delegate isn't capable to handle dynamic tensors, this flag need + // to be set to false. + kTfLiteDelegateFlagsAllowDynamicTensors = 1, + + // This flag can be used by delegates (that allow dynamic tensors) to ensure + // applicable tensor shapes are automatically propagated in the case of tensor + // resizing. + // This means that non-dynamic (allocation_type != kTfLiteDynamic) I/O tensors + // of a delegate kernel will have correct shapes before its Prepare() method + // is called. The runtime leverages TFLite builtin ops in the original + // execution plan to propagate shapes. + // + // A few points to note: + // 1. This requires kTfLiteDelegateFlagsAllowDynamicTensors. If that flag is + // false, this one is redundant since the delegate kernels are re-initialized + // every time tensors are resized. + // 2. Enabling this flag adds some overhead to AllocateTensors(), since extra + // work is required to prepare the original execution plan. + // 3. This flag requires that the original execution plan only have ops with + // valid registrations (and not 'dummy' custom ops like with Flex). + // WARNING: This feature is experimental and subject to change. + kTfLiteDelegateFlagsRequirePropagatedShapes = 2 +} TfLiteDelegateFlags; + +// WARNING: This is an experimental interface that is subject to change. +typedef struct TfLiteDelegate { + // Data that delegate needs to identify itself. This data is owned by the + // delegate. The delegate is owned in the user code, so the delegate is + // responsible for deallocating this when it is destroyed. + void* data_; + + // Invoked by ModifyGraphWithDelegate. This prepare is called, giving the + // delegate a view of the current graph through TfLiteContext*. It typically + // will look at the nodes and call ReplaceNodeSubsetsWithDelegateKernels() + // to ask the TensorFlow lite runtime to create macro-nodes to represent + // delegated subgraphs of the original graph. + TfLiteStatus (*Prepare)(TfLiteContext* context, + struct TfLiteDelegate* delegate); + + // Copy the data from delegate buffer handle into raw memory of the given + // 'tensor'. Note that the delegate is allowed to allocate the raw bytes as + // long as it follows the rules for kTfLiteDynamic tensors, in which case this + // cannot be null. + TfLiteStatus (*CopyFromBufferHandle)(TfLiteContext* context, + struct TfLiteDelegate* delegate, + TfLiteBufferHandle buffer_handle, + TfLiteTensor* tensor); + + // Copy the data from raw memory of the given 'tensor' to delegate buffer + // handle. This can be null if the delegate doesn't use its own buffer. + TfLiteStatus (*CopyToBufferHandle)(TfLiteContext* context, + struct TfLiteDelegate* delegate, + TfLiteBufferHandle buffer_handle, + TfLiteTensor* tensor); + + // Free the Delegate Buffer Handle. Note: This only frees the handle, but + // this doesn't release the underlying resource (e.g. textures). The + // resources are either owned by application layer or the delegate. + // This can be null if the delegate doesn't use its own buffer. + void (*FreeBufferHandle)(TfLiteContext* context, + struct TfLiteDelegate* delegate, + TfLiteBufferHandle* handle); + + // Bitmask flags. See the comments in `TfLiteDelegateFlags`. + int64_t flags; + + // The opaque delegate builder associated with this object. If set then the + // TF Lite runtime will give precedence to this field. E.g. instead of + // invoking 'Prepare' via the function pointer inside the 'TfLiteDelegate' + // object, the runtime will first check if the corresponding function + // pointer inside 'opaque_delegate_builder' is set and if so invoke that. + // + // If this field is non-null, then the 'Prepare' field (of the + // 'TfLiteDelegate') should be null. + struct TfLiteOpaqueDelegateBuilder* opaque_delegate_builder; +} TfLiteDelegate; + +// Build a 'null' delegate, with all the fields properly set to their default +// values. +TfLiteDelegate TfLiteDelegateCreate(void); + +// `TfLiteOpaqueDelegateBuilder` is used for constructing +// `TfLiteOpaqueDelegateStruct`, see `TfLiteOpaqueDelegateCreate` below. Note: +// This struct is not ABI stable. +// +// For forward source compatibility `TfLiteOpaqueDelegateBuilder` objects should +// be brace-initialized, so that all fields (including any that might be added +// in the future) get zero-initialized. The purpose of each field is exactly +// the same as with `TfLiteDelegate`. +// +// WARNING: This is an experimental interface that is subject to change. +typedef struct TfLiteOpaqueDelegateBuilder { + // Data that delegate needs to identify itself. This data is owned by the + // delegate. The delegate is owned in the user code, so the delegate is + // responsible for deallocating this when it is destroyed. + void* data; + // Invoked by ModifyGraphWithDelegate. This prepare is called, giving the + // delegate a view of the current graph through TfLiteContext*. It typically + // will look at the nodes and call ReplaceNodeSubsetsWithDelegateKernels() + // to ask the TensorFlow lite runtime to create macro-nodes to represent + // delegated subgraphs of the original graph. + TfLiteStatus (*Prepare)(TfLiteOpaqueContext* context, // NOLINT + struct TfLiteOpaqueDelegateStruct* delegate, + void* data); + // Copies the data from delegate buffer handle into raw memory of the given + // 'tensor'. Note that the delegate is allowed to allocate the raw bytes as + // long as it follows the rules for kTfLiteDynamic tensors, in which case this + // cannot be null. + TfLiteStatus (*CopyFromBufferHandle)( // NOLINT + TfLiteOpaqueContext* context, struct TfLiteOpaqueDelegateStruct* delegate, + void* data, TfLiteBufferHandle buffer_handle, TfLiteOpaqueTensor* tensor); + // Copies the data from raw memory of the given 'tensor' to delegate buffer + // handle. This can be null if the delegate doesn't use its own buffer. + TfLiteStatus (*CopyToBufferHandle)( // NOLINT + TfLiteOpaqueContext* context, struct TfLiteOpaqueDelegateStruct* delegate, + void* data, TfLiteBufferHandle buffer_handle, TfLiteOpaqueTensor* tensor); + // Frees the Delegate Buffer Handle. Note: This only frees the handle, but + // this doesn't release the underlying resource (e.g. textures). The + // resources are either owned by application layer or the delegate. + // This can be null if the delegate doesn't use its own buffer. + void (*FreeBufferHandle)(TfLiteOpaqueContext* context, // NOLINT + struct TfLiteOpaqueDelegateStruct* delegate, + void* data, TfLiteBufferHandle* handle); + // Bitmask flags. See the comments in `TfLiteDelegateFlags`. + int64_t flags; +} TfLiteOpaqueDelegateBuilder; + +// Creates an opaque delegate and returns its address. The opaque delegate will +// behave according to the provided 'opaque_delegate_builder'. The lifetime of +// the fields within the 'opaque_delegate_builder' must outlive any interaction +// between the runtime and the returned 'TfLiteOpaqueDelegateStruct'. The +// returned address should be passed to 'TfLiteOpaqueDelegateDelete' for +// deletion. If 'opaque_delegate_builder' is a null pointer, then a null +// pointer will be returned. +struct TfLiteOpaqueDelegateStruct* TfLiteOpaqueDelegateCreate( + const TfLiteOpaqueDelegateBuilder* opaque_delegate_builder); + +// Deletes the provided opaque 'delegate'. This function has no effect if the +// 'delegate' is a null pointer. +void TfLiteOpaqueDelegateDelete( + const struct TfLiteOpaqueDelegateStruct* delegate); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus +#endif // TENSORFLOW_LITE_C_COMMON_H_ diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/delegate.h b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/delegate.h new file mode 100644 index 0000000..7702c36 --- /dev/null +++ b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/delegate.h @@ -0,0 +1,45 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#ifndef TENSORFLOW_LITE_DELEGATES_GPU_DELEGATE_H_ +#define TENSORFLOW_LITE_DELEGATES_GPU_DELEGATE_H_ + +#include + +#include "common.h" +#include "delegate_options.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Creates a new delegate instance that need to be destroyed with +// TfLiteGpuDelegateV2Delete when delegate is no longer used by TFLite. +// +// This delegate encapsulates multiple GPU-acceleration APIs under the hood to +// make use of the fastest available on a device. +// +// When `options` is set to `nullptr`, then default options are used. +TFL_CAPI_EXPORT TfLiteDelegate* TfLiteGpuDelegateV2Create( + const TfLiteGpuDelegateOptionsV2* options); + +// Destroys a delegate created with `TfLiteGpuDelegateV2Create` call. +TFL_CAPI_EXPORT void TfLiteGpuDelegateV2Delete(TfLiteDelegate* delegate); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // TENSORFLOW_LITE_DELEGATES_GPU_DELEGATE_H_ diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/delegate_options.h b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/delegate_options.h new file mode 100644 index 0000000..1f51135 --- /dev/null +++ b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/delegate_options.h @@ -0,0 +1,150 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#ifndef TENSORFLOW_LITE_DELEGATES_GPU_DELEGATE_OPTIONS_H_ +#define TENSORFLOW_LITE_DELEGATES_GPU_DELEGATE_OPTIONS_H_ + +#include + +#include "common.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Encapsulated compilation/runtime tradeoffs. +enum TfLiteGpuInferenceUsage { + // Delegate will be used only once, therefore, bootstrap/init time should + // be taken into account. + TFLITE_GPU_INFERENCE_PREFERENCE_FAST_SINGLE_ANSWER = 0, + + // Prefer maximizing the throughput. Same delegate will be used repeatedly on + // multiple inputs. + TFLITE_GPU_INFERENCE_PREFERENCE_SUSTAINED_SPEED = 1, +}; + +enum TfLiteGpuInferencePriority { + // AUTO priority is needed when a single priority is the most important + // factor. For example, + // priority1 = MIN_LATENCY would result in the configuration that achieves + // maximum performance. + TFLITE_GPU_INFERENCE_PRIORITY_AUTO = 0, + TFLITE_GPU_INFERENCE_PRIORITY_MAX_PRECISION = 1, + TFLITE_GPU_INFERENCE_PRIORITY_MIN_LATENCY = 2, + TFLITE_GPU_INFERENCE_PRIORITY_MIN_MEMORY_USAGE = 3, +}; + +// Used to toggle experimental flags used in the delegate. Note that this is a +// bitmask, so the values should be 1, 2, 4, 8, ...etc. +enum TfLiteGpuExperimentalFlags { + TFLITE_GPU_EXPERIMENTAL_FLAGS_NONE = 0, + // Enables inference on quantized models with the delegate. + // NOTE: This is enabled in TfLiteGpuDelegateOptionsV2Default. + TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_QUANT = 1 << 0, + // Enforces execution with the provided backend. + TFLITE_GPU_EXPERIMENTAL_FLAGS_CL_ONLY = 1 << 1, + TFLITE_GPU_EXPERIMENTAL_FLAGS_GL_ONLY = 1 << 2, + // Enable serialization of GPU kernels & model data. Speeds up initilization + // at the cost of space on disk. + // Delegate performs serialization the first time it is applied with a new + // model or inference params. Later initializations are fast. + // ModifyGraphWithDelegate will fail if data cannot be serialized. + // + // NOTE: User also needs to set serialization_dir & model_token in + // TfLiteGpuDelegateOptionsV2. + // Currently works only if CL backend is used. + TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_SERIALIZATION = 1 << 3, +}; + +// IMPORTANT: Always use TfLiteGpuDelegateOptionsV2Default() method to create +// new instance of TfLiteGpuDelegateOptionsV2, otherwise every new added option +// may break inference. +typedef struct { + // When set to zero, computations are carried out in maximal possible + // precision. Otherwise, the GPU may quantify tensors, downcast values, + // process in FP16 to increase performance. For most models precision loss is + // warranted. + // [OBSOLETE]: to be removed + int32_t is_precision_loss_allowed; + + // Preference is defined in TfLiteGpuInferenceUsage. + int32_t inference_preference; + + // Ordered priorities provide better control over desired semantics, + // where priority(n) is more important than priority(n+1), therefore, + // each time inference engine needs to make a decision, it uses + // ordered priorities to do so. + // For example: + // MAX_PRECISION at priority1 would not allow to decrease precision, + // but moving it to priority2 or priority3 would result in F16 calculation. + // + // Priority is defined in TfLiteGpuInferencePriority. + // AUTO priority can only be used when higher priorities are fully specified. + // For example: + // VALID: priority1 = MIN_LATENCY, priority2 = AUTO, priority3 = AUTO + // VALID: priority1 = MIN_LATENCY, priority2 = MAX_PRECISION, + // priority3 = AUTO + // INVALID: priority1 = AUTO, priority2 = MIN_LATENCY, priority3 = AUTO + // INVALID: priority1 = MIN_LATENCY, priority2 = AUTO, + // priority3 = MAX_PRECISION + // Invalid priorities will result in error. + int32_t inference_priority1; + int32_t inference_priority2; + int32_t inference_priority3; + + // Bitmask flags. See the comments in TfLiteGpuExperimentalFlags. + int64_t experimental_flags; + + // A graph could have multiple partitions that can be delegated to the GPU. + // This limits the maximum number of partitions to be delegated. By default, + // it's set to 1 in TfLiteGpuDelegateOptionsV2Default(). + int32_t max_delegated_partitions; + + // The nul-terminated directory to use for serialization. + // Whether serialization actually happens or not is dependent on backend used + // and validity of this directory. + // Set to nullptr in TfLiteGpuDelegateOptionsV2Default(), which implies the + // delegate will not try serialization. + // + // NOTE: Users should ensure that this directory is private to the app to + // avoid data access issues. + const char* serialization_dir; + + // The unique nul-terminated token string that acts as a 'namespace' for + // all serialization entries. + // Should be unique to a particular model (graph & constants). + // For an example of how to generate this from a TFLite model, see + // StrFingerprint() in lite/delegates/serialization.h. + // + // Set to nullptr in TfLiteGpuDelegateOptionsV2Default(), which implies the + // delegate will not try serialization. + const char* model_token; +} TfLiteGpuDelegateOptionsV2; + +// Populates TfLiteGpuDelegateOptionsV2 as follows: +// is_precision_loss_allowed = false +// inference_preference = TFLITE_GPU_INFERENCE_PREFERENCE_FAST_SINGLE_ANSWER +// priority1 = TFLITE_GPU_INFERENCE_PRIORITY_MAX_PRECISION +// priority2 = TFLITE_GPU_INFERENCE_PRIORITY_AUTO +// priority3 = TFLITE_GPU_INFERENCE_PRIORITY_AUTO +// experimental_flags = TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_QUANT +// max_delegated_partitions = 1 +TFL_CAPI_EXPORT TfLiteGpuDelegateOptionsV2 TfLiteGpuDelegateOptionsV2Default(); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // TENSORFLOW_LITE_DELEGATES_GPU_DELEGATE_OPTIONS_H_ diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/xnnpack_delegate.h b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/xnnpack_delegate.h new file mode 100644 index 0000000..70e959f --- /dev/null +++ b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Headers/xnnpack_delegate.h @@ -0,0 +1,119 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#ifndef TENSORFLOW_LITE_DELEGATES_XNNPACK_XNNPACK_DELEGATE_H_ +#define TENSORFLOW_LITE_DELEGATES_XNNPACK_XNNPACK_DELEGATE_H_ + +#include "common.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Enable XNNPACK acceleration for signed quantized 8-bit inference. +// This includes operators with channel-wise quantized weights. +#define TFLITE_XNNPACK_DELEGATE_FLAG_QS8 0x00000001 +// Enable XNNPACK acceleration for unsigned quantized 8-bit inference. +#define TFLITE_XNNPACK_DELEGATE_FLAG_QU8 0x00000002 +// Force FP16 inference for FP32 operators. +#define TFLITE_XNNPACK_DELEGATE_FLAG_FORCE_FP16 0x00000004 +// Enable XNNPACK acceleration for FULLY_CONNECTED operator with dynamic +// weights. +#define TFLITE_XNNPACK_DELEGATE_FLAG_DYNAMIC_FULLY_CONNECTED 0x00000008 + +struct TfLiteXNNPackDelegateWeightsCache; + +typedef struct { + // Number of threads to use in the thread pool. + // 0 or negative value means no thread pool used. + int32_t num_threads; + // Bitfield with any combination of the following binary options: + // - TFLITE_XNNPACK_DELEGATE_FLAG_QS8 + // - TFLITE_XNNPACK_DELEGATE_FLAG_QU8 + // - TFLITE_XNNPACK_DELEGATE_FLAG_FORCE_FP16 + // - TFLITE_XNNPACK_DELEGATE_FLAG_DYNAMIC_FULLY_CONNECTED + uint32_t flags; + // Cache for packed weights, can be shared between multiple instances of + // delegates. + struct TfLiteXNNPackDelegateWeightsCache* weights_cache; + // Whether READ_VARIABLE, ASSIGN_VARIABLE, and VARIABLE_HANDLE operations + // should be handled by XNNPACK. + bool handle_variable_ops; +} TfLiteXNNPackDelegateOptions; + +// Returns a structure with the default XNNPack delegate options. +TFL_CAPI_EXPORT TfLiteXNNPackDelegateOptions +TfLiteXNNPackDelegateOptionsDefault(); + +// Creates a new delegate instance that need to be destroyed with +// `TfLiteXNNPackDelegateDelete` when delegate is no longer used by TFLite. +// When `options` is set to `nullptr`, default values are used (see +// implementation of TfLiteXNNPackDelegateOptionsDefault in the .cc file for +// details). +TFL_CAPI_EXPORT TfLiteDelegate* TfLiteXNNPackDelegateCreate( + const TfLiteXNNPackDelegateOptions* options); + +// Performs the same task as TfLiteXNNPackDelegateCreate, with one exception. +// If the context passed contains a non-null xnnpack_threadpool field, +// we will use it as the threadpool for the delegate created. +TfLiteDelegate* TfLiteXNNPackDelegateCreateWithThreadpool( + const TfLiteXNNPackDelegateOptions* options, TfLiteContext* context); + +// Returns the pthreadpool_t object used for parallelization in XNNPACK. +// Can return NULL if the XNNPack delegate is single-threaded. +// +// WARNING: This API is experimental and subject to change. +TFL_CAPI_EXPORT void* TfLiteXNNPackDelegateGetThreadPool( + TfLiteDelegate* delegate); + +// Destroys a delegate created with `TfLiteXNNPackDelegateCreate` call. +TFL_CAPI_EXPORT void TfLiteXNNPackDelegateDelete(TfLiteDelegate* delegate); + +// Creates a new weights cache that can be shared with multiple delegate +// instances. Prefer TfLiteXNNPackDelegateWeightsCacheCreateWithSize which can +// reduce memory bandwidth. +TFL_CAPI_EXPORT struct TfLiteXNNPackDelegateWeightsCache* +TfLiteXNNPackDelegateWeightsCacheCreate(); +// Creates a new weights cache with a specified initial size that can be shared +// with multiple delegate instances. The weights cache can hold up to size bytes +// without growing. +TFL_CAPI_EXPORT struct TfLiteXNNPackDelegateWeightsCache* +TfLiteXNNPackDelegateWeightsCacheCreateWithSize(size_t size); +// Soft-finalize a weights cache. Extra space will be left in the weights cache +// to allow for cache "insertion" only if it is a cache hit. This has memory +// overhead compared to TfLiteXNNPackDelegateWeightsCacheFinalizeHard. Use this +// if the number of interpreter instances using XNNPACK delegate is not fixed +// (e.g. created based on workload in a server daemon). +// Returns true on success, false on error. +TFL_CAPI_EXPORT bool TfLiteXNNPackDelegateWeightsCacheFinalizeSoft( + struct TfLiteXNNPackDelegateWeightsCache* cache); +// Hard-finalize a weights cache, cache is effectively frozen and no more cache +// operations are allowed. Memory is resized to smallest possible. Use this if +// the number of interpreter instances using XNNPACK delegate can be fixed and +// all creation of instances can happen up front. This has the lowest memory +// usage. +// Returns true on success, false on error. +TFL_CAPI_EXPORT bool TfLiteXNNPackDelegateWeightsCacheFinalizeHard( + struct TfLiteXNNPackDelegateWeightsCache* cache); +// Destroys a weights cache created with +// `TfLiteXNNPackDelegateWeightsCacheCreate` call. +TFL_CAPI_EXPORT void TfLiteXNNPackDelegateWeightsCacheDelete( + struct TfLiteXNNPackDelegateWeightsCache* cache); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // TENSORFLOW_LITE_DELEGATES_XNNPACK_XNNPACK_DELEGATE_H_ \ No newline at end of file diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Resources/Info.plist b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..5587109 --- /dev/null +++ b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,18 @@ + + + + + CFBundleIdentifier + org.tensorflow.TensorFlowLiteC + CFBundleName + TensorFlowLiteC + CFBundlePackageType + FMWK + CFBundleVersion + 2.14.0 + CFBundleShortVersionString + 2.14.0 + MinimumOSVersion + 10.11 + + diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/TensorFlowLiteC b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/TensorFlowLiteC new file mode 100644 index 0000000..26f43ec Binary files /dev/null and b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/TensorFlowLiteC differ diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/_CodeSignature/CodeDirectory b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/_CodeSignature/CodeDirectory new file mode 100644 index 0000000..21ef1a0 Binary files /dev/null and b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/_CodeSignature/CodeDirectory differ diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/_CodeSignature/CodeRequirements b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/_CodeSignature/CodeRequirements new file mode 100644 index 0000000..dbf9d61 Binary files /dev/null and b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/_CodeSignature/CodeRequirements differ diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/_CodeSignature/CodeResources b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/_CodeSignature/CodeResources new file mode 100644 index 0000000..47ba627 --- /dev/null +++ b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/_CodeSignature/CodeResources @@ -0,0 +1,181 @@ + + + + + files + + files2 + + Headers/builtin_ops.h + + hash2 + + wAEUi+pJvYl9coA9wOtQGNx1ePv5cQgTeOXdOxg22JQ= + + + Headers/c_api.h + + hash2 + + tgZcatwppx1L/f4Y1j6jsB5FFo2GateU0+bnMct/MdM= + + + Headers/c_api_experimental.h + + hash2 + + v93ruP448jsGRylFXJPud2s1ECN6kxC2nEMqxDkekZE= + + + Headers/c_api_types.h + + hash2 + + pnlapT0ZuvoRmmGxR2+4Sx8zOLLe0UAXQsg03+WPB4s= + + + Headers/common.h + + hash2 + + o52eXBFZKKtNRyzLJkkRaz1c/lxT6zbk0+dSBj7bbcI= + + + Headers/delegate.h + + hash2 + + Za2mrnn5Ivb81tllr+W/FaOgKgFJ7Vz5vOSBPWp/IgY= + + + Headers/delegate_options.h + + hash2 + + /V5XRWHwa1VnkcmZcHbZUfXec2vnn63tBc0F0wE//lQ= + + + Headers/xnnpack_delegate.h + + hash2 + + Q89F3r9v06Tm3e1QQWtcxwLKUQPs+Iy0ZfIAqhE0b+0= + + + TensorFlowLiteC + + cdhash + + 1kRbsqN4YhBUmrU8A+TEofMQcm0= + + requirement + cdhash H"d6445bb2a3786210549ab53c03e4c4a1f310726d" or cdhash H"a17169a5244efd38a61b7e7d6bc72686801394d1" + + + rules + + ^Resources/ + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ + + nested + + weight + 10 + + ^.* + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^Resources/ + + weight + 20 + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^[^/]+$ + + nested + + weight + 10 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/_CodeSignature/CodeSignature b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/A/_CodeSignature/CodeSignature new file mode 100644 index 0000000..e69de29 diff --git a/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/Current b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/macos/tflite_core/TensorFlowLiteCMac.xcframework/macos-arm64_x86_64/TensorFlowLiteC.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index fffa988..bc5eac6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,10 +14,11 @@ # limitations under the License. # -name: tflite_flutter +name: tflite_core description: TensorFlow Lite Flutter plugin provides an easy, flexible, and fast Dart API to integrate TFLite models in flutter apps across mobile and desktop platforms. -version: 0.12.1 -homepage: https://github.com/tensorflow/flutter-tflite +version: 0.12.11 +homepage: https://github.com/kmmhanan/tflite-core +repository: https://github.com/kmmhanan/tflite-core environment: sdk: '>=3.3.0 <4.0.0' diff --git a/test/tflite_flutter_method_channel_test.dart b/test/tflite_core_method_channel_test.dart similarity index 86% rename from test/tflite_flutter_method_channel_test.dart rename to test/tflite_core_method_channel_test.dart index 80b4d27..fa3a2ff 100644 --- a/test/tflite_flutter_method_channel_test.dart +++ b/test/tflite_core_method_channel_test.dart @@ -1,6 +1,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:tflite_flutter/tflite_flutter_method_channel.dart'; +import 'package:tflite_core/tflite_core_method_channel.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -9,8 +9,7 @@ void main() { const MethodChannel channel = MethodChannel('tflite_flutter'); setUp(() { - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler( + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler( channel, (MethodCall methodCall) async { return '42'; diff --git a/test/tflite_core_test.dart b/test/tflite_core_test.dart new file mode 100644 index 0000000..5c6f435 --- /dev/null +++ b/test/tflite_core_test.dart @@ -0,0 +1,33 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tflite_core/tflite_core_platform_interface.dart'; +import 'package:tflite_core/tflite_core_method_channel.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +// Mock platform that never touches the native dylib. +class MockTfliteFlutterPlatform with MockPlatformInterfaceMixin implements TfliteFlutterPlatform { + @override + Future getPlatformVersion() => Future.value('42'); +} + +void main() { + final TfliteFlutterPlatform initialPlatform = TfliteFlutterPlatform.instance; + + setUp(() { + // Replace the real platform (which loads the dylib) with the mock. + TfliteFlutterPlatform.instance = MockTfliteFlutterPlatform(); + }); + + tearDown(() { + // Restore so other test files are not affected. + TfliteFlutterPlatform.instance = initialPlatform; + }); + + test('MethodChannelTfliteFlutter is the default instance', () { + expect(initialPlatform, isInstanceOf()); + }); + + test('getPlatformVersion returns mocked value', () async { + final version = await TfliteFlutterPlatform.instance.getPlatformVersion(); + expect(version, '42'); + }); +} diff --git a/test/tflite_flutter_test.dart b/test/tflite_flutter_test.dart deleted file mode 100644 index cb48df6..0000000 --- a/test/tflite_flutter_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; -import 'package:tflite_flutter/tflite_flutter_platform_interface.dart'; -import 'package:tflite_flutter/tflite_flutter_method_channel.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; - -class MockTfliteFlutterPlatform - with MockPlatformInterfaceMixin - implements TfliteFlutterPlatform { - @override - Future getPlatformVersion() => Future.value('42'); -} - -void main() { - final TfliteFlutterPlatform initialPlatform = TfliteFlutterPlatform.instance; - - test('$MethodChannelTfliteFlutter is the default instance', () { - expect(initialPlatform, isInstanceOf()); - }); - - test('getPlatformVersion', () async { - expect(version, '42'); - }); -} diff --git a/test/tflite_helper_test.dart b/test/tflite_helper_test.dart new file mode 100644 index 0000000..57ff22f --- /dev/null +++ b/test/tflite_helper_test.dart @@ -0,0 +1,261 @@ +import 'dart:math' as math; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:tflite_core/tflite_core_platform_interface.dart'; +import 'package:tflite_core/tflite_core_method_channel.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +// ── Mock ─────────────────────────────────────────────────────────────────── + +class MockTfliteFlutterPlatform with MockPlatformInterfaceMixin implements TfliteFlutterPlatform { + @override + Future getPlatformVersion() => Future.value('iOS 17.0'); +} + +// ── Pure-Dart mirrors of package internals ──────────────────────────────── +// These replicate the logic from nlu_engine.dart / meta_provider.dart / +// wake_word_detector.dart so tests never load the native dylib. + +List _tokenize(String text, Map vocab, int maxLen) { + final tokens = text.toLowerCase().trim().split(RegExp(r'\s+')); + final ids = tokens.take(maxLen).map((w) => vocab[w] ?? 1).toList(); + while (ids.length < maxLen) { + ids.add(0); + } + return ids; +} + +List _softmax(List logits) { + final max = logits.reduce((a, b) => a > b ? a : b); + final exps = logits.map((l) => math.exp(l - max)).toList(); + final sum = exps.reduce((a, b) => a + b); + return exps.map((e) => e / sum).toList(); +} + +int _argmax(List v) { + var best = 0; + for (var i = 1; i < v.length; i++) { + if (v[i] > v[best]) best = i; + } + return best; +} + +String _extractCommand(String transcript, String wakeWord) => + transcript.replaceFirst(wakeWord, '').trim(); + +// ── Tests ────────────────────────────────────────────────────────────────── + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + late TfliteFlutterPlatform originalPlatform; + + setUp(() { + originalPlatform = TfliteFlutterPlatform.instance; + TfliteFlutterPlatform.instance = MockTfliteFlutterPlatform(); + }); + + tearDown(() { + TfliteFlutterPlatform.instance = originalPlatform; + }); + + // ── Platform channel ────────────────────────────────────────────────────── + + group('TfliteFlutter platform channel', () { + test('default instance is MethodChannelTfliteFlutter', () { + expect(originalPlatform, isInstanceOf()); + }); + + test('getPlatformVersion returns mocked OS string', () async { + final v = await TfliteFlutterPlatform.instance.getPlatformVersion(); + expect(v, 'iOS 17.0'); + }); + + test('getPlatformVersion is non-null', () async { + final v = await TfliteFlutterPlatform.instance.getPlatformVersion(); + expect(v, isNotNull); + }); + }); + + // ── NluMeta tokenizer ───────────────────────────────────────────────────── + + group('NluMeta.tokenize', () { + const vocab = { + 'hello': 2, + 'world': 3, + 'add': 4, + 'task': 5, + 'buy': 6, + 'milk': 7, + }; + const maxLen = 16; + + test('known words are mapped to their vocab ids', () { + final ids = _tokenize('hello world', vocab, maxLen); + expect(ids[0], 2); + expect(ids[1], 3); + }); + + test('unknown words are mapped to OOV id 1', () { + final ids = _tokenize('foobar', vocab, maxLen); + expect(ids[0], 1); + }); + + test('output is always padded to maxLen', () { + final ids = _tokenize('hello', vocab, maxLen); + expect(ids.length, maxLen); + expect(ids.sublist(1), everyElement(0)); + }); + + test('long input is truncated to maxLen', () { + final longText = List.generate(20, (_) => 'hello').join(' '); + final ids = _tokenize(longText, vocab, maxLen); + expect(ids.length, maxLen); + }); + + test('input is lowercased before tokenization', () { + expect(_tokenize('hello', vocab, maxLen), _tokenize('HELLO', vocab, maxLen)); + }); + + test('leading and trailing whitespace is ignored', () { + expect( + _tokenize('hello world', vocab, maxLen), + _tokenize(' hello world ', vocab, maxLen), + ); + }); + + test('empty string produces OOV id then all-padding', () { + final ids = _tokenize('', vocab, maxLen); + expect(ids[0], 1); + expect(ids.sublist(1), everyElement(0)); + }); + + test('multi-word intent phrase maps correctly', () { + final ids = _tokenize('add task', vocab, maxLen); + expect(ids[0], 4); // add + expect(ids[1], 5); // task + }); + }); + + // ── Softmax / argmax ────────────────────────────────────────────────────── + + group('NluEngine math helpers', () { + test('softmax outputs sum to ~1.0', () { + final probs = _softmax([1.0, 2.0, 3.0]); + expect(probs.reduce((a, b) => a + b), closeTo(1.0, 1e-6)); + }); + + test('softmax largest logit gets highest probability', () { + final probs = _softmax([1.0, 5.0, 2.0]); + expect(_argmax(probs), 1); + }); + + test('argmax returns index of maximum value', () { + expect(_argmax([0.1, 0.8, 0.1]), 1); + expect(_argmax([0.9, 0.05, 0.05]), 0); + expect(_argmax([0.1, 0.1, 0.8]), 2); + }); + + test('softmax is numerically stable for large logit differences', () { + final probs = _softmax([1000.0, 0.0, 0.0]); + expect(probs[0], closeTo(1.0, 1e-6)); + }); + + test('equal logits produce uniform distribution', () { + final probs = _softmax([1.0, 1.0, 1.0]); + for (final p in probs) { + expect(p, closeTo(1 / 3, 1e-6)); + } + }); + + test('all softmax values are between 0 and 1', () { + final probs = _softmax([-1.0, 0.0, 1.0, 2.0]); + for (final p in probs) { + expect(p, inInclusiveRange(0.0, 1.0)); + } + }); + + test('argmax with single element returns 0', () { + expect(_argmax([0.99]), 0); + }); + }); + + // ── WakeWord string logic ───────────────────────────────────────────────── + + group('WakeWordDetector string helpers', () { + test('command is extracted after wake word', () { + expect( + _extractCommand('hey add milk to my list', 'hey'), + 'add milk to my list', + ); + }); + + test('empty transcript after wake word returns empty string', () { + expect(_extractCommand('hey', 'hey'), ''); + }); + + test('wake word is stripped case-insensitively when pre-lowercased', () { + final t = 'never add task'.toLowerCase(); + final w = 'never'.toLowerCase(); + expect(_extractCommand(t, w), 'add task'); + }); + + test('only first occurrence of wake word is stripped', () { + expect(_extractCommand('hey hey do this', 'hey'), 'hey do this'); + }); + + test('extra whitespace after wake word is trimmed', () { + expect(_extractCommand('hey buy milk', 'hey'), 'buy milk'); + }); + + test('wake word at end of transcript leaves empty command', () { + expect(_extractCommand('say hey', 'hey'), 'say'); + }); + }); + + // ── AiState enum names ──────────────────────────────────────────────────── + + group('AiState enum', () { + const expectedNames = { + 'initialising', + 'ready', + 'listening', + 'awake', + 'processing', + 'reloading', + 'disposed', + 'permissionDenied', + }; + + test('all expected AiState value names are defined', () { + // When AiState is exported from your library, replace with: + // final names = AiState.values.map((s) => s.name).toSet(); + // expect(names, containsAll(expectedNames)); + expect(expectedNames.contains('ready'), isTrue); + expect(expectedNames.contains('listening'), isTrue); + expect(expectedNames.contains('awake'), isTrue); + expect(expectedNames.contains('processing'), isTrue); + expect(expectedNames.contains('permissionDenied'), isTrue); + expect(expectedNames.contains('disposed'), isTrue); + }); + + test('no unexpected state names are present', () { + expect(expectedNames.length, 8); + }); + }); + + // ── ActionDispatcher fallback ───────────────────────────────────────────── + + group('ActionDispatcher fallback response', () { + // Mirrors the fallback string in action_dispatcher.dart. + const fallback = "I'm not sure how to help with that yet."; + + test('fallback message is non-empty', () { + expect(fallback.trim(), isNotEmpty); + }); + + test('fallback message matches expected string', () { + expect(fallback, "I'm not sure how to help with that yet."); + }); + }); +} diff --git a/test/util/byte_conversion_utils_test.dart b/test/util/byte_conversion_utils_test.dart index b15f32f..45e4dea 100644 --- a/test/util/byte_conversion_utils_test.dart +++ b/test/util/byte_conversion_utils_test.dart @@ -1,23 +1,21 @@ +import 'dart:typed_data'; + import 'package:flutter_test/flutter_test.dart'; -import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_core/tflite_core.dart'; void main() { group('convertObjectToBytes and convertBytesToObject', () { test('TensorType.float32', () async { - var bytes = - ByteConversionUtils.convertObjectToBytes(1.1, TensorType.float32); + var bytes = ByteConversionUtils.convertObjectToBytes(1.1, TensorType.float32); expect(bytes, [205, 204, 140, 63]); - var object = ByteConversionUtils.convertBytesToObject( - bytes, TensorType.float32, [1]) as List; + var object = ByteConversionUtils.convertBytesToObject(bytes, TensorType.float32, [1]) as List; expect(object[0], closeTo(1.1, 0.0001)); }); test('TensorType.float16', () async { - var bytes = - ByteConversionUtils.convertObjectToBytes(1.1, TensorType.float16); + var bytes = ByteConversionUtils.convertObjectToBytes(1.1, TensorType.float16); expect(bytes, [102, 60]); - var object = ByteConversionUtils.convertBytesToObject( - bytes, TensorType.float16, [1]) as List; + var object = ByteConversionUtils.convertBytesToObject(bytes, TensorType.float16, [1]) as List; expect(object[0], closeTo(1.1, 0.001)); /* @@ -46,72 +44,62 @@ void main() { ]; for (int i = 0; i < values.length; i++) { - var bytes = ByteConversionUtils.convertObjectToBytes( - values[i], TensorType.float16); + var bytes = ByteConversionUtils.convertObjectToBytes(values[i], TensorType.float16); expect(bytes, bytesList[i]); - var object = ByteConversionUtils.convertBytesToObject( - bytes, TensorType.float16, [1]) as List; + var object = + ByteConversionUtils.convertBytesToObject(bytes, TensorType.float16, [1]) as List; expect(object[0], closeTo(values[i], 0.001)); } }); + test('bytesToFloat32 decodes little-endian float16 bytes', () { + expect(ByteConversionUtils.bytesToFloat32(Uint8List.fromList([0, 62])), 1.5); + }); + test('TensorType.int64', () async { var bytes = ByteConversionUtils.convertObjectToBytes(1, TensorType.int64); expect(bytes, [0, 0, 0, 0, 0, 0, 0, 1]); - var object = - ByteConversionUtils.convertBytesToObject(bytes, TensorType.int64, [1]) - as List; + var object = ByteConversionUtils.convertBytesToObject(bytes, TensorType.int64, [1]) as List; expect(object[0], 1); }); test('TensorType.int32', () async { var bytes = ByteConversionUtils.convertObjectToBytes(1, TensorType.int32); expect(bytes, [1, 0, 0, 0]); - var object = - ByteConversionUtils.convertBytesToObject(bytes, TensorType.int32, [1]) - as List; + var object = ByteConversionUtils.convertBytesToObject(bytes, TensorType.int32, [1]) as List; expect(object[0], 1); }); test('TensorType.int16', () async { var bytes = ByteConversionUtils.convertObjectToBytes(1, TensorType.int16); expect(bytes, [1, 0]); - var object = - ByteConversionUtils.convertBytesToObject(bytes, TensorType.int16, [1]) - as List; + var object = ByteConversionUtils.convertBytesToObject(bytes, TensorType.int16, [1]) as List; expect(object[0], 1); }); test('TensorType.int8', () async { var bytes = ByteConversionUtils.convertObjectToBytes(1, TensorType.int8); expect(bytes, [1]); - var object = - ByteConversionUtils.convertBytesToObject(bytes, TensorType.int8, [1]) - as List; + var object = ByteConversionUtils.convertBytesToObject(bytes, TensorType.int8, [1]) as List; expect(object[0], 1); }); test('TensorType.uint8', () async { var bytes = ByteConversionUtils.convertObjectToBytes(1, TensorType.uint8); expect(bytes, [1]); - var object = - ByteConversionUtils.convertBytesToObject(bytes, TensorType.uint8, [1]) - as List; + var object = ByteConversionUtils.convertBytesToObject(bytes, TensorType.uint8, [1]) as List; expect(object[0], 1); }); }); group('errors', () { test('float to int8', () async { - expect( - () => ByteConversionUtils.convertObjectToBytes(1.1, TensorType.int8), + expect(() => ByteConversionUtils.convertObjectToBytes(1.1, TensorType.int8), throwsA(isA())); }); test('float to None', () async { - expect( - () => - ByteConversionUtils.convertObjectToBytes(1.1, TensorType.noType), + expect(() => ByteConversionUtils.convertObjectToBytes(1.1, TensorType.noType), throwsA(isA())); }); });