recipe: tflite-runtime 2.21.0#105
Open
ndonkoHenri wants to merge 11 commits into
Open
Conversation
No sdist has ever existed (upstream wheels come from
tensorflow/lite/tools/pip_package/build_pip_package_with_cmake.sh, whose
cmake dispatch has no android case; python-for-android patches one in on
a TF 2.8 pin). Build from the TF v2.21.0 tag - the legacy CMake pip path
is still intact there and tf.lite has not yet moved out to LiteRT.
mobile.patch ADDS three files (TF root ships neither pyproject.toml nor
setup.py, nothing replaced): a PEP 517 shim (host-flatc build + cross
cmake of tensorflow/lite building ONLY the pybind wrapper target +
upstream's exact 5-file tflite_runtime/ staging) and an adapted
setup_with_binary.py. The wrapper has no FindPython: Python/numpy/pybind11
headers ride -I injections ({platlib} paths, no target-numpy imports);
libpython is linked explicitly (Android wants the DT_NEEDED; upstream
relies on manylinux lazy resolution).
Three fights, all captured in the patch/shim comments:
- TENSORFLOW_SOURCE_DIR must be pinned to the unpacked root: unset, the
lite build git-clones ITS OWN TensorFlow at v2.19.0 and compiles this
tree's sources against those stale headers (first slice died on a
header that only exists in 2.21).
- TF's Bazel `BUILD` file collides with setuptools' `build/` dir on
case-insensitive filesystems (macOS local builds) -> build_base moved.
- XNNPACK cannot be turned off for the python wheel on ANY ABI:
interpreter_wrapper.cc references TfLiteXNNPackDelegate* at link time.
Upstream's own 32-bit-arm OFF convention only works for the C++ lib;
XNNPACK-on-v7a builds fine with NDK r27 (p4a shipped it at TF 2.8).
Host flatc: standalone build of the exact flatbuffers tag TF pins
(parsed from tools/cmake/modules/flatbuffers.cmake), cached in the temp
dir per tag - host-arch tool, safe to share across ABI slices, and much
cheaper than upstream's second full lite configure.
Local matrix 3/3 (arm64-v8a, x86_64 - the p4a-era x86_64 failure does
not reproduce on 2.21 - and armeabi-v7a). Wheels 1.9-2.8MB, upstream's
exact package layout, 16KB-aligned, minimal DT_NEEDED. On-device arm64
emulator: 4/4 PASSED incl. REAL inference through XNNPACK on a 1KB
committed dense+relu model (desktop-recorded expectations matched
exactly; tests/requirements.txt pulls numpy - the wheel's one runtime
dep). tf.lite.Interpreter deprecation warning is upstream cosmetics;
ai-edge-litert (the successor) is Bazel-only and stays infeasible.
…solution logic and add platform-specific linker flag adjustments.
…atform parity
Same playbook as the onnxruntime-iOS extension: jinja lane split in
FORGE_CMAKE_ARGS (apple toolchain args) and per-slice apple keying in the
shim (sysroot+arch), plus three iOS-specific pieces:
- FORGE_SHARED_LINKER_FLAGS = -Wl,-undefined,dynamic_lookup: the wrapper
target has no FindPython to link libpython, and apple's two-level
namespace fails the link on undefined python symbols (android keeps
its explicit libpython + 16KB flags).
- -DFLATBUFFERS_BUILD_FLATC=OFF / -DFLATBUFFERS_INSTALL=OFF on iOS: the
FetchContent'd flatbuffers installs a TARGET flatc, which iOS's forced
MACOSX_BUNDLE mode rejects ("no BUNDLE DESTINATION") - and codegen
uses the cached HOST flatc anyway.
- The SHARED wrapper builds as .dylib on apple; the shim stages it under
the .so extension name (a dylib is loadable as a python ext - the
lightgbm precedent).
XNNPACK cross-compiles to iOS cleanly (default ON, all slices). All 3
iOS slices green; on-simulator 4/4 incl. REAL XNNPACK inference matching
desktop expectations to 1e-6. Tests: version-assert test removed per the
repo test conventions. meta reorganized by user; android lane unchanged
and re-verified by content (NDK marker + host entries per lane).
Flet 0.86's serious_python (4.3.0) only relocates ABI-tagged (cpython-*/abi3) extension modules out of sitepackages.zip into an importable jniLibs/.soref slot on Android; a plain '<name>.so' is misfiled as a dependency lib and fails on-device with 'cannot import name _pywrap_tensorflow_interpreter_wrapper' (build green, iOS fine). Stage the wrapper as _pywrap_tensorflow_interpreter_wrapper<EXT_SUFFIX> (e.g. .cpython-312.so) instead of a plain .so -- a valid CPython extension suffix, so the import still resolves. Verified: the rebuilt arm64 wheel now ships _pywrap_tensorflow_interpreter_wrapper.cpython-312.so.
Flet 0.86's serious_python (4.3.0) only relocates ABI-tagged (cpython-*/abi3) extension modules out of sitepackages.zip into an importable jniLibs/.soref slot on Android; a plain '<name>.so' is misfiled as a dependency lib and fails on-device with 'cannot import name onnxruntime_pybind11_state' (build green, iOS fine). Two changes: (1) the PEP 517 shim retags the built onnxruntime_pybind11_state.so to the target EXT_SUFFIX (e.g. .cpython-312.so) after staging; (2) setup.py builds package_data by globbing the hardcoded plain 'libs' names, so the retagged file would be dropped -- wildcard the pybind name and package the real basename. Verified: forge-rebuilt arm64 wheel ships onnxruntime/capi/onnxruntime_pybind11_state.cpython-312.so (present, 22MB).
serious_python 4.3.0 only relocates ABI-tagged (cpython-*/abi3) extension modules into an importable jniLibs/.soref slot on Android; a plain '<name>.so' bundled inside a package is misfiled as a dependency lib and fails on-device with 'cannot import name'. Add a forge-error-catalogue entry (error -> cause -> EXT_SUFFIX fix, incl. the setup.py-glob gotcha) and a new-mobile-recipe PEP 517-shim bullet (always stage extensions with EXT_SUFFIX). Precedents: machine/tflite-runtime, machine/onnxruntime-ext-suffix.
The EXT_SUFFIX retag + onnxruntime's copytree(dirs_exist_ok, which never deletes) + forge reusing the source tree across slices meant a prior slice's tagged .so lingered in onnxruntime/capi/. On iOS the per-slice suffixes differ (.cpython-312-iphoneos.so vs -iphonesimulator.so), so the wheel shipped BOTH and serious_python's .so->framework conversion failed on-device (dlopen: onnxruntime.capi.onnxruntime_pybind11_state.framework not found). Delete every onnxruntime_pybind11_state*.so that isn't the current slice's target after retagging. (Android is unaffected -- all its ABIs share .cpython-312.so; tflite is unaffected -- its shim rmtrees the package dir each hook.)
A recipe with excluded_arches (onnxruntime drops armeabi-v7a) has no wheel for the excluded ABI, but the recipe-tester's 'flet build apk' defaults to all 3 Android ABIs -> pip 'No matching distribution for <pkg>' on the excluded ABI, breaking the app build. stage_recipe.sh now derives [tool.flet.android] target_arch from the wheels actually present in dist-test/dist and writes it into the generated pyproject; recipes with all ABIs (or pure-Python, no per-ABI wheel) stay unrestricted.
- new-mobile-recipe PEP517 bullet: forge reuses the source tree across slices, so a shim that overlays (not wipes) must delete stale per-slice .so -- iOS suffixes differ (iphoneos vs iphonesimulator) and both would ship, breaking framework conversion. - forge-error-catalogue: 'No matching distribution for <pkg>' at APK build when a recipe has excluded_arches; stage_recipe.sh now auto-derives target_arch, and the mandatory target_arch note for Consumer notes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a
tflite-runtimerecipe — LiteRT /.tflitemodel inference on both Android and iOS.Closes flet-dev/flet#5135 and flet-dev/flet#3810 (and relevant to flet-dev/flet#4901).
Shape
tflite-runtime has never had an sdist — upstream wheels come from
tensorflow/lite/tools/pip_package/build_pip_package_with_cmake.sh, a host==target script. So this uses the PEP 517 shim archetype (same as onnxruntime): the source is the TensorFlow v2.21.0 release tree, andmobile.patchadds apyproject.toml+_forge/forge_tflite_backend.pythat builds a standalone hostflatc, cross-compilestensorflow/litedown to just the_pywrap_tensorflow_interpreter_wrapperpybind module, then stages upstream's exact 5-filetflite_runtime/package. Wheels are 1.9–2.8 MB.2.21 is the last buildable line — the
ai-edge-litertsuccessor is a Bazel wall (no CMake path), so pinning here is deliberate. Both historical p4a patches (-llog,minimal_loggingdedup) are already fixed upstream in 2.21.Notable cross-compile details (each documented in the recipe/patch):
-DTENSORFLOW_SOURCE_DIRpinned to the unpacked root — unset,lite/'s CMake git-clones its own TF at v2.19.0 and compiles 2.21 sources against 2.19 headers.TfLiteXNNPackDelegate*unconditionally); stays ON except 32-bit arm, following upstream's own pip convention.-Wl,-undefined,dynamic_lookup(Android links libpython explicitly instead); FetchContent'd flatbuffers'flatcinstall rejected by iOS's forced MACOSX_BUNDLE →-DFLATBUFFERS_BUILD_FLATC=OFF -DFLATBUFFERS_INSTALL=OFF(host flatc does codegen); apple SHARED wrapper is a.dylib→ staged under the.soname.Testing
tests/test_tflite_runtime.pyruns a committed 1 KBdense_relu.tflite(generated and validated with desktop TF 2.21, fixed weights + seed 42) through a realInterpreter.invoke()— the CI emulator/simulator runs actual XNNPACK inference and asserts desktop-recorded outputs to 1e-6, plus a re-set/second-invoke test. Test logic was pre-validated on desktop TF via atflite_runtime.interpreter→tf.litemodule alias, which caught a real numeric bug before any device.Follow-ups (not in this PR)
Delegates beyond XNNPACK (GPU / NNAPI / Core ML) if there's demand — the default XNNPACK-accelerated CPU path is the portable baseline.
Consumer notes (usage & recommendations)
tflite-runtimeruns.tflitemodels through the XNNPACK-accelerated CPU path — the portable, dependable baseline that works identically on Android and iOS. Everything runs offline; the only network you need is a one-time model download (or bundle the model — see below). The pinned version is 2.21.0, the last buildable release — itsai-edge-litertsuccessor can't be cross-compiled, so stay on this package name.Install
Add it to your deps (the pip name has a hyphen, the import has an underscore):
All Android ABIs are covered (
arm64-v8a,armeabi-v7a,x86_64) — though on old 32-bitarmeabi-v7athe XNNPACK accelerator is off, so prefer arm64 devices.Storage & the model file
.tflitemodels are usually small, so you have two options:assets/directory) and load from the bundle — simplest.FLET_APP_STORAGE_DATA) and load from there:Minimal usage
Run it off the UI thread
allocate_tensors()andinvoke()are CPU-bound — run them inpage.run_thread(...)so the UI stays responsive.Notes for good results on mobile
uint8/int8, not float — use theinp["quantization"](scale, zero-point) to convert. They're smaller and faster, ideal for mobile.interpreter.resize_tensor_input(inp["index"], new_shape)thenallocate_tensors()again before setting the tensor.ai_edge_litert; ignore it (that successor isn't buildable for mobile, which is why we pin this package).