Skip to content
Merged
18 changes: 18 additions & 0 deletions scripts/create_datasets/test_resources.sh
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,24 @@ for name in bmmc_cite/normal bmmc_cite/swap bmmc_multiome/normal bmmc_multiome/s
--output $DATASET_DIR/$name/models/simple_mlp/
fi

# senkin_tmp is CITE-only
if [[ "$name" == bmmc_cite/normal ]]; then
echo "pre-train senkin_tmp on $name"
if up_to_date $DATASET_DIR/$name/models/senkin_tmp/model.pkl $STATE; then
echo " already up to date, skipping"
else
mkdir -p $DATASET_DIR/$name/models/senkin_tmp/
viash run src/methods/senkin_tmp/senkin_tmp_train/config.vsh.yaml -- \
--input_train_mod1 $DATASET_DIR/$name/train_mod1.h5ad \
--input_train_mod2 $DATASET_DIR/$name/train_mod2.h5ad \
--input_test_mod1 $DATASET_DIR/$name/test_mod1.h5ad \
--lgbm_boost_rounds 50 \
--lgbm_early_stopping 10 \
--nn_epochs 2 \
--output $DATASET_DIR/$name/models/senkin_tmp/model.pkl
fi
fi

echo "pre-train novel on $name"
if up_to_date $DATASET_DIR/$name/models/novel/ $STATE; then
echo " already up to date, skipping"
Expand Down
27 changes: 27 additions & 0 deletions src/methods/senkin_tmp/senkin_tmp/config.vsh.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
__merge__: ../../../api/comp_method.yaml
name: senkin_tmp
label: "senkin & tmp"
summary: "LightGBM + bidirectional GRU ensemble for CITE-seq protein prediction (OpenProblems 2022 2nd place)"
description: |
Two-stage method from the OpenProblems NeurIPS 2021 competition. Stage 1 trains four
LightGBM models on different RNA feature representations (log-normalized, CLR-TSVD,
custom sqrt-normalized, and raw counts). Stage 2 refines predictions with two neural
network architectures: a bidirectional GRU with cosine-similarity loss and a dense
bidirectional GRU with MSE loss. Final predictions are a weighted blend (55% cosine,
45% MSE) of per-fold averaged outputs.
references:
doi:
- 10.64898/2026.02.24.707614
links:
repository: https://github.com/lueckenlab/senkin-tmp-cite-pred
info:
preferred_normalization: log_cp10k
resources:
- path: main.nf
type: nextflow_script
entrypoint: run_wf
dependencies:
- name: methods/senkin_tmp_train
- name: methods/senkin_tmp_predict
runners:
- type: nextflow
18 changes: 18 additions & 0 deletions src/methods/senkin_tmp/senkin_tmp/main.nf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
workflow run_wf {
take: input_ch
main:
output_ch = input_ch
| senkin_tmp_train.run(
fromState: ["input_train_mod1", "input_train_mod2", "input_test_mod1"],
toState: ["input_model": "output"]
)
| senkin_tmp_predict.run(
fromState: ["input_test_mod1", "input_train_mod2", "input_model"],
toState: ["output": "output"]
)
| map { tup ->
[tup[0], [output: tup[1].output]]
}

emit: output_ch
}
34 changes: 34 additions & 0 deletions src/methods/senkin_tmp/senkin_tmp_predict/config.vsh.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
__merge__: ../../../api/comp_method_predict.yaml
name: senkin_tmp_predict

info:
test_setup:
with_model:
input_test_mod1: resources_test/task_predict_modality/openproblems_neurips2021/bmmc_cite/normal/test_mod1.h5ad
input_train_mod2: resources_test/task_predict_modality/openproblems_neurips2021/bmmc_cite/normal/train_mod2.h5ad
input_model: resources_test/task_predict_modality/openproblems_neurips2021/bmmc_cite/normal/models/senkin_tmp/model.pkl
resources:
- path: script.py
type: python_script
test_resources:
- path: /resources_test/task_predict_modality/openproblems_neurips2021/bmmc_cite/normal
dest: resources_test/task_predict_modality/openproblems_neurips2021/bmmc_cite/normal
engines:
- type: docker
image: openproblems/base_pytorch_nvidia:1
setup:
- type: docker
run: pip install --no-cache-dir --no-deps git+https://github.com/lueckenlab/senkin-tmp-cite-pred.git
- type: python
packages:
- lightgbm>=4.0
- tensorflow>=2.12
- scikit-learn>=1.1
- mudata>=0.2
- muon>=0.1
- fast-array-utils
runners:
- type: executable
- type: nextflow
directives:
label: [highmem, hightime, midcpu]
41 changes: 41 additions & 0 deletions src/methods/senkin_tmp/senkin_tmp_predict/script.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import logging
import pickle

import anndata as ad
import numpy as np
from scipy.sparse import csc_matrix

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

## VIASH START
par = {
"input_test_mod1": "resources_test/task_predict_modality/openproblems_neurips2021/bmmc_cite/swap/test_mod1.h5ad",
"input_train_mod2": "resources_test/task_predict_modality/openproblems_neurips2021/bmmc_cite/swap/train_mod2.h5ad",
"input_model": "output_model.pkl",
"output": "output_pred.h5ad",
}
meta = {"name": "senkin_tmp"}
## VIASH END

logger.info("Reading input files...")
adata_rna_test = ad.read_h5ad(par["input_test_mod1"])
adata_prot_train = ad.read_h5ad(par["input_train_mod2"])

logger.info("Loading model bundle...")
with open(par["input_model"], "rb") as f:
bundle = pickle.load(f)

logger.info("Writing predictions...")
adata_out = ad.AnnData(
layers={"normalized": csc_matrix(bundle["test_predictions"])},
obs=adata_rna_test.obs,
var=adata_prot_train.var,
uns={
"dataset_id": adata_rna_test.uns.get("dataset_id", bundle.get("dataset_id", "")),
"method_id": "senkin_tmp",
},
)

adata_out.write_h5ad(par["output"], compression="gzip")
logger.info("Predictions saved to %s", par["output"])
51 changes: 51 additions & 0 deletions src/methods/senkin_tmp/senkin_tmp_train/config.vsh.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
__merge__: ../../../api/comp_method_train.yaml
name: senkin_tmp_train
resources:
- path: script.py
type: python_script
arguments:
- name: "--n_folds"
type: integer
default: 5
description: Number of cross-validation folds for LightGBM and neural network training.
- name: "--lgbm_boost_rounds"
type: integer
default: 10000
description: Maximum LightGBM boosting rounds (early stopping applies).
info:
test_default: 50
- name: "--lgbm_early_stopping"
type: integer
default: 100
description: LightGBM early stopping patience (rounds without improvement).
info:
test_default: 10
- name: "--nn_epochs"
type: integer
default: 100
description: Maximum neural network training epochs (early stopping applies).
info:
test_default: 2
- name: "--n_tsvd_components"
type: integer
default: 100
description: TSVD components for reducing LightGBM predictions before NN input.
engines:
- type: docker
image: openproblems/base_pytorch_nvidia:1
setup:
- type: docker
run: pip install --no-cache-dir --no-deps git+https://github.com/lueckenlab/senkin-tmp-cite-pred.git
- type: python
packages:
- lightgbm>=4.0
- tensorflow>=2.12
- scikit-learn>=1.1
- mudata>=0.2
- muon>=0.1
- fast-array-utils
runners:
- type: executable
- type: nextflow
directives:
label: [highmem, hightime, midcpu]
Loading
Loading