Download model.py from maozee/model_kcat_lgbm: direct link, hf CLI and curl.
- Browser
- Download file 2.29 kB
-
https://huggingface.co/maozee/model_kcat_lgbm/resolve/main/model.py
- Command line
-
hf download hf://maozee/model_kcat_lgbm/model.py
-
curl -L -o model.py https://huggingface.co/maozee/model_kcat_lgbm/resolve/main/model.py
2.29 kB
| """LightGBM on RDKit substrate features, sequence composition, and ESM-2 (8M) embeddings.""" | |
| import json | |
| from pathlib import Path | |
| import re | |
| import numpy as np | |
| from featurize import composition_features, esm_embeddings, smiles_features | |
| WEIGHTS = Path(__file__).parent / 'weights' | |
| class Model: | |
| def __init__(self, weights=WEIGHTS, threads=2): | |
| import lightgbm as lgb | |
| self.meta = json.loads((Path(weights) / 'meta.json').read_text()) | |
| self.threads = threads | |
| self.boosters = [lgb.Booster(model_file=str(Path(weights) / f'lgbm_{t}.txt')) for t in self.meta['targets']] | |
| def predict(self, frame): | |
| """Return an (n, 2) array of log10_kcat, log10_km for a frame with smiles and sequence.""" | |
| blocks = [] | |
| groups = self.meta['groups'] | |
| if 'smiles' in groups: | |
| blocks.append(self._per_unique(frame.smiles, smiles_features)) | |
| if 'comp' in groups: | |
| blocks.append(self._per_unique(frame.sequence, composition_features)) | |
| if 'esm' in groups: | |
| blocks.append(self._per_unique(frame.sequence, lambda s: esm_embeddings(s, threads=self.threads))) | |
| x = np.hstack(blocks) | |
| return np.column_stack([b.predict(x, num_threads=self.threads) for b in self.boosters]) | |
| def _per_unique(values, fn): | |
| keys, inverse = np.unique(values.to_numpy(), return_inverse=True) | |
| return fn(list(keys))[inverse] | |
| def validate_rows(rows, max_rows=256): | |
| if not isinstance(rows, list) or not 1 <= len(rows) <= max_rows: | |
| raise ValueError(f'Provide between 1 and {max_rows} rows.') | |
| ids = set() | |
| for row in rows: | |
| if not isinstance(row, dict) or set(row) != {'id', 'smiles', 'sequence'}: | |
| raise ValueError('Each row must contain exactly id, smiles, sequence.') | |
| if not isinstance(row['id'], str) or not re.fullmatch(r'[A-Za-z0-9_-]{1,80}', row['id']): | |
| raise ValueError('Invalid row ID.') | |
| if row['id'] in ids: | |
| raise ValueError('Duplicate row ID.') | |
| ids.add(row['id']) | |
| for key, limit in [('sequence', 50000), ('smiles', 20000)]: | |
| if not isinstance(row[key], str) or not 1 <= len(row[key]) <= limit: | |
| raise ValueError(f'Invalid {key}.') | |
| return rows | |