From 339660194bcf433b8e073d5a9ebdd803b213801a Mon Sep 17 00:00:00 2001 From: hz Date: Sun, 3 May 2026 01:45:46 +0000 Subject: [PATCH] release(0.1.19): pin torch<2.11, add GPU-compat self-check, expand CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit torch 2.11 dropped Volta (V100, CC 7.0) and Pascal (P100/GTX 10xx, CC 6.x) from its default cu128/cu129 wheels. With the previous <3 upper bound, `pip install scmidas` on those GPUs would silently install a broken torch — the first CUDA op would raise "no kernel image is available" from somewhere deep in the user's training loop. This patch: * tightens the upper bound to torch<2.11 (matching torchvision<0.26 and torchaudio<2.11) so default installs work on Volta/Pascal too; * adds a one-time GPU self-check at import that translates the cryptic CUDA error into actionable advice (downgrade torch or use cu126); * expands the CI matrix to test the new upper bound (torch 2.10 in place of the previous experimental "torch latest" job). --- .github/workflows/test.yml | 37 ++++++++++++++++++++++++++++++++----- docs/source/release.md | 26 ++++++++++++++++++++++++++ pyproject.toml | 19 ++++++++++--------- src/scmidas/__init__.py | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 14 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4ec5bea..3b66861 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,11 +7,38 @@ on: jobs: test: + name: ${{ matrix.label }} / py${{ matrix.python-version }} runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental }} strategy: fail-fast: false matrix: - python-version: ["3.10", "3.11", "3.12"] + include: + # Lower bound — pinned torch 2.5.1 across all supported Python versions. + - python-version: "3.10" + label: "torch 2.5" + torch-pip-args: "torch==2.5.1+cpu torchvision==0.20.1+cpu torchaudio==2.5.1+cpu" + experimental: false + - python-version: "3.11" + label: "torch 2.5" + torch-pip-args: "torch==2.5.1+cpu torchvision==0.20.1+cpu torchaudio==2.5.1+cpu" + experimental: false + - python-version: "3.12" + label: "torch 2.5" + torch-pip-args: "torch==2.5.1+cpu torchvision==0.20.1+cpu torchaudio==2.5.1+cpu" + experimental: false + # Verified — torch 2.8 was validated end-to-end in the mosaic DDP path + # (1000-epoch run, UMAP and numerics consistent with single-GPU baseline). + - python-version: "3.12" + label: "torch 2.8" + torch-pip-args: "torch==2.8.* torchvision==0.23.* torchaudio==2.8.*" + experimental: false + # Upper bound — torch 2.10 is the latest within our <2.11 cap. + # 2.11 was excluded because its default CUDA wheels dropped Volta/Pascal. + - python-version: "3.12" + label: "torch 2.10" + torch-pip-args: "torch==2.10.* torchvision==0.25.* torchaudio==2.10.*" + experimental: false steps: - uses: actions/checkout@v4 @@ -25,15 +52,15 @@ jobs: - name: Install torch (CPU build) run: | python -m pip install --upgrade pip - pip install \ - torch==2.5.1+cpu \ - torchvision==0.20.1+cpu \ - torchaudio==2.5.1+cpu \ + pip install ${{ matrix.torch-pip-args }} \ --index-url https://download.pytorch.org/whl/cpu - name: Install scmidas with dev extras run: pip install -e ".[dev]" + - name: Show installed torch + run: python -c "import torch; print('torch', torch.__version__)" + - name: Lint (non-blocking) run: ruff check . || true diff --git a/docs/source/release.md b/docs/source/release.md index 7a94863..db296e3 100644 --- a/docs/source/release.md +++ b/docs/source/release.md @@ -6,6 +6,32 @@ All notable changes to this project will be documented in this file. ## Version 0.1.x +### v0.1.19 (2026-05-03) +* **📦 Packaging — narrow torch upper bound to `<2.11`** + * torch 2.11 dropped Volta (V100, CC 7.0) and Pascal (P100, GTX + 10xx, CC 6.x) from its default `cu128` / `cu129` wheels (to + ship cuDNN 9.15.1, which is incompatible with those archs). On + those GPUs `pip install scmidas==0.1.18` would silently install + a torch that fails at the first CUDA op with + `no kernel image is available for execution on the device`. + * The pin now reads `torch>=2.5,<2.11` (with matching + `torchvision<0.26` / `torchaudio<2.11`). Users on + Ampere/Hopper/Ada/Blackwell GPUs can manually upgrade past the + cap; users on Volta/Pascal stay on a working default install. + * No source-code change — same scmidas as 0.1.18. +* **✨ Enhancements** + * `import scmidas` now runs a one-time GPU self-check: if the + local torch wheel has no kernels for the local GPU, scmidas + emits a `UserWarning` with actionable guidance (downgrade torch + or use the cu126 wheel) instead of the user later seeing a raw + `no kernel image is available` error from somewhere deep in + their training loop. The check no-ops on CPU-only environments + and on working GPU setups. +* **⚙️ CI** + * Test matrix gained a `torch 2.10` job (the new upper bound) and + dropped the previous experimental `torch latest` job. Lower + bound remains `torch 2.5.1` across Python 3.10 / 3.11 / 3.12. + ### v0.1.18 (2026-05-02) * **🐛 Bug Fixes (DDP + mosaic data)** * Default `sampler_type='auto'` now picks the DDP sampler when a diff --git a/pyproject.toml b/pyproject.toml index c69b1cc..5d3e54c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "scmidas" -version = '0.1.18' +version = '0.1.19' description = "A torch-based integration method for single-cell multi-omic data." readme = "README.md" requires-python = ">=3.10" @@ -26,14 +26,15 @@ classifiers = [ # --- Runtime dependencies (minimal but complete for your current imports) --- dependencies = [ # PyTorch. - # The previous <2.6 cap was a workaround for a suspected Lightning - # DDP incompatibility, but torch 2.8 has since been verified end-to-end - # in the mosaic DDP path (UMAP / numerics consistent with single-GPU). - # Keeping a major-version cap (<3) so a hypothetical breaking 3.x - # release does not silently land for users. - "torch>=2.5,<3", - "torchvision>=0.20,<1", - "torchaudio>=2.5,<3", + # Upper bound is <2.11 because torch 2.11 dropped Volta (V100, CC 7.0) + # and Pascal (P100, GTX 10xx, CC 6.x) from its CUDA 12.8/12.9 wheels + # to ship cuDNN 9.15.1 (which is incompatible with those archs). + # On those GPUs, `pip install scmidas` would silently install a torch + # that fails at the first CUDA op with "no kernel image is available". + # Newer-GPU users (Ampere+) can manually upgrade past this cap. + "torch>=2.5,<2.11", + "torchvision>=0.20,<0.26", + "torchaudio>=2.5,<2.11", # Lightning (uses lightning.pytorch.utilities.rank_zero_only) "lightning>=2.4,<2.7", diff --git a/src/scmidas/__init__.py b/src/scmidas/__init__.py index bffb34d..e79d49e 100644 --- a/src/scmidas/__init__.py +++ b/src/scmidas/__init__.py @@ -10,3 +10,36 @@ except PackageNotFoundError: __version__ = '0.0.0+unknown' del PackageNotFoundError, _pkg_version + + +def _check_gpu_compat(): + # torch 2.11 dropped Volta (V100, CC 7.0) and Pascal (P100/GTX 10xx, + # CC 6.x) from its default cu128/cu129 wheels. On those GPUs the first + # CUDA op raises "no kernel image is available" — translate that here. + try: + import warnings + import torch + if not torch.cuda.is_available(): + return + try: + (torch.zeros(1, device='cuda') + 1).cpu() + except Exception as e: + if 'no kernel image is available' not in str(e): + return + major, minor = torch.cuda.get_device_capability() + warnings.warn( + f"torch {torch.__version__} has no CUDA kernels for your GPU " + f"({torch.cuda.get_device_name(0)}, compute capability " + f"{major}.{minor}). torch 2.11+ dropped Volta/Pascal from its " + f"default cu128/cu129 wheels. Fix: " + f"pip install 'torch<2.11' 'torchvision<0.26' 'torchaudio<2.11' " + f"or use the cu126 wheel via " + f"--index-url https://download.pytorch.org/whl/cu126", + UserWarning, stacklevel=2, + ) + except Exception: + pass + + +_check_gpu_compat() +del _check_gpu_compat