diff --git a/keras/src/backend/openvino/excluded_concrete_tests.txt b/keras/src/backend/openvino/excluded_concrete_tests.txt index 1f2cf067ab0..e30819423eb 100644 --- a/keras/src/backend/openvino/excluded_concrete_tests.txt +++ b/keras/src/backend/openvino/excluded_concrete_tests.txt @@ -75,13 +75,6 @@ NumpyOneInputOpsCorrectnessTest::test_floor_divide NumpyOneInputOpsCorrectnessTest::test_imag NumpyOneInputOpsCorrectnessTest::test_isreal NumpyOneInputOpsCorrectnessTest::test_logaddexp2 -NumpyOneInputOpsCorrectnessTest::test_pad_float16_constant_2 -NumpyOneInputOpsCorrectnessTest::test_pad_float32_constant_2 -NumpyOneInputOpsCorrectnessTest::test_pad_float64_constant_2 -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_real NumpyOneInputOpsCorrectnessTest::test_reshape NumpyOneInputOpsCorrectnessTest::test_roll @@ -91,15 +84,12 @@ NumpyOneInputOpsCorrectnessTest::test_select NumpyOneInputOpsCorrectnessTest::test_signbit NumpyOneInputOpsCorrectnessTest::test_size NumpyOneInputOpsCorrectnessTest::test_slogdet -NumpyOneInputOpsCorrectnessTest::test_std NumpyOneInputOpsCorrectnessTest::test_swapaxes NumpyOneInputOpsCorrectnessTest::test_tile NumpyOneInputOpsCorrectnessTest::test_trace -NumpyOneInputOpsCorrectnessTest::test_transpose NumpyOneInputOpsCorrectnessTest::test_trapezoid NumpyOneInputOpsCorrectnessTest::test_trunc NumpyOneInputOpsCorrectnessTest::test_unravel_index -NumpyOneInputOpsCorrectnessTest::test_var NumpyOneInputOpsCorrectnessTest::test_vectorize NumpyOneInputOpsCorrectnessTest::test_vstack NumpyTwoInputOpsCorrectnessTest::test_bitwise_and @@ -112,7 +102,6 @@ NumpyTwoInputOpsCorrectnessTest::test_digitize NumpyTwoInputOpsCorrectnessTest::test_divide_no_nan NumpyTwoInputOpsCorrectnessTest::test_einsum NumpyTwoInputOpsCorrectnessTest::test_gcd -NumpyTwoInputOpsCorrectnessTest::test_heaviside NumpyTwoInputOpsCorrectnessTest::test_hypot NumpyTwoInputOpsCorrectnessTest::test_inner NumpyTwoInputOpsCorrectnessTest::test_isin @@ -128,21 +117,17 @@ NumpyOneInputOpsDynamicShapeTest::test_cbrt NumpyOneInputOpsDynamicShapeTest::test_corrcoef NumpyOneInputOpsDynamicShapeTest::test_hamming NumpyOneInputOpsDynamicShapeTest::test_hanning -NumpyOneInputOpsDynamicShapeTest::test_isposinf NumpyOneInputOpsDynamicShapeTest::test_isreal NumpyOneInputOpsDynamicShapeTest::test_kaiser NumpyOneInputOpsStaticShapeTest::test_angle NumpyOneInputOpsStaticShapeTest::test_cbrt -NumpyOneInputOpsStaticShapeTest::test_isposinf NumpyOneInputOpsStaticShapeTest::test_isreal NumpyTwoInputOpsDynamicShapeTest::test_gcd -NumpyTwoInputOpsDynamicShapeTest::test_heaviside NumpyTwoInputOpsDynamicShapeTest::test_hypot NumpyTwoInputOpsDynamicShapeTest::test_isin NumpyTwoInputOpsDynamicShapeTest::test_kron NumpyTwoInputOpsDynamicShapeTest::test_lcm NumpyTwoInputOpsStaticShapeTest::test_gcd -NumpyTwoInputOpsStaticShapeTest::test_heaviside NumpyTwoInputOpsStaticShapeTest::test_hypot NumpyTwoInputOpsStaticShapeTest::test_isin NumpyTwoInputOpsStaticShapeTest::test_kron diff --git a/keras/src/backend/openvino/numpy.py b/keras/src/backend/openvino/numpy.py index 88cdbf93984..c897c77e79e 100644 --- a/keras/src/backend/openvino/numpy.py +++ b/keras/src/backend/openvino/numpy.py @@ -553,9 +553,21 @@ def hamming(x): def heaviside(x1, x2): - raise NotImplementedError( - "`heaviside` is not supported with openvino backend" - ) + x1 = get_ov_output(x1) + x_type = x1.get_element_type() + x2 = get_ov_output(x2, x_type) + + zero_scalar = ov_opset.constant(0, x_type).output(0) + one_scalar = ov_opset.constant(1, x_type).output(0) + + neg = ov_opset.less(x1, zero_scalar).output(0) + pos = ov_opset.greater(x1, zero_scalar).output(0) + eq = ov_opset.equal(x1, zero_scalar).output(0) + + x = ov_opset.select(neg, zero_scalar, x1).output(0) + x = ov_opset.select(pos, one_scalar, x).output(0) + x = ov_opset.select(eq, x2, x).output(0) + return OpenVINOKerasTensor(x) def kaiser(x, beta): @@ -695,15 +707,9 @@ def count_nonzero(x, axis=None): zero_constant = ov_opset.convert_like(zero_constant, x) x = ov_opset.not_equal(x, zero_constant).output(0) 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) - if axis == []: + x, axis = _resolve_axis(x, axis) + if not axis: return OpenVINOKerasTensor(x) - axis = ov_opset.constant(axis, Type.i32).output(0) return OpenVINOKerasTensor(ov_opset.reduce_sum(x, axis, False).output(0)) @@ -722,11 +728,7 @@ def cumsum(x, axis=None, dtype=None): if dtype is not None: ov_type = OPENVINO_DTYPES[standardize_dtype(dtype)] x = ov_opset.convert(x, ov_type).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 - axis = ov_opset.constant(axis, Type.i32).output(0) + x, axis = _resolve_axis(x, axis) if x.get_element_type() == Type.boolean: x = ov_opset.convert(x, Type.i32).output(0) return OpenVINOKerasTensor(ov_opset.cumsum(x, axis).output(0)) @@ -1761,7 +1763,9 @@ def pad(x, pad_width, mode="constant", constant_values=None): "`pad` operation supports only scalar pad value " "in constant mode by openvino backend" ) - pad_value = constant_values + pad_value = ov_opset.constant( + constant_values, x.get_element_type() + ).output(0) # split pad_width into two tensors pads_begin and pads_end pads_begin = [] @@ -2026,22 +2030,9 @@ def stack(x, axis=0): def std(x, axis=None, keepdims=False): - x = get_ov_output(x) - 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 - axis = ov_opset.constant(axis, Type.i32).output(0) - # The variance is computed using $Var = E[|x|^2] - |E[x]|^2$, It is faster - # but less numerically stable. - mean = ov_opset.reduce_mean(x, axis, keepdims).output(0) - const_two = ov_opset.constant(2, x.get_element_type()).output(0) - squared_x = ov_opset.power(x, const_two).output(0) - squared_mean = ov_opset.power(mean, const_two).output(0) - squared_x_mean = ov_opset.reduce_mean(squared_x, axis, keepdims) - variance = ov_opset.subtract(squared_x_mean, squared_mean).output(0) - std_var = OpenVINOKerasTensor(ov_opset.sqrt(variance).output(0)) - return std_var + var_x = var(x, axis, keepdims) + std_dev = ov_opset.sqrt(var_x).output(0) + return OpenVINOKerasTensor(std_dev) def swapaxes(x, axis1, axis2): @@ -2406,18 +2397,26 @@ def trapezoid(y, x=None, dx=1.0, axis=-1): def var(x, axis=None, keepdims=False): x = get_ov_output(x) + x_type = x.get_element_type() + x, axis = _resolve_axis(x, axis) + + work_dtype = Type.f64 if x_type.is_integral() else x.get_element_type() + if x_type.is_integral(): + x = ov_opset.convert(x, work_dtype).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 - axis = ov_opset.constant(axis, Type.i32).output(0) + const_zero = ov_opset.constant(0, dtype=work_dtype).output(0) + return OpenVINOKerasTensor( + ov_opset.broadcast(const_zero, ov_opset.shape_of(x)).output(0) + ) # The variance is computed using $Var = E[|x|^2] - |E[x]|^2$, It is faster # but less numerically stable. mean = ov_opset.reduce_mean(x, axis, keepdims).output(0) - const_two = ov_opset.constant(2, x.get_element_type()).output(0) + const_two = ov_opset.constant(2, work_dtype).output(0) + squared_x = ov_opset.power(x, const_two).output(0) squared_mean = ov_opset.power(mean, const_two).output(0) - squared_x_mean = ov_opset.reduce_mean(squared_x, axis, keepdims) + + squared_x_mean = ov_opset.reduce_mean(squared_x, axis, keepdims).output(0) variance = OpenVINOKerasTensor( ov_opset.subtract(squared_x_mean, squared_mean).output(0) )