gemini-code-assist[bot] commented on code in PR #19637:
URL: https://github.com/apache/tvm/pull/19637#discussion_r3318327998


##########
python/tvm/relax/frontend/tflite/tflite_frontend.py:
##########
@@ -3445,6 +3446,168 @@ def _convert_reduce(self, relax_op, op):
 
         return out
 
+    def convert_reduce_window(self, op):
+        """Convert TFLite REDUCE_WINDOW."""
+
+        from tflite.BuiltinOptions2 import BuiltinOptions2
+        from tflite.ReduceWindowFunction import ReduceWindowFunction
+        from tflite.ReduceWindowOptions import ReduceWindowOptions
+
+        input_tensors = self.get_input_tensors(op)
+        output_tensors = self.get_output_tensors(op)
+        if len(input_tensors) != 5:
+            raise tvm.error.OpAttributeUnImplemented(
+                "TFLite REDUCE_WINDOW requires 5 input tensors."
+            )
+        if len(output_tensors) != 1:
+            raise tvm.error.OpAttributeUnImplemented(
+                "TFLite REDUCE_WINDOW requires 1 output tensor."
+            )
+
+        if op.BuiltinOptions2Type() != BuiltinOptions2.ReduceWindowOptions:
+            raise tvm.error.OpAttributeUnImplemented(
+                "TFLite REDUCE_WINDOW requires ReduceWindowOptions."
+            )
+
+        (
+            input_tensor,
+            init_tensor,
+            window_shape_tensor,
+            window_strides_tensor,
+            window_dilations_tensor,
+        ) = input_tensors
+        output_tensor = output_tensors[0]
+
+        if any(
+            self.has_expr(tensor.tensor_idx)
+            for tensor in [window_shape_tensor, window_strides_tensor, 
window_dilations_tensor]
+        ):
+            raise tvm.error.OpNotImplemented(
+                "TFLite REDUCE_WINDOW requires constant window_shape, "
+                "window_strides, and window_dilations."
+            )
+
+        input_shape = to_int_list(self.get_tensor_shape(input_tensor))
+        output_shape = to_int_list(self.get_tensor_shape(output_tensor))
+        input_dtype = self.get_tensor_type_str(input_tensor.tensor.Type())
+        output_dtype = self.get_tensor_type_str(output_tensor.tensor.Type())
+
+        if input_tensor.qnn_params or output_tensor.qnn_params:
+            raise tvm.error.OpNotImplemented(
+                "Quantized TFLite REDUCE_WINDOW is not yet supported in the 
Relax frontend."
+            )
+
+        if input_dtype != output_dtype:
+            raise tvm.error.OpAttributeUnImplemented(
+                "TFLite REDUCE_WINDOW requires input and output dtypes to 
match."
+            )
+
+        if len(to_int_list(self.get_tensor_shape(init_tensor))) != 0:
+            raise tvm.error.OpNotImplemented(
+                "TFLite REDUCE_WINDOW only supports scalar init_value."
+            )
+
+        options = ReduceWindowOptions()
+        op_options = op.BuiltinOptions2()
+        options.Init(op_options.Bytes, op_options.Pos)
+        reduce_function = options.ReduceFunction()
+
+        if reduce_function == ReduceWindowFunction.UNSUPPORTED:
+            raise tvm.error.OpNotImplemented(
+                "TFLite REDUCE_WINDOW with UNSUPPORTED reduce_function is not 
supported."
+            )
+
+        window_shape = to_int_list(self.get_tensor_value(window_shape_tensor))
+        window_strides = 
to_int_list(self.get_tensor_value(window_strides_tensor))
+        window_dilations = 
to_int_list(self.get_tensor_value(window_dilations_tensor))
+        rank = len(input_shape)
+
+        if not (len(window_shape) == len(window_strides) == 
len(window_dilations) == rank):
+            raise tvm.error.OpAttributeUnImplemented(
+                "TFLite REDUCE_WINDOW window_shape, window_strides, and 
window_dilations "
+                "must match input rank."
+            )
+
+        if any(value <= 0 for value in window_shape + window_strides + 
window_dilations):
+            raise tvm.error.OpAttributeUnImplemented(
+                "TFLite REDUCE_WINDOW window dimensions, strides, and 
dilations must be positive."
+            )
+
+        dilated_window_shape = [
+            (window_dim - 1) * dilation + 1
+            for window_dim, dilation in zip(window_shape, window_dilations)
+        ]
+        expected_output_shape = [
+            0 if input_dim < dilated_dim else (input_dim - dilated_dim) // 
stride + 1
+            for input_dim, dilated_dim, stride in zip(
+                input_shape, dilated_window_shape, window_strides
+            )
+        ]
+
+        numeric_reduce_functions = {
+            ReduceWindowFunction.ADD: (relax.op.sum, relax.op.add),
+            ReduceWindowFunction.MUL: (relax.op.prod, relax.op.multiply),
+            ReduceWindowFunction.MINIMUM: (relax.op.min, relax.op.minimum),
+            ReduceWindowFunction.MAXIMUM: (relax.op.max, relax.op.maximum),
+        }
+        bool_reduce_functions = {
+            ReduceWindowFunction.ALL: (relax.op.min, relax.op.logical_and),
+            ReduceWindowFunction.ANY: (relax.op.max, relax.op.logical_or),
+        }
+
+        if reduce_function in numeric_reduce_functions and input_dtype == 
"bool":
+            raise tvm.error.OpAttributeUnImplemented(
+                "TFLite REDUCE_WINDOW numeric reductions expect numeric input."
+            )
+        if reduce_function in bool_reduce_functions and input_dtype != "bool":
+            raise tvm.error.OpAttributeUnImplemented(
+                "TFLite REDUCE_WINDOW boolean reductions expect bool input."
+            )
+
+        if output_shape != expected_output_shape:
+            raise tvm.error.OpAttributeUnImplemented(
+                "TFLite REDUCE_WINDOW output shape does not match input/window 
parameters."
+            )
+
+        if any(output_dim == 0 for output_dim in output_shape):
+            return relax.op.zeros(output_shape, output_dtype)
+
+        data = self.get_tensor_expr(input_tensor)
+        init_value = self.get_tensor_expr(init_tensor)
+
+        windowed = relax.op.call_dps_packed(
+            "topi.sliding_window",
+            (
+                data,
+                0,
+                relax.ShapeExpr(dilated_window_shape),
+                relax.ShapeExpr(window_strides),
+            ),
+            out_sinfo=relax.TensorStructInfo(output_shape + 
dilated_window_shape, input_dtype),
+        )

