This is an automated email from the ASF dual-hosted git repository.
tlopex pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/main by this push:
new a9ce41e5a2 [Relax][Frontend][TFLite] Add explicit operator marker
handling (#19824)
a9ce41e5a2 is described below
commit a9ce41e5a26c26a72fa2dfcc7788acf24f66ffa3
Author: Hongyi Wu <[email protected]>
AuthorDate: Mon Jun 22 10:44:42 2026 +0800
[Relax][Frontend][TFLite] Add explicit operator marker handling (#19824)
## Summary
This PR adds explicit Relax TFLite frontend handling for the TFLite
builtin
operator markers from #19519 item H:
- `DELEGATE`
- `PLACEHOLDER_FOR_GREATER_OP_CODES`
These builtins are TFLite marker / pseudo operators rather than ordinary
tensor
operators. The frontend now recognizes them and raises a targeted
`OpNotImplemented` diagnostic instead of falling through to a generic
unsupported-operator path.
## Design
`DELEGATE` marks delegated TFLite subgraphs, and
`PLACEHOLDER_FOR_GREATER_OP_CODES` is a schema compatibility
placeholder. They
do not have Relax tensor semantics to lower. This PR therefore keeps the
importer conservative:
- both builtin names are added to the TFLite `convert_map`
- both route to a shared `convert_operator_marker` guard
- the guard reports that the marker is not a Relax tensor operator
This makes the unsupported status intentional and discoverable without
mapping
the markers to synthetic Relax ops.
## Tests
The tests manually build minimal TFLite flatbuffers containing each
marker
builtin and assert that import raises the targeted `OpNotImplemented`.
Local validation:
```bash
python -m ruff format \
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 operator_marker_unsupported -q
```
Result:
```text
ruff format: 2 files left unchanged
ruff check: All checks passed
operator_marker_unsupported tests: 2 passed, 535 deselected
```
## References
- Issue #19519 item H: TFLite operator markers
---
.../tvm/relax/frontend/tflite/tflite_frontend.py | 10 +++++++++
tests/python/relax/test_frontend_tflite.py | 26 ++++++++++++++++++++++
2 files changed, 36 insertions(+)
diff --git a/python/tvm/relax/frontend/tflite/tflite_frontend.py
b/python/tvm/relax/frontend/tflite/tflite_frontend.py
index a087ce5d36..44e9773973 100644
--- a/python/tvm/relax/frontend/tflite/tflite_frontend.py
+++ b/python/tvm/relax/frontend/tflite/tflite_frontend.py
@@ -221,6 +221,7 @@ class OperatorConverter:
"DENSIFY": self.convert_densify,
"DEPTH_TO_SPACE": self.convert_depth_to_space,
"DEPTHWISE_CONV_2D": functools.partial(self.convert_conv,
conv_type="depthwise"),
+ "DELEGATE": functools.partial(self.convert_operator_marker,
op_name="DELEGATE"),
"DEQUANTIZE": self.convert_dequantize,
"DETECTION_POSTPROCESS": self.convert_detection_postprocess,
"DILATE": self.convert_dilate,
@@ -292,6 +293,9 @@ class OperatorConverter:
"PACK": self.convert_pack,
"PAD": self.convert_pad,
"PADV2": self.convert_pad,
+ "PLACEHOLDER_FOR_GREATER_OP_CODES": functools.partial(
+ self.convert_operator_marker,
op_name="PLACEHOLDER_FOR_GREATER_OP_CODES"
+ ),
"POW": functools.partial(self._convert_elemwise,
relax_op=_op.power),
"PRELU": self.convert_prelu,
"RANGE": self.convert_range,
@@ -492,6 +496,12 @@ class OperatorConverter:
if len(raise_msg) > 0:
raise tvm.error.OpNotImplemented(raise_msg)
+ def convert_operator_marker(self, op, op_name):
+ """Reject TFLite marker builtins with an explicit diagnostic."""
+ raise tvm.error.OpNotImplemented(
+ f"TFLite operator marker {op_name} is not a Relax tensor operator"
+ )
+
def unbind(self, data, axis=1):
"""
This is a modified version compared to the one in common.py.
diff --git a/tests/python/relax/test_frontend_tflite.py
b/tests/python/relax/test_frontend_tflite.py
index de53735a76..590cc4ac45 100644
--- a/tests/python/relax/test_frontend_tflite.py
+++ b/tests/python/relax/test_frontend_tflite.py
@@ -4384,6 +4384,32 @@ def _get_builtin_operator(builtin_name):
return getattr(_tfl_builtin_operator, builtin_name)
+def _build_tflite_operator_marker_model(builtin_name):
+ """Build a minimal model containing a TFLite marker builtin."""
+ builder = flatbuffers.Builder(1024)
+ builtin_op = _get_builtin_operator(builtin_name)
+ op_code = _build_operator_code(builder, builtin_op)
+ tensors = [
+ _build_tensor(builder, 0, [1], tensor_type=_tfl_tensor_type.FLOAT32),
+ _build_tensor(builder, 0, [1], tensor_type=_tfl_tensor_type.FLOAT32),
+ ]
+ op = _build_operator(builder, 0, [0], [1])
+ subgraph = _build_subgraph(builder, tensors=tensors, operators=[op],
inputs=[0], outputs=[1])
+ return _finish_tflite_model(
+ builder,
+ subgraph=subgraph,
+ operator_codes=[op_code],
+ buffers=[_build_buffer(builder)],
+ )
+
+
[email protected]("builtin_name", ["DELEGATE",
"PLACEHOLDER_FOR_GREATER_OP_CODES"])
+def test_operator_marker_unsupported(builtin_name):
+ """TFLite marker builtins report explicit unsupported diagnostics."""
+ with pytest.raises(tvm.error.OpNotImplemented, match=f"TFLite operator
marker {builtin_name}"):
+
_load_model_from_buffer(_build_tflite_operator_marker_model(builtin_name))
+
+
def _run_module(mod, *inputs):
tgt = tvm.target.Target("c")
ex = tvm.compile(mod, tgt)