Skip to content

[Keras 3 OpenVINO Backend]: Support numpy.logspace operation #30114 #21253

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 126 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
126 commits
Select commit Hold shift + click to select a range
a9ba69a
OpenVINO: linspace and logspace
vi-shruti Apr 21, 2025
e95aba3
Updated for Commit
vi-shruti Apr 21, 2025
2933a49
Addressing pytest
vi-shruti Apr 21, 2025
94c678e
Addressing pytest
vi-shruti Apr 21, 2025
47cc458
Addressing pytest
vi-shruti Apr 22, 2025
54ecce1
Update numpy.py
vi-shruti Apr 22, 2025
00ef089
Update numpy.py
vi-shruti Apr 22, 2025
b449b7f
Update numpy.py
vi-shruti Apr 22, 2025
f1bc6f3
Update numpy.py
vi-shruti Apr 22, 2025
c11347e
Update numpy.py
vi-shruti Apr 22, 2025
831ceee
Update numpy.py
vi-shruti Apr 22, 2025
6744166
Update numpy.py
vi-shruti Apr 22, 2025
9683006
Update numpy.py
vi-shruti Apr 22, 2025
51cd940
Update numpy.py
vi-shruti Apr 22, 2025
01188fc
Update numpy.py
vi-shruti Apr 22, 2025
9368989
Update numpy.py
vi-shruti Apr 22, 2025
5aa98c0
Update numpy.py
vi-shruti Apr 22, 2025
98c9e04
Update numpy.py
vi-shruti Apr 22, 2025
6df399e
Update numpy.py
vi-shruti Apr 22, 2025
647c69e
Updated linspace
vi-shruti Apr 25, 2025
93e481e
Merge branch 'master' of https://github.com/vi-shruti/keras
vi-shruti Apr 25, 2025
92d384f
Update excluded_concrete_tests.txt
vi-shruti Apr 25, 2025
dc1e1e9
Update numpy.py
vi-shruti Apr 25, 2025
25fc834
Update numpy.py
vi-shruti Apr 25, 2025
d8aa091
Update numpy.py
vi-shruti Apr 25, 2025
5e3c537
Update numpy.py
vi-shruti Apr 26, 2025
2df8827
Update numpy.py
vi-shruti Apr 26, 2025
998a35b
Update numpy.py
vi-shruti Apr 26, 2025
7d30d96
Update numpy.py
vi-shruti Apr 27, 2025
2a9ec53
Update numpy.py
vi-shruti Apr 27, 2025
cdc91d9
Update numpy.py
vi-shruti Apr 27, 2025
004fce9
Update numpy.py
vi-shruti Apr 27, 2025
dc8081f
Update numpy.py
vi-shruti Apr 27, 2025
43f0125
Update numpy.py
vi-shruti Apr 27, 2025
fae2a81
Update numpy.py
vi-shruti Apr 27, 2025
3cf5427
Update numpy.py
vi-shruti Apr 27, 2025
a62795d
Update numpy.py
vi-shruti Apr 29, 2025
3c60459
Update numpy.py
vi-shruti Apr 29, 2025
d65d92c
Update numpy.py
vi-shruti Apr 29, 2025
37e96c1
Update numpy.py
vi-shruti Apr 29, 2025
af33c76
Update numpy.py
vi-shruti Apr 29, 2025
a26d3a6
Update numpy.py
vi-shruti Apr 29, 2025
5dc78bf
Update numpy.py
vi-shruti Apr 29, 2025
280be55
Update numpy.py
vi-shruti Apr 29, 2025
f982384
Update numpy.py
vi-shruti Apr 30, 2025
6a5fb1b
Update numpy.py
vi-shruti Apr 30, 2025
536b11a
Update numpy.py
vi-shruti Apr 30, 2025
abe68e4
Update numpy.py
vi-shruti Apr 30, 2025
0a39e5f
Update numpy.py
vi-shruti Apr 30, 2025
7d43dbf
Update numpy.py
vi-shruti Apr 30, 2025
fb5649f
Update numpy.py
vi-shruti Apr 30, 2025
e3fdbfa
Update numpy.py
vi-shruti Apr 30, 2025
96d17ff
Update numpy.py
vi-shruti Apr 30, 2025
209daf0
Update numpy.py
vi-shruti Apr 30, 2025
724b143
Update numpy.py
vi-shruti Apr 30, 2025
e60d708
Update numpy.py
vi-shruti May 5, 2025
9c7fbee
Update numpy.py
vi-shruti May 5, 2025
e6c98cc
logspace implementation
vi-shruti May 6, 2025
1fb460a
Update numpy.py
vi-shruti May 8, 2025
c6991f9
Update numpy.py
vi-shruti May 8, 2025
775ed4d
Merge branch 'master' into feature-logspace
vi-shruti May 8, 2025
4f1f2e8
Update numpy.py
vi-shruti May 8, 2025
f280554
Update numpy.py
vi-shruti May 8, 2025
f75dd47
Update numpy.py
vi-shruti May 8, 2025
437d933
Update numpy.py
vi-shruti May 8, 2025
2a008b8
Update numpy.py
vi-shruti May 9, 2025
fb2e1e0
Update numpy.py
vi-shruti May 9, 2025
636e025
Update numpy.py
vi-shruti May 9, 2025
d96ed3b
Update numpy.py
vi-shruti May 9, 2025
d217c6c
Update numpy.py
vi-shruti May 9, 2025
28901d2
Update numpy.py
vi-shruti May 9, 2025
32820ce
Update numpy.py
vi-shruti May 9, 2025
f33a621
Update numpy.py
vi-shruti May 9, 2025
724a7eb
Update numpy.py
vi-shruti May 9, 2025
5a9b3bc
Update numpy.py
vi-shruti May 10, 2025
6b2c676
Update numpy.py
vi-shruti May 10, 2025
f097818
Update numpy.py
vi-shruti May 10, 2025
1906f35
Update numpy.py
vi-shruti May 10, 2025
6c6ec9b
Update numpy.py
vi-shruti May 10, 2025
5d2987e
Update numpy.py
vi-shruti May 10, 2025
6dd5c10
Update numpy.py
vi-shruti May 12, 2025
0a9d08d
Update numpy.py
vi-shruti May 12, 2025
3ac4829
Update numpy.py
vi-shruti May 12, 2025
2a15d2a
Update numpy.py
vi-shruti May 12, 2025
6c7d3a6
Update numpy.py
vi-shruti May 12, 2025
4306789
Update numpy.py
vi-shruti May 12, 2025
b818a37
Update numpy.py
vi-shruti May 12, 2025
69bf9c6
Update numpy.py
vi-shruti May 12, 2025
d1ef9e6
Update numpy.py
vi-shruti May 12, 2025
3fb1968
Update numpy.py
vi-shruti May 12, 2025
d47b1bf
Update numpy.py
vi-shruti May 12, 2025
3df2483
Update numpy.py
vi-shruti May 12, 2025
f60d0ef
Update numpy.py
vi-shruti May 12, 2025
5f92bbe
Update numpy.py
vi-shruti May 12, 2025
8399860
Update numpy.py
vi-shruti May 12, 2025
fa78a0a
Update numpy.py
vi-shruti May 12, 2025
a77f9be
Update numpy.py
vi-shruti May 14, 2025
d1be6e6
Update numpy.py
vi-shruti May 14, 2025
70e7c1c
Update numpy.py
vi-shruti May 14, 2025
5219ffc
Update numpy.py
vi-shruti May 14, 2025
0469e5a
Update numpy.py
vi-shruti May 14, 2025
bd118a0
Update numpy.py
vi-shruti May 14, 2025
4cd3f55
Update numpy.py
vi-shruti May 14, 2025
9139c55
Update numpy.py
vi-shruti May 14, 2025
d78b845
Update numpy.py
vi-shruti May 14, 2025
0c77abd
Update numpy.py
vi-shruti May 14, 2025
630abcb
Update numpy.py
vi-shruti May 14, 2025
c33ac6c
Update numpy.py
vi-shruti May 14, 2025
c7cf7c7
Update numpy.py
vi-shruti May 14, 2025
8f29194
Update numpy.py
vi-shruti May 14, 2025
2f4824d
Update numpy.py
vi-shruti May 15, 2025
a410f4a
Update numpy.py
vi-shruti May 15, 2025
c1b6387
Update numpy.py
vi-shruti May 17, 2025
1075153
Update numpy.py
vi-shruti May 17, 2025
56c3216
Update numpy.py
vi-shruti May 17, 2025
4a0d9c6
Update numpy.py
vi-shruti May 17, 2025
5f7fadc
Update numpy.py
vi-shruti May 17, 2025
389e11d
Update numpy.py
vi-shruti May 17, 2025
9d60c1f
Update numpy.py
vi-shruti May 17, 2025
e9dc700
Update numpy.py
vi-shruti May 17, 2025
272f7ae
Update numpy.py
vi-shruti May 17, 2025
7183a28
Update numpy.py
vi-shruti May 17, 2025
997a65c
Update numpy.py
vi-shruti May 17, 2025
1e5cb70
Update numpy.py
vi-shruti May 26, 2025
8c4b152
Update excluded_concrete_tests.txt
vi-shruti May 26, 2025
93a14d2
Update excluded_concrete_tests.txt
vi-shruti May 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions keras/src/backend/openvino/excluded_concrete_tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ NumpyDtypeTest::test_inner
NumpyDtypeTest::test_isfinite
NumpyDtypeTest::test_isinf
NumpyDtypeTest::test_isnan
NumpyDtypeTest::test_linspace
NumpyDtypeTest::test_logaddexp
NumpyDtypeTest::test_logspace
NumpyDtypeTest::test_matmul_
NumpyDtypeTest::test_max
NumpyDtypeTest::test_mean
Expand Down Expand Up @@ -142,8 +140,6 @@ NumpyTwoInputOpsCorrectnessTest::test_digitize
NumpyTwoInputOpsCorrectnessTest::test_divide_no_nan
NumpyTwoInputOpsCorrectnessTest::test_einsum
NumpyTwoInputOpsCorrectnessTest::test_inner
NumpyTwoInputOpsCorrectnessTest::test_linspace
NumpyTwoInputOpsCorrectnessTest::test_logspace
NumpyTwoInputOpsCorrectnessTest::test_outer
NumpyTwoInputOpsCorrectnessTest::test_quantile
NumpyTwoInputOpsCorrectnessTest::test_take_along_axis
Expand Down
295 changes: 290 additions & 5 deletions keras/src/backend/openvino/numpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -910,9 +910,151 @@ def less_equal(x1, x2):
def linspace(
start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0
):
raise NotImplementedError(
"`linspace` is not supported with openvino backend"
)
"""
Return evenly spaced numbers over a specified interval.

Returns `num` evenly spaced samples, calculated over the
interval [`start`, `stop`].

The endpoint of the interval can optionally be excluded.

Parameters
----------
start : array_like
The starting value of the sequence.
stop : array_like
The end value of the sequence, unless `endpoint` is set to False.
In that case, the sequence consists of all but the last of ``num + 1``
evenly spaced samples, so that `stop` is excluded. Note that the step
size changes when `endpoint` is False.
num : int, optional
Number of samples to generate. Default is 50. Must be non-negative.
endpoint : bool, optional
If True, `stop` is the last sample. Otherwise, it is not included.
Default is True.
retstep : bool, optional
If True, return (`samples`, `step`), where `step` is the spacing
between samples.
dtype : dtype, optional
The type of the output array. If `dtype` is not given, the data type
is inferred from `start` and `stop`. The inferred dtype will never be
an integer; `float` is chosen even if the arguments would produce an
array of integers.
axis : int, optional
The axis in the result to store the samples. Relevant only if start
or stop are array-like. By default (0), the samples will be along a
new axis inserted at the beginning. Use -1 to get an axis at the end.

Returns
-------
samples : ndarray
There are `num` equally spaced samples in the closed interval
``[start, stop]`` or the half-open interval ``[start, stop)``
(depending on whether `endpoint` is True or False).
step : float, optional
Only returned if `retstep` is True

Size of spacing between samples.
"""

