Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
371e87a
Merge pull request #11 from hariszaf/develop
danielriosgarza May 22, 2023
fcad7da
Update example.ipynb
Biomerene Nov 3, 2023
eb9e5c9
first attempt
Biomerene Nov 3, 2023
b9e807c
there is a problem with _r vs _rv related to the removed bigg fix
Biomerene Nov 3, 2023
92aa6f1
Discovered a (unlikely) bug related to predicting non existant reactions
Biomerene Nov 15, 2023
7567e8c
related to the other _r vs _rv
Biomerene Nov 15, 2023
e6ecd4c
Merge branch 'Biomerene-patch-1' of https://github.com/MGXlab/DNNGIOR…
Biomerene Nov 15, 2023
ebe0087
Merge pull request #21 from MGXlab/Biomerene-patch-1
Biomerene Nov 17, 2023
b52b109
copied from MSEED_compounds
Biomerene Nov 17, 2023
2c0ab2b
made a change to not include exchange reactions in db reactions
Biomerene Nov 17, 2023
eb60862
script to create exchanges model
Biomerene Nov 23, 2023
1671227
moved to dnngior
Biomerene Nov 23, 2023
e14475b
readded bigg database
Biomerene Nov 23, 2023
178dbe1
model with exchanges
Biomerene Nov 23, 2023
69c58c7
slight cleanup
Biomerene Nov 23, 2023
35c41cd
renamed to distinguish between modelseed and BiGG
Biomerene Feb 7, 2024
61b8e08
commandline tool to build models from genomes
Biomerene Feb 7, 2024
555f0d1
test scripts
Biomerene Feb 7, 2024
0296a32
version control is hard
Biomerene Feb 7, 2024
9e78ab1
Commandline tool to build models from genomes
Biomerene Feb 7, 2024
6d8c8d1
added a blacklist and greylist option
Biomerene Feb 7, 2024
297a32d
Changed from direction to reversibility column for the modelseed
Biomerene Feb 7, 2024
370a916
made some changes to the loading of BiGG
Biomerene Feb 7, 2024
8df6406
removed space
Biomerene Feb 7, 2024
4d756ae
removed some modelseed default
Biomerene Feb 7, 2024
b996749
changed name
Biomerene Feb 7, 2024
173951e
lazy loading to avoid having to load everything if you want help
Biomerene Feb 7, 2024
a98b1cb
changed name
Biomerene Feb 7, 2024
c24c922
faa of fasta, idc
Biomerene Feb 7, 2024
b8bd592
please ignore, not doing this right
Biomerene Feb 7, 2024
ed4064c
doing the lazy loading different, needs to be within function
Biomerene Feb 7, 2024
9b79696
added some printed info
Biomerene Feb 8, 2024
dbe740d
fixed mistake in name exchanges
Biomerene Feb 8, 2024
0a69e83
rewrote the test script a bit to work within the git folder
Biomerene Feb 8, 2024
5cd1574
too see if the right class gets loaded, should be removed later
Biomerene Feb 8, 2024
02755f9
Refinement is only for modelseed atm, could be implemented for bigg here
Biomerene Feb 8, 2024
421e6a1
needs to know modeltype for refinement
Biomerene Feb 8, 2024
f30c83a
tempname is not very informative
Biomerene Feb 8, 2024
65c635e
Update addBGExchanges.py
Biomerene Feb 8, 2024
5be65fe
Update addExchanges.py
Biomerene Feb 8, 2024
5c2bf9f
test files removed
Biomerene Feb 8, 2024
d3999cd
Merge branch 'develop' of https://github.com/MGXlab/DNNGIOR into develop
Biomerene Feb 8, 2024
f166dbc
adjusted message
Biomerene Feb 8, 2024
0e5f438
removed unused file
Biomerene Feb 8, 2024
71cf22e
renamed command exp command line tool
Biomerene Feb 8, 2024
8526675
added some logging, and a check to avoid rebuilding the same models
Biomerene Apr 24, 2024
38a9a40
readded some functionality and a check to see if you have the right n…
Biomerene Apr 24, 2024
a1b841d
changed saving a little, added some comments. I need to check import.
Biomerene Apr 24, 2024
eceed7b
Little more explanation, custom networks in line with resubmission
Biomerene Jun 11, 2024
f486b3e
small change hoping to reduce complaints (does not seem to work)
Biomerene Jun 11, 2024
9abc6ca
update to loading different networks
Biomerene Jun 11, 2024
e866190
mismatch remediation, should remove some hassle
Biomerene Jun 11, 2024
608042b
change default Save to True
Biomerene Jun 11, 2024
3f8720c
It actually also works with .gz files
Biomerene Jun 11, 2024
a7f5fde
Function to make it easier to load a medium
Biomerene Jun 11, 2024
ebeef88
some more functionality
Biomerene Jun 11, 2024
5ec0d00
These are doubles, not required
Biomerene Jun 11, 2024
a4c4050
renamed tutorial
Biomerene Jun 11, 2024
1890b2a
moved training example
Biomerene Jun 11, 2024
3373af7
not sure what the function of this file is?
Biomerene Jun 11, 2024
9770085
update to also test NN training
Biomerene Jun 11, 2024
715805d
This was double
Biomerene Jun 11, 2024
2f6d493
changed return_lite to return_full and swapped default
Biomerene Jun 11, 2024
5714876
only one function neccesary
Biomerene Jun 11, 2024
916bc84
split medium and medium_file
Biomerene Jun 12, 2024
bd72b60
some additional testing
Biomerene Jun 12, 2024
83bc8c0
updating the tutorial
Biomerene Jun 12, 2024
5ddb294
trying to merge to avoid future issues
Biomerene Jun 12, 2024
41a5280
added a suffix parameter and made the strings f and slightly more con…
Biomerene Aug 27, 2024
247a78c
updated tutorial to include blacklists
Biomerene Sep 5, 2024
8b49573
new option to load medium file using CLI
Biomerene Sep 5, 2024
c1dc4b4
save media filename to data file
Biomerene Sep 11, 2024
610ae0d
broke the testscript while trying to stage blocks
Biomerene Sep 30, 2024
1632247
transfer annotation from draftmodel to gapfilled model
Biomerene Sep 30, 2024
ac1318f
some small additional comments
Biomerene Oct 4, 2024
66afa3d
Caught an exception for when you blacklist reactions that are part of…
Biomerene Oct 4, 2024
aeab2bc
updated the example notebook with some of the new features
Biomerene Oct 4, 2024
9d3fa92
Merge branch 'main' into develop
hariszaf Oct 4, 2024
92b3153
updated help text, added model suffix option and fixed checks, added …
Biomerene Nov 15, 2024
2412c15
added a part about the command line interface and cleaned up the outp…
Biomerene Nov 29, 2024
e886a8e
replaced preprint link with link to publication
Biomerene Nov 29, 2024
df8b73b
merged diversion main into develop
Biomerene Nov 29, 2024
d0e680b
removed old tutorial in the wrong place
Biomerene Nov 29, 2024
c1f2d2e
added some missing parts, improved some explanations
Biomerene Nov 29, 2024
f44b3d6
fixed broken link and changed debug message
Biomerene Nov 29, 2024
49beebc
added space
Biomerene Feb 21, 2025
c98534a
added comments explaining functions and updated error message
Biomerene Feb 21, 2025
442d04b
moved tensorflow specific log config to
Biomerene Feb 21, 2025
d7bf238
updated some comments for clarity
Biomerene Feb 26, 2025
0dd1995
fixed return raised in issue #8
Biomerene Feb 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import dnngior.gapfill_class.Gapfill
Gapfill(path_to_model)
```

You may find examples of gap-filling a genome scale reconstruction (GEM) with `dnngior` with a complete or a defined medium in this [example notebook](tutorials/example.ipynb). `dnngior` can gapfill both ModelSEED and BiGG models, to gapfill BiGG models you need to specify modeltype.
You may find examples of gap-filling a genome scale reconstruction (GEM) with `dnngior` with a complete or a defined medium in this [example notebook](tutorials/gapfilling_example.ipynb). `dnngior` can gapfill both ModelSEED and BiGG models, to gapfill BiGG models you need to specify modeltype.

```python
Gapfill(path_to_BiGG_model, modeltype='BiGG')
Expand All @@ -48,12 +48,13 @@ Alternatively you can find additional custom Neural Networks for several taxonom

