maltefranke commited on
Commit
b839af1
·
verified ·
1 Parent(s): e8cb9ca

Add GEOM-Drugs explicit-H epoch 50 with verified inference assets

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. geom/explicit_h/README.md +12 -0
  2. geom/explicit_h/atom_tokens.txt +10 -0
  3. geom/explicit_h/charge_tokens.txt +5 -0
  4. geom/explicit_h/config.yaml +345 -0
  5. geom/explicit_h/distributions.json +0 -0
  6. geom/explicit_h/distributions.pt +3 -0
  7. geom/explicit_h/edge_tokens.txt +4 -0
  8. geom/explicit_h/epoch_050.ckpt +3 -0
  9. geom/explicit_h/manifest.json +602 -0
  10. geom/explicit_h/metadata.json +48 -0
  11. geom/explicit_h/runtime/configs/callbacks/callbacks.yaml +20 -0
  12. geom/explicit_h/runtime/configs/data/chembl3d/chembl3d.yaml +8 -0
  13. geom/explicit_h/runtime/configs/data/chembl3d/implicit_h.yaml +5 -0
  14. geom/explicit_h/runtime/configs/data/chembl3d/max100.yaml +7 -0
  15. geom/explicit_h/runtime/configs/data/chembl3d/max100_implicit_h.yaml +5 -0
  16. geom/explicit_h/runtime/configs/data/geom/geom.yaml +11 -0
  17. geom/explicit_h/runtime/configs/data/geom/implicit_h.yaml +5 -0
  18. geom/explicit_h/runtime/configs/data/geom/scaffold_decoration.yaml +24 -0
  19. geom/explicit_h/runtime/configs/data/molecular.yaml +136 -0
  20. geom/explicit_h/runtime/configs/data/qm9/qm9.yaml +106 -0
  21. geom/explicit_h/runtime/configs/data/qm9/scaffold_decoration.yaml +22 -0
  22. geom/explicit_h/runtime/configs/default.yaml +25 -0
  23. geom/explicit_h/runtime/configs/defaults/chembl3d/chembl3d.yaml +5 -0
  24. geom/explicit_h/runtime/configs/defaults/chembl3d/implicit_h.yaml +5 -0
  25. geom/explicit_h/runtime/configs/defaults/chembl3d/implicit_h_2x4090.yaml +10 -0
  26. geom/explicit_h/runtime/configs/defaults/chembl3d/train_2x4090.yaml +40 -0
  27. geom/explicit_h/runtime/configs/defaults/core.yaml +13 -0
  28. geom/explicit_h/runtime/configs/defaults/geom/geom.yaml +20 -0
  29. geom/explicit_h/runtime/configs/defaults/geom/implicit_h.yaml +5 -0
  30. geom/explicit_h/runtime/configs/defaults/geom/scaffold_decoration.yaml +23 -0
  31. geom/explicit_h/runtime/configs/defaults/qm9/qm9.yaml +6 -0
  32. geom/explicit_h/runtime/configs/defaults/qm9/scaffold_decoration.yaml +11 -0
  33. geom/explicit_h/runtime/configs/embeddings/geom.yaml +28 -0
  34. geom/explicit_h/runtime/configs/embeddings/qm9.yaml +29 -0
  35. geom/explicit_h/runtime/configs/heads/head.yaml +75 -0
  36. geom/explicit_h/runtime/configs/insertion_head/gmm.yaml +16 -0
  37. geom/explicit_h/runtime/configs/insertion_head/unimodal.yaml +13 -0
  38. geom/explicit_h/runtime/configs/integrator/integrator.yaml +30 -0
  39. geom/explicit_h/runtime/configs/logging/wandb_logger.yaml +6 -0
  40. geom/explicit_h/runtime/configs/loss_weights/calibrated_geom.yaml +18 -0
  41. geom/explicit_h/runtime/configs/loss_weights/calibrated_geom_frozen.yaml +25 -0
  42. geom/explicit_h/runtime/configs/loss_weights/tuned_weights.yaml +15 -0
  43. geom/explicit_h/runtime/configs/loss_weights/uniform.yaml +15 -0
  44. geom/explicit_h/runtime/configs/model/backbones/dit.yaml +123 -0
  45. geom/explicit_h/runtime/configs/model/finetune/lora_finetune.yaml +13 -0
  46. geom/explicit_h/runtime/configs/model/finetune/scaffold_finetune.yaml +134 -0
  47. geom/explicit_h/runtime/configs/optimizer/muon_aux_adam.yaml +39 -0
  48. geom/explicit_h/runtime/configs/resume_geom.yaml +417 -0
  49. geom/explicit_h/runtime/configs/schedule/beta.yaml +3 -0
  50. geom/explicit_h/runtime/configs/schedule/cubic.yaml +1 -0
geom/explicit_h/README.md ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # GEOM-Drugs with explicit hydrogens — epoch 50
2
+
3
+ Continued from the best checkpoint after 48 completed epochs. The original Lightning checkpoint includes current weights, EMA weights and optimizer state. The inference loader constructs only the selected network (EMA by default).
4
+
5
+ ```python
6
+ from morph.inference import load_pretrained
7
+
8
+ model = load_pretrained("geom-explicit-h", epoch=50, device="cuda")
9
+ trajectories, validity, vocab, coordinate_std = model.generate(n_mols=16)
10
+ ```
11
+
12
+ The training subset contains at most 72 atoms including hydrogen. Coordinates returned by generation are in Angstrom. Config, vocabularies and training distributions are included; no dataset is needed for inference.
geom/explicit_h/atom_tokens.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ Br
2
+ C
3
+ Cl
4
+ F
5
+ H
6
+ I
7
+ N
8
+ O
9
+ P
10
+ S
geom/explicit_h/charge_tokens.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ -2
2
+ -1
3
+ 0
4
+ 1
5
+ 2
geom/explicit_h/config.yaml ADDED
@@ -0,0 +1,345 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ representation: molecule
2
+ seed: 42
3
+ heads:
4
+ heads:
5
+ _target_: morph.model.layers.heads.MultiHeadModule
6
+ output_init_std: ${model.head_initialization.output_std}
7
+ independent_adapters: ${oc.select:model.head_independent_adapters,false}
8
+ heads_configs:
9
+ graph_aggregation: mean
10
+ node_heads:
11
+ atom_type_head:
12
+ input_dim: ${model.head_node_dim}
13
+ output_dim: ${len:${data.vocab.atom_tokens}}
14
+ adapter_dim: ${model.head_node_adapter_dim}
15
+ group: state
16
+ charge_head:
17
+ input_dim: ${model.head_node_dim}
18
+ output_dim: ${len:${data.vocab.charge_tokens}}
19
+ adapter_dim: ${model.head_node_adapter_dim}
20
+ group: state
21
+ ins_rate_head:
22
+ input_dim: ${model.head_node_dim}
23
+ output_dim: 1
24
+ adapter_dim: ${model.head_node_adapter_dim}
25
+ group: edit
26
+ initial_rate: ${model.head_initialization.ins_rate}
27
+ do_del_head:
28
+ input_dim: ${model.head_node_dim}
29
+ output_dim: 1
30
+ adapter_dim: ${model.head_node_adapter_dim}
31
+ group: edit
32
+ initial_probability: ${model.head_initialization.do_del_probability}
33
+ do_sub_a_head:
34
+ input_dim: ${model.head_node_dim}
35
+ output_dim: 1
36
+ adapter_dim: ${model.head_node_adapter_dim}
37
+ group: edit
38
+ initial_probability: ${model.head_initialization.do_sub_a_probability}
39
+ edge_heads:
40
+ edge_type_head:
41
+ input_dim: ${model.head_edge_dim}
42
+ output_dim: ${len:${data.vocab.edge_tokens}}
43
+ adapter_dim: ${model.head_edge_adapter_dim}
44
+ group: state
45
+ do_sub_e_head:
46
+ input_dim: ${model.head_edge_dim}
47
+ output_dim: 1
48
+ adapter_dim: ${model.head_edge_adapter_dim}
49
+ group: state
50
+ initial_probability: ${model.head_initialization.do_sub_e_probability}
51
+ ins_edge_head:
52
+ _target_: morph.model.layers.heads.InsertionEdgeHead
53
+ _recursive_: false
54
+ hidden_dim: ${model.head_node_dim}
55
+ readout_dim: ${model.head_insertion_edge_dim}
56
+ output_init_std: ${model.head_initialization.output_std}
57
+ n_edge_types: ${len:${data.vocab.edge_tokens}}
58
+ n_atom_types: ${len:${data.vocab.atom_tokens}}
59
+ n_charge_types: ${len:${data.vocab.charge_tokens}}
60
+ rbf_embedding_args:
61
+ _target_: morph.model.layers.embedding.RBFEmbedding
62
+ num_rbf: 128
63
+ rbf_dmax: 3.5
64
+ out_dim: 64
65
+ dropout: 0.0
66
+ trainable: false
67
+ insertion_head:
68
+ mode: unimodal
69
+ dimension: 3
70
+ num_components: 1
71
+ model:
72
+ _target_: morph.model.layers.heads.UnimodalInsertionHead
73
+ hidden_dim: ${model.head_node_dim}
74
+ readout_dim: ${model.head_insertion_adapter_dim}
75
+ output_init_std: ${model.head_initialization.output_std}
76
+ independent_adapters: ${oc.select:model.head_independent_adapters,false}
77
+ N_a: ${len:${data.vocab.atom_tokens}}
78
+ N_c: ${len:${data.vocab.charge_tokens}}
79
+ model:
80
+ module:
81
+ optimizer_config:
82
+ implementation: torch
83
+ optimizer:
84
+ execution: ${oc.env:MORPH_MUON_EXECUTION,native}
85
+ lr: 0.01
86
+ momentum: 0.95
87
+ weight_decay: 0.0
88
+ nesterov: true
89
+ ns_steps: 5
90
+ eps: 1.0e-07
91
+ adjust_lr_fn: original
92
+ aux_optimizer:
93
+ lr: 0.0003
94
+ betas:
95
+ - 0.9
96
+ - 0.95
97
+ eps: 1.0e-10
98
+ weight_decay: 0.0
99
+ gradient_clip_val: 1.0
100
+ gradient_clip_algorithm: norm
101
+ scheduler:
102
+ _target_: morph.utils.lr_schedulers.MultiGroupCosineWarmupLR
103
+ warmup_steps: 2000
104
+ total_steps: 200000
105
+ min_lr_fraction: 0.05
106
+ last_epoch: -1
107
+ interval: step
108
+ monitor: null
109
+ loss_weights:
110
+ do_sub_a: 0.2
111
+ sub_a_class: 0.03
112
+ do_sub_e: 0.25
113
+ sub_e_class: 0.5
114
+ do_del: 0.4
115
+ ins_rate: 0.15
116
+ ins_state: 0.01
117
+ ins_e: 0.4
118
+ x: 2.0
119
+ c: 0.5
120
+ ins_e_ii: 0.03
121
+ _target_: morph.model.lightning.base.LightningModuleRates
122
+ insertion_head_mode: ${insertion_head.mode}
123
+ ins_noise_scale: ${data.ins_noise_scale}
124
+ ema_decay: 0.999
125
+ ema_warmup_steps: 5000
126
+ use_ema_for_eval: true
127
+ time_dist: ${if:${eq:${model.sample_time_strategy}, log}, ${model.beta_sched},
128
+ ${model.linear_sched}}
129
+ integrator: ${model.integrator}
130
+ vocab: ${data.vocab}
131
+ use_learnable_loss_weights: false
132
+ use_time_weights: false
133
+ model:
134
+ _target_: morph.model.backbones.dit.DiTBackboneWithHeads
135
+ _recursive_: false
136
+ atom_type_embedding_args: ${embeddings.atom_type_embedding}
137
+ edge_type_embedding_args: ${embeddings.edge_type_embedding}
138
+ time_embedding_args: ${embeddings.time_embedding}
139
+ node_count_embedding_args: ${embeddings.node_count_embedding}
140
+ incident_bond_embedding: false
141
+ backbone_model_args: ${model.backbone}
142
+ heads_args: ${heads.heads}
143
+ insertion_head_args: ${insertion_head.model}
144
+ ins_edge_head_args: ${heads.ins_edge_head}
145
+ rotate: true
146
+ n_augmentations: 1
147
+ integrator: ${integrator.integrator}
148
+ beta_sched:
149
+ _target_: torch.distributions.Beta
150
+ concentration1: 2.0
151
+ concentration0: 1.0
152
+ linear_sched:
153
+ _target_: torch.distributions.Uniform
154
+ low: 0.0
155
+ high: 1.0
156
+ sample_time_strategy: linear
157
+ head_node_dim: ${model.backbone.out_node_nf}
158
+ head_edge_dim: ${model.backbone.out_edge_nf}
159
+ head_node_adapter_dim: 256
160
+ head_edge_adapter_dim: 256
161
+ head_insertion_adapter_dim: 256
162
+ head_insertion_edge_dim: 256
163
+ head_independent_adapters: true
164
+ head_initialization:
165
+ output_std: 0.001
166
+ coordinate_output_std: 0.0
167
+ do_del_probability: 0.5
168
+ do_sub_a_probability: 0.5
169
+ do_sub_e_probability: 0.5
170
+ ins_rate: 0.6931471805599453
171
+ token_weighting:
172
+ type_loss_token_weights: uniform
173
+ weight_alpha: 0.4
174
+ lora:
175
+ enabled: false
176
+ rank: 8
177
+ alpha: 8.0
178
+ dropout: 0.0
179
+ targets:
180
+ - qkv
181
+ - proj
182
+ - mlp.gate_value
183
+ - mlp.out_proj
184
+ freeze_base: true
185
+ backbone:
186
+ _target_: morph.model.backbones.dit.DiTBackbone
187
+ _recursive_: false
188
+ d_input: ${embeddings.atom_type_embedding.out_dim}
189
+ d_cond: ${oc.eval:"${embeddings.time_embedding.out_dim} + ${embeddings.node_count_embedding.out_dim}"}
190
+ d_model: 512
191
+ out_node_nf: 256
192
+ out_edge_nf: 256
193
+ num_layers: 8
194
+ nhead: 16
195
+ mlp_ratio: 4.0
196
+ ffn_hidden_dim: null
197
+ ffn_multiple_of: 64
198
+ qk_norm: true
199
+ coordinate_output_init_std: ${model.head_initialization.coordinate_output_std}
200
+ center_coordinate_output: true
201
+ in_edge_nf: ${embeddings.edge_type_embedding.out_dim}
202
+ edge_pair_dim: 256
203
+ pair_bias_hidden_dim: 32
204
+ num_atom_types: ${len:${data.vocab.atom_tokens}}
205
+ lora: ${model.lora}
206
+ rbf_embedding_args:
207
+ _target_: morph.model.layers.embedding.RBFEmbedding
208
+ num_rbf: 128
209
+ rbf_dmax: 3.5
210
+ out_dim: 64
211
+ dropout: 0.0
212
+ trainable: false
213
+ schedule:
214
+ _target_: morph.flow_matching.schedules.SmoothstepSchedule
215
+ shift: 0.8
216
+ trainer:
217
+ trainer:
218
+ deterministic: warn
219
+ devices: 1
220
+ accelerator: auto
221
+ strategy: auto
222
+ precision: 32-true
223
+ max_epochs: -1
224
+ accumulate_grad_batches: 1
225
+ num_sanity_val_steps: 0
226
+ gradient_clip_val: null
227
+ gradient_clip_algorithm: norm
228
+ check_val_every_n_epoch: 1
229
+ num_val_samples: 4096
230
+ limit_val_batches: null
231
+ limit_predict_batches: 4
232
+ max_time: null
233
+ do_train: false
234
+ do_validate: false
235
+ do_predict: true
236
+ checkpoint_path: null
237
+ final_checkpoint_path: null
238
+ callbacks: {}
239
+ logging:
240
+ enabled: false
241
+ project: morph-${data.dataset_name}
242
+ name: geom-explicit-h
243
+ save_dir: .
244
+ offline: false
245
+ integrator:
246
+ integrator:
247
+ _target_: morph.flow_matching.integration.RateIntegrator
248
+ vocab: ${data.vocab}
249
+ distributions: None
250
+ insertion_head_mode: ${insertion_head.mode}
251
+ insertion_dimension: ${insertion_head.dimension}
252
+ insertion_num_components: ${insertion_head.num_components}
253
+ time_strategy: log
254
+ time_beta_alpha: 2.0
255
+ time_beta_beta: 1.0
256
+ num_integration_steps: 100
257
+ ins_noise_scale: ${data.ins_noise_scale}
258
+ renoise_insertions: true
259
+ exact_schedule_integration: true
260
+ del_schedule: ${data.interpolator.del_schedule}
261
+ ins_schedule: ${data.interpolator.ins_schedule}
262
+ sub_schedule: ${data.interpolator.sub_schedule}
263
+ sub_e_schedule: ${data.interpolator.sub_e_schedule}
264
+ data:
265
+ root_path: .
266
+ preprocess_workers: 0
267
+ preprocess_chunk_size: 128
268
+ statistics_workers: ${data.preprocess_workers}
269
+ hydrogen_mode: explicit
270
+ cache_name: ${data.dataset_name}${if:${eq:${data.hydrogen_mode},implicit},_implicit_h,''}
271
+ source_dir: null
272
+ max_atoms: 72
273
+ allowed_atom_symbols:
274
+ - H
275
+ - C
276
+ - 'N'
277
+ - O
278
+ - S
279
+ - F
280
+ - Cl
281
+ - Br
282
+ - P
283
+ - I
284
+ n_atoms_strategy: uniform
285
+ uniform_n_atoms_padding: 5
286
+ optimal_transport: equivariant
287
+ ins_noise_scale: 0.65
288
+ move_noise_scale: 0.5
289
+ allow_charged: true
290
+ preprocessing:
291
+ _target_: morph.dataset.core.preprocessing.Preprocessing
292
+ _recursive_: false
293
+ root: .
294
+ num_workers: 0
295
+ train_dataset: null
296
+ atom_tokens_path: ${data.preprocessing.root}/atom_tokens.txt
297
+ edge_tokens_path: ${data.preprocessing.root}/edge_tokens.txt
298
+ charge_tokens_path: ${data.preprocessing.root}/charge_tokens.txt
299
+ distributions_path: ${data.preprocessing.root}/distributions.pt
300
+ vocab: null
301
+ interpolator:
302
+ _target_: morph.flow_matching.interpolation.Interpolator
303
+ distributions: null
304
+ optimal_transport: ${data.optimal_transport}
305
+ ins_noise_scale: ${data.ins_noise_scale}
306
+ move_noise_scale: ${data.move_noise_scale}
307
+ atom_type_noise_prob: 0.0
308
+ pre_align_iters: 2
309
+ c_move: 1.0
310
+ c_sub: 0.0
311
+ c_ins: 6.125
312
+ c_del: 6.125
313
+ del_schedule: ${schedule}
314
+ ins_schedule: ${schedule}
315
+ sub_schedule:
316
+ _target_: morph.flow_matching.schedules.SmoothstepSchedule
317
+ shift: 1.5
318
+ sub_e_schedule:
319
+ _target_: morph.flow_matching.schedules.SmoothstepSchedule
320
+ shift: 1.5
321
+ datamodule: null
322
+ dataset_name: geom
323
+ dataset_target: morph.dataset.unconditional.geom.FlowMatchingGEOMDataset
324
+ embeddings:
325
+ atom_type_embedding:
326
+ _target_: morph.model.layers.embedding.Embedding
327
+ num_embeddings: ${len:${data.vocab.atom_tokens}}
328
+ embedding_dim: 64
329
+ out_dim: 128
330
+ edge_type_embedding:
331
+ _target_: morph.model.layers.embedding.Embedding
332
+ num_embeddings: ${len:${data.vocab.edge_tokens}}
333
+ embedding_dim: 64
334
+ out_dim: 128
335
+ time_embedding:
336
+ _target_: morph.model.layers.embedding.TimeEmbedding
337
+ embedding_dim: 128
338
+ out_dim: 128
339
+ node_count_embedding:
340
+ _target_: morph.model.layers.embedding.ExtrapolatableCountEmbedding
341
+ embedding_dim: 64
342
+ out_dim: 128
343
+ min_period: 128.0
344
+ max_period: 1024.0
345
+ max_count: 96.0
geom/explicit_h/distributions.json ADDED
The diff for this file is too large to render. See raw diff
 
