Skip to content
9 changes: 0 additions & 9 deletions keras/src/backend/openvino/excluded_concrete_tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@ NumpyDtypeTest::test_add_
NumpyDtypeTest::test_angle
NumpyDtypeTest::test_argpartition
NumpyDtypeTest::test_array
NumpyDtypeTest::test_bartlett
NumpyDtypeTest::test_blackman
NumpyDtypeTest::test_empty_like
NumpyDtypeTest::test_gcd
NumpyDtypeTest::test_hamming
NumpyDtypeTest::test_hanning
NumpyDtypeTest::test_heaviside
NumpyDtypeTest::test_hypot
Expand Down Expand Up @@ -57,9 +54,6 @@ HistogramTest
NumpyOneInputOpsCorrectnessTest::test_angle
NumpyOneInputOpsCorrectnessTest::test_argpartition
NumpyOneInputOpsCorrectnessTest::test_array
NumpyOneInputOpsCorrectnessTest::test_bartlett
NumpyOneInputOpsCorrectnessTest::test_blackman
NumpyOneInputOpsCorrectnessTest::test_hamming
NumpyOneInputOpsCorrectnessTest::test_hanning
NumpyOneInputOpsCorrectnessTest::test_kaiser
NumpyOneInputOpsCorrectnessTest::test_bitwise_invert
Expand Down Expand Up @@ -112,12 +106,9 @@ NumpyTwoInputOpsCorrectnessTest::test_quantile
NumpyTwoInputOpsCorrectnessTest::test_tensordot
NumpyTwoInputOpsCorrectnessTest::test_vdot
NumpyOneInputOpsDynamicShapeTest::test_angle
NumpyOneInputOpsDynamicShapeTest::test_bartlett
NumpyOneInputOpsDynamicShapeTest::test_blackman
NumpyOneInputOpsDynamicShapeTest::test_empty_like
NumpyOneInputOpsDynamicShapeTest::test_cbrt
NumpyOneInputOpsDynamicShapeTest::test_corrcoef
NumpyOneInputOpsDynamicShapeTest::test_hamming
NumpyOneInputOpsDynamicShapeTest::test_hanning
NumpyOneInputOpsDynamicShapeTest::test_isreal
NumpyOneInputOpsDynamicShapeTest::test_kaiser
Expand Down
78 changes: 72 additions & 6 deletions keras/src/backend/openvino/numpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,16 +545,61 @@ def average(x, axis=None, weights=None):


