Skip to content

ot.sliced.expected_sliced_plan fails on pytorch CUDA tensors #845

Description

@tvercaut

Describe the bug

ot.sliced.expected_sliced_plan() fails when inputs are PyTorch tensors on a CUDA device. The function appears to compute the transport plan on CUDA, but subsequently multiplies it with a distance matrix created on CPU, resulting in a device mismatch error.

To Reproduce

!pip install torch POT

import torch, ot
import sys, traceback

print(f"PyTorch Version: {torch.__version__}")
print(f"CUDA Available: {torch.cuda.is_available()}")
if torch.cuda.is_available():
    print(f"GPU Device: {torch.cuda.get_device_name(0)}")
print(f"POT Version: {ot.__version__}")

device = torch.device("cuda")
#device = torch.device("cpu")
X = torch.randn(4, 2, device=device)
w = torch.rand(4, device=device)
w = w / w.sum()
try:
  plan, cost = ot.sliced.expected_sliced_plan(X, X, n_projections=1)
except RuntimeError as e:
  print(f"\nexpected_sliced_plan with no weights failed:")
  traceback.print_exc(file=sys.stdout)
try:
  plan, cost = ot.sliced.expected_sliced_plan(X, X, w, w, n_projections=1, dense=False)
except RuntimeError as e:
  print(f"\nexpected_sliced_plan with dense=False failed:")
  traceback.print_exc(file=sys.stdout)
try:
  plan, cost = ot.sliced.expected_sliced_plan(X, X, w, w, n_projections=1, dense=True)
except RuntimeError as e:
  print(f"\nexpected_sliced_plan with dense=True failed:")
  traceback.print_exc(file=sys.stdout)

leads to

PyTorch Version: 2.11.0+cu128
CUDA Available: True
GPU Device: Tesla T4
POT Version: 0.9.7.post1

expected_sliced_plan with no weights failed:
Traceback (most recent call last):
  File "/tmp/ipykernel_757/207733201.py", line 18, in <cell line: 0>
    plan, cost = ot.sliced.expected_sliced_plan(X, X, n_projections=1)
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/ot/sliced/_sliced_plans.py", line 509, in expected_sliced_plan
    cost = nx.sum(plan * dist(X_s, X_t, metric=metric, p=p))
                  ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!

expected_sliced_plan with dense=False failed:
Traceback (most recent call last):
  File "/tmp/ipykernel_757/207733201.py", line 23, in <cell line: 0>
    plan, cost = ot.sliced.expected_sliced_plan(X, X, w, w, n_projections=1, dense=False)
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/ot/sliced/_sliced_plans.py", line 511, in expected_sliced_plan
    cost = plan.multiply(dist(X_s, X_t, metric=metric, p=p)).sum()
           ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: mul: expected 'out' to be CUDA, but got CPU

expected_sliced_plan with dense=True failed:
Traceback (most recent call last):
  File "/tmp/ipykernel_757/207733201.py", line 28, in <cell line: 0>
    plan, cost = ot.sliced.expected_sliced_plan(X, X, w, w, n_projections=1, dense=True)
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/dist-packages/ot/sliced/_sliced_plans.py", line 509, in expected_sliced_plan
    cost = nx.sum(plan * dist(X_s, X_t, metric=metric, p=p))
                  ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!

Additional context

The issue occurs for the different cases I tried:

  • implicit uniform weights,
  • explicit weights with dense=True,
  • explicit weights with dense=False.

The transport plan itself appears to be generated successfully. The failure apparently happens during the final cost computation due to mixed CPU/CUDA tensors.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions