Skip to content

Commit bd257b1

Browse files
committed
v0.3.0: Rebuild & Pass tests
1 parent 8d994cd commit bd257b1

File tree

8 files changed

+42
-37
lines changed

8 files changed

+42
-37
lines changed

.github/workflows/build.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
strategy:
1515
fail-fast: false
1616
matrix:
17-
python-version: [ 3.11 ]
17+
python-version: [ "3.10", "3.11", "3.12", "3.13" ]
1818

1919
steps:
2020
- name: Checkout repository
@@ -30,8 +30,9 @@ jobs:
3030
sudo apt update
3131
sudo apt install -y libxml2-utils pandoc
3232
curl -sSL https://install.python-poetry.org | python3 -
33-
pip install --upgrade pip
34-
pip install -e ".[docs, dev]"
33+
curl -LsSf https://astral.sh/uv/install.sh | sh
34+
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
35+
uv pip install -e ".[docs, dev]" --system
3536
install_pyg_dependencies
3637
3738
- name: Build documentation

.github/workflows/release.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ jobs:
2626
sudo apt update
2727
sudo apt install -y libxml2-utils pandoc
2828
curl -sSL https://install.python-poetry.org | python3 -
29-
pip install --upgrade pip
30-
pip install -e ".[docs, dev]"
29+
curl -LsSf https://astral.sh/uv/install.sh | sh
30+
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
31+
uv pip install -e ".[docs, dev]" --system
3132
install_pyg_dependencies
3233
3334
- name: Build documentation

Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ RUN apt-get update \
88
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
99

1010
# Copy DECIPHER package and install
11-
# USER rapids
1211
WORKDIR /app
1312
COPY ./decipher ./decipher
1413
COPY ./README.md ./README.md