dtype = standardize_dtype(dtype) or config.floatx()
out_dtype = OPENVINO_DTYPES[dtype]
dtype = OPENVINO_DTYPES[config.floatx()]

start = get_ov_output(start, dtype)
stop = get_ov_output(stop, dtype)
start = ov_opset.convert(start, dtype).output(0)
stop = ov_opset.convert(stop, dtype).output(0)

num = get_ov_output(num, Type.i32)
num = ov_opset.convert(num, Type.i32).output(0)

zero_i = ov_opset.constant(0, Type.i32).output(0)
one_i = ov_opset.constant(1, Type.i32).output(0)
axis_i = ov_opset.constant(axis, Type.i32).output(0)

div = ov_opset.subtract(num, one_i).output(0) if endpoint else num
div = ov_opset.convert(div, dtype).output(0)

zero = ov_opset.constant(0.0, dtype).output(0)
one = ov_opset.constant(1.0, dtype).output(0)
num_f = ov_opset.convert(num, dtype).output(0)
seq = ov_opset.range(zero, num_f, one, dtype).output(0)

ndim = len(start.shape)
dims = ov_opset.concat(
[
ov_opset.constant([-1], Type.i32),
ov_opset.constant([1] * ndim, Type.i32),
],
0,
).output(0)
seq = ov_opset.reshape(seq, dims, False).output(0)

