altar-enformer 0.3.0__tar.gz
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.
- altar_enformer-0.3.0/.gitignore +33 -0
- altar_enformer-0.3.0/LICENSE +21 -0
- altar_enformer-0.3.0/PKG-INFO +55 -0
- altar_enformer-0.3.0/README.md +30 -0
- altar_enformer-0.3.0/altar_enformer/__init__.py +29 -0
- altar_enformer-0.3.0/altar_enformer/plugin.py +263 -0
- altar_enformer-0.3.0/altar_enformer/py.typed +1 -0
- altar_enformer-0.3.0/altar_enformer/resources.py +330 -0
- altar_enformer-0.3.0/pyproject.toml +54 -0
- altar_enformer-0.3.0/tests/test_end_to_end.py +143 -0
- altar_enformer-0.3.0/tests/test_golden_lineage_ids.py +137 -0
- altar_enformer-0.3.0/tests/test_plugin.py +394 -0
- altar_enformer-0.3.0/tests/test_resources.py +176 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
*.pyc
|
|
2
|
+
*~
|
|
3
|
+
**/__pycache__/*
|
|
4
|
+
*.swp
|
|
5
|
+
.vscode/
|
|
6
|
+
.idea/
|
|
7
|
+
.DS_Store
|
|
8
|
+
.env*
|
|
9
|
+
.mypy_cache/
|
|
10
|
+
.ruff_cache/
|
|
11
|
+
.pytest_cache/
|
|
12
|
+
.coverage
|
|
13
|
+
htmlcov/
|
|
14
|
+
coverage.xml
|
|
15
|
+
pytest.xml
|
|
16
|
+
.hypothesis/
|
|
17
|
+
.python-version
|
|
18
|
+
.venv
|
|
19
|
+
.venv-*/
|
|
20
|
+
*.egg-info/
|
|
21
|
+
build/
|
|
22
|
+
dist/
|
|
23
|
+
site/
|
|
24
|
+
*.sqlite3
|
|
25
|
+
*.log
|
|
26
|
+
|
|
27
|
+
# Generated variant indexes and datasets. The small canonical gene table is tracked.
|
|
28
|
+
altar/altar/variants/data/ccres.dnatree
|
|
29
|
+
altar/altar/variants/data/region_annotations.parquet
|
|
30
|
+
altar/altar/variants/data/variants.pkl.gz
|
|
31
|
+
altar/altar/variants/data/region_provenance.json
|
|
32
|
+
altar/altar/variants/data/raw/
|
|
33
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Riya Sinha
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: altar-enformer
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Enformer model binding for large-scale Altar variant scoring
|
|
5
|
+
Project-URL: Documentation, https://kundajelab.github.io/altar/
|
|
6
|
+
Author: Riya Sinha
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Requires-Dist: altar<0.4,>=0.3.0
|
|
19
|
+
Provides-Extra: prepare
|
|
20
|
+
Requires-Dist: kagglehub<2,>=1; extra == 'prepare'
|
|
21
|
+
Provides-Extra: test
|
|
22
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'test'
|
|
23
|
+
Requires-Dist: pytest>=8; extra == 'test'
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# Altar Enformer binding
|
|
27
|
+
|
|
28
|
+
`altar-enformer` is the lightweight control-plane binding for high-throughput Enformer variant scoring. It
|
|
29
|
+
registers `ENFORMER` in Altar's canonical model-plugin group and has no TensorFlow dependency.
|
|
30
|
+
|
|
31
|
+
One Altar model instance contains immutable SavedModel and target-metadata resources plus a fixed selection
|
|
32
|
+
of Enformer's 5,313 human output tracks. A job is partitioned upstream into deterministic scoring batches;
|
|
33
|
+
the binding emits one independently retryable container task per batch. The runtime loads the model once per
|
|
34
|
+
task, microbatches reference/alternate sequence pairs, and writes:
|
|
35
|
+
|
|
36
|
+
- one primary row per variant, containing the track with the largest absolute SAD; and
|
|
37
|
+
- a `track_effects` detail row for every selected `(variant, track)` pair, preserving reference and alternate
|
|
38
|
+
activity, SAD, and SADR.
|
|
39
|
+
|
|
40
|
+
SAD and SADR follow the definitions in the [Basenji variant scorer linked by DeepMind's Enformer
|
|
41
|
+
release](https://github.com/calico/basenji/blob/738321c85f8925ae6ac318a6cd4901a42ea6bc3f/bin/basenji_sad.py):
|
|
42
|
+
`SAD = sum(alt) - sum(ref)` and `SADR = log2(sum(alt) + 1) - log2(sum(ref) + 1)` across the model's 896 output
|
|
43
|
+
bins. DeepMind's simpler [`EnformerScoreVariantsRaw`
|
|
44
|
+
notebook](https://github.com/google-deepmind/deepmind-research/blob/master/enformer/enformer-usage.ipynb) divides SAD
|
|
45
|
+
by the constant 896 by taking means; that does not change per-variant track ranking. `SAR` is a different Basenji
|
|
46
|
+
statistic—the sum of per-bin log ratios—and is intentionally not emitted under the wrong name. Track selection,
|
|
47
|
+
weight bytes, metadata bytes, runtime image, and hg38 reference identity are all durable inputs.
|
|
48
|
+
|
|
49
|
+
Scoring semantics 2.0 selects the primary track by absolute SAD, the main published Enformer variant-effect
|
|
50
|
+
score, and renames the former `sar`/`top_track_sar` fields to `sadr`/`top_track_sadr`. Existing primary scores
|
|
51
|
+
must be regenerated. Existing complete `track_effects` rows are sufficient for a later storage-layer migration
|
|
52
|
+
because their numeric `sar` values already contained SADR; Altar itself does not mutate deployed result stores.
|
|
53
|
+
|
|
54
|
+
The corresponding TensorFlow 2.13 / Python 3.10 executor lives under `runtimes/enformer` with its own lockfile
|
|
55
|
+
and immutable image lifecycle.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Altar Enformer binding
|
|
2
|
+
|
|
3
|
+
`altar-enformer` is the lightweight control-plane binding for high-throughput Enformer variant scoring. It
|
|
4
|
+
registers `ENFORMER` in Altar's canonical model-plugin group and has no TensorFlow dependency.
|
|
5
|
+
|
|
6
|
+
One Altar model instance contains immutable SavedModel and target-metadata resources plus a fixed selection
|
|
7
|
+
of Enformer's 5,313 human output tracks. A job is partitioned upstream into deterministic scoring batches;
|
|
8
|
+
the binding emits one independently retryable container task per batch. The runtime loads the model once per
|
|
9
|
+
task, microbatches reference/alternate sequence pairs, and writes:
|
|
10
|
+
|
|
11
|
+
- one primary row per variant, containing the track with the largest absolute SAD; and
|
|
12
|
+
- a `track_effects` detail row for every selected `(variant, track)` pair, preserving reference and alternate
|
|
13
|
+
activity, SAD, and SADR.
|
|
14
|
+
|
|
15
|
+
SAD and SADR follow the definitions in the [Basenji variant scorer linked by DeepMind's Enformer
|
|
16
|
+
release](https://github.com/calico/basenji/blob/738321c85f8925ae6ac318a6cd4901a42ea6bc3f/bin/basenji_sad.py):
|
|
17
|
+
`SAD = sum(alt) - sum(ref)` and `SADR = log2(sum(alt) + 1) - log2(sum(ref) + 1)` across the model's 896 output
|
|
18
|
+
bins. DeepMind's simpler [`EnformerScoreVariantsRaw`
|
|
19
|
+
notebook](https://github.com/google-deepmind/deepmind-research/blob/master/enformer/enformer-usage.ipynb) divides SAD
|
|
20
|
+
by the constant 896 by taking means; that does not change per-variant track ranking. `SAR` is a different Basenji
|
|
21
|
+
statistic—the sum of per-bin log ratios—and is intentionally not emitted under the wrong name. Track selection,
|
|
22
|
+
weight bytes, metadata bytes, runtime image, and hg38 reference identity are all durable inputs.
|
|
23
|
+
|
|
24
|
+
Scoring semantics 2.0 selects the primary track by absolute SAD, the main published Enformer variant-effect
|
|
25
|
+
score, and renames the former `sar`/`top_track_sar` fields to `sadr`/`top_track_sadr`. Existing primary scores
|
|
26
|
+
must be regenerated. Existing complete `track_effects` rows are sufficient for a later storage-layer migration
|
|
27
|
+
because their numeric `sar` values already contained SADR; Altar itself does not mutate deployed result stores.
|
|
28
|
+
|
|
29
|
+
The corresponding TensorFlow 2.13 / Python 3.10 executor lives under `runtimes/enformer` with its own lockfile
|
|
30
|
+
and immutable image lifecycle.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Copyright 2026 Riya Sinha
|
|
2
|
+
"""Enformer model binding for Altar."""
|
|
3
|
+
|
|
4
|
+
from altar_enformer.plugin import (
|
|
5
|
+
DEFAULT_IMAGE,
|
|
6
|
+
HUMAN_TRACK_COUNT,
|
|
7
|
+
KIND_SCORING,
|
|
8
|
+
OUTPUT_BIN_SIZE,
|
|
9
|
+
OUTPUT_BINS,
|
|
10
|
+
SEQUENCE_LENGTH,
|
|
11
|
+
EnformerConfiguration,
|
|
12
|
+
EnformerPlugin,
|
|
13
|
+
EnformerRunInputs,
|
|
14
|
+
EnformerShardKind,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"DEFAULT_IMAGE",
|
|
20
|
+
"HUMAN_TRACK_COUNT",
|
|
21
|
+
"KIND_SCORING",
|
|
22
|
+
"OUTPUT_BINS",
|
|
23
|
+
"OUTPUT_BIN_SIZE",
|
|
24
|
+
"SEQUENCE_LENGTH",
|
|
25
|
+
"EnformerConfiguration",
|
|
26
|
+
"EnformerPlugin",
|
|
27
|
+
"EnformerRunInputs",
|
|
28
|
+
"EnformerShardKind",
|
|
29
|
+
]
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# Copyright 2026 Riya Sinha
|
|
2
|
+
"""Backend-neutral Enformer binding for large-scale variant scoring.
|
|
3
|
+
|
|
4
|
+
The binding emits one independent container task for the request's deterministic scoring batch. The runtime
|
|
5
|
+
loads a content-addressed Enformer SavedModel once, microbatches reference/alternate sequence pairs, writes a
|
|
6
|
+
compact primary row per variant, and preserves every selected track's official SAD/SADR effect as named detail.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
import enum
|
|
11
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
12
|
+
|
|
13
|
+
from altar.execution import GpuPool, ResourceRequest
|
|
14
|
+
from altar.models import (
|
|
15
|
+
ApiVersionRange,
|
|
16
|
+
ContainerImageDigest,
|
|
17
|
+
ContainerScoringPlan,
|
|
18
|
+
DetailSchema,
|
|
19
|
+
ModelConfiguration,
|
|
20
|
+
ModelPlugin,
|
|
21
|
+
OutputSelection,
|
|
22
|
+
PluginCapability,
|
|
23
|
+
PluginKind,
|
|
24
|
+
PluginManifest,
|
|
25
|
+
PrioritizationPolicy,
|
|
26
|
+
ReferenceGenomeRunInputs,
|
|
27
|
+
ResourceReference,
|
|
28
|
+
ResultField,
|
|
29
|
+
ResultSchema,
|
|
30
|
+
RuntimeIdentityPolicy,
|
|
31
|
+
RuntimeKind,
|
|
32
|
+
RuntimeRequirement,
|
|
33
|
+
ScoringRequest,
|
|
34
|
+
VariantClass,
|
|
35
|
+
VariantEligibility,
|
|
36
|
+
require_resource_digests,
|
|
37
|
+
require_strictly_increasing,
|
|
38
|
+
resource_transfer,
|
|
39
|
+
single_container_plan,
|
|
40
|
+
)
|
|
41
|
+
from altar.predicates import Abs, Col, Ge, Lit, Predicate
|
|
42
|
+
from pydantic import Field, model_validator
|
|
43
|
+
|
|
44
|
+
from altar_enformer.resources import manifest_resources
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
if TYPE_CHECKING:
|
|
48
|
+
import os
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
SEQUENCE_LENGTH = 393_216
|
|
52
|
+
OUTPUT_BINS = 896
|
|
53
|
+
OUTPUT_BIN_SIZE = 128
|
|
54
|
+
HUMAN_TRACK_COUNT = 5_313
|
|
55
|
+
DEFAULT_IMAGE = "riyavsinha/altar-enformer@sha256:52aafa8c8d781763559814c4ab956ea4094fadb556e6c4903097dc3fab500fe5"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class EnformerShardKind(enum.StrEnum):
|
|
59
|
+
"""Stable execution kind emitted by :class:`EnformerPlugin`."""
|
|
60
|
+
|
|
61
|
+
SCORING = "enformer_scoring"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
KIND_SCORING = EnformerShardKind.SCORING
|
|
65
|
+
_SCORE_RESOURCES = ResourceRequest(gpu=GpuPool.NORMAL_GPU, count=1, memory_gb=16)
|
|
66
|
+
_SAD_PRIORITIZE_THRESHOLD = 0.5
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class EnformerConfiguration(ModelConfiguration):
|
|
70
|
+
"""Immutable Enformer resources and selected human output tracks.
|
|
71
|
+
|
|
72
|
+
``weights`` points to a tar archive containing one TensorFlow SavedModel. ``track_metadata`` is the
|
|
73
|
+
official ``targets_human.txt`` table whose ``index`` column maps output channels to stable identifiers.
|
|
74
|
+
Track indices are canonicalized by requiring strictly increasing values; equivalent selections therefore
|
|
75
|
+
cannot acquire different cache identities solely from ordering.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
weights: ResourceReference
|
|
79
|
+
track_metadata: ResourceReference
|
|
80
|
+
track_indices: tuple[int, ...] = Field(min_length=1)
|
|
81
|
+
image: ContainerImageDigest = DEFAULT_IMAGE
|
|
82
|
+
|
|
83
|
+
@model_validator(mode="after")
|
|
84
|
+
def validate_resources_and_tracks(self) -> EnformerConfiguration:
|
|
85
|
+
require_resource_digests(self, owner="Enformer")
|
|
86
|
+
require_strictly_increasing(
|
|
87
|
+
self.track_indices, owner="Enformer", field="track_indices", minimum=0, maximum=HUMAN_TRACK_COUNT - 1
|
|
88
|
+
)
|
|
89
|
+
return self
|
|
90
|
+
|
|
91
|
+
@classmethod
|
|
92
|
+
def from_resource_manifest(
|
|
93
|
+
cls, path: str | os.PathLike[str], *, base_uri: str | None = None, **settings: Any
|
|
94
|
+
) -> EnformerConfiguration:
|
|
95
|
+
"""Build a configuration from the ``enformer.resources.json`` that ``altar-enformer-resources`` wrote.
|
|
96
|
+
|
|
97
|
+
``settings`` are the remaining configuration fields: ``track_indices`` and ``image``. See
|
|
98
|
+
:func:`altar_enformer.resources.manifest_resources` for how ``base_uri`` locates the files.
|
|
99
|
+
"""
|
|
100
|
+
resources = manifest_resources(path, base_uri=base_uri)
|
|
101
|
+
return cls(weights=resources.weights, track_metadata=resources.track_metadata, **settings)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class EnformerRunInputs(ReferenceGenomeRunInputs):
|
|
105
|
+
"""Per-run Enformer inputs, currently restricted to its training assembly."""
|
|
106
|
+
|
|
107
|
+
supported_genome_builds = frozenset({"hg38"})
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class EnformerPlugin(ModelPlugin):
|
|
111
|
+
"""Predicts how a variant changes the chromatin, CAGE and TF tracks you select from Enformer's 5,313 (SAD)."""
|
|
112
|
+
|
|
113
|
+
model_type = "ENFORMER"
|
|
114
|
+
manifest = PluginManifest(
|
|
115
|
+
plugin_id="org.kundajelab.altar.model.enformer",
|
|
116
|
+
kind=PluginKind.MODEL,
|
|
117
|
+
capabilities=frozenset({PluginCapability.SCORE, PluginCapability.MATERIALIZE_RESULTS}),
|
|
118
|
+
architecture="Enformer",
|
|
119
|
+
plugin_version="0.0.1",
|
|
120
|
+
altar_api=ApiVersionRange("0.1.0", "0.2.0"),
|
|
121
|
+
configuration_schema_version="0.0.1",
|
|
122
|
+
result_schema=ResultSchema(
|
|
123
|
+
version="0.0.1",
|
|
124
|
+
fields=(
|
|
125
|
+
ResultField("top_track_index", "int", "Top Track Index", "Output index with largest absolute SAD"),
|
|
126
|
+
ResultField("top_track_id", "str", "Top Track", "Identifier of the output with largest absolute SAD"),
|
|
127
|
+
ResultField(
|
|
128
|
+
"top_track_sad",
|
|
129
|
+
"float",
|
|
130
|
+
"Top Track SAD",
|
|
131
|
+
"Alternate minus reference summed activity for the track with largest absolute SAD",
|
|
132
|
+
),
|
|
133
|
+
ResultField(
|
|
134
|
+
"top_track_sadr",
|
|
135
|
+
"float",
|
|
136
|
+
"Top Track SADR",
|
|
137
|
+
"Log2 alternate/reference summed-activity ratio for the track with largest absolute SAD",
|
|
138
|
+
),
|
|
139
|
+
ResultField("n_tracks_scored", "int", "Tracks Scored", "Number of selected human output tracks"),
|
|
140
|
+
),
|
|
141
|
+
),
|
|
142
|
+
detail_schemas=(
|
|
143
|
+
DetailSchema(
|
|
144
|
+
name="track_effects",
|
|
145
|
+
version="0.0.1",
|
|
146
|
+
description="Official Enformer SAD and SADR effects for every selected human output track.",
|
|
147
|
+
fields=(
|
|
148
|
+
ResultField("track_index", "int", "Track Index", "Zero-based Enformer human output index", False),
|
|
149
|
+
ResultField("track_id", "str", "Track ID", "Identifier from targets_human.txt", False),
|
|
150
|
+
ResultField(
|
|
151
|
+
"ref_signal", "float", "Reference Signal", "Reference activity summed over 896 bins", False
|
|
152
|
+
),
|
|
153
|
+
ResultField(
|
|
154
|
+
"alt_signal", "float", "Alternate Signal", "Alternate activity summed over 896 bins", False
|
|
155
|
+
),
|
|
156
|
+
ResultField("sad", "float", "SAD", "Alternate minus reference summed activity", False),
|
|
157
|
+
ResultField(
|
|
158
|
+
"sadr",
|
|
159
|
+
"float",
|
|
160
|
+
"SADR",
|
|
161
|
+
"Log2 alternate/reference summed-activity ratio with pseudocount 1",
|
|
162
|
+
False,
|
|
163
|
+
),
|
|
164
|
+
),
|
|
165
|
+
key_fields=("track_index",),
|
|
166
|
+
),
|
|
167
|
+
),
|
|
168
|
+
# The Enformer runtime substitutes one reference base; batch preparation filters out indels and MNVs.
|
|
169
|
+
variant_eligibility=VariantEligibility(frozenset({VariantClass.SNV})),
|
|
170
|
+
prioritization=PrioritizationPolicy(name="enformer-sad-effect-v2", version="0.0.1"),
|
|
171
|
+
runtimes=(
|
|
172
|
+
RuntimeRequirement(
|
|
173
|
+
name="model_runtime",
|
|
174
|
+
kind=RuntimeKind.CONTAINER_IMAGE,
|
|
175
|
+
policy=RuntimeIdentityPolicy.DIGEST_REQUIRED,
|
|
176
|
+
),
|
|
177
|
+
),
|
|
178
|
+
)
|
|
179
|
+
configuration_schema_id = "org.kundajelab.altar.model.enformer.configuration"
|
|
180
|
+
configuration_model = EnformerConfiguration
|
|
181
|
+
run_input_model = EnformerRunInputs
|
|
182
|
+
default_output = OutputSelection(outputs=("scores", "track_effects"), reducer="official_sad_sadr_v2")
|
|
183
|
+
|
|
184
|
+
def scoring_runtime_identities(self, configuration: ModelConfiguration) -> dict[str, str]:
|
|
185
|
+
"""Record the configured Enformer image as the scoring plan's one runtime."""
|
|
186
|
+
return {"model_runtime": self.parse_configuration_as(configuration, EnformerConfiguration).image}
|
|
187
|
+
|
|
188
|
+
def build_scoring_plan(self, request: ScoringRequest) -> ContainerScoringPlan:
|
|
189
|
+
"""Build one independently retryable task for one deterministic variant batch."""
|
|
190
|
+
configuration = self.parse_configuration_as(request.configuration, EnformerConfiguration)
|
|
191
|
+
run_inputs = self.parse_run_inputs_as(request.run_inputs, EnformerRunInputs)
|
|
192
|
+
|
|
193
|
+
layout, resolver = request.layout, request.resolver
|
|
194
|
+
weights_logical = layout.model_resource_file(request.model_id, "enformer.savedmodel.tar.gz")
|
|
195
|
+
metadata_logical = layout.model_resource_file(request.model_id, "targets_human.txt")
|
|
196
|
+
genome_logical = layout.genome_fasta(request.genome_label)
|
|
197
|
+
variants_logical = layout.model_variants_file(request.job_id, request.model_id, request.scoring_batch)
|
|
198
|
+
primary_logical = layout.scoring_result_file(request.job_id, request.model_id, request.scoring_batch)
|
|
199
|
+
details_logical = layout.detail_result_file(
|
|
200
|
+
request.job_id,
|
|
201
|
+
request.model_id,
|
|
202
|
+
"track_effects",
|
|
203
|
+
request.scoring_batch,
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
command = [
|
|
207
|
+
"enformer-score",
|
|
208
|
+
"score",
|
|
209
|
+
"--weights",
|
|
210
|
+
resolver.resolve(weights_logical),
|
|
211
|
+
"--weights-digest",
|
|
212
|
+
cast("str", configuration.weights.digest),
|
|
213
|
+
"--track-metadata",
|
|
214
|
+
resolver.resolve(metadata_logical),
|
|
215
|
+
"--track-metadata-digest",
|
|
216
|
+
cast("str", configuration.track_metadata.digest),
|
|
217
|
+
]
|
|
218
|
+
for track_index in configuration.track_indices:
|
|
219
|
+
command += ["--track-index", str(track_index)]
|
|
220
|
+
command += [
|
|
221
|
+
"--genome",
|
|
222
|
+
resolver.resolve(genome_logical),
|
|
223
|
+
"--genome-digest",
|
|
224
|
+
cast("str", run_inputs.genome.digest),
|
|
225
|
+
"--variants",
|
|
226
|
+
resolver.resolve(variants_logical),
|
|
227
|
+
"--primary-output",
|
|
228
|
+
resolver.resolve(primary_logical),
|
|
229
|
+
"--detail-output",
|
|
230
|
+
resolver.resolve(details_logical),
|
|
231
|
+
]
|
|
232
|
+
|
|
233
|
+
return single_container_plan(
|
|
234
|
+
self,
|
|
235
|
+
request,
|
|
236
|
+
kind=KIND_SCORING,
|
|
237
|
+
image=configuration.image,
|
|
238
|
+
command=command,
|
|
239
|
+
resources=_SCORE_RESOURCES,
|
|
240
|
+
inputs=[
|
|
241
|
+
resource_transfer(configuration.weights, weights_logical, locality_key=request.model_id),
|
|
242
|
+
resource_transfer(configuration.track_metadata, metadata_logical, locality_key=request.model_id),
|
|
243
|
+
resource_transfer(run_inputs.genome, genome_logical),
|
|
244
|
+
],
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
def prioritize_predicate(self) -> Predicate:
|
|
248
|
+
# Placeholder effect threshold, not a calibrated biological cutoff.
|
|
249
|
+
return Ge(Abs(Col("top_track_sad")), Lit(_SAD_PRIORITIZE_THRESHOLD))
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
__all__ = [
|
|
253
|
+
"DEFAULT_IMAGE",
|
|
254
|
+
"HUMAN_TRACK_COUNT",
|
|
255
|
+
"KIND_SCORING",
|
|
256
|
+
"OUTPUT_BINS",
|
|
257
|
+
"OUTPUT_BIN_SIZE",
|
|
258
|
+
"SEQUENCE_LENGTH",
|
|
259
|
+
"EnformerConfiguration",
|
|
260
|
+
"EnformerPlugin",
|
|
261
|
+
"EnformerRunInputs",
|
|
262
|
+
"EnformerShardKind",
|
|
263
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|