Skip to content

Commit f801a5e

Browse files
yinli-systemsKevin-Li-2025virchanogrisel
authored
FIX avoid torch dlpack crash for negative strides (scikit-learn#34380)
Co-authored-by: Kevin-Li-2025 <2242139@qq.com> Co-authored-by: Virgil Chan <virchan.math@gmail.com> Co-authored-by: Olivier Grisel <olivier.grisel@ensta.org>
1 parent f01a3b9 commit f801a5e

3 files changed

Lines changed: 41 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
- Array API supporting functions and estimators that handle mixed input
2+
namespaces now make negative-stride NumPy arrays contiguous before
3+
transferring them to PyTorch through DLPack, avoiding a Python process
4+
abort in ``torch.from_dlpack``.
5+
By :user:`Yin Li <Kevin-Li-2025>`.

sklearn/utils/_array_api.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,13 @@ def move_to(*arrays, xp, device):
580580
if xp == xp_array and device == device_array:
581581
converted_arrays.append(array)
582582
else:
583+
if _is_xp_namespace(xp, "torch") and _is_numpy_namespace(xp_array):
584+
if any(stride < 0 for stride in array.strides):
585+
# Work around PyTorch aborting the process when importing
586+
# negative-strided NumPy arrays with DLPack. Remove this once
587+
# https://github.com/pytorch/pytorch/issues/188023 is fixed.
588+
# See also https://github.com/scikit-learn/scikit-learn/issues/34307
589+
array = numpy.ascontiguousarray(array)
583590
try:
584591
# The dlpack protocol is the future proof and library agnostic
585592
# method to transfer arrays across namespace and device boundaries

sklearn/utils/tests/test_array_api.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
_array_api_for_tests,
5454
_convert_container,
5555
assert_array_equal,
56+
assert_run_python_script_without_output,
5657
skip_if_array_api_compat_not_configured,
5758
)
5859
from sklearn.utils.fixes import _IS_32BIT, CSR_CONTAINERS, np_version, parse_version
@@ -192,6 +193,34 @@ def test_move_to_sparse():
192193
move_to(sparse1, None, xp=xp_torch, device=device_cpu)
193194

194195

196+
def test_move_to_numpy_negative_strides_to_torch():
197+
"""Check NumPy arrays with negative strides can be moved to torch."""
198+
pytest.importorskip("torch")
199+
200+
code = """
201+
import os
202+
203+
os.environ["SCIPY_ARRAY_API"] = "1"
204+
205+
import numpy
206+
from numpy.testing import assert_allclose
207+
208+
from sklearn._config import config_context
209+
from sklearn.utils._array_api import get_namespace_and_device, move_to
210+
211+
import torch
212+
213+
a = numpy.arange(12.0).reshape(3, 4)[:, ::-1]
214+
with config_context(array_api_dispatch=True):
215+
xp, _, device = get_namespace_and_device(torch.asarray([1.0]))
216+
result = move_to(a, xp=xp, device=device)
217+
assert_allclose(result.cpu().numpy(), a)
218+
"""
219+
# This must run in a subprocess because old PyTorch versions abort the
220+
# Python process before a Python exception can be raised.
221+
assert_run_python_script_without_output(code)
222+
223+
195224
@pytest.mark.parametrize("array_api", ["numpy", "array_api_strict"])
196225
def test_asarray_with_order(array_api):
197226
"""Test _asarray_with_order passes along order for NumPy arrays."""

0 commit comments

Comments
 (0)