delta = ov_opset.subtract(stop, start).output(0)

cond = ov_opset.greater(div, zero).output(0)
nan_const = ov_opset.constant(float("nan"), dtype).output(0)
step_val = ov_opset.divide(delta, div).output(0)
step = ov_opset.select(cond, step_val, nan_const).output(0)

target_shape = ov_opset.concat(
[
ov_opset.constant([1], Type.i64),
ov_opset.shape_of(start).output(0),
],
0,
).output(0)
step = ov_opset.reshape(step, target_shape, False).output(0)

eq_zero = ov_opset.equal(step, zero).output(0)
any_zero = ov_opset.reduce_logical_or(
eq_zero, ov_opset.constant([0], Type.i32), False
).output(0)

y_norm = ov_opset.multiply(seq, step).output(0)
y_denorm = ov_opset.multiply(
ov_opset.divide(seq, div).output(0),
delta,
).output(0)
y_pos = ov_opset.convert(
ov_opset.select(any_zero, y_denorm, y_norm).output(0), dtype
).output(0)

y_zero = ov_opset.convert(
ov_opset.multiply(seq, delta).output(0), dtype
).output(0)
y = ov_opset.add(
ov_opset.convert(ov_opset.select(cond, y_pos, y_zero).output(0), dtype),
start,
).output(0)

