{"id":13444186,"url":"https://github.com/keiserlab/keras-neural-graph-fingerprint","last_synced_at":"2025-10-23T17:31:43.270Z","repository":{"id":84845401,"uuid":"70108270","full_name":"keiserlab/keras-neural-graph-fingerprint","owner":"keiserlab","description":"Keras implementation of Neural Graph Fingerprints as proposed by Duvenaud et al., 2015","archived":false,"fork":false,"pushed_at":"2019-01-25T06:22:46.000Z","size":3201,"stargazers_count":46,"open_issues_count":7,"forks_count":22,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-01-30T20:04:59.947Z","etag":null,"topics":["atom","differentiable-models","fingerprint","gpu","graph","graph-algorithms","keras","molecule","morgan-fingerprints","neural-networks","tensor"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/keiserlab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-10-05T23:43:24.000Z","updated_at":"2024-05-22T04:22:49.000Z","dependencies_parsed_at":null,"dependency_job_id":"ba7fac6f-b912-4d1e-9012-c0044c577e02","html_url":"https://github.com/keiserlab/keras-neural-graph-fingerprint","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keiserlab%2Fkeras-neural-graph-fingerprint","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keiserlab%2Fkeras-neural-graph-fingerprint/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keiserlab%2Fkeras-neural-graph-fingerprint/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keiserlab%2Fkeras-neural-graph-fingerprint/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/keiserlab","download_url":"https://codeload.github.com/keiserlab/keras-neural-graph-fingerprint/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237869066,"owners_count":19379259,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["atom","differentiable-models","fingerprint","gpu","graph","graph-algorithms","keras","molecule","morgan-fingerprints","neural-networks","tensor"],"created_at":"2024-07-31T03:02:21.296Z","updated_at":"2025-10-23T17:31:40.936Z","avatar_url":"https://github.com/keiserlab.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# Keras Neural Graph Fingerprint\n\nThis repository is an implementation of [Convolutional Networks on Graphs for Learning Molecular Fingerprints][NGF-paper] in Keras.\n\nIt includes a preprocessing function to convert molecules in smiles representation\ninto molecule tensors.\n\nNext to this, it includes two custom layers for Neural Graphs in Keras, allowing\nflexible Keras fingerprint models. See [examples.py](examples.py) for an examples\n\n## Related work\n\nThere are several implementations of this paper publicly available:\n - by [HIPS][1] using autograd\n - by [debbiemarkslab][2] using theano\n - by [GUR9000] [3] using keras\n - by [ericmjl][4] using autograd\n - by [DeepChem][5] using tensorflow\n\nThe closest implementation is the implementation by GUR9000 in Keras. However this\nrepository represents moleculs in a fundamentally different way. The consequences\nare described in the sections below.\n\n## Molecule Representation\n\n### Atom, bond and edge tensors\nThis codebase uses tensor matrices to represent molecules. Each molecule is\ndescribed by a combination of the following three tensors:\n\n   - **atom matrix**, size: `(max_atoms, num_atom_features)`\n   \t This matrix defines the atom features.\n\n     Each column in the atom matrix represents the feature vector for the atom at\n     the index of that column.\n\n   - **edge matrix**, size: `(max_atoms, max_degree)`\n     This matrix defines the connectivity between atoms.\n\n     Each column in the edge matrix represent the neighbours of an atom. The\n     neighbours are encoded by an integer representing the index of their feature\n     vector in the atom matrix.\n\n     As atoms can have a variable number of neighbours, not all rows will have a\n     neighbour index defined. These entries are filled with the masking value of\n     `-1`. (This explicit edge matrix masking value is important for the layers\n     to work)\n\n   - **bond tensor** size: `(max_atoms, max_degree, num_bond_features)`\n   \t This matrix defines the atom features.\n\n   \t The first two dimensions of this tensor represent the bonds defined in the\n   \t edge tensor. The column in the bond tensor at the position of the bond index\n   \t in the edge tensor defines the features of that bond.\n\n   \t Bonds that are unused are masked with 0 vectors.\n\n\n### Batch representations\n\n This codes deals with molecules in batches. An extra dimension is added to all\n of the three tensors at the first index. Their respective sizes become:\n\n - **atom matrix**, size: `(num_molecules, max_atoms, num_atom_features)`\n - **edge matrix**, size: `(num_molecules, max_atoms, max_degree)`\n - **bond tensor** size: `(num_molecules, max_atoms, max_degree, num_bond_features)`\n\nAs molecules have different numbers of atoms, max_atoms needs to be defined for\nthe entire dataset. Unused atom columns are masked by 0 vectors.\n\n### Strong and weak points\nThe obvious downside of this representation is that there is a lot of masking,\nresulting in a waste of computation power.\n\nThe alternative is to represent the entire dataset as a bag of atoms as in the\nauthors [original implementation](https://github.com/HIPS/neural-fingerprint). For\nlarger datasets, this is infeasable. In [GUR9000's implementation] (https://github.com/GUR9000/KerasNeuralFingerprint)\nthe same approach is used, but each batch is pre-calculated as a bag of atoms.\nThe downside of this is that each epoch uses the exact same composition of batches,\ndecreasing the stochasticity. Furthermore, Keras recognises the variability in batch-\nsize and will not run. In his implementation GUR9000 included a modified version\nof Keras to correct for this.\n\nThe tensor representation used in this repository does not have these downsides,\nand allows for many modificiations of Duvenauds algorithm (there is a lot to explore).\n\nTheir representation may be optimised for the regular algorithm, but at a first\nglance, the tensor implementation seems to perform reasonably fast (check out\n[the examples](examples.py)).\n\n## NeuralGraph layers\nThe two workhorses are defined in [NGF/layers.py](NGF/layers.py).\n\n`NeuralGraphHidden` takes a set of molecules (represented by `[atoms, bonds, edges]`),\nand returns the convolved feature vectors of the higher layers. Only the feature\nvectors change at each iteration, so for higher layers only the `atom` tensor needs\nto be replaced by the convolved output of the previous `NeuralGraphHidden`.\n\n`NeuralGraphOutput` takes a set of molecules (represented by `[atoms, bonds, edges]`),\nand returns the fingerprint output for that layer. According to the [original paper][NGF-paper],\nthe fingerprints of all layers need to be summed. But these are neural nets, so\nfeel free to play around with the architectures!\n\n### Initialisation\nThe NeuralGraph layers have an internal (`Dense`) layer of the output size\n(`conv_width` for `NeuralGraphHidden` or `fp_length` for `NeuralGraphOutput`).\nThis inner layer accounts for the trainable parameters, activation function, etc.\n\nThere are three ways to initialise the inner layer and it's parameters:\n\n1. Using an integer `conv_width` and possible kwags (`Dense` layer is used)\n  ```python\n  atoms1 = NeuralGraphHidden(conv_width, activation='relu', bias=False)([atoms0, bonds, edges])\n  ```\n\n2. Using an initialised `Dense` layer\n  ```python\n  atoms1 = NeuralGraphHidden(Dense(conv_width, activation='relu', bias=False))([atoms0, bonds, edges])\n  ```\n\n3. Using a function that returns an initialised `Dense` layer\n  ```python\n  atoms1 = NeuralGraphHidden(lambda: Dense(conv_width, activation='relu', bias=False))([atoms0, bonds, edges])\n  ```\n\nIn the case of `NeuralGraphOutput`, all these three methods would be identical.\nFor `NeuralGraphHidden`, these methods are equal, but can be slightly different.\nThe reason is that a `NeuralGraphHidden` has a dense layer for each `degree`.\n\nThe following will not work for `NeuralGraphHidden`:\n```python\natoms1 = NeuralGraphHidden(conv_width, activation='relu', bias=False, W_regularizer=l2(0.01))([atoms0, bonds, edges])\n```\n\nThe reason is that the same `l2` object will be passed to each internal layer,\nwheras an `l2` object can obly be assigned to one layer.\n\nMethod 2. will work, because a new layer is instanciated based on the configuration\nof the passed layer.\n\nMethod 3. will work if a function is provided that returns a new `l2` object each\ntime it is called (as would be the case for the given lambda function).\n\n\n## NeuralGraph models\nFor convienience, two builder functions are included that can build a variety\nof Neural Graph models by specifiying it's parameters. See [NGF/models.py](NGF/models.py).\n\nThe examples in [examples.py](examples.py) should help you along the way.\nNGF\nYou can store and load the trained models. Make sure to specify the custom classes:\n```python\nmodel = load_model('model.h5', custom_objects={'NeuralGraphHidden':NeuralGraphHidden, 'NeuralGraphOutput':NeuralGraphOutput})\n```\n\n## Dependencies\n- [**RDKit**](http://www.rdkit.org/) This dependency is nescecairy to convert molecules into tensor\nrepresentatins, once this step is conducted, the new data can be stored, and RDkit\nis no longer a dependency.\n- [**Keras**](https://keras.io/) Requires keras 1.x for building, training and evaluating the models.\n- [**NumPy**](http://www.numpy.org/)\n\n## Acknowledgements\n- Implementation is based on [Duvenaud et al., 2015][NGF-paper].\n- Feature extraction scripts were copied from [the original implementation][1]\n- Data preprocessing scripts were copied from [GRU2000][3]\n- The usage of the Keras functional API was inspired by [GRU2000][3]\n- Graphpool layer adopted from [Han, et al., 2016][DeepChem-paper]\n\n[NGF-paper]: https://arxiv.org/abs/1509.09292\n[DeepChem-paper]:https://arxiv.org/abs/1611.03199\n[keiserlab]: //http://www.keiserlab.org/\n[1]: https://github.com/HIPS/neural-fingerprint\n[2]: https://github.com/debbiemarkslab/neural-fingerprint-theano\n[3]: https://github.com/GUR9000/KerasNeuralFingerprint\n[4]: https://github.com/ericmjl/graph-fingerprint\n[5]: https://github.com/deepchem/deepchem","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkeiserlab%2Fkeras-neural-graph-fingerprint","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkeiserlab%2Fkeras-neural-graph-fingerprint","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkeiserlab%2Fkeras-neural-graph-fingerprint/lists"}