Commit 5a8dae4
authored
[Relax][Frontend][TFLite] Support static hashtable find (#19879)
## Summary
This PR extends the TFLite resource hashtable family from #19519 item G
from
"import + size" to a constant-foldable `HASHTABLE_FIND` subset. It
builds on the
static `HASHTABLE` / `HASHTABLE_IMPORT` import support added in #19639
and the
`HASHTABLE_LOOKUP` converter from #19654.
Relax has no string tensor type and no runtime hashtable operator, so
this PR
targets the only subset that can be lowered today: tables whose keys and
values
are constants imported in a `CALL_ONCE` init subgraph, queried by a
constant
string tensor. In that case the lookup is resolved at import time and
emitted as
a `relax.const`. Runtime string queries remain explicitly guarded
instead of
being lowered with incorrect semantics.
## Design
### Static String Tensor Decoding
The frontend now decodes constant TFLite string tensors through a shared
helper
`_get_string_tensor_value`. It parses the TFLite string-tensor binary
layout:
```text
[count(i32)][offset_0 .. offset_count(i32)][utf8 string data]
```
The helper validates the buffer length against the declared count,
checks that
offsets are in-bounds and monotonically non-decreasing, and verifies the
decoded
element count matches the tensor shape. This is reusable infrastructure
for any
future TFLite string support, independent of `HASHTABLE_FIND`.
### Hashtable Import State
`HASHTABLE_IMPORT` now stores the actual constant keys and values
(numeric or
decoded string buffers) in shared conversion state, instead of only
recording
table metadata (size, key/value dtype). Duplicate keys are rejected,
because the
constant-fold lookup assumes a unique key mapping. The captured table is
keyed by
the same `table_id` / handle resolution used by `HASHTABLE` and
`HASHTABLE_SIZE`,
so a `CALL_ONCE` init subgraph and the main graph agree on the same
logical
table.
### Constant-Foldable Find
`HASHTABLE_FIND` resolves the table handle through the importer-local
handle map
and the statically imported keys/values. For the supported subset it
builds a
Python key -> value map, applies the per-element default value,
overwrites hits
from the table, preserves the query tensor shape, and emits the result
as a
`relax.const`. The op produces no runtime Relax computation, which
matches the
fact that both the table and the query are compile-time constants.
The supported subset is intentionally narrow and guard-first:
- the table must be a constant `string -> int64` table imported via a
supported
`CALL_ONCE` `HASHTABLE_IMPORT`
- the query tensor must be a constant string buffer
- the default tensor must be a scalar or match the query shape
### String Graph Input Guard
`TensorType.STRING` graph inputs are now rejected in `from_tflite` with
a clear
`OpNotImplemented` instead of a low-level FFI `unknown dtype string`
error, since
Relax cannot represent a string tensor. This is the path hit by runtime
string
queries for `HASHTABLE_FIND` and string-valued `HASHTABLE_LOOKUP`, so
the guard
gives a frontend-level diagnostic for both.
## Operator Support
| Operator | TFLite options | Relax lowering | Supported subset |
|---|---|---|---|
| `HASHTABLE_IMPORT` | `HashtableImportOptions` | store constant
keys/values in importer state | `CALL_ONCE` init, constant keys/values,
no duplicate keys |
| `HASHTABLE_FIND` | `HashtableFindOptions` | constant-fold to
`relax.const` | constant `string -> int64` table + constant string query
|
## Not Included
- Runtime (non-constant) string queries and runtime hashtable lookup.
- `int64 -> string` find, which would require string-typed Relax
outputs.
- Any general `TensorType.STRING` tensor representation in Relax.
- A runtime Relax hashtable operator with string hashing / comparison.
- Mutable runtime resource-state threading through Relax functions.
These require core Relax support and are out of scope for the frontend.
## Tests
The tests manually build minimal TFLite flatbuffers and compare the
imported
Relax IR with `tvm.ir.assert_structural_equal`. Unsupported patterns use
`pytest.raises`.
| Test | Coverage |
|---|---|
| `test_hashtable_call_once_import_find_string_to_int64` | constant
`string -> int64` find folds to a `relax.const` |
| `test_hashtable_call_once_import_find_string_to_int64_2d_query` |
query shape preserved for a 2-D query |
| `test_hashtable_call_once_import_find_int64_to_string_unsupported` |
`int64 -> string` table rejected |
| `test_hashtable_call_once_import_find_runtime_query_unsupported` |
runtime string query rejected |
| `test_hashtable_call_once_import_duplicate_keys_unsupported` |
duplicate static keys rejected |
| `test_hashtable_lookup_string_value_unsupported` | string graph input
now gives a clean `OpNotImplemented` |
Local validation:
```bash
python -m ruff format --check \
python/tvm/relax/frontend/tflite/tflite_frontend.py \
tests/python/relax/test_frontend_tflite.py
python -m ruff check \
python/tvm/relax/frontend/tflite/tflite_frontend.py \
tests/python/relax/test_frontend_tflite.py
python -m pytest \
tests/python/relax/test_frontend_tflite.py \
-k "hashtable or resource or variable" -q
python -m pytest \
tests/python/relax/test_frontend_tflite.py -q
```
Result:
```text
ruff format --check: 2 files already formatted
ruff check: All checks passed
14 passed, 535 deselected
549 passed
```
## References
- Issue #19519 item G: TFLite resource / variable / hashtable operators
- PR #19639: TFLite resource variable and static hashtable import
support
- PR #19654: TFLite `HASHTABLE_LOOKUP` converter1 parent 730459c commit 5a8dae4
2 files changed
Lines changed: 342 additions & 22 deletions
File tree
- python/tvm/relax/frontend/tflite
- tests/python/relax
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
721 | 721 | | |
722 | 722 | | |
723 | 723 | | |
| 724 | + | |
| 725 | + | |
| 726 | + | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
| 741 | + | |
| 742 | + | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
| 746 | + | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
724 | 763 | | |
725 | 764 | | |
726 | 765 | | |
| |||
769 | 808 | | |
770 | 809 | | |
771 | 810 | | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
772 | 825 | | |
773 | 826 | | |
774 | 827 | | |
775 | 828 | | |
776 | 829 | | |
777 | 830 | | |
778 | 831 | | |
| 832 | + | |
| 833 | + | |
779 | 834 | | |
780 | 835 | | |
781 | 836 | | |
782 | 837 | | |
783 | | - | |
784 | | - | |
785 | | - | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
| 865 | + | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
| 876 | + | |
| 877 | + | |
| 878 | + | |
| 879 | + | |
| 880 | + | |
| 881 | + | |
| 882 | + | |
| 883 | + | |
| 884 | + | |
| 885 | + | |
| 886 | + | |
| 887 | + | |
| 888 | + | |
| 889 | + | |
| 890 | + | |
| 891 | + | |
| 892 | + | |
| 893 | + | |
| 894 | + | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
| 898 | + | |
| 899 | + | |
| 900 | + | |
| 901 | + | |
786 | 902 | | |
| 903 | + | |
| 904 | + | |
| 905 | + | |
| 906 | + | |
787 | 907 | | |
788 | 908 | | |
789 | 909 | | |
| |||
8834 | 8954 | | |
8835 | 8955 | | |
8836 | 8956 | | |
| 8957 | + | |
| 8958 | + | |
| 8959 | + | |
| 8960 | + | |
| 8961 | + | |
| 8962 | + | |
| 8963 | + | |
| 8964 | + | |
| 8965 | + | |
8837 | 8966 | | |
8838 | 8967 | | |
8839 | 8968 | | |
| |||
0 commit comments