From 0b057f014f94dc86c86d8c8b0877802ce7687d2e Mon Sep 17 00:00:00 2001 From: Robrecht Cannoodt Date: Tue, 29 Sep 2026 18:54:09 +0200 Subject: [PATCH 1/2] Guard novel LSI against empty cells --- CHANGELOG.md | 2 ++ src/methods/novel/helper_functions.py | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cf2a082..78934869 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -112,6 +112,8 @@ * `senkin_tmp_train`, `senkin_tmp_predict`: Store the model bundle (the test predictions, as the solution is transductive) as an h5ad file in a directory instead of a pickle. The train image is built from `nvidia/cuda` with the current pandas 3, the predict image `openproblems/base_pytorch_nvidia:1` ships pandas 2, and unpickling the bundled `var` DataFrame raised `NotImplementedError` in `NDArrayBacked.__setstate__`, so senkin_tmp finished both CITE training runs of run_2026-09-23 but never produced a prediction. The predict step still reads the old pickle until the test resources are regenerated (PR #73). +* `novel`: Guard the TF-IDF and LSI of the ATAC input against cells without counts in the selected peaks. These turned into NaN, so the validation loss never improved, no model was saved and `novel_predict` failed with a missing `tensor.pt` on the multiome swap datasets. + # task_predict_modality 0.1.1 ## NEW FUNCTIONALITY diff --git a/src/methods/novel/helper_functions.py b/src/methods/novel/helper_functions.py index 0ebe2009..dbb3a3e8 100644 --- a/src/methods/novel/helper_functions.py +++ b/src/methods/novel/helper_functions.py @@ -29,11 +29,13 @@ def fit(self, X): def transform(self, X): if not self.fitted: raise RuntimeError('Transformer was not fitted on any data') + row_sums = np.asarray(X.sum(axis=1)).reshape(-1, 1) + row_sums[row_sums == 0] = 1 if scipy.sparse.issparse(X): - tf = X.multiply(1 / X.sum(axis=1)) + tf = X.multiply(1 / row_sums) return tf.multiply(self.idf) else: - tf = X / X.sum(axis=1, keepdims=True) + tf = X / row_sums return tf * self.idf def fit_transform(self, X): @@ -75,7 +77,9 @@ def transform(self, adata): X_norm = np.log1p(X_norm * 1e4) X_lsi = self.pcaTransformer.transform(X_norm) X_lsi -= X_lsi.mean(axis=1, keepdims=True) - X_lsi /= X_lsi.std(axis=1, ddof=1, keepdims=True) + X_lsi_std = X_lsi.std(axis=1, ddof=1, keepdims=True) + X_lsi_std[X_lsi_std == 0] = 1 + X_lsi /= X_lsi_std lsi_df = pd.DataFrame(X_lsi, index = adata_use.obs_names) return lsi_df From 1e4254c6708e01a6bc1e4e391e4f0eb9ebaba42d Mon Sep 17 00:00:00 2001 From: Robrecht Cannoodt Date: Tue, 29 Sep 2026 19:08:18 +0200 Subject: [PATCH 2/2] Add PR number to changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78934869..2f7f1efc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -112,7 +112,7 @@ * `senkin_tmp_train`, `senkin_tmp_predict`: Store the model bundle (the test predictions, as the solution is transductive) as an h5ad file in a directory instead of a pickle. The train image is built from `nvidia/cuda` with the current pandas 3, the predict image `openproblems/base_pytorch_nvidia:1` ships pandas 2, and unpickling the bundled `var` DataFrame raised `NotImplementedError` in `NDArrayBacked.__setstate__`, so senkin_tmp finished both CITE training runs of run_2026-09-23 but never produced a prediction. The predict step still reads the old pickle until the test resources are regenerated (PR #73). -* `novel`: Guard the TF-IDF and LSI of the ATAC input against cells without counts in the selected peaks. These turned into NaN, so the validation loss never improved, no model was saved and `novel_predict` failed with a missing `tensor.pt` on the multiome swap datasets. +* `novel`: Guard the TF-IDF and LSI of the ATAC input against cells without counts in the selected peaks. These turned into NaN, so the validation loss never improved, no model was saved and `novel_predict` failed with a missing `tensor.pt` on the multiome swap datasets (PR #76). # task_predict_modality 0.1.1