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,211 @@
|
|
|
1
|
+
"""Soft K-Means clustering operator for single-cell analysis.
|
|
2
|
+
|
|
3
|
+
This module provides a differentiable implementation of soft k-means
|
|
4
|
+
clustering, enabling gradient-based learning of cluster centroids.
|
|
5
|
+
|
|
6
|
+
Key technique: Replace hard cluster assignment with softmax-based
|
|
7
|
+
soft assignments for fully differentiable clustering.
|
|
8
|
+
|
|
9
|
+
Applications: Cell type clustering, Leiden-like community detection.
|
|
10
|
+
|
|
11
|
+
Inherits from TemperatureOperator to get:
|
|
12
|
+
|
|
13
|
+
- _temperature property for temperature-controlled smoothing
|
|
14
|
+
- soft_max() for logsumexp-based smooth maximum
|
|
15
|
+
- soft_argmax() for soft position selection
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import logging
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
import jax
|
|
23
|
+
import jax.numpy as jnp
|
|
24
|
+
from datarax.core.config import OperatorConfig
|
|
25
|
+
from flax import nnx
|
|
26
|
+
from jaxtyping import Array, Float, Int, PyTree
|
|
27
|
+
|
|
28
|
+
from diffbio.core.base_operators import TemperatureOperator
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True)
|
|
34
|
+
class SoftClusteringConfig(OperatorConfig):
|
|
35
|
+
"""Configuration for SoftKMeansClustering.
|
|
36
|
+
|
|
37
|
+
Attributes:
|
|
38
|
+
n_clusters: Number of clusters.
|
|
39
|
+
n_features: Dimensionality of input embeddings.
|
|
40
|
+
temperature: Temperature for softmax (lower = sharper).
|
|
41
|
+
learnable_centroids: Whether centroids are learnable parameters.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
n_clusters: int = 10
|
|
45
|
+
n_features: int = 50
|
|
46
|
+
temperature: float = 1.0
|
|
47
|
+
learnable_centroids: bool = True
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class SoftKMeansClustering(TemperatureOperator):
|
|
51
|
+
"""Differentiable soft k-means clustering.
|
|
52
|
+
|
|
53
|
+
This operator implements soft k-means with learnable cluster centroids.
|
|
54
|
+
Instead of hard cluster assignments, cells are softly assigned to clusters
|
|
55
|
+
using softmax over negative squared distances.
|
|
56
|
+
|
|
57
|
+
Algorithm:
|
|
58
|
+
1. Compute squared distances from cells to centroids
|
|
59
|
+
2. Apply softmax for soft assignments: P(k|x) = softmax(-||x - c_k||² / T)
|
|
60
|
+
3. Optionally update centroids based on weighted means
|
|
61
|
+
|
|
62
|
+
Inherits from TemperatureOperator to get:
|
|
63
|
+
|
|
64
|
+
- _temperature property for temperature-controlled smoothing
|
|
65
|
+
- soft_max() for logsumexp-based smooth maximum
|
|
66
|
+
- soft_argmax() for soft position selection
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
config: SoftClusteringConfig with model parameters.
|
|
70
|
+
rngs: Flax NNX random number generators.
|
|
71
|
+
name: Optional operator name.
|
|
72
|
+
|
|
73
|
+
Example:
|
|
74
|
+
```python
|
|
75
|
+
config = SoftClusteringConfig(n_clusters=10, n_features=50)
|
|
76
|
+
clusterer = SoftKMeansClustering(config, rngs=nnx.Rngs(42))
|
|
77
|
+
data = {"embeddings": cell_embeddings}
|
|
78
|
+
result, state, meta = clusterer.apply(data, {}, None)
|
|
79
|
+
```
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
def __init__(
|
|
83
|
+
self,
|
|
84
|
+
config: SoftClusteringConfig,
|
|
85
|
+
*,
|
|
86
|
+
rngs: nnx.Rngs | None = None,
|
|
87
|
+
name: str | None = None,
|
|
88
|
+
):
|
|
89
|
+
"""Initialize the soft k-means clustering operator.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
config: Clustering configuration.
|
|
93
|
+
rngs: Random number generators for initialization.
|
|
94
|
+
name: Optional operator name.
|
|
95
|
+
"""
|
|
96
|
+
super().__init__(config, rngs=rngs, name=name)
|
|
97
|
+
|
|
98
|
+
rngs = rngs or nnx.Rngs(0)
|
|
99
|
+
self.cluster_shape = nnx.static((config.n_clusters, config.n_features))
|
|
100
|
+
self.n_clusters, self.n_features = self.cluster_shape
|
|
101
|
+
# Temperature is now managed by TemperatureOperator via self._temperature
|
|
102
|
+
|
|
103
|
+
# Initialize cluster centroids
|
|
104
|
+
key = rngs.params()
|
|
105
|
+
init_centroids = jax.random.normal(key, self.cluster_shape) * 0.1
|
|
106
|
+
self.centroids = nnx.Param(init_centroids)
|
|
107
|
+
|
|
108
|
+
def compute_distances(
|
|
109
|
+
self,
|
|
110
|
+
embeddings: Float[Array, "n_cells n_features"],
|
|
111
|
+
) -> Float[Array, "n_cells n_clusters"]:
|
|
112
|
+
"""Compute squared distances from cells to centroids.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
embeddings: Cell embedding vectors.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Squared Euclidean distances to each centroid.
|
|
119
|
+
"""
|
|
120
|
+
centroids = self.centroids[...] # (n_clusters, n_features)
|
|
121
|
+
|
|
122
|
+
# Efficient distance computation using expansion
|
|
123
|
+
# ||x - c||² = ||x||² + ||c||² - 2 * x · c
|
|
124
|
+
emb_sq = jnp.sum(embeddings**2, axis=-1, keepdims=True) # (n_cells, 1)
|
|
125
|
+
cent_sq = jnp.sum(centroids**2, axis=-1) # (n_clusters,)
|
|
126
|
+
dot_product = jnp.einsum("nf,kf->nk", embeddings, centroids) # (n_cells, n_clusters)
|
|
127
|
+
|
|
128
|
+
distances_sq = emb_sq + cent_sq - 2 * dot_product
|
|
129
|
+
|
|
130
|
+
return distances_sq
|
|
131
|
+
|
|
132
|
+
def compute_assignments(
|
|
133
|
+
self,
|
|
134
|
+
embeddings: Float[Array, "n_cells n_features"],
|
|
135
|
+
) -> Float[Array, "n_cells n_clusters"]:
|
|
136
|
+
"""Compute soft cluster assignments.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
embeddings: Cell embedding vectors.
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Soft assignment probabilities for each cluster.
|
|
143
|
+
"""
|
|
144
|
+
distances_sq = self.compute_distances(embeddings)
|
|
145
|
+
|
|
146
|
+
# Soft assignments via softmax over negative distances
|
|
147
|
+
# Use inherited _temperature property from TemperatureOperator
|
|
148
|
+
assignments = jax.nn.softmax(-distances_sq / self._temperature, axis=-1)
|
|
149
|
+
|
|
150
|
+
return assignments
|
|
151
|
+
|
|
152
|
+
def get_hard_labels(
|
|
153
|
+
self,
|
|
154
|
+
assignments: Float[Array, "n_cells n_clusters"],
|
|
155
|
+
) -> Int[Array, "n_cells"]:
|
|
156
|
+
"""Get hard cluster labels from soft assignments.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
assignments: Soft cluster assignments.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
Hard cluster labels (argmax).
|
|
163
|
+
"""
|
|
164
|
+
return jnp.argmax(assignments, axis=-1)
|
|
165
|
+
|
|
166
|
+
def apply(
|
|
167
|
+
self,
|
|
168
|
+
data: PyTree,
|
|
169
|
+
state: PyTree,
|
|
170
|
+
metadata: dict[str, Any] | None,
|
|
171
|
+
random_params: Any = None,
|
|
172
|
+
stats: dict[str, Any] | None = None,
|
|
173
|
+
) -> tuple[PyTree, PyTree, dict[str, Any] | None]:
|
|
174
|
+
"""Apply soft k-means clustering to cell embeddings.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
data: Dictionary containing:
|
|
178
|
+
- "embeddings": Cell embeddings (n_cells, n_features)
|
|
179
|
+
state: Element state (passed through unchanged)
|
|
180
|
+
metadata: Element metadata (passed through unchanged)
|
|
181
|
+
random_params: Not used
|
|
182
|
+
stats: Not used
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
Tuple of (transformed_data, state, metadata):
|
|
186
|
+
- transformed_data contains:
|
|
187
|
+
|
|
188
|
+
- "embeddings": Original embeddings
|
|
189
|
+
- "cluster_assignments": Soft assignment probabilities
|
|
190
|
+
- "cluster_labels": Hard cluster labels
|
|
191
|
+
- "centroids": Cluster centroid positions
|
|
192
|
+
- state is passed through unchanged
|
|
193
|
+
- metadata is passed through unchanged
|
|
194
|
+
"""
|
|
195
|
+
embeddings = data["embeddings"]
|
|
196
|
+
|
|
197
|
+
# Compute soft assignments
|
|
198
|
+
assignments = self.compute_assignments(embeddings)
|
|
199
|
+
|
|
200
|
+
# Get hard labels
|
|
201
|
+
labels = self.get_hard_labels(assignments)
|
|
202
|
+
|
|
203
|
+
# Build output data
|
|
204
|
+
transformed_data = {
|
|
205
|
+
"embeddings": embeddings,
|
|
206
|
+
"cluster_assignments": assignments,
|
|
207
|
+
"cluster_labels": labels,
|
|
208
|
+
"centroids": self.centroids[...],
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return transformed_data, state, metadata
|