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,326 @@
|
|
|
1
|
+
"""Enhanced end-to-end differentiable variant calling pipeline.
|
|
2
|
+
|
|
3
|
+
This module provides an enhanced variant calling pipeline that composes:
|
|
4
|
+
1. Quality filtering (preprocessing) - Filter low-quality bases
|
|
5
|
+
2. Pileup generation - Aggregate reads at each position
|
|
6
|
+
3. CNN classification - DeepVariant-style variant classification
|
|
7
|
+
4. Quality recalibration - VQSR-style variant quality filtering
|
|
8
|
+
|
|
9
|
+
The pipeline is fully differentiable, enabling gradient-based optimization
|
|
10
|
+
of all components jointly.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
import jax.numpy as jnp
|
|
18
|
+
from datarax.core.config import OperatorConfig
|
|
19
|
+
from datarax.core.operator import OperatorModule
|
|
20
|
+
from flax import nnx
|
|
21
|
+
from jaxtyping import Array
|
|
22
|
+
|
|
23
|
+
from diffbio.operators.quality_filter import (
|
|
24
|
+
DifferentiableQualityFilter,
|
|
25
|
+
QualityFilterConfig,
|
|
26
|
+
)
|
|
27
|
+
from diffbio.operators.variant import (
|
|
28
|
+
CNNVariantClassifier,
|
|
29
|
+
CNNVariantClassifierConfig,
|
|
30
|
+
DifferentiablePileup,
|
|
31
|
+
PileupConfig,
|
|
32
|
+
SoftVariantQualityFilter,
|
|
33
|
+
VariantQualityFilterConfig,
|
|
34
|
+
)
|
|
35
|
+
from diffbio.utils.nn_utils import extract_windows_1d
|
|
36
|
+
|
|
37
|
+
logger = logging.getLogger(__name__)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass(frozen=True)
|
|
41
|
+
class EnhancedVariantCallingPipelineConfig(OperatorConfig):
|
|
42
|
+
# pylint: disable=too-many-instance-attributes
|
|
43
|
+
"""Configuration for the enhanced variant calling pipeline.
|
|
44
|
+
|
|
45
|
+
Attributes:
|
|
46
|
+
reference_length: Length of reference sequence.
|
|
47
|
+
num_classes: Number of variant classes (default: 3 for ref/snp/indel).
|
|
48
|
+
quality_threshold: Initial quality score threshold for filtering.
|
|
49
|
+
pileup_window_size: Window size for pileup context.
|
|
50
|
+
cnn_input_height: Height of pileup image for CNN (coverage depth).
|
|
51
|
+
cnn_hidden_channels: Hidden channels for CNN classifier.
|
|
52
|
+
cnn_fc_dims: Fully connected layer dimensions for CNN.
|
|
53
|
+
cnn_dropout_rate: Dropout rate for CNN classifier.
|
|
54
|
+
quality_recal_n_components: Number of GMM components for quality recalibration.
|
|
55
|
+
quality_recal_n_features: Number of features for quality recalibration.
|
|
56
|
+
quality_recal_threshold: Threshold for quality filtering.
|
|
57
|
+
enable_preprocessing: Whether to enable quality filtering preprocessing.
|
|
58
|
+
enable_quality_recalibration: Whether to enable quality recalibration.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
reference_length: int = 1000
|
|
62
|
+
num_classes: int = 3
|
|
63
|
+
quality_threshold: float = 20.0
|
|
64
|
+
pileup_window_size: int = 11
|
|
65
|
+
cnn_input_height: int = 100
|
|
66
|
+
cnn_hidden_channels: tuple[int, ...] = (64, 128, 256)
|
|
67
|
+
cnn_fc_dims: tuple[int, ...] = (256, 128)
|
|
68
|
+
cnn_dropout_rate: float = 0.1
|
|
69
|
+
quality_recal_n_components: int = 3
|
|
70
|
+
quality_recal_n_features: int = 4
|
|
71
|
+
quality_recal_threshold: float = 0.5
|
|
72
|
+
enable_preprocessing: bool = True
|
|
73
|
+
enable_quality_recalibration: bool = True
|
|
74
|
+
|
|
75
|
+
def __post_init__(self) -> None:
|
|
76
|
+
"""Set non-default stochastic fields."""
|
|
77
|
+
object.__setattr__(self, "stochastic", True)
|
|
78
|
+
if self.stream_name is None:
|
|
79
|
+
object.__setattr__(self, "stream_name", "sample")
|
|
80
|
+
super().__post_init__()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class EnhancedVariantCallingPipeline(OperatorModule):
|
|
84
|
+
"""Enhanced end-to-end differentiable variant calling pipeline.
|
|
85
|
+
|
|
86
|
+
This pipeline processes sequencing reads to call variants using a
|
|
87
|
+
DeepVariant-style CNN classifier followed by VQSR-style quality
|
|
88
|
+
recalibration:
|
|
89
|
+
|
|
90
|
+
Input data structure:
|
|
91
|
+
- reads: Float[Array, "num_reads read_length 4"] - One-hot encoded reads
|
|
92
|
+
- positions: Int[Array, "num_reads"] - Read start positions on reference
|
|
93
|
+
- quality: Float[Array, "num_reads read_length"] - Base quality scores
|
|
94
|
+
|
|
95
|
+
Output data structure (adds):
|
|
96
|
+
- pileup: Float[Array, "reference_length 4"] - Aggregated base frequencies
|
|
97
|
+
- logits: Float[Array, "reference_length num_classes"] - Raw predictions
|
|
98
|
+
- probabilities: Float[Array, "reference_length num_classes"] - Class probs
|
|
99
|
+
- quality_scores: Float[Array, "reference_length"] - Recalibrated quality
|
|
100
|
+
- filter_weights: Float[Array, "reference_length"] - Soft filter weights
|
|
101
|
+
|
|
102
|
+
The pipeline is fully differentiable, supporting gradient-based training
|
|
103
|
+
to optimize all components jointly.
|
|
104
|
+
|
|
105
|
+
Example:
|
|
106
|
+
```python
|
|
107
|
+
config = EnhancedVariantCallingPipelineConfig(reference_length=1000)
|
|
108
|
+
pipeline = EnhancedVariantCallingPipeline(config, rngs=nnx.Rngs(42))
|
|
109
|
+
result, state, meta = pipeline.apply(data, {}, None)
|
|
110
|
+
probs = result["probabilities"]
|
|
111
|
+
```
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
def __init__(
|
|
115
|
+
self,
|
|
116
|
+
config: EnhancedVariantCallingPipelineConfig,
|
|
117
|
+
*,
|
|
118
|
+
rngs: nnx.Rngs,
|
|
119
|
+
name: str | None = None,
|
|
120
|
+
):
|
|
121
|
+
"""Initialize the enhanced variant calling pipeline.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
config: Pipeline configuration.
|
|
125
|
+
rngs: Random number generators for parameter initialization.
|
|
126
|
+
name: Optional name for the pipeline.
|
|
127
|
+
"""
|
|
128
|
+
super().__init__(config, rngs=rngs, name=name)
|
|
129
|
+
|
|
130
|
+
# 1. Quality filter for preprocessing (optional)
|
|
131
|
+
self.quality_filter = (
|
|
132
|
+
DifferentiableQualityFilter(
|
|
133
|
+
QualityFilterConfig(initial_threshold=config.quality_threshold),
|
|
134
|
+
rngs=rngs,
|
|
135
|
+
)
|
|
136
|
+
if config.enable_preprocessing
|
|
137
|
+
else None
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# 2. Pileup generation
|
|
141
|
+
self.pileup = DifferentiablePileup(
|
|
142
|
+
PileupConfig(
|
|
143
|
+
reference_length=config.reference_length,
|
|
144
|
+
use_quality_weights=True,
|
|
145
|
+
),
|
|
146
|
+
rngs=rngs,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# 3. CNN classifier (DeepVariant-style)
|
|
150
|
+
# Use 4 channels (A, C, G, T) from the pileup
|
|
151
|
+
self.cnn_classifier = CNNVariantClassifier(
|
|
152
|
+
CNNVariantClassifierConfig(
|
|
153
|
+
num_classes=config.num_classes,
|
|
154
|
+
input_height=config.cnn_input_height,
|
|
155
|
+
input_width=config.pileup_window_size,
|
|
156
|
+
num_channels=4, # A, C, G, T from pileup
|
|
157
|
+
hidden_channels=config.cnn_hidden_channels,
|
|
158
|
+
fc_dims=config.cnn_fc_dims,
|
|
159
|
+
dropout_rate=config.cnn_dropout_rate,
|
|
160
|
+
),
|
|
161
|
+
rngs=rngs,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# 4. Quality recalibration (optional)
|
|
165
|
+
self.quality_recalibration = (
|
|
166
|
+
SoftVariantQualityFilter(
|
|
167
|
+
VariantQualityFilterConfig(
|
|
168
|
+
n_components=config.quality_recal_n_components,
|
|
169
|
+
n_features=config.quality_recal_n_features,
|
|
170
|
+
threshold=config.quality_recal_threshold,
|
|
171
|
+
),
|
|
172
|
+
rngs=rngs,
|
|
173
|
+
)
|
|
174
|
+
if config.enable_quality_recalibration
|
|
175
|
+
else None
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
def apply(
|
|
179
|
+
self,
|
|
180
|
+
data: dict[str, Array],
|
|
181
|
+
state: dict[str, Any],
|
|
182
|
+
metadata: dict[str, Any] | None,
|
|
183
|
+
random_params: Any = None, # noqa: ARG002
|
|
184
|
+
stats: dict[str, Any] | None = None, # noqa: ARG002
|
|
185
|
+
) -> tuple[dict[str, Array], dict[str, Any], dict[str, Any] | None]:
|
|
186
|
+
"""Apply the enhanced variant calling pipeline.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
data: Input data containing:
|
|
190
|
+
- reads: Float[Array, "num_reads read_length 4"]
|
|
191
|
+
- positions: Int[Array, "num_reads"]
|
|
192
|
+
- quality: Float[Array, "num_reads read_length"]
|
|
193
|
+
state: Element state (passed through).
|
|
194
|
+
metadata: Element metadata (passed through).
|
|
195
|
+
random_params: Random parameters for stochastic operations.
|
|
196
|
+
stats: Optional statistics dict.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
Tuple of (output_data, state, metadata) where output_data contains
|
|
200
|
+
all input keys plus variant calling outputs.
|
|
201
|
+
"""
|
|
202
|
+
reads = data["reads"]
|
|
203
|
+
positions = data["positions"]
|
|
204
|
+
quality = data["quality"]
|
|
205
|
+
|
|
206
|
+
# Step 1: Quality filtering (optional)
|
|
207
|
+
if self.quality_filter is not None:
|
|
208
|
+
# Apply quality filter per-base
|
|
209
|
+
num_reads, read_length, _ = reads.shape
|
|
210
|
+
reads_flat = reads.reshape(-1, 4)
|
|
211
|
+
quality_flat = quality.reshape(-1)
|
|
212
|
+
|
|
213
|
+
filter_data = {"sequence": reads_flat, "quality_scores": quality_flat}
|
|
214
|
+
filter_result, _, _ = self.quality_filter.apply(filter_data, {}, None)
|
|
215
|
+
|
|
216
|
+
reads = filter_result["sequence"].reshape(num_reads, read_length, 4)
|
|
217
|
+
quality = filter_result["quality_scores"].reshape(num_reads, read_length)
|
|
218
|
+
|
|
219
|
+
# Step 2: Generate pileup
|
|
220
|
+
pileup_data = {
|
|
221
|
+
"reads": reads,
|
|
222
|
+
"positions": positions,
|
|
223
|
+
"quality": quality,
|
|
224
|
+
}
|
|
225
|
+
pileup_result, _, _ = self.pileup.apply(pileup_data, {}, None)
|
|
226
|
+
pileup = pileup_result["pileup"] # (reference_length, 4)
|
|
227
|
+
|
|
228
|
+
# Step 3: CNN classification
|
|
229
|
+
# Extract windows around each position for CNN input
|
|
230
|
+
# CNN expects (batch, height, width, channels)
|
|
231
|
+
ref_length = self.config.reference_length
|
|
232
|
+
window_size = self.config.pileup_window_size
|
|
233
|
+
|
|
234
|
+
# Extract windows: (ref_length, window_size, 4)
|
|
235
|
+
# extract_windows_1d handles padding internally
|
|
236
|
+
windows = extract_windows_1d(pileup, window_size)
|
|
237
|
+
|
|
238
|
+
# Add depth dimension for CNN: (ref_length, height, width, channels)
|
|
239
|
+
# Use pileup as a simple "pileup image" - repeat to create height
|
|
240
|
+
cnn_input_height = self.config.cnn_input_height
|
|
241
|
+
# Create a simplified pileup image by repeating the window pattern
|
|
242
|
+
pileup_images = jnp.broadcast_to(
|
|
243
|
+
windows[:, None, :, :], (ref_length, cnn_input_height, window_size, 4)
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
# Apply CNN classifier
|
|
247
|
+
cnn_data = {"pileup_image": pileup_images}
|
|
248
|
+
cnn_result, _, _ = self.cnn_classifier.apply(cnn_data, {}, None)
|
|
249
|
+
|
|
250
|
+
logits = cnn_result["logits"] # (ref_length, num_classes)
|
|
251
|
+
probabilities = cnn_result["class_probs"] # CNN outputs class_probs
|
|
252
|
+
|
|
253
|
+
# Build output
|
|
254
|
+
output_data = {
|
|
255
|
+
**data,
|
|
256
|
+
"pileup": pileup,
|
|
257
|
+
"logits": logits,
|
|
258
|
+
"probabilities": probabilities,
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
# Step 4: Quality recalibration (optional)
|
|
262
|
+
if self.quality_recalibration is not None:
|
|
263
|
+
# Compute variant features for quality recalibration
|
|
264
|
+
# Features: depth, max_prob, entropy, strand_balance
|
|
265
|
+
depth = pileup.sum(axis=-1) # Total coverage at each position
|
|
266
|
+
max_prob = probabilities.max(axis=-1) # Confidence of prediction
|
|
267
|
+
entropy = -jnp.sum(
|
|
268
|
+
probabilities * jnp.log(probabilities + 1e-10), axis=-1
|
|
269
|
+
) # Prediction entropy
|
|
270
|
+
# Simple strand balance proxy (ratio of first two bases)
|
|
271
|
+
strand_balance = jnp.abs(pileup[:, 0] - pileup[:, 1]) / (depth + 1e-10)
|
|
272
|
+
|
|
273
|
+
variant_features = jnp.stack(
|
|
274
|
+
[depth, max_prob, entropy, strand_balance], axis=-1
|
|
275
|
+
) # (ref_length, 4)
|
|
276
|
+
|
|
277
|
+
recal_data = {"variant_features": variant_features}
|
|
278
|
+
recal_result, _, _ = self.quality_recalibration.apply(recal_data, {}, None)
|
|
279
|
+
|
|
280
|
+
output_data["quality_scores"] = recal_result["quality_scores"]
|
|
281
|
+
output_data["filter_weights"] = recal_result["filter_weights"]
|
|
282
|
+
|
|
283
|
+
return output_data, state, metadata
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def create_enhanced_variant_calling_pipeline(
|
|
287
|
+
reference_length: int = 1000,
|
|
288
|
+
num_classes: int = 3,
|
|
289
|
+
pileup_window_size: int = 11,
|
|
290
|
+
cnn_hidden_channels: tuple[int, ...] | None = None,
|
|
291
|
+
cnn_fc_dims: tuple[int, ...] | None = None,
|
|
292
|
+
enable_preprocessing: bool = True,
|
|
293
|
+
enable_quality_recalibration: bool = True,
|
|
294
|
+
seed: int = 42,
|
|
295
|
+
) -> EnhancedVariantCallingPipeline:
|
|
296
|
+
"""Factory function to create an enhanced variant calling pipeline.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
reference_length: Length of reference sequence.
|
|
300
|
+
num_classes: Number of variant classes.
|
|
301
|
+
pileup_window_size: Window size for pileup context.
|
|
302
|
+
cnn_hidden_channels: Hidden channels for CNN classifier.
|
|
303
|
+
cnn_fc_dims: Fully connected dimensions for CNN.
|
|
304
|
+
enable_preprocessing: Whether to enable quality filtering.
|
|
305
|
+
enable_quality_recalibration: Whether to enable quality recalibration.
|
|
306
|
+
seed: Random seed.
|
|
307
|
+
|
|
308
|
+
Returns:
|
|
309
|
+
Configured EnhancedVariantCallingPipeline instance.
|
|
310
|
+
"""
|
|
311
|
+
if cnn_hidden_channels is None:
|
|
312
|
+
cnn_hidden_channels = (64, 128, 256)
|
|
313
|
+
if cnn_fc_dims is None:
|
|
314
|
+
cnn_fc_dims = (256, 128)
|
|
315
|
+
|
|
316
|
+
config = EnhancedVariantCallingPipelineConfig(
|
|
317
|
+
reference_length=reference_length,
|
|
318
|
+
num_classes=num_classes,
|
|
319
|
+
pileup_window_size=pileup_window_size,
|
|
320
|
+
cnn_hidden_channels=cnn_hidden_channels,
|
|
321
|
+
cnn_fc_dims=cnn_fc_dims,
|
|
322
|
+
enable_preprocessing=enable_preprocessing,
|
|
323
|
+
enable_quality_recalibration=enable_quality_recalibration,
|
|
324
|
+
)
|
|
325
|
+
rngs = nnx.Rngs(seed)
|
|
326
|
+
return EnhancedVariantCallingPipeline(config, rngs=rngs)
|