From ba88fb13ce2d927975916e77bbbfa255a4c6df00 Mon Sep 17 00:00:00 2001
From: "Plamen K. Kosseff" <333840+blackd@users.noreply.github.com>
Date: Tue, 8 Sep 2026 09:44:35 +0300
Subject: [PATCH] fix(diffusers): auto-detect CUDA instead of defaulting to CPU
(#11891)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The device fell back to CPU unless the model config set cuda: true,
while MPS right below was auto-detected — GPU hosts silently rendered
on CPU for any gallery entry missing the flag. Use CUDA whenever torch
reports it available (ROCm builds included), keep cuda: true as an
explicit force, and allow pinning with the device: model option (e.g.
options: ["device:cpu"]). Gallery entries stay untouched.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Plamen K. Kosseff
---
backend/python/diffusers/backend.py | 28 +++++++++++++++-----
backend/python/diffusers/test.py | 20 ++++++++++++++
docs/content/advanced/model-configuration.md | 2 +-
3 files changed, 43 insertions(+), 7 deletions(-)
diff --git a/backend/python/diffusers/backend.py b/backend/python/diffusers/backend.py
index f32187a25..312754a34 100755
--- a/backend/python/diffusers/backend.py
+++ b/backend/python/diffusers/backend.py
@@ -122,6 +122,21 @@ from diffusers.schedulers import (
UniPCMultistepScheduler,
)
+def select_device(request_cuda, device_option, cuda_available, xpu, mps_available):
+ """Pick the pipeline device. An explicit `device:` model option wins;
+ otherwise CUDA is used whenever torch reports it available (ROCm
+ builds included) or the model config forces it with `cuda: true`,
+ keeping the pre-existing XPU/MPS overrides. CPU is the fallback, not
+ the default."""
+ if device_option:
+ return device_option
+ device = "cuda" if (request_cuda or cuda_available) else "cpu"
+ if xpu:
+ device = "xpu"
+ if mps_available:
+ device = "mps"
+ return device
+
def is_float(s):
"""Check if a string can be converted to float."""
try:
@@ -627,12 +642,13 @@ class BackendServicer(backend_pb2_grpc.BackendServicer):
# modify LoraAdapter to be relative to modelFileBase
request.LoraAdapter = os.path.join(request.ModelPath, request.LoraAdapter)
- device = "cpu" if not request.CUDA else "cuda"
- if XPU:
- device = "xpu"
- mps_available = hasattr(torch.backends, "mps") and torch.backends.mps.is_available()
- if mps_available:
- device = "mps"
+ device = select_device(
+ request.CUDA,
+ self.options.pop("device", None),
+ torch.cuda.is_available(),
+ XPU,
+ hasattr(torch.backends, "mps") and torch.backends.mps.is_available(),
+ )
self.device = device
if request.LoraAdapter:
# Check if its a local file and not a directory ( we load lora differently for a safetensor file )
diff --git a/backend/python/diffusers/test.py b/backend/python/diffusers/test.py
index 2922f2a03..f2a07d4e3 100644
--- a/backend/python/diffusers/test.py
+++ b/backend/python/diffusers/test.py
@@ -7,6 +7,7 @@ import time
from unittest.mock import patch, MagicMock
# Import dynamic loader for testing (these don't need gRPC)
+import backend
import diffusers_dynamic_loader as loader
from diffusers import DiffusionPipeline, StableDiffusionPipeline
@@ -425,3 +426,22 @@ class TestGenerateImageOptionsKwargsMerge(unittest.TestCase):
self.assertEqual(pipeline.kwargs["num_inference_steps"], 4)
finally:
os.unlink(dst_path)
+
+
+class TestDeviceSelection(unittest.TestCase):
+ """Unit tests for backend.select_device (no GPU required)."""
+
+ def test_autodetect_cuda(self):
+ self.assertEqual(backend.select_device(False, None, True, False, False), "cuda")
+
+ def test_cpu_fallback(self):
+ self.assertEqual(backend.select_device(False, None, False, False, False), "cpu")
+
+ def test_forced_cuda(self):
+ self.assertEqual(backend.select_device(True, None, False, False, False), "cuda")
+
+ def test_device_option_wins(self):
+ self.assertEqual(backend.select_device(True, "cpu", True, True, True), "cpu")
+
+ def test_mps_overrides(self):
+ self.assertEqual(backend.select_device(False, None, True, False, True), "mps")
diff --git a/docs/content/advanced/model-configuration.md b/docs/content/advanced/model-configuration.md
index b748fca05..d629e1be8 100644
--- a/docs/content/advanced/model-configuration.md
+++ b/docs/content/advanced/model-configuration.md
@@ -739,7 +739,7 @@ For image generation models using the `diffusers` backend:
| Field | Type | Description |
|-------|------|-------------|
-| `diffusers.cuda` | bool | Enable CUDA for diffusers |
+| `diffusers.cuda` | bool | Force CUDA. By default the backend auto-detects and uses CUDA when a compatible GPU is present (ROCm builds included). Pin the CPU with `options: ["device:cpu"]` |
| `diffusers.pipeline_type` | string | Pipeline type (e.g., `stable-diffusion`, `stable-diffusion-xl`) |
| `diffusers.scheduler_type` | string | Scheduler type (e.g., `euler`, `ddpm`) |
| `diffusers.enable_parameters` | string | Comma-separated parameters to enable |