Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Handle native backend tensors in data adapters - #23596

Open
samudraneel05 wants to merge 5 commits into
keras-team:pluggable_backendfrom
samudraneel05:native-array-data-adapter
Open

Handle native backend tensors in data adapters#23596
samudraneel05 wants to merge 5 commits into
keras-team:pluggable_backendfrom
samudraneel05:native-array-data-adapter

Conversation

@samudraneel05

Copy link
Copy Markdown
Contributor

as suggested by @hertschuh in keras-team/keras-mlx#40

Description

the data adapters should handle native arrays where is_tensor(x) is true, rather than relying on a keras-mlx workaround that converts the full dataset to numpy.

Pluggable backend tensors (e.g. MLX arrays) are rejected by the array data adapter. can_slice_array() and convert_to_sliceable() check for numpy, TF, JAX, torch, pandas, scipy, and __array__, but MLX intentionally dropped __array__ in favor of the Python Buffer Protocol (ml-explore/mlx#323). So MLX arrays fall through every check and model.fit/evaluate/predict crashes.

Fix

added ops.is_tensor(x) as a fallback in both can_slice_array() and convert_to_sliceable(). For the sliceable representation, using np.asarray(x) to get a zero-copy numpy view. falling back to ops.convert_to_numpy(x) when np.asarray raises (e.g. MLX bfloat16, which fails the buffer protocol) or silently wraps the input in a 0-D object array (e.g. openvino tensors, which don't expose __array__ or the buffer protocol).

Contributor Agreement

Please review our AI-Assisted Contribution Policy and check all boxes below before submitting your PR for review:

  • I am a human, and not a bot.
  • I will be responsible for responding to review comments in a timely manner.
  • I will work with the maintainers to push this PR forward until submission.

Note: Failing to adhere to this agreement may result in your future PRs no longer being reviewed.

Add ops.is_tensor(x) fallback to can_slice_array and
convert_to_sliceable so pluggable backend tensors (e.g. MLX)
are accepted by the array data adapter. Uses np.asarray for
zero-copy views via the buffer protocol, falling back to
ops.convert_to_numpy for dtypes numpy can't handle directly
(e.g. MLX bfloat16).

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for slicing pluggable backend tensors (such as MLX) by checking if the input is a tensor and converting it to a NumPy array. However, the current implementation uses ops.is_tensor(x), which will raise an AttributeError because is_tensor is not exported by keras.src.ops. It is recommended to use backend.is_tensor(x) instead, which is already imported and available.

Comment thread keras/src/trainers/data_adapters/array_slicing.py Outdated
Comment thread keras/src/trainers/data_adapters/array_slicing.py Outdated
@codecov-commenter

codecov-commenter commented Sep 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 70.00000% with 9 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (pluggable_backend@79a49f9). Learn more about missing BASE report.

Files with missing lines Patch % Lines
...s/src/trainers/data_adapters/array_data_adapter.py 28.57% 5 Missing ⚠️
keras/src/trainers/data_adapters/array_slicing.py 85.00% 2 Missing and 1 partial ⚠️
keras/src/trainers/data_adapters/data_adapter.py 50.00% 1 Missing ⚠️
Additional details and impacted files
@@                 Coverage Diff                  @@
##             pluggable_backend   #23596   +/-   ##
====================================================
  Coverage                     ?   83.98%           
====================================================
  Files                        ?      458           
  Lines                        ?    62472           
  Branches                     ?    10609           
====================================================
  Hits                         ?    52469           
  Misses                       ?     7329           
  Partials                     ?     2674           
Flag Coverage Δ
keras 83.81% <66.66%> (?)
keras-cpu 83.81% <66.66%> (?)
keras-jax 65.58% <56.66%> (?)
keras-numpy 61.06% <53.33%> (?)
keras-tensorflow 67.46% <53.33%> (?)
keras-torch 66.78% <63.33%> (?)

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

☔ View full report in Codecov by Harness.
📢 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.

@hertschuh hertschuh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for working on this!

CC @MarcosAsh

Comment thread keras/src/trainers/data_adapters/array_slicing.py Outdated
Comment thread keras/src/trainers/data_adapters/array_slicing.py Outdated
@samudraneel05

Copy link
Copy Markdown
Contributor Author

i added three tests.

one checks that adapters without a native iterator fall back to the numpy iterator, one checks that native arrays remain native across regular and shuffled batching, and one checks the conversion methods on nativearraysliceable. the small fake array is there so the generic pluggable backend path can be tested in keras without depending on mlx or another backend package.

once this goes through, the tests on keras-team/keras-mlx#57 should turn green too.

also added the target backend in (None, "numpy"): condition so native sliceables are only used by the native and numpy iterator paths (jax tests were failing otherwise due to nativearraysliceable being selected by the jax iterator)

@hertschuh hertschuh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Did you get a chance to test that it works with the MLX backend?

Comment thread keras/src/trainers/data_adapters/array_slicing.py Outdated
Comment thread keras/src/trainers/data_adapters/array_slicing.py Outdated
Comment thread keras/src/trainers/data_adapters/array_data_adapter_test.py Outdated
Comment thread keras/src/trainers/data_adapters/array_data_adapter_test.py Outdated
Comment thread keras/src/trainers/data_adapters/array_data_adapter_test.py Outdated
@samudraneel05

Copy link
Copy Markdown
Contributor Author

removed the mock tests and made the torch related changes. previously for the NativeArraySliceable I was using convert_to_tensor(), which works perfectly fine with MLX but crashes on torch because it put indices on the active device (mps) while the input stayed on cpu.

since torch tensors will now use NativeArraySliceablei've now gone for the indices.tolist() approach as that works for both without any significant slowdown.

i hope this approach makes sense.

@MarcosAsh

Copy link
Copy Markdown
Contributor

Ran it against keras-mlx#57 on Apple silicon with the CI config, mlx 0.31.2: full keras suite 12938 passed, 0 failed. Trainers and callbacks also pass with compile on. Works for MLX.

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.

5 participants