{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<h1><center>Bristol-Myers Squibb - Molecular Translation</center></h1>","metadata":{}},{"cell_type":"markdown","source":"InChI or International Chemical Identifier is a textual identifier for chemical substances, designed to provide a standard way to encode molecular information and to facilitate the search for such information in databases and on the web.","metadata":{}},{"cell_type":"markdown","source":"**This code is an Inference code to find the training details check out this kaggle notebook** <a href=\"https://www.kaggle.com/sambhavsg/bms-baseline-inchi-first-layer-train-tf-keras?scriptVersionId=62450249\">BMS Baseline InChI first layer Train TF Keras</a> \n","metadata":{}},{"cell_type":"markdown","source":"# Import Modules","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\n\nimport tensorflow as tf\nimport tensorflow.keras.models as M\nimport tensorflow.keras.layers as L\nimport tensorflow.keras.optimizers as O\nimport tensorflow.keras.losses as Loss\n\nfrom tqdm import tqdm\n\nfrom PIL import Image\nimport cv2\n\nimport matplotlib.pyplot as plt","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"gpus = tf.config.list_physical_devices('GPU')\nif gpus:\n  # Restrict TensorFlow to only allocate 1GB of memory on the first GPU\n  try:\n    tf.config.experimental.set_virtual_device_configuration(\n        gpus[0],\n        [tf.config.experimental.VirtualDeviceConfiguration(memory_limit=15240)])\n    logical_gpus = tf.config.experimental.list_logical_devices('GPU')\n    print(len(gpus), \"Physical GPUs,\", len(logical_gpus), \"Logical GPUs\")\n  except RuntimeError as e:\n    # Virtual devices must be set before GPUs have been initialized\n    print(e)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loading and Preprocessing Data","metadata":{}},{"cell_type":"markdown","source":"## Setting global variables","metadata":{}},{"cell_type":"markdown","source":"### Batch Size, Epochs, input image dimensions and max length of the target sequence is defined here.","metadata":{}},{"cell_type":"code","source":"BATCH_SIZE = 800\nEPOCHS = 1\nDIM =(100,100)\nMAX_LENGTH = 20","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Importing and preprcocessing train data","metadata":{}},{"cell_type":"markdown","source":"# Loading test data","metadata":{}},{"cell_type":"code","source":"sampl = pd.read_csv('../input/bms-molecular-translation/sample_submission.csv')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Image path is added to the image id column of the data to load the image for inference","metadata":{}},{"cell_type":"code","source":"test_path = '../input/bms-molecular-translation/test'\nfor i in tqdm(range(len(sampl))):\n    image_id = sampl.image_id.values[i]\n    sampl.image_id.values[i] = test_path+'/'+image_id[0]+'/'+image_id[1]+'/'+image_id[2]+'/'+image_id+'.png'\nsampl.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"During training tokens were defined to tokenize the input data labels. Now, in order to detokenize the data a detokens dictionary is created. This dictionary will be sued later in this code to interpret the predictions and detokenize the predicted values.","metadata":{}},{"cell_type":"code","source":"detokens = {0: 'S', 1: 'B', 2: 'N', 3: 'I', 4: 'F', 5: 'P', 6: '3', 7: '6', 8: 'i', 9: '5', 10: '8', 11: 'C', 12: '7', 13: '4', 14: 'r', 15: '0', 16: '2', 17: 'O', 18: '9', 19: 'H', 20: 'l', 21: '$', 22: '1'} \nprint(detokens)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This function preprocesses the data before loading the image to the GPU for predictions. In this function the image is loaded directly during prediction reducing the use of the available RAM as it would be nearly impossible to load that much data in the current provided RAM size before prerdiction. This function is utilized during prediction to preprocess the data when fetched.","metadata":{}},{"cell_type":"code","source":"def preprocess_test_image(image_id):\n    image = tf.io.read_file(image_id)    \n    image = tf.image.decode_png(image,channels=1)\n    def f1(): return tf.image.rot90(image,k=3)\n    def f2(): return image\n    image = tf.cond(tf.less(tf.shape(image)[1],tf.shape(image)[0]),f1,f2)\n    image = tf.image.convert_image_dtype(image, tf.float32)\n    image = tf.image.resize_with_pad(image, DIM[0],DIM[1])\n    return image","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#     image = tf.io.read_file('../input/bms-molecular-translation/train/0/0/0/000011a64c74.png')\n#     image = tf.image.decode_png(image,channels=1)\n#     print(tf.shape(image))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Here tf.data.Dataset is utlized to fetch the data on the go instead of preloading the data in the RAM which would be nearly impossible given the current available RAM size. This function only loads the batch size amount of data in the memory and preprocesses the data on the go using the above function. Also, prefetch is used here that prefetches some data before hand to minimize bottleneck and improves spped.","metadata":{}},{"cell_type":"code","source":"test_data = tf.data.Dataset.from_tensor_slices(sampl.image_id.values).map(preprocess_test_image,num_parallel_calls=tf.data.AUTOTUNE).batch(2048).prefetch(tf.data.AUTOTUNE)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loading Pretrained Model","metadata":{}},{"cell_type":"code","source":"model = M.load_model('../input/trained-model-for-bmsmolecular/phase1_base_model_v1.4.h5')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference ","metadata":{}},{"cell_type":"markdown","source":"This function is utilized to detokenize the prediction using the detokens dictionary","metadata":{}},{"cell_type":"code","source":"def detokenize(pred):\n    string_d = []\n    for i in range(len(pred)):\n        a = []\n        for j in range(len(pred[i])):\n            if pred[i][j] in detokens.keys():\n                a.append(detokens[pred[i][j]])\n            else:\n                a.append(str(pred[i][j]-47))\n        a = \"\".join(a)\n        string_d.append(a)\n    return string_d","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Prediction","metadata":{}},{"cell_type":"code","source":"pred = model.predict(test_data,verbose=1)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Post Processing","metadata":{}},{"cell_type":"markdown","source":"Since the predictions are in range between 0 and 1 and the output activation was sigmoid so we are using argmax function to find the index of the maximum value in the axis, then the data is detokenized using the detokenize function and then the padded token is removed from the detokenized predicted sequences","metadata":{}},{"cell_type":"code","source":"pred = np.argmax(pred,axis=-1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred = detokenize(pred)\npred = np.char.strip(pred,chars='$')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sampl.InChI = pred","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Removing the file path from the image id column of the data","metadata":{}},{"cell_type":"code","source":"for i in tqdm(range(len(sampl.image_id.values))):\n    sampl.image_id.values[i] = sampl.image_id.values[i][46:58]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This is baseline for the first layer of the InChI notation so the other layers are set the same for all values.","metadata":{}},{"cell_type":"code","source":"text = '/c1-18(2,3)24-17(22)21-10-6-8-14(21)15-11-13(20-25-15)12-7-5-9-19-16(12)23-4/h5,7,9,11,14H,6,8,10H2,1-4H3'\nsampl.InChI = sampl.InChI.values+text","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sampl.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sampl.to_csv('submission.csv',index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}