Family Foundation Model

Download the models

Model release 21 September 2026. Target preference is version 2, built 21 September 2026, and it answers both kinds of comparison; compound preference is unchanged from 13 September 2026. Trained on ChEMBL 37 alone.

Two bundles, one per question. Both run entirely on your own machine, nothing is sent anywhere, and each carries everything it needs to score.

QuantityCompound preferenceTarget preference
The questionwhich of two compounds a target preferswhich of two targets a compound prefers, from different families or from one
Row layoutligand, sequence, ligandsequence, ligand, sequence
Feature width2,5561,998
Forest on disk1.18 GB0.42 GB
Targets it can score2,0792,279
Protein families3234
Held-out accuracy, across families—0.75 on 8,689
Held-out accuracy, within one family—0.78 on 32,738
Held-out accuracy0.71 on 65,725—

The target-preference forest loads to about 3.4 GB of memory in about five seconds, so a laptop with 8 GB runs it comfortably. The preference forest is the larger of the two and wants 16 GB, because it loads to rather more than its size on disk. Load either once at process start rather than per request. No GPU is used at any point.

Held-out accuracy for each is measured on its own compound-disjoint holdout, and the two holdouts are different sets, so read each figure on its own, as set out on the methods page. For target preference the two kinds of comparison are measured apart and never pooled.

The two bundles

BundleFileSizeSHA-256
Compound preference
one target, two compounds
lsl_v1.tar.gz1.18 GB63efc35e584c20b5e881055d317aa9e3…
Target preference
one compound, two targets, from different families or from one family
xfam_v2.tar.gz0.42 GB5f4bfb34f2a2611864151a74f88c15b4…

Those are the checksums of the archives themselves, shown as a prefix, enough to spot a wrong or truncated download. Inside each archive the forest carries its own SHA-256 in MANIFEST.json, and that is the one the installer verifies before it will report success.

Add your own data to either bundle. The extension tools merge trees fitted on your measurements into a released model, on your own machine, and can add targets beyond the roster: how it works, and the full guide, EXTEND.md.

Get the code

The command line tools, the inference API and everything needed to rebuild the training set are on GitHub: github.com/smuskal/ffm.

git clone https://github.com/smuskal/ffm.git
cd ffm && ./install.sh

That installs the environment with the versions pinned below and fetches both bundles, then proves each one works: it checks the forest against the SHA-256 in that bundle's own manifest and replays the reference predictions shipped beside it. If they do not reproduce to 1e-6 the install fails rather than reporting success. FFM_MODELS=selectivity or FFM_MODELS=preference fetches just one.

Run them

Rank targets for one compound, the target-preference question:

ffm rank --smiles "CC(=O)Oc1ccccc1C(=O)O" --targets P00533 P08684 P28223

Rank compounds at one target, the compound-preference question:

ffm rank-ligands --target P00533 --smiles-file hits.smi

Or from Python, loading either bundle by path and keeping the two modules under distinct names:

import familyfm.preference_predict as P m = P.load("path/to/lsl_v2_stratified") P.compare_ligands(m, smiles_a, smiles_b, "P00533") # P(the target prefers the first) P.rank_ligands(m, [s1, s2, s3, s4], "P00533") # preference order at one target P.strength(p) # max(p, 1-p)

Both bundles hold the same two properties, asserted by their own self-tests: every prediction averages both argument orders, so compare(A,B) + compare(B,A) is exactly 1 and a thing compared with itself returns exactly 0.5. Ranking n items costs n(n-1)/2 comparisons, so keep a call to a sane panel size. An unparseable SMILES raises rather than being dropped.

Targets are named by UniProt accession. Gene symbols are many-to-many against accessions and the failure is silent, so the accession is what the model is given. The full roster is on the targets page.

Extend a model with your own data

