decimer 2.2.2__tar.gz → 2.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. {decimer-2.2.2 → decimer-2.5.0}/DECIMER/Efficient_Net_encoder.py +7 -26
  2. decimer-2.5.0/DECIMER/Predictor_usingCheckpoints.py +275 -0
  3. {decimer-2.2.2 → decimer-2.5.0}/DECIMER/Repack_model.py +71 -21
  4. decimer-2.5.0/DECIMER/Transformer_decoder.py +210 -0
  5. {decimer-2.2.2 → decimer-2.5.0}/DECIMER/Utils/Create_TFrecord_From_pickles.py +3 -4
  6. {decimer-2.2.2 → decimer-2.5.0}/DECIMER/Utils/Create_image_tokenizer.py +3 -4
  7. {decimer-2.2.2 → decimer-2.5.0}/DECIMER/__init__.py +3 -4
  8. {decimer-2.2.2 → decimer-2.5.0}/DECIMER/config.py +80 -84
  9. {decimer-2.2.2 → decimer-2.5.0}/DECIMER/decimer.py +66 -21
  10. {decimer-2.2.2 → decimer-2.5.0}/DECIMER/efficientnetv2/effnetv2_configs.py +2 -1
  11. {decimer-2.2.2 → decimer-2.5.0}/DECIMER/efficientnetv2/effnetv2_model.py +5 -5
  12. {decimer-2.2.2 → decimer-2.5.0}/DECIMER/efficientnetv2/hparams.py +4 -1
  13. {decimer-2.2.2 → decimer-2.5.0}/DECIMER/efficientnetv2/utils.py +81 -29
  14. {decimer-2.2.2 → decimer-2.5.0}/DECIMER/utils.py +30 -0
  15. {decimer-2.2.2/decimer.egg-info → decimer-2.5.0}/PKG-INFO +5 -5
  16. {decimer-2.2.2 → decimer-2.5.0}/README.md +1 -1
  17. {decimer-2.2.2 → decimer-2.5.0/decimer.egg-info}/PKG-INFO +5 -5
  18. {decimer-2.2.2 → decimer-2.5.0}/decimer.egg-info/SOURCES.txt +2 -3
  19. {decimer-2.2.2 → decimer-2.5.0}/decimer.egg-info/requires.txt +3 -1
  20. {decimer-2.2.2 → decimer-2.5.0}/setup.py +15 -5
  21. decimer-2.2.2/DECIMER/Predictor_EfficientNet2.py +0 -160
  22. decimer-2.2.2/DECIMER/Transformer_decoder.py +0 -445
  23. decimer-2.2.2/tests/test_functions.py +0 -10
  24. {decimer-2.2.2 → decimer-2.5.0}/DECIMER/DECIMER_EfficinetNetV2_Transfomer_Trainer.py +8 -8
  25. {decimer-2.2.2 → decimer-2.5.0}/LICENSE +0 -0
  26. {decimer-2.2.2 → decimer-2.5.0}/decimer.egg-info/dependency_links.txt +0 -0
  27. {decimer-2.2.2 → decimer-2.5.0}/decimer.egg-info/top_level.txt +0 -0
  28. {decimer-2.2.2 → decimer-2.5.0}/setup.cfg +0 -0
@@ -1,37 +1,25 @@
1
1
  # EfficientNet-V2 config
2
2
  import tensorflow as tf
3
- import DECIMER.efficientnetv2 as efficientnetv2
3
+
4
+ import DECIMER.efficientnetv2
5
+ from DECIMER.efficientnetv2 import effnetv2_configs
6
+ from DECIMER.efficientnetv2 import effnetv2_model
4
7
 
5
8
  BATCH_SIZE_DEBUG = 2
6
- MODEL = "efficientnetv2-b3" # @param
9
+ MODEL = "efficientnetv2-m" # @param
7
10
 
8
11
 
9
12
  # Define encoder
10
13
  def get_efficientnetv2_backbone(
11
- model_name, include_top=False, input_shape=(299, 299, 3), pooling=None, weights=None
14
+ model_name, include_top=False, input_shape=(512, 512, 3), pooling=None, weights=None
12
15
  ):
