From c32ae9687de657eb9834eb106850145a1fc4ac99 Mon Sep 17 00:00:00 2001 From: samthakur587 Date: Sat, 9 Aug 2025 12:07:27 +0530 Subject: [PATCH 1/3] feat: prod numpy for openvino backend --- keras/src/backend/openvino/numpy.py | 38 ++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/keras/src/backend/openvino/numpy.py b/keras/src/backend/openvino/numpy.py index 8b3c5e0b5a96..5a1ea1b8018d 100644 --- a/keras/src/backend/openvino/numpy.py +++ b/keras/src/backend/openvino/numpy.py @@ -1303,7 +1303,43 @@ def pad(x, pad_width, mode="constant", constant_values=None): def prod(x, axis=None, keepdims=False, dtype=None): - raise NotImplementedError("`prod` is not supported with openvino backend") + x = get_ov_output(x) + x_type = x.get_element_type() + + # Convert to appropriate type for reduction + if x_type == Type.boolean: + # Convert boolean to int32 for reduction + x = ov_opset.convert(x, Type.i32).output(0) + + if axis is None: + flatten_shape = ov_opset.constant([-1], Type.i32).output(0) + x = ov_opset.reshape(x, flatten_shape, False).output(0) + axis = 0 + + if isinstance(axis, tuple): + axis = list(axis) + axis = ov_opset.constant(axis, Type.i32).output(0) + + # Compute the product + result = ov_opset.reduce_prod(x, axis, keepdims).output(0) + + # Convert to the specified dtype if provided + if dtype is not None: + ov_dtype = _convert_to_ov_type(dtype) + result = ov_opset.convert(result, ov_dtype).output(0) + else: + # Handle dtype promotion rules + if x_type == Type.boolean: + result = ov_opset.convert(result, Type.i32).output(0) + elif x_type == Type.i64: + result = ov_opset.convert(result, Type.i64).output(0) + elif x_type in (Type.u8, Type.u16, Type.u32): + result = ov_opset.convert(result, Type.u32).output(0) + elif x_type.is_integral(): + result = ov_opset.convert(result, Type.i32).output(0) + + return OpenVINOKerasTensor(result) + def quantile(x, q, axis=None, method="linear", keepdims=False): From 938d017976281875914922123adc5a79b8e6dbee Mon Sep 17 00:00:00 2001 From: samthakur587 Date: Sat, 9 Aug 2025 12:07:43 +0530 Subject: [PATCH 2/3] feat: included tests for prod --- keras/src/backend/openvino/excluded_concrete_tests.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/keras/src/backend/openvino/excluded_concrete_tests.txt b/keras/src/backend/openvino/excluded_concrete_tests.txt index c366943c7eba..2fc1c6c4608d 100644 --- a/keras/src/backend/openvino/excluded_concrete_tests.txt +++ b/keras/src/backend/openvino/excluded_concrete_tests.txt @@ -46,7 +46,6 @@ NumpyDtypeTest::test_meshgrid NumpyDtypeTest::test_minimum_python_types NumpyDtypeTest::test_multiply NumpyDtypeTest::test_power -NumpyDtypeTest::test_prod NumpyDtypeTest::test_quantile NumpyDtypeTest::test_roll NumpyDtypeTest::test_round @@ -106,7 +105,6 @@ NumpyOneInputOpsCorrectnessTest::test_pad_int16_constant_2 NumpyOneInputOpsCorrectnessTest::test_pad_int8_constant_2 NumpyOneInputOpsCorrectnessTest::test_pad_uint8_constant_2 NumpyOneInputOpsCorrectnessTest::test_pad_int32_constant_2 -NumpyOneInputOpsCorrectnessTest::test_prod NumpyOneInputOpsCorrectnessTest::test_real NumpyOneInputOpsCorrectnessTest::test_reshape NumpyOneInputOpsCorrectnessTest::test_roll From a17392817f243823090654a7e1ae4df8d3881888 Mon Sep 17 00:00:00 2001 From: samthakur587 Date: Sat, 9 Aug 2025 16:27:30 +0530 Subject: [PATCH 3/3] fix: handled dtype permosion --- keras/src/backend/openvino/numpy.py | 44 ++++++++++++----------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/keras/src/backend/openvino/numpy.py b/keras/src/backend/openvino/numpy.py index 5a1ea1b8018d..2b310d96a278 100644 --- a/keras/src/backend/openvino/numpy.py +++ b/keras/src/backend/openvino/numpy.py @@ -1304,42 +1304,34 @@ def pad(x, pad_width, mode="constant", constant_values=None): def prod(x, axis=None, keepdims=False, dtype=None): x = get_ov_output(x) - x_type = x.get_element_type() - - # Convert to appropriate type for reduction - if x_type == Type.boolean: - # Convert boolean to int32 for reduction - x = ov_opset.convert(x, Type.i32).output(0) - + + # If a specific dtype is requested, cast the input to that dtype. + if dtype is not None: + ov_dtype = OPENVINO_DTYPES[standardize_dtype(dtype)] + x = ov_opset.convert(x, ov_dtype).output(0) + # Otherwise, apply dtype promotion rules before reduction. + else: + x_type = x.get_element_type() + if x_type == Type.boolean: + x = ov_opset.convert(x, Type.i32).output(0) + elif x_type in (Type.i8, Type.i16): + x = ov_opset.convert(x, Type.i32).output(0) + elif x_type in (Type.u8, Type.u16): + x = ov_opset.convert(x, Type.u32).output(0) + if axis is None: flatten_shape = ov_opset.constant([-1], Type.i32).output(0) x = ov_opset.reshape(x, flatten_shape, False).output(0) axis = 0 - + if isinstance(axis, tuple): axis = list(axis) axis = ov_opset.constant(axis, Type.i32).output(0) - + # Compute the product result = ov_opset.reduce_prod(x, axis, keepdims).output(0) - - # Convert to the specified dtype if provided - if dtype is not None: - ov_dtype = _convert_to_ov_type(dtype) - result = ov_opset.convert(result, ov_dtype).output(0) - else: - # Handle dtype promotion rules - if x_type == Type.boolean: - result = ov_opset.convert(result, Type.i32).output(0) - elif x_type == Type.i64: - result = ov_opset.convert(result, Type.i64).output(0) - elif x_type in (Type.u8, Type.u16, Type.u32): - result = ov_opset.convert(result, Type.u32).output(0) - elif x_type.is_integral(): - result = ov_opset.convert(result, Type.i32).output(0) - - return OpenVINOKerasTensor(result) + return OpenVINOKerasTensor(result) def quantile(x, q, axis=None, method="linear", keepdims=False):