Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

[![CI](https://github.com/AI4SCR/car-conditional-monge/actions/workflows/ci.yml/badge.svg)](https://github.com/AI4SCR/car-conditional-monge/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![DOI](https://zenodo.org/badge/885465953.svg)](https://doi.org/10.5281/zenodo.17526342)

The conditional Monge Gap applied the single cell RNA sequencing data of Chimeric Antigen Receptor T cells. Extension of the [Conditional Monge Gap](https://github.com/AI4SCR/conditional-monge), to include CAR specific dataloaders, embeddings and trainers. Additionally `notebooks` contains Notebooks for generating the figures of the preprint ... and additional analyses. In the `configs` and `scripts` directories are all scripts to replicate the experiments from this preprint.

The conditional Monge Gap applied the single cell RNA sequencing data of Chimeric Antigen Receptor T cells. Extension of the [Conditional Monge Gap](https://github.com/AI4SCR/conditional-monge), to include CAR specific dataloaders, embeddings and trainers. Additionally `notebooks` contains Notebooks for generating the figures of the preprint and additional analyses. In the `configs` and `scripts` directories are all scripts to replicate the experiments from this preprint.

## Development setup & installation
We use [poetry](https://python-poetry.org/docs/managing-environments/) as package manager and tested the code in Python 3.10.
Expand Down
3 changes: 2 additions & 1 deletion carot/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ def score_transports_and_targets_combinations(all_expr, all_meta):

return scores


def monge_get_source_target_transport(
trainer: "MongeGapTrainer",
datamodule: "AbstractDataModule",
Expand Down Expand Up @@ -268,4 +269,4 @@ def monge_get_source_target_transport(
all_expr = pd.concat(all_expr).reset_index(drop=True)
all_meta = pd.concat(all_meta).reset_index(drop=True)

return all_expr, all_meta
return all_expr, all_meta
3,023 changes: 1,700 additions & 1,323 deletions poetry.lock

Large diffs are not rendered by default.

19 changes: 8 additions & 11 deletions scripts/chemCPA_MMD_and_WD.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from cmonge.evaluate import log_mean_metrics, log_metrics
import jax
import jax.numpy as jnp
from jaxtyping import PRNGKeyArray
import pathlib
import pickle
from typing import Iterator

import jax
import jax.numpy as jnp
import typer
import yaml
from cmonge.evaluate import log_mean_metrics, log_metrics
from jaxtyping import PRNGKeyArray


def format_dict(dict_):
Expand Down Expand Up @@ -50,7 +51,7 @@ def evaluate_condition(
def main(config: str, split: str):

# donors = ["D09", "D17"]
donors = ["D09"] # in case of dummy data
donors = ["D09"] # in case of dummy data
metrics = {}
key = jax.random.key(0)
with open(config, "r") as f:
Expand All @@ -63,9 +64,7 @@ def main(config: str, split: str):

# All drug_dose combis in current OOD results
# chemCPA condition also contains cell line, but we don't use it
current_cars = list(
set([c.split("_")[0] for c in predictions_dict.keys()])
)
current_cars = list(set([c.split("_")[0] for c in predictions_dict.keys()]))

# We gather all cells from same drug-dose combi as in CMonge
for car in current_cars:
Expand Down Expand Up @@ -96,9 +95,7 @@ def main(config: str, split: str):
target_loader = sampler_iter(all_target, batch_size=512, key=k1)
transport_loader = sampler_iter(all_transport, batch_size=512, key=k2)

evaluate_condition(
target_loader, transport_loader, degs_idx, metrics[car]
)
evaluate_condition(target_loader, transport_loader, degs_idx, metrics[car])
log_mean_metrics(metrics[car])

format_dict(metrics[car])
Expand Down
36 changes: 15 additions & 21 deletions scripts/chemCPA_ckpt_to_carot_eval.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
from chemCPA.data import load_dataset_splits

import yaml
import pandas as pd
from pathlib import Path
import pickle
import numpy as np
from pathlib import Path

import numpy as np
import pandas as pd
import scanpy as sc
import torch
import typer
from tqdm.auto import tqdm

import yaml
from chemCPA.data import (
canonicalize_smiles,
drug_names_to_once_canon_smiles,
load_dataset_splits,
)
from chemCPA.embedding import get_chemical_representation
from chemCPA.model import ComPert
from chemCPA.paths import CHECKPOINT_DIR
from chemCPA.train import bool2idx, compute_prediction, repeat_n

from cmonge.metrics import average_r2, compute_scalar_mmd, wasserstein_distance
from tqdm.auto import tqdm

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

Expand All @@ -47,7 +44,6 @@ def load_smiles(dataset, key_dict):
drugs_names_unique_sorted = np.array(sorted(drugs_names_unique))
canon_smiles_unique_sorted = drugs_names_unique_sorted


return canon_smiles_unique_sorted


Expand All @@ -69,11 +65,11 @@ def load_model(config, canon_smiles_unique_sorted, checkpoint_dir=CHECKPOINT_DIR
if len(dumped_model) == 3:
print("This model does not contain the covariate embeddings or adversaries.")
state_dict, init_args, history = dumped_model
COV_EMB_AVAILABLE = False
cov_emb_available = False
elif len(dumped_model) == 4:
print("This model does not contain the covariate embeddings.")
state_dict, cov_adv_state_dicts, init_args, history = dumped_model
COV_EMB_AVAILABLE = False
cov_emb_available = False
elif len(dumped_model) == 5:
(
state_dict,
Expand All @@ -82,7 +78,7 @@ def load_model(config, canon_smiles_unique_sorted, checkpoint_dir=CHECKPOINT_DIR
init_args,
history,
) = dumped_model
COV_EMB_AVAILABLE = True
cov_emb_available = True
assert len(cov_emb_state_dicts) == 1
append_layer_width = (
config["dataset"]["n_vars"]
Expand All @@ -99,7 +95,7 @@ def load_model(config, canon_smiles_unique_sorted, checkpoint_dir=CHECKPOINT_DIR
device=device,
)
model = model.eval()
if COV_EMB_AVAILABLE:
if cov_emb_available:
for embedding_cov, state_dict_cov in zip(
model.covariates_embeddings, cov_emb_state_dicts
):
Expand Down Expand Up @@ -142,14 +138,14 @@ def compute_pred(
dosages=[1e4],
cell_lines=None,
genes_control=None,
use_DEGs=True,
use_degs=True,
verbose=True,
):
# dataset.pert_categories contains: 'celltype_perturbation_dose' info
pert_categories_index = pd.Index(dataset.pert_categories, dtype="category")

cl_dict = {
torch.Tensor([1, 0 ]): "D09",
torch.Tensor([1, 0]): "D09",
torch.Tensor([0, 1]): "D17",
}

Expand Down Expand Up @@ -250,7 +246,7 @@ def compute_pred(

mean_pred = mean_pred.cpu().numpy()
y_true = y_true.cpu().numpy()
if use_DEGs:
if use_degs:
drug_r2[cell_drug_dose_comb] = average_r2(
y_true[:, idx_de], mean_pred[:, idx_de]
)
Expand All @@ -270,9 +266,7 @@ def main(config_path, split):
cell_lines = ["D09", "D17"]
dataset, key_dict = load_dataset(config)
config["dataset"]["n_vars"] = dataset.n_vars
canon_smiles_unique_sorted = load_smiles(
dataset, key_dict
)
canon_smiles_unique_sorted = load_smiles(dataset, key_dict)

# Load dataset
data_params = config["dataset"]["data_params"]
Expand All @@ -294,7 +288,7 @@ def main(config_path, split):
genes_control=datasets["test_control"].genes,
dosages=dosages,
cell_lines=cell_lines,
use_DEGs=True,
use_degs=True,
verbose=True,
)

Expand Down
20 changes: 13 additions & 7 deletions scripts/create_chemCPA_model_per_car_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ def change_and_save_configs(
cars = [car.rstrip() for car in cars]

for car in cars:
config = base_config.copy()
config["dataset"]["data_params"]["dataset_path"]= adata_path
config = base_config.copy()
config["dataset"]["data_params"]["dataset_path"] = adata_path
config["dataset"]["data_params"]["split_key"] = f"{car}_ID"

exp_path = f"{exp_base_dir}/{car}/"
try:
os.makedirs(exp_path)
Expand All @@ -42,15 +42,21 @@ def change_and_save_configs(


if __name__ == "__main__":
data_name = "CD4" # CD4, CD8
base_config_path = Path(f"/Users/alicedriessen/Projects/car-conditional-monge/configs/chemCPA_{data_name}_ID_config_dummy_donor.yml")
data_name = "CD4" # CD4, CD8
base_config_path = Path(
f"/Users/alicedriessen/Projects/car-conditional-monge/configs/chemCPA_{data_name}_ID_config_dummy_donor.yml"
)
configs_save_path = Path(
f"/Users/alicedriessen/Projects/car-conditional-monge/configs/chemCPA_per_car/{data_name}/",
)

exp_base_dir = Path(f"/Users/alicedriessen/Box/LegacyFromOldColleagues/Alice/CAR_Tcells/Model/chemCPA/model_per_car/{data_name}")
exp_base_dir = Path(
f"/Users/alicedriessen/Box/LegacyFromOldColleagues/Alice/CAR_Tcells/Model/chemCPA/model_per_car/{data_name}"
)
adata_path = f"/Users/alicedriessen/Box/LegacyFromOldColleagues/Alice/CAR_Tcells/Model/OT/{data_name}_chemCPA_anno.h5ad"
car_variants = Path("/Users/alicedriessen/Box/LegacyFromOldColleagues/Alice/CAR_Tcells/Model/OT/CAR_variants.txt")
car_variants = Path(
"/Users/alicedriessen/Box/LegacyFromOldColleagues/Alice/CAR_Tcells/Model/OT/CAR_variants.txt"
)

for d in [configs_save_path, exp_base_dir]:
try:
Expand Down
4 changes: 2 additions & 2 deletions scripts/train_chemCPA.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pickle
import yaml

import typer
import yaml
from chemCPA.experiments_run import ExperimentWrapper


Expand All @@ -13,7 +14,6 @@ def main(config_path):
) as f:
args = yaml.safe_load(f)


exp.seed = 1337
# loads the dataset splits
exp.init_dataset(**args["dataset"])
Expand Down
4 changes: 3 additions & 1 deletion scripts/train_ood_car.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ def train_conditional_monge(config_path: Path):
data = config.data.file_path.split("/")[-1][:-5]
embed = config.model.embedding.name
car = ""
logger_path = Path(f"/Users/alicedriessen/Box/CAR_Tcells/Model/conditional-monge/experiments/cmonge_ood/41BB_OOD/{data}/logs.yml")
logger_path = Path(
f"/Users/alicedriessen/Box/CAR_Tcells/Model/conditional-monge/experiments/cmonge_ood/41BB_OOD/{data}/logs.yml"
)
logger.info(f"Experiment: Leaving {config.ood_condition.conditions} out")

datamodule = ConditionalDataModule(config.data, config.condition, config.ae)
Expand Down