Skip to content

[Relax][Frontend][TFLite] Add missing TFLite operator mappings#19813

Merged
tlopex merged 2 commits into
apache:mainfrom
Aharrypotter:codex/tflite-operator-gap-closure
Jun 18, 2026
Merged

[Relax][Frontend][TFLite] Add missing TFLite operator mappings#19813
tlopex merged 2 commits into
apache:mainfrom
Aharrypotter:codex/tflite-operator-gap-closure

Conversation

@Aharrypotter

@Aharrypotter Aharrypotter commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds Relax TFLite frontend coverage for a batch of builtin operators tracked in
#19412. All lowerings reuse existing Relax ops; the change is limited to the
TFLite frontend converter and its tests.

Changes

Grouped by the #19412 checklist section:

Section A — drop-in operator mappings

  • SIGN -> relax.op.sign
  • BITWISE_XOR -> relax.op.bitwise_xor
  • RIGHT_SHIFT -> relax.op.right_shift
  • RELU_0_TO_1 -> relax.op.clip
  • BUCKETIZE -> relax.op.bucketize
  • UNIQUE -> relax.op.unique (unique values + inverse indices)

Section B — compose with existing Relax ops

  • RANK -> scalar rank constant for statically-ranked inputs
  • UNSORTED_SEGMENT_SUM -> extends the existing scatter-based segment lowering
    (scatter_nd, reduction="add")
  • UNSORTED_SEGMENT_MAX -> same, reduction="max"

Section C — fix partial implementation

  • FAKE_QUANT: the handler called the non-existent relax.op.const and raised
    AttributeError on every invocation; switch to relax.const so the op works.
    (The builtin op carries only scalar min/max, so there is no per-channel/vector
    min/max path.)

Tests

Adds coverage in tests/python/relax/test_frontend_tflite.py for the new
mappings and the FAKE_QUANT narrow-range vector path. Most tests use
structural-equal Relax IR checks; data-dependent and numeric regression cases
add focused output checks for UNIQUE and FAKE_QUANT.

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 "unique or sign or bitwise_xor or right_shift or bucketize or relu_0_to_1 or rank or unsorted_segment_sum or unsorted_segment_max or fake_quant"
python -m pytest tests/python/relax/test_frontend_tflite.py

Result:

  • ruff format: 2 files left unchanged
  • ruff check: All checks passed
  • target pytest: 22 passed, 523 deselected
  • full TFLite pytest: 545 passed

References

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses several Relax TFLite frontend gaps by implementing mappings for operators such as SIGN, BITWISE_XOR, RIGHT_SHIFT, BUCKETIZE, RELU_0_TO_1, UNIQUE, RANK, UNSORTED_SEGMENT_SUM, and UNSORTED_SEGMENT_MAX, along with fixing FAKE_QUANT narrow-range vector conversion. Feedback suggests simplifying the RANK conversion by passing the Python integer directly to relax.const rather than wrapping it in a NumPy array, and using positional arguments instead of keyword arguments in relax.op.clip for consistency and compatibility.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

output_dtype = self.get_tensor_type_str(output_tensors[0].tensor.Type())

rank = len(self.get_tensor_shape(input_tensors[0]))
return relax.const(np.array(rank, dtype=output_dtype), dtype=output_dtype)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

We can simplify this by passing the Python integer rank directly to relax.const instead of wrapping it in a np.array. relax.const natively supports Python scalars with a specified dtype.

Suggested change
return relax.const(np.array(rank, dtype=output_dtype), dtype=output_dtype)
return relax.const(rank, dtype=output_dtype)

@Aharrypotter Aharrypotter Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed by returning relax.const(rank, dtype=output_dtype).

Comment on lines +1626 to +1631
if input_tensor.qnn_params:
in_f32 = self.dequantize(in_expr, input_tensor)
out = relax.op.clip(in_f32, min=0, max=1)
out = self.quantize(out, output_tensor)
else:
out = relax.op.clip(in_expr, min=0, max=1)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For consistency with other uses of relax.op.clip in this file (e.g., in convert_fake_quant), and to ensure compatibility with TVM's FFI wrappers, it is recommended to use positional arguments instead of keyword arguments (min and max).

Suggested change
if input_tensor.qnn_params:
in_f32 = self.dequantize(in_expr, input_tensor)
out = relax.op.clip(in_f32, min=0, max=1)
out = self.quantize(out, output_tensor)
else:
out = relax.op.clip(in_expr, min=0, max=1)
if input_tensor.qnn_params:
in_f32 = self.dequantize(in_expr, input_tensor)
out = relax.op.clip(in_f32, 0, 1)
out = self.quantize(out, output_tensor)
else:
out = relax.op.clip(in_expr, 0, 1)

@Aharrypotter Aharrypotter Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed by switching the new relax.op.clip calls to positional arguments.

@Aharrypotter Aharrypotter force-pushed the codex/tflite-operator-gap-closure branch from 5843680 to 864935f Compare June 17, 2026 09:49
@Aharrypotter Aharrypotter changed the title [Relax][Frontend][TFLite] Close remaining TFLite operator gaps [Relax][Frontend][TFLite] Add missing TFLite operator mappings Jun 17, 2026
@Aharrypotter Aharrypotter marked this pull request as ready for review June 17, 2026 10:41
@Aharrypotter Aharrypotter marked this pull request as draft June 17, 2026 10:47
@Aharrypotter Aharrypotter marked this pull request as ready for review June 17, 2026 11:01
@tlopex

tlopex commented Jun 17, 2026

Copy link
Copy Markdown
Member

Could you resolve the conflict so that we can merge it in?

@Aharrypotter Aharrypotter force-pushed the codex/tflite-operator-gap-closure branch from c786073 to 0ff302e Compare June 18, 2026 02:36
@Aharrypotter

Copy link
Copy Markdown
Contributor Author

Rebased the PR onto the latest main and resolved the branch conflict in the
TFLite converter map.

Also refreshed the PR description with the post-rebase validation results.

@Aharrypotter Aharrypotter requested a review from tlopex June 18, 2026 02:59
@tlopex tlopex merged commit 0bc3a6f into apache:main Jun 18, 2026
9 of 10 checks passed
@Aharrypotter

Aharrypotter commented Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

Updated the PR description for clearer scope: the changes are now grouped by the
#19412 checklist section — Section A (drop-in mappings: SIGN, BITWISE_XOR,
RIGHT_SHIFT, RELU_0_TO_1, BUCKETIZE, UNIQUE), Section B (RANK,
UNSORTED_SEGMENT_SUM/MAX), and Section C (the FAKE_QUANT crash fix:
relax.op.constrelax.const) —
with a link back to the tracking issue. No code change; this only makes it
clearer which tracked items this PR covers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants