decimer 2.3.0__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.
- {decimer-2.3.0 → decimer-2.5.0}/DECIMER/Efficient_Net_encoder.py +7 -26
- decimer-2.5.0/DECIMER/Predictor_usingCheckpoints.py +275 -0
- {decimer-2.3.0 → decimer-2.5.0}/DECIMER/Repack_model.py +61 -22
- decimer-2.5.0/DECIMER/Transformer_decoder.py +210 -0
- {decimer-2.3.0 → decimer-2.5.0}/DECIMER/Utils/Create_TFrecord_From_pickles.py +3 -4
- {decimer-2.3.0 → decimer-2.5.0}/DECIMER/Utils/Create_image_tokenizer.py +3 -4
- {decimer-2.3.0 → decimer-2.5.0}/DECIMER/__init__.py +3 -4
- {decimer-2.3.0 → decimer-2.5.0}/DECIMER/config.py +29 -32
- {decimer-2.3.0 → decimer-2.5.0}/DECIMER/decimer.py +66 -21
- {decimer-2.3.0 → decimer-2.5.0}/DECIMER/efficientnetv2/effnetv2_configs.py +2 -1
- {decimer-2.3.0 → decimer-2.5.0}/DECIMER/efficientnetv2/effnetv2_model.py +5 -5
- {decimer-2.3.0 → decimer-2.5.0}/DECIMER/efficientnetv2/hparams.py +4 -1
- {decimer-2.3.0 → decimer-2.5.0}/DECIMER/efficientnetv2/utils.py +81 -29
- {decimer-2.3.0 → decimer-2.5.0}/DECIMER/utils.py +30 -0
- {decimer-2.3.0 → decimer-2.5.0}/PKG-INFO +3 -6
- {decimer-2.3.0 → decimer-2.5.0}/README.md +1 -1
- {decimer-2.3.0 → decimer-2.5.0}/decimer.egg-info/PKG-INFO +3 -6
- decimer-2.5.0/decimer.egg-info/SOURCES.txt +23 -0
- {decimer-2.3.0 → decimer-2.5.0}/decimer.egg-info/requires.txt +2 -0
- {decimer-2.3.0 → decimer-2.5.0}/setup.py +5 -3
- decimer-2.3.0/.github/ISSUE_TEMPLATE/Bug_Report.yml +0 -113
- decimer-2.3.0/.github/workflows/Check_errors.yml +0 -37
- decimer-2.3.0/.gitignore +0 -132
- decimer-2.3.0/.readthedocs.yml +0 -19
- decimer-2.3.0/Benchmark/README.md +0 -32
- decimer-2.3.0/Benchmark/TEST.txt +0 -3
- decimer-2.3.0/Benchmark/distort_images.py +0 -64
- decimer-2.3.0/Benchmark/evaluate_benchmarks.py +0 -90
- decimer-2.3.0/Benchmark/run_decimer_save_results.py +0 -33
- decimer-2.3.0/Benchmark/test_images/DECIMER_test_0.png +0 -0
- decimer-2.3.0/Benchmark/test_images/DECIMER_test_1.png +0 -0
- decimer-2.3.0/Benchmark/test_images/github_issue_test.png +0 -0
- decimer-2.3.0/CITATION.cff +0 -18
- decimer-2.3.0/CODE_OF_CONDUCT.md +0 -128
- decimer-2.3.0/DECIMER/Predictor_EfficientNet2.py +0 -160
- decimer-2.3.0/DECIMER/Transformer_decoder.py +0 -445
- decimer-2.3.0/DECIMER_V2.png +0 -0
- decimer-2.3.0/ISSUES.md +0 -16
- decimer-2.3.0/Python_Requirements.txt +0 -5
- decimer-2.3.0/Tests/caffeine.png +0 -0
- decimer-2.3.0/Tests/test_functions.py +0 -10
- decimer-2.3.0/decimer.egg-info/SOURCES.txt +0 -51
- decimer-2.3.0/docs/DECIMER.rst +0 -29
- decimer-2.3.0/docs/Makefile +0 -20
- decimer-2.3.0/docs/_static/DECIMER.gif +0 -0
- decimer-2.3.0/docs/conf.py +0 -90
- decimer-2.3.0/docs/index.rst +0 -38
- decimer-2.3.0/docs/make.bat +0 -35
- decimer-2.3.0/docs/modules.rst +0 -7
- decimer-2.3.0/docs/requirements.txt +0 -9
- decimer-2.3.0/tox.ini +0 -46
- {decimer-2.3.0 → decimer-2.5.0}/DECIMER/DECIMER_EfficinetNetV2_Transfomer_Trainer.py +8 -8
- {decimer-2.3.0 → decimer-2.5.0}/LICENSE +0 -0
- {decimer-2.3.0 → decimer-2.5.0}/decimer.egg-info/dependency_links.txt +0 -0
- {decimer-2.3.0 → decimer-2.5.0}/decimer.egg-info/top_level.txt +0 -0
- {decimer-2.3.0 → decimer-2.5.0}/setup.cfg +0 -0
|
@@ -1,37 +1,25 @@
|
|
|
1
1
|
# EfficientNet-V2 config
|
|
2
2
|
import tensorflow as tf
|
|
3
|
-
|
|
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-
|
|
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=(
|
|
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 =
|
|
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,11 +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
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import config
|
|
8
|
-
import utils
|
|
8
|
+
import DECIMER.config as config
|
|
9
|
+
import DECIMER.Efficient_Net_encoder as Efficient_Net_encoder
|
|
10
|
+
import DECIMER.Transformer_decoder as Transformer_decoder
|
|
9
11
|
|
|
10
12
|
print(tf.__version__)
|
|
11
13
|
|
|
@@ -16,19 +18,19 @@ for gpu in gpus:
|
|
|
16
18
|
tf.config.experimental.set_memory_growth(gpu, True)
|
|
17
19
|
|
|
18
20
|
# load assets
|
|
19
|
-
tokenizer = pickle.load(open("
|
|
20
|
-
max_length = pickle.load(open("
|
|
21
|
+
tokenizer = pickle.load(open("tokenizer.pkl", "rb"))
|
|
22
|
+
max_length = pickle.load(open("max_length.pkl", "rb"))
|
|
21
23
|
|
|
22
24
|
# Image parameters
|
|
23
|
-
IMG_EMB_DIM = (16, 16,
|
|
25
|
+
IMG_EMB_DIM = (16, 16, 512)
|
|
24
26
|
IMG_EMB_DIM = (IMG_EMB_DIM[0] * IMG_EMB_DIM[1], IMG_EMB_DIM[2])
|
|
25
27
|
IMG_SHAPE = (512, 512, 3)
|
|
26
28
|
PE_INPUT = IMG_EMB_DIM[0]
|
|
27
29
|
IMG_SEQ_LEN, IMG_EMB_DEPTH = IMG_EMB_DIM
|
|
28
|
-
D_MODEL =
|
|
30
|
+
D_MODEL = 512
|
|
29
31
|
|
|
30
32
|
# Network parameters
|
|
31
|
-
N_LAYERS =
|
|
33
|
+
N_LAYERS = 6
|
|
32
34
|
D_MODEL = 512
|
|
33
35
|
D_FF = 2048
|
|
34
36
|
N_HEADS = 8
|
|
@@ -56,14 +58,13 @@ testing_config.initialize_encoder_config(
|
|
|
56
58
|
image_shape=IMG_SHAPE,
|
|
57
59
|
do_permute=IMG_EMB_DIM[1] < IMG_EMB_DIM[0],
|
|
58
60
|
)
|
|
59
|
-
|
|
60
61
|
testing_config.initialize_transformer_config(
|
|
61
62
|
vocab_len=VOCAB_LEN,
|
|
62
63
|
max_len=MAX_LEN,
|
|
63
64
|
n_transformer_layers=N_LAYERS,
|
|
64
65
|
transformer_d_dff=D_FF,
|
|
65
66
|
transformer_n_heads=N_HEADS,
|
|
66
|
-
image_embedding_dim=
|
|
67
|
+
image_embedding_dim=D_MODEL,
|
|
67
68
|
)
|
|
68
69
|
|
|
69
70
|
# Prepare model
|
|
@@ -85,17 +86,56 @@ if ckpt_manager.latest_checkpoint:
|
|
|
85
86
|
start_epoch = int(ckpt_manager.latest_checkpoint.split("-")[-1])
|
|
86
87
|
|
|
87
88
|
|
|
88
|
-
def detokenize_output(predicted_array):
|
|
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
|
+
"""
|
|
89
100
|
outputs = [tokenizer.index_word[i] for i in predicted_array[0].numpy()]
|
|
90
101
|
prediction = (
|
|
91
102
|
"".join([str(elem) for elem in outputs])
|
|
92
103
|
.replace("<start>", "")
|
|
93
104
|
.replace("<end>", "")
|
|
94
105
|
)
|
|
95
|
-
|
|
96
106
|
return prediction
|
|
97
107
|
|
|
98
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
|
+
|
|
99
139
|
class DECIMER_Predictor(tf.Module):
|
|
100
140
|
"""This is a class which takes care of inference. It loads the saved checkpoint and the necessary
|
|
101
141
|
tokenizers. The inference begins with the start token (<start>) and ends when the end token(<end>)
|
|
@@ -129,8 +169,6 @@ class DECIMER_Predictor(tf.Module):
|
|
|
129
169
|
output (tf.Tensor[tf.int64]): predicted output as an array.
|
|
130
170
|
"""
|
|
131
171
|
assert isinstance(Decoded_image, tf.Tensor)
|
|
132
|
-
if len(Decoded_image.shape) == 0:
|
|
133
|
-
sentence = Decoded_image[tf.newaxis]
|
|
134
172
|
|
|
135
173
|
_image_batch = tf.expand_dims(Decoded_image, 0)
|
|
136
174
|
_image_embedding = encoder(_image_batch, training=False)
|
|
@@ -144,28 +182,29 @@ class DECIMER_Predictor(tf.Module):
|
|
|
144
182
|
|
|
145
183
|
output_array = tf.TensorArray(dtype=tf.int32, size=0, dynamic_size=True)
|
|
146
184
|
output_array = output_array.write(0, start_token)
|
|
185
|
+
confidence_array = tf.TensorArray(dtype=tf.float32, size=0, dynamic_size=True)
|
|
147
186
|
|
|
148
187
|
for t in tf.range(max_length):
|
|
149
188
|
output = tf.transpose(output_array.stack())
|
|
150
|
-
combined_mask = Transformer_decoder.
|
|
189
|
+
combined_mask = Transformer_decoder.create_masks_decoder(output)
|
|
151
190
|
|
|
152
191
|
# predictions.shape == (batch_size, seq_len, vocab_size)
|
|
153
|
-
prediction_batch
|
|
154
|
-
|
|
192
|
+
prediction_batch = transformer(
|
|
193
|
+
output, _image_embedding, training=False, look_ahead_mask=combined_mask
|
|
155
194
|
)
|
|
156
195
|
|
|
157
196
|
# select the last word from the seq_len dimension
|
|
158
197
|
predictions = prediction_batch[:, -1:, :] # (batch_size, 1, vocab_size)
|
|
159
198
|
|
|
160
199
|
predicted_id = tf.cast(tf.argmax(predictions, axis=-1), tf.int32)
|
|
161
|
-
|
|
200
|
+
confidence = predictions[0, 0, int(predicted_id[0, 0])]
|
|
162
201
|
output_array = output_array.write(t + 1, predicted_id[0])
|
|
163
|
-
|
|
202
|
+
confidence_array = confidence_array.write(t + 1, confidence)
|
|
164
203
|
if predicted_id == end_token:
|
|
165
204
|
break
|
|
166
205
|
output = tf.transpose(output_array.stack())
|
|
167
206
|
|
|
168
|
-
return output
|
|
207
|
+
return output, confidence_array.stack()
|
|
169
208
|
|
|
170
209
|
|
|
171
210
|
DECIMER = DECIMER_Predictor(encoder, tokenizer, transformer, MAX_LEN)
|