dnakit 0.1.0.dev0__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.
- dnakit/__init__.py +108 -0
- dnakit/_version.py +5 -0
- dnakit/alignment/__init__.py +6 -0
- dnakit/alignment/pairwise.py +512 -0
- dnakit/alignment/results.py +188 -0
- dnakit/backends/__init__.py +80 -0
- dnakit/backends/external.py +517 -0
- dnakit/backends/registry.py +207 -0
- dnakit/batch.py +452 -0
- dnakit/cache/__init__.py +5 -0
- dnakit/cache/store.py +424 -0
- dnakit/chunking.py +920 -0
- dnakit/cli/__init__.py +5 -0
- dnakit/cli/__main__.py +6 -0
- dnakit/cli/app.py +814 -0
- dnakit/cli/workflow.py +94 -0
- dnakit/config/__init__.py +5 -0
- dnakit/config/loader.py +381 -0
- dnakit/core/__init__.py +80 -0
- dnakit/core/_json.py +206 -0
- dnakit/core/backend_info.py +70 -0
- dnakit/core/collection.py +163 -0
- dnakit/core/coordinates.py +295 -0
- dnakit/core/enums.py +95 -0
- dnakit/core/facade.py +719 -0
- dnakit/core/feature.py +90 -0
- dnakit/core/gap.py +82 -0
- dnakit/core/issues.py +62 -0
- dnakit/core/provenance.py +305 -0
- dnakit/core/record.py +161 -0
- dnakit/core/results.py +134 -0
- dnakit/core/sequence.py +327 -0
- dnakit/datasets/__init__.py +100 -0
- dnakit/datasets/_advanced_shared.py +198 -0
- dnakit/datasets/_metadata.py +33 -0
- dnakit/datasets/advanced_deduplicate.py +183 -0
- dnakit/datasets/advanced_split.py +302 -0
- dnakit/datasets/clustering.py +286 -0
- dnakit/datasets/config.py +531 -0
- dnakit/datasets/deduplicate.py +303 -0
- dnakit/datasets/evaluation.py +244 -0
- dnakit/datasets/filter.py +135 -0
- dnakit/datasets/neural_clustering.py +221 -0
- dnakit/datasets/results.py +520 -0
- dnakit/datasets/split.py +450 -0
- dnakit/descriptors/__init__.py +102 -0
- dnakit/descriptors/_dinucleotide.py +345 -0
- dnakit/descriptors/_shared.py +180 -0
- dnakit/descriptors/all.py +917 -0
- dnakit/descriptors/basic.py +193 -0
- dnakit/descriptors/codon.py +195 -0
- dnakit/descriptors/complexity.py +201 -0
- dnakit/descriptors/entropy.py +101 -0
- dnakit/descriptors/homopolymer.py +105 -0
- dnakit/descriptors/kmer.py +88 -0
- dnakit/descriptors/results.py +286 -0
- dnakit/descriptors/schema.py +414 -0
- dnakit/descriptors/window.py +203 -0
- dnakit/download/__init__.py +54 -0
- dnakit/download/catalogs.py +166 -0
- dnakit/download/ena.py +131 -0
- dnakit/download/encode.py +103 -0
- dnakit/download/files.py +469 -0
- dnakit/download/indexes.py +233 -0
- dnakit/download/metadata.py +164 -0
- dnakit/download/models.py +227 -0
- dnakit/download/ncbi.py +333 -0
- dnakit/download/sequence.py +133 -0
- dnakit/download/ucsc.py +99 -0
- dnakit/evaluation/__init__.py +81 -0
- dnakit/evaluation/_shared.py +288 -0
- dnakit/evaluation/collection.py +270 -0
- dnakit/evaluation/config.py +591 -0
- dnakit/evaluation/distribution.py +287 -0
- dnakit/evaluation/frechet.py +223 -0
- dnakit/evaluation/generative.py +381 -0
- dnakit/evaluation/reference.py +409 -0
- dnakit/evaluation/results.py +137 -0
- dnakit/evaluation/scorecard.py +211 -0
- dnakit/evaluation/sequence.py +403 -0
- dnakit/evaluation/synthesis.py +249 -0
- dnakit/exceptions.py +189 -0
- dnakit/fingerprints/__init__.py +109 -0
- dnakit/fingerprints/_shared.py +116 -0
- dnakit/fingerprints/advanced.py +829 -0
- dnakit/fingerprints/bit.py +229 -0
- dnakit/fingerprints/encoding.py +351 -0
- dnakit/fingerprints/kmer.py +170 -0
- dnakit/fingerprints/results.py +531 -0
- dnakit/fingerprints/sketch.py +246 -0
- dnakit/io/__init__.py +112 -0
- dnakit/io/_advanced_common.py +105 -0
- dnakit/io/_formats.py +994 -0
- dnakit/io/annotations.py +1179 -0
- dnakit/io/api.py +759 -0
- dnakit/io/config.py +315 -0
- dnakit/io/genbank.py +523 -0
- dnakit/io/indexed.py +1146 -0
- dnakit/io/metadata.py +452 -0
- dnakit/io/parquet.py +56 -0
- dnakit/io/results.py +131 -0
- dnakit/io/source.py +138 -0
- dnakit/io/tables.py +1237 -0
- dnakit/molbio/__init__.py +101 -0
- dnakit/molbio/_shared.py +266 -0
- dnakit/molbio/assembly.py +279 -0
- dnakit/molbio/crispr.py +181 -0
- dnakit/molbio/optimization.py +897 -0
- dnakit/molbio/primer3_design.py +667 -0
- dnakit/molbio/primers.py +899 -0
- dnakit/molbio/restriction.py +573 -0
- dnakit/molbio/results.py +583 -0
- dnakit/ops/__init__.py +588 -0
- dnakit/ops/_common.py +201 -0
- dnakit/ops/circular.py +193 -0
- dnakit/ops/concat.py +204 -0
- dnakit/ops/direction.py +27 -0
- dnakit/ops/edit.py +443 -0
- dnakit/ops/evolution.py +991 -0
- dnakit/ops/mutation.py +151 -0
- dnakit/ops/records.py +1012 -0
- dnakit/ops/translation.py +257 -0
- dnakit/patterns/__init__.py +81 -0
- dnakit/patterns/_shared.py +282 -0
- dnakit/patterns/coding.py +360 -0
- dnakit/patterns/crispr.py +337 -0
- dnakit/patterns/motif.py +721 -0
- dnakit/patterns/regions.py +341 -0
- dnakit/patterns/repeats.py +480 -0
- dnakit/patterns/restriction.py +281 -0
- dnakit/patterns/results.py +411 -0
- dnakit/py.typed +1 -0
- dnakit/references/__init__.py +27 -0
- dnakit/references/models.py +155 -0
- dnakit/references/ncbi.py +785 -0
- dnakit/representations/__init__.py +29 -0
- dnakit/representations/backends.py +928 -0
- dnakit/representations/checkpoints.py +356 -0
- dnakit/representations/extraction.py +220 -0
- dnakit/representations/models.py +395 -0
- dnakit/representations/results.py +79 -0
- dnakit/search/__init__.py +132 -0
- dnakit/search/_http.py +271 -0
- dnakit/search/_shared.py +108 -0
- dnakit/search/blast.py +516 -0
- dnakit/search/ena.py +245 -0
- dnakit/search/encode.py +102 -0
- dnakit/search/ensembl.py +874 -0
- dnakit/search/models.py +159 -0
- dnakit/search/ncbi.py +756 -0
- dnakit/search/ucsc.py +388 -0
- dnakit/secondary_structure/__init__.py +38 -0
- dnakit/secondary_structure/dotbracket.py +410 -0
- dnakit/secondary_structure/nupack.py +589 -0
- dnakit/secondary_structure/results.py +142 -0
- dnakit/similarity/__init__.py +125 -0
- dnakit/similarity/_shared.py +152 -0
- dnakit/similarity/approximate.py +258 -0
- dnakit/similarity/compare.py +162 -0
- dnakit/similarity/dashing.py +936 -0
- dnakit/similarity/distance.py +279 -0
- dnakit/similarity/index.py +365 -0
- dnakit/similarity/matrix.py +254 -0
- dnakit/similarity/results.py +676 -0
- dnakit/similarity/search.py +286 -0
- dnakit/similarity/sketch.py +96 -0
- dnakit/similarity/vector.py +662 -0
- dnakit/standardize/__init__.py +77 -0
- dnakit/standardize/_shared.py +100 -0
- dnakit/standardize/config.py +411 -0
- dnakit/standardize/gaps.py +1060 -0
- dnakit/standardize/normalize.py +565 -0
- dnakit/standardize/results.py +247 -0
- dnakit/standardize/validate.py +487 -0
- dnakit/structure3d/__init__.py +47 -0
- dnakit/structure3d/_shared.py +47 -0
- dnakit/structure3d/geometry.py +773 -0
- dnakit/structure3d/pdb.py +253 -0
- dnakit/structure3d/results.py +233 -0
- dnakit/structure3d/threedna.py +174 -0
- dnakit/thermodynamics/__init__.py +112 -0
- dnakit/thermodynamics/_shared.py +92 -0
- dnakit/thermodynamics/backends.py +653 -0
- dnakit/thermodynamics/calculations.py +837 -0
- dnakit/thermodynamics/config.py +175 -0
- dnakit/thermodynamics/equilibrium.py +340 -0
- dnakit/thermodynamics/optics.py +385 -0
- dnakit/thermodynamics/parameters.py +79 -0
- dnakit/thermodynamics/results.py +445 -0
- dnakit/visualization/__init__.py +43 -0
- dnakit/visualization/_svg.py +185 -0
- dnakit/visualization/advanced.py +314 -0
- dnakit/visualization/config.py +255 -0
- dnakit/visualization/export.py +349 -0
- dnakit/visualization/matrix.py +279 -0
- dnakit/visualization/report.py +431 -0
- dnakit/visualization/results.py +236 -0
- dnakit/visualization/sequence.py +459 -0
- dnakit/workflows/__init__.py +45 -0
- dnakit/workflows/manifest.py +365 -0
- dnakit/workflows/runner.py +1548 -0
- dnakit/workflows/schema.py +898 -0
- dnakit-0.1.0.dev0.dist-info/METADATA +126 -0
- dnakit-0.1.0.dev0.dist-info/RECORD +210 -0
- dnakit-0.1.0.dev0.dist-info/WHEEL +5 -0
- dnakit-0.1.0.dev0.dist-info/entry_points.txt +2 -0
- dnakit-0.1.0.dev0.dist-info/licenses/DISCLAIMER.md +26 -0
- dnakit-0.1.0.dev0.dist-info/licenses/LICENSE +21 -0
- dnakit-0.1.0.dev0.dist-info/licenses/THIRD_PARTY_NOTICES.md +73 -0
- dnakit-0.1.0.dev0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
"""Registry and configuration for DNA foundation-model representations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from typing import Literal, TypeAlias
|
|
8
|
+
|
|
9
|
+
from dnakit.exceptions import ConfigurationError
|
|
10
|
+
|
|
11
|
+
CheckpointKind: TypeAlias = Literal["huggingface", "dataverse"]
|
|
12
|
+
LoaderKind: TypeAlias = Literal[
|
|
13
|
+
"transformers",
|
|
14
|
+
"enformer",
|
|
15
|
+
"alphagenome",
|
|
16
|
+
"janusdna",
|
|
17
|
+
"evo2",
|
|
18
|
+
]
|
|
19
|
+
PoolingMethod: TypeAlias = Literal["mean", "cls", "max", "last"]
|
|
20
|
+
AmbiguityPolicy: TypeAlias = Literal["replace_with_n", "error"]
|
|
21
|
+
TorchDType: TypeAlias = Literal["auto", "float32", "float16", "bfloat16"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True, slots=True)
|
|
25
|
+
class DNAEmbeddingModel:
|
|
26
|
+
"""One selectable DNA model and its official checkpoint metadata."""
|
|
27
|
+
|
|
28
|
+
name: str
|
|
29
|
+
display_name: str
|
|
30
|
+
loader: LoaderKind
|
|
31
|
+
checkpoint_kind: CheckpointKind
|
|
32
|
+
checkpoint_id: str
|
|
33
|
+
cache_name: str
|
|
34
|
+
source_repository: str
|
|
35
|
+
checkpoint_url: str
|
|
36
|
+
chunk_length: int
|
|
37
|
+
chunk_unit: Literal["bp", "token"]
|
|
38
|
+
default_pooling: PoolingMethod = "mean"
|
|
39
|
+
trust_remote_code: bool = False
|
|
40
|
+
required_package: str | None = None
|
|
41
|
+
output_dimension: int | None = None
|
|
42
|
+
allow_patterns: tuple[str, ...] | None = None
|
|
43
|
+
archive_name: str | None = None
|
|
44
|
+
archive_md5: str | None = None
|
|
45
|
+
evo2_layer: str | None = None
|
|
46
|
+
gated: bool = False
|
|
47
|
+
notes: str = ""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
_HF_MODEL_PATTERNS = (
|
|
51
|
+
"*.bin",
|
|
52
|
+
"*.json",
|
|
53
|
+
"*.model",
|
|
54
|
+
"*.pt",
|
|
55
|
+
"*.py",
|
|
56
|
+
"*.safetensors",
|
|
57
|
+
"*.txt",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
MODEL_REGISTRY: dict[str, DNAEmbeddingModel] = {
|
|
62
|
+
"dnabert2": DNAEmbeddingModel(
|
|
63
|
+
name="dnabert2",
|
|
64
|
+
display_name="DNABERT-2-117M",
|
|
65
|
+
loader="transformers",
|
|
66
|
+
checkpoint_kind="huggingface",
|
|
67
|
+
checkpoint_id="zhihan1996/DNABERT-2-117M",
|
|
68
|
+
cache_name="dnabert2-117m",
|
|
69
|
+
source_repository="https://github.com/MAGICS-LAB/DNABERT_2",
|
|
70
|
+
checkpoint_url="https://huggingface.co/zhihan1996/DNABERT-2-117M",
|
|
71
|
+
chunk_length=512,
|
|
72
|
+
chunk_unit="token",
|
|
73
|
+
trust_remote_code=True,
|
|
74
|
+
allow_patterns=_HF_MODEL_PATTERNS,
|
|
75
|
+
),
|
|
76
|
+
"ntv2": DNAEmbeddingModel(
|
|
77
|
+
name="ntv2",
|
|
78
|
+
display_name="Nucleotide Transformer v2 500M multi-species",
|
|
79
|
+
loader="transformers",
|
|
80
|
+
checkpoint_kind="huggingface",
|
|
81
|
+
checkpoint_id="InstaDeepAI/nucleotide-transformer-v2-500m-multi-species",
|
|
82
|
+
cache_name="ntv2-500m-multi-species",
|
|
83
|
+
source_repository="https://github.com/instadeepai/nucleotide-transformer",
|
|
84
|
+
checkpoint_url=(
|
|
85
|
+
"https://huggingface.co/InstaDeepAI/nucleotide-transformer-v2-500m-multi-species"
|
|
86
|
+
),
|
|
87
|
+
chunk_length=2_048,
|
|
88
|
+
chunk_unit="token",
|
|
89
|
+
trust_remote_code=True,
|
|
90
|
+
allow_patterns=_HF_MODEL_PATTERNS,
|
|
91
|
+
),
|
|
92
|
+
"hyenadna": DNAEmbeddingModel(
|
|
93
|
+
name="hyenadna",
|
|
94
|
+
display_name="HyenaDNA medium 450k",
|
|
95
|
+
loader="transformers",
|
|
96
|
+
checkpoint_kind="huggingface",
|
|
97
|
+
checkpoint_id="LongSafari/hyenadna-medium-450k-seqlen-hf",
|
|
98
|
+
cache_name="hyenadna-medium-450k",
|
|
99
|
+
source_repository="https://github.com/HazyResearch/hyena-dna",
|
|
100
|
+
checkpoint_url="https://huggingface.co/LongSafari/hyenadna-medium-450k-seqlen-hf",
|
|
101
|
+
chunk_length=450_000,
|
|
102
|
+
chunk_unit="bp",
|
|
103
|
+
trust_remote_code=True,
|
|
104
|
+
allow_patterns=_HF_MODEL_PATTERNS,
|
|
105
|
+
),
|
|
106
|
+
"caduceus": DNAEmbeddingModel(
|
|
107
|
+
name="caduceus",
|
|
108
|
+
display_name="Caduceus-Ph 131k",
|
|
109
|
+
loader="transformers",
|
|
110
|
+
checkpoint_kind="huggingface",
|
|
111
|
+
checkpoint_id="kuleshov-group/caduceus-ph_seqlen-131k_d_model-256_n_layer-16",
|
|
112
|
+
cache_name="caduceus-ph-131k",
|
|
113
|
+
source_repository="https://github.com/kuleshov-group/caduceus",
|
|
114
|
+
checkpoint_url=(
|
|
115
|
+
"https://huggingface.co/kuleshov-group/caduceus-ph_seqlen-131k_d_model-256_n_layer-16"
|
|
116
|
+
),
|
|
117
|
+
chunk_length=131_072,
|
|
118
|
+
chunk_unit="bp",
|
|
119
|
+
trust_remote_code=True,
|
|
120
|
+
allow_patterns=_HF_MODEL_PATTERNS,
|
|
121
|
+
),
|
|
122
|
+
"grover": DNAEmbeddingModel(
|
|
123
|
+
name="grover",
|
|
124
|
+
display_name="GROVER",
|
|
125
|
+
loader="transformers",
|
|
126
|
+
checkpoint_kind="huggingface",
|
|
127
|
+
checkpoint_id="PoetschLab/GROVER",
|
|
128
|
+
cache_name="grover",
|
|
129
|
+
source_repository="https://huggingface.co/PoetschLab/GROVER",
|
|
130
|
+
checkpoint_url="https://huggingface.co/PoetschLab/GROVER",
|
|
131
|
+
chunk_length=512,
|
|
132
|
+
chunk_unit="token",
|
|
133
|
+
allow_patterns=_HF_MODEL_PATTERNS,
|
|
134
|
+
notes="Only model and tokenizer files are downloaded; tokenized chromosomes are excluded.",
|
|
135
|
+
),
|
|
136
|
+
"lucaone": DNAEmbeddingModel(
|
|
137
|
+
name="lucaone",
|
|
138
|
+
display_name="LucaOne gene step 36.8M",
|
|
139
|
+
loader="transformers",
|
|
140
|
+
checkpoint_kind="huggingface",
|
|
141
|
+
checkpoint_id="LucaGroup/LucaOne-gene-step36.8M",
|
|
142
|
+
cache_name="lucaone-gene-step36-8m",
|
|
143
|
+
source_repository="https://github.com/LucaOne/LucaOne",
|
|
144
|
+
checkpoint_url="https://huggingface.co/LucaGroup/LucaOne-gene-step36.8M",
|
|
145
|
+
chunk_length=4_096,
|
|
146
|
+
chunk_unit="token",
|
|
147
|
+
trust_remote_code=True,
|
|
148
|
+
allow_patterns=_HF_MODEL_PATTERNS,
|
|
149
|
+
),
|
|
150
|
+
"generator": DNAEmbeddingModel(
|
|
151
|
+
name="generator",
|
|
152
|
+
display_name="GENERator v2 eukaryote 1.2B",
|
|
153
|
+
loader="transformers",
|
|
154
|
+
checkpoint_kind="huggingface",
|
|
155
|
+
checkpoint_id="GenerTeam/GENERator-v2-eukaryote-1.2b-base",
|
|
156
|
+
cache_name="generator-v2-eukaryote-1-2b",
|
|
157
|
+
source_repository="https://github.com/GenerTeam/GENERator",
|
|
158
|
+
checkpoint_url="https://huggingface.co/GenerTeam/GENERator-v2-eukaryote-1.2b-base",
|
|
159
|
+
chunk_length=16_384,
|
|
160
|
+
chunk_unit="token",
|
|
161
|
+
trust_remote_code=True,
|
|
162
|
+
allow_patterns=_HF_MODEL_PATTERNS,
|
|
163
|
+
),
|
|
164
|
+
"enformer": DNAEmbeddingModel(
|
|
165
|
+
name="enformer",
|
|
166
|
+
display_name="Enformer PyTorch",
|
|
167
|
+
loader="enformer",
|
|
168
|
+
checkpoint_kind="huggingface",
|
|
169
|
+
checkpoint_id="EleutherAI/enformer-official-rough",
|
|
170
|
+
cache_name="enformer-official-rough",
|
|
171
|
+
source_repository="https://github.com/lucidrains/enformer-pytorch",
|
|
172
|
+
checkpoint_url="https://huggingface.co/EleutherAI/enformer-official-rough",
|
|
173
|
+
chunk_length=196_608,
|
|
174
|
+
chunk_unit="bp",
|
|
175
|
+
default_pooling="mean",
|
|
176
|
+
required_package="enformer-pytorch>=0.8.11",
|
|
177
|
+
output_dimension=3_072,
|
|
178
|
+
allow_patterns=_HF_MODEL_PATTERNS,
|
|
179
|
+
),
|
|
180
|
+
"alphagenome": DNAEmbeddingModel(
|
|
181
|
+
name="alphagenome",
|
|
182
|
+
display_name="AlphaGenome all folds",
|
|
183
|
+
loader="alphagenome",
|
|
184
|
+
checkpoint_kind="huggingface",
|
|
185
|
+
checkpoint_id="google/alphagenome-all-folds",
|
|
186
|
+
cache_name="alphagenome-all-folds",
|
|
187
|
+
source_repository="https://github.com/google-deepmind/alphagenome_research",
|
|
188
|
+
checkpoint_url="https://huggingface.co/google/alphagenome-all-folds",
|
|
189
|
+
chunk_length=1_048_576,
|
|
190
|
+
chunk_unit="bp",
|
|
191
|
+
default_pooling="mean",
|
|
192
|
+
required_package=("git+https://github.com/google-deepmind/alphagenome_research.git"),
|
|
193
|
+
output_dimension=1_536,
|
|
194
|
+
gated=True,
|
|
195
|
+
allow_patterns=None,
|
|
196
|
+
notes="Checkpoint access requires accepting Google's non-commercial model terms.",
|
|
197
|
+
),
|
|
198
|
+
"janusdna": DNAEmbeddingModel(
|
|
199
|
+
name="janusdna",
|
|
200
|
+
display_name="JanusDNA 131k",
|
|
201
|
+
loader="janusdna",
|
|
202
|
+
checkpoint_kind="dataverse",
|
|
203
|
+
checkpoint_id="doi:10.7910/DVN/HDT0RN",
|
|
204
|
+
cache_name="janusdna-131k",
|
|
205
|
+
source_repository="https://github.com/Qihao-Duan/JanusDNA",
|
|
206
|
+
checkpoint_url="https://dataverse.harvard.edu/api/access/datafile/12016924",
|
|
207
|
+
chunk_length=131_072,
|
|
208
|
+
chunk_unit="bp",
|
|
209
|
+
trust_remote_code=False,
|
|
210
|
+
required_package="JanusDNA source checkout plus its official environment",
|
|
211
|
+
output_dimension=144,
|
|
212
|
+
archive_name=(
|
|
213
|
+
"janusdna_len-131k_d_model-144_inter_dim-576_n_layer-8_lr-8e-3_"
|
|
214
|
+
"step-50K_moeloss-true_1head_onlymoe_finalmlp.tar.bz2"
|
|
215
|
+
),
|
|
216
|
+
archive_md5="1fce7f29c728f312d72262d6820e2ba0",
|
|
217
|
+
),
|
|
218
|
+
"evo2": DNAEmbeddingModel(
|
|
219
|
+
name="evo2",
|
|
220
|
+
display_name="Evo 2 7B",
|
|
221
|
+
loader="evo2",
|
|
222
|
+
checkpoint_kind="huggingface",
|
|
223
|
+
checkpoint_id="arcinstitute/evo2_7b",
|
|
224
|
+
cache_name="evo2-7b",
|
|
225
|
+
source_repository="https://github.com/ArcInstitute/evo2",
|
|
226
|
+
checkpoint_url="https://huggingface.co/arcinstitute/evo2_7b",
|
|
227
|
+
chunk_length=70_000,
|
|
228
|
+
chunk_unit="bp",
|
|
229
|
+
default_pooling="mean",
|
|
230
|
+
required_package="evo2>=0.5.3,<0.6",
|
|
231
|
+
output_dimension=4_096,
|
|
232
|
+
allow_patterns=_HF_MODEL_PATTERNS,
|
|
233
|
+
evo2_layer="blocks.28.mlp.l3",
|
|
234
|
+
),
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
_MODEL_ALIASES = {
|
|
239
|
+
"alpha-genome": "alphagenome",
|
|
240
|
+
"caduceus-ph": "caduceus",
|
|
241
|
+
"dna-bert-2": "dnabert2",
|
|
242
|
+
"dnabert-2": "dnabert2",
|
|
243
|
+
"enformer-pytorch": "enformer",
|
|
244
|
+
"evo-2": "evo2",
|
|
245
|
+
"generator-v2": "generator",
|
|
246
|
+
"hyena-dna": "hyenadna",
|
|
247
|
+
"janus-dna": "janusdna",
|
|
248
|
+
"luca-one": "lucaone",
|
|
249
|
+
"nt-v2": "ntv2",
|
|
250
|
+
"nucleotide-transformer": "ntv2",
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def available_embedding_models() -> tuple[str, ...]:
|
|
255
|
+
"""Return the stable model names accepted by :class:`RepresentationConfig`."""
|
|
256
|
+
|
|
257
|
+
return tuple(sorted(MODEL_REGISTRY))
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def get_embedding_model(name: str) -> DNAEmbeddingModel:
|
|
261
|
+
"""Resolve one canonical model name or documented alias."""
|
|
262
|
+
|
|
263
|
+
if not isinstance(name, str) or not name.strip():
|
|
264
|
+
raise ConfigurationError(
|
|
265
|
+
"model must be a non-empty string.",
|
|
266
|
+
code="INVALID_EMBEDDING_MODEL",
|
|
267
|
+
)
|
|
268
|
+
key = name.strip().lower().replace("_", "-")
|
|
269
|
+
canonical = _MODEL_ALIASES.get(key, key.replace("-", ""))
|
|
270
|
+
if canonical not in MODEL_REGISTRY:
|
|
271
|
+
raise ConfigurationError(
|
|
272
|
+
"Unknown DNA embedding model.",
|
|
273
|
+
code="INVALID_EMBEDDING_MODEL",
|
|
274
|
+
context={"model": name, "available": available_embedding_models()},
|
|
275
|
+
)
|
|
276
|
+
return MODEL_REGISTRY[canonical]
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
@dataclass(frozen=True, slots=True)
|
|
280
|
+
class RepresentationConfig:
|
|
281
|
+
"""Configure checkpoint resolution and sequence-level representation extraction."""
|
|
282
|
+
|
|
283
|
+
model: str = "lucaone"
|
|
284
|
+
checkpoint_dir: str | os.PathLike[str] | None = None
|
|
285
|
+
checkpoint_path: str | os.PathLike[str] | None = None
|
|
286
|
+
model_source_path: str | os.PathLike[str] | None = None
|
|
287
|
+
pooling: PoolingMethod = "mean"
|
|
288
|
+
ambiguity_policy: AmbiguityPolicy = "replace_with_n"
|
|
289
|
+
device: str = "auto"
|
|
290
|
+
dtype: TorchDType = "auto"
|
|
291
|
+
batch_size: int = 4
|
|
292
|
+
max_length: int | None = None
|
|
293
|
+
max_records: int = 10_000
|
|
294
|
+
show_progress: bool = True
|
|
295
|
+
allow_remote_code: bool = False
|
|
296
|
+
hf_token: str | None = field(default=None, repr=False)
|
|
297
|
+
|
|
298
|
+
def __post_init__(self) -> None:
|
|
299
|
+
model_spec = get_embedding_model(self.model)
|
|
300
|
+
object.__setattr__(self, "model", model_spec.name)
|
|
301
|
+
for field_name in ("checkpoint_dir", "checkpoint_path", "model_source_path"):
|
|
302
|
+
value = getattr(self, field_name)
|
|
303
|
+
if value is None:
|
|
304
|
+
continue
|
|
305
|
+
try:
|
|
306
|
+
resolved = os.fspath(value)
|
|
307
|
+
except TypeError as exc:
|
|
308
|
+
raise ConfigurationError(
|
|
309
|
+
f"{field_name} must be path-like or None.",
|
|
310
|
+
code="INVALID_REPRESENTATION_CONFIG",
|
|
311
|
+
) from exc
|
|
312
|
+
if not resolved.strip():
|
|
313
|
+
raise ConfigurationError(
|
|
314
|
+
f"{field_name} must not be empty.",
|
|
315
|
+
code="INVALID_REPRESENTATION_CONFIG",
|
|
316
|
+
)
|
|
317
|
+
object.__setattr__(self, field_name, resolved)
|
|
318
|
+
if self.checkpoint_dir is not None and self.checkpoint_path is not None:
|
|
319
|
+
raise ConfigurationError(
|
|
320
|
+
"checkpoint_dir and checkpoint_path are mutually exclusive.",
|
|
321
|
+
code="INVALID_REPRESENTATION_CONFIG",
|
|
322
|
+
)
|
|
323
|
+
if self.pooling not in {"mean", "cls", "max", "last"}:
|
|
324
|
+
raise ConfigurationError(
|
|
325
|
+
"Unknown representation pooling method.",
|
|
326
|
+
code="INVALID_REPRESENTATION_POOLING",
|
|
327
|
+
)
|
|
328
|
+
if self.ambiguity_policy not in {"replace_with_n", "error"}:
|
|
329
|
+
raise ConfigurationError(
|
|
330
|
+
"Unknown ambiguity_policy.",
|
|
331
|
+
code="INVALID_REPRESENTATION_CONFIG",
|
|
332
|
+
)
|
|
333
|
+
if not isinstance(self.device, str) or not self.device.strip():
|
|
334
|
+
raise ConfigurationError(
|
|
335
|
+
"device must be non-empty text.",
|
|
336
|
+
code="INVALID_REPRESENTATION_CONFIG",
|
|
337
|
+
)
|
|
338
|
+
if self.dtype not in {"auto", "float32", "float16", "bfloat16"}:
|
|
339
|
+
raise ConfigurationError(
|
|
340
|
+
"Unknown representation dtype.",
|
|
341
|
+
code="INVALID_REPRESENTATION_CONFIG",
|
|
342
|
+
)
|
|
343
|
+
for name, value, maximum in (
|
|
344
|
+
("batch_size", self.batch_size, 1_024),
|
|
345
|
+
("max_records", self.max_records, 1_000_000),
|
|
346
|
+
):
|
|
347
|
+
if isinstance(value, bool) or not isinstance(value, int) or not 1 <= value <= maximum:
|
|
348
|
+
raise ConfigurationError(
|
|
349
|
+
f"{name} must be in [1, {maximum}].",
|
|
350
|
+
code="INVALID_REPRESENTATION_CONFIG",
|
|
351
|
+
)
|
|
352
|
+
if self.max_length is not None and (
|
|
353
|
+
isinstance(self.max_length, bool)
|
|
354
|
+
or not isinstance(self.max_length, int)
|
|
355
|
+
or not 1 <= self.max_length <= 10_000_000
|
|
356
|
+
):
|
|
357
|
+
raise ConfigurationError(
|
|
358
|
+
"max_length must be None or an integer in [1, 10000000].",
|
|
359
|
+
code="INVALID_REPRESENTATION_CONFIG",
|
|
360
|
+
)
|
|
361
|
+
if not isinstance(self.show_progress, bool):
|
|
362
|
+
raise ConfigurationError(
|
|
363
|
+
"show_progress must be boolean.",
|
|
364
|
+
code="INVALID_REPRESENTATION_CONFIG",
|
|
365
|
+
)
|
|
366
|
+
if not isinstance(self.allow_remote_code, bool):
|
|
367
|
+
raise ConfigurationError(
|
|
368
|
+
"allow_remote_code must be boolean.",
|
|
369
|
+
code="INVALID_REPRESENTATION_CONFIG",
|
|
370
|
+
)
|
|
371
|
+
if self.hf_token is not None and (
|
|
372
|
+
not isinstance(self.hf_token, str) or not self.hf_token.strip()
|
|
373
|
+
):
|
|
374
|
+
raise ConfigurationError(
|
|
375
|
+
"hf_token must be None or non-empty text.",
|
|
376
|
+
code="INVALID_REPRESENTATION_CONFIG",
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
@property
|
|
380
|
+
def model_spec(self) -> DNAEmbeddingModel:
|
|
381
|
+
"""Return the resolved registry entry."""
|
|
382
|
+
|
|
383
|
+
return get_embedding_model(self.model)
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
__all__ = [
|
|
387
|
+
"MODEL_REGISTRY",
|
|
388
|
+
"AmbiguityPolicy",
|
|
389
|
+
"DNAEmbeddingModel",
|
|
390
|
+
"PoolingMethod",
|
|
391
|
+
"RepresentationConfig",
|
|
392
|
+
"TorchDType",
|
|
393
|
+
"available_embedding_models",
|
|
394
|
+
"get_embedding_model",
|
|
395
|
+
]
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Results returned by DNA representation extraction."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from dnakit.exceptions import ConfigurationError
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(frozen=True, slots=True, eq=False)
|
|
12
|
+
class RepresentationResult:
|
|
13
|
+
"""A read-only float32 matrix aligned with the input record IDs."""
|
|
14
|
+
|
|
15
|
+
record_ids: tuple[str, ...]
|
|
16
|
+
representations: Any
|
|
17
|
+
model_name: str
|
|
18
|
+
checkpoint_path: str | None
|
|
19
|
+
pooling: str
|
|
20
|
+
embedding_dimension: int
|
|
21
|
+
input_count: int
|
|
22
|
+
ambiguity_policy: str
|
|
23
|
+
|
|
24
|
+
def __post_init__(self) -> None:
|
|
25
|
+
try:
|
|
26
|
+
import numpy as np
|
|
27
|
+
except ImportError as exc: # pragma: no cover - reached through the neural extra.
|
|
28
|
+
raise ConfigurationError(
|
|
29
|
+
"RepresentationResult requires NumPy.",
|
|
30
|
+
code="MISSING_NEURAL_DEPENDENCY",
|
|
31
|
+
) from exc
|
|
32
|
+
matrix = np.asarray(self.representations, dtype=np.float32)
|
|
33
|
+
if matrix.ndim != 2:
|
|
34
|
+
raise ConfigurationError(
|
|
35
|
+
"representations must be a two-dimensional matrix.",
|
|
36
|
+
code="INVALID_REPRESENTATION_MATRIX",
|
|
37
|
+
)
|
|
38
|
+
if matrix.shape != (self.input_count, self.embedding_dimension):
|
|
39
|
+
raise ConfigurationError(
|
|
40
|
+
"Representation matrix shape does not match result metadata.",
|
|
41
|
+
code="INVALID_REPRESENTATION_MATRIX",
|
|
42
|
+
context={
|
|
43
|
+
"shape": tuple(int(value) for value in matrix.shape),
|
|
44
|
+
"input_count": self.input_count,
|
|
45
|
+
"embedding_dimension": self.embedding_dimension,
|
|
46
|
+
},
|
|
47
|
+
)
|
|
48
|
+
if len(self.record_ids) != self.input_count:
|
|
49
|
+
raise ConfigurationError(
|
|
50
|
+
"record_ids must align with representation rows.",
|
|
51
|
+
code="INVALID_REPRESENTATION_MATRIX",
|
|
52
|
+
)
|
|
53
|
+
if not np.isfinite(matrix).all():
|
|
54
|
+
raise ConfigurationError(
|
|
55
|
+
"Representations must contain only finite numbers.",
|
|
56
|
+
code="INVALID_REPRESENTATION_MATRIX",
|
|
57
|
+
)
|
|
58
|
+
matrix = np.array(matrix, dtype=np.float32, copy=True, order="C")
|
|
59
|
+
matrix.setflags(write=False)
|
|
60
|
+
object.__setattr__(self, "representations", matrix)
|
|
61
|
+
|
|
62
|
+
def to_dict(self, *, include_representations: bool = True) -> dict[str, object]:
|
|
63
|
+
"""Return JSON-compatible metadata and, by default, the extracted vectors."""
|
|
64
|
+
|
|
65
|
+
payload: dict[str, object] = {
|
|
66
|
+
"record_ids": self.record_ids,
|
|
67
|
+
"model_name": self.model_name,
|
|
68
|
+
"checkpoint_path": self.checkpoint_path,
|
|
69
|
+
"pooling": self.pooling,
|
|
70
|
+
"embedding_dimension": self.embedding_dimension,
|
|
71
|
+
"input_count": self.input_count,
|
|
72
|
+
"ambiguity_policy": self.ambiguity_policy,
|
|
73
|
+
}
|
|
74
|
+
if include_representations:
|
|
75
|
+
payload["representations"] = self.representations.tolist()
|
|
76
|
+
return payload
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
__all__ = ["RepresentationResult"]
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Unified, bounded adapters for public biological database queries."""
|
|
2
|
+
|
|
3
|
+
from dnakit.search.blast import (
|
|
4
|
+
DEFAULT_NCBI_BLAST_URL,
|
|
5
|
+
BlastJob,
|
|
6
|
+
BlastProgress,
|
|
7
|
+
BlastStatus,
|
|
8
|
+
blast_results,
|
|
9
|
+
blast_status,
|
|
10
|
+
identify,
|
|
11
|
+
novelty,
|
|
12
|
+
submit_blast,
|
|
13
|
+
wait_for_blast,
|
|
14
|
+
)
|
|
15
|
+
from dnakit.search.ena import (
|
|
16
|
+
DEFAULT_ENA_PORTAL_URL,
|
|
17
|
+
DEFAULT_READ_FIELDS,
|
|
18
|
+
ena_search,
|
|
19
|
+
reads,
|
|
20
|
+
)
|
|
21
|
+
from dnakit.search.ena import (
|
|
22
|
+
project as ena_project,
|
|
23
|
+
)
|
|
24
|
+
from dnakit.search.ena import (
|
|
25
|
+
sample as ena_sample,
|
|
26
|
+
)
|
|
27
|
+
from dnakit.search.encode import DEFAULT_ENCODE_URL, encode_search
|
|
28
|
+
from dnakit.search.ensembl import (
|
|
29
|
+
DEFAULT_ENSEMBL_REST_URL,
|
|
30
|
+
annotation,
|
|
31
|
+
chromosome,
|
|
32
|
+
comparative_alignment,
|
|
33
|
+
genome_info,
|
|
34
|
+
homology,
|
|
35
|
+
id_convert,
|
|
36
|
+
map_coordinates,
|
|
37
|
+
nearby,
|
|
38
|
+
regulation,
|
|
39
|
+
sequence,
|
|
40
|
+
sequence_by_id,
|
|
41
|
+
transcripts,
|
|
42
|
+
variant,
|
|
43
|
+
)
|
|
44
|
+
from dnakit.search.ensembl import (
|
|
45
|
+
lookup as ensembl_lookup,
|
|
46
|
+
)
|
|
47
|
+
from dnakit.search.models import QueryProgress, QueryResult, SearchConfig
|
|
48
|
+
from dnakit.search.ncbi import (
|
|
49
|
+
DEFAULT_NCBI_DATASETS_URL,
|
|
50
|
+
DEFAULT_NCBI_EUTILS_URL,
|
|
51
|
+
accession,
|
|
52
|
+
assembly,
|
|
53
|
+
clinical_variant,
|
|
54
|
+
database_version,
|
|
55
|
+
entrez,
|
|
56
|
+
expression,
|
|
57
|
+
gene,
|
|
58
|
+
literature,
|
|
59
|
+
ncbi_orthologs,
|
|
60
|
+
project,
|
|
61
|
+
sample,
|
|
62
|
+
taxonomy,
|
|
63
|
+
virus,
|
|
64
|
+
)
|
|
65
|
+
from dnakit.search.ucsc import DEFAULT_UCSC_API_URL
|
|
66
|
+
from dnakit.search.ucsc import chromosomes as ucsc_chromosomes
|
|
67
|
+
from dnakit.search.ucsc import files as ucsc_files
|
|
68
|
+
from dnakit.search.ucsc import genomes as ucsc_genomes
|
|
69
|
+
from dnakit.search.ucsc import sequence as ucsc_sequence
|
|
70
|
+
from dnakit.search.ucsc import track_data as ucsc_track_data
|
|
71
|
+
from dnakit.search.ucsc import tracks as ucsc_tracks
|
|
72
|
+
|
|
73
|
+
__all__ = [
|
|
74
|
+
"DEFAULT_ENA_PORTAL_URL",
|
|
75
|
+
"DEFAULT_ENCODE_URL",
|
|
76
|
+
"DEFAULT_ENSEMBL_REST_URL",
|
|
77
|
+
"DEFAULT_NCBI_BLAST_URL",
|
|
78
|
+
"DEFAULT_NCBI_DATASETS_URL",
|
|
79
|
+
"DEFAULT_NCBI_EUTILS_URL",
|
|
80
|
+
"DEFAULT_READ_FIELDS",
|
|
81
|
+
"DEFAULT_UCSC_API_URL",
|
|
82
|
+
"BlastJob",
|
|
83
|
+
"BlastProgress",
|
|
84
|
+
"BlastStatus",
|
|
85
|
+
"QueryProgress",
|
|
86
|
+
"QueryResult",
|
|
87
|
+
"SearchConfig",
|
|
88
|
+
"accession",
|
|
89
|
+
"annotation",
|
|
90
|
+
"assembly",
|
|
91
|
+
"blast_results",
|
|
92
|
+
"blast_status",
|
|
93
|
+
"chromosome",
|
|
94
|
+
"clinical_variant",
|
|
95
|
+
"comparative_alignment",
|
|
96
|
+
"database_version",
|
|
97
|
+
"ena_project",
|
|
98
|
+
"ena_sample",
|
|
99
|
+
"ena_search",
|
|
100
|
+
"encode_search",
|
|
101
|
+
"ensembl_lookup",
|
|
102
|
+
"entrez",
|
|
103
|
+
"expression",
|
|
104
|
+
"gene",
|
|
105
|
+
"genome_info",
|
|
106
|
+
"homology",
|
|
107
|
+
"id_convert",
|
|
108
|
+
"identify",
|
|
109
|
+
"literature",
|
|
110
|
+
"map_coordinates",
|
|
111
|
+
"ncbi_orthologs",
|
|
112
|
+
"nearby",
|
|
113
|
+
"novelty",
|
|
114
|
+
"project",
|
|
115
|
+
"reads",
|
|
116
|
+
"regulation",
|
|
117
|
+
"sample",
|
|
118
|
+
"sequence",
|
|
119
|
+
"sequence_by_id",
|
|
120
|
+
"submit_blast",
|
|
121
|
+
"taxonomy",
|
|
122
|
+
"transcripts",
|
|
123
|
+
"ucsc_chromosomes",
|
|
124
|
+
"ucsc_files",
|
|
125
|
+
"ucsc_genomes",
|
|
126
|
+
"ucsc_sequence",
|
|
127
|
+
"ucsc_track_data",
|
|
128
|
+
"ucsc_tracks",
|
|
129
|
+
"variant",
|
|
130
|
+
"virus",
|
|
131
|
+
"wait_for_blast",
|
|
132
|
+
]
|