## License


Please see [License](LICENSE)


## Cite

The paper that will accompany the tool is currrently available as preprint:\
https://www.biorxiv.org/content/10.1101/2023.07.10.548314v2
The paper that will accompany the tool is can be found here:\
https://www.cell.com/iscience/fulltext/S2589-0042(24)02574-4


2 changes: 1 addition & 1 deletion dnngior/MSEED_reactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ def parseStoichOnt(self, stoichiometry):

#For empty reaction
if(stoichiometry == ""):
return rxn_cpds_array
return rxn_cpds_dict

for rgt in stoichiometry.split(";"):
(coeff, cpd, cpt, index, name) = rgt.split(":", 4)
Expand Down
38 changes: 32 additions & 6 deletions dnngior/NN_Predictor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,40 @@
import pandas as pd
import cobra.core.model as cobra_model
from dnngior.reaction_class import Reaction
from dnngior.variables import *
import os
import sys
from math import exp
from pathlib import Path

class NN:
def __init__(self, modeltype=None, path=None, custom=None):
def __init__(self, path=None, modeltype=None, custom=None):
'''
Light version of the model, saves space, uses only numpy and cobra and no tensorflow
'''

self.path=path
self.__get_pseudo_network()
if custom:
self.network = custom[0]
self.modeltype = custom[1]
self.rxn_keys = custom[2]
else:
if path:
self.path=path