if endpoint:
idx = ov_opset.subtract(num, one_i).output(0)
idx = ov_opset.convert(idx, Type.i32).output(0)
idx_tensor = ov_opset.broadcast(idx, target_shape).output(0)
stop_tensor = ov_opset.broadcast(stop, target_shape).output(0)
y = ov_opset.scatter_elements_update(
y, idx_tensor, stop_tensor, 0
).output(0)

if axis != 0:
rank = ov_opset.rank(y).output(0)
axis_p1 = ov_opset.add(axis_i, one_i).output(0)
pre = ov_opset.range(one_i, axis_p1, one_i).output(0)
post = ov_opset.range(axis_p1, rank, one_i).output(0)
zero_i = ov_opset.reshape(
zero_i, ov_opset.constant([1], Type.i32), False
).output(0)
perm = ov_opset.concat([pre, zero_i, post], 0).output(0)
y = ov_opset.transpose(y, perm).output(0)

y = ov_opset.convert(y, out_dtype).output(0)

return_step = ov_opset.convert(step, out_dtype).output(0)
if retstep:
return (OpenVINOKerasTensor(y), OpenVINOKerasTensor(return_step))
return OpenVINOKerasTensor(y)


def log(x):
Expand Down Expand Up @@ -993,9 +1135,152 @@ def logical_or(x1, x2):


