histotuner
GPU UMAP and Clustering on Linux
histotuner installs CPU UMAP support through umap-learn. GPU UMAP is
optional because it depends on the local CUDA driver/toolkit stack and should be
installed separately from the package dependencies in pyproject.toml.
GPU UMAP uses RAPIDS cuML when both cuml and cupy are available in the
active Python environment and a CUDA-capable NVIDIA GPU is visible.
The same optional GPU stack is also used by native clustering:
ht.umap(...)ht.leiden(...)ht.dbscan(...)histotuner-leidenhistotuner-dbscan
Check the active environment from Python:
import histotuner as ht
ht.umap_backend_status()
Expected GPU-ready output has gpu_available: True, with both gpu_cuml and
gpu_cupy set to True.
Recommended install path on Linux is to create a RAPIDS-compatible environment with the official RAPIDS install selector:
https://docs.rapids.ai/install/
For conda/mamba environments, install at least cuml and the matching CUDA
runtime package for your machine. A typical CUDA 12-style command looks like:
mamba create -n histotuner-rapids \
-c rapidsai -c conda-forge -c nvidia \
python=3.12 cuml cuda-version=12.0
mamba activate histotuner-rapids
pip install -e .
For pip-based RAPIDS installs, choose wheels matching the installed CUDA major
version. histotuner now provides an optional extra for a CUDA 12 Linux GPU
stack:
pip install -e ".[linux-gpu]" --extra-index-url=https://pypi.nvidia.com
That extra currently expands to:
pip install cupy-cuda12x cudf-cu12 cugraph-cu12 cuml-cu12 \
--extra-index-url=https://pypi.nvidia.com
If your Linux environment is not CUDA 12 based, use the RAPIDS selector to
generate the correct command for that exact CUDA/RAPIDS combination instead of
the linux-gpu extra.
Then run UMAP with:
ht.umap(
sdata=zarr_path,
tableKeys=["mstar_tokens", "virchow2_tokens"],
sample_n=25000,
prefer_gpu="auto", # uses GPU if RAPIDS is available, otherwise CPU
)
To require GPU and fail loudly if RAPIDS is not available:
ht.umap(
sdata=zarr_path,
tableKeys=["mstar_tokens", "virchow2_tokens"],
sample_n=25000,
prefer_gpu="gpu",
)
Native clustering uses the same prefer_gpu switch:
ht.leiden(
sdata=zarr_path,
tableKeys="tokens",
obsm_key="X_umap",
prefer_gpu="auto",
target_col="leiden",
)
ht.dbscan(
sdata=zarr_path,
tableKeys="tokens",
obsm_key="X_umap",
prefer_gpu="gpu",
target_col="dbscan",
)
CLI examples:
histotuner-leiden /path/to/sample.zarr \
--tables tokens \
--obsm-key X_umap \
--prefer-gpu auto \
--target-col leiden
histotuner-dbscan /path/to/sample.zarr \
--tables tokens \
--obsm-key X_umap \
--prefer-gpu gpu \
--target-col dbscan
Notes:
- RAPIDS requires Linux or WSL2; native Windows Python environments generally cannot install/use cuML, cuGraph, or cuDF directly.
- GPU UMAP uses
cumlpluscupy. - GPU Leiden uses
cudf,cugraph,cuml, andcupy. - GPU DBSCAN uses
cumlpluscupy. - CUDA package suffixes must match the CUDA toolkit/driver stack in the environment. If installation fails, generate a fresh command from the RAPIDS selector for the specific Linux, Python, CUDA, and RAPIDS versions.
Supported token-extraction backends
histotuner can append multiple model-specific token tables into the same
SpatialData Zarr while keeping shared geometry layers model-agnostic.
Currently supported token extractors:
hf-hub:bioptimus/H-optimus-1hf-hub:MahmoodLab/UNI2-hhf-hub:paige-ai/Virchow2hf-hub:Wangyh/mSTARhf-hub:prov-gigapath/prov-gigapathowkin/phikon-v2MahmoodLab/conchv1_5WenchuanZhang/Patho-CLIP-Lmajiabo/GPFMkaiko-ai/vitl14xiangjx/musk
Token-grid semantics
All currently supported models export a unified 14x14 token grid so token
tables can be compared directly across models.
phikon-v2exports a native14x14patch-token grid.hf-hub:bioptimus/H-optimus-1,hf-hub:Wangyh/mSTAR, andhf-hub:prov-gigapath/prov-gigapathexport native14x14grids.hf-hub:MahmoodLab/UNI2-handhf-hub:paige-ai/Virchow2have native16x16patch-token grids after special tokens are stripped, andhistotuneradaptively average-pools them to14x14.conchv1_5is special:- the native vision encoder runs at
448x448withpatch16 - that produces a native
28x28patch-token grid histotuneraverage-pools each non-overlapping2x2token neighborhood to export a compatibility14x14token grid
- the native vision encoder runs at
Patho-CLIP-Lis also special:- the native CLIP-L/14 vision encoder produces a
24x24patch-token grid at336x336input resolution histotuneradaptively average-pools that native24x24grid to export a compatibility14x14token grid
- the native CLIP-L/14 vision encoder produces a
GPFMis also special:- the native DINOv2 ViT-L/14 encoder produces a
16x16patch-token grid at224x224input resolution histotuneradaptively average-pools that native16x16grid to export a compatibility14x14token grid
- the native DINOv2 ViT-L/14 encoder produces a
kaiko-ai/vitl14is also special:- the native Kaiko ViT-L/14 encoder produces a
16x16patch-token grid at224x224input resolution histotuneruses the Kaiko preprocessing defaults (mean=std=0.5) and adaptively average-pools that native16x16grid to export a compatibility14x14token grid
- the native Kaiko ViT-L/14 encoder produces a
xiangjx/muskis also special:- the native MUSK patch16 vision encoder produces a
24x24patch-token grid at384x384input resolution histotuneruses the MUSK preprocessing defaults (mean=std=0.5) and adaptively average-pools that native24x24grid to export a compatibility14x14token grid- MUSK is gated on Hugging Face and requires the optional official
muskpackage
- the native MUSK patch16 vision encoder produces a
That pooling choice is deliberate so downstream single-cell workflows can
consume every supported model through the same 14x14 token layout. For the
pooled models, this is a compatibility semantic rather than the model's native
tokenization:
UNI2-handVirchow2: pooled from native16x16conchv1_5: pooled from native28x28Patho-CLIP-L: pooled from native24x24GPFM: pooled from native16x16kaiko-ai/vitl14: pooled from native16x16xiangjx/musk: pooled from native24x24
Not yet supported for token extraction
- none from the current requested set
O2 batch job generation
To generate one embedder.yaml and one embed_cluster.sh per sample folder on
O2:
python generate_o2_jobs.py \
--root-dir /n/scratch/users/a/ajn16/histotuner/full \
--template-yaml embedder.yaml \
--template-shell embed_cluster.sh \
--output-dir /n/scratch/users/a/ajn16/histotuner/generated_jobs
python generate_o2_jobs.py \
--root-dir /n/scratch/users/a/ajn16/histotuner/heonly \
--template-yaml embedder_HEonly.yaml \
--template-shell embed_cluster_HEonly.sh \
--output-dir /n/scratch/users/a/ajn16/histotuner/generated_jobs
To preview the sbatch submissions for the generated job scripts:
python submit_generated_jobs.py \
--generated-dir /n/scratch/users/a/ajn16/histotuner/generated_jobs \
--dry-run
Melanocyte UMAP/DBSCAN token pipeline
The scripts in o2/melanocyte_dbscan/ find SpatialData .zarr stores under a
folder, map tokens to cells, compute UMAP for native token tables, map broad
phenotype labels onto token tables, and run DBSCAN on X_umap for tokens where
phenotype_broad == "Melanocytes". They then generate thumbnail PDFs for
dbscan_melanocytes_umap using an HE image auto-detected beside each .zarr,
and save two UMAP plots for each token table/model:
dbscan_melanocytes_umap, excluding-1andnanphenotype_broad, excluding-1and0
Run a local dry-run first:
python .\o2\melanocyte_dbscan\run_token_umap_melanocyte_dbscan.py `
"C:\Users\aj\Downloads\test" `
--recursive `
--dry-run
Run the local pipeline and write a summary:
python -u .\o2\melanocyte_dbscan\run_token_umap_melanocyte_dbscan.py `
"C:\Users\aj\Downloads\test" `
--recursive `
--continue-on-error `
--summary-json "C:\Users\aj\Downloads\test\melanocyte_dbscan_summary.json"
The script uses native histotuner token-table selection. By default,
tokenCellMapper and phenotypeCellMapper auto-detect token tables, while UMAP
and DBSCAN use the native tokens selector. Melanocyte DBSCAN uses
--dbscan-min-samples 100 by default. Pass --no-thumbnail-pdfs to skip PDF
generation, or --thumbnail-image-path /path/to/image.ome.tiff to provide an
explicit image for a single-sample run.
Pass --no-umap-plots to skip the saved UMAP plots.
The pipeline runs ht.repairSpatialDataTableRegistry(...) at the start, after
UMAP writes, and after DBSCAN writes so on-disk tables are re-registered before
downstream plotting/PDF steps.
O2 parallel melanocyte DBSCAN jobs
On O2, generate one Slurm script per sample/zarr without submitting:
python o2/melanocyte_dbscan/submit_melanocyte_dbscan_jobs.py \
--root-dir /n/scratch/users/a/ajn16/he_embed \
--output-dir /n/scratch/users/a/ajn16/melanocyte_dbscan_jobs
Submit a single test job:
python o2/melanocyte_dbscan/submit_melanocyte_dbscan_jobs.py \
--root-dir /n/scratch/users/a/ajn16/he_embed \
--output-dir /n/scratch/users/a/ajn16/melanocyte_dbscan_jobs_test \
--limit 1 \
--submit
Submit all jobs:
python o2/melanocyte_dbscan/submit_melanocyte_dbscan_jobs.py \
--root-dir /n/scratch/users/a/ajn16/he_embed \
--output-dir /n/scratch/users/a/ajn16/melanocyte_dbscan_jobs \
--submit
Replace /n/scratch/users/a/ajn16/he_embed with the O2 path containing the
sample folders or .zarr stores. Each submitted job runs the melanocyte DBSCAN
pipeline on one sample folder, so samples run in parallel through Slurm.
Thumbnail PDFs are generated by default in each sample job; pass
--no-thumbnail-pdfs to
o2/melanocyte_dbscan/submit_melanocyte_dbscan_jobs.py to disable them. UMAP
plots are also generated by default; pass --no-umap-plots to disable them.
The submission manifest is written to
/n/scratch/users/a/ajn16/melanocyte_dbscan_jobs/submission_manifest.csv.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file histotuner-0.3.3.tar.gz.
File metadata
- Download URL: histotuner-0.3.3.tar.gz
- Upload date:
- Size: 221.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.8.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a5840a069a15b496abb3d3fb626149273d4617c94ca492138f518f66011f7565
|
|
| MD5 |
3f048e636ea3489fd9b220892d2d3015
|
|
| BLAKE2b-256 |
f15fdfd08800185b49050d54dab6bb4987c47581141ec3f54da56662d4150403
|
File details
Details for the file histotuner-0.3.3-py3-none-any.whl.
File metadata
- Download URL: histotuner-0.3.3-py3-none-any.whl
- Upload date:
- Size: 238.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.8.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
05e28fe4fcbe514c7376e817c5480141af98787c412326bd1b8532708cc50bc2
|
|
| MD5 |
0f2c97c7497ccaa438f60c8bd2058d5b
|
|
| BLAKE2b-256 |
a4ade5cef79b9a581cd3968435ffb56af5224d839cabac2fcb70d024f371a60e
|