def bartlett(x):
raise NotImplementedError(
"`bartlett` is not supported with openvino backend"
x = get_ov_output(x)
zero_const = ov_opset.constant(0, Type.i64)
one_const = ov_opset.constant(1, Type.i64)
two_const = ov_opset.constant(2, Type.i64)
two_const_f64 = ov_opset.constant(2.0, Type.f64)
if x.get_element_type() != Type.i64:
x = ov_opset.convert(x, Type.i64)
half = ov_opset.convert(
ov_opset.divide(ov_opset.subtract(x, one_const), two_const), Type.f64
)
n = ov_opset.range(zero_const, x, one_const, Type.f64)
condition = ov_opset.less_equal(n, half)
first_half = ov_opset.divide(
ov_opset.multiply(two_const_f64, n),
ov_opset.convert(ov_opset.subtract(x, one_const), Type.f64),
)
second_half = ov_opset.subtract(two_const_f64, first_half)
window = ov_opset.select(condition, first_half, second_half)
window = ov_opset.convert(window, OPENVINO_DTYPES[config.floatx()]).output(
0
)
return OpenVINOKerasTensor(window)


def hamming(x):
raise NotImplementedError(
"`hamming` is not supported with openvino backend"
m = get_ov_output(x)

m_i64 = (
m if m.get_element_type() == Type.i64 else ov_opset.convert(m, Type.i64)
)

start = ov_opset.constant(0, Type.i64)
step = ov_opset.constant(1, Type.i64)
n = ov_opset.range(start, m_i64, step, Type.f64)

one_i64 = ov_opset.constant(1, Type.i64)
denom_i64 = ov_opset.subtract(m_i64, one_i64)
denom = ov_opset.convert(denom_i64, Type.f64)

two_pi = ov_opset.constant(2.0 * np.pi, Type.f64)
two_pi_over_m_minus_1 = ov_opset.divide(two_pi, denom)

x = ov_opset.multiply(two_pi_over_m_minus_1, n)
c = ov_opset.cos(x)

# 0.54 - 0.46 * cos(...)
a = ov_opset.constant(0.54, Type.f64)
b = ov_opset.constant(0.46, Type.f64)
hamming_window = ov_opset.subtract(a, ov_opset.multiply(b, c))
hamming_window = ov_opset.convert(
hamming_window, OPENVINO_DTYPES[config.floatx()]
)

return OpenVINOKerasTensor(hamming_window.output(0))


def heaviside(x1, x2):
x1 = get_ov_output(x1)
Expand Down Expand Up @@ -624,9 +669,30 @@ def bincount(x, weights=None, minlength=0, sparse=False):


def blackman(x):
raise NotImplementedError(
"`blackman` is not supported with openvino backend"
x = get_ov_output(x)
zero_const = ov_opset.constant(0, Type.i64)
one_const = ov_opset.constant(1, Type.i64)
two_pi = ov_opset.constant(2.0 * np.pi, Type.f64)
term_1 = ov_opset.constant(0.42, Type.f64)
term_2 = ov_opset.constant(0.5, Type.f64)
term_3 = ov_opset.constant(0.08, Type.f64)
if x.get_element_type() != Type.i64:
x = ov_opset.convert(x, Type.i64)
n = ov_opset.range(zero_const, x, one_const, Type.f64)
n_minus_1 = ov_opset.subtract(
ov_opset.convert(x, Type.f64), ov_opset.constant(1.0, Type.f64)
).output(0)
angle_2pi = ov_opset.divide(ov_opset.multiply(two_pi, n), n_minus_1)
angle_4pi = ov_opset.multiply(angle_2pi, ov_opset.constant(2.0, Type.f64))
cos_2pi = ov_opset.cos(angle_2pi)
cos_4pi = ov_opset.cos(angle_4pi)
term_2_final = ov_opset.multiply(term_2, cos_2pi)
term_3_final = ov_opset.multiply(term_3, cos_4pi)
window = ov_opset.add(ov_opset.subtract(term_1, term_2_final), term_3_final)
window = ov_opset.convert(window, OPENVINO_DTYPES[config.floatx()]).output(
0
)
return OpenVINOKerasTensor(window)


def broadcast_to(x, shape):
Expand Down
9 changes: 9 additions & 0 deletions keras/src/ops/numpy_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3622,6 +3622,15 @@ def test_digitize(self):


class NumpyOneInputOpsCorrectnessTest(testing.TestCase):
def assertAllClose(self, x1, x2, atol=1e-6, rtol=1e-6, msg=None):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's not do that, it reduces the precision for dozens of ops.

Which op(s) have the issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@hertschuh Sure - with this change omitted:

-test_bartlett

E           Mismatched elements: 64 / 73 (87.7%)
E           Max absolute difference among violations: 0.00021701
E           Max relative difference among violations: 0.00035511
E            ACTUAL: array([0.      , 0.027771, 0.055542, 0.083313, 0.111084, 0.138916,
E                  0.166626, 0.194458, 0.222168, 0.25    , 0.277832, 0.305664,
E                  0.333252, 0.361084, 0.388916, 0.416748, 0.444336, 0.472168,...
E            DESIRED: array([0.      , 0.027778, 0.055556, 0.083333, 0.111111, 0.138889,
E                  0.166667, 0.194444, 0.222222, 0.25    , 0.277778, 0.305556,
E                  0.333333, 0.361111, 0.388889, 0.416667, 0.444444, 0.472222,...
  • test_blackman
E           Mismatched elements: 40 / 46 (87%)
E           Max absolute difference among violations: 0.0002353
E           Max relative difference among violations: 0.00032871
E            ACTUAL: array([-0.      ,  0.001767,  0.007214,  0.016754,  0.031052,  0.050873,
E                   0.077087,  0.110413,  0.151611,  0.200806,  0.258057,  0.322754,
E                   0.394043,  0.470215,  0.549805,  0.629883,  0.708496,  0.782227,...
E            DESIRED: array([-1.387779e-17,  1.766901e-03,  7.213000e-03,  1.675772e-02,
E                   3.104564e-02,  5.086963e-02,  7.707242e-02,  1.104350e-01,
E                   1.515615e-01,  2.007701e-01,  2.580005e-01,  3.227451e-01,
  • test_hamming
E           Mismatched elements: 10 / 11 (90.9%)
E           Max absolute difference among violations: 9.70361625e-05
E           Max relative difference among violations: 0.0002439
E            ACTUAL: array([0.080017, 0.167847, 0.397949, 0.682129, 0.912109, 1.      ,
E                  0.912109, 0.682129, 0.397949, 0.167847, 0.080017], dtype=float32)
E            DESIRED: array([0.08    , 0.167852, 0.397852, 0.682148, 0.912148, 1.      ,
E                  0.912148, 0.682148, 0.397852, 0.167852, 0.08    ])

Alternatively, there could be an "openvino" check in these tests before calling the assertion and updating the tolerance (such that it doesn't impact other operations to your point).

if backend.backend() == "openvino":
# OpenVINO seems to use lower precision for some operations,
# or employs some different algorithms that wind up with
# slightly different results. To address this, we relax
# the tolerances for OpenVINO backend.
atol = 1e-3
super().assertAllClose(x1, x2, atol=atol, rtol=rtol, msg=msg)

def test_mean(self):
x = np.array([[1, 2, 3], [3, 2, 1]])
self.assertAllClose(knp.mean(x), np.mean(x))
Expand Down
Loading