Skip to content

[OpenVINO Backend] update __getitem__ #21359

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 2 commits into
base: master
Choose a base branch
from

Conversation

Mohamed-Ashraf273
Copy link
Contributor

@Mohamed-Ashraf273 Mohamed-Ashraf273 commented Jun 5, 2025

Hi @rkazants ,
I've updated __getitem__ using gather_nd as suggested, and I've avoided using convert_to_numpy. Also, I've enabled variables_test.
__getitem__ passed all tests aviable + I've tested it locally.
Here are my test cases:

import numpy as np
from keras import ops
from keras.src import testing

class GetItemOpsTest(testing.TestCase):
    def test_getitem(self):
        self.np_tensor = np.arange(24).reshape(2, 3, 4)
        self.tensor = ops.convert_to_tensor(self.np_tensor)

        t = self.tensor[1]
        n = self.np_tensor[1]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[1, 2, 3]
        n = self.np_tensor[1, 2, 3]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[1:2]
        n = self.np_tensor[1:2]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[1:2, 2:3, 3:4]
        n = self.np_tensor[1:2, 2:3, 3:4]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[1:2, None]
        n = self.np_tensor[1:2, None]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[1:2, 2:3, ...]
        n = self.np_tensor[1:2, 2:3, ...]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[1:2, ..., 3:4]
        n = self.np_tensor[1:2, ..., 3:4]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[None, ..., 3:4, None]
        n = self.np_tensor[None, ..., 3:4, None]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[1:2:None]
        n = self.np_tensor[1:2:None]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[:, 2]
        n = self.np_tensor[:, 2]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[None]
        n = self.np_tensor[None]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[None, None]
        n = self.np_tensor[None, None]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[...]
        n = self.np_tensor[...]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[..., 1]
        n = self.np_tensor[..., 1]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[..., 1, 2]
        n = self.np_tensor[..., 1, 2]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[..., -1, 2]
        n = self.np_tensor[..., -1, 2]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[..., -1:-2, 2]
        n = self.np_tensor[..., -1:-2, 2]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[..., None, None]
        n = self.np_tensor[..., None, None]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[None, ..., None]
        n = self.np_tensor[None, ..., None]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[1, 2, None, ..., None]
        n = self.np_tensor[1, 2, None, ..., None]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[None, ..., 1, 2]
        n = self.np_tensor[None, ..., 1, 2]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[1, None, 2]
        n = self.np_tensor[1, None, 2]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        index_tensor = ops.convert_to_tensor(np.array(1, dtype=np.int32))
        t = self.tensor[index_tensor]
        n = self.np_tensor[ops.convert_to_numpy(index_tensor)]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        index_tensor = ops.convert_to_tensor(np.array(1, dtype=np.int32))
        t = self.tensor[index_tensor, 2, None]
        n = self.np_tensor[ops.convert_to_numpy(index_tensor), 2, None]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        index_tensor = ops.convert_to_tensor(np.array(-2, dtype=np.int32))
        t = self.tensor[index_tensor, 1]
        n = self.np_tensor[ops.convert_to_numpy(index_tensor), 1]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        index_tensor = ops.convert_to_tensor(np.array(-1, dtype=np.int32))
        t = self.tensor[-2, index_tensor]
        n = self.np_tensor[-2, ops.convert_to_numpy(index_tensor)]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        # Negative indexing
        t = self.tensor[-1]
        n = self.np_tensor[-1]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[1, -1, -2]
        n = self.np_tensor[1, -1, -2]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        # Slicing with step
        t = self.tensor[::2]
        n = self.np_tensor[::2]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        # Mixed slices and integers
        t = self.tensor[1, :, 1:4]
        n = self.np_tensor[1, :, 1:4]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

        t = self.tensor[:, 1:2, 3]
        n = self.np_tensor[:, 1:2, 3]
        self.assertEqual(t.shape, n.shape)
        self.assertTrue(np.array_equal(ops.convert_to_numpy(t), n))

The PR is ready for review.

@codecov-commenter
Copy link

codecov-commenter commented Jun 5, 2025

Codecov Report

Attention: Patch coverage is 81.39535% with 16 lines in your changes missing coverage. Please review.

