Spaces:
Build error
Build error
| """ | |
| predict() entry point for the Tox21 leaderboard (ml-jku/tox21_leaderboard). | |
| Input: list of SMILES. Output: nested dict {smiles: {target: probability}}. | |
| Unparseable molecules return 0.5 for every target. | |
| Model: VIDRAFT rich-feature XGBoost (Morgan2048 + MACCS167 + RDKit 2D descriptors), | |
| one XGBoost per Tox21 task, trained on the official ml-jku/tox21 train split. | |
| Feature order is loaded from checkpoints/feat_spec.json so it is identical to training | |
| regardless of the local RDKit version. | |
| """ | |
| import os | |
| import json | |
| import numpy as np | |
| import xgboost as xgb | |
| from rdkit import Chem, RDLogger, DataStructs | |
| from rdkit.Chem import AllChem, MACCSkeys | |
| from rdkit.ML.Descriptors import MoleculeDescriptors | |
| RDLogger.DisableLog("rdApp.*") | |
| TASKS = ["NR-AhR", "NR-AR", "NR-AR-LBD", "NR-Aromatase", "NR-ER", "NR-ER-LBD", | |
| "NR-PPAR-gamma", "SR-ARE", "SR-ATAD5", "SR-HSE", "SR-MMP", "SR-p53"] | |
| _HERE = os.path.dirname(os.path.abspath(__file__)) | |
| _CK = os.path.join(_HERE, "checkpoints") | |
| _spec = json.load(open(os.path.join(_CK, "feat_spec.json"))) | |
| _DESC = _spec["desc"] | |
| _calc = MoleculeDescriptors.MolecularDescriptorCalculator(_DESC) | |
| _med = np.load(os.path.join(_CK, "feat_median.npy")) | |
| _FPN, _MACCSN = 2048, 167 | |
| _DIM = _FPN + _MACCSN + len(_DESC) | |
| _models = {} | |
| for _t in TASKS: | |
| _m = xgb.XGBClassifier() | |
| _m.load_model(os.path.join(_CK, "xgb_%s.json" % _t)) | |
| _models[_t] = _m | |
| def _feat_one(smi): | |
| mol = Chem.MolFromSmiles(str(smi)) | |
| if mol is None: | |
| return None | |
| fp = AllChem.GetMorganFingerprintAsBitVect(mol, 2, nBits=_FPN) | |
| a = np.zeros(_FPN, np.int8); DataStructs.ConvertToNumpyArray(fp, a) | |
| mc = MACCSkeys.GenMACCSKeys(mol) | |
| b = np.zeros(_MACCSN, np.int8); DataStructs.ConvertToNumpyArray(mc, b) | |
| d = np.array(_calc.CalcDescriptors(mol), dtype=np.float32) | |
| return np.concatenate([a.astype(np.float32), b.astype(np.float32), d]) | |
| def predict(smiles_list): | |
| n = len(smiles_list) | |
| X = np.zeros((n, _DIM), np.float32) | |
| ok = np.zeros(n, bool) | |
| for i, s in enumerate(smiles_list): | |
| f = _feat_one(s) | |
| if f is not None: | |
| X[i] = f; ok[i] = True | |
| X[~np.isfinite(X)] = np.nan | |
| bad = np.where(np.isnan(X)) | |
| if bad[0].size: | |
| X[bad] = np.take(_med, bad[1]) | |
| probs = {t: _models[t].predict_proba(X)[:, 1] for t in TASKS} | |
| out = {} | |
| for i, s in enumerate(smiles_list): | |
| out[s] = {t: (float(probs[t][i]) if ok[i] else 0.5) for t in TASKS} | |
| return out | |