Skip to content

Commit 72dfa36

Browse files
More OpenVINO Operations (#21774)
* additional ov ops * std/var returning correct results, albeit as f64 * chore: pydocs * chore: pydocs * chore: pydocs * Update keras/src/backend/openvino/numpy.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * fix heaviside * use broadcast instead of multiply --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 08f102d commit 72dfa36

File tree

2 files changed

+38
-54
lines changed

2 files changed

+38
-54
lines changed

keras/src/backend/openvino/excluded_concrete_tests.txt

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,6 @@ NumpyOneInputOpsCorrectnessTest::test_floor_divide
7676
NumpyOneInputOpsCorrectnessTest::test_imag
7777
NumpyOneInputOpsCorrectnessTest::test_isreal
7878
NumpyOneInputOpsCorrectnessTest::test_logaddexp2
79-
NumpyOneInputOpsCorrectnessTest::test_pad_float16_constant_2
80-
NumpyOneInputOpsCorrectnessTest::test_pad_float32_constant_2
81-
NumpyOneInputOpsCorrectnessTest::test_pad_float64_constant_2
82-
NumpyOneInputOpsCorrectnessTest::test_pad_int16_constant_2
83-
NumpyOneInputOpsCorrectnessTest::test_pad_int8_constant_2
84-
NumpyOneInputOpsCorrectnessTest::test_pad_uint8_constant_2
85-
NumpyOneInputOpsCorrectnessTest::test_pad_int32_constant_2
8679
NumpyOneInputOpsCorrectnessTest::test_real
8780
NumpyOneInputOpsCorrectnessTest::test_reshape
8881
NumpyOneInputOpsCorrectnessTest::test_roll
@@ -92,15 +85,12 @@ NumpyOneInputOpsCorrectnessTest::test_select
9285
NumpyOneInputOpsCorrectnessTest::test_signbit
9386
NumpyOneInputOpsCorrectnessTest::test_size
9487
NumpyOneInputOpsCorrectnessTest::test_slogdet
95-
NumpyOneInputOpsCorrectnessTest::test_std
9688
NumpyOneInputOpsCorrectnessTest::test_swapaxes
9789
NumpyOneInputOpsCorrectnessTest::test_tile
9890
NumpyOneInputOpsCorrectnessTest::test_trace
99-
NumpyOneInputOpsCorrectnessTest::test_transpose
10091
NumpyOneInputOpsCorrectnessTest::test_trapezoid
10192
NumpyOneInputOpsCorrectnessTest::test_trunc
10293
NumpyOneInputOpsCorrectnessTest::test_unravel_index
103-
NumpyOneInputOpsCorrectnessTest::test_var
10494
NumpyOneInputOpsCorrectnessTest::test_vectorize
10595
NumpyOneInputOpsCorrectnessTest::test_vstack
10696
NumpyOneInputOpsCorrectnessTest::test_view
@@ -114,7 +104,6 @@ NumpyTwoInputOpsCorrectnessTest::test_digitize
114104
NumpyTwoInputOpsCorrectnessTest::test_divide_no_nan
115105
NumpyTwoInputOpsCorrectnessTest::test_einsum
116106
NumpyTwoInputOpsCorrectnessTest::test_gcd
117-
NumpyTwoInputOpsCorrectnessTest::test_heaviside
118107
NumpyTwoInputOpsCorrectnessTest::test_hypot
119108
NumpyTwoInputOpsCorrectnessTest::test_inner
120109
NumpyTwoInputOpsCorrectnessTest::test_isin
@@ -130,23 +119,19 @@ NumpyOneInputOpsDynamicShapeTest::test_cbrt
130119
NumpyOneInputOpsDynamicShapeTest::test_corrcoef
131120
NumpyOneInputOpsDynamicShapeTest::test_hamming
132121
NumpyOneInputOpsDynamicShapeTest::test_hanning
133-
NumpyOneInputOpsDynamicShapeTest::test_isposinf
134122
NumpyOneInputOpsDynamicShapeTest::test_isreal
135123
NumpyOneInputOpsDynamicShapeTest::test_kaiser
136124
NumpyOneInputOpsDynamicShapeTest::test_view
137125
NumpyOneInputOpsStaticShapeTest::test_angle
138126
NumpyOneInputOpsStaticShapeTest::test_cbrt
139-
NumpyOneInputOpsStaticShapeTest::test_isposinf
140127
NumpyOneInputOpsStaticShapeTest::test_isreal
141128
NumpyOneInputOpsStaticShapeTest::test_view
142129
NumpyTwoInputOpsDynamicShapeTest::test_gcd
143-
NumpyTwoInputOpsDynamicShapeTest::test_heaviside
144130
NumpyTwoInputOpsDynamicShapeTest::test_hypot
145131
NumpyTwoInputOpsDynamicShapeTest::test_isin
146132
NumpyTwoInputOpsDynamicShapeTest::test_kron
147133
NumpyTwoInputOpsDynamicShapeTest::test_lcm
148134
NumpyTwoInputOpsStaticShapeTest::test_gcd
149-
NumpyTwoInputOpsStaticShapeTest::test_heaviside
150135
NumpyTwoInputOpsStaticShapeTest::test_hypot
151136
NumpyTwoInputOpsStaticShapeTest::test_isin
152137
NumpyTwoInputOpsStaticShapeTest::test_kron

keras/src/backend/openvino/numpy.py

Lines changed: 38 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -557,9 +557,21 @@ def hamming(x):
557557

558558

559559
def heaviside(x1, x2):
560-
raise NotImplementedError(
561-
"`heaviside` is not supported with openvino backend"
562-
)
560+
x1 = get_ov_output(x1)
561+
x_type = x1.get_element_type()
562+
x2 = get_ov_output(x2, x_type)
563+
564+
zero_scalar = ov_opset.constant(0, x_type).output(0)
565+
one_scalar = ov_opset.constant(1, x_type).output(0)
566+
567+
neg = ov_opset.less(x1, zero_scalar).output(0)
568+
pos = ov_opset.greater(x1, zero_scalar).output(0)
569+
eq = ov_opset.equal(x1, zero_scalar).output(0)
570+
571+
x = ov_opset.select(neg, zero_scalar, x1).output(0)
572+
x = ov_opset.select(pos, one_scalar, x).output(0)
573+
x = ov_opset.select(eq, x2, x).output(0)
574+
return OpenVINOKerasTensor(x)
563575

564576

565577
def kaiser(x, beta):
@@ -699,15 +711,9 @@ def count_nonzero(x, axis=None):
699711
zero_constant = ov_opset.convert_like(zero_constant, x)
700712
x = ov_opset.not_equal(x, zero_constant).output(0)
701713
x = ov_opset.convert(x, Type.i32).output(0)
702-
if axis is None:
703-
flatten_shape = ov_opset.constant([-1], Type.i32).output(0)
704-
x = ov_opset.reshape(x, flatten_shape, False).output(0)
705-
axis = 0
706-
if isinstance(axis, tuple):
707-
axis = list(axis)
708-
if axis == []:
714+
x, axis = _resolve_axis(x, axis)
715+
if not axis:
709716
return OpenVINOKerasTensor(x)
710-
axis = ov_opset.constant(axis, Type.i32).output(0)
711717
return OpenVINOKerasTensor(ov_opset.reduce_sum(x, axis, False).output(0))
712718

713719

@@ -726,11 +732,7 @@ def cumsum(x, axis=None, dtype=None):
726732
if dtype is not None:
727733
ov_type = OPENVINO_DTYPES[standardize_dtype(dtype)]
728734
x = ov_opset.convert(x, ov_type).output(0)
729-
if axis is None:
730-
flatten_shape = ov_opset.constant([-1], Type.i32).output(0)
731-
x = ov_opset.reshape(x, flatten_shape, False).output(0)
732-
axis = 0
733-
axis = ov_opset.constant(axis, Type.i32).output(0)
735+
x, axis = _resolve_axis(x, axis)
734736
if x.get_element_type() == Type.boolean:
735737
x = ov_opset.convert(x, Type.i32).output(0)
736738
return OpenVINOKerasTensor(ov_opset.cumsum(x, axis).output(0))
@@ -1765,7 +1767,9 @@ def pad(x, pad_width, mode="constant", constant_values=None):
17651767
"`pad` operation supports only scalar pad value "
17661768
"in constant mode by openvino backend"
17671769
)
1768-
pad_value = constant_values
1770+
pad_value = ov_opset.constant(
1771+
constant_values, x.get_element_type()
1772+
).output(0)
17691773