13
- """Initiate and get the desired Efficient-Net V2 backbone as encoder
14
-
15
- Args:
16
- model_name (str): Name of the Efficient-Net V2 model
17
- include_top (bool, optional): Defaults to False.
18
- input_shape (tuple, optional): Image shape. Defaults to (299, 299, 3).
19
- pooling (int, optional): Max pooling values. Defaults to None.
20
- weights ( optional): Pretrained weights. Defaults to None.
21
-
22
- Raises:
23
- NotImplementedError: At this time we only want to use the raw
24
-
25
- Returns:
26
- Efficient Net V2 backbone
27
- """
28
16
  # Catch unsupported arguments
29
17
  if pooling or weights or include_top:
30
18
  raise NotImplementedError(
31
19
  "\n...At this time we only want to use the raw "
32
20
  "(no pretraining), headless, features with no pooling ...\n"
33
21
  )
34
- backbone = efficientnetv2.effnetv2_model.EffNetV2Model(model_name=model_name)
22
+ backbone = effnetv2_model.EffNetV2Model(model_name=model_name)
35
23
  backbone(
36
24
  tf.ones((BATCH_SIZE_DEBUG, *input_shape)), training=False, features_only=True
37
25
  )
@@ -39,12 +27,6 @@ def get_efficientnetv2_backbone(
39
27
 
40
28
 
41
29
  class Encoder(tf.keras.Model):
42
- """Encoder class
43
-
44
- Args:
45
- tf (_type_): tensorflow model module
46
- """
47
-
48
30
  def __init__(
49
31
  self,
50
32
  image_embedding_dim,
@@ -56,7 +38,6 @@ class Encoder(tf.keras.Model):
56
38
  pretrained_weights=None,
57
39
  scale_factor=0,
58
40
  ):
59
-
60
41
  super(Encoder, self).__init__()
61
42
 
62
43
  self.image_embedding_dim = image_embedding_dim
@@ -0,0 +1,275 @@
1
+ import os
2
+ import pickle
3
+ import sys
4
+ from typing import List
5
+ from typing import Tuple
6
+
7
+ import pystow
8
+ import tensorflow as tf
9
+ import Transformer_decoder
10
+
11
+ if int(tf.__version__.split(".")[1]) <= 10:
12
+ import Efficient_Net_encoder
13
+ else:
14
+ raise ImportError("Please use tensorflow 2.10 when working with the checkpoints.")
15
+ import config
16
+ import utils
17
+
18
+ print(tf.__version__)
19
+
20
+ # Set GPU
21
+ os.environ["CUDA_VISIBLE_DEVICES"] = ""
22
+ """
23
+ gpus = tf.config.experimental.list_physical_devices("GPU")
24
+ for gpu in gpus:
25
+ tf.config.experimental.set_memory_growth(gpu, True)
26
+ """
27
+ # Set path
28
+ default_path = pystow.join("DECIMER-V2")
29
+
30
+ # model download location
31
+ checkpoint_url = "https://zenodo.org/record/8093783/files/DECIMER_512_checkpoints.zip"
32
+ checkpoint_path = str(default_path) + "/DECIMER_checkpoints/"
33
+
34
+ if not os.path.exists(checkpoint_path):
35
+ config.download_trained_weights(checkpoint_url, default_path)
36
+
37
+ # load assets
38
+
39
+ tokenizer = pickle.load(
40
+ open(
41
+ default_path.as_posix() + "/DECIMER_model/assets/tokenizer_SMILES.pkl",
42
+ "rb",
43
+ )
44
+ )
45
+
46
+ max_length = 302
47
+
48
+ # Image partameters
49
+ IMG_EMB_DIM = (16, 16, 512)
50
+ IMG_EMB_DIM = (IMG_EMB_DIM[0] * IMG_EMB_DIM[1], IMG_EMB_DIM[2])
51
+ IMG_SHAPE = (512, 512, 3)
52
+ PE_INPUT = IMG_EMB_DIM[0]
53
+ IMG_SEQ_LEN, IMG_EMB_DEPTH = IMG_EMB_DIM
54
+ D_MODEL = 512
55
+
56
+ # Network parameters
57
+ N_LAYERS = 6
58
+ D_MODEL = 512
59
+ D_FF = 2048
60
+ N_HEADS = 8
61
+ DROPOUT_RATE = 0.1
62
+
63
+ # Misc
64
+ MAX_LEN = max_length
65
+ VOCAB_LEN = len(tokenizer.word_index)
66
+ PE_OUTPUT = MAX_LEN
67
+ TARGET_V_SIZE = VOCAB_LEN
68
+ REPLICA_BATCH_SIZE = 1
69
+
70
+ # Config Encoder
71
+ PREPROCESSING_FN = tf.keras.applications.efficientnet.preprocess_input
72
+ BB_FN = Efficient_Net_encoder.get_efficientnetv2_backbone
73
+
74
+ # Config Model
75
+ testing_config = config.Config()
76
+
77
+ testing_config.initialize_encoder_config(
78
+ image_embedding_dim=IMG_EMB_DIM,
79
+ preprocessing_fn=PREPROCESSING_FN,
80
+ backbone_fn=BB_FN,
81
+ image_shape=IMG_SHAPE,
82
+ do_permute=IMG_EMB_DIM[1] < IMG_EMB_DIM[0],
83
+ )
84
+ testing_config.initialize_transformer_config(
85
+ vocab_len=VOCAB_LEN,
86
+ max_len=MAX_LEN,
87
+ n_transformer_layers=N_LAYERS,
88
+ transformer_d_dff=D_FF,
89
+ transformer_n_heads=N_HEADS,
90
+ image_embedding_dim=D_MODEL,
91
+ )
92
+
93
+ # print(f"Encoder config:\n\t -> {testing_config.encoder_config}\n")
94
+ # print(f"Transformer config:\n\t -> {testing_config.transformer_config}\n")
95
+
96
+ # Prepare model
97
+ optimizer, encoder, transformer = config.prepare_models(
98
+ encoder_config=testing_config.encoder_config,
99
+ transformer_config=testing_config.transformer_config,
100
+ replica_batch_size=REPLICA_BATCH_SIZE,
101
+ verbose=0,
102
+ )
103
+
104
+ # Load trained model checkpoint
105
+ ckpt = tf.train.Checkpoint(
106
+ encoder=encoder, transformer=transformer, optimizer=optimizer
107
+ )
108
+ ckpt_manager = tf.train.CheckpointManager(ckpt, checkpoint_path, max_to_keep=50)
109
+ if ckpt_manager.latest_checkpoint:
110
+ ckpt.restore(tf.train.latest_checkpoint(checkpoint_path))
111
+ start_epoch = int(ckpt_manager.latest_checkpoint.split("-")[-1])
112
+
113
+
114
+ def main():
115
+ if len(sys.argv) != 2:
116
+ print("Usage: {} $image_path".format(sys.argv[0]))
117
+ else:
118
+ SMILES = predict_SMILES(sys.argv[1])
119
+ print(SMILES)
120
+ SMILES_with_confidence = predict_SMILES_with_confidence(sys.argv[1])
121
+ for tup in SMILES_with_confidence:
122
+ print(tup)
123
+
124
+
125
+ class DECIMER_Predictor(tf.Module):
126
+ def __init__(self, encoder, tokenizer, transformer, max_length):
127
+ self.encoder = encoder
128
+ self.tokenizer = tokenizer
129
+ self.transformer = transformer
130
+ self.max_length = max_length
131
+
132
+ def __call__(self, Decoded_image):
133
+ """
134
+ Run the DECIMER predictor model when called.
135
+ Usage of predict_SMILES or predict_SMILES_with_confidence is recommended instead
136
+
137
+ Args:
138
+ Decoded_image (_type_): output of config.decode_image
139
+
140
+ Returns:
141
+ Tuple[tf.Tensor, tf.Tensor]: predicted tokens, confidence values
142
+ """
143
+ assert isinstance(Decoded_image, tf.Tensor)
144
+
145
+ _image_batch = tf.expand_dims(Decoded_image, 0)
146
+ _image_embedding = encoder(_image_batch, training=False)
147
+
148
+ start_token = tf.cast(
149
+ tf.convert_to_tensor([tokenizer.word_index["<start>"]]), tf.int32
150
+ )
151
+ end_token = tf.cast(
152
+ tf.convert_to_tensor([tokenizer.word_index["<end>"]]), tf.int32
153
+ )
154
+
155
+ output_array = tf.TensorArray(dtype=tf.int32, size=0, dynamic_size=True)
156
+ output_array = output_array.write(0, start_token)
157
+ confidence_array = tf.TensorArray(dtype=tf.float32, size=0, dynamic_size=True)
158
+
159
+ for t in tf.range(max_length):
160
+ output = tf.transpose(output_array.stack())
161
+ combined_mask = Transformer_decoder.create_masks_decoder(output)
162
+
163
+ # predictions.shape == (batch_size, seq_len, vocab_size)
164
+ prediction_batch = transformer(
165
+ output, _image_embedding, training=False, look_ahead_mask=combined_mask
166
+ )
167
+
168
+ # select the last word from the seq_len dimension
169
+ predictions = prediction_batch[:, -1:, :] # (batch_size, 1, vocab_size)
170
+
171
+ predicted_id = tf.cast(tf.argmax(predictions, axis=-1), tf.int32)
172
+ confidence = predictions[-1][-1][int(predicted_id)]
173
+ output_array = output_array.write(t + 1, predicted_id[0])
174
+ confidence_array = confidence_array.write(t + 1, confidence)
175
+ if predicted_id == end_token:
176
+ break
177
+ output = tf.transpose(output_array.stack())
178
+
179
+ return output, confidence_array.stack()
180
+
181
+
182
+ def detokenize_output(predicted_array: tf.Tensor) -> str:
183
+ """
184
+ This function takes the predicted array of tokens and returns the predicted SMILES
185
+ string.
186
+
187
+ Args:
188
+ predicted_array (tf.Tensor): Transformer Decoder output array (predicted tokens)
189
+
190
+ Returns:
191
+ str: SMILES string
192
+ """
193
+ outputs = [tokenizer.index_word[i] for i in predicted_array[0].numpy()]
194
+ prediction = (
195
+ "".join([str(elem) for elem in outputs])
196
+ .replace("<start>", "")
197
+ .replace("<end>", "")
198
+ )
199
+ return prediction
200
+
201
+
202
+ def detokenize_output_add_confidence(
203
+ predicted_array: tf.Tensor,
204
+ confidence_array: tf.Tensor,
205
+ ) -> List[Tuple[str, float]]:
206
+ """
207
+ This function takes the predicted array of tokens as well as the confidence values
208
+ returned by the Transformer Decoder and returns a list of tuples
209
+ that contain each token of the predicted SMILES string and the confidence
210
+ value.
211
+
212
+ Args:
213
+ predicted_array (tf.Tensor): Transformer Decoder output array (predicted tokens)
214
+
215
+ Returns:
216
+ str: SMILES string
217
+ """
218
+ prediction_with_confidence = [
219
+ (
220
+ tokenizer.index_word[predicted_array[0].numpy()[i]],
221
+ confidence_array[i].numpy(),
222
+ )
223
+ for i in range(len(confidence_array))
224
+ ]
225
+ decoded_prediction_with_confidence = list(
226
+ [(utils.decoder(tok), conf) for tok, conf in prediction_with_confidence[1:-1]]
227
+ )
228
+ decoded_prediction_with_confidence.append(prediction_with_confidence[-1])
229
+ return decoded_prediction_with_confidence
230
+
231
+
232
+ # Initiate the DECIMER class
233
+ DECIMER = DECIMER_Predictor(encoder, tokenizer, transformer, MAX_LEN)
234
+
235
+
236
+ def predict_SMILES_with_confidence(image_path: str) -> List[Tuple[str, float]]:
237
+ """
238
+ This function takes an image path (str) and returns a list of tuples
239
+ that contain each token of the predicted SMILES string and the confidence
240
+ level from the last layer of the Transformer decoder.
241
+
242
+ Args:
243
+ image_path (str): Path of chemical structure depiction image
244
+
245
+ Returns:
246
+ (List[Tuple[str, float]]): Tuples that contain the tokens and the confidence
247
+ values of the predicted SMILES
248
+ """
249
+ decodedImage = config.decode_image(image_path)
250
+ predicted_tokens, confidence_values = DECIMER(tf.constant(decodedImage))
251
+ predicted_SMILES_with_confidence = detokenize_output_add_confidence(
252
+ predicted_tokens, confidence_values
253
+ )
254
+ return predicted_SMILES_with_confidence
255
+
256
+
257
+ def predict_SMILES(image_path: str) -> str:
258
+ """
259
+ This function takes an image path (str) and returns the SMILES
260
+ representation of the depicted molecule (str).
261
+
262
+ Args:
263
+ image_path (str): Path of chemical structure depiction image
264
+
265
+ Returns:
266
+ (str): SMILES representation of the molecule in the input image
267
+ """
268
+ decodedImage = config.decode_image(image_path)
269
+ predicted_tokens, _ = DECIMER(tf.constant(decodedImage))
270
+ predicted_SMILES = utils.decoder(detokenize_output(predicted_tokens))
271
+ return predicted_SMILES
272
+
273
+
274
+ if __name__ == "__main__":
275
+ main()
@@ -1,10 +1,13 @@
1
1
  import os
2
+ import pickle
3
+ from typing import List
4
+ from typing import Tuple
5
+
2
6
  import tensorflow as tf
3
7
 
4
- import pickle
5
- import Transformer_decoder
6
- import Efficient_Net_encoder
7
- import config
8
+ import DECIMER.config as config
9
+ import DECIMER.Efficient_Net_encoder as Efficient_Net_encoder
10
+ import DECIMER.Transformer_decoder as Transformer_decoder
8
11
 
9
12
  print(tf.__version__)
10
13
 
@@ -15,19 +18,19 @@ for gpu in gpus:
15
18
  tf.config.experimental.set_memory_growth(gpu, True)
16
19
 
17
20
  # load assets
18
- tokenizer = pickle.load(open("tokenizer_TPU_Stereo.pkl", "rb"))
19
- max_length = pickle.load(open("max_length_TPU_Stereo.pkl", "rb"))
21
+ tokenizer = pickle.load(open("tokenizer.pkl", "rb"))
22
+ max_length = pickle.load(open("max_length.pkl", "rb"))
20
23
 
21
24
  # Image parameters
22
- IMG_EMB_DIM = (10, 10, 232)
25
+ IMG_EMB_DIM = (16, 16, 512)
23
26
  IMG_EMB_DIM = (IMG_EMB_DIM[0] * IMG_EMB_DIM[1], IMG_EMB_DIM[2])
24
- IMG_SHAPE = (299, 299, 3)
27
+ IMG_SHAPE = (512, 512, 3)
25
28
  PE_INPUT = IMG_EMB_DIM[0]
26
29
  IMG_SEQ_LEN, IMG_EMB_DEPTH = IMG_EMB_DIM
27
- D_MODEL = IMG_EMB_DEPTH
30
+ D_MODEL = 512
28
31
 
29
32
  # Network parameters
30
- N_LAYERS = 4
33
+ N_LAYERS = 6
31
34
  D_MODEL = 512
32
35
  D_FF = 2048
33
36
  N_HEADS = 8
@@ -55,14 +58,13 @@ testing_config.initialize_encoder_config(
55
58
  image_shape=IMG_SHAPE,
56
59
  do_permute=IMG_EMB_DIM[1] < IMG_EMB_DIM[0],
57
60
  )
58
-
59
61
  testing_config.initialize_transformer_config(
60
62
  vocab_len=VOCAB_LEN,
61
63
  max_len=MAX_LEN,
62
64
  n_transformer_layers=N_LAYERS,
63
65
  transformer_d_dff=D_FF,
64
66
  transformer_n_heads=N_HEADS,
65
- image_embedding_dim=IMG_EMB_DIM,
67
+ image_embedding_dim=D_MODEL,
66
68
  )
67
69
 
68
70
  # Prepare model
@@ -84,6 +86,56 @@ if ckpt_manager.latest_checkpoint:
84
86
  start_epoch = int(ckpt_manager.latest_checkpoint.split("-")[-1])
85
87
 
86
88
 
89
+ def detokenize_output(predicted_array: tf.Tensor) -> str:
90
+ """
91
+ This function takes the predicted array of tokens and returns the predicted SMILES
92
+ string.
93
+
94
+ Args:
95
+ predicted_array (tf.Tensor): Transformer Decoder output array (predicted tokens)
96
+
97
+ Returns:
98
+ str: SMILES string
99
+ """
100
+ outputs = [tokenizer.index_word[i] for i in predicted_array[0].numpy()]
101
+ prediction = (
102
+ "".join([str(elem) for elem in outputs])
103
+ .replace("<start>", "")
104
+ .replace("<end>", "")
105
+ )
106
+ return prediction
107
+
108
+
109
+ def detokenize_output_add_confidence(
110
+ predicted_array: tf.Tensor,
111
+ confidence_array: tf.Tensor,
112
+ ) -> List[Tuple[str, float]]:
113
+ """
114
+ This function takes the predicted array of tokens as well as the confidence values
115
+ returned by the Transformer Decoder and returns a list of tuples
116
+ that contain each token of the predicted SMILES string and the confidence
117
+ value.
118
+
119
+ Args:
120
+ predicted_array (tf.Tensor): Transformer Decoder output array (predicted tokens)
121
+
122
+ Returns:
123
+ str: SMILES string
124
+ """
125
+ prediction_with_confidence = [
126
+ (
127
+ tokenizer.index_word[predicted_array[0].numpy()[i]],
128
+ confidence_array[i].numpy(),
129
+ )
130
+ for i in range(len(confidence_array))
131
+ ]
132
+ decoded_prediction_with_confidence = list(
133
+ [(utils.decoder(tok), conf) for tok, conf in prediction_with_confidence[1:-1]]
134
+ )
135
+ decoded_prediction_with_confidence.append(prediction_with_confidence[-1])
136
+ return decoded_prediction_with_confidence
137
+
138
+
87
139
  class DECIMER_Predictor(tf.Module):
88
140
  """This is a class which takes care of inference. It loads the saved checkpoint and the necessary
89
141
  tokenizers. The inference begins with the start token (<start>) and ends when the end token(<end>)
@@ -116,10 +168,7 @@ class DECIMER_Predictor(tf.Module):
116
168
  Returns:
117
169
  output (tf.Tensor[tf.int64]): predicted output as an array.
118
170
  """
119
-
120
171
  assert isinstance(Decoded_image, tf.Tensor)
121
- if len(Decoded_image.shape) == 0:
122
- Decoded_image = Decoded_image[tf.newaxis]
123
172
 
124
173
  _image_batch = tf.expand_dims(Decoded_image, 0)
125
174
  _image_embedding = encoder(_image_batch, training=False)
@@ -133,28 +182,29 @@ class DECIMER_Predictor(tf.Module):
133
182
 
134
183
  output_array = tf.TensorArray(dtype=tf.int32, size=0, dynamic_size=True)
135
184
  output_array = output_array.write(0, start_token)
185
+ confidence_array = tf.TensorArray(dtype=tf.float32, size=0, dynamic_size=True)
136
186
 
137
187
  for t in tf.range(max_length):
138
188
  output = tf.transpose(output_array.stack())
139
- combined_mask = Transformer_decoder.create_mask(None, output)
189
+ combined_mask = Transformer_decoder.create_masks_decoder(output)
140
190
 
141
191
  # predictions.shape == (batch_size, seq_len, vocab_size)
142
- prediction_batch, _ = transformer(
143
- _image_embedding, output, training=False, look_ahead_mask=combined_mask
192
+ prediction_batch = transformer(
193
+ output, _image_embedding, training=False, look_ahead_mask=combined_mask
144
194
  )
145
195
 
146
196
  # select the last word from the seq_len dimension
147
197
  predictions = prediction_batch[:, -1:, :] # (batch_size, 1, vocab_size)
148
198
 
149
199
  predicted_id = tf.cast(tf.argmax(predictions, axis=-1), tf.int32)
150
-
200
+ confidence = predictions[0, 0, int(predicted_id[0, 0])]
151
201
  output_array = output_array.write(t + 1, predicted_id[0])
152
-
202
+ confidence_array = confidence_array.write(t + 1, confidence)
153
203
  if predicted_id == end_token:
154
204
  break
155
205
  output = tf.transpose(output_array.stack())
156
206
 
157
- return output
207
+ return output, confidence_array.stack()
158
208
 
159
209
 
160
210
  DECIMER = DECIMER_Predictor(encoder, tokenizer, transformer, MAX_LEN)