elif modeltype:
if modeltype == 'ModelSEED':
self.path = TRAINED_NN_MSEED
elif modeltype == 'BiGG':

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Biomerene do we know support BiGG all the way through? 😃

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gap-filling BiGG models should work now yes, the models do not get refined based on the aliases (which are part of the ModelSEED database). See also my comment on the refinement in the model build (#26 (comment)).

self.path = TRAINED_NN_BIGG
else:
print("Modeltype: {} not recognized, defaulting to ModelSEED".format(modeltype))
self.path = TRAINED_NN_MSEED
else:
print("No path or modeltype provided, defaulting to ModelSEED")
self.path = TRAINED_NN_MSEED
self.__get_pseudo_network()




#Function that loads the Neural network; path is path to .h5 file
Expand Down Expand Up @@ -53,10 +74,10 @@ def predict(self, input):
#check if reaction class
input2 = self.__convert_reaction_list(set(input.reactions))
elif isinstance(input, pd.DataFrame):
input.reindex(self.rxn_keys)
input1b = input.reindex(self.rxn_keys).fillna(0.0)
df_columns = input.columns
#Transpose because rows need to be different models for the network
input2 = np.asarray(input.T)
input2 = np.asarray(input1b.T)
elif isinstance(input, dict):
#check if dictionary, get list of reactions and convert
input2 = self.__convert_reaction_list([i for i in input if input[i]==1])
Expand All @@ -75,6 +96,9 @@ def predict(self, input):
else:
single_input=False

if not input2.shape[1] == self.network[0][0].shape[0]:
raise Exception("Input size ({}) does not match network ({})".format(input2.shape[1], len(self.rxn_keys)))

a = input2
for layer in self.network:
a = a.clip(0)
Expand All @@ -85,6 +109,8 @@ def predict(self, input):
prediction = dict(zip(self.rxn_keys, np.squeeze(prediction)))
if isinstance(input, pd.DataFrame):
prediction = pd.DataFrame(index=self.rxn_keys, columns=df_columns, data=prediction.T)
if len(prediction.index) != len(input.index):
print('Warning mismatch input vs prediction ({})'.format(len(prediction.index) - len(input.index)))
return prediction

#function that generates a binary input based on a list of reaction ids
Expand All @@ -106,7 +132,7 @@ def __convert_reaction_list(self, reaction_set):
b_input.append(1)
else:
b_input.append(0)
print("#reactions not found in keys: ", len(set(reaction_set)) - sum(b_input), '/', len(reaction_set))
print("#reactions not found in NN-keys: ", len(set(reaction_set)) - sum(b_input), '/', len(reaction_set))
except:
raise Exception("Conversion failed")

Expand Down
67 changes: 45 additions & 22 deletions dnngior/NN_Trainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import sys
from tensorflow import compat, config, dtypes

import dnngior.NN_Predictor
from dnngior.NN_Predictor import NN

# Tensorflow; please consider: https://www.tensorflow.org/api_docs/python/tf/compat/v1/disable_eager_execution
compat.v1.disable_eager_execution()
Expand All @@ -31,7 +31,7 @@ def noise_data(i, noise_0, noise_1, del_p, con_p):
----------
i : numpy array, required
an array of 0s and 1s which you want to noisify
noise_0 : numpy array, required
noise_0 : numpy array, requiredimport dnngior.NN_Predictor
fraction of 0s to change to 1s
noise_1 : numpy array, required
fraction of 1s to change to 0s
Expand Down Expand Up @@ -73,7 +73,7 @@ def noise_data(i, noise_0, noise_1, del_p, con_p):
o = temp
return o

def generate_training_set(data,nuplo, min_con, max_con, min_for, max_for, del_p, con_p):
def generate_feature(data, nuplo, min_con, max_con, min_for, max_for, del_p, con_p):
"""
Function to generate the dataset for training (feature).
PARAMETERS:
Expand Down Expand Up @@ -150,7 +150,7 @@ def custom_loss(y_true, y_pred): #y_true is the label, y_pred is the prediction
return bias*(1-y_true)*loss+(1-bias)*y_true*loss # return the biased loss y_true are all cases where prediction shouold be 1, 1-y_true all cases where prediction should be one, can scale between these two classes
return custom_loss

def train(data, modeltype,rxn_keys=None,labels = None,validation_split=0.0,nuplo=30, min_con=0, max_con=0, min_for=0.05, max_for=0.3, con_p=None, del_p = None, nlayers=1, nnodes=256, nepochs=10, b_size=32, dropout=0.1, bias_0=0.3, maskI=True, save=False, name='noname', output_path='', return_history=False):
def train(data, modeltype,rxn_keys=None,labels = None,validation_split=0.0,nuplo=30, min_con=0, max_con=0, min_for=0.05, max_for=0.3, con_p=None, del_p = None, nlayers=1, nnodes=256, nepochs=10, b_size=32, dropout=0.1, bias_0=0.3, maskI=True, save=True, output_path='dnngior_predictor.npz', return_history=False, return_full_network=False):
"""
Most important function, creates actual NN, there are many optional parameters

Expand All @@ -168,7 +168,7 @@ def train(data, modeltype,rxn_keys=None,labels = None,validation_split=0.0,nuplo

TRAINING PARAMETERS:
-------
see generate_training_set() ^
see generate_feature() ^

NETWORK PARAMETERS
-------------
Expand Down Expand Up @@ -200,39 +200,57 @@ def train(data, modeltype,rxn_keys=None,labels = None,validation_split=0.0,nuplo
SAVING PARAMETERS:

save: boolean, optional
Whether you want to save the network, default = False
name: string, optional
name of your network, default='noname'
Whether you want to save the network, default = True
output_path: string,
where output, default=''
Where to save the network, file_extension that work are .h5 and .npz
all other file_extensions defailt to npz (lite network)
default='dnngior_predictor.npz'

OPTIONAL RETURNS:

return_history: boolean, optional
If you want training history

default = False
return_full_network: boolean, optional
if you want to return the lite_network or full tensorflow object
default = False
Returns:
-------------
trainedNN
NN class containing network, rxn_keys and modeltype
history: type, if history=True
history: if history=True
history of training
"""

print("Num GPUs Available: ", len(config.list_physical_devices('GPU')))

if os.path.exists(output_path):
print("# WARNING: overwriting savefile")
elif os.access(os.path.dirname(output_path), os.W_OK):
print("Saving network at: {}".format(output_path))
else:
Exception("Can not save at: {}".format(output_path))

if(isinstance(data, pd.DataFrame)):
rxn_keys = data.index
ndata = np.asarray(data, dtype=np.float32).T
elif rxn_keys is None:
raise(Exception('Provide DataFrame or rxn_keys'))

#create feature and labels from training data
#create feature from training data
if(labels is None):
labels = np.repeat(np.copy(ndata), nuplo, axis=0).astype(np.float32)
feature = np.repeat(np.copy(ndata), nuplo, axis=0).astype(np.float32)
print('using data as labels')
else:
labels = np.repeat(np.copy(labels), nuplo, axis=0).astype(np.float32)
if(isinstance(labels, pd.DataFrame)):
rxn_keys = data.index
nlabels = np.asarray(labels, dtype=np.float32).T
else:
nlabels = labels.astype(np.float32).T
feature = np.repeat(np.copy(nlabels), nuplo, axis=0).astype(np.float32)
print("using user provided labels")

train_data = generate_training_set(ndata, nuplo, min_con, max_con, min_for, max_for, del_p, con_p)
train_data = generate_feature(ndata, nuplo, min_con, max_con, min_for, max_for, del_p, con_p)

print('dataset created')
nmodels, nreactions = ndata.shape
Expand All @@ -253,23 +271,28 @@ def train(data, modeltype,rxn_keys=None,labels = None,validation_split=0.0,nuplo
#print summary of model
network.summary()
#train model, history can be used to observe training
history = network.fit(train_data, labels, validation_split = validation_split, epochs = nepochs, shuffle=True, batch_size = b_size, verbose=1)
history = network.fit(train_data, feature, validation_split = validation_split, epochs = nepochs, shuffle=True, batch_size = b_size, verbose=1)
pseudo_network = []
for i in range(0, len(network.layers),2):
pseudo_network.append(network.layers[i].get_weights())
pseudo_network = np.asarray(pseudo_network, dtype=object)
#save Network
if(save):
if(save == 'h5'):
network_path = os.path.join(output_path, "{}.h5".format(name))
with h5py.File(model_path, mode='w') as f:
if(output_path.endswith('.h5')):
with h5py.File(output_path, mode='w') as f:
network.save(f)
f.attrs['modeltype'] = modeltype
f.create_dataset("rxn_keys", data =[n.encode("ascii", "ignore") for n in rxn_keys])
else:
network_path = os.path.join(output_path, "{}.npz".format(name))
np.savez(network_path,network=pseudo_network, modeltype=modeltype,rxn_keys=rxn_keys)
trainedNN = NN_Predictor.NN(custom=[pseudo_network,rxn_keys,modeltype])
if not output_path.endswith('.npz'):
file_extension = output_path.split('.')[-1]
print('{} not recognized, saving as .npz (lite) instead'.format(file_extension))
output_path.replace(file_extension, '.npz')
np.savez(output_path,network=pseudo_network, modeltype=modeltype,rxn_keys=rxn_keys)
if return_full_network:
trainedNN = NN(custom=[network,modeltype,rxn_keys])
else:
trainedNN = NN(custom=[pseudo_network,modeltype,rxn_keys])
if return_history:
return trainedNN, history
else:
Expand Down
Loading