17701774
# split pad_width into two tensors pads_begin and pads_end
17711775
pads_begin = []
@@ -2061,22 +2065,9 @@ def stack(x, axis=0):
20612065

20622066

20632067
def std(x, axis=None, keepdims=False):
2064-
x = get_ov_output(x)
2065-
if axis is None:
2066-
flatten_shape = ov_opset.constant([-1], Type.i32).output(0)
2067-
x = ov_opset.reshape(x, flatten_shape, False).output(0)
2068-
axis = 0
2069-
axis = ov_opset.constant(axis, Type.i32).output(0)
2070-
# The variance is computed using $Var = E[|x|^2] - |E[x]|^2$, It is faster
2071-
# but less numerically stable.
2072-
mean = ov_opset.reduce_mean(x, axis, keepdims).output(0)
2073-
const_two = ov_opset.constant(2, x.get_element_type()).output(0)
2074-
squared_x = ov_opset.power(x, const_two).output(0)
2075-
squared_mean = ov_opset.power(mean, const_two).output(0)
2076-
squared_x_mean = ov_opset.reduce_mean(squared_x, axis, keepdims)
2077-
variance = ov_opset.subtract(squared_x_mean, squared_mean).output(0)
2078-
std_var = OpenVINOKerasTensor(ov_opset.sqrt(variance).output(0))
2079-
return std_var
2068+
var_x = var(x, axis, keepdims)
2069+
std_dev = ov_opset.sqrt(var_x).output(0)
2070+
return OpenVINOKerasTensor(std_dev)
20802071