Review Comment:
   ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)
   
   The `topi.sliding_window` packed function expects 5 arguments: `data`, 
`pad_before`, `pad_after`, `window_shape`, and `strides`. The current call only 
passes 4 arguments, omitting `pad_after`. Additionally, `pad_before` is passed 
as `0` (an integer) instead of a shape expression of zeros of length `rank` 
(e.g., `relax.ShapeExpr([0] * rank)`). This will cause a runtime failure when 
executing the compiled model.
   
   ```suggestion
           windowed = relax.op.call_dps_packed(
               "topi.sliding_window",
               (
                   data,
                   relax.ShapeExpr([0] * rank),
                   relax.ShapeExpr([0] * rank),
                   relax.ShapeExpr(dilated_window_shape),
                   relax.ShapeExpr(window_strides),
               ),
               out_sinfo=relax.TensorStructInfo(output_shape + 
dilated_window_shape, input_dtype),
           )
   ```



##########
tests/python/relax/test_frontend_tflite.py:
##########
@@ -3951,6 +3953,376 @@ def _load_model_from_buffer(model_bytes):
     return mod
 
 
+def _build_reduce_window_options(builder, reduce_function):
+    _tfl_reduce_window_options.ReduceWindowOptionsStart(builder)
+    _tfl_reduce_window_options.ReduceWindowOptionsAddReduceFunction(builder, 
reduce_function)
+    return _tfl_reduce_window_options.ReduceWindowOptionsEnd(builder)
+
+
+def _reduce_window_output_shape(input_shape, window_shape, window_strides, 
window_dilations):
+    output_shape = []
+    for input_dim, window_dim, stride, dilation in zip(
+        input_shape, window_shape, window_strides, window_dilations
+    ):
+        dilated_window = (window_dim - 1) * dilation + 1
+        if stride <= 0:
+            output_shape.append(0)
+        elif input_dim < dilated_window:
+            output_shape.append(0)
+        else:
+            output_shape.append((input_dim - dilated_window) // stride + 1)
+    return tuple(output_shape)
+
+
+def _build_reduce_window_model(
+    *,
+    input_shape,
+    init_value,
+    window_shape,
+    window_strides,
+    window_dilations,
+    output_shape=None,
+    reduce_function,
+    tensor_type=None,
+    value_dtype=np.float32,
+):
+    builder = flatbuffers.Builder(1024)
+    if tensor_type is None:
+        tensor_type = _tfl_tensor_type.FLOAT32
+
+    input_tensor_idx = 0
+    init_tensor_idx = 1
+    window_shape_tensor_idx = 2
+    window_strides_tensor_idx = 3
+    window_dilations_tensor_idx = 4
+    output_tensor_idx = 5
+
+    if output_shape is None:
+        output_shape = _reduce_window_output_shape(
+            input_shape, window_shape, window_strides, window_dilations
+        )
+
+    input_tensor = _build_tensor(builder, 1, input_shape, 
tensor_type=tensor_type)
+    init_tensor = _build_tensor(builder, 2, [], tensor_type=tensor_type)
+    window_shape_tensor = _build_tensor(
+        builder, 3, [len(window_shape)], tensor_type=_tfl_tensor_type.INT64
+    )
+    window_strides_tensor = _build_tensor(
+        builder, 4, [len(window_strides)], tensor_type=_tfl_tensor_type.INT64
+    )
+    window_dilations_tensor = _build_tensor(
+        builder, 5, [len(window_dilations)], tensor_type=_tfl_tensor_type.INT64
+    )
+    output_tensor = _build_tensor(builder, 6, output_shape, 
tensor_type=tensor_type)
+
+    reduce_window_opts = _build_reduce_window_options(builder, reduce_function)
+    reduce_window_op = _build_operator(
+        builder,
+        0,
+        [
+            input_tensor_idx,
+            init_tensor_idx,
+            window_shape_tensor_idx,
+            window_strides_tensor_idx,
+            window_dilations_tensor_idx,
+        ],
+        [output_tensor_idx],
+        builtin_options2_type=_tfl_builtin_options2.ReduceWindowOptions,
+        builtin_options2=reduce_window_opts,
+    )
+
+    subgraph = _build_subgraph(
+        builder,
+        tensors=[
+            input_tensor,
+            init_tensor,
+            window_shape_tensor,
+            window_strides_tensor,
+            window_dilations_tensor,
+            output_tensor,
+        ],
+        operators=[reduce_window_op],
+        inputs=[input_tensor_idx],
+        outputs=[output_tensor_idx],
+    )
+    operator_codes = [_build_operator_code(builder, 
_tfl_builtin_operator.REDUCE_WINDOW)]
+
+    buffers = [
+        _build_buffer(builder),
+        _build_buffer(builder),
+        _build_buffer(builder, np.asarray([init_value], 
dtype=value_dtype).tobytes()),
+        _build_buffer(builder, np.asarray(window_shape, 
dtype=np.int64).tobytes()),
+        _build_buffer(builder, np.asarray(window_strides, 
dtype=np.int64).tobytes()),
+        _build_buffer(builder, np.asarray(window_dilations, 
dtype=np.int64).tobytes()),
+        _build_buffer(builder),
+    ]
+
+    return _finish_tflite_model(
+        builder, subgraph=subgraph, operator_codes=operator_codes, 
buffers=buffers
+    )
+
+
+def _from_reduce_window_model(**kwargs):
+    return _load_model_from_buffer(_build_reduce_window_model(**kwargs))
+
+
+def _reduce_window_dilated_shape(window_shape, window_dilations):
+    return [
+        (window_dim - 1) * dilation + 1
+        for window_dim, dilation in zip(window_shape, window_dilations)
+    ]
+
+
+def _make_reduce_window_numeric_expected(
+    *,
+    input_shape,
+    init_value,
+    window_shape,
+    window_strides,
+    window_dilations,
+    reduce_op,
+    combine_op,
+    dtype="float32",
+):
+    output_shape = _reduce_window_output_shape(
+        input_shape, window_shape, window_strides, window_dilations
+    )
+    dilated_window_shape = _reduce_window_dilated_shape(window_shape, 
window_dilations)
+    rank = len(input_shape)
+
+    bb = relax.BlockBuilder()
+    x = relax.Var("tvmgen_tensor_0", relax.TensorStructInfo(input_shape, 
dtype))
+    with bb.function("main", [x]):
+        with bb.dataflow():
+            windowed = bb.emit(
+                relax.op.call_dps_packed(
+                    "topi.sliding_window",
+                    (
+                        x,
+                        0,
+                        relax.ShapeExpr(dilated_window_shape),
+                        relax.ShapeExpr(window_strides),
+                    ),
+                    out_sinfo=relax.TensorStructInfo(
+                        output_shape + tuple(dilated_window_shape), dtype
+                    ),
+                )
+            )

Review Comment:
   ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)
   
   Update the expected `topi.sliding_window` call in the test helper to match 