Project coverage is 82.74%. Comparing base (771b001) to head (58b23f3).
Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
keras/src/backend/openvino/core.py 81.39% 8 Missing and 8 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #21359      +/-   ##
==========================================
+ Coverage   82.70%   82.74%   +0.04%     
==========================================
  Files         565      565              
  Lines       54894    54969      +75     
  Branches     8517     8534      +17     
==========================================
+ Hits        45398    45484      +86     
+ Misses       7415     7397      -18     
- Partials     2081     2088       +7     
Flag Coverage Δ
keras 82.55% <81.39%> (+0.04%) ⬆️
keras-jax 63.48% <0.00%> (-0.09%) ⬇️
keras-numpy 58.64% <0.00%> (-0.08%) ⬇️
keras-openvino 33.79% <81.39%> (+0.26%) ⬆️
keras-tensorflow 63.87% <0.00%> (-0.09%) ⬇️
keras-torch 63.51% <0.00%> (-0.09%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Mohamed-Ashraf273 Mohamed-Ashraf273 force-pushed the update_getitem branch 5 times, most recently from 88938fd to 5043d78 Compare June 5, 2025 22:08
@Mohamed-Ashraf273 Mohamed-Ashraf273 marked this pull request as ready for review June 5, 2025 22:10
@Mohamed-Ashraf273 Mohamed-Ashraf273 marked this pull request as draft June 5, 2025 22:16
@Mohamed-Ashraf273 Mohamed-Ashraf273 marked this pull request as ready for review June 5, 2025 22:40
@Mohamed-Ashraf273 Mohamed-Ashraf273 marked this pull request as draft June 5, 2025 22:49
@Mohamed-Ashraf273 Mohamed-Ashraf273 force-pushed the update_getitem branch 2 times, most recently from e7f4898 to 0ba9c10 Compare June 6, 2025 01:31
@Mohamed-Ashraf273 Mohamed-Ashraf273 marked this pull request as ready for review June 6, 2025 01:32
@Mohamed-Ashraf273 Mohamed-Ashraf273 force-pushed the update_getitem branch 3 times, most recently from d274a50 to 6ddb1b4 Compare June 6, 2025 12:30
@Mohamed-Ashraf273 Mohamed-Ashraf273 marked this pull request as draft June 6, 2025 12:34
@Mohamed-Ashraf273 Mohamed-Ashraf273 force-pushed the update_getitem branch 2 times, most recently from 4a1d931 to 08aebcf Compare June 6, 2025 20:26
@Mohamed-Ashraf273 Mohamed-Ashraf273 marked this pull request as ready for review June 6, 2025 20:27
@rkazants
Copy link
Contributor

rkazants commented Jun 8, 2025

@Mohamed-Ashraf273, can you add your tests to sources as well?

)
if index_type != Type.i32:
index = ov_opset.convert(index, Type.i32).output(0)
shape_tensor = ov_opset.shape_of(data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can specify output type to i32 then you don't need convert below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I do that index = get_ov_output(index, Type.i32) it will not be changed to i.32 based on the implementation of get_ov_ouput:
Screenshot from 2025-06-08 20-14-17

index = ov_opset.select(
is_negative, adjusted_index, index
).output(0)
index_shape = index.get_partial_shape()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

already computed above. Please clean-up your code properly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I computed index_shape = index.get_partial_shape() above to ensure it's less than or equal to 1, else I would terminate early, the second computation, because the select operation can change the shape of index.
Based on this test case:

index_tensor = ops.convert_to_tensor(np.array(1, dtype=np.int32))
t = self.tensor[index_tensor]
n = self.np_tensor[ops.convert_to_numpy(index_tensor)]
self.assertEqual(t.shape, n.shape)

Fails due to the change of len(shape) to 0, and we need to unsqueeze.

@Mohamed-Ashraf273
Copy link
Contributor Author

@Mohamed-Ashraf273, can you add your tests to sources as well?

@rkazants
I added them to /keras/keras/src/ops/core_test.py

@Mohamed-Ashraf273
Copy link
Contributor Author

Hi @rkazants ,
I wanted to follow up and see if there are any updates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants