From 2aa81e17d66080a564b8dad7e6408e24bd8eae0d Mon Sep 17 00:00:00 2001 From: Srinjoy Date: Wed, 26 Feb 2025 19:16:13 +0530 Subject: [PATCH 1/3] Support np.diag() for openvino --- .../openvino/excluded_concrete_tests.txt | 2 - keras/src/backend/openvino/numpy.py | 58 ++++++++++++++++++- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/keras/src/backend/openvino/excluded_concrete_tests.txt b/keras/src/backend/openvino/excluded_concrete_tests.txt index 6465d75101b6..b29240de5b7e 100644 --- a/keras/src/backend/openvino/excluded_concrete_tests.txt +++ b/keras/src/backend/openvino/excluded_concrete_tests.txt @@ -21,7 +21,6 @@ NumpyDtypeTest::test_count_nonzero NumpyDtypeTest::test_cross NumpyDtypeTest::test_cumprod NumpyDtypeTest::test_cumsum_bool -NumpyDtypeTest::test_diag NumpyDtypeTest::test_diff NumpyDtypeTest::test_digitize NumpyDtypeTest::test_dot @@ -101,7 +100,6 @@ NumpyOneInputOpsCorrectnessTest::test_conj NumpyOneInputOpsCorrectnessTest::test_correlate NumpyOneInputOpsCorrectnessTest::test_count_nonzero NumpyOneInputOpsCorrectnessTest::test_cumprod -NumpyOneInputOpsCorrectnessTest::test_diag NumpyOneInputOpsCorrectnessTest::test_diagonal NumpyOneInputOpsCorrectnessTest::test_diff NumpyOneInputOpsCorrectnessTest::test_dot diff --git a/keras/src/backend/openvino/numpy.py b/keras/src/backend/openvino/numpy.py index 1caf0ecf8303..e64819044abe 100644 --- a/keras/src/backend/openvino/numpy.py +++ b/keras/src/backend/openvino/numpy.py @@ -473,8 +473,62 @@ def cumsum(x, axis=None, dtype=None): def diag(x, k=0): - raise NotImplementedError("`diag` is not supported with openvino backend") - + x = get_ov_output(x) + x_shape = x.get_partial_shape() + rank = x_shape.rank.get_length() + + if rank == 1: + N_dim = x_shape[0] + if not N_dim.is_static: + raise ValueError("diag requires input with static shape for 1D input.") + N = N_dim.get_length() + output_size = N + np.abs(k) + out_shape = ov_opset.constant([output_size, output_size], dtype=Type.i32).output(0) + zeros_const = ov_opset.constant(0, x.get_element_type()).output(0) + diag_matrix = ov_opset.broadcast(zeros_const, out_shape) + + indices = [] + if k >= 0: + for i in range(N): + indices.append([i, i + k]) + else: + for i in range(N): + indices.append([i - k, i]) + + indices = np.array(indices, dtype=np.int32) + indices_const = ov_opset.constant(indices, dtype=Type.i32).output(0) + updated = ov_opset.scatter_nd_update(diag_matrix, indices_const, x) + return OpenVINOKerasTensor(updated.output(0)) + + elif rank == 2: + M_dim = x_shape[0] + N_dim = x_shape[1] + if not M_dim.is_static or not N_dim.is_static: + raise ValueError("diag requires input with static shape for 2D input.") + M = M_dim.get_length() + N = N_dim.get_length() + + if k >= 0: + L = np.minimum(M, N - k) if (N - k) > 0 else 0 + indices = [[i, i + k] for i in range(L)] + else: + L = np.minimum(M + k, N) if (M + k) > 0 else 0 + indices = [[i - k, i] for i in range(L)] + + if L <= 0: + keras_dtype = ov_to_keras_type(x.get_element_type()) + np_dtype = np.dtype(keras_dtype) + empty_np = np.empty((0,), dtype=np_dtype) + empty_const = ov_opset.constant(empty_np, x.get_element_type()).output(0) + return OpenVINOKerasTensor(empty_const) + + indices = np.array(indices, dtype=np.int32) + indices_const = ov_opset.constant(indices, dtype=Type.i32).output(0) + diag_vec = ov_opset.gather_nd(x, indices_const) + return OpenVINOKerasTensor(diag_vec.output(0)) + + else: + raise ValueError("diag supports only 1D or 2D tensors") def diagonal(x, offset=0, axis1=0, axis2=1): raise NotImplementedError( From 153335f97bf938af73c060359a2e3dcf65a0af7e Mon Sep 17 00:00:00 2001 From: Srinjoy Date: Fri, 28 Feb 2025 11:31:24 +0530 Subject: [PATCH 2/3] Update excluded tests file and fix code format --- .../openvino/excluded_concrete_tests.txt | 3 +++ keras/src/backend/openvino/numpy.py | 22 +++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/keras/src/backend/openvino/excluded_concrete_tests.txt b/keras/src/backend/openvino/excluded_concrete_tests.txt index b29240de5b7e..c172a526830f 100644 --- a/keras/src/backend/openvino/excluded_concrete_tests.txt +++ b/keras/src/backend/openvino/excluded_concrete_tests.txt @@ -21,6 +21,8 @@ NumpyDtypeTest::test_count_nonzero NumpyDtypeTest::test_cross NumpyDtypeTest::test_cumprod NumpyDtypeTest::test_cumsum_bool +NumpyDtypeTest::test_diagflat +NumpyDtypeTest::test_diagonal NumpyDtypeTest::test_diff NumpyDtypeTest::test_digitize NumpyDtypeTest::test_dot @@ -100,6 +102,7 @@ NumpyOneInputOpsCorrectnessTest::test_conj NumpyOneInputOpsCorrectnessTest::test_correlate NumpyOneInputOpsCorrectnessTest::test_count_nonzero NumpyOneInputOpsCorrectnessTest::test_cumprod +NumpyOneInputOpsCorrectnessTest::test_diagflat NumpyOneInputOpsCorrectnessTest::test_diagonal NumpyOneInputOpsCorrectnessTest::test_diff NumpyOneInputOpsCorrectnessTest::test_dot diff --git a/keras/src/backend/openvino/numpy.py b/keras/src/backend/openvino/numpy.py index e64819044abe..19a773547440 100644 --- a/keras/src/backend/openvino/numpy.py +++ b/keras/src/backend/openvino/numpy.py @@ -480,10 +480,14 @@ def diag(x, k=0): if rank == 1: N_dim = x_shape[0] if not N_dim.is_static: - raise ValueError("diag requires input with static shape for 1D input.") + raise ValueError( + "diag requires input with static shape for 1D input." + ) N = N_dim.get_length() output_size = N + np.abs(k) - out_shape = ov_opset.constant([output_size, output_size], dtype=Type.i32).output(0) + out_shape = ov_opset.constant( + [output_size, output_size], dtype=Type.i32 + ).output(0) zeros_const = ov_opset.constant(0, x.get_element_type()).output(0) diag_matrix = ov_opset.broadcast(zeros_const, out_shape) @@ -499,12 +503,14 @@ def diag(x, k=0): indices_const = ov_opset.constant(indices, dtype=Type.i32).output(0) updated = ov_opset.scatter_nd_update(diag_matrix, indices_const, x) return OpenVINOKerasTensor(updated.output(0)) - + elif rank == 2: M_dim = x_shape[0] N_dim = x_shape[1] if not M_dim.is_static or not N_dim.is_static: - raise ValueError("diag requires input with static shape for 2D input.") + raise ValueError( + "diag requires input with static shape for 2D input." + ) M = M_dim.get_length() N = N_dim.get_length() @@ -519,14 +525,16 @@ def diag(x, k=0): keras_dtype = ov_to_keras_type(x.get_element_type()) np_dtype = np.dtype(keras_dtype) empty_np = np.empty((0,), dtype=np_dtype) - empty_const = ov_opset.constant(empty_np, x.get_element_type()).output(0) + empty_const = ov_opset.constant( + empty_np, x.get_element_type() + ).output(0) return OpenVINOKerasTensor(empty_const) - + indices = np.array(indices, dtype=np.int32) indices_const = ov_opset.constant(indices, dtype=Type.i32).output(0) diag_vec = ov_opset.gather_nd(x, indices_const) return OpenVINOKerasTensor(diag_vec.output(0)) - + else: raise ValueError("diag supports only 1D or 2D tensors") From a2911f53985016a69e60bc9c6890f6b12df2bb65 Mon Sep 17 00:00:00 2001 From: Srinjoy Date: Fri, 28 Feb 2025 11:40:00 +0530 Subject: [PATCH 3/3] Fix formatting issue --- keras/src/backend/openvino/numpy.py | 1 + 1 file changed, 1 insertion(+) diff --git a/keras/src/backend/openvino/numpy.py b/keras/src/backend/openvino/numpy.py index 19a773547440..6b7c4ef205c8 100644 --- a/keras/src/backend/openvino/numpy.py +++ b/keras/src/backend/openvino/numpy.py @@ -538,6 +538,7 @@ def diag(x, k=0): else: raise ValueError("diag supports only 1D or 2D tensors") + def diagonal(x, offset=0, axis1=0, axis2=1): raise NotImplementedError( "`diagonal` is not supported with openvino backend"