diffbio 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- diffbio/__init__.py +39 -0
- diffbio/configs.py +75 -0
- diffbio/constants.py +204 -0
- diffbio/core/__init__.py +127 -0
- diffbio/core/base_operators.py +612 -0
- diffbio/core/data_types.py +260 -0
- diffbio/core/gnn_components.py +629 -0
- diffbio/core/graph_utils.py +149 -0
- diffbio/core/neural_components.py +270 -0
- diffbio/core/optimal_transport.py +133 -0
- diffbio/core/soft_ops/__init__.py +216 -0
- diffbio/core/soft_ops/_projections_permutahedron.py +1864 -0
- diffbio/core/soft_ops/_projections_simplex.py +240 -0
- diffbio/core/soft_ops/_projections_transport.py +508 -0
- diffbio/core/soft_ops/_sorting_network.py +204 -0
- diffbio/core/soft_ops/_types.py +15 -0
- diffbio/core/soft_ops/_utils.py +342 -0
- diffbio/core/soft_ops/autograd_safe.py +120 -0
- diffbio/core/soft_ops/comparison.py +235 -0
- diffbio/core/soft_ops/elementwise.py +309 -0
- diffbio/core/soft_ops/logical.py +146 -0
- diffbio/core/soft_ops/quantile.py +376 -0
- diffbio/core/soft_ops/selection.py +236 -0
- diffbio/core/soft_ops/sorting.py +926 -0
- diffbio/core/soft_ops/straight_through.py +261 -0
- diffbio/core/uncertainty.py +279 -0
- diffbio/evaluation/__init__.py +42 -0
- diffbio/evaluation/adapters.py +409 -0
- diffbio/evaluation/graders.py +223 -0
- diffbio/evaluation/problem.py +157 -0
- diffbio/evaluation/runner.py +277 -0
- diffbio/losses/__init__.py +59 -0
- diffbio/losses/alignment_losses.py +222 -0
- diffbio/losses/biological_regularization.py +288 -0
- diffbio/losses/metric_losses.py +139 -0
- diffbio/losses/singlecell_losses.py +387 -0
- diffbio/losses/statistical_losses.py +345 -0
- diffbio/operators/__init__.py +60 -0
- diffbio/operators/_count_vae.py +197 -0
- diffbio/operators/_loss_balancing.py +65 -0
- diffbio/operators/_masked_gene_transformer.py +118 -0
- diffbio/operators/_transformer_validation.py +50 -0
- diffbio/operators/alignment/__init__.py +51 -0
- diffbio/operators/alignment/profile_hmm.py +350 -0
- diffbio/operators/alignment/scoring.py +127 -0
- diffbio/operators/alignment/smith_waterman.py +261 -0
- diffbio/operators/alignment/soft_msa.py +419 -0
- diffbio/operators/assembly/__init__.py +27 -0
- diffbio/operators/assembly/gnn_assembly.py +252 -0
- diffbio/operators/assembly/metagenomic_binning.py +296 -0
- diffbio/operators/crispr/__init__.py +17 -0
- diffbio/operators/crispr/guide_scoring.py +269 -0
- diffbio/operators/drug_discovery/__init__.py +133 -0
- diffbio/operators/drug_discovery/_graph_utils.py +142 -0
- diffbio/operators/drug_discovery/admet_predictor.py +285 -0
- diffbio/operators/drug_discovery/attentive_fp.py +411 -0
- diffbio/operators/drug_discovery/dti.py +261 -0
- diffbio/operators/drug_discovery/fingerprint.py +490 -0
- diffbio/operators/drug_discovery/maccs_keys.py +267 -0
- diffbio/operators/drug_discovery/message_passing.py +200 -0
- diffbio/operators/drug_discovery/primitives.py +242 -0
- diffbio/operators/drug_discovery/property_predictor.py +163 -0
- diffbio/operators/drug_discovery/similarity.py +193 -0
- diffbio/operators/epigenomics/__init__.py +35 -0
- diffbio/operators/epigenomics/chromatin_state.py +491 -0
- diffbio/operators/epigenomics/contextual.py +288 -0
- diffbio/operators/epigenomics/fno_peak_calling.py +153 -0
- diffbio/operators/epigenomics/peak_calling.py +555 -0
- diffbio/operators/foundation_models/__init__.py +119 -0
- diffbio/operators/foundation_models/adapters.py +114 -0
- diffbio/operators/foundation_models/contracts.py +245 -0
- diffbio/operators/foundation_models/embedding_probe.py +83 -0
- diffbio/operators/foundation_models/experimental.py +128 -0
- diffbio/operators/foundation_models/foundation_model.py +332 -0
- diffbio/operators/foundation_models/frozen.py +59 -0
- diffbio/operators/foundation_models/precomputed.py +270 -0
- diffbio/operators/foundation_models/transformer_encoder.py +564 -0
- diffbio/operators/mapping/__init__.py +17 -0
- diffbio/operators/mapping/neural_mapper.py +493 -0
- diffbio/operators/metabolomics/__init__.py +39 -0
- diffbio/operators/metabolomics/spectral_similarity.py +315 -0
- diffbio/operators/molecular_dynamics/__init__.py +51 -0
- diffbio/operators/molecular_dynamics/force_field.py +265 -0
- diffbio/operators/molecular_dynamics/integrator.py +304 -0
- diffbio/operators/molecular_dynamics/primitives.py +115 -0
- diffbio/operators/multiomics/__init__.py +38 -0
- diffbio/operators/multiomics/hic_contact.py +377 -0
- diffbio/operators/multiomics/multiomics_vae.py +325 -0
- diffbio/operators/multiomics/spatial_deconvolution.py +316 -0
- diffbio/operators/multiomics/spatial_gene_detection.py +493 -0
- diffbio/operators/normalization/__init__.py +42 -0
- diffbio/operators/normalization/embedding.py +222 -0
- diffbio/operators/normalization/phate.py +400 -0
- diffbio/operators/normalization/umap.py +261 -0
- diffbio/operators/normalization/vae_normalizer.py +258 -0
- diffbio/operators/population/__init__.py +17 -0
- diffbio/operators/population/ancestry_estimation.py +274 -0
- diffbio/operators/preprocessing/__init__.py +76 -0
- diffbio/operators/preprocessing/adapter_removal.py +311 -0
- diffbio/operators/preprocessing/duplicate_filter.py +317 -0
- diffbio/operators/preprocessing/error_correction.py +287 -0
- diffbio/operators/protein/__init__.py +31 -0
- diffbio/operators/protein/secondary_structure.py +509 -0
- diffbio/operators/quality_filter.py +128 -0
- diffbio/operators/rna_structure/__init__.py +35 -0
- diffbio/operators/rna_structure/rna_folding.py +509 -0
- diffbio/operators/rnaseq/__init__.py +23 -0
- diffbio/operators/rnaseq/motif_discovery.py +251 -0
- diffbio/operators/rnaseq/splicing_psi.py +216 -0
- diffbio/operators/singlecell/__init__.py +193 -0
- diffbio/operators/singlecell/ambient_removal.py +333 -0
- diffbio/operators/singlecell/archetypes.py +191 -0
- diffbio/operators/singlecell/batch_correction.py +288 -0
- diffbio/operators/singlecell/cell_annotation.py +519 -0
- diffbio/operators/singlecell/communication.py +704 -0
- diffbio/operators/singlecell/differential_distribution.py +243 -0
- diffbio/operators/singlecell/doublet_detection.py +657 -0
- diffbio/operators/singlecell/downsampling.py +166 -0
- diffbio/operators/singlecell/enhanced_batch_correction.py +519 -0
- diffbio/operators/singlecell/grn_inference.py +336 -0
- diffbio/operators/singlecell/imputation.py +429 -0
- diffbio/operators/singlecell/knockdown_filter.py +176 -0
- diffbio/operators/singlecell/ot_trajectory.py +277 -0
- diffbio/operators/singlecell/simulation.py +444 -0
- diffbio/operators/singlecell/sindy_grn.py +247 -0
- diffbio/operators/singlecell/soft_clustering.py +211 -0
- diffbio/operators/singlecell/spatial_domains.py +677 -0
- diffbio/operators/singlecell/switch_de.py +184 -0
- diffbio/operators/singlecell/trajectory.py +447 -0
- diffbio/operators/singlecell/velocity.py +361 -0
- diffbio/operators/statistical/__init__.py +35 -0
- diffbio/operators/statistical/em_quantification.py +260 -0
- diffbio/operators/statistical/hmm.py +234 -0
- diffbio/operators/statistical/nb_glm.py +272 -0
- diffbio/operators/variant/__init__.py +64 -0
- diffbio/operators/variant/classifier.py +333 -0
- diffbio/operators/variant/cnn_classifier.py +255 -0
- diffbio/operators/variant/cnv_segmentation.py +678 -0
- diffbio/operators/variant/deepvariant_pileup.py +426 -0
- diffbio/operators/variant/pileup.py +240 -0
- diffbio/operators/variant/quality_recalibration.py +274 -0
- diffbio/pipelines/__init__.py +65 -0
- diffbio/pipelines/differential_expression.py +279 -0
- diffbio/pipelines/enhanced_variant_calling.py +326 -0
- diffbio/pipelines/perturbation.py +407 -0
- diffbio/pipelines/preprocessing.py +267 -0
- diffbio/pipelines/single_cell.py +366 -0
- diffbio/pipelines/variant_calling.py +490 -0
- diffbio/samplers/__init__.py +9 -0
- diffbio/samplers/perturbation_sampler.py +142 -0
- diffbio/sequences/__init__.py +34 -0
- diffbio/sequences/dna.py +239 -0
- diffbio/sources/__init__.py +149 -0
- diffbio/sources/_anndata_shared.py +89 -0
- diffbio/sources/_batch_iteration.py +37 -0
- diffbio/sources/_benchmark_source.py +152 -0
- diffbio/sources/_indexed_batch_source.py +38 -0
- diffbio/sources/_utils.py +45 -0
- diffbio/sources/anndata_interop.py +387 -0
- diffbio/sources/anndata_source.py +361 -0
- diffbio/sources/archive_ii.py +174 -0
- diffbio/sources/balifam.py +207 -0
- diffbio/sources/bam.py +265 -0
- diffbio/sources/bengrn_ground_truth.py +306 -0
- diffbio/sources/contextual_epigenomics.py +242 -0
- diffbio/sources/dti.py +359 -0
- diffbio/sources/embeddings.py +203 -0
- diffbio/sources/encode_peaks.py +223 -0
- diffbio/sources/fasta.py +226 -0
- diffbio/sources/immune_human.py +172 -0
- diffbio/sources/indexed_embeddings.py +128 -0
- diffbio/sources/indexed_view.py +191 -0
- diffbio/sources/molnet.py +493 -0
- diffbio/sources/multiomics.py +279 -0
- diffbio/sources/pancreas.py +108 -0
- diffbio/sources/perturbation/__init__.py +69 -0
- diffbio/sources/perturbation/_types.py +51 -0
- diffbio/sources/perturbation/_utils.py +125 -0
- diffbio/sources/perturbation/concat_source.py +115 -0
- diffbio/sources/perturbation/control_mapping.py +215 -0
- diffbio/sources/perturbation/experiment_config.py +261 -0
- diffbio/sources/perturbation/h5_metadata_cache.py +218 -0
- diffbio/sources/perturbation/output_space.py +52 -0
- diffbio/sources/perturbation/perturbation_source.py +513 -0
- diffbio/sources/seqfish.py +145 -0
- diffbio/sources/sequence_foundation.py +68 -0
- diffbio/sources/singlecell_foundation.py +68 -0
- diffbio/splitters/__init__.py +63 -0
- diffbio/splitters/base.py +251 -0
- diffbio/splitters/molecular.py +330 -0
- diffbio/splitters/perturbation.py +199 -0
- diffbio/splitters/random.py +217 -0
- diffbio/splitters/sequence.py +201 -0
- diffbio/utils/__init__.py +55 -0
- diffbio/utils/dependency_runtime.py +115 -0
- diffbio/utils/nn_utils.py +157 -0
- diffbio/utils/quality.py +45 -0
- diffbio/utils/training.py +585 -0
- diffbio-0.1.0.dist-info/METADATA +480 -0
- diffbio-0.1.0.dist-info/RECORD +202 -0
- diffbio-0.1.0.dist-info/WHEEL +4 -0
- diffbio-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
"""Foundation model infrastructure for single-cell genomics.
|
|
2
|
+
|
|
3
|
+
This module provides differentiable implementations inspired by Geneformer and
|
|
4
|
+
scGPT architectures for single-cell gene expression foundation models.
|
|
5
|
+
|
|
6
|
+
Key components:
|
|
7
|
+
|
|
8
|
+
- **GeneTokenizer**: Geneformer-style rank-value encoding via differentiable
|
|
9
|
+
soft sorting. For each cell, genes are ranked by expression value in
|
|
10
|
+
descending order using a temperature-controlled soft permutation matrix.
|
|
11
|
+
- **DifferentiableFoundationModel**: scGPT-inspired masked gene expression
|
|
12
|
+
model that tokenizes gene expression, embeds gene identities and expression
|
|
13
|
+
values, applies random masking, encodes with a transformer, and predicts
|
|
14
|
+
masked expression values.
|
|
15
|
+
|
|
16
|
+
References:
|
|
17
|
+
- Geneformer: Theodoris et al. (2023) Nature
|
|
18
|
+
- scGPT: Cui et al. (2024) Nature Methods
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import logging
|
|
22
|
+
from dataclasses import dataclass
|
|
23
|
+
from typing import Any
|
|
24
|
+
|
|
25
|
+
import jax
|
|
26
|
+
import jax.numpy as jnp
|
|
27
|
+
from datarax.core.operator import OperatorModule
|
|
28
|
+
from flax import nnx
|
|
29
|
+
from jaxtyping import Array, Float, PyTree
|
|
30
|
+
|
|
31
|
+
from diffbio.core import soft_ops
|
|
32
|
+
from diffbio.operators._masked_gene_transformer import (
|
|
33
|
+
MaskedGeneTransformerConfigBase,
|
|
34
|
+
MaskedGeneTransformerOperatorMixin,
|
|
35
|
+
build_masked_gene_transformer_encoder,
|
|
36
|
+
)
|
|
37
|
+
from diffbio.operators.foundation_models.contracts import (
|
|
38
|
+
FoundationEmbeddingMixin,
|
|
39
|
+
FoundationEmbeddingOperatorConfig,
|
|
40
|
+
FoundationModelKind,
|
|
41
|
+
PoolingStrategy,
|
|
42
|
+
register_foundation_model,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
logger = logging.getLogger(__name__)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass(frozen=True)
|
|
49
|
+
class FoundationModelConfig(
|
|
50
|
+
FoundationEmbeddingOperatorConfig,
|
|
51
|
+
MaskedGeneTransformerConfigBase,
|
|
52
|
+
):
|
|
53
|
+
"""Configuration for DifferentiableFoundationModel.
|
|
54
|
+
|
|
55
|
+
Attributes:
|
|
56
|
+
adapter_mode: Integration mode for the model artifact.
|
|
57
|
+
artifact_id: Identifier for the model artifact/version.
|
|
58
|
+
preprocessing_version: Version tag for count/gene-ID preprocessing.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
artifact_id: str = "diffbio.differentiable_foundation_model"
|
|
62
|
+
preprocessing_version: str = "counts_gene_ids_v1"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class GeneTokenizer(nnx.Module):
|
|
66
|
+
"""Geneformer-style rank-value gene tokenizer.
|
|
67
|
+
|
|
68
|
+
Converts gene expression vectors into rank-ordered representations using
|
|
69
|
+
a differentiable soft sort approximation. For each cell, genes are ranked
|
|
70
|
+
by expression value in descending order. The output is a soft permutation
|
|
71
|
+
matrix of shape ``(n_genes, n_genes)`` where row *i* is a soft one-hot
|
|
72
|
+
indicating which gene occupies rank *i*.
|
|
73
|
+
|
|
74
|
+
The key insight from Geneformer: token IDs are gene indices sorted by
|
|
75
|
+
expression magnitude. We approximate the discrete argsort with a
|
|
76
|
+
temperature-controlled soft permutation to maintain differentiability.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
n_genes: Number of genes.
|
|
80
|
+
rngs: Flax NNX random number generators.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
def __init__(self, n_genes: int, *, rngs: nnx.Rngs) -> None:
|
|
84
|
+
"""Initialize the gene tokenizer.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
n_genes: Number of genes in the vocabulary.
|
|
88
|
+
rngs: Random number generators (unused, kept for NNX API).
|
|
89
|
+
"""
|
|
90
|
+
super().__init__()
|
|
91
|
+
self.n_genes = n_genes
|
|
92
|
+
|
|
93
|
+
def __call__(
|
|
94
|
+
self,
|
|
95
|
+
expression: Float[Array, "n_genes"],
|
|
96
|
+
temperature: float = 1.0,
|
|
97
|
+
) -> Float[Array, "n_genes n_genes"]:
|
|
98
|
+
"""Compute soft permutation matrix from expression values.
|
|
99
|
+
|
|
100
|
+
Genes are ranked in descending order of expression. The returned
|
|
101
|
+
matrix ``P`` has shape ``(n_genes, n_genes)`` where ``P[i, j]``
|
|
102
|
+
approximates the probability that gene *j* occupies rank *i*.
|
|
103
|
+
|
|
104
|
+
At low temperature this approaches a hard permutation matrix
|
|
105
|
+
(the true argsort).
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
expression: Gene expression values for one cell, shape ``(n_genes,)``.
|
|
109
|
+
temperature: Softmax temperature (lower is sharper).
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Soft permutation matrix of shape ``(n_genes, n_genes)``.
|
|
113
|
+
"""
|
|
114
|
+
return _soft_sort_permutation(expression, temperature)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _soft_sort_permutation(
|
|
118
|
+
values: Float[Array, "n"],
|
|
119
|
+
temperature: float,
|
|
120
|
+
) -> Float[Array, "n n"]:
|
|
121
|
+
"""Compute a differentiable soft permutation for descending sort.
|
|
122
|
+
|
|
123
|
+
Uses the pairwise comparison approach: for each pair (i, j), compute
|
|
124
|
+
a soft indicator of whether ``values[j] > values[i]``. The soft rank
|
|
125
|
+
of gene *j* is the sum of these indicators. A softmax over negative
|
|
126
|
+
squared distance between soft ranks and integer positions yields the
|
|
127
|
+
permutation matrix.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
values: 1-D array of values to sort.
|
|
131
|
+
temperature: Temperature for softmax (lower is sharper).
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Soft permutation matrix ``P`` of shape ``(n, n)`` where ``P[i, j]``
|
|
135
|
+
approximates the probability that element *j* is at position *i*
|
|
136
|
+
in the descending sort.
|
|
137
|
+
"""
|
|
138
|
+
return soft_ops.argsort(values, axis=0, descending=True, softness=temperature)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class DifferentiableFoundationModel(
|
|
142
|
+
FoundationEmbeddingMixin,
|
|
143
|
+
MaskedGeneTransformerOperatorMixin,
|
|
144
|
+
OperatorModule,
|
|
145
|
+
):
|
|
146
|
+
"""Differentiable single-cell foundation model operator.
|
|
147
|
+
|
|
148
|
+
Implements a masked gene expression prediction model inspired by
|
|
149
|
+
Geneformer (rank-value tokenization) and scGPT (masked expression
|
|
150
|
+
prediction with gene + value embeddings).
|
|
151
|
+
|
|
152
|
+
Algorithm:
|
|
153
|
+
|
|
154
|
+
1. **Tokenize**: Rank genes by expression per cell via soft sort
|
|
155
|
+
(Geneformer-style, used for gene embedding ordering context).
|
|
156
|
+
2. **Embed gene IDs** via ``TransformerSequenceEncoder`` with
|
|
157
|
+
``input_embedding_type="token_embedding"``.
|
|
158
|
+
3. **Add expression value projection**: scalar expression values are
|
|
159
|
+
projected to ``hidden_dim`` and added to gene embeddings (scGPT-style).
|
|
160
|
+
4. **Random mask**: ``mask_ratio`` fraction of genes have their expression
|
|
161
|
+
embeddings replaced with a learned mask token.
|
|
162
|
+
5. **Transformer encoder**: contextualizes gene representations.
|
|
163
|
+
6. **Predict**: linear output head predicts masked gene expression.
|
|
164
|
+
7. **Cell embedding**: mean pooling of non-masked gene representations.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
config: FoundationModelConfig with model parameters.
|
|
168
|
+
rngs: Flax NNX random number generators.
|
|
169
|
+
name: Optional operator name.
|
|
170
|
+
|
|
171
|
+
Example:
|
|
172
|
+
>>> config = FoundationModelConfig(n_genes=2000, hidden_dim=128)
|
|
173
|
+
>>> model = DifferentiableFoundationModel(
|
|
174
|
+
... config, rngs=nnx.Rngs(params=0, sample=1, dropout=2))
|
|
175
|
+
>>> rp = model.generate_random_params(
|
|
176
|
+
... jax.random.key(0), {"counts": (100, 2000)})
|
|
177
|
+
>>> data = {"counts": counts, "gene_ids": jnp.arange(2000)}
|
|
178
|
+
>>> result, state, meta = model.apply(data, {}, None, random_params=rp)
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
foundation_model_kind = FoundationModelKind.SINGLE_CELL_TRANSFORMER
|
|
182
|
+
|
|
183
|
+
def __init__(
|
|
184
|
+
self,
|
|
185
|
+
config: FoundationModelConfig,
|
|
186
|
+
*,
|
|
187
|
+
rngs: nnx.Rngs | None = None,
|
|
188
|
+
name: str | None = None,
|
|
189
|
+
) -> None:
|
|
190
|
+
"""Initialize the foundation model.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
config: Foundation model configuration.
|
|
194
|
+
rngs: Random number generators for parameter initialization.
|
|
195
|
+
name: Optional operator name.
|
|
196
|
+
"""
|
|
197
|
+
super().__init__(config, rngs=rngs, name=name)
|
|
198
|
+
|
|
199
|
+
if rngs is None:
|
|
200
|
+
rngs = nnx.Rngs(params=0, sample=1, dropout=2)
|
|
201
|
+
|
|
202
|
+
# Gene tokenizer for rank-value encoding
|
|
203
|
+
self.tokenizer = GeneTokenizer(config.n_genes, rngs=rngs)
|
|
204
|
+
|
|
205
|
+
# Reuse the shared masked-gene token encoder contract.
|
|
206
|
+
self.encoder = build_masked_gene_transformer_encoder(config, rngs=rngs)
|
|
207
|
+
|
|
208
|
+
# Expression value projection: scalar -> hidden_dim (scGPT ContinuousValueEncoder)
|
|
209
|
+
self.expression_projection = nnx.Sequential(
|
|
210
|
+
nnx.Linear(1, config.hidden_dim, rngs=rngs),
|
|
211
|
+
nnx.Linear(config.hidden_dim, config.hidden_dim, rngs=rngs),
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
# Learned mask token embedding (replaces expression embedding for masked genes)
|
|
215
|
+
self.mask_token = nnx.Param(jax.random.normal(rngs.params(), (config.hidden_dim,)) * 0.02)
|
|
216
|
+
|
|
217
|
+
# Output head: hidden_dim -> 1 (predict scalar expression per gene)
|
|
218
|
+
self.output_head = nnx.Linear(config.hidden_dim, 1, rngs=rngs)
|
|
219
|
+
|
|
220
|
+
def foundation_pooling_strategy(self) -> PoolingStrategy:
|
|
221
|
+
"""Return the pooling strategy for cell-level embeddings."""
|
|
222
|
+
return PoolingStrategy.MEAN
|
|
223
|
+
|
|
224
|
+
def _process_single_cell(
|
|
225
|
+
self,
|
|
226
|
+
expression: Float[Array, "n_genes"],
|
|
227
|
+
gene_ids: Float[Array, "n_genes"],
|
|
228
|
+
mask: Float[Array, "n_genes"],
|
|
229
|
+
) -> tuple[
|
|
230
|
+
Float[Array, "n_genes hidden_dim"],
|
|
231
|
+
Float[Array, "hidden_dim"],
|
|
232
|
+
Float[Array, "n_genes"],
|
|
233
|
+
]:
|
|
234
|
+
"""Process a single cell through the foundation model.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
expression: Gene expression values for one cell.
|
|
238
|
+
gene_ids: Integer gene IDs.
|
|
239
|
+
mask: Binary mask (1 = masked, 0 = observed).
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
Tuple of (gene_representations, cell_embedding, predicted_expression).
|
|
243
|
+
"""
|
|
244
|
+
# Step 1: Embed gene IDs via the encoder's input projection (nnx.Embed)
|
|
245
|
+
gene_embeddings = self.encoder.input_projection(gene_ids) # (n_genes, hidden_dim)
|
|
246
|
+
|
|
247
|
+
# Step 2: Project expression values to hidden_dim (scGPT-style value encoder)
|
|
248
|
+
expr_projected = self.expression_projection(expression[:, None]) # (n_genes, hidden_dim)
|
|
249
|
+
|
|
250
|
+
# Step 3: Apply mask -- replace masked expression embeddings with mask token
|
|
251
|
+
mask_expanded = mask[:, None] # (n_genes, 1)
|
|
252
|
+
mask_token_broadcast = jnp.broadcast_to(self.mask_token[...][None, :], expr_projected.shape)
|
|
253
|
+
expr_projected = jnp.where(mask_expanded > 0.5, mask_token_broadcast, expr_projected)
|
|
254
|
+
|
|
255
|
+
# Step 4: Combine gene identity embeddings + expression value embeddings
|
|
256
|
+
hidden = gene_embeddings + expr_projected # (n_genes, hidden_dim)
|
|
257
|
+
|
|
258
|
+
# Step 5: Apply transformer encoder
|
|
259
|
+
hidden = hidden[None, :, :] # (1, n_genes, hidden_dim)
|
|
260
|
+
hidden = self.encoder.transformer(hidden, mask=None, deterministic=True)
|
|
261
|
+
hidden = hidden[0] # (n_genes, hidden_dim)
|
|
262
|
+
|
|
263
|
+
# Step 6: Predict expression for all genes via output head
|
|
264
|
+
predicted = self.output_head(hidden).squeeze(-1) # (n_genes,)
|
|
265
|
+
|
|
266
|
+
# Step 7: Cell embedding = mean pooling of non-masked gene representations
|
|
267
|
+
# Use (1 - mask) to select non-masked genes
|
|
268
|
+
non_masked_weight = (1.0 - mask)[:, None] # (n_genes, 1)
|
|
269
|
+
non_masked_count = jnp.maximum(jnp.sum(1.0 - mask), 1.0)
|
|
270
|
+
cell_embedding = (
|
|
271
|
+
jnp.sum(hidden * non_masked_weight, axis=0) / non_masked_count
|
|
272
|
+
) # (hidden_dim,)
|
|
273
|
+
|
|
274
|
+
return hidden, cell_embedding, predicted
|
|
275
|
+
|
|
276
|
+
def apply(
|
|
277
|
+
self,
|
|
278
|
+
data: PyTree,
|
|
279
|
+
state: PyTree,
|
|
280
|
+
metadata: dict[str, Any] | None,
|
|
281
|
+
random_params: Any = None,
|
|
282
|
+
stats: dict[str, Any] | None = None,
|
|
283
|
+
) -> tuple[PyTree, PyTree, dict[str, Any] | None]:
|
|
284
|
+
"""Apply foundation model to single-cell count data.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
data: Dictionary containing:
|
|
288
|
+
- ``"counts"``: Gene expression matrix ``(n_cells, n_genes)``
|
|
289
|
+
- ``"gene_ids"``: Integer gene IDs ``(n_genes,)``
|
|
290
|
+
state: Element state (passed through unchanged).
|
|
291
|
+
metadata: Element metadata (passed through unchanged).
|
|
292
|
+
random_params: JAX random key for mask generation.
|
|
293
|
+
stats: Not used.
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
Tuple of (transformed_data, state, metadata):
|
|
297
|
+
- transformed_data contains:
|
|
298
|
+
|
|
299
|
+
- All original keys from data
|
|
300
|
+
- ``"embeddings"``: Cell embeddings ``(n_cells, hidden_dim)``
|
|
301
|
+
- ``"token_embeddings"``: Contextual gene embeddings
|
|
302
|
+
``(n_cells, n_genes, hidden_dim)``
|
|
303
|
+
- ``"predicted_expression"``: Predicted expression ``(n_cells, n_genes)``
|
|
304
|
+
- ``"foundation_model"``: Canonical artifact metadata
|
|
305
|
+
- state is passed through unchanged
|
|
306
|
+
- metadata is passed through unchanged
|
|
307
|
+
"""
|
|
308
|
+
counts, gene_ids_int, mask = self.prepare_masked_gene_batch(data, random_params)
|
|
309
|
+
|
|
310
|
+
# Process each cell independently via vmap
|
|
311
|
+
gene_reps, embeddings, predicted = jax.vmap(
|
|
312
|
+
self._process_single_cell,
|
|
313
|
+
in_axes=(0, None, None),
|
|
314
|
+
)(counts, gene_ids_int, mask)
|
|
315
|
+
# gene_reps: (n_cells, n_genes, hidden_dim)
|
|
316
|
+
# embeddings: (n_cells, hidden_dim)
|
|
317
|
+
# predicted: (n_cells, n_genes)
|
|
318
|
+
|
|
319
|
+
transformed_data = self.foundation_result(
|
|
320
|
+
data,
|
|
321
|
+
embeddings,
|
|
322
|
+
token_embeddings=gene_reps,
|
|
323
|
+
extra_outputs={"predicted_expression": predicted},
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
return transformed_data, state, metadata
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
register_foundation_model(
|
|
330
|
+
FoundationModelKind.SINGLE_CELL_TRANSFORMER,
|
|
331
|
+
DifferentiableFoundationModel,
|
|
332
|
+
)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Frozen in-process adapters for benchmarked foundation-model integrations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import jax.numpy as jnp
|
|
9
|
+
from flax import nnx
|
|
10
|
+
|
|
11
|
+
from diffbio.operators.foundation_models.adapters import (
|
|
12
|
+
FoundationBenchmarkAdapterBase,
|
|
13
|
+
register_foundation_adapter,
|
|
14
|
+
)
|
|
15
|
+
from diffbio.operators.foundation_models.contracts import AdapterMode
|
|
16
|
+
from diffbio.operators.foundation_models.transformer_encoder import (
|
|
17
|
+
TransformerSequenceEncoder,
|
|
18
|
+
TransformerSequenceEncoderConfig,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class FrozenSequenceEncoderAdapter(FoundationBenchmarkAdapterBase):
|
|
23
|
+
"""Benchmark adapter for a frozen in-process sequence encoder."""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
*,
|
|
28
|
+
config: TransformerSequenceEncoderConfig,
|
|
29
|
+
rngs: nnx.Rngs | None = None,
|
|
30
|
+
source_name: str = "diffbio_frozen_encoder",
|
|
31
|
+
) -> None:
|
|
32
|
+
if config.adapter_mode is not AdapterMode.FROZEN_ENCODER:
|
|
33
|
+
raise ValueError("FrozenSequenceEncoderAdapter requires adapter_mode='frozen_encoder'.")
|
|
34
|
+
|
|
35
|
+
self.encoder = TransformerSequenceEncoder(config, rngs=rngs)
|
|
36
|
+
super().__init__(
|
|
37
|
+
artifact_spec=self.encoder.foundation_artifact_spec(),
|
|
38
|
+
source_name=source_name,
|
|
39
|
+
embedding_source="in_process_operator",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
def load_dataset_embeddings(
|
|
43
|
+
self,
|
|
44
|
+
*,
|
|
45
|
+
reference_sequence_ids: Sequence[str],
|
|
46
|
+
one_hot_sequences: Any,
|
|
47
|
+
) -> jnp.ndarray:
|
|
48
|
+
"""Encode a benchmark dataset in-process without updating encoder weights."""
|
|
49
|
+
sequences = jnp.asarray(one_hot_sequences, dtype=jnp.float32)
|
|
50
|
+
if sequences.shape[0] != len(reference_sequence_ids):
|
|
51
|
+
raise ValueError(
|
|
52
|
+
"reference_sequence_ids and one_hot_sequences "
|
|
53
|
+
"must share the same leading dimension."
|
|
54
|
+
)
|
|
55
|
+
result, _, _ = self.encoder.apply({"sequence": sequences}, {}, None)
|
|
56
|
+
return jnp.asarray(result["embeddings"], dtype=jnp.float32)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
register_foundation_adapter("diffbio_frozen_encoder", FrozenSequenceEncoderAdapter)
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"""Precomputed artifact adapters for imported foundation-model embeddings."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from collections.abc import Sequence
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
import jax.numpy as jnp
|
|
10
|
+
|
|
11
|
+
from diffbio.operators.foundation_models.adapters import (
|
|
12
|
+
FoundationBenchmarkAdapterBase,
|
|
13
|
+
register_foundation_adapter,
|
|
14
|
+
)
|
|
15
|
+
from diffbio.operators.foundation_models.contracts import (
|
|
16
|
+
AdapterMode,
|
|
17
|
+
FoundationArtifactSpec,
|
|
18
|
+
FoundationModelKind,
|
|
19
|
+
PoolingStrategy,
|
|
20
|
+
)
|
|
21
|
+
from diffbio.sources.sequence_foundation import align_sequence_embeddings
|
|
22
|
+
from diffbio.sources.singlecell_foundation import align_singlecell_embeddings
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _singlecell_precomputed_spec(
|
|
26
|
+
*,
|
|
27
|
+
artifact_id: str,
|
|
28
|
+
preprocessing_version: str,
|
|
29
|
+
pooling_strategy: PoolingStrategy,
|
|
30
|
+
) -> FoundationArtifactSpec:
|
|
31
|
+
"""Build the canonical artifact spec for imported single-cell embeddings."""
|
|
32
|
+
return FoundationArtifactSpec(
|
|
33
|
+
model_family=FoundationModelKind.SINGLE_CELL_TRANSFORMER,
|
|
34
|
+
artifact_id=artifact_id,
|
|
35
|
+
preprocessing_version=preprocessing_version,
|
|
36
|
+
adapter_mode=AdapterMode.PRECOMPUTED,
|
|
37
|
+
pooling_strategy=pooling_strategy,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _sequence_precomputed_spec(
|
|
42
|
+
*,
|
|
43
|
+
artifact_id: str,
|
|
44
|
+
preprocessing_version: str,
|
|
45
|
+
pooling_strategy: PoolingStrategy,
|
|
46
|
+
) -> FoundationArtifactSpec:
|
|
47
|
+
"""Build the canonical artifact spec for imported sequence embeddings."""
|
|
48
|
+
return FoundationArtifactSpec(
|
|
49
|
+
model_family=FoundationModelKind.SEQUENCE_TRANSFORMER,
|
|
50
|
+
artifact_id=artifact_id,
|
|
51
|
+
preprocessing_version=preprocessing_version,
|
|
52
|
+
adapter_mode=AdapterMode.PRECOMPUTED,
|
|
53
|
+
pooling_strategy=pooling_strategy,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class _ArtifactBackedFoundationAdapter(FoundationBenchmarkAdapterBase):
|
|
58
|
+
"""Shared base for artifact-backed imported foundation-model adapters."""
|
|
59
|
+
|
|
60
|
+
def __init__(
|
|
61
|
+
self,
|
|
62
|
+
*,
|
|
63
|
+
artifact_path: Path | str,
|
|
64
|
+
artifact_spec: FoundationArtifactSpec,
|
|
65
|
+
source_name: str,
|
|
66
|
+
extra_metadata: dict[str, Any] | None = None,
|
|
67
|
+
) -> None:
|
|
68
|
+
super().__init__(
|
|
69
|
+
artifact_spec=artifact_spec,
|
|
70
|
+
source_name=source_name,
|
|
71
|
+
embedding_source="external_artifact",
|
|
72
|
+
extra_metadata=extra_metadata,
|
|
73
|
+
)
|
|
74
|
+
self.artifact_path = Path(artifact_path)
|
|
75
|
+
|
|
76
|
+
def load_aligned_embeddings(
|
|
77
|
+
self,
|
|
78
|
+
*,
|
|
79
|
+
reference_cell_ids: list[str] | tuple[str, ...],
|
|
80
|
+
require_cell_ids: bool = True,
|
|
81
|
+
) -> jnp.ndarray:
|
|
82
|
+
"""Load and align embeddings to the benchmark dataset order."""
|
|
83
|
+
return align_singlecell_embeddings(
|
|
84
|
+
reference_cell_ids=reference_cell_ids,
|
|
85
|
+
artifact_path=self.artifact_path,
|
|
86
|
+
require_cell_ids=require_cell_ids,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class SingleCellPrecomputedAdapter(_ArtifactBackedFoundationAdapter):
|
|
91
|
+
"""Base adapter for precomputed single-cell embedding artifacts."""
|
|
92
|
+
|
|
93
|
+
def load_aligned_embeddings(
|
|
94
|
+
self,
|
|
95
|
+
*,
|
|
96
|
+
reference_cell_ids: list[str] | tuple[str, ...],
|
|
97
|
+
require_cell_ids: bool = True,
|
|
98
|
+
) -> jnp.ndarray:
|
|
99
|
+
"""Load and align embeddings to the benchmark dataset order."""
|
|
100
|
+
return align_singlecell_embeddings(
|
|
101
|
+
reference_cell_ids=reference_cell_ids,
|
|
102
|
+
artifact_path=self.artifact_path,
|
|
103
|
+
require_cell_ids=require_cell_ids,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class SequencePrecomputedAdapter(_ArtifactBackedFoundationAdapter):
|
|
108
|
+
"""Base adapter for precomputed sequence embedding artifacts."""
|
|
109
|
+
|
|
110
|
+
def load_aligned_embeddings(
|
|
111
|
+
self,
|
|
112
|
+
*,
|
|
113
|
+
reference_sequence_ids: list[str] | tuple[str, ...],
|
|
114
|
+
require_sequence_ids: bool = True,
|
|
115
|
+
) -> jnp.ndarray:
|
|
116
|
+
"""Load and align embeddings to the benchmark sequence order."""
|
|
117
|
+
return align_sequence_embeddings(
|
|
118
|
+
reference_sequence_ids=reference_sequence_ids,
|
|
119
|
+
artifact_path=self.artifact_path,
|
|
120
|
+
require_sequence_ids=require_sequence_ids,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
def load_dataset_embeddings(
|
|
124
|
+
self,
|
|
125
|
+
*,
|
|
126
|
+
reference_sequence_ids: Sequence[str],
|
|
127
|
+
one_hot_sequences: Any,
|
|
128
|
+
) -> jnp.ndarray:
|
|
129
|
+
"""Load embeddings for a sequence benchmark dataset."""
|
|
130
|
+
n_sequences = int(jnp.asarray(one_hot_sequences).shape[0])
|
|
131
|
+
if n_sequences != len(reference_sequence_ids):
|
|
132
|
+
raise ValueError(
|
|
133
|
+
"reference_sequence_ids and one_hot_sequences "
|
|
134
|
+
"must share the same leading dimension."
|
|
135
|
+
)
|
|
136
|
+
return self.load_aligned_embeddings(
|
|
137
|
+
reference_sequence_ids=list(reference_sequence_ids),
|
|
138
|
+
require_sequence_ids=True,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class DNABERT2PrecomputedAdapter(SequencePrecomputedAdapter):
|
|
143
|
+
"""Precomputed embedding adapter for DNABERT-2 artifacts."""
|
|
144
|
+
|
|
145
|
+
def __init__(
|
|
146
|
+
self,
|
|
147
|
+
*,
|
|
148
|
+
artifact_path: Path | str,
|
|
149
|
+
artifact_id: str = "dnabert2.v1",
|
|
150
|
+
preprocessing_version: str = "kmer6_v1",
|
|
151
|
+
pooling_strategy: PoolingStrategy = PoolingStrategy.MEAN,
|
|
152
|
+
) -> None:
|
|
153
|
+
super().__init__(
|
|
154
|
+
artifact_path=artifact_path,
|
|
155
|
+
artifact_spec=_sequence_precomputed_spec(
|
|
156
|
+
artifact_id=artifact_id,
|
|
157
|
+
preprocessing_version=preprocessing_version,
|
|
158
|
+
pooling_strategy=pooling_strategy,
|
|
159
|
+
),
|
|
160
|
+
source_name="dnabert2_precomputed",
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class NucleotideTransformerPrecomputedAdapter(SequencePrecomputedAdapter):
|
|
165
|
+
"""Precomputed embedding adapter for Nucleotide Transformer artifacts."""
|
|
166
|
+
|
|
167
|
+
def __init__(
|
|
168
|
+
self,
|
|
169
|
+
*,
|
|
170
|
+
artifact_path: Path | str,
|
|
171
|
+
artifact_id: str = "nucleotide_transformer.v1",
|
|
172
|
+
preprocessing_version: str = "bpe_v1",
|
|
173
|
+
pooling_strategy: PoolingStrategy = PoolingStrategy.MEAN,
|
|
174
|
+
) -> None:
|
|
175
|
+
super().__init__(
|
|
176
|
+
artifact_path=artifact_path,
|
|
177
|
+
artifact_spec=_sequence_precomputed_spec(
|
|
178
|
+
artifact_id=artifact_id,
|
|
179
|
+
preprocessing_version=preprocessing_version,
|
|
180
|
+
pooling_strategy=pooling_strategy,
|
|
181
|
+
),
|
|
182
|
+
source_name="nucleotide_transformer_precomputed",
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class ProteinLMPrecomputedAdapter(SequencePrecomputedAdapter):
|
|
187
|
+
"""Precomputed embedding adapter for exported protein language-model artifacts."""
|
|
188
|
+
|
|
189
|
+
def __init__(
|
|
190
|
+
self,
|
|
191
|
+
*,
|
|
192
|
+
artifact_path: Path | str,
|
|
193
|
+
artifact_id: str = "protein_lm.v1",
|
|
194
|
+
preprocessing_version: str = "protein_tokens_v1",
|
|
195
|
+
pooling_strategy: PoolingStrategy = PoolingStrategy.MEAN,
|
|
196
|
+
) -> None:
|
|
197
|
+
super().__init__(
|
|
198
|
+
artifact_path=artifact_path,
|
|
199
|
+
artifact_spec=_sequence_precomputed_spec(
|
|
200
|
+
artifact_id=artifact_id,
|
|
201
|
+
preprocessing_version=preprocessing_version,
|
|
202
|
+
pooling_strategy=pooling_strategy,
|
|
203
|
+
),
|
|
204
|
+
source_name="protein_lm_precomputed",
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class GeneformerPrecomputedAdapter(SingleCellPrecomputedAdapter):
|
|
209
|
+
"""Precomputed embedding adapter for Geneformer artifacts."""
|
|
210
|
+
|
|
211
|
+
def __init__(
|
|
212
|
+
self,
|
|
213
|
+
*,
|
|
214
|
+
artifact_path: Path | str,
|
|
215
|
+
artifact_id: str = "geneformer.v1",
|
|
216
|
+
preprocessing_version: str = "rank_value_v1",
|
|
217
|
+
pooling_strategy: PoolingStrategy = PoolingStrategy.MEAN,
|
|
218
|
+
) -> None:
|
|
219
|
+
super().__init__(
|
|
220
|
+
artifact_path=artifact_path,
|
|
221
|
+
artifact_spec=_singlecell_precomputed_spec(
|
|
222
|
+
artifact_id=artifact_id,
|
|
223
|
+
preprocessing_version=preprocessing_version,
|
|
224
|
+
pooling_strategy=pooling_strategy,
|
|
225
|
+
),
|
|
226
|
+
source_name="geneformer_precomputed",
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
class ScGPTPrecomputedAdapter(SingleCellPrecomputedAdapter):
|
|
231
|
+
"""Precomputed embedding adapter for scGPT artifacts."""
|
|
232
|
+
|
|
233
|
+
def __init__(
|
|
234
|
+
self,
|
|
235
|
+
*,
|
|
236
|
+
artifact_path: Path | str,
|
|
237
|
+
artifact_id: str = "scgpt.v1",
|
|
238
|
+
preprocessing_version: str = "gene_vocab_v1",
|
|
239
|
+
pooling_strategy: PoolingStrategy = PoolingStrategy.MEAN,
|
|
240
|
+
batch_key: str | None = None,
|
|
241
|
+
context_version: str | None = None,
|
|
242
|
+
) -> None:
|
|
243
|
+
extra_metadata: dict[str, Any] = {
|
|
244
|
+
"requires_batch_context": batch_key is not None or context_version is not None,
|
|
245
|
+
}
|
|
246
|
+
if batch_key is not None:
|
|
247
|
+
extra_metadata["batch_key"] = batch_key
|
|
248
|
+
if context_version is not None:
|
|
249
|
+
extra_metadata["context_version"] = context_version
|
|
250
|
+
|
|
251
|
+
super().__init__(
|
|
252
|
+
artifact_path=artifact_path,
|
|
253
|
+
artifact_spec=_singlecell_precomputed_spec(
|
|
254
|
+
artifact_id=artifact_id,
|
|
255
|
+
preprocessing_version=preprocessing_version,
|
|
256
|
+
pooling_strategy=pooling_strategy,
|
|
257
|
+
),
|
|
258
|
+
source_name="scgpt_precomputed",
|
|
259
|
+
extra_metadata=extra_metadata,
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
register_foundation_adapter("dnabert2_precomputed", DNABERT2PrecomputedAdapter)
|
|
264
|
+
register_foundation_adapter(
|
|
265
|
+
"nucleotide_transformer_precomputed",
|
|
266
|
+
NucleotideTransformerPrecomputedAdapter,
|
|
267
|
+
)
|
|
268
|
+
register_foundation_adapter("protein_lm_precomputed", ProteinLMPrecomputedAdapter)
|
|
269
|
+
register_foundation_adapter("geneformer_precomputed", GeneformerPrecomputedAdapter)
|
|
270
|
+
register_foundation_adapter("scgpt_precomputed", ScGPTPrecomputedAdapter)
|