The extension tool, extend/ffm_extend.py, fits decision trees on measurements you hold and merges them into a released forest, on your own machine. Your structures, sequences and activity values stay on your computer and are never written into the bundle; only the trees fitted from them are. It works on both bundles and reads the layout from the bundle's own manifest, so one command serves either. The base bundle is opened read-only, and the output is a complete bundle whose predict.py loads the merged forest unchanged.

python extend/ffm_extend.py --base ffm-models/lsl_v2_stratified --data mine.csv --out ./mine_lsl
python extend/ffm_extend.py --base ffm-models/xfam_v2_samefamily --data mine.csv --out ./mine_sls

Your targets can go beyond the roster. The released bundles score {n(L["targets_servable"])} and {n(F["targets_servable"])} targets. Name a target by UniProt accession to use one a bundle already carries, or supply its amino acid sequence to add a new one: the sequence is embedded with the same ESM2 recipe the models were built on, your trees are fitted on it, and it is written into the output bundle's sequence vectors and target index, so it can be scored afterwards like any other target.

Measured on held-out public ChEMBL data. For compound preference, 1,858 added comparisons across five targets, with 797 more from those targets held out: 80 added trees moved accuracy on those targets from 0.69 to 0.73, with a breadth reference across the roster steady at 0.69. What your own data adds depends on your data.

An extended model is measured on your data. Added trees change every prediction, so the figures on this site describe the released bundles. The tool replaces the performance block in the output manifest with a withdrawal notice; measure the extended model on your own held-out comparisons, and re-measure the strength operating point there, before quoting a number from it. Keep comparisons between two families and comparisons inside one family apart when you measure, as the released figures do.

Adding a target by sequence also needs torch and transformers; naming targets by accession needs neither. The scikit-learn version must match the bundle manifest. Input formats, worked examples and the tree-count sweep are in EXTEND.md.

What is in a bundle

Both bundles ship the same file set, differing only in the forest and in the target roster each can score.

FileWhat it is
familyfm_selectivity.joblib or familyfm_preference.joblibthe forest, one per bundle
predict.pythe inference API; load it by file path, nothing to install
sequence_vectors.npzESM2 vectors for every servable target, precomputed
sequence_index.jsonsequence key to row
target_index.jsonaccession to sequence key, and the family per target
MANIFEST.jsonprovenance, hyperparameters, measured performance
reference_predictions.json30 fixed inputs and the outputs this bundle produced
heldout_scored.csvevery held-out comparison with its probability, so the headline can be recomputed

Because heldout_scored.csv ships with the bundle, every number on this site can be recomputed from the download without rerunning the model.

Pin these versions

A joblib forest is a pickled object graph, so scikit-learn, numpy and joblib are pinned to the build versions. Another scikit-learn warns when it loads a forest; both bundles were checked under 1.6.1 and reproduce their reference predictions, and the installer's replay is how you confirm any environment. RDKit computes 1,024 of every ligand block's 1,038 dimensions, so it is held to the releases measured to compute byte-identical features: 2024.03.6 through 2025.09.5.

Install on Python 3.10 to 3.13, on macOS or Linux; both bundles verify identically on 3.12. install.sh picks a suitable Python and installs the pinned libraries, RDKit included, and python -m familyfm.rdkit_check confirms your RDKit computes the same ligand features. The models were built with:

PackagePinned
numpy2.2.6
python3.10.15
sklearn1.7.2

Licensing

The code is Apache 2.0. The model weights are CC BY-SA 4.0, which is the share-alike term ChEMBL itself carries: this model is trained on ChEMBL 37 and nothing else, so the weights inherit its attribution and share-alike conditions. Cite ChEMBL alongside this model in anything you publish.

The sibling Kinase Foundation Model ships its weights under research-and-evaluation terms instead, because it is trained on a commercial database. This one is not, which is why it can be downloaded freely.

Model release 21 September 2026, target preference version 2. For each bundle the forest, the reference predictions and the held-out scores all come from that build, and the checksum in its MANIFEST.json is what the installer verifies. The preference forest carries e693f791edf1cdf4….