{"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 style=\"text-align: center; font-family: Verdana; font-size: 32px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; font-variant: small-caps; letter-spacing: 3px; color: #FF1493; background-color: #ffffff;\">Bristol-Myers Squibb – Molecular Translation</h1>\n<h2 style=\"text-align: center; font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: underline; text-transform: none; letter-spacing: 2px; color: navy; background-color: #ffffff;\">TFRecord Creation</h2>\n<h5 style=\"text-align: center; font-family: Verdana; font-size: 12px; font-style: normal; font-weight: bold; text-decoration: None; text-transform: none; letter-spacing: 1px; color: black; background-color: #ffffff;\">CREATED BY: DARIEN SCHETTLER</h5>\n\n---\n\n<br><br>\n\n<font color=\"purple\" style=\"font-weight: bold;\">CHANGE LOG</font>\n\n---\n\n* **v1 - `Working Draft`**\n* **v2 - `384x384x1 - No Rotation - Raw Labels - Preprocessing (inversion, pad2square)`**\n* **v3-9 - `Working Draft`**\n* **v10 - `384x384x1 - Yes Rotation - Tokenized - Preprocessing (inversion, pad2square) - Just Train/Val `**\n* **v11 - `128x128x1 - Yes Rotation - Tokenized - Preprocessing (inversion, pad2square) - Train/Val/Test `**\n* **v12 - `256x256x1 - Yes Rotation - Tokenized - Preprocessing (inversion, pad2square) - Train/Val/Test [CURRENT]`**\n* **v13-15 - `Working Draft`**\n\n---\n\n<br>","metadata":{}},{"cell_type":"markdown","source":"<p id=\"toc\"></p>\n\n<br><br>\n\n<h1 style=\"font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; color: navy; background-color: #ffffff;\">TABLE OF CONTENTS</h1>\n\n---\n\n<h3 style=\"text-indent: 10vw; font-family: Verdana; font-size: 20px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: navy; background-color: #ffffff;\"><a href=\"#imports\">0&nbsp;&nbsp;&nbsp;&nbsp;IMPORTS</a></h3>\n\n---\n\n<h3 style=\"text-indent: 10vw; font-family: Verdana; font-size: 20px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: navy; background-color: #ffffff;\"><a href=\"#background_information\">1&nbsp;&nbsp;&nbsp;&nbsp;BACKGROUND INFORMATION</a></h3>\n\n---\n\n<h3 style=\"text-indent: 10vw; font-family: Verdana; font-size: 20px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: navy; background-color: #ffffff;\"><a href=\"#setup\">2&nbsp;&nbsp;&nbsp;&nbsp;SETUP</a></h3>\n\n---\n\n<h3 style=\"text-indent: 10vw; font-family: Verdana; font-size: 20px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: navy; background-color: #ffffff;\"><a href=\"#helper_functions\">3&nbsp;&nbsp;&nbsp;&nbsp;HELPER FUNCTIONS</a></h3>\n\n---\n\n<h3 style=\"text-indent: 10vw; font-family: Verdana; font-size: 20px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: navy; background-color: #ffffff;\"><a href=\"#dataset_preparation\">4&nbsp;&nbsp;&nbsp;&nbsp;PREPARE THE DATASET</a></h3>\n\n---","metadata":{}},{"cell_type":"markdown","source":"<h1 style=\"font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; background-color: #ffffff; color: navy;\" id=\"imports\">0&nbsp;&nbsp;IMPORTS&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#toc\">&#10514;</a></h1>","metadata":{}},{"cell_type":"code","source":"print(\"\\n... IMPORTS STARTING ...\\n\")\nprint(\"\\n\\tVERSION INFORMATION\")\n\n# Parallel application across pandas apply operation\n!pip install pandarallel\nfrom pandarallel import pandarallel\npandarallel.initialize()\n\n# Machine Learning and Data Science Imports\nimport tensorflow as tf; print(f\"\\t\\t– TENSORFLOW VERSION: {tf.__version__}\");\nimport tensorflow_addons as tfa; print(f\"\\t\\t– TENSORFLOW ADDONS VERSION: {tfa.__version__}\");\nimport pandas as pd; pd.options.mode.chained_assignment = None;\nimport numpy as np; print(f\"\\t\\t– NUMPY VERSION: {np.__version__}\");\n\n# Built In Imports\nfrom kaggle_datasets import KaggleDatasets\nfrom collections import Counter\nfrom datetime import datetime\nimport multiprocessing as mp\nfrom glob import glob\nimport warnings\nimport requests\nimport imageio\nimport IPython\nimport urllib\nimport zipfile\nimport pickle\nimport random\nimport shutil\nimport string\nimport math\nimport time\nimport gzip\nimport ast\nimport io\nimport os\nimport gc\nimport re\n\n# Visualization Imports\nfrom matplotlib.colors import ListedColormap\nimport matplotlib.patches as patches\nimport plotly.graph_objects as go\nimport matplotlib.pyplot as plt\nfrom tqdm.notebook import tqdm; tqdm.pandas();\nimport plotly.express as px\nimport seaborn as sns\nfrom PIL import Image\nimport matplotlib; print(f\"\\t\\t– MATPLOTLIB VERSION: {matplotlib.__version__}\");\nimport plotly\nimport PIL\nimport cv2\n\n\nprint(\"\\n\\n... IMPORTS COMPLETE ...\\n\")\n\n\ngpus = tf.config.experimental.list_physical_devices('GPU')\nif gpus:\n    try:\n        # Currently, memory growth needs to be the same across GPUs\n        for gpu in gpus:\n            tf.config.experimental.set_memory_growth(gpu, True)\n        logical_gpus = tf.config.experimental.list_logical_devices('GPU')\n        print(len(gpus), \"... Physical GPUs,\", len(logical_gpus), \"Logical GPUs ...\\n\")\n    except RuntimeError as e:\n        # Memory growth must be set before GPUs have been initialized\n        print(e)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h1 style=\"font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; color: navy; background-color: #ffffff;\" id=\"background_information\">1&nbsp;&nbsp;BACKGROUND INFORMATION&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#toc\">&#10514;</a></h1>\n\n<br><b style=\"text-decoration: underline; font-family: Verdana; text-transform: uppercase;\">POSSIBLE FLAG EXPLORATION</b>\n\nTBD","metadata":{}},{"cell_type":"markdown","source":"<h1 style=\"font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; color: navy; background-color: #ffffff;\" id=\"setup\">2&nbsp;&nbsp;SETUP&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#toc\">&#10514;</a></h1>","metadata":{}},{"cell_type":"markdown","source":"<h3 style=\"font-family: Verdana; font-size: 20px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: navy; background-color: #ffffff;\">2.1  BASIC SETUP</h3>","metadata":{}},{"cell_type":"code","source":"# Only required if `APPLY_TOKENIZATION=True`\nTOKEN_LIST = [\"<PAD>\", \"InChI=1S/\", \"<END>\", \"/c\", \"/h\", \"/m\", \"/t\", \"/b\", \"/s\", \"/i\"] +\\\n             ['Si', 'Br', 'Cl', 'F', 'I', 'N', 'O', 'P', 'S', 'C', 'H', 'B', ] +\\\n             [str(i) for i in range(167,-1,-1)] +\\\n             [\"\\+\", \"\\(\", \"\\)\", \"\\-\", \",\", \"D\", \"T\"]\nSTART_TOKEN = tf.constant(TOKEN_LIST.index(\"InChI=1S/\"), dtype=tf.uint8)\nEND_TOKEN = tf.constant(TOKEN_LIST.index(\"<END>\"), dtype=tf.uint8)\nPAD_TOKEN = tf.constant(TOKEN_LIST.index(\"<PAD>\"), dtype=tf.uint8)\n\n# Define the root and data directories\nROOT_DIR = \"/kaggle/input\"\nDATA_DIR = os.path.join(ROOT_DIR, \"bms-molecular-translation\")\n\nTRAIN_DIR = os.path.join(DATA_DIR, \"train\")\nTEST_DIR = os.path.join(DATA_DIR, \"test\")\n\nTRAIN_CSV_PATH = \"/kaggle/input/bms-csvs-w-extra-metadata/train_labels_w_extra.csv\"\nSS_CSV_PATH = \"/kaggle/input/bms-csvs-w-extra-metadata/sample_submission_w_extra.csv\"\n\ntrain_df = pd.read_csv(TRAIN_CSV_PATH)\ntrain_df.roi_bbox = train_df.roi_bbox.progress_apply(lambda x: ast.literal_eval(x))\n\nprint(\"\\n... TRAIN DATAFRAME W/ PATHS ...\\n\")\ndisplay(train_df)\n\nss_df = pd.read_csv(SS_CSV_PATH)\nss_df.roi_bbox = ss_df.roi_bbox.progress_apply(lambda x: ast.literal_eval(x))\n\nprint(\"\\n... SUBMISSION DATAFRAME ...\\n\")\ndisplay(ss_df)\n\n# def get_new_ar(row):\n#     if row.crop_width<row.crop_height:\n#         return row.crop_height/row.crop_width\n#     else:\n#         return row.aspect_ratio\n\n# ss_df.progress_apply(lambda x: get_new_ar(x), axis=1).describe()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h3 style=\"font-family: Verdana; font-size: 20px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: navy; background-color: #ffffff;\">2.2 USER INPUT VARIABLES</h3>","metadata":{}},{"cell_type":"code","source":"# Proportion of data for training/validation\nN_TEST = len(ss_df) # 1616107\nN_VAL = 80_000 \nN_TRAIN = len(train_df)-N_VAL # 2424186-N_VAL\n\n# Whether to rotate images 90 degrees based on the w/h rule\n# Only True for test images\nFIX_ROTATION = True\n\n# Whether to invert foreground/background\nDO_INVERT = True\n\n# Whether to repair images - not implemented yet\nDO_REPAIR = False\n\n# Desired image shape ... the last axis indicates whether to tile the single channel image to 3\nIMG_SHAPE = (192,384,1)\n\n# Whether or not to do tokenization to inchi strings\nAPPLY_TOKENIZATION = True","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h3 style=\"font-family: Verdana; font-size: 20px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: navy; background-color: #ffffff;\">2.3 AUTO DETECTED VARIABLES</h3>","metadata":{}},{"cell_type":"code","source":"# INCHI RELATED\nTOK2INT = {c.strip(\"\\\\\"):i for i,c in enumerate(TOKEN_LIST)}\nINT2TOK = {v:k for k,v in TOK2INT.items()}\n\n# MAX_LEN = train_df.InChI.progress_apply(lambda x: len(re.findall(\"|\".join(TOKEN_LIST), x))).max()+1\n#     - Using half of the actual max length to accelerate training\nFILTER_ON_MAX_LEN=False\nMAX_LEN = train_df.inchi_token_len.max()+1 # +1 is for the end token\nVOCAB_LEN = len(INT2TOK)\n\n# IMG RELATED\nN_CHANNELS = IMG_SHAPE[-1]\nIMG_SIZE = IMG_SHAPE[:2]\n\n# Split dataframe\nval_df = train_df[:N_VAL].reset_index(drop=True)\ntrain_df = train_df[N_VAL:].reset_index(drop=True)\n\n# For TFRecord sharding - very rough estimations\nN_EX_PER_REC = (20000 if np.product(IMG_SHAPE)>400000 else 40000)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h1 style=\"font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; color: navy; background-color: #ffffff;\" id=\"helper_functions\">3&nbsp;&nbsp;HELPER FUNCTIONS&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#toc\">&#10514;</a></h1>","metadata":{}},{"cell_type":"code","source":"def flatten_l_o_l(nested_list):\n    \"\"\" Flatten a list of lists \"\"\"\n    return [item for sublist in nested_list for item in sublist]\n\n\ndef tf_load_image(path, bbox, img_size=(224,224), tile_to_3_channel=True, invert=False, rotate_trick=True, repair_images=False):\n    \"\"\" Load an image with the correct size and shape \"\"\"\n    img = decode_img(tf.io.read_file(path), bbox, img_size, n_channels=1, invert=invert, rotate_trick=rotate_trick, repair_images=repair_images)\n    \n    if tile_to_3_channel:\n        return tf.tile(img, tf.constant((1, 1, 3), dtype=tf.int32))\n    else:\n        return img\n    \ndef rotate_trick_fn(a):\n    \"\"\" Pad a tensor array `a` evenly until it is a square \"\"\"\n    h_src = tf.shape(a)[0]\n    w_src = tf.shape(a)[1] \n            \n    if h_src>w_src: # pad width\n        a = tf.image.rot90(a)\n\n    return a\n    \n    \ndef decode_img(img, bbox, img_size=(224,224), n_channels=1, invert=False, rotate_trick=True, repair_images=False):\n    \"\"\" Decode the image by utilizing TF ... pad to square ... and resize \"\"\"\n    \n    # convert the compressed string to a 3D uint8 tensor\n    img = tf.image.decode_png(img, channels=n_channels)\n    img = tf.image.crop_to_bounding_box(img, bbox[1], bbox[0], bbox[3]-bbox[1], bbox[2]-bbox[0])\n    \n    if invert:\n        img = tf.ones_like(img, dtype=tf.uint8)*255-img\n        constant_pad=0\n    else:\n        constant_pad=255\n        \n    if repair_images:\n        pass\n        \n    # rotate trick\n    #if rotate_trick:\n    #img = rotate_trick_fn(img)\n    \n    img = tf.image.resize(img, img_size, method=\"bilinear\")\n    return tf.cast(img, tf.uint8)\n\n\ndef tokens_to_str(caption_tokens, discard_padding=True):\n    \"\"\" Should convert a string of token ids to an InChI string \"\"\"\n    if discard_padding:\n        return \"\".join([int_2_char_lex[x] for x in caption_tokens if x!=len(int_2_char_lex)])\n    else:\n        return \"\".join([int_2_char_lex[x] for x in caption_tokens])\n    \n    \ndef evaluate(image, from_np=False):\n    \"\"\" TBD \"\"\"\n    attention_plot = np.zeros((MAX_LEN, fixed_encoder.output_shape[1]))\n    hidden = tf.zeros((1, RNN_UNITS), tf.float32)\n\n    if not from_np:\n        temp_input = tf.expand_dims(tf_load_image(image, img_size=INPUT_SHAPE[:-1]), 0)\n        img_tensor_val = fixed_encoder(temp_input)\n    else:\n        img_tensor_val=image\n    \n    features = trainable_encoder(img_tensor_val)\n    dec = tf.ones((1, 1), tf.uint8)\n    result = [int_2_char_lex[1],]\n\n    for i in range(MAX_LEN-1):\n        predictions, hidden, attention_weights = dec_model([dec, hidden, features])\n        attention_plot[i] = tf.reshape(attention_weights, (-1, )).numpy()\n        predicted_id = tf.random.categorical(predictions, 1)[0][0].numpy()\n        result.append(int_2_char_lex[predicted_id])\n        if int_2_char_lex[predicted_id] == '<END>':\n            return result, attention_plot\n\n        dec = tf.expand_dims([predicted_id], 0)\n\n    attention_plot = attention_plot[:len(result), :]\n    return result, attention_plot\n\n\ndef plot_attention(image, result, attention_plot):\n    \"\"\" TBD \"\"\"    \n    temp_image = np.array(Image.open(image))\n\n    fig = plt.figure(figsize=(18, 14))\n\n    len_result = len(result)\n    for l in range(len_result):\n        temp_att = np.resize(attention_plot[l], (8, 8))\n        ax = fig.add_subplot(len_result//2, len_result//2, l+1)\n        ax.set_title(result[l])\n        img = ax.imshow(temp_image)\n        ax.imshow(temp_att, cmap='gray', alpha=0.4, extent=img.get_extent())\n\n    plt.tight_layout()\n    plt.show()\n    \ndef test_random_image(style=\"full\"):\n    \"\"\" TBD \"\"\"    \n    rid = np.random.randint(0, len(val_subset_df))\n    path = val_subset_df[\"img_path\"][rid]\n    \n    if style==\"full\":\n        real_caption = val_subset_df[\"InChI\"][rid][:-1]\n    else:\n        real_caption = val_subset_df[\"InChI_chem\"][rid][:-1]\n\n    result, attention_plot = evaluate(path)\n    result = ''.join(result[:-1])\n    print (f\"\\n\\tReal Caption       : {real_caption}\")\n    print (f\"\\tPrediction Caption   : {result}\")\n    print(f\"\\tLevenshtein Distance  : {Levenshtein.distance(real_caption, result)}\\n\")\n    plot_attention(path, result, attention_plot)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h1 style=\"font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; color: navy; background-color: #ffffff;\" id=\"dataset_preparation\">4&nbsp;&nbsp;PREPARE THE DATASET&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"#toc\">&#10514;</a></h1>\n\nIn this section we prepare a subset of the dataset for modelling","metadata":{}},{"cell_type":"code","source":"# def get_roi_bbox(img_path, area_thresh=100):\n#     \"\"\" TBD \n    \n#     Args:\n#         TBD\n    \n#     Returns:\n#         TBD\n#     \"\"\"\n    \n#     img = 255-cv2.imread(img_path, 0)\n#     mask = np.zeros_like(img)\n    \n#     img_morph = cv2.morphologyEx(img, cv2.MORPH_DILATE, np.ones((3,3), np.uint8), iterations=3)\n    \n#     # num_labels : The total number of unique labels (i.e., number of total components) that were detected\n#     # labels     : A mask named labels has the same spatial dimensions as our input thresh image. \n#     #              For each location in labels, we have an integer ID value that corresponds to the connected component where the pixel belongs. \n#     # stats      : Statistics on each connected component, including the bounding box coordinates and area (in pixels).\n#     #                    - The starting x coordinate of the component\n#     #                    - The starting y coordinate of the component\n#     #                    - The width (w) of the component\n#     #                    - The height (h) of the component\n#     #                    - The centroid (x, y)-coordinates of the component\n#     # centroids  : (i.e., center) (x, y)-coordinates of each connected component.\n#     numLabels, labels, stats, centroids = cv2.connectedComponentsWithStats(img_morph, 4, cv2.CV_32S)\n    \n#     for i in range(1, numLabels):\n#         # extract the connected component statistics for the current label\n#         x = stats[i, cv2.CC_STAT_LEFT]\n#         y = stats[i, cv2.CC_STAT_TOP]\n#         w = stats[i, cv2.CC_STAT_WIDTH]\n#         h = stats[i, cv2.CC_STAT_HEIGHT]\n#         area = stats[i, cv2.CC_STAT_AREA]\n\n\n#         if area>area_thresh:\n#             # construct a mask for the current connected component and then take the bitwise OR with the mask\n#             componentMask = (labels == i).astype(\"uint8\") * 255\n#             mask = cv2.bitwise_or(mask, componentMask)\n\n#     left_pt = np.where(mask==255)[0].min()\n#     top_pt = np.where(mask==255)[1].min()\n#     right_pt = np.where(mask==255)[0].max()\n#     bottom_pt = np.where(mask==255)[1].max()\n    \n#     return (left_pt, top_pt, right_pt, bottom_pt)\n\n# train_df[\"roi_bbox\"] = train_df.img_path.parallel_apply(lambda x: get_roi_bbox(x))\n# ss_df[\"roi_bbox\"] = ss_df.img_path.parallel_apply(lambda x: get_roi_bbox(x))\n\n# train_df.to_csv(\"./train_labels_w_extra.csv\", index=False)\n# ss_df.to_csv(\"./sample_submission_w_extra.csv\", index=False)\n\n# train_df[\"crop_width\"] = train_df[\"roi_bbox\"].apply(lambda x: x[2]-x[0])\n# ss_df[\"crop_width\"] = ss_df[\"roi_bbox\"].apply(lambda x: x[2]-x[0])\n\n# train_df[\"crop_height\"] = train_df[\"roi_bbox\"].apply(lambda x: x[3]-x[1])\n# ss_df[\"crop_height\"] = ss_df[\"roi_bbox\"].apply(lambda x: x[3]-x[1])\n\n# train_df.to_csv(\"./train_labels_w_extra.csv\", index=False)\n# ss_df.to_csv(\"./sample_submission_w_extra.csv\", index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if APPLY_TOKENIZATION:\n    print(\"\\n... CREATING THE TOKENIZED INCHI LABEL ARRAYS STARTING ...\\n\")\n\n    print(\"\\n... STEP 1: ADDING STOP TOKEN `<END>` IF NECESSARY ...\")\n    if not train_df[\"InChI\"][0].endswith(\"<END>\"):\n        train_df[\"InChI\"] = train_df[\"InChI\"]+\"<END>\"\n        val_df[\"InChI\"] = val_df[\"InChI\"]+\"<END>\"\n    \n    print(\"\\n... STEP 2: ITERATE OVER THE DATASET (OR LOAD FROM FILE) TO CONVERT STRING TO SPARSE TOKENIZED ENCODING ...\")\n    try:  \n        with open('/kaggle/input/bms-simple-tfrecord-creation/train_captions_darien_tokenized.pickle', 'rb') as handle:\n            train_captions = pickle.load(handle)\n        with open('/kaggle/input/bms-simple-tfrecord-creation/val_captions_darien_tokenized.pickle', 'rb') as handle:\n            val_captions = pickle.load(handle)\n        print(\"\\t--> LOADING CAPTIONS FROM FILE SUCCESSFUL\")\n    except:\n        print(\"\\t--> LOADING CAPTIONS FROM FILE UNSUCCESSFUL... GENERATING FROM SCRATCH\")\n        # Captions start as zeros because that is the padding token (by using zero we can mask it later)\n        \n        print(\"\\t--> WORKING ON TRAIN CAPTIONS\")\n        train_captions = np.zeros((N_TRAIN, MAX_LEN,), dtype=np.uint8)    \n        # Make the sparse, padded encodings for our captions \n        for i, inchi in tqdm(enumerate(train_df.InChI.values), total=N_TRAIN):\n            sparse_rep = [TOK2INT[c] for c in re.findall(\"|\".join(TOKEN_LIST), inchi)]\n            train_captions[i, :len(sparse_rep)] = sparse_rep  \n\n        print(\"\\t--> WORKING ON VAL CAPTIONS\")\n        val_captions = np.zeros((N_VAL, MAX_LEN,), dtype=np.uint8)    \n        # Make the sparse, padded encodings for our captions \n        for i, inchi in tqdm(enumerate(val_df.InChI.values), total=N_VAL):\n            sparse_rep = [TOK2INT[c] for c in re.findall(\"|\".join(TOKEN_LIST), inchi)]\n            val_captions[i, :len(sparse_rep)] = sparse_rep  \n\n    # print(\"\\n... STEP 3: SAVE ARRAYS FOR FUTURE USE TO SAVE TIME IF USING THIS ENCODING ...\")\n    # Save for next time\n    # with open('/kaggle/working/train_captions_darien_tokenized.pickle', 'wb') as handle:\n        # pickle.dump(train_captions, handle, protocol=pickle.HIGHEST_PROTOCOL)\n    # with open('/kaggle/working/val_captions_darien_tokenized.pickle', 'wb') as handle:\n        # pickle.dump(val_captions, handle, protocol=pickle.HIGHEST_PROTOCOL)\n    \n    train_captions = tf.cast(train_captions, tf.uint8)\n    val_captions = tf.cast(val_captions, tf.uint8)\n    \n    print(\"\\n\\n... CREATING THE TOKENIZED INCHI LABEL ARRAYS COMPLETED ...\\n\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h3 style=\"font-family: Verdana; font-size: 20px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: navy; background-color: #ffffff;\">4.3  UTILITY FUNCTIONS FOR TFRECORD CREATION</h3>","metadata":{}},{"cell_type":"code","source":"def _bytes_feature(value, is_list=False):\n    \"\"\"Returns a bytes_list from a string / byte.\"\"\"\n    if isinstance(value, type(tf.constant(0))):\n        value = value.numpy() # BytesList won't unpack a string from an EagerTensor.\n    \n    if not is_list:\n        value = [value]\n    \n    return tf.train.Feature(bytes_list=tf.train.BytesList(value=value))\n\ndef _float_feature(value, is_list=False):\n    \"\"\"Returns a float_list from a float / double.\"\"\"\n        \n    if not is_list:\n        value = [value]\n        \n    return tf.train.Feature(float_list=tf.train.FloatList(value=value))\n\ndef _int64_feature(value, is_list=False):\n    \"\"\"Returns an int64_list from a bool / enum / int / uint.\"\"\"\n        \n    if not is_list:\n        value = [value]\n        \n    return tf.train.Feature(int64_list=tf.train.Int64List(value=value))\n\n\ndef create_tf_dataset(df, is_test=False, tokenized_inchi=None):\n    ds = tf.data.Dataset.from_tensor_slices(df[\"img_path\"].values)\n    ds_roi_bbox = tf.data.Dataset.from_tensor_slices([tf.constant(x) for x in tqdm(df[\"roi_bbox\"].values)])\n    ds = tf.data.Dataset.zip((ds, ds_roi_bbox))\n    \n    if is_test:\n        return ds\n    else:\n        if tokenized_inchi is not None:\n            target_ds = tf.data.Dataset.from_tensor_slices(tokenized_inchi)\n        else:\n            target_ds = tf.data.Dataset.from_tensor_slices(df[\"InChI\"].values)\n        return tf.data.Dataset.zip((ds, target_ds))       \n\ndef prep_tf_dataset_w_target(img_path, bbox, target, img_shape,\n                             invert=True, \n                             rotate_trick=True, \n                             repair_images=False):\n    \n    img_tensor = tf_load_image(img_path, bbox,\n                               img_size=img_shape[:2], \n                               tile_to_3_channel=img_shape[-1]==3, \n                               invert=invert, \n                               rotate_trick=rotate_trick, \n                               repair_images=repair_images)\n    return img_tensor, target\n\ndef prep_tf_dataset_wo_target(img_path, bbox, img_shape,\n                             invert=True, \n                             rotate_trick=True, \n                             repair_images=False):\n    \n    img_tensor = tf_load_image(img_path, bbox,\n                               img_size=img_shape[:2], \n                               tile_to_3_channel=img_shape[-1]==3, \n                               invert=invert, \n                               rotate_trick=rotate_trick, \n                               repair_images=repair_images)\n    img_id = tf.strings.split(tf.strings.split(img_path, \".png\")[0], \"/\")[-1]\n    return img_tensor, img_id\n\ndef serialize_raw(image, image_id, target=None):\n    \"\"\"\n    Creates a tf.Example message ready to be written to a file from 4 features.\n\n    Args:\n        image (TBD): TBD\n        image_id (str): TBD\n        target (str): | delimited integers\n    \n    Returns:\n        A tf.Example Message ready to be written to file\n    \"\"\"\n    \n    # Create a dictionary mapping the feature name to the \n    # tf.Example-compatible data type.\n    feature = {'image': _bytes_feature(tf.io.encode_png(image), is_list=False)}\n    \n    if target is not None:\n        feature[\"inchi\"] = _bytes_feature(target, is_list=False)\n    else:\n        feature[\"image_id\"] = _bytes_feature(image_id, is_list=False)\n        \n    # Create a Features message using tf.train.Example.\n    example_proto = tf.train.Example(features=tf.train.Features(feature=feature))\n    return example_proto.SerializeToString()\n\ndef serialize_tokenized(image, other, is_test=False):\n    \"\"\"\n    Creates a tf.Example message ready to be written to a file from 4 features.\n\n    Args:\n        image (TBD): TBD\n        other: Either the image_id or the target inchi\n    \n    Returns:\n        A tf.Example Message ready to be written to file\n    \"\"\"\n    # Create a dictionary mapping the feature name to the \n    # tf.Example-compatible data type.\n    feature = {'image': _bytes_feature(tf.io.encode_png(image), is_list=False)}\n    if not is_test:\n        feature[\"inchi\"] = _int64_feature(other, is_list=True)\n    else:\n        feature[\"image_id\"] = _bytes_feature(other, is_list=False)\n    \n    # Create a Features message using tf.train.Example.\n    example_proto = tf.train.Example(features=tf.train.Features(feature=feature))\n    return example_proto.SerializeToString()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_ds = create_tf_dataset(train_df, tokenized_inchi=train_captions)\ntrain_ds = train_ds.map(lambda x,y: (prep_tf_dataset_w_target(x[0], x[1], y, IMG_SHAPE, \n                                                              invert=DO_INVERT, \n                                                              rotate_trick=FIX_ROTATION, \n                                                              repair_images=DO_REPAIR)), num_parallel_calls=tf.data.AUTOTUNE).prefetch(tf.data.AUTOTUNE)\n\nval_ds = create_tf_dataset(val_df, tokenized_inchi=val_captions)\nval_ds = val_ds.map(lambda x,y: (prep_tf_dataset_w_target(x[0], x[1], y, IMG_SHAPE, \n                                                          invert=DO_INVERT, \n                                                          rotate_trick=FIX_ROTATION, \n                                                          repair_images=DO_REPAIR)), \n                    num_parallel_calls=tf.data.AUTOTUNE).prefetch(tf.data.AUTOTUNE)\n\ntest_ds = create_tf_dataset(ss_df, is_test=True)\ntest_ds = test_ds.map(lambda x,y: (prep_tf_dataset_wo_target(x, y, IMG_SHAPE, \n                                                           invert=DO_INVERT, \n                                                           rotate_trick=FIX_ROTATION, \n                                                           repair_images=DO_REPAIR)),\n                      num_parallel_calls=tf.data.AUTOTUNE).prefetch(tf.data.AUTOTUNE)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def write_tfrecords(ds, n_ex, n_ex_per_rec=20000, serialize_fn=serialize_tokenized, out_dir=\"/kaggle/working/train_records\", is_test=False):\n    n_recs = int(np.ceil(n_ex/n_ex_per_rec))\n    \n    # Make dataset iterable\n    ds = ds.as_numpy_iterator()\n    \n    # Create folder\n    if not os.path.isdir(out_dir):\n        os.makedirs(out_dir, exist_ok=True)\n        \n    # Create tfrecords\n    for i in tqdm(range(n_recs), total=n_recs):\n        print(f\"\\n... Writing TFRecord {i+1} of {n_recs} ...\\n\")\n        tfrec_path = os.path.join(out_dir, f\"{out_dir.rsplit('_', 1)[1]}_{(i+1):02}_{n_recs:02}.tfrec\")\n        with tf.io.TFRecordWriter(tfrec_path) as writer:\n            for ex in tqdm(range(n_ex_per_rec), total=n_ex_per_rec):\n                try:\n                    example = serialize_fn(*next(ds), is_test=is_test)\n                    writer.write(example)\n                except:\n                    break\n                    \n# print(\"\\n... MAKING TRAINING TFRECORDS ...\\n\")\n# write_tfrecords(train_ds, N_TRAIN, N_EX_PER_REC, serialize_fn=serialize_tokenized, out_dir=\"/kaggle/working/train_records\")\n                    \n# print(\"\\n... MAKING VALIDATION TFRECORDS ...\\n\")\n# write_tfrecords(val_ds, N_VAL, N_EX_PER_REC, serialize_fn=serialize_tokenized, out_dir=\"/kaggle/working/val_records\")\n\nprint(\"\\n... MAKING TESTING TFRECORDS ...\\n\")\nwrite_tfrecords(test_ds, N_TEST, N_EX_PER_REC, serialize_fn=serialize_tokenized, out_dir=\"/kaggle/working/test_records\", is_test=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def decode_records(serialized_example, is_test=False, is_tokenized=True, img_shape=(192,384,3)):\n    \"\"\" Parses a set of features and label from the given `serialized_example`.\n        \n        It is used as a map function for `dataset.map`\n\n    Args:\n        serialized_example (tf.Example): A serialized example containing the\n            following features:\n                – sensor_feature_0 – [int64]\n                – sensor_feature_1 – [int64]\n                – sensor_feature_2 – [int64]\n        is_test (bool, optional): Whether to allow for the label feature\n        \n    Returns:\n        A decoded tf.data.Dataset object representing the tfrecord dataset\n    \"\"\"\n    # Defaults are not specified since both keys are required.\n    feature_dict = {\n        'image': tf.io.FixedLenFeature(shape=[], dtype=tf.string),\n    }\n    \n    if not is_test:\n        if is_tokenized:\n            feature_dict[\"inchi\"] = tf.io.FixedLenFeature(shape=[MAX_LEN], dtype=tf.int64, default_value=[0]*MAX_LEN)\n        else:\n            feature_dict[\"inchi\"] = tf.io.FixedLenFeature(shape=[], dtype=tf.string, default_value='')\n    else:\n        feature_dict['image_id'] = tf.io.FixedLenFeature(shape=[], dtype=tf.string, default_value='')\n    \n  \n    # Define a parser\n    features = tf.io.parse_single_example(serialized_example, features=feature_dict)\n    \n    image = decode_tf_ex_image(features['image'], resize_to=(*img_shape[:2], 3))\n    if not is_test:\n        target = features[\"inchi\"]\n        return image, target\n    else:\n        image_id = features[\"image_id\"]\n        return image, image_id\n    \ndef decode_tf_ex_image(image_data, resize_to=(192,384,3)):\n    image = tf.image.decode_png(image_data, channels=3)\n    image = tf.reshape(image, resize_to)\n    return tf.cast(image, tf.uint8)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# print(\"\\n... TRAIN CHECK ...\\n\")\n# CHECK_TRAIN_TFREC_PATHS = sorted(tf.io.gfile.glob(f'/kaggle/working/train_records/*.tfrec'), key=lambda x: int(x[:-4].rsplit(\"_\", 2)[1]))[:1]\n# check_train_ds = tf.data.TFRecordDataset(CHECK_TRAIN_TFREC_PATHS, num_parallel_reads=tf.data.AUTOTUNE)\n# check_train_ds = check_train_ds.map(lambda x: (decode_records(x, img_shape=IMG_SHAPE)), num_parallel_calls=tf.data.AUTOTUNE)\n# for x,y in check_train_ds.take(1):\n#     plt.figure(figsize=(12,12))\n#     plt.imshow(x)\n#     plt.title(\"\".join([INT2TOK[c] for c in  y.numpy() if c not in [0,1,2]]))\n#     plt.show()\n\n    \n# print(\"\\n... VALIDATION CHECK ...\\n\")\n# CHECK_VAL_TFREC_PATHS = sorted(tf.io.gfile.glob(f'/kaggle/working/val_records/*.tfrec'), key=lambda x: int(x[:-4].rsplit(\"_\", 2)[1]))[:1]\n# check_val_ds = tf.data.TFRecordDataset(CHECK_VAL_TFREC_PATHS, num_parallel_reads=tf.data.AUTOTUNE)\n# check_val_ds = check_val_ds.map(lambda x: (decode_records(x, img_shape=IMG_SHAPE)), num_parallel_calls=tf.data.AUTOTUNE)\n# for x,y in check_val_ds.take(1):\n#     plt.figure(figsize=(12,12))\n#     plt.imshow(x)\n#     plt.title(\"\".join([INT2TOK[c] for c in  y.numpy() if c not in [0,1,2]]))\n#     plt.show()\n\n\nprint(\"\\n... TEST CHECK ...\\n\")\nCHECK_TEST_TFREC_PATHS = sorted(tf.io.gfile.glob(f'/kaggle/working/test_records/*.tfrec'), key=lambda x: int(x[:-4].rsplit(\"_\", 2)[1]))[:1]\ncheck_test_ds = tf.data.TFRecordDataset(CHECK_TEST_TFREC_PATHS, num_parallel_reads=tf.data.AUTOTUNE)\ncheck_test_ds = check_test_ds.map(lambda x: (decode_records(x, img_shape=IMG_SHAPE, is_test=True)), num_parallel_calls=tf.data.AUTOTUNE)\nfor x,y in check_test_ds.take(1):\n    plt.figure(figsize=(12,12))\n    plt.imshow(x)\n    plt.title(str(y.numpy().decode()))\n    plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}