geom/explicit_h/distributions.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:40a31704ab58d0349daff35083d43dcf4771ef368fd9c8a8503c94fe844016c5
3
+ size 63581
geom/explicit_h/edge_tokens.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ <NO_BOND>
2
+ 1
3
+ 2
4
+ 3
geom/explicit_h/epoch_050.ckpt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:016c4a5bbb4f5ef36d1d62dff772ecf8d384e8ab3e2c94ebeb4c4357183f690a
3
+ size 509181385
geom/explicit_h/manifest.json ADDED
@@ -0,0 +1,602 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "README.md": {
3
+ "bytes": 701,
4
+ "sha256": "9947149d5b311da2f381b57f135811eb1eade2dba84cdf452ae69f5e11ba1016"
5
+ },
6
+ "atom_tokens.txt": {
7
+ "bytes": 22,
8
+ "sha256": "c9b712563ad2509593aa48fddbb5145aa42a70c4791255b8eea2984f549cae6a"
9
+ },
10
+ "charge_tokens.txt": {
11
+ "bytes": 12,
12
+ "sha256": "e2533aa090751f1006a74d165aa2d4a7ac23dbf73a65eb624c2a81216cc7dff5"
13
+ },
14
+ "config.yaml": {
15
+ "bytes": 10648,
16
+ "sha256": "e448c580096659af3b7e7e718e395565aa397b7b6666bc148576c7a455940a66"
17
+ },
18
+ "distributions.json": {
19
+ "bytes": 220286,
20
+ "sha256": "17bcf85c09486e5070aa8b3be4f4411fa01e6b3cf1b39c5488a5f46149f52e0f"
21
+ },
22
+ "distributions.pt": {
23
+ "bytes": 63581,
24
+ "sha256": "40a31704ab58d0349daff35083d43dcf4771ef368fd9c8a8503c94fe844016c5"
25
+ },
26
+ "edge_tokens.txt": {
27
+ "bytes": 16,
28
+ "sha256": "42b635ef938d2ec5a601044e4b01f3f84ed121f1bfaac984d86f180a8ccba3fd"
29
+ },
30
+ "epoch_050.ckpt": {
31
+ "bytes": 509181385,
32
+ "sha256": "016c4a5bbb4f5ef36d1d62dff772ecf8d384e8ab3e2c94ebeb4c4357183f690a"
33
+ },
34
+ "metadata.json": {
35
+ "bytes": 1094,
36
+ "sha256": "b23b8944369765d12b2cbae0f5d48614225e44cb59deff8bb0e49783318ddb31"
37
+ },
38
+ "runtime/configs/callbacks/callbacks.yaml": {
39
+ "bytes": 699,
40
+ "sha256": "dce0adebf5956dce687d64a074238f9c12866373bfe21df6658d967d6bfd1f90"
41
+ },
42
+ "runtime/configs/data/chembl3d/chembl3d.yaml": {
43
+ "bytes": 278,
44
+ "sha256": "a96974d90353a850c4a1d0bac27de5f1fc8724b81cc5bbc122aab6f76f3051c5"
45
+ },
46
+ "runtime/configs/data/chembl3d/implicit_h.yaml": {
47
+ "bytes": 81,
48
+ "sha256": "08da196d0288cf1fe4dba8dd407c49d9bee003607504beb59f79e5d6b9eaef0c"
49
+ },
50
+ "runtime/configs/data/chembl3d/max100.yaml": {
51
+ "bytes": 246,
52
+ "sha256": "052dba7b3f3efce990019518823476bd6bf1381bb5f606822c9fc7a485e6d0bf"
53
+ },
54
+ "runtime/configs/data/chembl3d/max100_implicit_h.yaml": {
55
+ "bytes": 79,
56
+ "sha256": "152325f11c7d1500469d4ee381100ae12247e6a2e0b90e5ef7501b405144bb2d"
57
+ },
58
+ "runtime/configs/data/geom/geom.yaml": {
59
+ "bytes": 428,
60
+ "sha256": "736c04e86c029bed65ce3ed022f937dd418ddc70d4b9fc064b38d979bf29ee6d"
61
+ },
62
+ "runtime/configs/data/geom/implicit_h.yaml": {
63
+ "bytes": 73,
64
+ "sha256": "c6b3ff5496af997de0c28e5aa7265903d6d0c8b59aab001ab21d6a64baeb772a"
65
+ },
66
+ "runtime/configs/data/geom/scaffold_decoration.yaml": {
67
+ "bytes": 1107,
68
+ "sha256": "d317728a98961e98a1f03bcc3b0f8c513169ca23b68ea07ba807b99066e7ca80"
69
+ },
70
+ "runtime/configs/data/molecular.yaml": {
71
+ "bytes": 5005,
72
+ "sha256": "f79ade5ddbf7d08f2eecbb2aa9c3e6b182b8a8e7e48960aff5e5edda5601bdc9"
73
+ },
74
+ "runtime/configs/data/qm9/qm9.yaml": {
75
+ "bytes": 3648,
76
+ "sha256": "3beea93868a1e889b049dcc2ccbc3b7489fa4672e964138654bc512ea01ab9f2"
77
+ },
78
+ "runtime/configs/data/qm9/scaffold_decoration.yaml": {
79
+ "bytes": 890,
80
+ "sha256": "40b36f2bc25bf4052cdd676a26d9e528cb4f7b13deddbb1660f454f97b159c40"
81
+ },
82
+ "runtime/configs/default.yaml": {
83
+ "bytes": 1294,
84
+ "sha256": "bcf9744acbf53afa4305ffd6e9cf95e6f99571750488eaa8cad85896a51aca66"
85
+ },
86
+ "runtime/configs/defaults/chembl3d/chembl3d.yaml": {
87
+ "bytes": 90,
88
+ "sha256": "f09553bc670e6c87ac8c1f8bbd0a8df73f1e83b02a3dcf9d6d06b915ac3bce93"
89
+ },
90
+ "runtime/configs/defaults/chembl3d/implicit_h.yaml": {
91
+ "bytes": 102,
92
+ "sha256": "a0ee1440984eb4c9d3c96a5d1c18df9f59b8e42c499f8a340ccd8deb8c454cd8"
93
+ },
94
+ "runtime/configs/defaults/chembl3d/implicit_h_2x4090.yaml": {
95
+ "bytes": 331,
96
+ "sha256": "518571405333a40e1602ee4c77fd153b56fd53e77aaa2aaf530796142f58d4b8"
97
+ },
98
+ "runtime/configs/defaults/chembl3d/train_2x4090.yaml": {
99
+ "bytes": 826,
100
+ "sha256": "0e6b01b264ab1ae70ae7f144ecd0a03d242e24f02feb087e3d5e2b7bc24790da"
101
+ },
102
+ "runtime/configs/defaults/core.yaml": {
103
+ "bytes": 431,
104
+ "sha256": "0dcfb68e2fece1dc277f647d3b3769af882cf8175e0c3b479bc50029e2538b1c"
105
+ },
106
+ "runtime/configs/defaults/geom/geom.yaml": {
107
+ "bytes": 425,
108
+ "sha256": "f447a1bdd39e211b5cf43c4cce56e708da6472d58f79e87885621ec4899c1c8e"
109
+ },
110
+ "runtime/configs/defaults/geom/implicit_h.yaml": {
111
+ "bytes": 98,
112
+ "sha256": "9d3a188e6bd2a2b01609ba0d652184bb8a2f7e27fd89d4a3031568051cae605e"
113
+ },
114
+ "runtime/configs/defaults/geom/scaffold_decoration.yaml": {
115
+ "bytes": 828,
116
+ "sha256": "bcce546bce2b0b7bfaf7c0663e05423fd03c952bf6e52cbbf31976723661f0d1"
117
+ },
118
+ "runtime/configs/defaults/qm9/qm9.yaml": {
119
+ "bytes": 132,
120
+ "sha256": "f83bd8e10802df07c2b1933dd40597807e3ee8a8cc39349ab14eb6f722f8475e"
121
+ },
122
+ "runtime/configs/defaults/qm9/scaffold_decoration.yaml": {
123
+ "bytes": 348,
124
+ "sha256": "3bb8b6a757ea4921c31df2c0869949baef703df980b964d9636f52b64ac39267"
125
+ },
126
+ "runtime/configs/embeddings/geom.yaml": {
127
+ "bytes": 803,
128
+ "sha256": "06793f4d446d899197e3db28d064592af9049612ee78cb0718a63e3d6fdc3151"
129
+ },
130
+ "runtime/configs/embeddings/qm9.yaml": {
131
+ "bytes": 849,
132
+ "sha256": "de57af7f1ff9b44dbb952f852c0177789196105b77f396298ff8e0218c0626b7"
133
+ },
134
+ "runtime/configs/heads/head.yaml": {
135
+ "bytes": 2475,
136
+ "sha256": "238e2346041e0aedccd16a6ed4066e163004c0e45a2cbc6fd1f6d17e16eb44ed"
137
+ },
138
+ "runtime/configs/insertion_head/gmm.yaml": {
139
+ "bytes": 488,
140
+ "sha256": "1e26914eed9b4971e0f6ff0b61bbdb34103233d346719a55ba6273dd3d785c05"
141
+ },
142
+ "runtime/configs/insertion_head/unimodal.yaml": {
143
+ "bytes": 495,
144
+ "sha256": "547a6391c3b341e3e369f8f4c7aab9752c67dfbbb533388d25956e9011b305e8"
145
+ },
146
+ "runtime/configs/integrator/integrator.yaml": {
147
+ "bytes": 1580,
148
+ "sha256": "8f0d9aafb0b2727cd58154e1fd97df693c8b7d4f5a3fb5efcb9188553f54660f"
149
+ },
150
+ "runtime/configs/logging/wandb_logger.yaml": {
151
+ "bytes": 139,
152
+ "sha256": "a9a2787e048d4eb70f2ff3c49d4355f1a5a382047c8619203b1f9131d829928d"
153
+ },
154
+ "runtime/configs/loss_weights/calibrated_geom.yaml": {
155
+ "bytes": 644,
156
+ "sha256": "d4763c84aa9e1eb77fb2b456384332a4b3a84b072d560918b2357222a43f4ca1"
157
+ },
158
+ "runtime/configs/loss_weights/calibrated_geom_frozen.yaml": {
159
+ "bytes": 1141,
160
+ "sha256": "a08acb61d67a852051dbded08f8bb67f21101888fd0a22a96a522781d28c570d"
161
+ },
162
+ "runtime/configs/loss_weights/tuned_weights.yaml": {
163
+ "bytes": 420,
164
+ "sha256": "2bb5884465666d6fc638f787fd79257e4126c69a5cc55b55615fc45e02e65894"
165
+ },
166
+ "runtime/configs/loss_weights/uniform.yaml": {
167
+ "bytes": 336,
168
+ "sha256": "3c14d6443048f69d436fe03792703a33c67f368ecbb349de2fd145da4c96eabc"
169
+ },
170
+ "runtime/configs/model/backbones/dit.yaml": {
171
+ "bytes": 4039,
172
+ "sha256": "65b0f08be8fb307b8b01e7b460fd083fe60d48148fbece378d7e5a23dd4a9fb0"
173
+ },
174
+ "runtime/configs/model/finetune/lora_finetune.yaml": {
175
+ "bytes": 328,
176
+ "sha256": "6334a5112499c0f3bc1fe5de224e2b6b3265dc524c8d6b9048113868fb864558"
177
+ },
178
+ "runtime/configs/model/finetune/scaffold_finetune.yaml": {
179
+ "bytes": 5659,
180
+ "sha256": "1aad0d33e9b5ae95d9f50b5201a29bb8677fe42ea2bcf59e0e61d053ef1dfddb"
181
+ },
182
+ "runtime/configs/optimizer/muon_aux_adam.yaml": {
183
+ "bytes": 1212,
184
+ "sha256": "3b0a6189f3ba81f85f7d26c6f6ad7f64dcb25098a14e411211d7a62983a7180c"
185
+ },
186
+ "runtime/configs/resume_geom.yaml": {
187
+ "bytes": 13525,
188
+ "sha256": "abdca1624682973bc89829625c2c01abdaa3f318daa51a08da189967c8253195"
189
+ },
190
+ "runtime/configs/schedule/beta.yaml": {
191
+ "bytes": 78,
192
+ "sha256": "75c485edfd70016b255282adcf5de25dfb95c9e32bb6587017fb8935ffe64eaa"
193
+ },
194
+ "runtime/configs/schedule/cubic.yaml": {
195
+ "bytes": 54,
196
+ "sha256": "a998a2d3390ab5daf4df079852ae8daa907687cf059f55c500409c9493949c0c"
197
+ },
198
+ "runtime/configs/schedule/fast_power.yaml": {
199
+ "bytes": 126,
200
+ "sha256": "22f36106bd43ca253ffea412e00539f2b07efbc49109b97c1232df6a827a2baf"
201
+ },
202
+ "runtime/configs/schedule/linear.yaml": {
203
+ "bytes": 55,
204
+ "sha256": "f7881af26080ab5569e67b39f6eae2733c033b9623020e6271959f09fac45fa0"
205
+ },
206
+ "runtime/configs/schedule/smoothstep.yaml": {
207
+ "bytes": 70,
208
+ "sha256": "f6e8651953d93f0d18c997d40c199b3d80ddd352a2041cc51e29adc9a7f22778"
209
+ },
210
+ "runtime/configs/trainer/trainer.yaml": {
211
+ "bytes": 1402,
212
+ "sha256": "6f78e83ad46529bee7a2878b20727ff403420a515c1629bd73a608a2fb654f5f"
213
+ },
214
+ "runtime/pyproject.toml": {
215
+ "bytes": 4464,
216
+ "sha256": "d4854128f81144905cef68d37222d0d06fb372e2bd148e49177e0ff082a7b01f"
217
+ },
218
+ "runtime/requirements-tested.txt": {
219
+ "bytes": 177,
220
+ "sha256": "fac030b53775fd8ed8f89b17050ea74180f99dfab270b1d75d4ca3c0573ede76"
221
+ },
222
+ "runtime/src/morph/__init__.py": {
223
+ "bytes": 79,
224
+ "sha256": "bb402ea5c6f79e569205cc2bf4168d06430753ce8499ca4ffb8614743626fd59"
225
+ },
226
+ "runtime/src/morph/__main__.py": {
227
+ "bytes": 149,
228
+ "sha256": "95a7983479559ca2b15c7afa3881b3142ef4636583501184469b972df7646d4f"
229
+ },
230
+ "runtime/src/morph/_vendor/__init__.py": {
231
+ "bytes": 72,
232
+ "sha256": "8480cd966a03870a7142e1763094bf00e221d2c3c2b1af1d4d458fb8b7f37a20"
233
+ },
234
+ "runtime/src/morph/_vendor/geom_drugs_preprocessing.py": {
235
+ "bytes": 11328,
236
+ "sha256": "33a9c21d29df269a5f342a0b0e8bced0fc620559f0cb3a7a4cfabd5c369ceccb"
237
+ },
238
+ "runtime/src/morph/_vendor/muon.py": {
239
+ "bytes": 16405,
240
+ "sha256": "c61af8c2c4a635cc682b84e279851cb54fedc6fb935d8eb11aafbeb1c5e81fc6"
241
+ },
242
+ "runtime/src/morph/cli.py": {
243
+ "bytes": 9723,
244
+ "sha256": "27eee3fd6d6410747f12b19b670a74f50a51b842a50b1eff4e75c46d0d08a986"
245
+ },
246
+ "runtime/src/morph/config.py": {
247
+ "bytes": 704,
248
+ "sha256": "bd3562c030611f87cc514308f155ad93740dd59927732f71b2e15009012d78ff"
249
+ },
250
+ "runtime/src/morph/dataset/__init__.py": {
251
+ "bytes": 620,
252
+ "sha256": "44ae493354fed0fec4b410f46e0c1fb0351b5fbe5f404ff50f77181e60a39cee"
253
+ },
254
+ "runtime/src/morph/dataset/conditional/__init__.py": {
255
+ "bytes": 238,
256
+ "sha256": "e46c747069acbf3d82407ccfcf96f2e33608c010a429f9abdb064bb71795d134"
257
+ },
258
+ "runtime/src/morph/dataset/conditional/scaffold/__init__.py": {
259
+ "bytes": 167,
260
+ "sha256": "6ef414b31cceb7303c174d720e0d0666efd6f6678c97b3cf86d33c799d2153dd"
261
+ },
262
+ "runtime/src/morph/dataset/conditional/scaffold/cutters.py": {
263
+ "bytes": 12282,
264
+ "sha256": "b29e0d7b1758461cda868bcba56d58b21ce76a45a9365bed73f7a2735103616f"
265
+ },
266
+ "runtime/src/morph/dataset/conditional/scaffold/datamodule.py": {
267
+ "bytes": 1402,
268
+ "sha256": "ecd4a5819d3654f8f76e3e0d059a60bfc9d0ac2ec343514d45517e7094c7c282"
269
+ },
270
+ "runtime/src/morph/dataset/conditional/scaffold/lmdb.py": {
271
+ "bytes": 4243,
272
+ "sha256": "54ea075ebb4a8ed481f93f57e9a5e25504918b6595bde106f2489e21e7e73b5b"
273
+ },
274
+ "runtime/src/morph/dataset/conditional/scaffold/wrappers.py": {
275
+ "bytes": 7720,
276
+ "sha256": "a44d61452b676dc1dfd8d6bd44c09b22d463c8129b23cf98ec3903d10a693f2c"
277
+ },
278
+ "runtime/src/morph/dataset/core/__init__.py": {
279
+ "bytes": 376,
280
+ "sha256": "7bab9c675f0850efc50e14a9898accfde5f8d1c1e2420414ac8c0986822d27e0"
281
+ },
282
+ "runtime/src/morph/dataset/core/atomic_data.py": {
283
+ "bytes": 708,
284
+ "sha256": "7d59ec16ed5b3cf82b57b49dd4d7799862709353a65f4d473d4571ba91b86fa6"
285
+ },
286
+ "runtime/src/morph/dataset/core/batch.py": {
287
+ "bytes": 23924,
288
+ "sha256": "7b2b2afd749b621b1ca890d192e4dc9378b61ead9ef34b90f04dc449e6bad369"
289
+ },
290
+ "runtime/src/morph/dataset/core/containers.py": {
291
+ "bytes": 19637,
292
+ "sha256": "adae656c3fbbe5cfe32f378a419c7e1076f653163ffe7d2c1d1d0abc71a99cd7"
293
+ },
294
+ "runtime/src/morph/dataset/core/conversion.py": {
295
+ "bytes": 2224,
296
+ "sha256": "0842565c503048a86a517c202dd0cc7c07e9296a841601b178ec38c43f903a6a"
297
+ },
298
+ "runtime/src/morph/dataset/core/flow_matching_wrapper.py": {
299
+ "bytes": 7568,
300
+ "sha256": "7672ce6dc416bbccae1471b8e4fb66f44adf7eaf8f0f2fa151f1268e9513a17d"
301
+ },
302
+ "runtime/src/morph/dataset/core/insertion_data.py": {
303
+ "bytes": 14393,
304
+ "sha256": "7e99e4d59b29ea537708b5f7887ed3e61b4b31ebf80d55fe5a0c6823ff8a439c"
305
+ },
306
+ "runtime/src/morph/dataset/core/insertion_targets.py": {
307
+ "bytes": 6614,
308
+ "sha256": "2e62e89125310572735d916e97c8a544cfb3eb76fb167ecd134b5f8b0424df8c"
309
+ },
310
+ "runtime/src/morph/dataset/core/lightning_datamodule.py": {
311
+ "bytes": 7057,
312
+ "sha256": "4d525cbcde4a64d7cac41837e0379c40097cc38fbbc2f54ff30ff7e3ab83de4c"
313
+ },
314
+ "runtime/src/morph/dataset/core/lmdb.py": {
315
+ "bytes": 10111,
316
+ "sha256": "748b7a10f8fb20f74c267de393cc3e1933ea86debde99d8fdaaef94e0a9afd29"
317
+ },
318
+ "runtime/src/morph/dataset/core/preprocessing.py": {
319
+ "bytes": 20145,
320
+ "sha256": "da9cffd6beb6da63ee749dd8b60d4d0509bcd937778014739b04ffc599dde066"
321
+ },
322
+ "runtime/src/morph/dataset/core/properties.py": {
323
+ "bytes": 1952,
324
+ "sha256": "4dc63574f5fde284245078adf50fb2d8a9ac16443b8276154c03b7703cc2e937"
325
+ },
326
+ "runtime/src/morph/dataset/core/representation.py": {
327
+ "bytes": 6591,
328
+ "sha256": "0ecac55e1faf9748826ec8f4c7f1a274263214ea3f68cc69de7047b55dd6a65f"
329
+ },
330
+ "runtime/src/morph/dataset/core/tokenized_decode.py": {
331
+ "bytes": 6559,
332
+ "sha256": "483afb3d468113da33cc8699998e6439fcde2264ee7ca479724206360584a2b8"
333
+ },
334
+ "runtime/src/morph/dataset/core/vocab.py": {
335
+ "bytes": 2236,
336
+ "sha256": "f8618488f7bcdc8a58d8b9f3443b764eac60985a33ead1bcc2d17d3bdc213329"
337
+ },
338
+ "runtime/src/morph/dataset/unconditional/__init__.py": {
339
+ "bytes": 403,
340
+ "sha256": "d7cd3b85745ad1a4d884c0a11a64b3ab9cedcc64e30f604dbe83f5beb14fa97b"
341
+ },
342
+ "runtime/src/morph/dataset/unconditional/chembl3d.py": {
343
+ "bytes": 9854,
344
+ "sha256": "d5cfd1ee4ddd3085b95b9a678d761d4f0beef99ac5ecfb21d3dfb3cae59653eb"
345
+ },
346
+ "runtime/src/morph/dataset/unconditional/geom.py": {
347
+ "bytes": 4071,
348
+ "sha256": "12bc792c2a61b3e6c29ae265b9997ba610765e268408e873918b5a65225945be"
349
+ },
350
+ "runtime/src/morph/dataset/unconditional/qm9.py": {
351
+ "bytes": 9520,
352
+ "sha256": "06b6086cb1234b283cd3a45daad2e06d3bdb5d45810b873f860c82969ccbfe53"
353
+ },
354
+ "runtime/src/morph/flow_matching/__init__.py": {
355
+ "bytes": 78,
356
+ "sha256": "674f4630aa8421d7e75c913741c6efb1a163fbc38ce909c6cdb011f9ba9ef48e"
357
+ },
358
+ "runtime/src/morph/flow_matching/assignment.py": {
359
+ "bytes": 16050,
360
+ "sha256": "b6ad66538f5bd7f14e0eee2a0ffd25a4110d1504e057a0a9eb63a354d9f6aadb"
361
+ },
362
+ "runtime/src/morph/flow_matching/integration.py": {
363
+ "bytes": 33356,
364
+ "sha256": "f64b7b9ed2a79c11932b72e498e57eef924b5c85a05aa6893ddfe11e2d4595e9"
365
+ },
366
+ "runtime/src/morph/flow_matching/interpolation.py": {
367
+ "bytes": 22169,
368
+ "sha256": "6ef2e03626fd4b3194c68df6e2410ab6e630f4891f97a8328b4eb0b3e18c7dcd"
369
+ },
370
+ "runtime/src/morph/flow_matching/prior.py": {
371
+ "bytes": 2389,
372
+ "sha256": "0f9b77274238b23be7a2ad88ee8e6dcbb785817fcfa3a35aa863b489d2a6e05d"
373
+ },
374
+ "runtime/src/morph/flow_matching/sampling_step.py": {
375
+ "bytes": 2806,
376
+ "sha256": "c768682a47da1b7852838e20b39317528717fc0485cbc35030b3ca71d7d845bb"
377
+ },
378
+ "runtime/src/morph/flow_matching/schedules.py": {
379
+ "bytes": 6776,
380
+ "sha256": "6fd8396a05052ae7831babc75ca40a7e748fb9edffe82bb2559533afa949b2a9"
381
+ },
382
+ "runtime/src/morph/inference/__init__.py": {
383
+ "bytes": 732,
384
+ "sha256": "63047340b4c7ed784e969b7d54035ab737282ee2acc6eeb26ba6cb3d52b4f573"
385
+ },
386
+ "runtime/src/morph/inference/bundles.py": {
387
+ "bytes": 6395,
388
+ "sha256": "f6e2d46e6e428452a58208e78c83da01d6c786f10f7062643a093fb6750dafe6"
389
+ },
390
+ "runtime/src/morph/inference/catalog.py": {
391
+ "bytes": 6215,
392
+ "sha256": "53a27b86d39641fd4964da82f4b1875598a0cdb1533f981074c6b7a14b4174b7"
393
+ },
394
+ "runtime/src/morph/inference/generate.py": {
395
+ "bytes": 11889,
396
+ "sha256": "c3181fbf6187cf22b476431ed7c0fdea4c74ea8e97acf270f486318e43646d19"
397
+ },
398
+ "runtime/src/morph/inference/hub.py": {
399
+ "bytes": 9739,
400
+ "sha256": "fa1f43937d66f0ab4b7b9c11ed749aef8d23444b2df3257c36ff72ecd3b821ca"
401
+ },
402
+ "runtime/src/morph/inference/module.py": {
403
+ "bytes": 3820,
404
+ "sha256": "415e0f9c624c191855874b8dd88d5e7aa18941632bc403a9c0b685bbf74f1d60"
405
+ },
406
+ "runtime/src/morph/inference/registry.py": {
407
+ "bytes": 4314,
408
+ "sha256": "8ca3e4246e00707ed0d646e6e760acebd5e3d3443e5e8d5f71f3b54653993fa9"
409
+ },
410
+ "runtime/src/morph/model/README.md": {
411
+ "bytes": 10319,
412
+ "sha256": "9c06b5b90300f7449048640417116aa8869dc1a75f106cbdd9344a89f6e446d3"
413
+ },
414
+ "runtime/src/morph/model/__init__.py": {
415
+ "bytes": 80,
416
+ "sha256": "1c7c3875387d5ba7f9166a804ea5a7ef7bd469728c1ad5c5003150d44e33be51"
417
+ },
418
+ "runtime/src/morph/model/backbones/__init__.py": {
419
+ "bytes": 64,
420
+ "sha256": "a1a1419590c11aa6ed429f8b6b293470e30fe767f5571d2517b0883efb071e0c"
421
+ },
422
+ "runtime/src/morph/model/backbones/conditional_dit.py": {
423
+ "bytes": 25451,
424
+ "sha256": "411fe1d0fd17c24e03e153d57f299aa0436bc5749e2064d5574681878429795d"
425
+ },
426
+ "runtime/src/morph/model/backbones/dit.py": {
427
+ "bytes": 31262,
428
+ "sha256": "e2798baaf31bc8004a17c2432c56af9c4b12651d259cc0deaf5f18c83c6ddd33"
429
+ },
430
+ "runtime/src/morph/model/build.py": {
431
+ "bytes": 3442,
432
+ "sha256": "e69f4231815f09c094d787f11edc49e222cbdc970edc6e416b6b94a9b88d4b21"
433
+ },
434
+ "runtime/src/morph/model/finetune/__init__.py": {
435
+ "bytes": 282,
436
+ "sha256": "8746b1e29e5a3b3b1805389257270b90f5d30995783f2cf41b9fb533c485fc0c"
437
+ },
438
+ "runtime/src/morph/model/finetune/base/__init__.py": {
439
+ "bytes": 803,
440
+ "sha256": "6e0ded0b3a5c2a76ccb85b05cf63bcc54e145bd1be07d933a737d6151433d856"
441
+ },
442
+ "runtime/src/morph/model/finetune/base/conditional_backbone.py": {
443
+ "bytes": 2853,
444
+ "sha256": "1353e96443eacf3ce88473a30d02ab4f1c8b6a9c90763ea61c58d353b806b378"
445
+ },
446
+ "runtime/src/morph/model/finetune/base/context_encoder.py": {
447
+ "bytes": 15124,
448
+ "sha256": "8d5dfc91ec73120161ed0a51dcc7edac442004ad4d5213ba34d9d11cfd1eee15"
449
+ },
450
+ "runtime/src/morph/model/finetune/base/finetune_base.py": {
451
+ "bytes": 9526,
452
+ "sha256": "2efa00fd8eed1096a9cf8799dee4abfd8b27de1c0600e22a906dddaa089c4ca0"
453
+ },
454
+ "runtime/src/morph/model/finetune/scaffold/__init__.py": {
455
+ "bytes": 366,
456
+ "sha256": "6345e71c8b03ee5eb0dcd105c0532acf73a1795bf6360b2847be600bcecd40ba"
457
+ },
458
+ "runtime/src/morph/model/finetune/scaffold/scaffold.py": {
459
+ "bytes": 1984,
460
+ "sha256": "6de7a6083b4303ae422f03f15b5b40b1233d48bfc2dd1e0aa83a4eaa8adf40dd"
461
+ },
462
+ "runtime/src/morph/model/finetune/scaffold/scaffold_context.py": {
463
+ "bytes": 6086,
464
+ "sha256": "d9446254770e3c3ea2c634a0636ab82a718514a7cb69760d756e9235cfbe2814"
465
+ },
466
+ "runtime/src/morph/model/layers/__init__.py": {
467
+ "bytes": 189,
468
+ "sha256": "79671fbdea358c330a45b7fd3d842119b32b1d548804b3d441bbfb7dbd703b69"
469
+ },
470
+ "runtime/src/morph/model/layers/attention.py": {
471
+ "bytes": 21038,
472
+ "sha256": "7efc416ac8fec0236909661ad0693a0aef613ff97a964fb6d8252cb49c60b5c6"
473
+ },
474
+ "runtime/src/morph/model/layers/embedding.py": {
475
+ "bytes": 14356,
476
+ "sha256": "efe924190da5904e05495f421dcc313134cebe0dee9bf665060e1e5781cd95ef"
477
+ },
478
+ "runtime/src/morph/model/layers/gmm.py": {
479
+ "bytes": 6753,
480
+ "sha256": "628e90c73bdbb3e70104214f80bbf8a94896ddbe22a9a3fc40cce34b20d2565f"
481
+ },
482
+ "runtime/src/morph/model/layers/heads.py": {
483
+ "bytes": 30913,
484
+ "sha256": "7113c29a6be81c93ca980dc19d0847d2015ac36702683e4f1adedd549aed46ae"
485
+ },
486
+ "runtime/src/morph/model/layers/kernels.py": {
487
+ "bytes": 12483,
488
+ "sha256": "be0c52b69c7612946244755e2865de0491440a41163cf828168eb750a8f929cf"
489
+ },
490
+ "runtime/src/morph/model/layers/lora.py": {
491
+ "bytes": 5947,
492
+ "sha256": "7194750605e7b5df9a02e4c4a39cf29c982f117c40198c99c73211c85ecdfe4b"
493
+ },
494
+ "runtime/src/morph/model/lightning/__init__.py": {
495
+ "bytes": 339,
496
+ "sha256": "c53943a4eb1e45568cebfb538655cc5eb7ead46284bbcd515800102c89177e52"
497
+ },
498
+ "runtime/src/morph/model/lightning/_optimizer.py": {
499
+ "bytes": 19578,
500
+ "sha256": "f77519db8d3458c05aec1543cb4cd487995cf398abcc71b62ea1835cb132165e"
501
+ },
502
+ "runtime/src/morph/model/lightning/_sampling.py": {
503
+ "bytes": 15344,
504
+ "sha256": "2694ba5cd0b315147285ba268ed5ad246d6091d2426fcd7b21f78d0eb0a8fca1"
505
+ },
506
+ "runtime/src/morph/model/lightning/_setup.py": {
507
+ "bytes": 6537,
508
+ "sha256": "835f510094110c4dbc590a88d9b94d41474ae87b442785a949328feda5b9afce"
509
+ },
510
+ "runtime/src/morph/model/lightning/_training.py": {
511
+ "bytes": 22479,
512
+ "sha256": "0451c3c4f1ad46cc5380615a3fbf8452d1fb4a0d27d69c885a411a3612c0997c"
513
+ },
514
+ "runtime/src/morph/model/lightning/_validation.py": {
515
+ "bytes": 11509,
516
+ "sha256": "03890457e504eed96f23dd8633a6af4317a9ed61e80b3e4ec935aaf9e63038d7"
517
+ },
518
+ "runtime/src/morph/model/lightning/base.py": {
519
+ "bytes": 9294,
520
+ "sha256": "ce9159e7b387ece0a3ce010b164f675b81980d2f617b5b05d00f96695ee33e28"
521
+ },
522
+ "runtime/src/morph/model/losses/__init__.py": {
523
+ "bytes": 190,
524
+ "sha256": "bb9de5950496ed184a32e11834d8e6f3b7d406773509ffa6c406a86bb5249fae"
525
+ },
526
+ "runtime/src/morph/model/losses/functional.py": {
527
+ "bytes": 11765,
528
+ "sha256": "42ae52f604a0cb8b7fe08955cfd273945ca068727994f20b02c80cdee3a00e1b"
529
+ },
530
+ "runtime/src/morph/utils/__init__.py": {
531
+ "bytes": 78,
532
+ "sha256": "eb76ca86f046931eaea693a696317e8b3ce0b8ad8695a92e3744fd1892f2b9b8"
533
+ },
534
+ "runtime/src/morph/utils/checkpoints.py": {
535
+ "bytes": 2301,
536
+ "sha256": "750302eb039e3947a5d4c84e4e7d04eb46e974cc0031ef1d197a3573e20eae4b"
537
+ },
538
+ "runtime/src/morph/utils/edge_alignment.py": {
539
+ "bytes": 4896,
540
+ "sha256": "0edcde93cfa3a2d825e783ea5cf64715aa248e59ffb8c6a23d4490d74976a71e"
541
+ },
542
+ "runtime/src/morph/utils/graph_math.py": {
543
+ "bytes": 6755,
544
+ "sha256": "2bae326c3538d757aac66dcfc4a0b5d023b17bd987d814d3dab9a57f9ce60552"
545
+ },
546
+ "runtime/src/morph/utils/loss_accumulation.py": {
547
+ "bytes": 15115,
548
+ "sha256": "0f3eca42145e715290576dd86f4bcfb1553714ec4cabeda9246cfaf1e4f4323c"
549
+ },
550
+ "runtime/src/morph/utils/lr_schedulers.py": {
551
+ "bytes": 5554,
552
+ "sha256": "b954c12df413ca6676263ef1af960e2a4ff52692acfd4223e72a6e02122a3638"
553
+ },
554
+ "runtime/src/morph/utils/metrics/__init__.py": {
555
+ "bytes": 6730,
556
+ "sha256": "abec143d21e36343fff54db0ca8042111b9e70da426567b13ec36d6cb05696b6"
557
+ },
558
+ "runtime/src/morph/utils/metrics/chemistry.py": {
559
+ "bytes": 34152,
560
+ "sha256": "61b598b99fad41571f9334b28f94fbeeeb0282d1b80423b1f2bc8f14180884e8"
561
+ },
562
+ "runtime/src/morph/utils/metrics/distribution.py": {
563
+ "bytes": 3348,
564
+ "sha256": "0a6c25c4e65843308059a3effc44e1072837e747926074c1d7c47ba7ee72cb46"
565
+ },
566
+ "runtime/src/morph/utils/metrics/plotting.py": {
567
+ "bytes": 4270,
568
+ "sha256": "686d491d7fbc83cf35f772649a869dc1a271966d2a4fa6162d6e2334db735723"
569
+ },
570
+ "runtime/src/morph/utils/metrics/posecheck_strain.py": {
571
+ "bytes": 6695,
572
+ "sha256": "60a4751cce0e23d87d8602135de0c9850182fe97f20632cb9095445bdc6b0365"
573
+ },
574
+ "runtime/src/morph/utils/metrics/tensor.py": {
575
+ "bytes": 13503,
576
+ "sha256": "3fcb867cde5d47f81725acc3b862fc56af5ecce23dee3a11ebe6d05c1772c6fe"
577
+ },
578
+ "runtime/src/morph/utils/rdkit_utils.py": {
579
+ "bytes": 9018,
580
+ "sha256": "0fddc055c6de60893272fe8c50c92de29c9e72b7819827caac753e4cd0c6f1e5"
581
+ },
582
+ "runtime/src/morph/utils/run_config.py": {
583
+ "bytes": 8025,
584
+ "sha256": "0c289120887a051379523af528ebc9310f356f3b92efb898ddaf773dbf698aa2"
585
+ },
586
+ "runtime/src/morph/utils/vocab_utils.py": {
587
+ "bytes": 6343,
588
+ "sha256": "7b5506971b5092865b86311173b24d7fb70a881f123c57fd8696c412a25d618b"
589
+ },
590
+ "runtime/uv.lock": {
591
+ "bytes": 611263,
592
+ "sha256": "6fd6609500ea661b3b5c9f17d0997c5709295ca2cbbe16c97fc8259178fa931e"
593
+ },
594
+ "training_config.yaml": {
595
+ "bytes": 13428,
596
+ "sha256": "4fd11b415e9b4a599344431218db7f9960ba443dc29787410a4566ce5dacb434"
597
+ },
598
+ "validation.json": {
599
+ "bytes": 294,
600
+ "sha256": "5acbbb78be426e03abd58c3dc062b30b000e91e815c329dfa7f1422c9866b740"
601
+ }
602
+ }
geom/explicit_h/metadata.json ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "dataset": "geom",
3
+ "variant": "explicit_h",
4
+ "includes_explicit_hydrogens": true,
5
+ "source_max_total_atoms_including_h": 72,
6
+ "training_run": "geom-explicit-e48-resume-16520626",
7
+ "resumed_from_completed_epoch": 48,
8
+ "source_snapshot": "geom_resume_e48_20261008",
9
+ "checkpoint_format": "Original Lightning checkpoint, current + EMA + optimizer state",
10
+ "epoch_numbering": "Completed epochs (one-based); original checkpoint epoch is zero-based",
11
+ "checkpoints": [
12
+ {
13
+ "filename": "epoch_050.ckpt",
14
+ "original_filename": "epoch=49-step=441050.ckpt",
15
+ "completed_epochs": 50,
16
+ "checkpoint_epoch_index": 49,
17
+ "global_step": 441050,
18
+ "bytes": 509181385,
19
+ "sha256": "016c4a5bbb4f5ef36d1d62dff772ecf8d384e8ab3e2c94ebeb4c4357183f690a"
20
+ }
21
+ ],
22
+ "atom_tokens": [
23
+ "Br",
24
+ "C",
25
+ "Cl",
26
+ "F",
27
+ "H",
28
+ "I",
29
+ "N",
30
+ "O",
31
+ "P",
32
+ "S"
33
+ ],
34
+ "edge_tokens": [
35
+ "<NO_BOND>",
36
+ "1",
37
+ "2",
38
+ "3"
39
+ ],
40
+ "charge_tokens": [
41
+ "-2",
42
+ "-1",
43
+ "0",
44
+ "1",
45
+ "2"
46
+ ],
47
+ "coordinate_std_angstrom": 2.4406259059906006
48
+ }
geom/explicit_h/runtime/configs/callbacks/callbacks.yaml ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # @package _global_
2
+
3
+ ## Put your callback args here
4
+ callbacks:
5
+ monitor_metric: ${if:${oc.eval:"'${representation}' in ('geometric_graph', 'molecule')"},val/validity,val/batch/pair_dist_l1}
6
+ monitor_metric_mode: ${if:${oc.eval:"'${representation}' in ('geometric_graph', 'molecule')"},max,min}
7
+
8
+ # model_checkpoints -> best-by-metric (top-1, monitored)
9
+ # every_n_epochs_checkpoint -> latest (no monitor; overwrites every epoch)
10
+ model_checkpoints:
11
+ save_top_k: 1
12
+ save_last: False
13
+ verbose: False
14
+
15
+ every_n_epochs_checkpoint:
16
+ every_n_epochs: 1
17
+ save_top_k: 1
18
+ save_last: False
19
+ verbose: False
20
+ save_on_train_epoch_end: True # Force per-train-epoch firing
geom/explicit_h/runtime/configs/data/chembl3d/chembl3d.yaml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # LoQI ChEMBL3D source format, without dataset-specific size/element filters.
2
+ defaults:
3
+ - /data/molecular@_here_
4
+ - _self_
5
+
6
+ dataset_name: chembl3d
7
+ dataset_target: morph.dataset.unconditional.chembl3d.FlowMatchingChEMBL3DDataset
8
+ source_dir: ${oc.env:CHEMBL3D_SOURCE_DIR,null}
geom/explicit_h/runtime/configs/data/chembl3d/implicit_h.yaml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ defaults:
2
+ - /data/chembl3d/chembl3d@_here_
3
+ - _self_
4
+
5
+ hydrogen_mode: implicit
geom/explicit_h/runtime/configs/data/chembl3d/max100.yaml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # Inclusive total-atom limit, applied before hydrogen removal.
2
+ defaults:
3
+ - /data/chembl3d/chembl3d@_here_
4
+ - _self_
5
+
6
+ max_atoms: 100
7
+ cache_name: ${data.dataset_name}_max${data.max_atoms}${if:${eq:${data.hydrogen_mode},implicit},_implicit_h,''}
geom/explicit_h/runtime/configs/data/chembl3d/max100_implicit_h.yaml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ defaults:
2
+ - /data/chembl3d/max100@_here_
3
+ - _self_
4
+
5
+ hydrogen_mode: implicit
geom/explicit_h/runtime/configs/data/geom/geom.yaml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # GEOM-Drugs source format and default molecule subset.
2
+ defaults:
3
+ - /data/molecular@_here_
4
+ - _self_
5
+
6
+ dataset_name: geom
7
+ dataset_target: morph.dataset.unconditional.geom.FlowMatchingGEOMDataset
8
+ source_dir: ${oc.env:GEOM_SOURCE_DIR,null} # Optional prefiltered pickle directory.
9
+ # Preserve the established GEOM subset. Limits apply before hydrogen removal.
10
+ max_atoms: 72
11
+ allowed_atom_symbols: [H, C, N, O, S, F, Cl, Br, P, I]
geom/explicit_h/runtime/configs/data/geom/implicit_h.yaml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ defaults:
2
+ - /data/geom/geom@_here_
3
+ - _self_
4
+
5
+ hydrogen_mode: implicit
geom/explicit_h/runtime/configs/data/geom/scaffold_decoration.yaml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # GEOM-Drugs data config for the **scaffold decoration** task.
2
+ #
3
+ # Mirrors configs/data/qm9/scaffold_decoration.yaml but on GEOM-Drugs: source
4
+ # is the selected scaffold of each target; target is the full molecule. The model
5
+ # learns to grow it by inserting decoration atoms around the fixed scaffold.
6
+ #
7
+ # Inherits from configs/data/geom/geom.yaml and overrides:
8
+ # - datamodule._target_ -> ScaffoldLightningDataModule
9
+ #
10
+ # The scaffold cache is built lazily into ``scaffold_groups_dir`` on first run
11
+ # (one file per split and scaffold kind) and reused afterwards.
12
+ defaults:
13
+ - /data/geom/geom@_here_
14
+ - _self_
15
+
16
+ scaffold_groups_dir: ${data.preprocessing.root}/processed/scaffold_groups
17
+ scaffold_kind: rgroup # murcko, rgroup (BRICS), heavy (generate H), linker
18
+ # Evaluate each distinct molecule/scaffold pair; training always draws randomly.
19
+ enumerate_slicings: false
20
+ datamodule:
21
+ _target_: morph.dataset.conditional.scaffold.datamodule.ScaffoldLightningDataModule
22
+ scaffold_groups_dir: ${data.scaffold_groups_dir}
23
+ scaffold_kind: ${data.scaffold_kind}
24
+ enumerate_slicings: ${data.enumerate_slicings}
geom/explicit_h/runtime/configs/data/molecular.yaml ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Shared drug-like molecular training and preprocessing configuration.
2
+
3
+ root_path: ${oc.env:PROJECT_ROOT}/data
4
+ preprocess_workers: 10
5
+ preprocess_chunk_size: 128
6
+ statistics_workers: ${data.preprocess_workers}
7
+ hydrogen_mode: explicit
8
+ # The mode is part of the cache path; changing it discovers fresh vocab/statistics.
9
+ cache_name: ${data.dataset_name}${if:${eq:${data.hydrogen_mode},implicit},_implicit_h,''}
10
+ source_dir: null
11
+ max_atoms: null
12
+ allowed_atom_symbols: null
13
+
14
+ n_atoms_strategy: "uniform" # "approx", "empirical", "learned"
15
+ # Uniform source-count support padding; explicit so inference and training can
16
+ # be matched or ablated without code changes.
17
+ uniform_n_atoms_padding: 5
18
+ optimal_transport: "equivariant"
19
+ # Physical Angstroms (converted to normalized coordinates internally). These
20
+ # reproduce the former normalized 0.25 / 0.2 scales at GEOM's training-set std.
21
+ # Physical Angstroms. Insertion bridge noise vanishes as (1-t); move noise is
22
+ # the persistent training-time jitter floor for matched atoms and insertions
23
+ # that are already present.
24
+ ins_noise_scale: 0.65
25
+ move_noise_scale: 0.5
26
+
27
+ # Drug-like datasets contain charged species; allow them in validity metrics.
28
+ allow_charged: true
29
+
30
+
31
+ # Preprocessing configuration - computes tokens from data and distributions from training dataset only
32
+ preprocessing:
33
+ _target_: morph.dataset.core.preprocessing.Preprocessing
34
+ _recursive_: false
35
+ root: ${data.root_path}/${data.cache_name}
36
+ num_workers: ${data.statistics_workers}
37
+ train_dataset: ${data.datamodule.datasets.train}
38
+ atom_tokens_path: ${data.preprocessing.root}/processed/atom_tokens.txt
39
+ edge_tokens_path: ${data.preprocessing.root}/processed/edge_tokens.txt
40
+ charge_tokens_path: ${data.preprocessing.root}/processed/charge_tokens.txt
41
+ distributions_path: ${data.preprocessing.root}/processed/distributions.pt
42
+ # Tokens and distributions will be discovered from data and saved to files
43
+ # On subsequent runs, they will be loaded from the files
44
+
45
+ vocab: null
46
+
47
+ interpolator:
48
+ _target_: morph.flow_matching.interpolation.Interpolator
49
+ distributions: null
50
+ optimal_transport: ${data.optimal_transport}
51
+ ins_noise_scale: ${data.ins_noise_scale}
52
+ move_noise_scale: ${data.move_noise_scale}
53
+ # Training-only categorical corruption; pairs are scaled per molecule to
54
+ # match the expected number of changed atoms. Clean targets stay unchanged.
55
+ atom_type_noise_prob: 0.0
56
+ # OT matching (cost always squared-Euclidean; move cost in Angstrom). c_move
57
+ # scales the squared move distance (A^2); c_ins/c_del/c_sub are fixed A^2 costs,
58
+ # directly comparable. At 6.125 each, delete+insert costs 3.5^2, so atoms
59
+ # farther than 3.5 A apart are left unmatched by default.
60
+ pre_align_iters: 2 # equivariant-OT inner loop (Hungarian+Kabsch) iters
61
+ c_move: 1.0
62
+ c_sub: 0.0
63
+ c_ins: 6.125
64
+ c_del: 6.125
65
+ del_schedule: ${schedule}
66
+ ins_schedule: ${schedule}
67
+ sub_schedule:
68
+ _target_: morph.flow_matching.schedules.SmoothstepSchedule
69
+ shift: 1.5
70
+ sub_e_schedule:
71
+ _target_: morph.flow_matching.schedules.SmoothstepSchedule
72
+ shift: 1.5
73
+
74
+ datamodule:
75
+ _target_: morph.dataset.core.lightning_datamodule.LightningDataModule
76
+ # tokens and distributions will be passed from preprocessing in run.py
77
+
78
+ vocab: ${data.vocab}
79
+ distributions: null
80
+ representation: ${representation}
81
+
82
+ datasets:
83
+ train:
84
+ _target_: ${data.dataset_target}
85
+ root: ${data.preprocessing.root}
86
+ preprocess_workers: ${data.preprocess_workers}
87
+ preprocess_chunk_size: ${data.preprocess_chunk_size}
88
+ hydrogen_mode: ${data.hydrogen_mode}
89
+ source_dir: ${data.source_dir}
90
+ max_atoms: ${data.max_atoms}
91
+ allowed_atom_symbols: ${data.allowed_atom_symbols}
92
+ vocab: ${data.vocab}
93
+ distributions: null
94
+
95
+ val:
96
+ - _target_: ${data.dataset_target}
97
+ root: ${data.preprocessing.root}
98
+ preprocess_workers: ${data.preprocess_workers}
99
+ preprocess_chunk_size: ${data.preprocess_chunk_size}
100
+ hydrogen_mode: ${data.hydrogen_mode}
101
+ source_dir: ${data.source_dir}
102
+ max_atoms: ${data.max_atoms}
103
+ allowed_atom_symbols: ${data.allowed_atom_symbols}
104
+ vocab: ${data.vocab}
105
+ distributions: null
106
+
107
+ test:
108
+ - _target_: ${data.dataset_target}
109
+ root: ${data.preprocessing.root}
110
+ preprocess_workers: ${data.preprocess_workers}
111
+ preprocess_chunk_size: ${data.preprocess_chunk_size}
112
+ hydrogen_mode: ${data.hydrogen_mode}
113
+ source_dir: ${data.source_dir}
114
+ max_atoms: ${data.max_atoms}
115
+ allowed_atom_symbols: ${data.allowed_atom_symbols}
116
+ vocab: ${data.vocab}
117
+ distributions: null
118
+
119
+ interpolator: ${data.interpolator}
120
+
121
+ rotate: ${model.rotate}
122
+ n_augmentations: ${model.n_augmentations}
123
+
124
+ num_workers:
125
+ train: 10
126
+ val: 0
127
+ test: 0
128
+
129
+ batch_size:
130
+ train: 320
131
+ val: 128
132
+ test: 64
133
+
134
+ n_atoms_strategy: ${data.n_atoms_strategy}
135
+ uniform_n_atoms_padding: ${data.uniform_n_atoms_padding}
136
+ time_dist: ${model.module.time_dist}
geom/explicit_h/runtime/configs/data/qm9/qm9.yaml ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## QM9 data and preprocessing configuration.
2
+
3
+ dataset_name: qm9
4
+ root_path: ${oc.env:PROJECT_ROOT}/data
5
+ preprocess_workers: 0
6
+
7
+ n_atoms_strategy: "uniform" # "approx", "empirical", "learned"
8
+ # Expand both ends of the empirical count support for the uniform flow source.
9
+ # QM9's minimum is already the hard lower bound of 3, so positive padding is
10
+ # necessarily asymmetric; set to 0 for an unpadded 3--29 diagnostic prior.
11
+ uniform_n_atoms_padding: 5
12
+ optimal_transport: "equivariant"
13
+ # Physical Angstroms (converted to normalized coordinates internally). Insertion
14
+ # bridge noise vanishes as (1-t); move noise is the persistent training-time
15
+ # jitter floor for matched atoms and insertions that are already present.
16
+ ins_noise_scale: 0.35
17
+ move_noise_scale: 0.3
18
+
19
+ # QM9 contains only neutral molecules; charged species are treated as invalid.
20
+ allow_charged: false
21
+
22
+
23
+ # Preprocessing configuration - computes tokens from data and distributions from training dataset only
24
+ preprocessing:
25
+ _target_: morph.dataset.core.preprocessing.Preprocessing
26
+ _recursive_: false
27
+ root: ${data.root_path}/qm9
28
+ train_dataset: ${data.datamodule.datasets.train}
29
+ # Canonical (representation-agnostic) cache. One preprocessing per dataset;
30
+ # representation-specific projection happens at runtime in the wrapper.
31
+ atom_tokens_path: ${data.preprocessing.root}/processed/atom_tokens.txt
32
+ edge_tokens_path: ${data.preprocessing.root}/processed/edge_tokens.txt
33
+ charge_tokens_path: ${data.preprocessing.root}/processed/charge_tokens.txt
34
+ distributions_path: ${data.preprocessing.root}/processed/distributions.pt
35
+
36
+ vocab: None
37
+
38
+ interpolator:
39
+ _target_: morph.flow_matching.interpolation.Interpolator
40
+ distributions: None
41
+ optimal_transport: ${data.optimal_transport}
42
+ ins_noise_scale: ${data.ins_noise_scale}
43
+ move_noise_scale: ${data.move_noise_scale}
44
+ # OT matching (cost always squared-Euclidean; move cost in Angstrom). c_move
45
+ # scales the squared move distance (A^2); c_ins/c_del/c_sub are fixed A^2 costs,
46
+ # directly comparable. At 6.125 each, delete+insert costs 3.5^2, so atoms
47
+ # farther than 3.5 A apart are left unmatched by default.
48
+ pre_align_iters: 2 # equivariant-OT inner loop (Hungarian+Kabsch) iters
49
+ c_move: 1.0
50
+ c_sub: 0.0
51
+ c_ins: 6.125
52
+ c_del: 6.125
53
+ del_schedule: ${schedule}
54
+ ins_schedule: ${schedule}
55
+ sub_schedule:
56
+ _target_: morph.flow_matching.schedules.SmoothstepSchedule
57
+ shift: 1.5
58
+ sub_e_schedule:
59
+ _target_: morph.flow_matching.schedules.SmoothstepSchedule
60
+ shift: 1.5
61
+
62
+ datamodule:
63
+ _target_: morph.dataset.core.lightning_datamodule.LightningDataModule
64
+ # tokens and distributions will be passed from preprocessing in run.py
65
+
66
+ vocab: ${data.vocab}
67
+ distributions: None
68
+ representation: ${representation}
69
+
70
+ datasets:
71
+ train:
72
+ _target_: morph.dataset.unconditional.qm9.FlowMatchingQM9Dataset
73
+ root: ${data.root_path}/qm9
74
+ vocab: ${data.vocab}
75
+ distributions: None
76
+
77
+ val:
78
+ - _target_: morph.dataset.unconditional.qm9.FlowMatchingQM9Dataset
79
+ root: ${data.root_path}/qm9
80
+ vocab: ${data.vocab}
81
+ distributions: None
82
+
83
+ test:
84
+ - _target_: morph.dataset.unconditional.qm9.FlowMatchingQM9Dataset
85
+ root: ${data.root_path}/qm9
86
+ vocab: ${data.vocab}
87
+ distributions: None
88
+
89
+ interpolator: ${data.interpolator}
90
+
91
+ rotate: ${model.rotate}
92
+ n_augmentations: ${model.n_augmentations}
93
+
94
+ num_workers:
95
+ train: 10
96
+ val: 0
97
+ test: 0
98
+
99
+ batch_size:
100
+ train: 1024
101
+ val: 128
102
+ test: 32
103
+
104
+ n_atoms_strategy: ${data.n_atoms_strategy}
105
+ uniform_n_atoms_padding: ${data.uniform_n_atoms_padding}
106
+ time_dist: ${model.module.time_dist}
geom/explicit_h/runtime/configs/data/qm9/scaffold_decoration.yaml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # QM9 data config for the **scaffold decoration** task.
2
+ #
3
+ # Source is the selected scaffold of each target; target is the full molecule.
4
+ # The model learns to grow the molecule by inserting decoration atoms
5
+ # around the fixed scaffold.
6
+ #
7
+ # Inherits from configs/data/qm9/qm9.yaml and overrides:
8
+ # - datamodule._target_ → ScaffoldLightningDataModule
9
+ #
10
+ defaults:
11
+ - /data/qm9/qm9@_here_
12
+ - _self_
13
+
14
+ scaffold_groups_dir: ${data.root_path}/qm9/processed/scaffold_groups
15
+ scaffold_kind: rgroup # murcko, rgroup (BRICS), heavy (generate H), linker
16
+ # Evaluate each distinct molecule/scaffold pair; training always draws randomly.
17
+ enumerate_slicings: false
18
+ datamodule:
19
+ _target_: morph.dataset.conditional.scaffold.datamodule.ScaffoldLightningDataModule
20
+ scaffold_groups_dir: ${data.scaffold_groups_dir}
21
+ scaffold_kind: ${data.scaffold_kind}
22
+ enumerate_slicings: ${data.enumerate_slicings}
geom/explicit_h/runtime/configs/default.yaml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ defaults:
2
+ - _self_
3
+ # Single-knob presets bundle
4
+ # `data` + `embeddings` (with dataset-tuned ExtrapolatableCount params)
5
+ # plus the shared `core` group selections. Override individual groups as
6
+ # usual, e.g. `defaults=geom/geom model=backbones/dit embeddings=qm9`.
7
+ - defaults: qm9/qm9
8
+
9
+ # What the model trains on. Datasets declare their CAPABILITIES; run.py validates
10
+ # the requested mode against them before preprocessing.
11
+ # pointcloud — x, a only (charges and edges are dummy singletons)
12
+ # charged_pointcloud — x, a, c (edges are dummy singletons)
13
+ # geometric_graph — x, a, edge_index, e (charges are dummy neutral)
14
+ # molecule — full chemistry (current behavior)
15
+ representation: molecule
16
+ seed: 42
17
+
18
+ # Run directory: <root>/<dataset>/<cfg_method>/<date>/<wandb_id>. Root is
19
+ # MORPH_RUN_ROOT (scratch, set in .env) so every run's outputs/checkpoints/wandb
20
+ # land off-repo; falls back to <cwd>/outputs for ad-hoc runs with no env set.
21
+ # wandb id is MORPH_RUN_ID (same as WANDB_RUN_ID). Set in the shell before
22
+ # torchrun, or set automatically for single-process runs in run.py before Hydra composes.
23
+ hydra:
24
+ run:
25
+ dir: ${oc.env:MORPH_RUN_ROOT,${hydra:runtime.cwd}/outputs}/${hydra:runtime.choices.data}/${now:%Y-%m-%d}/${oc.env:MORPH_RUN_ID}
geom/explicit_h/runtime/configs/defaults/chembl3d/chembl3d.yaml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # @package _global_
2
+ defaults:
3
+ - core
4
+ - /data: chembl3d/chembl3d
5
+ - /embeddings: geom
geom/explicit_h/runtime/configs/defaults/chembl3d/implicit_h.yaml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # @package _global_
2
+ defaults:
3
+ - /defaults/core
4
+ - /data: chembl3d/implicit_h
5
+ - /embeddings: geom
geom/explicit_h/runtime/configs/defaults/chembl3d/implicit_h_2x4090.yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # @package _global_
2
+ defaults:
3
+ - /defaults/chembl3d/train_2x4090
4
+ - override /data: chembl3d/max100_implicit_h
5
+ - _self_
6
+
7
+ # Train from scratch: the atom vocabulary/statistics differ from the H model.
8
+ # Preserve global batch 640, eval every epoch, both checkpoint callbacks every 5.
9
+ logging:
10
+ project: morph-chembl3d-implicit-h
geom/explicit_h/runtime/configs/defaults/chembl3d/train_2x4090.yaml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # @package _global_
2
+ defaults:
3
+ - /defaults/core
4
+ - /data: chembl3d/max100
5
+ - /embeddings: geom
6
+ - _self_
7
+
8
+ # Profiled on max100 ChEMBL: 2 GPUs * 320 * 1 = 640 effective global batch.
9
+ data:
10
+ datamodule:
11
+ train_prefetch_factor: 1
12
+ batch_size:
13
+ train: 320
14
+ val: 32
15
+ test: 32
16
+ num_workers:
17
+ train: 20
18
+ val: 2
19
+ test: 2
20
+
21
+ trainer:
22
+ trainer:
23
+ accelerator: gpu
24
+ devices: 2
25
+ accumulate_grad_batches: 1
26
+ max_epochs: -1
27
+ check_val_every_n_epoch: 1
28
+ num_val_samples: 4096
29
+ # Validation runs during fit; leave wall-clock headroom for final checkpointing.
30
+ do_validate: false
31
+ do_predict: false
32
+ final_checkpoint_path: final.ckpt
33
+
34
+ callbacks:
35
+ model_checkpoints:
36
+ every_n_epochs: 5
37
+ every_n_epochs_checkpoint:
38
+ every_n_epochs: 5
39
+ save_top_k: -1
40
+ save_last: link
geom/explicit_h/runtime/configs/defaults/core.yaml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # @package _global_
2
+ # Shared default groups that don't change between QM9 / GEOM runs.
3
+ # Dataset-specific presets (defaults/qm9/qm9.yaml, defaults/geom/geom.yaml) inherit
4
+ # from this and only add `data` + `embeddings`.
5
+ defaults:
6
+ - /heads: head
7
+ - /insertion_head: unimodal
8
+ - /model: backbones/dit
9
+ - /schedule: smoothstep
10
+ - /trainer: trainer
11
+ - /callbacks: callbacks
12
+ - /logging: wandb_logger
13
+ - /integrator: integrator
geom/explicit_h/runtime/configs/defaults/geom/geom.yaml ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # @package _global_
2
+ # GEOM preset: shared core + GEOM data and embeddings.
3
+ defaults:
4
+ - core
5
+ - /data: geom/geom
6
+ - /embeddings: geom
7
+ - _self_
8
+
9
+ # Evaluate every epoch; keep every fifth completed epoch for releases/resuming.
10
+ trainer:
11
+ trainer:
12
+ check_val_every_n_epoch: 1
13
+
14
+ callbacks:
15
+ model_checkpoints:
16
+ every_n_epochs: 5
17
+ every_n_epochs_checkpoint:
18
+ every_n_epochs: 5
19
+ save_top_k: -1
20
+ save_last: link
geom/explicit_h/runtime/configs/defaults/geom/implicit_h.yaml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # @package _global_
2
+ defaults:
3
+ - /defaults/core
4
+ - /data: geom/implicit_h
5
+ - /embeddings: geom
geom/explicit_h/runtime/configs/defaults/geom/scaffold_decoration.yaml ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # @package _global_
2
+ # GEOM-Drugs **scaffold decoration** fine-tune preset.
3
+ #
4
+ # Mirrors defaults/qm9/scaffold_decoration.yaml on GEOM-Drugs. Bare-scaffold
5
+ # source -> full-molecule target: the model learns to grow a molecule by
6
+ # inserting decoration atoms around the fixed scaffold.
7
+ #
8
+ # Differences from the QM9 scaffold preset:
9
+ # - data -> geom/scaffold_decoration (GEOM base datasets)
10
+ # - embeddings -> geom
11
+ #
12
+ # Reuses the scaffold_finetune model config (loads the pretrained unconditional
13
+ # DiT into the clean lane + adds the node/edge conditioning and the gated
14
+ # cross-attn blocks).
15
+ #
16
+ # Pair with a GEOM unconditional DiT checkpoint via
17
+ # ``model.module.pretrained_ckpt=...``.
18
+ defaults:
19
+ - core
20
+ - /data: geom/scaffold_decoration
21
+ - /embeddings: geom
22
+ - override /model: finetune/scaffold_finetune
23
+ - _self_
geom/explicit_h/runtime/configs/defaults/qm9/qm9.yaml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # @package _global_
2
+ # QM9 preset: shared core + QM9 data and embeddings.
3
+ defaults:
4
+ - core
5
+ - /data: qm9/qm9
6
+ - /embeddings: qm9
geom/explicit_h/runtime/configs/defaults/qm9/scaffold_decoration.yaml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # @package _global_
2
+ # QM9 **scaffold decoration** fine-tune preset.
3
+ #
4
+ # Bare-scaffold source → full-molecule target. The model learns to grow
5
+ # a molecule by inserting decoration atoms around the fixed scaffold.
6
+ defaults:
7
+ - core
8
+ - /data: qm9/scaffold_decoration
9
+ - /embeddings: qm9
10
+ - override /model: finetune/scaffold_finetune
11
+ - _self_
geom/explicit_h/runtime/configs/embeddings/geom.yaml ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Shared embedding stack tuned for GEOM-Drugs.
2
+ # - node_count_embedding uses ExtrapolatableCountEmbedding with periods/max_count
3
+ # scaled up for the much larger atom counts in GEOM-Drugs.
4
+
5
+ atom_type_embedding:
6
+ _target_: morph.model.layers.embedding.Embedding
7
+ num_embeddings: ${len:${data.vocab.atom_tokens}}
8
+ embedding_dim: 64
9
+ out_dim: 128
10
+
11
+ edge_type_embedding:
12
+ _target_: morph.model.layers.embedding.Embedding
13
+ num_embeddings: ${len:${data.vocab.edge_tokens}}
14
+ embedding_dim: 64
15
+ out_dim: 128
16
+
17
+ time_embedding:
18
+ _target_: morph.model.layers.embedding.TimeEmbedding
19
+ embedding_dim: 128
20
+ out_dim: 128
21
+
22
+ node_count_embedding:
23
+ _target_: morph.model.layers.embedding.ExtrapolatableCountEmbedding
24
+ embedding_dim: 64
25
+ out_dim: 128
26
+ min_period: 128.0
27
+ max_period: 1024.0
28
+ max_count: 96.0
geom/explicit_h/runtime/configs/embeddings/qm9.yaml ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Shared embedding stack tuned for QM9.
2
+ # - node_count_embedding uses ExtrapolatableCountEmbedding so the model can
3
+ # generalise slightly outside the training atom-count support.
4
+ # - Defaults sized for QM9 (training counts in [3, 29]).
5
+
6
+ atom_type_embedding:
7
+ _target_: morph.model.layers.embedding.Embedding
8
+ num_embeddings: ${len:${data.vocab.atom_tokens}}
9
+ embedding_dim: 64
10
+ out_dim: 128
11
+
12
+ edge_type_embedding:
13
+ _target_: morph.model.layers.embedding.Embedding
14
+ num_embeddings: ${len:${data.vocab.edge_tokens}}
15
+ embedding_dim: 64
16
+ out_dim: 128
17
+
18
+ time_embedding:
19
+ _target_: morph.model.layers.embedding.TimeEmbedding
20
+ embedding_dim: 128
21
+ out_dim: 128
22
+
23
+ node_count_embedding:
24
+ _target_: morph.model.layers.embedding.ExtrapolatableCountEmbedding
25
+ embedding_dim: 64
26
+ out_dim: 128
27
+ min_period: 64.0
28
+ max_period: 512.0
29
+ max_count: 32.0
geom/explicit_h/runtime/configs/heads/head.yaml ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Standard molecular DiT readouts. The insertion-content head is an independent
2
+ # Hydra choice (``insertion_head=unimodal`` by default, or ``=gmm``).
3
+
4
+ heads:
5
+ _target_: morph.model.layers.heads.MultiHeadModule
6
+ output_init_std: ${model.head_initialization.output_std}
7
+ independent_adapters: ${oc.select:model.head_independent_adapters,false}
8
+
9
+ heads_configs:
10
+ graph_aggregation: mean
11
+
12
+ node_heads:
13
+ atom_type_head:
14
+ input_dim: ${model.head_node_dim}
15
+ output_dim: ${len:${data.vocab.atom_tokens}}
16
+ adapter_dim: ${model.head_node_adapter_dim}
17
+ group: state
18
+
19
+ charge_head:
20
+ input_dim: ${model.head_node_dim}
21
+ output_dim: ${len:${data.vocab.charge_tokens}}
22
+ adapter_dim: ${model.head_node_adapter_dim}
23
+ group: state
24
+
25
+ ins_rate_head:
26
+ input_dim: ${model.head_node_dim}
27
+ output_dim: 1
28
+ adapter_dim: ${model.head_node_adapter_dim}
29
+ group: edit
30
+ initial_rate: ${model.head_initialization.ins_rate}
31
+
32
+ do_del_head:
33
+ input_dim: ${model.head_node_dim}
34
+ output_dim: 1
35
+ adapter_dim: ${model.head_node_adapter_dim}
36
+ group: edit
37
+ initial_probability: ${model.head_initialization.do_del_probability}
38
+
39
+ do_sub_a_head:
40
+ input_dim: ${model.head_node_dim}
41
+ output_dim: 1
42
+ adapter_dim: ${model.head_node_adapter_dim}
43
+ group: edit
44
+ initial_probability: ${model.head_initialization.do_sub_a_probability}
45
+
46
+ edge_heads:
47
+ edge_type_head:
48
+ input_dim: ${model.head_edge_dim}
49
+ output_dim: ${len:${data.vocab.edge_tokens}}
50
+ adapter_dim: ${model.head_edge_adapter_dim}
51
+ group: state
52
+
53
+ do_sub_e_head:
54
+ input_dim: ${model.head_edge_dim}
55
+ output_dim: 1
56
+ adapter_dim: ${model.head_edge_adapter_dim}
57
+ group: state
58
+ initial_probability: ${model.head_initialization.do_sub_e_probability}
59
+
60
+ ins_edge_head:
61
+ _target_: morph.model.layers.heads.InsertionEdgeHead
62
+ _recursive_: false
63
+ hidden_dim: ${model.head_node_dim}
64
+ readout_dim: ${model.head_insertion_edge_dim}
65
+ output_init_std: ${model.head_initialization.output_std}
66
+ n_edge_types: ${len:${data.vocab.edge_tokens}}
67
+ n_atom_types: ${len:${data.vocab.atom_tokens}}
68
+ n_charge_types: ${len:${data.vocab.charge_tokens}}
69
+ rbf_embedding_args:
70
+ _target_: morph.model.layers.embedding.RBFEmbedding
71
+ num_rbf: 128
72
+ rbf_dmax: 3.5
73
+ out_dim: 64
74
+ dropout: 0.0
75
+ trainable: false
geom/explicit_h/runtime/configs/insertion_head/gmm.yaml ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Optional mixture-density insertion-content head.
2
+ mode: gmm
3
+ dimension: 3
4
+ num_components: 10
5
+
6
+ model:
7
+ _target_: morph.model.layers.heads.GMMInsertionHead
8
+ hidden_dim: ${model.head_node_dim}
9
+ readout_dim: ${model.head_insertion_adapter_dim}
10
+ output_init_std: ${model.head_initialization.output_std}
11
+ num_components: ${insertion_head.num_components}
12
+ sigma_min: 0.05
13
+ sigma_max: 2.0
14
+ sigma_init: 0.5
15
+ N_a: ${len:${data.vocab.atom_tokens}}
16
+ N_c: ${len:${data.vocab.charge_tokens}}
geom/explicit_h/runtime/configs/insertion_head/unimodal.yaml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Default insertion-content head: one nearest pending atom per spawning node.
2
+ mode: unimodal
3
+ dimension: 3
4
+ num_components: 1
5
+
6
+ model:
7
+ _target_: morph.model.layers.heads.UnimodalInsertionHead
8
+ hidden_dim: ${model.head_node_dim}
9
+ readout_dim: ${model.head_insertion_adapter_dim}
10
+ output_init_std: ${model.head_initialization.output_std}
11
+ independent_adapters: ${oc.select:model.head_independent_adapters,false}
12
+ N_a: ${len:${data.vocab.atom_tokens}}
13
+ N_c: ${len:${data.vocab.charge_tokens}}
geom/explicit_h/runtime/configs/integrator/integrator.yaml ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ integrator:
2
+ _target_: morph.flow_matching.integration.RateIntegrator
3
+ vocab: ${data.vocab}
4
+ distributions: None
5
+ insertion_head_mode: ${insertion_head.mode}
6
+ insertion_dimension: ${insertion_head.dimension}
7
+ insertion_num_components: ${insertion_head.num_components}
8
+ # strategy used for sampling time during **integration**
9
+ # NOTE can be different from the time strategy used for the model (see below)
10
+ time_strategy: log # "linear", "log", or "beta"
11
+ # shape params for time_strategy: beta (Beta inverse-CDF spacing).
12
+ # defaults match the model's beta_sched (concentration1=2.0, concentration0=1.0)
13
+ time_beta_alpha: 2.0
14
+ time_beta_beta: 1.0
15
+ num_integration_steps: 100
16
+ ins_noise_scale: ${data.ins_noise_scale}
17
+ # When true, freshly-inserted nodes are pushed to the t+dt marginal (kappa-mix
18
+ # on atom/bond types, (1-t)*ins_noise on x) to match training. Charge remains
19
+ # a clean prediction target rather than an interpolated state. When false,
20
+ # insertions enter at the model's clean prediction.
21
+ renoise_insertions: true
22
+ # Integrate the known categorical schedule hazard over every time interval
23
+ # instead of using its left-endpoint Euler approximation.
24
+ # With either method, the final interval always completes pending discrete
25
+ # transitions using the learned edit probabilities (no extra model call).
26
+ exact_schedule_integration: true
27
+ del_schedule: ${data.interpolator.del_schedule}
28
+ ins_schedule: ${data.interpolator.ins_schedule}
29
+ sub_schedule: ${data.interpolator.sub_schedule}
30
+ sub_e_schedule: ${data.interpolator.sub_e_schedule}
geom/explicit_h/runtime/configs/logging/wandb_logger.yaml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ ## Put your model args here
2
+ enabled: true
3
+ project: morph-${data.dataset_name}
4
+ name: ${oc.env:MORPH_RUN_ID,base}
5
+ save_dir: .
6
+ offline: false
geom/explicit_h/runtime/configs/loss_weights/calibrated_geom.yaml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # @package model.module.loss_weights
2
+ # Balance-only (geometric-mean=1) calibration weights, scaled down by a global
3
+ # factor of 0.2 (1/5). At the original geometric-mean=1 scale the realized
4
+ # full-model grad-norm was ~5, far above gradient_clip_val=1.0, so clipping
5
+ # fired on every step. The 0.2 factor brings the realized norm to ~1.0 so the
6
+ # clip becomes a spike safety-valve again. Re-running calibration now applies
7
+ # this scaling automatically (see trainer.target_total_grad_norm).
8
+ c: 0.164
9
+ do_del: 0.20
10
+ do_sub_a: 0.30
11
+ do_sub_e: 0.24
12
+ ins_e: 0.21
13
+ ins_e_ii: 0.22
14
+ ins_state: 0.14
15
+ ins_rate: 0.20
16
+ sub_a_class: 0.15
17
+ sub_e_class: 0.19
18
+ x: 0.22
geom/explicit_h/runtime/configs/loss_weights/calibrated_geom_frozen.yaml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # @package model.module.loss_weights
2
+ # Balance-only (geometric-mean = 1) loss weights — ratios only. The learning
3
+ # rate owns step size and gradient_clip_val stays a pure spike catch, so these
4
+ # are NOT scaled to a target grad-norm (unlike the older calibrated_geom.yaml,
5
+ # which baked in a ~0.2 global scale to hit the clip target).
6
+ #
7
+ # Source: frozen init-state calibration (trainer.calibrate_mode=loss,
8
+ # calibrate_freeze_model=true), geom / DiT / uncond,
9
+ # run 2026-06-07 (outputs/geom/uncond/cal_then_lr/2026-06-07_12-29-25/calibrate).
10
+ # Because the model is held at init, every probe batch is an unbiased snapshot of
11
+ # the initial per-term losses — so the three binary do_* losses come out equal
12
+ # (all BCE at p=0.5 = ln2), unlike the previous 2500-step *training* probe
13
+ # (calibrated_geom.yaml) which gave them different weights purely from differing
14
+ # training rates. See notebooks/lr_calibration_analysis.ipynb for the comparison.
15
+ c: 0.745146
16
+ do_del: 1.730107
17
+ do_sub_a: 1.730107
18
+ do_sub_e: 1.730106
19
+ ins_e: 0.867232
20
+ ins_e_ii: 0.867232
21
+ ins_state: 0.519379
22
+ ins_rate: 1.128104
23
+ sub_a_class: 0.522109
24
+ sub_e_class: 0.867232
25
+ x: 1.298792
geom/explicit_h/runtime/configs/loss_weights/tuned_weights.yaml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # @package model.module.loss_weights
2
+ # Canonical tuned weights for molecular training. Backbones can select this
3
+ # preset explicitly, and task-specific experiments may override the group. The
4
+ # package directive mounts the values under model.module.loss_weights.
5
+ do_sub_a: 0.2
6
+ sub_a_class: 0.03
7
+ do_sub_e: 0.25
8
+ sub_e_class: 0.5
9
+ do_del: 0.4
10
+ ins_rate: 0.15
11
+ ins_state: 0.01
12
+ ins_e: 0.4
13
+ x: 2.0 # was 1.0
14
+ c: 0.5
15
+ ins_e_ii: 0.03
geom/explicit_h/runtime/configs/loss_weights/uniform.yaml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # @package model.module.loss_weights
2
+ # Uniform 1.0 weight per loss component. The key set matches
3
+ # LightningModuleRates.LOSS_GROUPS exactly (the 11 actual loss terms
4
+ # emitted by shared_step).
5
+ do_sub_a: 1.0
6
+ sub_a_class: 1.0
7
+ do_sub_e: 1.0
8
+ sub_e_class: 1.0
9
+ do_del: 1.0
10
+ ins_rate: 1.0
11
+ ins_state: 1.0
12
+ ins_e: 1.0
13
+ ins_e_ii: 1.0
14
+ x: 1.0
15
+ c: 1.0
geom/explicit_h/runtime/configs/model/backbones/dit.yaml ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Molecular DiT: the repository's first-class generative backbone.
2
+ ##
3
+ ## This intentionally keeps charge out of the state and adds neither an
4
+ ## equivariant lane nor an evolving dense pair state. It retains the atom-count
5
+ ## condition: time plus current graph size disambiguates otherwise identical
6
+ ## local states and is especially useful while insertion/deletion is active.
7
+ defaults:
8
+ - /optimizer: muon_aux_adam
9
+ - /loss_weights: tuned_weights
10
+ - _self_
11
+
12
+ rotate: true
13
+ n_augmentations: 1
14
+
15
+ integrator: ${integrator.integrator}
16
+
17
+ beta_sched:
18
+ _target_: torch.distributions.Beta
19
+ concentration1: 2.0
20
+ concentration0: 1.0
21
+
22
+ linear_sched:
23
+ _target_: torch.distributions.Uniform
24
+ low: 0.0
25
+ high: 1.0
26
+
27
+ sample_time_strategy: linear
28
+
29
+ module:
30
+ _target_: morph.model.lightning.base.LightningModuleRates
31
+ insertion_head_mode: ${insertion_head.mode}
32
+ ins_noise_scale: ${data.ins_noise_scale}
33
+ ema_decay: 0.999
34
+ ema_warmup_steps: 5000
35
+ use_ema_for_eval: true
36
+ time_dist: ${if:${eq:${model.sample_time_strategy}, log}, ${model.beta_sched}, ${model.linear_sched}}
37
+ integrator: ${model.integrator}
38
+ vocab: ${data.vocab}
39
+ use_learnable_loss_weights: false
40
+ use_time_weights: false
41
+
42
+ model:
43
+ _target_: morph.model.backbones.dit.DiTBackboneWithHeads
44
+ _recursive_: false
45
+
46
+ atom_type_embedding_args: ${embeddings.atom_type_embedding}
47
+ edge_type_embedding_args: ${embeddings.edge_type_embedding}
48
+ time_embedding_args: ${embeddings.time_embedding}
49
+ node_count_embedding_args: ${embeddings.node_count_embedding}
50
+ # Sum the existing incident edge embeddings into each atom's input, excluding
51
+ # NO_BOND, through a zero-initialized projection. Uses the existing heads.
52
+ incident_bond_embedding: false
53
+ backbone_model_args: ${model.backbone}
54
+ heads_args: ${heads.heads}
55
+ insertion_head_args: ${insertion_head.model}
56
+ ins_edge_head_args: ${heads.ins_edge_head}
57
+
58
+ head_node_dim: ${model.backbone.out_node_nf}
59
+ head_edge_dim: ${model.backbone.out_edge_nf}
60
+
61
+ # Shared adapters avoid seven separate full-width MLPs. At the >150M preset,
62
+ # node/insertion adapters widen while pair readouts remain compact.
63
+ head_node_adapter_dim: 256
64
+ head_edge_adapter_dim: 256
65
+ head_insertion_adapter_dim: 256
66
+ head_insertion_edge_dim: 256
67
+ head_independent_adapters: true
68
+
69
+ # Categorical biases are replaced at module construction with exact dataset
70
+ # marginals. There is no dataset-level transition-frequency statistic for the
71
+ # binary/rate heads, so their defaults deliberately preserve the old neutral
72
+ # predictions instead of inventing a corpus-independent edit prior.
73
+ head_initialization:
74
+ output_std: 1.0e-3
75
+ coordinate_output_std: 0.0
76
+ do_del_probability: 0.5
77
+ do_sub_a_probability: 0.5
78
+ do_sub_e_probability: 0.5
79
+ ins_rate: 0.6931471805599453
80
+
81
+ token_weighting:
82
+ type_loss_token_weights: uniform
83
+ weight_alpha: 0.4
84
+
85
+ # Optional low-rank adaptation of the attention and SwiGLU projections. The
86
+ # adapter residual is zero at initialization, so enabling this while loading a
87
+ # pretrained checkpoint preserves its outputs exactly.
88
+ lora:
89
+ enabled: false
90
+ rank: 8
91
+ alpha: 8.0
92
+ dropout: 0.0
93
+ targets: [qkv, proj, mlp.gate_value, mlp.out_proj]
94
+ freeze_base: true
95
+
96
+ backbone:
97
+ _target_: morph.model.backbones.dit.DiTBackbone
98
+ _recursive_: false
99
+ d_input: ${embeddings.atom_type_embedding.out_dim}
100
+ d_cond: ${oc.eval:"${embeddings.time_embedding.out_dim} + ${embeddings.node_count_embedding.out_dim}"}
101
+ d_model: 512
102
+ out_node_nf: 256
103
+ out_edge_nf: 256
104
+ num_layers: 8
105
+ nhead: 16
106
+ mlp_ratio: 4.0
107
+ ffn_hidden_dim: null
108
+ ffn_multiple_of: 64
109
+ qk_norm: true
110
+ coordinate_output_init_std: ${model.head_initialization.coordinate_output_std}
111
+ center_coordinate_output: true
112
+ in_edge_nf: ${embeddings.edge_type_embedding.out_dim}
113
+ edge_pair_dim: 256
114
+ pair_bias_hidden_dim: 32
115
+ num_atom_types: ${len:${data.vocab.atom_tokens}}
116
+ lora: ${model.lora}
117
+ rbf_embedding_args:
118
+ _target_: morph.model.layers.embedding.RBFEmbedding
119
+ num_rbf: 128
120
+ rbf_dmax: 3.5
121
+ out_dim: 64
122
+ dropout: 0.0
123
+ trainable: false
geom/explicit_h/runtime/configs/model/finetune/lora_finetune.yaml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Parameter-efficient fine-tuning of the unconditional DiT.
2
+ defaults:
3
+ - /model/backbones/dit@_here_
4
+ - _self_
5
+
6
+ lora:
7
+ enabled: true
8
+
9
+ module:
10
+ _target_: morph.model.finetune.base.LightningModuleRatesFinetune
11
+ pretrained_ckpt: ${oc.env:MORPH_PRETRAINED_CKPT}
12
+ pretrained_prefer_ema: true
13
+ freeze_pretrained_backbone: true
geom/explicit_h/runtime/configs/model/finetune/scaffold_finetune.yaml ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # DiT backbone augmented with Flamingo-style gated cross-attention for
2
+ # scaffold-decoration fine-tuning.
3
+ #
4
+ # Conditioning (all derived from mol_t.keep_mask):
5
+ # - node_cond : per-atom scaffold membership (always on)
6
+ # - edge_cond : per-edge scaffold class (always on)
7
+ # - cross-attn: scaffold subgraph encoded by a shared LightweightContextEncoder
8
+ # (OPTIONAL — toggle via backbone.use_cross_attn):
9
+ # * false → option 1: node+edge only
10
+ # * true → option 2: node+edge+cross-attn
11
+ #
12
+ # Inherits everything from configs/model/backbones/dit.yaml and overrides:
13
+ # - module._target_ → LightningModuleRatesScaffoldFinetune (loads a pretrained
14
+ # unconditional DiT checkpoint and adds scaffold loss/inference masking)
15
+ # - model._target_ → ScaffoldConditionalDiTBackboneWithHeads (auto-builds the
16
+ # node/edge cond and, when use_cross_attn, the scaffold cross-attn tokens)
17
+ # - backbone._target_ → ConditionalDiTBackbone (DiT + gated cross-attn blocks)
18
+ #
19
+ # Provides a ``pretrained_ckpt`` field for the lightning module to load.
20
+ defaults:
21
+ - /model/backbones/dit@_here_
22
+ - _self_
23
+
24
+ module:
25
+ _target_: morph.model.finetune.scaffold.LightningModuleRatesScaffoldFinetune
26
+ # Path to the unconditional DiT checkpoint to load weights from.
27
+ # ConditionalDiT keys are auto-retargeted (backbone.* → backbone.dit.*).
28
+ pretrained_ckpt: ${oc.env:MORPH_PRETRAINED_CKPT}
29
+ pretrained_prefer_ema: true
30
+ # If true, dispatches to ``self.model.freeze_pretrained()`` — for the
31
+ # cross-attn scaffold model this freezes the entire clean lane
32
+ # (embedding, ``backbone.dit``, all heads). Only the gated cross-attn
33
+ # blocks and edge gate plus the scaffold encoder train.
34
+ freeze_pretrained_backbone: true
35
+ optimizer_config:
36
+ optimizer:
37
+ lr: 1e-3
38
+ aux_optimizer:
39
+ lr: 1e-4
40
+ # Whether to exclude scaffold atoms from sub / x losses. These atoms are
41
+ # frozen at inference, so training them adds no useful signal.
42
+ exclude_scaffold_from_sub_loss: true
43
+ exclude_scaffold_from_x_loss: true
44
+ # Pin kept coordinates during integration and restore the input coordinate
45
+ # frame on output. To train flowing scaffold geometry, set this and the x-loss
46
+ # exclusion above to false.
47
+ freeze_keep_positions: true
48
+
49
+ # Override the model target to the scaffold-aware cross-attn wrapper.
50
+ model:
51
+ _target_: morph.model.finetune.scaffold.ScaffoldConditionalDiTBackboneWithHeads
52
+ _recursive_: false
53
+
54
+ atom_type_embedding_args: ${embeddings.atom_type_embedding}
55
+ edge_type_embedding_args: ${embeddings.edge_type_embedding}
56
+ time_embedding_args: ${embeddings.time_embedding}
57
+ node_count_embedding_args: ${embeddings.node_count_embedding}
58
+
59
+ backbone_model_args: ${model.backbone}
60
+
61
+ heads_args: ${heads.heads}
62
+ insertion_head_args: ${insertion_head.model}
63
+ ins_edge_head_args: ${heads.ins_edge_head}
64
+
65
+ # Cross-attention context encoder (option 2). Required because the backbone
66
+ # below has use_cross_attn: true. For option 1 (node+edge only), set
67
+ # backbone.use_cross_attn=false AND null this (the two must agree).
68
+ xattn_encoder_args: ${model.xattn_encoder}
69
+ # Geometric correspondence prior (query atom ↔ co-located scaffold token).
70
+ use_distance_bias: true
71
+
72
+ # Cross-attention context encoder (option 2): encodes the scaffold subgraph of
73
+ # mol_t (extracted via filter_nodes) into context tokens. ctx_dim must match
74
+ # model.backbone.ctx_dim.
75
+ # Node/edge conditioning is NOT configured here — the wrapper builds those directly
76
+ # from backbone.d_model / backbone.in_edge_nf. Null this (and set
77
+ # backbone.use_cross_attn=false) for node+edge-only scaffold conditioning.
78
+ xattn_encoder:
79
+ _target_: morph.model.finetune.base.LightweightContextEncoder
80
+ num_atom_types: ${len:${data.vocab.atom_tokens}}
81
+ num_charges: ${len:${data.vocab.charge_tokens}}
82
+ atom_embed_dim: 64
83
+ charge_embed_dim: 16
84
+ pos_embed_dim: 32
85
+ ctx_dim: ${model.backbone.ctx_dim}
86
+ num_attn_layers: 4
87
+ nhead: 8
88
+ mlp_ratio: 4.0
89
+ dropout: 0.0
90
+ # Edge-based pair bias on the encoder's self-attention (RBF distance +
91
+ # edge-type of the scaffold's own bonds) so tokens mix with geometry/topology
92
+ # awareness, like the DiT backbone. num_edge_types/edge_embed_dim only used here.
93
+ use_pair_bias: true
94
+ num_edge_types: ${len:${data.vocab.edge_tokens}}
95
+ edge_embed_dim: 32
96
+ num_rbf: 32
97
+ rbf_dmax: 5.0
98
+ pair_bias_hidden_dim: 32
99
+
100
+ # Override the backbone to use ConditionalDiTBackbone.
101
+ backbone:
102
+ _target_: morph.model.backbones.conditional_dit.ConditionalDiTBackbone
103
+ _recursive_: false
104
+ d_input: ${embeddings.atom_type_embedding.out_dim}
105
+ d_cond: ${oc.eval:"${embeddings.time_embedding.out_dim} + ${embeddings.node_count_embedding.out_dim}"}
106
+ d_model: 512
107
+ out_node_nf: 256
108
+ out_edge_nf: 256
109
+ num_layers: 8
110
+ nhead: 16
111
+ mlp_ratio: 4.0
112
+ ffn_hidden_dim: null
113
+ ffn_multiple_of: 64
114
+ qk_norm: true
115
+ coordinate_output_init_std: ${model.head_initialization.coordinate_output_std}
116
+ center_coordinate_output: true
117
+ in_edge_nf: ${embeddings.edge_type_embedding.out_dim}
118
+ edge_pair_dim: 256
119
+ pair_bias_hidden_dim: 32
120
+ num_atom_types: ${len:${data.vocab.atom_tokens}}
121
+ lora: ${model.lora}
122
+ ctx_dim: 128
123
+ use_cross_attn: true # cross-attention (cond_tokens) port
124
+ # Per-node conditioning: scaffold membership (which atoms to keep).
125
+ use_node_cond: true
126
+ # Per-edge conditioning: the scaffold encoder emits edge_cond at in_edge_nf.
127
+ use_edge_cond: true
128
+ rbf_embedding_args:
129
+ _target_: morph.model.layers.embedding.RBFEmbedding
130
+ num_rbf: 128
131
+ rbf_dmax: 3.5
132
+ out_dim: 64
133
+ dropout: 0.0
134
+ trainable: false
geom/explicit_h/runtime/configs/optimizer/muon_aux_adam.yaml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # @package model.module.optimizer_config
2
+ # Muon + auxiliary AdamW preset for the molecular DiT. Per-run overrides
3
+ # go on ``model.module.optimizer_config``:
4
+ # model.module.optimizer_config.optimizer.lr=0.005 ...
5
+ implementation: torch
6
+
7
+ optimizer:
8
+ # no _target_ -> triggers Muon path in configure_optimizers
9
+ # The RTX 4090 Euler template selects native-arithmetic CUDA graph replay.
10
+ execution: ${oc.env:MORPH_MUON_EXECUTION,native}
11
+ lr: 0.01
12
+ momentum: 0.95
13
+ weight_decay: 0.0
14
+ nesterov: true
15
+ ns_steps: 5
16
+ eps: 1e-7
17
+ adjust_lr_fn: original
18
+
19
+ aux_optimizer:
20
+ lr: 3e-4
21
+ betas: [0.9, 0.95]
22
+ eps: 1e-10
23
+ weight_decay: 0.0
24
+
25
+ # Lightning's two-optimizer path uses manual optimization, so clipping is
26
+ # configured here and applied once to the full model gradient.
27
+ gradient_clip_val: 1.0
28
+ gradient_clip_algorithm: norm
29
+
30
+ scheduler:
31
+ _target_: morph.utils.lr_schedulers.MultiGroupCosineWarmupLR
32
+ # configure_optimizers injects each native optimizer here.
33
+ warmup_steps: 2000 # Typically 2-5% of total_steps
34
+ total_steps: 200000 # The total number of training iterations
35
+ min_lr_fraction: 0.05 # Decays to 5% of each optimizer's peak LR
36
+ last_epoch: -1
37
+
38
+ interval: step
39
+ monitor: null
geom/explicit_h/runtime/configs/resume_geom.yaml ADDED
@@ -0,0 +1,417 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ representation: molecule
2
+ seed: 42
3
+ heads:
4
+ heads:
5
+ _target_: morph.model.layers.heads.MultiHeadModule
6
+ output_init_std: ${model.head_initialization.output_std}
7
+ independent_adapters: ${oc.select:model.head_independent_adapters,false}
8
+ heads_configs:
9
+ graph_aggregation: mean
10
+ node_heads:
11
+ atom_type_head:
12
+ input_dim: ${model.head_node_dim}
13
+ output_dim: ${len:${data.vocab.atom_tokens}}
14
+ adapter_dim: ${model.head_node_adapter_dim}
15
+ group: state
16
+ charge_head:
17
+ input_dim: ${model.head_node_dim}
18
+ output_dim: ${len:${data.vocab.charge_tokens}}
19
+ adapter_dim: ${model.head_node_adapter_dim}
20
+ group: state
21
+ ins_rate_head:
22
+ input_dim: ${model.head_node_dim}
23
+ output_dim: 1
24
+ adapter_dim: ${model.head_node_adapter_dim}
25
+ group: edit
26
+ initial_rate: ${model.head_initialization.ins_rate}
27
+ do_del_head:
28
+ input_dim: ${model.head_node_dim}
29
+ output_dim: 1
30
+ adapter_dim: ${model.head_node_adapter_dim}
31
+ group: edit
32
+ initial_probability: ${model.head_initialization.do_del_probability}
33
+ do_sub_a_head:
34
+ input_dim: ${model.head_node_dim}
35
+ output_dim: 1
36
+ adapter_dim: ${model.head_node_adapter_dim}
37
+ group: edit
38
+ initial_probability: ${model.head_initialization.do_sub_a_probability}
39
+ edge_heads:
40
+ edge_type_head:
41
+ input_dim: ${model.head_edge_dim}
42
+ output_dim: ${len:${data.vocab.edge_tokens}}
43
+ adapter_dim: ${model.head_edge_adapter_dim}
44
+ group: state
45
+ do_sub_e_head:
46
+ input_dim: ${model.head_edge_dim}
47
+ output_dim: 1
48
+ adapter_dim: ${model.head_edge_adapter_dim}
49
+ group: state
50
+ initial_probability: ${model.head_initialization.do_sub_e_probability}
51
+ ins_edge_head:
52
+ _target_: morph.model.layers.heads.InsertionEdgeHead
53
+ _recursive_: false
54
+ hidden_dim: ${model.head_node_dim}
55
+ readout_dim: ${model.head_insertion_edge_dim}
56
+ output_init_std: ${model.head_initialization.output_std}
57
+ n_edge_types: ${len:${data.vocab.edge_tokens}}
58
+ n_atom_types: ${len:${data.vocab.atom_tokens}}
59
+ n_charge_types: ${len:${data.vocab.charge_tokens}}
60
+ rbf_embedding_args:
61
+ _target_: morph.model.layers.embedding.RBFEmbedding
62
+ num_rbf: 128
63
+ rbf_dmax: 3.5
64
+ out_dim: 64
65
+ dropout: 0.0
66
+ trainable: false
67
+ insertion_head:
68
+ mode: unimodal
69
+ dimension: 3
70
+ num_components: 1
71
+ model:
72
+ _target_: morph.model.layers.heads.UnimodalInsertionHead
73
+ hidden_dim: ${model.head_node_dim}
74
+ readout_dim: ${model.head_insertion_adapter_dim}
75
+ output_init_std: ${model.head_initialization.output_std}
76
+ independent_adapters: ${oc.select:model.head_independent_adapters,false}
77
+ N_a: ${len:${data.vocab.atom_tokens}}
78
+ N_c: ${len:${data.vocab.charge_tokens}}
79
+ model:
80
+ module:
81
+ optimizer_config:
82
+ implementation: torch
83
+ optimizer:
84
+ execution: ${oc.env:MORPH_MUON_EXECUTION,native}
85
+ lr: 0.01
86
+ momentum: 0.95
87
+ weight_decay: 0.0
88
+ nesterov: true
89
+ ns_steps: 5
90
+ eps: 1.0e-07
91
+ adjust_lr_fn: original
92
+ aux_optimizer:
93
+ lr: 0.0003
94
+ betas:
95
+ - 0.9
96
+ - 0.95
97
+ eps: 1.0e-10
98
+ weight_decay: 0.0
99
+ gradient_clip_val: 1.0
100
+ gradient_clip_algorithm: norm
101
+ scheduler:
102
+ _target_: morph.utils.lr_schedulers.MultiGroupCosineWarmupLR
103
+ warmup_steps: 2000
104
+ total_steps: 200000
105
+ min_lr_fraction: 0.05
106
+ last_epoch: -1
107
+ interval: step
108
+ monitor: null
109
+ loss_weights:
110
+ do_sub_a: 0.2
111
+ sub_a_class: 0.03
112
+ do_sub_e: 0.25
113
+ sub_e_class: 0.5
114
+ do_del: 0.4
115
+ ins_rate: 0.15
116
+ ins_state: 0.01
117
+ ins_e: 0.4
118
+ x: 2.0
119
+ c: 0.5
120
+ ins_e_ii: 0.03
121
+ _target_: morph.model.lightning.base.LightningModuleRates
122
+ insertion_head_mode: ${insertion_head.mode}
123
+ ins_noise_scale: ${data.ins_noise_scale}
124
+ ema_decay: 0.999
125
+ ema_warmup_steps: 5000
126
+ use_ema_for_eval: true
127
+ time_dist: ${if:${eq:${model.sample_time_strategy}, log}, ${model.beta_sched},
128
+ ${model.linear_sched}}
129
+ integrator: ${model.integrator}
130
+ vocab: ${data.vocab}
131
+ use_learnable_loss_weights: false
132
+ use_time_weights: false
133
+ model:
134
+ _target_: morph.model.backbones.dit.DiTBackboneWithHeads
135
+ _recursive_: false
136
+ atom_type_embedding_args: ${embeddings.atom_type_embedding}
137
+ edge_type_embedding_args: ${embeddings.edge_type_embedding}
138
+ time_embedding_args: ${embeddings.time_embedding}
139
+ node_count_embedding_args: ${embeddings.node_count_embedding}
140
+ incident_bond_embedding: false
141
+ backbone_model_args: ${model.backbone}
142
+ heads_args: ${heads.heads}
143
+ insertion_head_args: ${insertion_head.model}
144
+ ins_edge_head_args: ${heads.ins_edge_head}
145
+ rotate: true
146
+ n_augmentations: 1
147
+ integrator: ${integrator.integrator}
148
+ beta_sched:
149
+ _target_: torch.distributions.Beta
150
+ concentration1: 2.0
151
+ concentration0: 1.0
152
+ linear_sched:
153
+ _target_: torch.distributions.Uniform
154
+ low: 0.0
155
+ high: 1.0
156
+ sample_time_strategy: linear
157
+ head_node_dim: ${model.backbone.out_node_nf}
158
+ head_edge_dim: ${model.backbone.out_edge_nf}
159
+ head_node_adapter_dim: 256
160
+ head_edge_adapter_dim: 256
161
+ head_insertion_adapter_dim: 256
162
+ head_insertion_edge_dim: 256
163
+ head_independent_adapters: true
164
+ head_initialization:
165
+ output_std: 0.001
166
+ coordinate_output_std: 0.0
167
+ do_del_probability: 0.5
168
+ do_sub_a_probability: 0.5
169
+ do_sub_e_probability: 0.5
170
+ ins_rate: 0.6931471805599453
171
+ token_weighting:
172
+ type_loss_token_weights: uniform
173
+ weight_alpha: 0.4
174
+ lora:
175
+ enabled: false
176
+ rank: 8
177
+ alpha: 8.0
178
+ dropout: 0.0
179
+ targets:
180
+ - qkv
181
+ - proj
182
+ - mlp.gate_value
183
+ - mlp.out_proj
184
+ freeze_base: true
185
+ backbone:
186
+ _target_: morph.model.backbones.dit.DiTBackbone
187
+ _recursive_: false
188
+ d_input: ${embeddings.atom_type_embedding.out_dim}
189
+ d_cond: ${oc.eval:"${embeddings.time_embedding.out_dim} + ${embeddings.node_count_embedding.out_dim}"}
190
+ d_model: 512
191
+ out_node_nf: 256
192
+ out_edge_nf: 256
193
+ num_layers: 8
194
+ nhead: 16
195
+ mlp_ratio: 4.0
196
+ ffn_hidden_dim: null
197
+ ffn_multiple_of: 64
198
+ qk_norm: true
199
+ coordinate_output_init_std: ${model.head_initialization.coordinate_output_std}
200
+ center_coordinate_output: true
201
+ in_edge_nf: ${embeddings.edge_type_embedding.out_dim}
202
+ edge_pair_dim: 256
203
+ pair_bias_hidden_dim: 32
204
+ num_atom_types: ${len:${data.vocab.atom_tokens}}
205
+ lora: ${model.lora}
206
+ rbf_embedding_args:
207
+ _target_: morph.model.layers.embedding.RBFEmbedding
208
+ num_rbf: 128
209
+ rbf_dmax: 3.5
210
+ out_dim: 64
211
+ dropout: 0.0
212
+ trainable: false
213
+ schedule:
214
+ _target_: morph.flow_matching.schedules.SmoothstepSchedule
215
+ shift: 0.8
216
+ trainer:
217
+ trainer:
218
+ deterministic: warn
219
+ devices: 2
220
+ accelerator: auto
221
+ strategy: ddp_find_unused_parameters_false
222
+ precision: bf16-mixed
223
+ max_epochs: -1
224
+ accumulate_grad_batches: 1
225
+ num_sanity_val_steps: 0
226
+ gradient_clip_val: null
227
+ gradient_clip_algorithm: norm
228
+ check_val_every_n_epoch: 1
229
+ num_val_samples: 4096
230
+ limit_val_batches: null
231
+ limit_predict_batches: 4
232
+ max_time:
233
+ hours: 47
234
+ minutes: 15
235
+ do_train: true
236
+ do_validate: false
237
+ do_predict: false
238
+ checkpoint_path: /cluster/project/krause/frankem/morph-chem/outputs/geom_resume_e48_20261008/resume_epoch_048.ckpt
239
+ final_checkpoint_path: final.ckpt
240
+ callbacks:
241
+ monitor_metric: ${if:${oc.eval:"'${representation}' in ('geometric_graph', 'molecule')"},val/validity,val/batch/pair_dist_l1}
242
+ monitor_metric_mode: ${if:${oc.eval:"'${representation}' in ('geometric_graph',
243
+ 'molecule')"},max,min}
244
+ model_checkpoints:
245
+ save_top_k: 1
246
+ save_last: false
247
+ verbose: false
248
+ every_n_epochs: 5
249
+ every_n_epochs_checkpoint:
250
+ every_n_epochs: 5
251
+ save_top_k: -1
252
+ save_last: link
253
+ verbose: false
254
+ save_on_train_epoch_end: true
255
+ logging:
256
+ enabled: true
257
+ project: morph-${data.dataset_name}
258
+ name: ${oc.env:MORPH_RUN_ID}
259
+ save_dir: .
260
+ offline: false
261
+ integrator:
262
+ integrator:
263
+ _target_: morph.flow_matching.integration.RateIntegrator
264
+ vocab: ${data.vocab}
265
+ distributions: None
266
+ insertion_head_mode: ${insertion_head.mode}
267
+ insertion_dimension: ${insertion_head.dimension}
268
+ insertion_num_components: ${insertion_head.num_components}
269
+ time_strategy: log
270
+ time_beta_alpha: 2.0
271
+ time_beta_beta: 1.0
272
+ num_integration_steps: 100
273
+ ins_noise_scale: ${data.ins_noise_scale}
274
+ renoise_insertions: true
275
+ exact_schedule_integration: true
276
+ del_schedule: ${data.interpolator.del_schedule}
277
+ ins_schedule: ${data.interpolator.ins_schedule}
278
+ sub_schedule: ${data.interpolator.sub_schedule}
279
+ sub_e_schedule: ${data.interpolator.sub_e_schedule}
280
+ data:
281
+ root_path: /cluster/project/krause/frankem/morph-chem/data
282
+ preprocess_workers: 10
283
+ preprocess_chunk_size: 128
284
+ statistics_workers: ${data.preprocess_workers}
285
+ hydrogen_mode: explicit
286
+ cache_name: ${data.dataset_name}${if:${eq:${data.hydrogen_mode},implicit},_implicit_h,''}
287
+ source_dir: ${oc.env:GEOM_SOURCE_DIR,null}
288
+ max_atoms: 72
289
+ allowed_atom_symbols:
290
+ - H
291
+ - C
292
+ - 'N'
293
+ - O
294
+ - S
295
+ - F
296
+ - Cl
297
+ - Br
298
+ - P
299
+ - I
300
+ n_atoms_strategy: uniform
301
+ uniform_n_atoms_padding: 5
302
+ optimal_transport: equivariant
303
+ ins_noise_scale: 0.65
304
+ move_noise_scale: 0.5
305
+ allow_charged: true
306
+ preprocessing:
307
+ _target_: morph.dataset.core.preprocessing.Preprocessing
308
+ _recursive_: false
309
+ root: /cluster/project/krause/frankem/morph/data/geom
310
+ num_workers: ${data.statistics_workers}
311
+ train_dataset: ${data.datamodule.datasets.train}
312
+ atom_tokens_path: ${data.preprocessing.root}/processed/atom_tokens.txt
313
+ edge_tokens_path: ${data.preprocessing.root}/processed/edge_tokens.txt
314
+ charge_tokens_path: ${data.preprocessing.root}/processed/charge_tokens.txt
315
+ distributions_path: ${data.preprocessing.root}/processed/distributions.pt
316
+ vocab: null
317
+ interpolator:
318
+ _target_: morph.flow_matching.interpolation.Interpolator
319
+ distributions: null
320
+ optimal_transport: ${data.optimal_transport}
321
+ ins_noise_scale: ${data.ins_noise_scale}
322
+ move_noise_scale: ${data.move_noise_scale}
323
+ atom_type_noise_prob: 0.0
324
+ pre_align_iters: 2
325
+ c_move: 1.0
326
+ c_sub: 0.0
327
+ c_ins: 6.125
328
+ c_del: 6.125
329
+ del_schedule: ${schedule}
330
+ ins_schedule: ${schedule}
331
+ sub_schedule:
332
+ _target_: morph.flow_matching.schedules.SmoothstepSchedule
333
+ shift: 1.5
334
+ sub_e_schedule:
335
+ _target_: morph.flow_matching.schedules.SmoothstepSchedule
336
+ shift: 1.5
337
+ datamodule:
338
+ _target_: morph.dataset.core.lightning_datamodule.LightningDataModule
339
+ vocab: ${data.vocab}
340
+ distributions: null
341
+ representation: ${representation}
342
+ datasets:
343
+ train:
344
+ _target_: ${data.dataset_target}
345
+ root: ${data.preprocessing.root}
346
+ preprocess_workers: ${data.preprocess_workers}
347
+ preprocess_chunk_size: ${data.preprocess_chunk_size}
348
+ hydrogen_mode: ${data.hydrogen_mode}
349
+ source_dir: ${data.source_dir}
350
+ max_atoms: ${data.max_atoms}
351
+ allowed_atom_symbols: ${data.allowed_atom_symbols}
352
+ vocab: ${data.vocab}
353
+ distributions: null
354
+ val:
355
+ - _target_: ${data.dataset_target}
356
+ root: ${data.preprocessing.root}
357
+ preprocess_workers: ${data.preprocess_workers}
358
+ preprocess_chunk_size: ${data.preprocess_chunk_size}
359
+ hydrogen_mode: ${data.hydrogen_mode}
360
+ source_dir: ${data.source_dir}
361
+ max_atoms: ${data.max_atoms}
362
+ allowed_atom_symbols: ${data.allowed_atom_symbols}
363
+ vocab: ${data.vocab}
364
+ distributions: null
365
+ test:
366
+ - _target_: ${data.dataset_target}
367
+ root: ${data.preprocessing.root}
368
+ preprocess_workers: ${data.preprocess_workers}
369
+ preprocess_chunk_size: ${data.preprocess_chunk_size}
370
+ hydrogen_mode: ${data.hydrogen_mode}
371
+ source_dir: ${data.source_dir}
372
+ max_atoms: ${data.max_atoms}
373
+ allowed_atom_symbols: ${data.allowed_atom_symbols}
374
+ vocab: ${data.vocab}
375
+ distributions: null
376
+ interpolator: ${data.interpolator}
377
+ rotate: ${model.rotate}
378
+ n_augmentations: ${model.n_augmentations}
379
+ num_workers:
380
+ train: 20
381
+ val: 0
382
+ test: 0
383
+ batch_size:
384
+ train: 320
385
+ val: 32
386
+ test: 32
387
+ n_atoms_strategy: ${data.n_atoms_strategy}
388
+ uniform_n_atoms_padding: ${data.uniform_n_atoms_padding}
389
+ time_dist: ${model.module.time_dist}
390
+ train_prefetch_factor: 1
391
+ dataset_name: geom
392
+ dataset_target: morph.dataset.unconditional.geom.FlowMatchingGEOMDataset
393
+ embeddings:
394
+ atom_type_embedding:
395
+ _target_: morph.model.layers.embedding.Embedding
396
+ num_embeddings: ${len:${data.vocab.atom_tokens}}
397
+ embedding_dim: 64
398
+ out_dim: 128
399
+ edge_type_embedding:
400
+ _target_: morph.model.layers.embedding.Embedding
401
+ num_embeddings: ${len:${data.vocab.edge_tokens}}
402
+ embedding_dim: 64
403
+ out_dim: 128
404
+ time_embedding:
405
+ _target_: morph.model.layers.embedding.TimeEmbedding
406
+ embedding_dim: 128
407
+ out_dim: 128
408
+ node_count_embedding:
409
+ _target_: morph.model.layers.embedding.ExtrapolatableCountEmbedding
410
+ embedding_dim: 64
411
+ out_dim: 128
412
+ min_period: 128.0
413
+ max_period: 1024.0
414
+ max_count: 96.0
415
+ hydra:
416
+ run:
417
+ dir: ${oc.env:MORPH_RUN_ROOT}/geom/geom/${now:%Y-%m-%d}/${oc.env:MORPH_RUN_ID}
geom/explicit_h/runtime/configs/schedule/beta.yaml ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ _target_: morph.flow_matching.schedules.BetaSchedule
2
+ k_alpha: 1.0
3
+ k_beta: 1.5
geom/explicit_h/runtime/configs/schedule/cubic.yaml ADDED
@@ -0,0 +1 @@
 
 
1
+ _target_: morph.flow_matching.schedules.CubicSchedule