def logspace(start, stop, num=50, endpoint=True, base=10, dtype=None, axis=0):
raise NotImplementedError(
"`logspace` is not supported with openvino backend"
"""
Return numbers spaced evenly on a log scale.

In linear space, the sequence starts at ``base ** start``
(`base` to the power of `start`) and ends with ``base ** stop``
(see `endpoint` below).

Parameters
----------
start : array_like
``base ** start`` is the starting value of the sequence.
stop : array_like
``base ** stop`` is the final value of the sequence, unless `endpoint`
is False. In that case, ``num + 1`` values are spaced over the
interval in log-space, of which all but the last (a sequence of
length `num`) are returned.
num : integer, optional
Number of samples to generate. Default is 50.
endpoint : boolean, optional
If true, `stop` is the last sample. Otherwise, it is not included.
Default is True.
base : array_like, optional
The base of the log space. The step size between the elements in
``ln(samples) / ln(base)`` (or ``log_base(samples)``) is uniform.
Default is 10.0.
dtype : dtype
The type of the output array. If `dtype` is not given, the data type
is inferred from `start` and `stop`. The inferred type will never be
an integer; `float` is chosen even if the arguments would produce an
array of integers.
axis : int, optional
The axis in the result to store the samples. Relevant only if start,
stop, or base are array-like. By default (0), the samples will be
along a new axis inserted at the beginning. Use -1 to get an axis at
the end.

Returns
-------
samples : ndarray
`num` samples, equally spaced on a log scale.
"""
if not (isinstance(num, int) or hasattr(num, "get_element_type")):
raise ValueError(
f"Expected 'num' to be a non-negative integer or OpenVINO scalar, "
f"got {type(num)}"
)
if isinstance(num, int) and num < 0:
raise ValueError(f"Number of samples must be non-negative, got {num}")
if not isinstance(axis, int):
raise TypeError(f"'axis' must be an integer, got {type(axis)}")

if dtype is None:
start_type = (
ov_to_keras_type(start.get_element_type())
if hasattr(start, "get_element_type")
else np.asarray(start).dtype
)
stop_type = (
ov_to_keras_type(stop.get_element_type())
if hasattr(stop, "get_element_type")
else np.asarray(stop).dtype
)

dtype = dtypes.result_type(start_type, stop_type)

out_dtype = standardize_dtype(dtype) or np.float64 # config.floatx()
out_dtype = OPENVINO_DTYPES[out_dtype]

if num == 0:
return OpenVINOKerasTensor(
ov_opset.constant(
[], dtype=OPENVINO_DTYPES[config.floatx()]
).output(0)
)

if (
not hasattr(start, "get_element_type")
and not hasattr(stop, "get_element_type")
and not hasattr(base, "get_element_type")
):
y = np.logspace(
start,
stop,
num=num,
endpoint=endpoint,
base=base,
dtype=dtype,
)

return OpenVINOKerasTensor(
ov_opset.convert(get_ov_output(y, out_dtype), out_dtype).output(0)
)

#########################################################
# dtype = OPENVINO_DTYPES[config.floatx()]

start, stop, base = (
get_ov_output(start),
get_ov_output(stop),
get_ov_output(base),
)
start, stop, base = (
ov_opset.convert(start, dtype).output(0),
ov_opset.convert(stop, dtype).output(0),
ov_opset.convert(base, dtype).output(0),
)

start = ov_opset.reshape(
start,
ov_opset.concat(
[
ov_opset.constant([1], Type.i64),
ov_opset.shape_of(start).output(0),
],
axis=0,
).output(0),
False,
).output(0)
stop = ov_opset.reshape(
stop,
ov_opset.concat(
[
ov_opset.constant([1], Type.i64),
ov_opset.shape_of(stop).output(0),
],
axis=0,
).output(0),
False,
).output(0)

target_shape = ov_opset.shape_of(start).output(0)
target_shape = ov_opset.concat(
[ov_opset.constant([num], Type.i64), target_shape[1:]], axis=0
).output(0)

start = ov_opset.broadcast(start, target_shape).output(0)
stop = ov_opset.broadcast(stop, target_shape).output(0)

lin_output = linspace(
start, stop, num=num, endpoint=endpoint, dtype=dtype, axis=axis
)

y = ov_opset.power(base, lin_output).output(0)
y = ov_opset.convert(y, out_dtype).output(0)

return OpenVINOKerasTensor(y)


def maximum(x1, x2):
Expand Down