the corrected 5-argument signature with explicit `pad_before` and `pad_after` 
shape expressions.
   
   ```python
               windowed = bb.emit(
                   relax.op.call_dps_packed(
                       "topi.sliding_window",
                       (
                           x,
                           relax.ShapeExpr([0] * rank),
                           relax.ShapeExpr([0] * rank),
                           relax.ShapeExpr(dilated_window_shape),
                           relax.ShapeExpr(window_strides),
                       ),
                       out_sinfo=relax.TensorStructInfo(
                           output_shape + tuple(dilated_window_shape), dtype
                       ),
                   )
               )
   ```



##########
tests/python/relax/test_frontend_tflite.py:
##########
@@ -3951,6 +3953,376 @@ def _load_model_from_buffer(model_bytes):
     return mod
 
 
+def _build_reduce_window_options(builder, reduce_function):
+    _tfl_reduce_window_options.ReduceWindowOptionsStart(builder)
+    _tfl_reduce_window_options.ReduceWindowOptionsAddReduceFunction(builder, 
reduce_function)
+    return _tfl_reduce_window_options.ReduceWindowOptionsEnd(builder)
+
+
+def _reduce_window_output_shape(input_shape, window_shape, window_strides, 
window_dilations):
+    output_shape = []
+    for input_dim, window_dim, stride, dilation in zip(
+        input_shape, window_shape, window_strides, window_dilations
+    ):
+        dilated_window = (window_dim - 1) * dilation + 1
+        if stride <= 0:
+            output_shape.append(0)
+        elif input_dim < dilated_window:
+            output_shape.append(0)
+        else:
+            output_shape.append((input_dim - dilated_window) // stride + 1)
+    return tuple(output_shape)
+
+
+def _build_reduce_window_model(
+    *,
+    input_shape,
+    init_value,
+    window_shape,
+    window_strides,
+    window_dilations,
+    output_shape=None,
+    reduce_function,
+    tensor_type=None,
+    value_dtype=np.float32,
+):
+    builder = flatbuffers.Builder(1024)
+    if tensor_type is None:
+        tensor_type = _tfl_tensor_type.FLOAT32
+
+    input_tensor_idx = 0
+    init_tensor_idx = 1
+    window_shape_tensor_idx = 2
+    window_strides_tensor_idx = 3
+    window_dilations_tensor_idx = 4
+    output_tensor_idx = 5
+
+    if output_shape is None:
+        output_shape = _reduce_window_output_shape(
+            input_shape, window_shape, window_strides, window_dilations
+        )
+
+    input_tensor = _build_tensor(builder, 1, input_shape, 
tensor_type=tensor_type)
+    init_tensor = _build_tensor(builder, 2, [], tensor_type=tensor_type)
+    window_shape_tensor = _build_tensor(
+        builder, 3, [len(window_shape)], tensor_type=_tfl_tensor_type.INT64
+    )
+    window_strides_tensor = _build_tensor(
+        builder, 4, [len(window_strides)], tensor_type=_tfl_tensor_type.INT64
+    )
+    window_dilations_tensor = _build_tensor(
+        builder, 5, [len(window_dilations)], tensor_type=_tfl_tensor_type.INT64
+    )
+    output_tensor = _build_tensor(builder, 6, output_shape, 
tensor_type=tensor_type)
+
+    reduce_window_opts = _build_reduce_window_options(builder, reduce_function)
+    reduce_window_op = _build_operator(
+        builder,
+        0,
+        [
+            input_tensor_idx,
+            init_tensor_idx,
+            window_shape_tensor_idx,
+            window_strides_tensor_idx,
+            window_dilations_tensor_idx,
+        ],
+        [output_tensor_idx],
+        builtin_options2_type=_tfl_builtin_options2.ReduceWindowOptions,
+        builtin_options2=reduce_window_opts,
+    )
+
+    subgraph = _build_subgraph(
+        builder,
+        tensors=[
+            input_tensor,
+            init_tensor,
+            window_shape_tensor,
+            window_strides_tensor,
+            window_dilations_tensor,
+            output_tensor,
+        ],
+        operators=[reduce_window_op],
+        inputs=[input_tensor_idx],
+        outputs=[output_tensor_idx],
+    )
+    operator_codes = [_build_operator_code(builder, 
_tfl_builtin_operator.REDUCE_WINDOW)]
+
+    buffers = [
+        _build_buffer(builder),
+        _build_buffer(builder),
+        _build_buffer(builder, np.asarray([init_value], 
dtype=value_dtype).tobytes()),
+        _build_buffer(builder, np.asarray(window_shape, 
dtype=np.int64).tobytes()),
+        _build_buffer(builder, np.asarray(window_strides, 
dtype=np.int64).tobytes()),
+        _build_buffer(builder, np.asarray(window_dilations, 
dtype=np.int64).tobytes()),
+        _build_buffer(builder),
+    ]
+
+    return _finish_tflite_model(
+        builder, subgraph=subgraph, operator_codes=operator_codes, 
buffers=buffers
+    )
+
+
+def _from_reduce_window_model(**kwargs):
+    return _load_model_from_buffer(_build_reduce_window_model(**kwargs))
+
+
+def _reduce_window_dilated_shape(window_shape, window_dilations):
+    return [
+        (window_dim - 1) * dilation + 1
+        for window_dim, dilation in zip(window_shape, window_dilations)
+    ]
+
+
+def _make_reduce_window_numeric_expected(
+    *,
+    input_shape,
+    init_value,
+    window_shape,
+    window_strides,
+    window_dilations,
+    reduce_op,
+    combine_op,
+    dtype="float32",
+):
+    output_shape = _reduce_window_output_shape(
+        input_shape, window_shape, window_strides, window_dilations
+    )
+    dilated_window_shape = _reduce_window_dilated_shape(window_shape, 
window_dilations)
+    rank = len(input_shape)
+
+    bb = relax.BlockBuilder()
+    x = relax.Var("tvmgen_tensor_0", relax.TensorStructInfo(input_shape, 
dtype))
+    with bb.function("main", [x]):
+        with bb.dataflow():
+            windowed = bb.emit(
+                relax.op.call_dps_packed(
+                    "topi.sliding_window",
+                    (
+                        x,
+                        0,
+                        relax.ShapeExpr(dilated_window_shape),
+                        relax.ShapeExpr(window_strides),
+                    ),
+                    out_sinfo=relax.TensorStructInfo(
+                        output_shape + tuple(dilated_window_shape), dtype
+                    ),
+                )
+            )
+            if any(dilation != 1 for dilation in window_dilations):
+                windowed = bb.emit(
+                    relax.op.strided_slice(
+                        windowed,
+                        axes=list(range(rank, 2 * rank)),
+                        begin=[0] * rank,
+                        end=dilated_window_shape,
+                        strides=window_dilations,
+                    )
+                )
+            reduced = bb.emit(reduce_op(windowed, axis=list(range(rank, 2 * 
rank))))
+            gv = bb.emit_output(combine_op(reduced, relax.const(init_value, 
dtype)))
+        bb.emit_func_output(gv)
+
+    mod = bb.get()
+    mod["main"] = mod["main"].with_attr("num_input", 1)
+    return mod
+
+
+def _make_reduce_window_bool_expected(
+    *,
+    input_shape,
+    init_value,
+    window_shape,
+    window_strides,
+    window_dilations,
+    reduce_op,
+    combine_op,
+):
+    output_shape = _reduce_window_output_shape(
+        input_shape, window_shape, window_strides, window_dilations
+    )
+    dilated_window_shape = _reduce_window_dilated_shape(window_shape, 
window_dilations)
+    rank = len(input_shape)
+
+    bb = relax.BlockBuilder()
+    x = relax.Var("tvmgen_tensor_0", relax.TensorStructInfo(input_shape, 
"bool"))
+    with bb.function("main", [x]):
+        with bb.dataflow():
+            windowed = bb.emit(
+                relax.op.call_dps_packed(
+                    "topi.sliding_window",
+                    (
+                        x,
+                        0,
+                        relax.ShapeExpr(dilated_window_shape),
+                        relax.ShapeExpr(window_strides),
+                    ),
+                    out_sinfo=relax.TensorStructInfo(
+                        output_shape + tuple(dilated_window_shape), "bool"
+                    ),
+                )
+            )

Review Comment:
   ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)
   
   Update the expected `topi.sliding_window` call in the boolean test helper to 
match the corrected 5-argument signature with explicit `pad_before` and 
`pad_after` shape expressions.
   
   ```suggestion
               windowed = bb.emit(
                   relax.op.call_dps_packed(
                       "topi.sliding_window",
                       (
                           x,
                           relax.ShapeExpr([0] * rank),
                           relax.ShapeExpr([0] * rank),
                           relax.ShapeExpr(dilated_window_shape),
                           relax.ShapeExpr(window_strides),
                       ),
                       out_sinfo=relax.TensorStructInfo(
                           output_shape + tuple(dilated_window_shape), "bool"
                       ),
                   )
               )
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to