Skip to content
Open
Show file tree
Hide file tree
Changes from all 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 @@ -39,9 +39,7 @@ NumpyDtypeTest::test_isnan
NumpyDtypeTest::test_isneginf
NumpyDtypeTest::test_isposinf
NumpyDtypeTest::test_kron
NumpyDtypeTest::test_linspace
NumpyDtypeTest::test_logaddexp
NumpyDtypeTest::test_logspace
NumpyDtypeTest::test_matmul_
NumpyDtypeTest::test_max
NumpyDtypeTest::test_mean
Expand Down Expand Up @@ -148,8 +146,6 @@ NumpyTwoInputOpsCorrectnessTest::test_hypot
NumpyTwoInputOpsCorrectnessTest::test_inner
NumpyTwoInputOpsCorrectnessTest::test_isin
NumpyTwoInputOpsCorrectnessTest::test_kron
NumpyTwoInputOpsCorrectnessTest::test_linspace
NumpyTwoInputOpsCorrectnessTest::test_logspace
NumpyTwoInputOpsCorrectnessTest::test_quantile
NumpyTwoInputOpsCorrectnessTest::test_tensordot
NumpyTwoInputOpsCorrectnessTest::test_vdot
Expand Down
150 changes: 146 additions & 4 deletions keras/src/backend/openvino/numpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -1009,9 +1009,131 @@ 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.

Supports axis=0 (prepend) and axis=-1 (append). Intermediate axis values are
treated as axis=-1.

If `retstep` is True, also returns the step size between values.

"""

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)
zero_i32 = ov_opset.constant(0, Type.i32).output(0)
one_i32 = ov_opset.constant(1, Type.i32).output(0)
one_i32_array = ov_opset.constant([1], Type.i32).output(0)

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(
zero_i32,
ov_opset.constant(num, Type.i32).output(0),
one_i32,
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)
ones_for_start = ov_opset.broadcast(one_i32, start_rank).output(0)

if axis == 0:
indices_target_shape = ov_opset.concat(
[indices_shape, ones_for_start], 0
).output(0)
start_target_shape = ov_opset.concat(
[one_i32_array, start_shape], 0
).output(0)
else:
indices_target_shape = ov_opset.concat(
[ones_for_start, indices_shape], 0
).output(0)
start_target_shape = ov_opset.concat(
[start_shape, one_i32_array], 0
).output(0)

indices_reshaped = ov_opset.reshape(
indices, indices_target_shape, False
).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)

scaled_indices = ov_opset.multiply(indices_reshaped, step_reshaped).output(
0
)
result = ov_opset.add(start_reshaped, scaled_indices).output(0)

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


def log(x):
Expand Down Expand Up @@ -1092,10 +1214,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