beiken1201 commited on
Commit
5ed2951
·
verified ·
1 Parent(s): 1b51026

Unify BioMod interfaces and centralize checkpoint compatibility

Browse files

Use the bundled BioModEncoder, BioModLM and BioModLM_GO interfaces throughout. Remove obsolete CLI aliases and the external attention fallback. Centralize legacy configuration and state-dictionary translation in biomod_compat.py and document the shared asset. Model weights, paired configuration, datasets and unrelated files remain unchanged.

BioMod/README.md CHANGED
@@ -156,6 +156,7 @@ $BIOMOD_ROOT/model_dependencies/ # Shared gene mappings, gene lists
156
  │ ├── pytorch.py
157
  │ ├── pytorch_old.py
158
  │ └── reversible.py
 
159
  ├── gene2ens.csv
160
  ├── selected_gene2vec_27k.npy
161
  └── selected_genes_27k.txt
@@ -351,6 +352,8 @@ files and shows which entries are missing.
351
  Check `BIOMOD_ROOT` for shell commands or `PROJECT_ROOT` in a notebook, and verify that the BioMod model weights, matching
352
  `.pkl` configuration, gene2vec file, gene list, gene mapping, and
353
  `pytorch_cont/` directory exist at the paths listed under Shared Assets.
 
 
354
 
355
  ### No space left on device
356
 
 
156
  │ ├── pytorch.py
157
  │ ├── pytorch_old.py
158
  │ └── reversible.py
159
+ ├── biomod_compat.py # Legacy checkpoint and configuration compatibility
160
  ├── gene2ens.csv
161
  ├── selected_gene2vec_27k.npy
162
  └── selected_genes_27k.txt
 
352
  Check `BIOMOD_ROOT` for shell commands or `PROJECT_ROOT` in a notebook, and verify that the BioMod model weights, matching
353
  `.pkl` configuration, gene2vec file, gene list, gene mapping, and
354
  `pytorch_cont/` directory exist at the paths listed under Shared Assets.
355
+ Keep `biomod_compat.py` alongside that directory so existing serialized
356
+ configurations and checkpoint field names can be translated during loading.
357
 
358
  ### No space left on device
359
 
BioMod/biomod.py CHANGED
@@ -65,7 +65,6 @@
65
  sys.path.insert(0, str(SOURCE_DIR))
66
  from models_biomod import (
67
  BioMod,
68
- normalize_biomod_decoder_type,
69
  sanitize_biomod_config,
70
  )
71
  from biomod_dataset import BioModSCDataset, load_biomod_data
@@ -115,7 +114,7 @@
115
  help='Reconstruct loss aggregation method: gene_mean=masked gene equal weight (current); module_mean=masked module equal weight (MAE style)')
116
  parser.add_argument("--recon_target_level", type=str, default="gene", choices=["gene", "module_mean_value"],
117
  help='Reconstruction target granularity: gene=gene-by-gene reconstruction; module_mean_value=decoder directly outputs the module mean and calculates the loss with the target mean')
118
- parser.add_argument("--decoder_type", type=normalize_biomod_decoder_type, default="biomod", choices=["none", "simple", "biomod", "cross_attn"],
119
  help='decoder type: none=directly use encoder to output predictions; simple=no token mixing; biomod=decoder self-attention; cross_attn=only masked->visible cross-attention')
120
  parser.add_argument("--decoder_gene_agg", action='store_true',
121
  help='The reconstruction head is changed to module->gene aggregation and then gene-level reconstruction (off by default to facilitate comparison with the old module_head)')
 
65
  sys.path.insert(0, str(SOURCE_DIR))
66
  from models_biomod import (
67
  BioMod,
 
68
  sanitize_biomod_config,
69
  )
70
  from biomod_dataset import BioModSCDataset, load_biomod_data
 
114
  help='Reconstruct loss aggregation method: gene_mean=masked gene equal weight (current); module_mean=masked module equal weight (MAE style)')
115
  parser.add_argument("--recon_target_level", type=str, default="gene", choices=["gene", "module_mean_value"],
116
  help='Reconstruction target granularity: gene=gene-by-gene reconstruction; module_mean_value=decoder directly outputs the module mean and calculates the loss with the target mean')
117
+ parser.add_argument("--decoder_type", type=str, default="biomod", choices=["none", "simple", "biomod", "cross_attn"],
118
  help='decoder type: none=directly use encoder to output predictions; simple=no token mixing; biomod=decoder self-attention; cross_attn=only masked->visible cross-attention')
119
  parser.add_argument("--decoder_gene_agg", action='store_true',
120
  help='The reconstruction head is changed to module->gene aggregation and then gene-level reconstruction (off by default to facilitate comparison with the old module_head)')
BioMod/cell_annotation/train.py CHANGED
@@ -1173,9 +1173,8 @@ def parse_args():
1173
  parser.add_argument("--max_cells", type=int, default=None)
1174
 
1175
  parser.add_argument("--config_pkl", type=str, default=str(WEIGHTS_DIR / "BioMod.pkl"))
