Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
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 @@ -36,9 +36,7 @@ NumpyDtypeTest::test_isinf
NumpyDtypeTest::test_isnan
NumpyDtypeTest::test_isneginf
NumpyDtypeTest::test_isposinf
NumpyDtypeTest::test_linspace
NumpyDtypeTest::test_logaddexp
NumpyDtypeTest::test_logspace
NumpyDtypeTest::test_matmul_
NumpyDtypeTest::test_max
NumpyDtypeTest::test_mean
Expand Down Expand Up @@ -144,8 +142,6 @@ NumpyTwoInputOpsCorrectnessTest::test_einsum
NumpyTwoInputOpsCorrectnessTest::test_heaviside
NumpyTwoInputOpsCorrectnessTest::test_inner
NumpyTwoInputOpsCorrectnessTest::test_isin
NumpyTwoInputOpsCorrectnessTest::test_linspace
NumpyTwoInputOpsCorrectnessTest::test_logspace
NumpyTwoInputOpsCorrectnessTest::test_quantile
NumpyTwoInputOpsCorrectnessTest::test_tensordot
NumpyTwoInputOpsCorrectnessTest::test_vdot
Expand Down
179 changes: 175 additions & 4 deletions keras/src/backend/openvino/numpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -997,9 +997,160 @@ 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.

Parameters
----------
axis : int, optional
Currently only supports axis=0 (prepend) and axis=-1 (append).
Intermediate axis values are treated as axis=-1.
"""
start = get_ov_output(start)
stop = get_ov_output(stop)

if hasattr(num, "output") or isinstance(num, OpenVINOKerasTensor):
num_tensor = get_ov_output(num)
try:
if num_tensor.get_node().get_type_name() == "Constant":
num_value = num_tensor.get_node().get_vector()[0]
num = int(num_value)
else:
raise NotImplementedError(
"Dynamic num values not fully supported"
)
except Exception as e:
raise NotImplementedError(
"Could not extract num value from tensor"
) from e
else:
num = int(num)
if dtype is None:
output_type = OPENVINO_DTYPES[config.floatx()]
else:
output_type = OPENVINO_DTYPES[dtype]

start = ov_opset.convert(start, output_type).output(0)
stop = ov_opset.convert(stop, output_type).output(0)
if num < 0:
raise ValueError("Number of samples, `num`, must be non-negative.")
if num == 0:
empty_shape = ov_opset.constant([0], Type.i32).output(0)
result = ov_opset.broadcast(
ov_opset.constant(0.0, output_type).output(0), empty_shape
).output(0)
if retstep:
nan_step = ov_opset.constant(np.nan, output_type).output(0)
return OpenVINOKerasTensor(result), OpenVINOKerasTensor(nan_step)
return OpenVINOKerasTensor(result)

if num == 1:
result_val = start
axis_const = ov_opset.constant([axis], Type.i32).output(0)
result = ov_opset.unsqueeze(result_val, axis_const).output(0)
if retstep:
if endpoint:
step = ov_opset.constant(np.nan, output_type).output(0)
else:
step = ov_opset.subtract(stop, start).output(0)
return OpenVINOKerasTensor(result), OpenVINOKerasTensor(step)

num_const = ov_opset.constant(num, output_type).output(0)

if endpoint:
divisor = ov_opset.subtract(
num_const, ov_opset.constant(1, output_type).output(0)
).output(0)
else:
divisor = num_const

step = ov_opset.divide(
ov_opset.subtract(stop, start).output(0), divisor
).output(0)

indices = ov_opset.range(
ov_opset.constant(0, Type.i32).output(0),
ov_opset.constant(num, Type.i32).output(0),
ov_opset.constant(1, Type.i32).output(0),
output_type,
).output(0)

start_shape = ov_opset.convert(
ov_opset.shape_of(start).output(0), Type.i32
).output(0)
indices_shape = ov_opset.convert(
ov_opset.shape_of(indices).output(0), Type.i32
).output(0)

start_rank = ov_opset.shape_of(start_shape).output(0)

if axis == 0:
result_shape = ov_opset.concat([indices_shape, start_shape], 0).output(
0
)

ones_for_start = ov_opset.broadcast(
ov_opset.constant(1, Type.i32).output(0), start_rank
).output(0)
indices_target_shape = ov_opset.concat(
[indices_shape, ones_for_start], 0
).output(0)
indices_reshaped = ov_opset.reshape(
indices, indices_target_shape, False
).output(0)

one_const = ov_opset.constant([1], Type.i32).output(0)
start_target_shape = ov_opset.concat(
[one_const, start_shape], 0
).output(0)
start_reshaped = ov_opset.reshape(
start, start_target_shape, False
).output(0)
step_reshaped = ov_opset.reshape(
step, start_target_shape, False
).output(0)
else:
result_shape = ov_opset.concat([start_shape, indices_shape], 0).output(
0
)

ones_for_start = ov_opset.broadcast(
ov_opset.constant(1, Type.i32).output(0), start_rank
).output(0)
indices_target_shape = ov_opset.concat(
[ones_for_start, indices_shape], 0
).output(0)
indices_reshaped = ov_opset.reshape(
indices, indices_target_shape, False
).output(0)

one_const = ov_opset.constant([1], Type.i32).output(0)
start_target_shape = ov_opset.concat(
[start_shape, one_const], 0
).output(0)
start_reshaped = ov_opset.reshape(
start, start_target_shape, False
).output(0)
step_reshaped = ov_opset.reshape(
step, start_target_shape, False
).output(0)

indices_broadcasted = ov_opset.broadcast(
indices_reshaped, result_shape
).output(0)
start_broadcasted = ov_opset.broadcast(start_reshaped, result_shape).output(
0
)
step_broadcasted = ov_opset.broadcast(step_reshaped, result_shape).output(0)

scaled_indices = ov_opset.multiply(
indices_broadcasted, step_broadcasted
).output(0)
result = ov_opset.add(start_broadcasted, scaled_indices).output(0)

if retstep:
return OpenVINOKerasTensor(result), OpenVINOKerasTensor(step)
return OpenVINOKerasTensor(result)


def log(x):
Expand Down Expand Up @@ -1080,10 +1231,30 @@ 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"
linear_samples = linspace(
start=start,
stop=stop,
num=num,
endpoint=endpoint,
retstep=False,
dtype=dtype,
axis=axis,
)

if dtype is None:
output_type = OPENVINO_DTYPES[config.floatx()]
else:
output_type = OPENVINO_DTYPES[dtype]

linear_output = get_ov_output(linear_samples)
base_tensor = get_ov_output(base)

base_tensor = ov_opset.convert(base_tensor, output_type).output(0)

result = ov_opset.power(base_tensor, linear_output).output(0)

return OpenVINOKerasTensor(result)


def maximum(x1, x2):
x1 = get_ov_output(x1)
Expand Down