Pin exact evaluated starting checkpoint, objective equivalence tests, source and joint training protocol
Browse files- preparation_complete.json +31 -0
- prepared_data_hub.json +6 -0
- smoke_validation.json +83 -0
- source/multitask_data.py +66 -9
- source/multitask_evaluate.py +1 -1
- source/multitask_train.py +13 -7
- source_hashes.json +3 -3
preparation_complete.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"completed": true,
|
| 3 |
+
"time": 1793210639.778262,
|
| 4 |
+
"initialization": {
|
| 5 |
+
"initial_checkpoint_repository": "Queimo/rem3di-pcqm-epoch2-cosmo",
|
| 6 |
+
"initial_checkpoint_path": "epoch_10",
|
| 7 |
+
"initial_checkpoint_revision": "9266a41fbe3b36afe0615e0c3ba232ca74bdeef7",
|
| 8 |
+
"initial_hashes": {
|
| 9 |
+
"encoder.pth": "97e616a16e8317717784929495ba3a030bfcd821038be6e05324624b17c409c0",
|
| 10 |
+
"atomic_preprocessor.pth": "9683883267a902773b4f6777eedb366befd016f4f7083bed62a1bd35ae113e3d",
|
| 11 |
+
"geometric_preprocessor.pth": "4da0843646d06fcd2ff5b13e1fd4fb4b22c8c0456d0507c59df01e665c4d6d7b",
|
| 12 |
+
"cosmo_head.pth": "1a43270e60f00c9428099e0e37ab62f77a2c219ea611d4f05194bc1abf69b0a7"
|
| 13 |
+
},
|
| 14 |
+
"frozen_foundation_sha256": "fab8b8713c832f31a2a853aaa22fd638be8a369cbf5095e6b3e982a18d10e93a",
|
| 15 |
+
"verified_against_bigsoldb_protocol": true,
|
| 16 |
+
"bigsoldb_protocol_sha256": "dcd893dc297eef5d50b225367f295cdded69a6a9cd9b53c8f8f63c241f7e371b",
|
| 17 |
+
"denoising_decoder": {
|
| 18 |
+
"repository": "Queimo/rem3di-pcqm500k-corrected",
|
| 19 |
+
"revision": "2f5c3b40b36259a13adc8412689254054bb93288",
|
| 20 |
+
"path": "runs/corrected_20261027/evaluation/paper_audit/author_pcqm500k_5ep/epoch_02/decoder.pth",
|
| 21 |
+
"sha256": "bffdd09bae9bcb2d863165546dea090a10be06d8a52b89e4f651e0f1c80ae7c4"
|
| 22 |
+
},
|
| 23 |
+
"explanation": "All encoder, atomic/geometric preprocessor and COSMO head weights come from the exact evaluated COSMO10 checkpoint. Only its omitted denoising decoder is restored from PCQM epoch2."
|
| 24 |
+
},
|
| 25 |
+
"data": {
|
| 26 |
+
"repository": "Queimo/combisolv-qm-rem3di-multitask",
|
| 27 |
+
"revision": "de87254deae3bbdc031e3c2185df7c3ad63945ac",
|
| 28 |
+
"verified": true,
|
| 29 |
+
"files": 23
|
| 30 |
+
}
|
| 31 |
+
}
|
prepared_data_hub.json
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"repository": "Queimo/combisolv-qm-rem3di-multitask",
|
| 3 |
+
"revision": "de87254deae3bbdc031e3c2185df7c3ad63945ac",
|
| 4 |
+
"verified": true,
|
| 5 |
+
"files": 23
|
| 6 |
+
}
|
smoke_validation.json
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"passed": true,
|
| 3 |
+
"all_head_gradients": {
|
| 4 |
+
"encoder.pth": true,
|
| 5 |
+
"atomic_preprocessor.pth": true,
|
| 6 |
+
"geometric_preprocessor.pth": true,
|
| 7 |
+
"cosmo_head.pth": true,
|
| 8 |
+
"denoising_decoder.pth": true,
|
| 9 |
+
"combisolv_head.pth": true
|
| 10 |
+
},
|
| 11 |
+
"encoder_updated": true,
|
| 12 |
+
"task_weights_updated": true,
|
| 13 |
+
"optimizer_and_rng_resume_next_step_exact": true,
|
| 14 |
+
"normalization_buffers_unchanged": true,
|
| 15 |
+
"initial_bigsoldb_embedding_match": {
|
| 16 |
+
"molecules": 1334,
|
| 17 |
+
"max_absolute": 4.184246063232422e-05,
|
| 18 |
+
"mean_absolute": 1.621990719513633e-07
|
| 19 |
+
},
|
| 20 |
+
"real_batch_loss": {
|
| 21 |
+
"denoising": 0.0400693416595459,
|
| 22 |
+
"denoising_raw": 43.59544372558594,
|
| 23 |
+
"cosmo": 0.020166773349046707,
|
| 24 |
+
"cov_cosmo": 1.5453895684913732e-05,
|
| 25 |
+
"descriptor_std_cosmo": 0.11399243026971817,
|
| 26 |
+
"cosmo_sigma": 0.05140712857246399,
|
| 27 |
+
"cosmo_area": 0.0041954368352890015,
|
| 28 |
+
"cosmo_volume": 0.004897752311080694,
|
| 29 |
+
"combisolv": 1.3595600128173828,
|
| 30 |
+
"cov_combisolv": 0.0001902484946185723,
|
| 31 |
+
"descriptor_std_combisolv": 0.18535533547401428,
|
| 32 |
+
"total": 0.4212467670440674,
|
| 33 |
+
"gradient_norm": 2.3515171745204047,
|
| 34 |
+
"combisolv_rmse_kcal_mol": 5.220246867294003,
|
| 35 |
+
"log_variance_rem3di_denoising": -0.5009999871253967,
|
| 36 |
+
"precision_rem3di_denoising": 0.8251854181289673,
|
| 37 |
+
"log_variance_cosmo": -0.5009999871253967,
|
| 38 |
+
"precision_cosmo": 0.8251854181289673,
|
| 39 |
+
"log_variance_combisolv": -0.49900001287460327,
|
| 40 |
+
"precision_combisolv": 0.8235366940498352
|
| 41 |
+
},
|
| 42 |
+
"seconds_per_joint_step": 2.9659399400006805,
|
| 43 |
+
"steady_seconds_per_joint_step": 0.5084904360010114,
|
| 44 |
+
"smoke_cosmo_molecules": 64,
|
| 45 |
+
"smoke_qm_pairs": 256,
|
| 46 |
+
"peak_gpu_GB": 13.077587456,
|
| 47 |
+
"config": {
|
| 48 |
+
"epochs": 5,
|
| 49 |
+
"seed": 42026,
|
| 50 |
+
"learning_rate_backbone": 1e-05,
|
| 51 |
+
"learning_rate_cosmo": 1e-05,
|
| 52 |
+
"deterministic_training": true,
|
| 53 |
+
"learning_rate_denoiser": 1e-05,
|
| 54 |
+
"learning_rate_combisolv": 0.0003,
|
| 55 |
+
"learning_rate_uncertainty": 0.001,
|
| 56 |
+
"weight_decay": 0.0001,
|
| 57 |
+
"gradient_clip": 1.0,
|
| 58 |
+
"cosmo_batch_size": 96,
|
| 59 |
+
"cosmo_atom_cap": 4000,
|
| 60 |
+
"qm_pair_batch_size": 256,
|
| 61 |
+
"qm_graph_batch_size": 64,
|
| 62 |
+
"qm_atom_cap": 3600,
|
| 63 |
+
"noise_sigma": 0.3,
|
| 64 |
+
"denoising_reduction": "Original atom_denoising_loss / 1088 embedding channels; raw loss also logged",
|
| 65 |
+
"task_order": [
|
| 66 |
+
"rem3di_denoising",
|
| 67 |
+
"cosmo",
|
| 68 |
+
"combisolv"
|
| 69 |
+
],
|
| 70 |
+
"uncertainty_init": -0.5,
|
| 71 |
+
"uncertainty_objective": "sum(L_t/(2*exp(s_t)) + s_t/2); s is learned log variance; no weight normalization in objective",
|
| 72 |
+
"decorrelation_weight": 8.0,
|
| 73 |
+
"decorrelation": "Monroe off_diag_cov_loss: sum(offdiag(sample covariance)^2)/(D*(D-1)); average COSMO and unique CombiSolv molecular batches; outside UW",
|
| 74 |
+
"monroe_revision": "de075eabe98e4adbbedbc86ca9e877f4bfd9b629",
|
| 75 |
+
"temperature_input": "Temperature_K/298",
|
| 76 |
+
"qm_head": "concat(solute640, solvent640, T/298) -> Linear1281x256 -> SiLU -> Linear256x1",
|
| 77 |
+
"epoch_definition": "Maximum of full COSMO and full CombiSolv training-loader lengths. Cycle shorter loader. Every epoch covers every retained training row from each corpus.",
|
| 78 |
+
"initial_checkpoint": "Exact PCQMep2COSMOep10 used in existing BigSolDB evaluation",
|
| 79 |
+
"denoiser_initialization": "PCQM epoch2 decoder only; encoder/preprocessors/COSMO head all from COSMO10",
|
| 80 |
+
"frozen": "MACE-POLAR foundation only; full float32 raw features cached; learned atomic/geometric preprocessors trainable",
|
| 81 |
+
"evaluation": "Identical BigSolDB2.0 author test IDs, shared baseline geometries, concatenated solute+solvent+T, Kumo Large four estimators seed42 full75731-row context and all1281 columns; evaluate every epoch without test-based selection"
|
| 82 |
+
}
|
| 83 |
+
}
|
source/multitask_data.py
CHANGED
|
@@ -194,7 +194,8 @@ def prepare_tables():
|
|
| 194 |
|
| 195 |
def prepare_geometries():
|
| 196 |
path=DATA/'combisolv_geometries.parquet'
|
| 197 |
-
if path.exists():
|
|
|
|
| 198 |
molecules=pd.read_parquet(DATA/'combisolv_molecules.parquet')
|
| 199 |
status('generating_combisolv_3d',total=len(molecules))
|
| 200 |
result=[]
|
|
@@ -206,8 +207,18 @@ def prepare_geometries():
|
|
| 206 |
assert not failures,failures[:10]
|
| 207 |
assert [r['smiles'] for r in result]==molecules.smiles.tolist()
|
| 208 |
pd.DataFrame(result).to_parquet(path,index=False,compression='zstd')
|
| 209 |
-
|
| 210 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 211 |
no_2d_fallback=True,missing=0))
|
| 212 |
|
| 213 |
|
|
@@ -252,7 +263,10 @@ def cache_mace(name,frame):
|
|
| 252 |
mace=build_author_mace_runtime().cuda().eval().requires_grad_(False)
|
| 253 |
captures=[]
|
| 254 |
hook=mace.preprocessor.atomic_preprocessor.register_forward_pre_hook(lambda m,a:captures.append(a[0].detach()))
|
| 255 |
-
started=time.time()
|
|
|
|
|
|
|
|
|
|
| 256 |
status('caching_frozen_mace',corpus=name,total=len(frame),atoms=int(ptr[-1]),bytes=int(ptr[-1])*4096*4,batches=len(plan))
|
| 257 |
with torch.inference_mode():
|
| 258 |
for bi,ids in enumerate(plan,1):
|
|
@@ -276,9 +290,55 @@ def cache_mace(name,frame):
|
|
| 276 |
def publish_data():
|
| 277 |
marker=OUT/'prepared_data_hub.json'
|
| 278 |
if marker.exists():return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 279 |
files=[p for p in DATA.iterdir() if p.is_file()]
|
| 280 |
commit=HfApi().create_commit(repo_id=DATA_REPO,repo_type='dataset',
|
| 281 |
-
operations=[CommitOperationAdd(path_in_repo='prepared/'+p.name,path_or_fileobj=str(p)) for p in files]
|
|
|
|
| 282 |
commit_message='Add reproducible joint splits, all geometries, label transforms and benchmark exclusions')
|
| 283 |
remote={p.rfilename:p for p in HfApi().dataset_info(DATA_REPO,revision=commit.oid,files_metadata=True).siblings}
|
| 284 |
for p in files:
|
|
@@ -300,14 +360,11 @@ def main():
|
|
| 300 |
graphs=pd.read_parquet(WORK/'bigsoldb_evaluation/features/shared_graphs.parquet')
|
| 301 |
vocab=NODE_FEAT_LIST_ONE_HOT['atomic_number'];col=list(NODE_FEAT_LIST_ONE_HOT).index('atomic_number')
|
| 302 |
ptable=Chem.GetPeriodicTable()
|
| 303 |
-
graph_atoms=pd.DataFrame(dict(smiles=graphs.smiles,positions=graphs.pos_rdkit,
|
| 304 |
atomic_numbers=[[ptable.GetAtomicNumber(vocab[int(i)]) for i in np.stack(codes)[:,col]] for codes in graphs.node_codes],
|
| 305 |
charge=[int(round(float(np.stack(v)[:,5].sum()))) for v in graphs.node_float]))
|
| 306 |
graph_atoms.to_parquet(DATA/'bigsoldb_fixed_geometries.parquet',index=False,compression='zstd')
|
| 307 |
cache_mace('bigsoldb',graph_atoms)
|
| 308 |
-
manifest=json.loads((DATA/'manifest.json').read_text())
|
| 309 |
-
manifest['files']={p.name:sha(p) for p in DATA.iterdir() if p.is_file() and p.name!='manifest.json'}
|
| 310 |
-
write(DATA/'manifest.json',manifest)
|
| 311 |
publish_data()
|
| 312 |
write(OUT/'preparation_complete.json',dict(completed=True,time=time.time(),initialization=json.loads((OUT/'initialization.json').read_text()),data=json.loads((OUT/'prepared_data_hub.json').read_text())))
|
| 313 |
status('preparation_complete')
|
|
|
|
| 194 |
|
| 195 |
def prepare_geometries():
|
| 196 |
path=DATA/'combisolv_geometries.parquet'
|
| 197 |
+
if path.exists():
|
| 198 |
+
record_geometry_manifest(path);return
|
| 199 |
molecules=pd.read_parquet(DATA/'combisolv_molecules.parquet')
|
| 200 |
status('generating_combisolv_3d',total=len(molecules))
|
| 201 |
result=[]
|
|
|
|
| 207 |
assert not failures,failures[:10]
|
| 208 |
assert [r['smiles'] for r in result]==molecules.smiles.tolist()
|
| 209 |
pd.DataFrame(result).to_parquet(path,index=False,compression='zstd')
|
| 210 |
+
record_geometry_manifest(path)
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
def record_geometry_manifest(path):
|
| 214 |
+
from rdkit import rdBase
|
| 215 |
+
frame=pd.read_parquet(path,columns=['smiles','geometry_method'])
|
| 216 |
+
molecules=pd.read_parquet(DATA/'combisolv_molecules.parquet',columns=['smiles'])
|
| 217 |
+
assert frame.smiles.tolist()==molecules.smiles.tolist()
|
| 218 |
+
write(DATA/'geometry_manifest.json',dict(rows=len(frame),sha256=sha(path),seed=42026,
|
| 219 |
+
rdkit_version=rdBase.rdkitVersion,
|
| 220 |
+
algorithm='RDKit ETKDGv3 explicit H, deterministic random-coordinate retries, generic 3D distance geometry fallback; MMFF94s or UFF where parameterized',
|
| 221 |
+
methods={str(k):int(v) for k,v in frame.geometry_method.value_counts().items()},
|
| 222 |
no_2d_fallback=True,missing=0))
|
| 223 |
|
| 224 |
|
|
|
|
| 263 |
mace=build_author_mace_runtime().cuda().eval().requires_grad_(False)
|
| 264 |
captures=[]
|
| 265 |
hook=mace.preprocessor.atomic_preprocessor.register_forward_pre_hook(lambda m,a:captures.append(a[0].detach()))
|
| 266 |
+
started=time.time()
|
| 267 |
+
if name=='bigsoldb':
|
| 268 |
+
plan=list(common.batch_indices(np.arange(len(frame)),lengths,max_size=24,atom_cap=2400))
|
| 269 |
+
else:plan=list(batches(np.arange(len(frame)),lengths,max_size=64,atom_cap=3600))
|
| 270 |
status('caching_frozen_mace',corpus=name,total=len(frame),atoms=int(ptr[-1]),bytes=int(ptr[-1])*4096*4,batches=len(plan))
|
| 271 |
with torch.inference_mode():
|
| 272 |
for bi,ids in enumerate(plan,1):
|
|
|
|
| 290 |
def publish_data():
|
| 291 |
marker=OUT/'prepared_data_hub.json'
|
| 292 |
if marker.exists():return
|
| 293 |
+
pairs=pd.read_parquet(DATA/'combisolv_pairs.parquet')
|
| 294 |
+
for split,frame in pairs.groupby('split',sort=False):
|
| 295 |
+
frame.to_parquet(DATA/f'combisolv_{split}.parquet',index=False,compression='zstd')
|
| 296 |
+
manifest=json.loads((DATA/'manifest.json').read_text())
|
| 297 |
+
manifest['files']={p.name:sha(p) for p in DATA.iterdir() if p.is_file() and p.name!='manifest.json'}
|
| 298 |
+
write(DATA/'manifest.json',manifest)
|
| 299 |
+
header='''---
|
| 300 |
+
license: cc-by-4.0
|
| 301 |
+
task_categories:
|
| 302 |
+
- tabular-regression
|
| 303 |
+
configs:
|
| 304 |
+
- config_name: raw_combisolv_qm
|
| 305 |
+
default: true
|
| 306 |
+
data_files:
|
| 307 |
+
- split: records
|
| 308 |
+
path: raw/combisolv_qm.parquet
|
| 309 |
+
- config_name: prepared_pairs
|
| 310 |
+
data_files:
|
| 311 |
+
- split: train
|
| 312 |
+
path: prepared/combisolv_train.parquet
|
| 313 |
+
- split: validation
|
| 314 |
+
path: prepared/combisolv_validation.parquet
|
| 315 |
+
- split: benchmark_overlap
|
| 316 |
+
path: prepared/combisolv_benchmark_overlap.parquet
|
| 317 |
+
- split: auxiliary_holdout
|
| 318 |
+
path: prepared/combisolv_auxiliary_holdout.parquet
|
| 319 |
+
- config_name: combisolv_geometries
|
| 320 |
+
data_files:
|
| 321 |
+
- split: molecules
|
| 322 |
+
path: prepared/combisolv_geometries.parquet
|
| 323 |
+
- config_name: cosmo_pool
|
| 324 |
+
data_files:
|
| 325 |
+
- split: records
|
| 326 |
+
path: prepared/cosmo-*.parquet
|
| 327 |
+
---
|
| 328 |
+
'''
|
| 329 |
+
card=header+'\n# CombiSolv-QM and COSMO multi-task continuation data\n\n'
|
| 330 |
+
card+='The unchanged original one-million-row CombiSolv-QM table is preserved under `raw/`, together with source archive/CSV/Parquet checksums. The target is signed solvation Gibbs free energy at 298 K, in kcal/mol, using 1 mol/L reference concentrations. It is distinct from experimental solubility.\n\n'
|
| 331 |
+
card+=f"Prepared CombiSolv memberships: `{json.dumps(manifest['combisolv_splits'],sort_keys=True)}`. All {manifest['unique_qm_molecules']:,} unique structures have explicit-H coordinates; supplied InChI defines identity, and original SMILES/InChI mappings are retained. Solute/solvent indices refer to row order in the geometry and molecule tables.\n\n"
|
| 332 |
+
card+='Geometries use seeded RDKit ETKDGv3, random-coordinate retries and generic 3D distance geometry for strained/unusual structures, followed by MMFF94s or UFF when parameterized. There is no 2D fallback. Geometry methods, software version, coverage and checksums are recorded.\n\n'
|
| 333 |
+
card+=f"The COSMO pool retains the source training/validation records and adds an explicit `joint_split` membership: `{json.dumps(manifest['cosmo_splits'],sort_keys=True)}`. Filter that column for training. The complete original COSMO dataset and its existing ESOL/FreeSolv quarantine remain available in [Queimo/pubchemqc-cosmo-pm6](https://huggingface.co/datasets/{COSMO_REPO}) at revision `{COSMO_REV}`.\n\n"
|
| 334 |
+
card+='BigSolDB2.0 held-out solute connectivity groups are excluded from all new objectives and both CombiSolv input roles. CombiSolv validation solutes are excluded across objectives. Existing COSMO validation groups are excluded from CombiSolv training. Raw rows remain available with explicit quarantine membership; earlier exposure in the starting checkpoint cannot be undone. ESOL/FreeSolv quarantine is preserved for COSMO, but is not claimed for CombiSolv.\n\n'
|
| 335 |
+
card+='CombiSolv target mean/std is fitted on its retained training rows only; signed energies are not log transformed. The existing COSMO log1p/ln transform and normalization are preserved so the initialized output head retains its meaning.\n\n'
|
| 336 |
+
card+='[SolProp v1.2 source](https://zenodo.org/records/5970538) · [Vermeire and Green (2021)](https://doi.org/10.1016/j.cej.2021.129307) · [Vermeire, Chung and Green (2022)](https://doi.org/10.1021/jacs.2c01768). Please cite the original data authors.\n'
|
| 337 |
+
card_path=OUT/'dataset_README.md';card_path.write_text(card)
|
| 338 |
files=[p for p in DATA.iterdir() if p.is_file()]
|
| 339 |
commit=HfApi().create_commit(repo_id=DATA_REPO,repo_type='dataset',
|
| 340 |
+
operations=[CommitOperationAdd(path_in_repo='prepared/'+p.name,path_or_fileobj=str(p)) for p in files]+[
|
| 341 |
+
CommitOperationAdd(path_in_repo='README.md',path_or_fileobj=str(card_path))],
|
| 342 |
commit_message='Add reproducible joint splits, all geometries, label transforms and benchmark exclusions')
|
| 343 |
remote={p.rfilename:p for p in HfApi().dataset_info(DATA_REPO,revision=commit.oid,files_metadata=True).siblings}
|
| 344 |
for p in files:
|
|
|
|
| 360 |
graphs=pd.read_parquet(WORK/'bigsoldb_evaluation/features/shared_graphs.parquet')
|
| 361 |
vocab=NODE_FEAT_LIST_ONE_HOT['atomic_number'];col=list(NODE_FEAT_LIST_ONE_HOT).index('atomic_number')
|
| 362 |
ptable=Chem.GetPeriodicTable()
|
| 363 |
+
graph_atoms=pd.DataFrame(dict(smiles=graphs.smiles,positions=[np.stack(p).astype(np.float32).tolist() for p in graphs.pos_rdkit],
|
| 364 |
atomic_numbers=[[ptable.GetAtomicNumber(vocab[int(i)]) for i in np.stack(codes)[:,col]] for codes in graphs.node_codes],
|
| 365 |
charge=[int(round(float(np.stack(v)[:,5].sum()))) for v in graphs.node_float]))
|
| 366 |
graph_atoms.to_parquet(DATA/'bigsoldb_fixed_geometries.parquet',index=False,compression='zstd')
|
| 367 |
cache_mace('bigsoldb',graph_atoms)
|
|
|
|
|
|
|
|
|
|
| 368 |
publish_data()
|
| 369 |
write(OUT/'preparation_complete.json',dict(completed=True,time=time.time(),initialization=json.loads((OUT/'initialization.json').read_text()),data=json.loads((OUT/'prepared_data_hub.json').read_text())))
|
| 370 |
status('preparation_complete')
|
source/multitask_evaluate.py
CHANGED
|
@@ -21,7 +21,7 @@ def embeddings(epoch):
|
|
| 21 |
model=MultiTask(checkpoint);model.eval().requires_grad_(False)
|
| 22 |
cache=RawCache('bigsoldb');X=np.empty((len(geometry),640),dtype=np.float32)
|
| 23 |
with torch.inference_mode():
|
| 24 |
-
for ids in
|
| 25 |
_,_,z=model.encode(cache.sample(ids));X[ids]=z.float().cpu().numpy()
|
| 26 |
assert np.isfinite(X).all()
|
| 27 |
np.savez_compressed(path,X=X,smiles=geometry.smiles.to_numpy(dtype=str),checkpoint_sha256=json.dumps(hashes))
|
|
|
|
| 21 |
model=MultiTask(checkpoint);model.eval().requires_grad_(False)
|
| 22 |
cache=RawCache('bigsoldb');X=np.empty((len(geometry),640),dtype=np.float32)
|
| 23 |
with torch.inference_mode():
|
| 24 |
+
for ids in common.batch_indices(np.arange(len(geometry)),cache.lengths,max_size=24,atom_cap=2400):
|
| 25 |
_,_,z=model.encode(cache.sample(ids));X[ids]=z.float().cpu().numpy()
|
| 26 |
assert np.isfinite(X).all()
|
| 27 |
np.savez_compressed(path,X=X,smiles=geometry.smiles.to_numpy(dtype=str),checkpoint_sha256=json.dumps(hashes))
|
source/multitask_train.py
CHANGED
|
@@ -174,13 +174,15 @@ def smoke(data):
|
|
| 174 |
else:check_monroe_losses()
|
| 175 |
model=MultiTask();optimizer=optimizer_for(model)
|
| 176 |
scheduler=torch.optim.lr_scheduler.LambdaLR(optimizer,lambda e:1.)
|
| 177 |
-
model.eval();baseline=RawCache('bigsoldb')
|
| 178 |
with torch.no_grad():
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
|
|
|
|
|
|
| 184 |
frozen={n:b.cpu().clone() for n,b in model.pre.atomic_preprocessor.invariant_normalization.named_buffers()}
|
| 185 |
cp,qp,_=data.plans(1);ci=cp[10];qi=qp[10]
|
| 186 |
initial=next(model.encoder.parameters()).detach().clone()
|
|
@@ -195,7 +197,9 @@ def smoke(data):
|
|
| 195 |
expected_state={n:v.detach().cpu().clone() for n,v in model.state_dict().items()}
|
| 196 |
model.load_parts(temp);state=torch.load(temp/'training_state.pt',map_location='cpu',weights_only=False)
|
| 197 |
optimizer.load_state_dict(state['optimizer']);scheduler.load_state_dict(state['scheduler']);restore_rng(state)
|
|
|
|
| 198 |
actual=update(model,optimizer,data,ci,qi)
|
|
|
|
| 199 |
assert all(np.isclose(actual[k],expected[k],atol=1e-7,rtol=1e-7) for k in expected),(expected,actual)
|
| 200 |
assert all(torch.equal(v.detach().cpu(),expected_state[n]) for n,v in model.state_dict().items()),'Resume changed next-step parameters'
|
| 201 |
for n,b in model.pre.atomic_preprocessor.invariant_normalization.named_buffers():assert torch.equal(b.cpu(),frozen[n])
|
|
@@ -203,6 +207,7 @@ def smoke(data):
|
|
| 203 |
result=dict(passed=True,all_head_gradients=gradients,encoder_updated=True,task_weights_updated=True,
|
| 204 |
optimizer_and_rng_resume_next_step_exact=True,normalization_buffers_unchanged=True,
|
| 205 |
initial_bigsoldb_embedding_match=initial_difference,real_batch_loss=first,seconds_per_joint_step=duration,
|
|
|
|
| 206 |
smoke_cosmo_molecules=len(ci),smoke_qm_pairs=len(qi),peak_gpu_GB=peak,config=CONFIG)
|
| 207 |
write(OUT/'smoke_validation.json',result);shutil.rmtree(temp)
|
| 208 |
status('smoke_passed',seconds_per_joint_step=duration,peak_gpu_GB=peak,initial_embedding_difference=initial_difference)
|
|
@@ -219,7 +224,8 @@ def main():
|
|
| 219 |
torch.manual_seed(CONFIG['seed']);torch.cuda.manual_seed_all(CONFIG['seed']);np.random.seed(CONFIG['seed']);random.seed(CONFIG['seed'])
|
| 220 |
data=TrainingData()
|
| 221 |
if args.smoke:smoke(data);return
|
| 222 |
-
|
|
|
|
| 223 |
checkpoints=sorted((OUT/'checkpoints').glob('epoch_[0-9][0-9]')) if (OUT/'checkpoints').exists() else []
|
| 224 |
model=MultiTask(checkpoints[-1] if checkpoints else None);optimizer=optimizer_for(model)
|
| 225 |
scheduler=torch.optim.lr_scheduler.LambdaLR(optimizer,lambda e:.1+.9*.5*(1+math.cos(math.pi*e/CONFIG['epochs'])))
|
|
|
|
| 174 |
else:check_monroe_losses()
|
| 175 |
model=MultiTask();optimizer=optimizer_for(model)
|
| 176 |
scheduler=torch.optim.lr_scheduler.LambdaLR(optimizer,lambda e:1.)
|
| 177 |
+
model.eval();baseline=RawCache('bigsoldb')
|
| 178 |
with torch.no_grad():
|
| 179 |
+
ref=np.load(WORK/'bigsoldb_evaluation/features/cosmo_epoch10.npz')['X']
|
| 180 |
+
ours=np.empty_like(ref)
|
| 181 |
+
for ids in common.batch_indices(np.arange(len(ref)),baseline.lengths,max_size=24,atom_cap=2400):
|
| 182 |
+
_,_,z=model.encode(baseline.sample(ids));ours[ids]=z.cpu().numpy()
|
| 183 |
+
difference=np.abs(ours-ref)
|
| 184 |
+
assert np.allclose(ours,ref,atol=2e-4,rtol=2e-4),(float(difference.max()),float(difference.mean()))
|
| 185 |
+
initial_difference=dict(molecules=len(ref),max_absolute=float(difference.max()),mean_absolute=float(difference.mean()))
|
| 186 |
frozen={n:b.cpu().clone() for n,b in model.pre.atomic_preprocessor.invariant_normalization.named_buffers()}
|
| 187 |
cp,qp,_=data.plans(1);ci=cp[10];qi=qp[10]
|
| 188 |
initial=next(model.encoder.parameters()).detach().clone()
|
|
|
|
| 197 |
expected_state={n:v.detach().cpu().clone() for n,v in model.state_dict().items()}
|
| 198 |
model.load_parts(temp);state=torch.load(temp/'training_state.pt',map_location='cpu',weights_only=False)
|
| 199 |
optimizer.load_state_dict(state['optimizer']);scheduler.load_state_dict(state['scheduler']);restore_rng(state)
|
| 200 |
+
replay_started=time.perf_counter()
|
| 201 |
actual=update(model,optimizer,data,ci,qi)
|
| 202 |
+
steady_duration=time.perf_counter()-replay_started
|
| 203 |
assert all(np.isclose(actual[k],expected[k],atol=1e-7,rtol=1e-7) for k in expected),(expected,actual)
|
| 204 |
assert all(torch.equal(v.detach().cpu(),expected_state[n]) for n,v in model.state_dict().items()),'Resume changed next-step parameters'
|
| 205 |
for n,b in model.pre.atomic_preprocessor.invariant_normalization.named_buffers():assert torch.equal(b.cpu(),frozen[n])
|
|
|
|
| 207 |
result=dict(passed=True,all_head_gradients=gradients,encoder_updated=True,task_weights_updated=True,
|
| 208 |
optimizer_and_rng_resume_next_step_exact=True,normalization_buffers_unchanged=True,
|
| 209 |
initial_bigsoldb_embedding_match=initial_difference,real_batch_loss=first,seconds_per_joint_step=duration,
|
| 210 |
+
steady_seconds_per_joint_step=steady_duration,
|
| 211 |
smoke_cosmo_molecules=len(ci),smoke_qm_pairs=len(qi),peak_gpu_GB=peak,config=CONFIG)
|
| 212 |
write(OUT/'smoke_validation.json',result);shutil.rmtree(temp)
|
| 213 |
status('smoke_passed',seconds_per_joint_step=duration,peak_gpu_GB=peak,initial_embedding_difference=initial_difference)
|
|
|
|
| 224 |
torch.manual_seed(CONFIG['seed']);torch.cuda.manual_seed_all(CONFIG['seed']);np.random.seed(CONFIG['seed']);random.seed(CONFIG['seed'])
|
| 225 |
data=TrainingData()
|
| 226 |
if args.smoke:smoke(data);return
|
| 227 |
+
smoke_result=json.loads((OUT/'smoke_validation.json').read_text())
|
| 228 |
+
assert smoke_result['passed'] and smoke_result['config']==CONFIG
|
| 229 |
checkpoints=sorted((OUT/'checkpoints').glob('epoch_[0-9][0-9]')) if (OUT/'checkpoints').exists() else []
|
| 230 |
model=MultiTask(checkpoints[-1] if checkpoints else None);optimizer=optimizer_for(model)
|
| 231 |
scheduler=torch.optim.lr_scheduler.LambdaLR(optimizer,lambda e:.1+.9*.5*(1+math.cos(math.pi*e/CONFIG['epochs'])))
|
source_hashes.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
{
|
| 2 |
-
"multitask_data.py": "
|
| 3 |
"multitask_model.py": "1ffe262b355bc911e3ea35c9e6844d40ab5b6dafb5a11a90eba6565361083b05",
|
| 4 |
-
"multitask_train.py": "
|
| 5 |
-
"multitask_evaluate.py": "
|
| 6 |
"multitask_driver.py": "ade6f9106b3be1d488e39db711119d43e07457ebe9425196b460c87440205ad7",
|
| 7 |
"eval_common.py": "e694f4e3dc4d62f2567b55a3e3b4da9855686c2977ba3b182094c86b1fb8eaa5",
|
| 8 |
"train_cosmo.py": "a2ce3a8bfcd7dd8eafb108151cf7ccce78b3e576b07df83c2b436fde931dd866",
|
|
|
|
| 1 |
{
|
| 2 |
+
"multitask_data.py": "7ba9accbbd9a0d9c23720946cb0ebd2e410853aa7951dc58c9198a4f2586c616",
|
| 3 |
"multitask_model.py": "1ffe262b355bc911e3ea35c9e6844d40ab5b6dafb5a11a90eba6565361083b05",
|
| 4 |
+
"multitask_train.py": "00983d0060b26f148eb67b021899d9a73d84231aaf821406b2a4d9f1c36d568d",
|
| 5 |
+
"multitask_evaluate.py": "ea5132b5bd4efe97924009bbe94f6d1f7ff4504f993b37689c0ce7ef93dea9c6",
|
| 6 |
"multitask_driver.py": "ade6f9106b3be1d488e39db711119d43e07457ebe9425196b460c87440205ad7",
|
| 7 |
"eval_common.py": "e694f4e3dc4d62f2567b55a3e3b4da9855686c2977ba3b182094c86b1fb8eaa5",
|
| 8 |
"train_cosmo.py": "a2ce3a8bfcd7dd8eafb108151cf7ccce78b3e576b07df83c2b436fde931dd866",
|