1176
- # Retain the legacy CLI spelling as a compatibility alias.
1177
  parser.add_argument(
1178
- "--biomod_checkpoint", "--performer_checkpoint",
1179
  type=str,
1180
  default=str(WEIGHTS_DIR / "BioMod.pth"),
1181
  dest='biomod_checkpoint',
 
1173
  parser.add_argument("--max_cells", type=int, default=None)
1174
 
1175
  parser.add_argument("--config_pkl", type=str, default=str(WEIGHTS_DIR / "BioMod.pkl"))
 
1176
  parser.add_argument(
1177
+ "--biomod_checkpoint",
1178
  type=str,
1179
  default=str(WEIGHTS_DIR / "BioMod.pth"),
1180
  dest='biomod_checkpoint',
BioMod/models_biomod.py CHANGED
@@ -15,25 +15,12 @@
15
  if os.path.isdir(model_dependencies_dir) and model_dependencies_dir not in sys.path:
16
  sys.path.insert(0, model_dependencies_dir)
17
 
18
- try:
19
- from pytorch_cont.ding_models import (
20
- Performer as BioModEncoder,
21
- Always,
22
- cast_tuple,
23
- )
24
- except ImportError:
25
- try:
26
- from pytorch_cont.pytorch import (
27
- Performer as BioModEncoder,
28
- Always,
29
- cast_tuple,
30
- )
31
- except ImportError:
32
- from performer_pytorch.performer_pytorch import (
33
- Performer as BioModEncoder,
34
- Always,
35
- cast_tuple,
36
- )
37
  import torch
38
  from torch import nn
39
  import torch.nn.functional as F
@@ -41,82 +28,6 @@
41
  import numpy as np
42
 
43
 
44
- def normalize_biomod_decoder_type(decoder_type: str) -> str:
45
- """Normalize the legacy decoder option without changing the attention backend."""
46
- if decoder_type == "performer": # Legacy CLI and serialized-config alias.
47
- return "biomod"
48
- return decoder_type
49
-
50
-
51
- def _migrate_legacy_biomod_name(value: str) -> str:
52
- """Translate serialized pre-rename names without changing their semantics."""
53
- replacements = (
54
- ("PATHCH", "MODULE"),
55
- ("Pathch", "Module"),
56
- ("pathch", "module"),
57
- ("PATCHES", "MODULES"),
58
- ("Patches", "Modules"),
59
- ("patches", "modules"),
60
- ("PATCH", "MODULE"),
61
- ("Patch", "Module"),
62
- ("patch", "module"),
63
- )
64
- for old, new in replacements:
65
- value = value.replace(old, new)
66
- return value
67
-
68
-
69
- def migrate_legacy_biomod_config(config: Dict[str, object]) -> Dict[str, object]:
70
- """Return a BioMod-compatible copy of an older serialized configuration."""
71
- def translate(value):
72
- if isinstance(value, dict):
73
- migrated = {}
74
- for key, item in value.items():
75
- new_key = _migrate_legacy_biomod_name(key) if isinstance(key, str) else key
76
- if new_key in migrated:
77
- raise ValueError(
78
- f"Legacy configuration migration would duplicate key {new_key!r}"
79
- )
80
- migrated[new_key] = translate(item)
81
- return migrated
82
- if isinstance(value, list):
83
- return [translate(item) for item in value]
84
- if isinstance(value, tuple):
85
- return tuple(translate(item) for item in value)
86
- if isinstance(value, str):
87
- return _migrate_legacy_biomod_name(value)
88
- return value
89
-
90
- migrated = translate(dict(config))
91
- if "decoder_type" in migrated:
92
- migrated["decoder_type"] = normalize_biomod_decoder_type(migrated["decoder_type"])
93
- return migrated
94
-
95
-
96
- def migrate_legacy_biomod_state_dict(state_dict):
97
- """Translate old state-dict key names before PyTorch performs strict loading."""
98
- try:
99
- migrated = state_dict.__class__()
100
- except TypeError:
101
- migrated = {}
102
-
103
- for key, value in state_dict.items():
104
- new_key = _migrate_legacy_biomod_name(key) if isinstance(key, str) else key
105
- if new_key in migrated:
106
- # If both spellings are supplied, prefer the explicit new spelling.
107
- if key == new_key:
108
- migrated[new_key] = value
109
- continue
110
- migrated[new_key] = value
111
-
112
- if hasattr(state_dict, "_metadata"):
113
- migrated._metadata = {
114
- _migrate_legacy_biomod_name(key): value
115
- for key, value in state_dict._metadata.items()
116
- }
117
- return migrated
118
-
119
-
120
  def normalize_fusion_method(fusion_method: str) -> str:
121
  if fusion_method == "expression_only_mlp":
122
  return "add"
 
15
  if os.path.isdir(model_dependencies_dir) and model_dependencies_dir not in sys.path:
16
  sys.path.insert(0, model_dependencies_dir)
17
 
18
+ from biomod_compat import (
19
+ migrate_legacy_biomod_config,
20
+ migrate_legacy_biomod_state_dict,
21
+ normalize_biomod_decoder_type,
22
+ )
23
+ from pytorch_cont.pytorch import BioModEncoder, Always, cast_tuple
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  import torch
25
  from torch import nn
26
  import torch.nn.functional as F
 
28
  import numpy as np
29
 
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  def normalize_fusion_method(fusion_method: str) -> str:
32
  if fusion_method == "expression_only_mlp":
33
  return "add"
README.md CHANGED
@@ -81,6 +81,9 @@ architecture and gene-module definitions.
81
 
82
  The model components are bundled under
83
  [`model_dependencies/pytorch_cont/`](model_dependencies/pytorch_cont/).
 
 
 
84
  Optional [Hallmark and Reactome source definitions](model_dependencies/biomod_data_sources/)
85
  are kept in `biomod_data_sources/`. They are separate from the default checkpoint
86
  runtime definitions in `biomod_data_all/`.
@@ -275,6 +278,7 @@ BioMod/ # Project root: s
275
  │ │ ├── pytorch.py
276
  │ │ ├── pytorch_old.py
277
  │ │ └── reversible.py
 
278
  │ ├── gene2ens.csv
279
  │ ├── selected_gene2vec_27k.npy
280
  │ └── selected_genes_27k.txt
 
81
 
82
  The model components are bundled under
83
  [`model_dependencies/pytorch_cont/`](model_dependencies/pytorch_cont/).
84
+ Legacy serialized names are handled by
85
+ [`biomod_compat.py`](model_dependencies/biomod_compat.py) when loading existing
86
+ checkpoints; the original checkpoint files remain unchanged.
87
  Optional [Hallmark and Reactome source definitions](model_dependencies/biomod_data_sources/)
88
  are kept in `biomod_data_sources/`. They are separate from the default checkpoint
89
  runtime definitions in `biomod_data_all/`.
 
278
  │ │ ├── pytorch.py
279
  │ │ ├── pytorch_old.py
280
  │ │ └── reversible.py
281
+ │ ├── biomod_compat.py # Legacy checkpoint and configuration compatibility
282
  │ ├── gene2ens.csv
283
  │ ├── selected_gene2vec_27k.npy
284
  │ └── selected_genes_27k.txt
model_dependencies/biomod_compat.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Read historical BioMod serialized names without rewriting checkpoint files.
2
+
3
+ Current interfaces use BioMod names. Legacy spellings are kept only here so
4
+ existing configuration dictionaries and tensor state dictionaries still load.
5
+ This module intentionally has no model or tensor-library imports.
6
+ """
7
+
8
+ from typing import Dict
9
+
10
+
11
+ def normalize_biomod_decoder_type(decoder_type: str) -> str:
12
+ """Normalize the legacy decoder option without changing the attention backend."""
13
+ if decoder_type == "performer": # Legacy serialized-config alias.
14
+ return "biomod"
15
+ return decoder_type
16
+
17
+
18
+ def _migrate_legacy_biomod_name(value: str) -> str:
19
+ """Translate serialized pre-rename names without changing their semantics."""
20
+ replacements = (
21
+ ("PATHCH", "MODULE"),
22
+ ("Pathch", "Module"),
23
+ ("pathch", "module"),
24
+ ("PATCHES", "MODULES"),
25
+ ("Patches", "Modules"),
26
+ ("patches", "modules"),
27
+ ("PATCH", "MODULE"),
28
+ ("Patch", "Module"),
29
+ ("patch", "module"),
30
+ )
31
+ for old, new in replacements:
32
+ value = value.replace(old, new)
33
+ return value
34
+
35
+
36
+ def migrate_legacy_biomod_config(config: Dict[str, object]) -> Dict[str, object]:
37
+ """Return a BioMod-compatible copy of an older serialized configuration."""
38
+ def translate(value):
39
+ if isinstance(value, dict):
40
+ migrated = {}
41
+ for key, item in value.items():
42
+ new_key = _migrate_legacy_biomod_name(key) if isinstance(key, str) else key
43
+ if new_key in migrated:
44
+ raise ValueError(
45
+ f"Legacy configuration migration would duplicate key {new_key!r}"
46
+ )
47
+ migrated[new_key] = translate(item)
48
+ return migrated
49
+ if isinstance(value, list):
50
+ return [translate(item) for item in value]
51
+ if isinstance(value, tuple):
52
+ return tuple(translate(item) for item in value)
53
+ if isinstance(value, str):
54
+ return _migrate_legacy_biomod_name(value)
55
+ return value
56
+
57
+ migrated = translate(dict(config))
58
+ if "decoder_type" in migrated:
59
+ migrated["decoder_type"] = normalize_biomod_decoder_type(migrated["decoder_type"])
60
+ return migrated
61
+
62
+
63
+ def migrate_legacy_biomod_state_dict(state_dict):
64
+ """Translate old state-dict key names before PyTorch performs strict loading."""
65
+ try:
66
+ migrated = state_dict.__class__()
67
+ except TypeError:
68
+ migrated = {}
69
+
70
+ for key, value in state_dict.items():
71
+ new_key = _migrate_legacy_biomod_name(key) if isinstance(key, str) else key
72
+ if new_key in migrated:
73
+ # If both spellings are supplied, prefer the explicit new spelling.
74
+ if key == new_key:
75
+ migrated[new_key] = value
76
+ continue
77
+ migrated[new_key] = value
78
+
79
+ if hasattr(state_dict, "_metadata"):
80
+ migrated._metadata = {
81
+ _migrate_legacy_biomod_name(key): value
82
+ for key, value in state_dict._metadata.items()
83
+ }
84
+ return migrated
85
+
86
+
87
+ def migrate_legacy_encoder_prefix(state_dict, prefix: str) -> None:
88
+ """Translate one legacy language-model subtree in place before loading.
89
+
90
+ Explicit current keys take precedence if both spellings are present.
91
+ The caller supplies the full parent prefix, including its trailing dot.
92
+ """
93
+ old_root = prefix + "performer"
94
+ new_root = prefix + "biomod"
95
+ old_prefix = old_root + "."
96
+ new_prefix = new_root + "."
97
+ for key in list(state_dict):
98
+ if isinstance(key, str) and key.startswith(old_prefix):
99
+ new_key = new_prefix + key[len(old_prefix):]
100
+ if new_key not in state_dict:
101
+ state_dict[new_key] = state_dict[key]
102
+ del state_dict[key]
103
+
104
+ metadata = getattr(state_dict, "_metadata", None)
105
+ if metadata is not None:
106
+ for key in list(metadata):
107
+ if key == old_root or key.startswith(old_prefix):
108
+ new_key = new_root + key[len(old_root):]
109
+ if new_key not in metadata:
110
+ metadata[new_key] = metadata[key]
111
+ del metadata[key]
model_dependencies/pytorch_cont/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
- # Export the bundled Performer attention implementation.
2
- from pytorch_cont.pytorch import PerformerLM, Performer, FastAttention, SelfAttention
 
1
+ # Export the bundled BioMod attention implementation.
2
+ from pytorch_cont.pytorch import BioModLM, BioModEncoder, FastAttention, SelfAttention
model_dependencies/pytorch_cont/ding_models.py CHANGED
@@ -1,3 +1,4 @@
 
1
  from pytorch_cont.pytorch import *
2
  import torch.nn as nn
3
  from torch_geometric.nn import SGConv
@@ -125,7 +126,7 @@ def get_similarity_network(gene_list, data_path, num_similar_genes_go_graph):
125
 
126
 
127
 
128
- class PerformerLM_GO(nn.Module):
129
  def __init__(
130
  self,
131
  *,
@@ -189,17 +190,28 @@ class PerformerLM_GO(nn.Module):
189
  gene2vec_file = gene2vec_file)
190
  print('dropout')
191
  self.dropout = nn.Dropout(emb_dropout)
192
- print('performer')
193
- self.performer = Performer(dim, depth, heads, dim_head, local_attn_heads, local_window_size, causal, ff_mult, nb_features, feature_redraw_interval, reversible, ff_chunks, generalized_attention, kernel_fn, use_scalenorm, use_rezero, ff_glu, ff_dropout, attn_dropout, cross_attend, no_projection, auto_check_redraw, qkv_bias)
194
  self.norm = nn.LayerNorm(dim)
195
  # self.to_out = nn.Linear(dim, num_tokens) if not tie_embed else None
196
  self.to_out = nn.Linear(dim, 1) if not tie_embed else None
197
 
 
 
 
 
 
 
 
 
 
 
 
198
  def check_redraw_projections(self):
199
- self.performer.check_redraw_projections()
200
 
201
  def fix_projection_matrices_(self):
202
- self.performer.fix_projection_matrices_()
203
 
204
  def forward(self, x, return_encodings = False, output_attentions = False, **kwargs):
205
  b, n, device = *x.shape, x.device
@@ -213,11 +225,11 @@ class PerformerLM_GO(nn.Module):
213
  x += self.go_conv(x)
214
  x = self.dropout(x)
215
 
216
- # performer layers
217
  layer_pos_emb = self.layer_pos_emb(x)
218
 
219
  if output_attentions:
220
- x, attn_weights = self.performer(x, pos_emb = layer_pos_emb, output_attentions = output_attentions, **kwargs)
221
  # norm and to logits
222
  x = self.norm(x)
223
  if return_encodings:
@@ -228,7 +240,7 @@ class PerformerLM_GO(nn.Module):
228
 
229
  return (x @ self.token_emb.weight.t()), attn_weights
230
  else:
231
- x = self.performer(x, pos_emb = layer_pos_emb, output_attentions = output_attentions, **kwargs)
232
 
233
  # norm and to logits
234
  x = self.norm(x)
@@ -318,17 +330,17 @@ class DualEncoderSCFM(nn.Module):
318
  gene2vec_file = gene2vec_file)
319
  self.dropout = nn.Dropout(emb_dropout)
320
 
321
- self.mini_encoder = Performer(base_dim, mini_enc_depth, mini_enc_heads, mini_enc_dim_head,
322
  local_attn_heads, local_window_size, causal, ff_mult, nb_features, feature_redraw_interval, reversible, ff_chunks, generalized_attention, kernel_fn, use_scalenorm, use_rezero, ff_glu, ff_dropout, attn_dropout, cross_attend, no_projection, auto_check_redraw, qkv_bias)
323
 
324
  self.base_to_large = nn.Linear(base_dim, large_dim)
325
  self.large_in_norm = nn.LayerNorm(large_dim)
326
- self.large_encoder = Performer(large_dim, large_enc_depth, large_enc_heads, large_enc_dim_head,
327
  local_attn_heads, local_window_size, causal, ff_mult, nb_features, feature_redraw_interval, reversible, ff_chunks, generalized_attention, kernel_fn, use_scalenorm, use_rezero, ff_glu, ff_dropout, attn_dropout, cross_attend, no_projection, auto_check_redraw, qkv_bias)
328
  self.large_to_base = nn.Linear(large_dim, base_dim)
329
  self.large_to_base_out_norm = nn.LayerNorm(base_dim)
330
 
331
- self.decoder = Performer(base_dim, dec_depth, dec_heads, dec_dim_head,
332
  local_attn_heads, local_window_size, causal, ff_mult, nb_features, feature_redraw_interval, reversible, ff_chunks, generalized_attention, kernel_fn, use_scalenorm, use_rezero, ff_glu, ff_dropout, attn_dropout, cross_attend, no_projection, auto_check_redraw, qkv_bias)
333
  self.decode_norm = nn.LayerNorm(base_dim)
334
 
 
1
+ from biomod_compat import migrate_legacy_encoder_prefix
2
  from pytorch_cont.pytorch import *
3
  import torch.nn as nn
4
  from torch_geometric.nn import SGConv
 
126
 
127
 
128
 
129
+ class BioModLM_GO(nn.Module):
130
  def __init__(
131
  self,
132
  *,
 
190
  gene2vec_file = gene2vec_file)
191
  print('dropout')
192
  self.dropout = nn.Dropout(emb_dropout)
193
+ print('BioMod')
194
+ self.biomod = BioModEncoder(dim, depth, heads, dim_head, local_attn_heads, local_window_size, causal, ff_mult, nb_features, feature_redraw_interval, reversible, ff_chunks, generalized_attention, kernel_fn, use_scalenorm, use_rezero, ff_glu, ff_dropout, attn_dropout, cross_attend, no_projection, auto_check_redraw, qkv_bias)
195
  self.norm = nn.LayerNorm(dim)
196
  # self.to_out = nn.Linear(dim, num_tokens) if not tie_embed else None
197
  self.to_out = nn.Linear(dim, 1) if not tie_embed else None
198
 
199
+ def _load_from_state_dict(
200
+ self, state_dict, prefix, local_metadata, strict,
201
+ missing_keys, unexpected_keys, error_msgs,
202
+ ):
203
+ """Normalize historical encoder prefixes before loading parameters."""
204
+ migrate_legacy_encoder_prefix(state_dict, prefix)
205
+ super()._load_from_state_dict(
206
+ state_dict, prefix, local_metadata, strict,
207
+ missing_keys, unexpected_keys, error_msgs,
208
+ )
209
+
210
  def check_redraw_projections(self):
211
+ self.biomod.check_redraw_projections()
212
 
213
  def fix_projection_matrices_(self):
214
+ self.biomod.fix_projection_matrices_()
215
 
216
  def forward(self, x, return_encodings = False, output_attentions = False, **kwargs):
217
  b, n, device = *x.shape, x.device
 
225
  x += self.go_conv(x)
226
  x = self.dropout(x)
227
 
228
+ # BioMod encoder layers
229
  layer_pos_emb = self.layer_pos_emb(x)
230
 
231
  if output_attentions:
232
+ x, attn_weights = self.biomod(x, pos_emb = layer_pos_emb, output_attentions = output_attentions, **kwargs)
233
  # norm and to logits
234
  x = self.norm(x)
235
  if return_encodings:
 
240
 
241
  return (x @ self.token_emb.weight.t()), attn_weights
242
  else:
243
+ x = self.biomod(x, pos_emb = layer_pos_emb, output_attentions = output_attentions, **kwargs)
244
 
245
  # norm and to logits
246
  x = self.norm(x)
 
330
  gene2vec_file = gene2vec_file)
331
  self.dropout = nn.Dropout(emb_dropout)
332
 
333
+ self.mini_encoder = BioModEncoder(base_dim, mini_enc_depth, mini_enc_heads, mini_enc_dim_head,
334
  local_attn_heads, local_window_size, causal, ff_mult, nb_features, feature_redraw_interval, reversible, ff_chunks, generalized_attention, kernel_fn, use_scalenorm, use_rezero, ff_glu, ff_dropout, attn_dropout, cross_attend, no_projection, auto_check_redraw, qkv_bias)
335
 
336
  self.base_to_large = nn.Linear(base_dim, large_dim)
337
  self.large_in_norm = nn.LayerNorm(large_dim)
338
+ self.large_encoder = BioModEncoder(large_dim, large_enc_depth, large_enc_heads, large_enc_dim_head,
339
  local_attn_heads, local_window_size, causal, ff_mult, nb_features, feature_redraw_interval, reversible, ff_chunks, generalized_attention, kernel_fn, use_scalenorm, use_rezero, ff_glu, ff_dropout, attn_dropout, cross_attend, no_projection, auto_check_redraw, qkv_bias)
340
  self.large_to_base = nn.Linear(large_dim, base_dim)
341
  self.large_to_base_out_norm = nn.LayerNorm(base_dim)
342
 
343
+ self.decoder = BioModEncoder(base_dim, dec_depth, dec_heads, dec_dim_head,
344
  local_attn_heads, local_window_size, causal, ff_mult, nb_features, feature_redraw_interval, reversible, ff_chunks, generalized_attention, kernel_fn, use_scalenorm, use_rezero, ff_glu, ff_dropout, attn_dropout, cross_attend, no_projection, auto_check_redraw, qkv_bias)
345
  self.decode_norm = nn.LayerNorm(base_dim)
346
 
model_dependencies/pytorch_cont/pytorch.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import math
2
  from pathlib import Path
3
  import numpy as np
@@ -238,7 +239,7 @@ class FastAttention(nn.Module):
238
  import fast_transformers.causal_product.causal_product_cuda
239
  self.causal_linear_fn = partial(causal_linear_attention)
240
  except ImportError:
241
- print('unable to import cuda code for auto-regressive Performer. will default to the memory inefficient non-cuda version')
242
  self.causal_linear_fn = causal_linear_attention_noncuda
243
 
244
  @torch.no_grad()
@@ -472,16 +473,16 @@ class Gene2VecPositionalEmbedding(nn.Module):
472
  t = torch.arange(x.shape[1], device=x.device)
473
  return self.emb(t)
474
 
475
- # performer
476
 
477
- class Performer(nn.Module):
478
  def __init__(
479
  self,
480
  dim, # dimension
481
  depth, # layers
482
  heads, # heads
483
  dim_head, # dim of head
484
- local_attn_heads = 0, # num of local attention heads, (heads - local_attn_heads) is num of global performers
485
  local_window_size = 256, # window size of local attention
486
  causal = False, # autoregressive or not
487
  ff_mult = 4, # dim of intermediate features after attention / dim of input features
@@ -576,7 +577,7 @@ class TwoLayerMLP(nn.Module):
576
  x = self.fc2(x)
577
  return x
578
 
579
- class PerformerLM(nn.Module):
580
  def __init__(
581
  self,
582
  *,
@@ -626,17 +627,28 @@ class PerformerLM(nn.Module):
626
  self.layer_pos_emb = Always(None)
627
  print('dropout')
628
  self.dropout = nn.Dropout(emb_dropout)
629
- print('performer')
630
- self.performer = Performer(dim, depth, heads, dim_head, local_attn_heads, local_window_size, causal, ff_mult, nb_features, feature_redraw_interval, reversible, ff_chunks, generalized_attention, kernel_fn, use_scalenorm, use_rezero, ff_glu, ff_dropout, attn_dropout, cross_attend, no_projection, auto_check_redraw, qkv_bias)
631
  self.norm = nn.LayerNorm(dim)
632
  # self.to_out = nn.Linear(dim, num_tokens) if not tie_embed else None
633
  self.to_out = nn.Linear(dim, 1) if not tie_embed else None
634
 
 
 
 
 
 
 
 
 
 
 
 
635
  def check_redraw_projections(self):
636
- self.performer.check_redraw_projections()
637
 
638
  def fix_projection_matrices_(self):
639
- self.performer.fix_projection_matrices_()
640
 
641
  def forward(self, x, return_encodings = False, output_attentions = False, **kwargs):
642
  b, n, device = *x.shape, x.device
@@ -649,11 +661,11 @@ class PerformerLM(nn.Module):
649
  x += self.pos_emb(x)
650
  x = self.dropout(x)
651
 
652
- # performer layers
653
  layer_pos_emb = self.layer_pos_emb(x)
654
 
655
  if output_attentions:
656
- x, attn_weights = self.performer(x, pos_emb = layer_pos_emb, output_attentions = output_attentions, **kwargs)
657
  # norm and to logits
658
  x = self.norm(x)
659
  if return_encodings:
@@ -664,7 +676,7 @@ class PerformerLM(nn.Module):
664
 
665
  return (x @ self.token_emb.weight.t()), attn_weights
666
  else:
667
- x = self.performer(x, pos_emb = layer_pos_emb, output_attentions = output_attentions, **kwargs)
668
 
669
  # norm and to logits
670
  x = self.norm(x)
 
1
+ from biomod_compat import migrate_legacy_encoder_prefix
2
  import math
3
  from pathlib import Path
4
  import numpy as np
 
239
  import fast_transformers.causal_product.causal_product_cuda
240
  self.causal_linear_fn = partial(causal_linear_attention)
241
  except ImportError:
242
+ print('unable to import cuda code for autoregressive BioMod attention. will default to the memory inefficient non-cuda version')
243
  self.causal_linear_fn = causal_linear_attention_noncuda
244
 
245
  @torch.no_grad()
 
473
  t = torch.arange(x.shape[1], device=x.device)
474
  return self.emb(t)
475
 
476
+ # BioMod encoder
477
 
478
+ class BioModEncoder(nn.Module):
479
  def __init__(
480
  self,
481
  dim, # dimension
482
  depth, # layers
483
  heads, # heads
484
  dim_head, # dim of head
485
+ local_attn_heads = 0, # num of local attention heads, (heads - local_attn_heads) is number of global attention heads
486
  local_window_size = 256, # window size of local attention
487
  causal = False, # autoregressive or not
488
  ff_mult = 4, # dim of intermediate features after attention / dim of input features
 
577
  x = self.fc2(x)
578
  return x
579
 
580
+ class BioModLM(nn.Module):
581
  def __init__(
582
  self,
583
  *,
 
627
  self.layer_pos_emb = Always(None)
628
  print('dropout')
629
  self.dropout = nn.Dropout(emb_dropout)
630
+ print('BioMod')
631
+ self.biomod = BioModEncoder(dim, depth, heads, dim_head, local_attn_heads, local_window_size, causal, ff_mult, nb_features, feature_redraw_interval, reversible, ff_chunks, generalized_attention, kernel_fn, use_scalenorm, use_rezero, ff_glu, ff_dropout, attn_dropout, cross_attend, no_projection, auto_check_redraw, qkv_bias)
632
  self.norm = nn.LayerNorm(dim)
633
  # self.to_out = nn.Linear(dim, num_tokens) if not tie_embed else None
634
  self.to_out = nn.Linear(dim, 1) if not tie_embed else None
635
 
636
+ def _load_from_state_dict(
637
+ self, state_dict, prefix, local_metadata, strict,
638
+ missing_keys, unexpected_keys, error_msgs,
639
+ ):
640
+ """Normalize historical encoder prefixes before loading parameters."""
641
+ migrate_legacy_encoder_prefix(state_dict, prefix)
642
+ super()._load_from_state_dict(
643
+ state_dict, prefix, local_metadata, strict,
644
+ missing_keys, unexpected_keys, error_msgs,
645
+ )
646
+
647
  def check_redraw_projections(self):
648
+ self.biomod.check_redraw_projections()
649
 
650
  def fix_projection_matrices_(self):
651
+ self.biomod.fix_projection_matrices_()
652
 
653
  def forward(self, x, return_encodings = False, output_attentions = False, **kwargs):
654
  b, n, device = *x.shape, x.device
 
661
  x += self.pos_emb(x)
662
  x = self.dropout(x)
663
 
664
+ # BioMod encoder layers
665
  layer_pos_emb = self.layer_pos_emb(x)
666
 
667
  if output_attentions:
668
+ x, attn_weights = self.biomod(x, pos_emb = layer_pos_emb, output_attentions = output_attentions, **kwargs)
669
  # norm and to logits
670
  x = self.norm(x)
671
  if return_encodings:
 
676
 
677
  return (x @ self.token_emb.weight.t()), attn_weights
678
  else:
679
+ x = self.biomod(x, pos_emb = layer_pos_emb, output_attentions = output_attentions, **kwargs)
680
 
681
  # norm and to logits
682
  x = self.norm(x)
model_dependencies/pytorch_cont/pytorch_old.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import math
2
  from pathlib import Path
3
  import numpy as np
@@ -238,7 +239,7 @@ class FastAttention(nn.Module):
238
  import fast_transformers.causal_product.causal_product_cuda
239
  self.causal_linear_fn = partial(causal_linear_attention)
240
  except ImportError:
241
- print('unable to import cuda code for auto-regressive Performer. will default to the memory inefficient non-cuda version')
242
  self.causal_linear_fn = causal_linear_attention_noncuda
243
 
244
  @torch.no_grad()
@@ -462,16 +463,16 @@ class Gene2VecPositionalEmbedding(nn.Module):
462
  t = torch.arange(x.shape[1], device=x.device)
463
  return self.emb(t)
464
 
465
- # performer
466
 
467
- class Performer(nn.Module):
468
  def __init__(
469
  self,
470
  dim, # dimension
471
  depth, # layers
472
  heads, # heads
473
  dim_head, # dim of head
474
- local_attn_heads = 0, # num of local attention heads, (heads - local_attn_heads) is num of global performers
475
  local_window_size = 256, # window size of local attention
476
  causal = False, # autoregressive or not
477
  ff_mult = 4, # dim of intermediate features after attention / dim of input features
@@ -566,7 +567,7 @@ class TwoLayerMLP(nn.Module):
566
  x = self.fc2(x)
567
  return x
568
 
569
- class PerformerLM(nn.Module):
570
  def __init__(
571
  self,
572
  *,
@@ -616,17 +617,28 @@ class PerformerLM(nn.Module):
616
  self.layer_pos_emb = Always(None)
617
  print('dropout')
618
  self.dropout = nn.Dropout(emb_dropout)
619
- print('performer')
620
- self.performer = Performer(dim, depth, heads, dim_head, local_attn_heads, local_window_size, causal, ff_mult, nb_features, feature_redraw_interval, reversible, ff_chunks, generalized_attention, kernel_fn, use_scalenorm, use_rezero, ff_glu, ff_dropout, attn_dropout, cross_attend, no_projection, auto_check_redraw, qkv_bias)
621
  self.norm = nn.LayerNorm(dim)
622
  # self.to_out = nn.Linear(dim, num_tokens) if not tie_embed else None
623
  self.to_out = nn.Linear(dim, 1) if not tie_embed else None
624
 
 
 
 
 
 
 
 
 
 
 
 
625
  def check_redraw_projections(self):
626
- self.performer.check_redraw_projections()
627
 
628
  def fix_projection_matrices_(self):
629
- self.performer.fix_projection_matrices_()
630
 
631
  def forward(self, x, return_encodings = False, output_attentions = False, **kwargs):
632
  b, n, device = *x.shape, x.device
@@ -639,11 +651,11 @@ class PerformerLM(nn.Module):
639
  x += self.pos_emb(x)
640
  x = self.dropout(x)
641
 
642
- # performer layers
643
  layer_pos_emb = self.layer_pos_emb(x)
644
 
645
  if output_attentions:
646
- x, attn_weights = self.performer(x, pos_emb = layer_pos_emb, output_attentions = output_attentions, **kwargs)
647
  # norm and to logits
648
  x = self.norm(x)
649
  if return_encodings:
@@ -654,7 +666,7 @@ class PerformerLM(nn.Module):
654
 
655
  return (x @ self.token_emb.weight.t()), attn_weights
656
  else:
657
- x = self.performer(x, pos_emb = layer_pos_emb, output_attentions = output_attentions, **kwargs)
658
 
659
  # norm and to logits
660
  x = self.norm(x)
 
1
+ from biomod_compat import migrate_legacy_encoder_prefix
2
  import math
3
  from pathlib import Path
4
  import numpy as np
 
239
  import fast_transformers.causal_product.causal_product_cuda
240
  self.causal_linear_fn = partial(causal_linear_attention)
241
  except ImportError:
242
+ print('unable to import cuda code for autoregressive BioMod attention. will default to the memory inefficient non-cuda version')
243
  self.causal_linear_fn = causal_linear_attention_noncuda
244
 
245
  @torch.no_grad()
 
463
  t = torch.arange(x.shape[1], device=x.device)
464
  return self.emb(t)
465
 
466
+ # BioMod encoder
467
 
468
+ class BioModEncoder(nn.Module):
469
  def __init__(
470
  self,
471
  dim, # dimension
472
  depth, # layers
473
  heads, # heads
474
  dim_head, # dim of head
475
+ local_attn_heads = 0, # num of local attention heads, (heads - local_attn_heads) is number of global attention heads
476
  local_window_size = 256, # window size of local attention
477
  causal = False, # autoregressive or not
478
  ff_mult = 4, # dim of intermediate features after attention / dim of input features
 
567
  x = self.fc2(x)
568
  return x
569
 
570
+ class BioModLM(nn.Module):
571
  def __init__(
572
  self,
573
  *,
 
617
  self.layer_pos_emb = Always(None)
618
  print('dropout')
619
  self.dropout = nn.Dropout(emb_dropout)
620
+ print('BioMod')
621
+ self.biomod = BioModEncoder(dim, depth, heads, dim_head, local_attn_heads, local_window_size, causal, ff_mult, nb_features, feature_redraw_interval, reversible, ff_chunks, generalized_attention, kernel_fn, use_scalenorm, use_rezero, ff_glu, ff_dropout, attn_dropout, cross_attend, no_projection, auto_check_redraw, qkv_bias)
622
  self.norm = nn.LayerNorm(dim)
623
  # self.to_out = nn.Linear(dim, num_tokens) if not tie_embed else None
624
  self.to_out = nn.Linear(dim, 1) if not tie_embed else None
625
 
626
+ def _load_from_state_dict(
627
+ self, state_dict, prefix, local_metadata, strict,
628
+ missing_keys, unexpected_keys, error_msgs,
629
+ ):
630
+ """Normalize historical encoder prefixes before loading parameters."""
631
+ migrate_legacy_encoder_prefix(state_dict, prefix)
632
+ super()._load_from_state_dict(
633
+ state_dict, prefix, local_metadata, strict,
634
+ missing_keys, unexpected_keys, error_msgs,
635
+ )
636
+
637
  def check_redraw_projections(self):
638
+ self.biomod.check_redraw_projections()
639
 
640
  def fix_projection_matrices_(self):
641
+ self.biomod.fix_projection_matrices_()
642
 
643
  def forward(self, x, return_encodings = False, output_attentions = False, **kwargs):
644
  b, n, device = *x.shape, x.device
 
651
  x += self.pos_emb(x)
652
  x = self.dropout(x)
653
 
654
+ # BioMod encoder layers
655
  layer_pos_emb = self.layer_pos_emb(x)
656
 
657
  if output_attentions:
658
+ x, attn_weights = self.biomod(x, pos_emb = layer_pos_emb, output_attentions = output_attentions, **kwargs)
659
  # norm and to logits
660
  x = self.norm(x)
661
  if return_encodings:
 
666
 
667
  return (x @ self.token_emb.weight.t()), attn_weights
668
  else:
669
+ x = self.biomod(x, pos_emb = layer_pos_emb, output_attentions = output_attentions, **kwargs)
670
 
671
  # norm and to logits
672
  x = self.norm(x)