20812072

20822073
def swapaxes(x, axis1, axis2):
@@ -2441,18 +2432,26 @@ def trapezoid(y, x=None, dx=1.0, axis=-1):
24412432

24422433
def var(x, axis=None, keepdims=False):
24432434
x = get_ov_output(x)
2435+
x_type = x.get_element_type()
2436+
x, axis = _resolve_axis(x, axis)
2437+
2438+
work_dtype = Type.f64 if x_type.is_integral() else x.get_element_type()
2439+
if x_type.is_integral():
2440+
x = ov_opset.convert(x, work_dtype).output(0)
24442441
if axis is None:
2445-
flatten_shape = ov_opset.constant([-1], Type.i32).output(0)
2446-
x = ov_opset.reshape(x, flatten_shape, False).output(0)
2447-
axis = 0
2448-
axis = ov_opset.constant(axis, Type.i32).output(0)
2442+
const_zero = ov_opset.constant(0, dtype=work_dtype).output(0)
2443+
return OpenVINOKerasTensor(
2444+
ov_opset.broadcast(const_zero, ov_opset.shape_of(x)).output(0)
2445+
)
24492446
# The variance is computed using $Var = E[|x|^2] - |E[x]|^2$, It is faster
24502447
# but less numerically stable.
24512448
mean = ov_opset.reduce_mean(x, axis, keepdims).output(0)
2452-
const_two = ov_opset.constant(2, x.get_element_type()).output(0)
2449+
const_two = ov_opset.constant(2, work_dtype).output(0)
2450+
24532451
squared_x = ov_opset.power(x, const_two).output(0)
24542452
squared_mean = ov_opset.power(mean, const_two).output(0)
2455-
squared_x_mean = ov_opset.reduce_mean(squared_x, axis, keepdims)
2453+
2454+
squared_x_mean = ov_opset.reduce_mean(squared_x, axis, keepdims).output(0)
24562455
variance = OpenVINOKerasTensor(
24572456
ov_opset.subtract(squared_x_mean, squared_mean).output(0)
24582457
)

0 commit comments

Comments
 (0)