decipher/cls.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ def register_data(
9393
self.edge_index = edge_index
9494
np.save(self.work_dir / "edge_index.npy", self.edge_index.numpy())
9595

96+
# Save hyperparameters
97+
OmegaConf.save(CFG, self.work_dir / "hyperparams.yaml")
98+
9699
def fit_sc(self) -> None:
97100
r"""
98101
Fit on single cell data
@@ -133,7 +136,6 @@ def fit_omics(self) -> None:
133136
# save embeddings
134137
np.save(self.work_dir / "center_emb.npy", self.center_emb)
135138
np.save(self.work_dir / "nbr_emb.npy", self.nbr_emb)
136-
OmegaConf.save(CFG, self.work_dir / "hyperparams.yaml")
137139
logger.info(f"Results saved to {self.work_dir}")
138140

139141
def load(self, from_dir: str) -> None:
@@ -170,6 +172,7 @@ def fit_ddp(self, gpus: int = -1) -> None:
170172
max_gpus = torch.cuda.device_count()
171173
assert max_gpus > 1, "DDP requires at least 2 GPUs."
172174
gpus = min(gpus, max_gpus) if gpus > 0 else max_gpus
175+
logger.info(f"Using {gpus} GPUs for DDP training.")
173176

174177
# DDP fit omics
175178
subprocess.run(

decipher/explain/gene/mixin.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
import ray
88
import scanpy as sc
99
import torch
10-
import yaml
1110
from loguru import logger
11+
from omegaconf import OmegaConf
1212
from scanpy._utils import check_nonnegative_integers
1313
from scipy.sparse import issparse
1414
from torch_geometric.data import Batch, Data
@@ -82,8 +82,7 @@ def train_gene_select(
8282
cfg.center_dim = self.center_emb.shape[1]
8383
cfg.nbr_dim = self.nbr_emb.shape[1]
8484
cfg.work_dir = str(work_dir)
85-
with open(work_dir / "gene_select_config.yaml", "w") as f:
86-
yaml.dump(cfg, f)
85+
OmegaConf.save(cfg, work_dir / "gene_select_config.yaml")
8786
logger.debug(f"Gene select config: {cfg}")
8887

8988
# prepare data

decipher/explain/regress/regression.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import pandas as pd
77
import ray
88
import torch
9+
from loguru import logger
910
from omegaconf import OmegaConf
1011
from pytorch_lightning import LightningDataModule, LightningModule
1112
from rui_utils.torch.trainer import fit_and_inference
@@ -126,7 +127,11 @@ def calc_metric(self, pred_y, y):
126127
"test_r2_score": float(r2),
127128
"test_mae_score": float(mae),
128129
}
129-
self.log_dict(self.test_metric, prog_bar=True)
130+
try:
131+
self.log_dict(self.test_metric, prog_bar=True)
132+
except Exception as e: # noqa
133+
logger.error(f"Error logging test metrics: {e}")
134+
print(self.test_metric)
130135

131136

132137
def train_regress(
@@ -173,6 +178,8 @@ def train_regress(
173178
config.trainer.model_dir = str(Path(config.work_dir) / save_dir)
174179
regress_model = DeepRegression(config, test_cell_type)
175180
fit_and_inference(regress_model, data, config.trainer)
181+
if not hasattr(regress_model, "test_metric"):
182+
regress_model.on_test_epoch_end()
176183
test_metric = regress_model.test_metric
177184

178185
metric_path = Path(config.work_dir) / save_dir / "test_metric.json"

pyproject.toml

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ build-backend = "poetry.core.masonry.api"
66
[tool.poetry]
77
name = "cell-decipher"
88
packages = [{include = "decipher"}]
9-
version = "0.2.2"
10-
description = "Spatial-omics data embedding and analysis"
9+
version = "0.3.0"
10+
description = "DECIPHER for learning disentangled cellular embeddings in large-scale heterogeneous spatial omics data"
1111
readme = "README.md"
1212
license = "MIT"
1313
authors = ["Chen-Rui Xia <[email protected]>"]
@@ -25,6 +25,7 @@ classifiers = [
2525
"Programming Language :: Python :: 3.10",
2626
"Programming Language :: Python :: 3.11",
2727
"Programming Language :: Python :: 3.12",
28+
"Programming Language :: Python :: 3.13",
2829
"Topic :: Scientific/Engineering :: Bio-Informatics"
2930
]
3031

@@ -43,13 +44,14 @@ bs4 = "*"
4344
rui_utils = "*"
4445
harmony-pytorch = "*"
4546

46-
torch = ">=2.0"
47+
torch = ">=2.0, <2.9"
4748
torchvision = "*"
4849
torchaudio = "*"
4950
pytorch-lightning = ">=2.1"
5051
torch_geometric = ">=2.3.0"
5152
tensorboard = "*"
5253
einops = "*"
54+
transformers = "*"
5355

5456
sphinx = {version = "<=6.2.1", optional = true}
5557
sphinx-autodoc-typehints = {version = "*", optional = true}
@@ -69,24 +71,18 @@ papermill = {version = "*", optional = true}
6971
jupyter = {version = "*", optional = true}
7072
jupyter_contrib_nbextensions = {version = "*", optional = true}
7173
jupytext = {version = "*", optional = true}
72-
ipykernel = {version = "*", optional = true}
7374
nbformat = {version = "*", optional = true}
7475
pre-commit = {version = "*", optional = true}
7576
black = {version = "*", optional = true}
7677
isort = {version = "*", optional = true}
7778
py-spy = {version = "*", optional = true}
78-
bokeh = {version = "*", optional = true}
79-
datatable = {version = "*", optional = true}
80-
parse = {version = "*", optional = true}
81-
plotly = {version = "*", optional = true}
82-
kaleido = {version = "*", optional = true}
8379

8480
[tool.poetry.extras]
8581
docs = ["sphinx", "sphinx-autodoc-typehints", "sphinx-copybutton", "sphinx-intl",
8682
"nbsphinx", "sphinx-rtd-theme", "sphinx_gallery", "jinja2", "myst-parser"]
8783
dev = ["pytest", "pytest-sugar", "pytest-cov", "pytest-xdist",
88-
"papermill", "jupyter","jupyter_contrib_nbextensions", "ipykernel", "nbformat", "jupytext",
89-
"pre-commit", "black", "isort", "py-spy", "bokeh", "datatable", "parse", "plotly", "kaleido"]
84+
"papermill", "jupyter","jupyter_contrib_nbextensions", "nbformat", "jupytext",
85+
"pre-commit", "black", "isort", "py-spy"]
9086

9187
[tool.pyright]
9288
include = ["decipher"]
@@ -106,8 +102,8 @@ source = ["decipher"]
106102
show_missing = true
107103

108104
[tool.poetry.scripts]
109-
decipher_ddp_sc = "decipher.ddp:decipher_ddp_sc"
110-
decipher_ddp_spatial = "decipher.ddp:decipher_ddp_spatial"
105+
decipher_ddp_sc = "decipher.utils:decipher_ddp_sc"
106+
decipher_ddp_spatial = "decipher.utils:decipher_ddp_spatial"
111107
install_pyg_dependencies = "decipher.utils:install_pyg_dep"
112108

113109
[tool.jupytext]

tests/test_explain.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
import torch
22
from torch_geometric.data import Batch, Data
33

4+
from decipher import CFG
45
from decipher.explain.gene.gene_selection import train_GAE
56
from decipher.explain.regress.mixin import train_regress
6-
from decipher.utils import GENESELECT_CFG, REGRESS_CFG
77

88

99
def test_GAE_mimic():
10-
GENESELECT_CFG.center_dim = 8
11-
GENESELECT_CFG.expr_dim = 100
12-
GENESELECT_CFG.work_dir = "./results/explain"
13-
GENESELECT_CFG.gae_epochs = 2
14-
GENESELECT_CFG.fit.epochs = 2
10+
CFG.gene_select.center_dim = 8
11+
CFG.gene_select.expr_dim = 100
12+
CFG.gene_select.work_dir = "./results/explain"
13+
CFG.gene_select.gae_epochs = 2
1514

1615
N_CELL1 = 100
1716
graph1 = Data(
@@ -27,19 +26,19 @@ def test_GAE_mimic():
2726
expr=torch.randn(N_CELL2, 100),
2827
)
2928
graph_all = Batch.from_data_list([graph1, graph2])
30-
train_GAE(graph1, GENESELECT_CFG, save_dir="test_GAE")
31-
train_GAE(graph_all, GENESELECT_CFG, save_dir="test_GAE_batched")
29+
train_GAE(graph1, CFG.gene_select, save_dir="test_GAE")
30+
train_GAE(graph_all, CFG.gene_select, save_dir="test_GAE_batched")
3231

3332

3433
def test_regress_mimic():
35-
REGRESS_CFG.center_dim = 8
36-
REGRESS_CFG.nbr_dim = 8
37-
REGRESS_CFG.work_dir = "./results/explain"
38-
REGRESS_CFG.fit.epochs = 2
34+
CFG.regress.center_dim = 8
35+
CFG.regress.nbr_dim = 8
36+
CFG.regress.work_dir = "./results/explain"
37+
CFG.regress.trainer.epochs = 2
3938

4039
x = torch.randn(100, 8)
4140
y = torch.randn(100, 8)
42-
train_regress(x, y, REGRESS_CFG, save_dir="test_regress")
41+
train_regress(x, y, CFG.regress, save_dir="test_regress")
4342

4443

4544
if __name__ == "__main__":

0 commit comments

Comments
 (0)