From e1c095e72dd5d11ba72c15d6fb5bd0a6943c1f9b Mon Sep 17 00:00:00 2001 From: TroyHernandez Date: Sun, 2 Aug 2026 23:57:19 -0500 Subject: [PATCH] Survive torch installed without lantern win-builder R-devel failed 0.2.2 with two errors, both "Lantern is not loaded": * the auto-detect branch of the auto_devices() example * test_resident.R Root cause is one line in .detect_vram(). When nvidia-smi is absent it falls back to torch::cuda_is_available(), which ERRORS rather than returning FALSE when torch is installed without its lantern binaries. That is exactly the state win-builder and CRAN are in, and exactly the branch they land in, since those machines have no nvidia-smi either. is_blackwell_gpu() has guarded this since it was written, and the comment there says why; .detect_vram() never did. It now probes through tryCatch() the same way, which fixes auto_devices(), sdxl_memory_profile() and recommend() together, since all three route through it. test_resident.R built real nn_modules at top level with no lantern guard. The torch-dependent sections (component discovery, the dtype table, the CUDA round trip) now sit behind one, and the pure-R sections -- state machine, transition guards, status, print, unload -- still run on CRAN, where they are the parts that can run. Why the local Windows check missed it: windows-hr has lantern installed on both R 4.6.0 and R-devel, so cuda_is_available() returns FALSE there cleanly and the fallback behaved. cran-comments.md claimed that box ran "without its lantern backend", which was simply untrue and is corrected here. The box is not a proxy for CRAN on this axis. It is reproducible locally, which is the durable fix: TORCH_HOME=$(mktemp -d) Rscript --vanilla -e \ 'library(diffuseR); library(tinytest); run_test_dir("inst/tinytest")' An empty TORCH_HOME makes torch_is_installed() FALSE and cuda_is_available() throw, matching win-builder. Under it the five previously-failing examples pass and 271 assertions run green, the rest skipping as intended. --- R/vram.R | 9 +++++++-- cran-comments.md | 12 ++++++++---- inst/tinytest/test_resident.R | 15 ++++++++++++++- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/R/vram.R b/R/vram.R index bdaf55a..b9fa9ab 100644 --- a/R/vram.R +++ b/R/vram.R @@ -58,8 +58,13 @@ is_blackwell_gpu <- function() { return(mb / 1024) } - # Fallback: check if CUDA available but can't determine VRAM - if (torch::cuda_is_available()) { + # Fallback: check if CUDA available but can't determine VRAM. + # cuda_is_available() ERRORS (not FALSE) when torch is installed + # without its lantern binaries - fresh installs, win-builder, CRAN - + # and this branch is exactly where those machines land, since they + # have no nvidia-smi either. Probe soft, same as is_blackwell_gpu(). + if (isTRUE(tryCatch(torch::cuda_is_available(), + error = function(e) FALSE))) { # Conservative estimate - assume 8GB if we can't detect message("Could not detect VRAM via nvidia-smi; assuming 8 GB.") return(8) diff --git a/cran-comments.md b/cran-comments.md index 56e88df..d9c6ccd 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -18,9 +18,11 @@ addressed: ## Test environments * Ubuntu 24.04 (local), R 4.6.x: R CMD check --as-cran -* Windows 10, R 4.6.0 (full test suite against installed torch backend) -* Windows 10, R-devel, torch installed without its lantern backend - (tests skip gracefully) +* Windows 10, R 4.6.0 and R-devel: R CMD check --as-cran, with torch's + lantern backend installed (so the full suite runs) +* Ubuntu, with lantern deliberately absent, to exercise the path + win-builder and CRAN take: examples and tests skip gracefully rather + than erroring * win-builder, R-devel ## R CMD check results @@ -71,4 +73,6 @@ package. under tools::R_user_dir("diffuseR", "data"). * torch is in Imports; all tests, examples, and vignette code degrade gracefully when torch's backend (lantern) is not installed, as on - win-builder. + win-builder. Note that `torch::cuda_is_available()` raises an error + rather than returning FALSE in that state, so the package probes it + through `tryCatch()` everywhere it is reachable without a GPU. diff --git a/inst/tinytest/test_resident.R b/inst/tinytest/test_resident.R index 59890a6..4fb0623 100644 --- a/inst/tinytest/test_resident.R +++ b/inst/tinytest/test_resident.R @@ -19,8 +19,19 @@ fake_pipeline <- function() { class = "test_pipeline") } +# Everything from here to the "state machine" section builds real +# nn_modules or torch dtypes, so it needs a working lantern. torch +# installed WITHOUT its lantern binaries is the normal state on +# win-builder and CRAN, and there `torch::nn_linear()` errors rather +# than returning. The state-machine sections below are pure R and run +# everywhere. +have_torch <- requireNamespace("torch", quietly = TRUE) && + torch::torch_is_installed() + # --- component discovery ---------------------------------------------------------- +if (have_torch) { + pipe <- fake_pipeline() comps <- diffuseR:::.resident_components(pipe) expect_equal(sort(names(comps)), c("decoder", "text_encoder", "transformer")) @@ -40,6 +51,8 @@ expect_equal(diffuseR:::.dtype_bytes(torch::torch_bfloat16()), 2) expect_equal(diffuseR:::.dtype_bytes(torch::torch_uint8()), 1) expect_equal(diffuseR:::.dtype_bytes(torch::torch_int64()), 8) +} # end have_torch + # --- byte formatting -------------------------------------------------------------- expect_equal(diffuseR:::.fmt_gb(0), "0 GB") @@ -140,7 +153,7 @@ expect_equal(resident_status(u)$state, "unloaded") # --- CUDA round trip -------------------------------------------------------------- -if (at_home() && torch::cuda_is_available()) { +if (have_torch && at_home() && torch::cuda_is_available()) { pipe <- fake_pipeline() staging <- diffuseR:::.resident_pin(pipe, verbose = FALSE) expect_equal(sort(names(staging)),