{"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":"# TFLite Weighted Ensemble Starter\n\nIn this notebook, I demonstrate how to ensemble top public notebooks into a single weighted super-model and convert that to TFLite format. This can also be done for KFold model ensembles. Just be careful about the 40MB size limit. If it fails unexpectedly during submission, that might be why.\n\nI show a couple ways to deal with issues importing public notebooks. These approaches might not work for every notebook. I ran into more issues than I expected - please upvote if this is helpful!\n\n<br><br>\n\n**\\#OpenToWork**\n\nAfter 9 years as a Silicon Firmware Engineer at Intel, I am now looking for my next career opportunity. Naturally I am especially interested in Machine Learning opportunities.\n\nIn this notebook, my goals are to:\n* Demonstrate my core strengths. Soft skills like problem solving, communication, and passion.\n* Build up my knowledge skills. I love machine learning and, in particular, love to optimize anything and everything. In this notebook, I explore TensorFlow and Neural Networks.\n* Continue to build on previous Kaggle successes.\n\n**LinkedIn:** https://www.linkedin.com/in/robhatch/\n\n**Kaggle:** https://www.kaggle.com/roberthatch","metadata":{}},{"cell_type":"code","source":"#### The core functionality is simple. It is shown here for reference.\n#### The rest of the notebook is a full working example, including a couple ways to deal with more difficult imports from public notebooks.\n#### For local KFold it is much simpler, you can just keep the models in memory, since they won't take up much space. NOTE again: Be careful of 40MB max limit.\n\n# class TFLiteEnsemble(tf.keras.Model):\n#     def __init__(self, models, weights):\n#         super(TFLiteEnsemble, self).__init__()\n#         self.weight_list = weights\n#         self.models = models\n    \n#     @tf.function(input_signature=[tf.TensorSpec(shape=[None, 543, 3], dtype=tf.float32, name='inputs')])\n#     def call(self, inputs):\n#         x = tf.cast(inputs, dtype=tf.float32)\n#         ## The commented out line might work better for KFold, I haven't tested it yet.\n#         # model_outputs = [model(x) for model in self.models]\n\n#         ## This version with '.popitem()[1]' requires that the 'model(inputs)' call always returns a dict with only one key: value pair.\n#         ## It is a workaround due to different models having dict['output'] vs dict['outputs']\n#         ## Second workaround: tf.reshape to handle either (1, 250) or (250)\n#         model_outputs = [tf.reshape(model(x).popitem()[1], [-1]) for model in self.models]\n#         ## NOTE: this assumes weights add to 1.0!\n#         outputs = tf.add_n([inp for (w, inp) in zip(self.weight_list, model_outputs)])\n\n#         # Return a dictionary with the output tensor\n#         return {'outputs': outputs}\n\n# ensemble_model = TFLiteEnsemble(models, weights)","metadata":{"execution":{"iopub.status.busy":"2023-03-09T00:47:00.474302Z","iopub.execute_input":"2023-03-09T00:47:00.474738Z","iopub.status.idle":"2023-03-09T00:47:00.504378Z","shell.execute_reply.started":"2023-03-09T00:47:00.474701Z","shell.execute_reply":"2023-03-09T00:47:00.503054Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# IMPORTS","metadata":{}},{"cell_type":"code","source":"print(\"\\n... PIP INSTALLS STARTING ...\\n\")\nprint(\"\\n... PIP INSTALLS COMPLETE ...\\n\")\n\n\nprint(\"\\n... IMPORTS STARTING ...\\n\")\nprint(\"\\n\\tVERSION INFORMATION\")\n# Competition Specific Imports (You'll see why we need these later)\n# mediapipe above\n\n# Machine Learning and Data Science Imports (basics)\nimport tensorflow as tf; print(f\"\\t\\t– TENSORFLOW VERSION: {tf.__version__}\");\n# import tensorflow_io as tfio; print(f\"\\t\\t– TENSORFLOW-IO VERSION: {tfio.__version__}\");\nimport pandas as pd; pd.options.mode.chained_assignment = None; pd.set_option('display.max_columns', None);\nimport numpy as np; print(f\"\\t\\t– NUMPY VERSION: {np.__version__}\");\nimport sklearn; print(f\"\\t\\t– SKLEARN VERSION: {sklearn.__version__}\");\n\n# Built-In Imports (mostly don't worry about these)\nfrom kaggle_datasets import KaggleDatasets\nfrom collections import Counter\nfrom datetime import datetime\nfrom zipfile import ZipFile\nfrom glob import glob\nimport Levenshtein\nimport warnings\nimport requests\nimport hashlib\nimport imageio\nimport IPython\nimport sklearn\nimport urllib\nimport zipfile\nimport pickle\nimport random\nimport shutil\nimport string\nimport json\nimport math\nimport time\nimport gzip\nimport ast\nimport sys\nimport io\nimport os\nimport gc\nimport re\n\nprint(\"\\n\\n... IMPORTS COMPLETE ...\\n\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-03-09T00:47:00.506426Z","iopub.execute_input":"2023-03-09T00:47:00.506804Z","iopub.status.idle":"2023-03-09T00:47:12.161754Z","shell.execute_reply.started":"2023-03-09T00:47:00.506767Z","shell.execute_reply":"2023-03-09T00:47:12.160350Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"models = []\nweights = []","metadata":{"execution":{"iopub.status.busy":"2023-03-09T00:47:12.163232Z","iopub.execute_input":"2023-03-09T00:47:12.164715Z","iopub.status.idle":"2023-03-09T00:47:12.170010Z","shell.execute_reply.started":"2023-03-09T00:47:12.164668Z","shell.execute_reply":"2023-03-09T00:47:12.168508Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Approach 1\nFor TF notebook like mine, that's based on @dschettler 's notebook format, the easiest way I found was to save the final keras model in a personal copy of the original notebook.\n\nIt requires creating a copy, modifying it, and rerunning it, but it is only one line of code, and can be simpler than copying the entire feature gen preprocessing source code.\n\nUPDATE: 3 lines of code:\nBEFORE:\n``` python\nclass TFLiteModel(tf.Module):\n# ...\n    def __call__(self, inputs):\n# ...\n```\nAFTER:\n``` python\nclass TFLiteModel(tf.keras.Model):\n# ...\n    def call(self, inputs):\n# ...\ntflite_keras_model.save(\"./models/final_model\")\n```\n","metadata":{}},{"cell_type":"code","source":"models.append(tf.keras.models.load_model(\"/kaggle/input/gislr-lb-0-63-on-the-shoulders/models/final_model\"))\nweights.append(0.7)\n\nprint(models[-1](tf.keras.Input(shape=(543, 3))))\n\nmodels.append(tf.keras.models.load_model(\"/kaggle/input/gislr-small-version-on-the-shoulders/models/final_model\"))\nweights.append(0.3)\n\nprint(models[-1](tf.keras.Input(shape=(543, 3))))","metadata":{"execution":{"iopub.status.busy":"2023-03-09T00:47:12.173744Z","iopub.execute_input":"2023-03-09T00:47:12.174815Z","iopub.status.idle":"2023-03-09T00:47:16.953614Z","shell.execute_reply.started":"2023-03-09T00:47:12.174721Z","shell.execute_reply":"2023-03-09T00:47:16.952404Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Approach 2\nFor PyTorch notebook like [this one](https://www.kaggle.com/code/clemchris/asl-sign-detection-pytorch-lightning), it is saved, but not saved as a keras model. However, since it is a PyTorch converted notebook, it is ... well, mostly self-contained TensorFlow template.\nCopy the relevant source notebook classes, the final wrapper class, AND the feature gen class it refers to.\nThen I needed to do three more things in the case of this notebook.\n\n* Convert class ASLInferModel(tf.Module) to class ASLInferModel(tf.keras.layers.Layer)\n* Include configuration defines and functions used inside FeatureGenTF\n* return output directly not \"output_tensors\" dict","metadata":{}},{"cell_type":"code","source":"# Config\ntf_model_path = \"/kaggle/input/asl-sign-detection-pytorch-lightning/tf_model\"","metadata":{"execution":{"iopub.status.busy":"2023-03-09T00:47:16.955355Z","iopub.execute_input":"2023-03-09T00:47:16.955708Z","iopub.status.idle":"2023-03-09T00:47:16.961023Z","shell.execute_reply.started":"2023-03-09T00:47:16.955674Z","shell.execute_reply":"2023-03-09T00:47:16.959146Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DROP_Z = False\n\nNUM_FRAMES = 15\nSEGMENTS = 3\n\nLEFT_HAND_OFFSET = 468\nPOSE_OFFSET = LEFT_HAND_OFFSET + 21\nRIGHT_HAND_OFFSET = POSE_OFFSET + 33\n\n## average over the entire face, and the entire 'pose'\naveraging_sets = [[0, 468], [POSE_OFFSET, 33]]\n\nlip_landmarks = [\n    61,\n    185,\n    40,\n    39,\n    37,\n    0,\n    267,\n    269,\n    270,\n    409,\n    291,\n    146,\n    91,\n    181,\n    84,\n    17,\n    314,\n    405,\n    321,\n    375,\n    78,\n    191,\n    80,\n    81,\n    82,\n    13,\n    312,\n    311,\n    310,\n    415,\n    95,\n    88,\n    178,\n    87,\n    14,\n    317,\n    402,\n    318,\n    324,\n    308,\n]\nleft_hand_landmarks = list(range(LEFT_HAND_OFFSET, LEFT_HAND_OFFSET + 21))\nright_hand_landmarks = list(range(RIGHT_HAND_OFFSET, RIGHT_HAND_OFFSET + 21))\n\npoint_landmarks = [\n    item\n    for sublist in [lip_landmarks, left_hand_landmarks, right_hand_landmarks]\n    for item in sublist\n]\n\nLANDMARKS = len(point_landmarks) + len(averaging_sets)\nprint(LANDMARKS)\nif DROP_Z:\n    INPUT_SHAPE = (NUM_FRAMES, LANDMARKS * 2)\nelse:\n    INPUT_SHAPE = (NUM_FRAMES, LANDMARKS * 3)\n\nFLAT_INPUT_SHAPE = (INPUT_SHAPE[0] + 2 * (SEGMENTS + 1)) * INPUT_SHAPE[1]","metadata":{"execution":{"iopub.status.busy":"2023-03-09T00:47:16.962350Z","iopub.execute_input":"2023-03-09T00:47:16.962670Z","iopub.status.idle":"2023-03-09T00:47:16.987707Z","shell.execute_reply.started":"2023-03-09T00:47:16.962640Z","shell.execute_reply":"2023-03-09T00:47:16.986363Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def tf_nan_mean(x, axis=0):\n    return tf.reduce_sum(\n        tf.where(tf.math.is_nan(x), tf.zeros_like(x), x), axis=axis\n    ) / tf.reduce_sum(\n        tf.where(tf.math.is_nan(x), tf.zeros_like(x), tf.ones_like(x)), axis=axis\n    )\n\n\ndef tf_nan_std(x, axis=0):\n    d = x - tf_nan_mean(x, axis=axis)\n    return tf.math.sqrt(tf_nan_mean(d * d, axis=axis))\n\n\ndef flatten_means_and_stds(x, axis=0):\n    # Get means and stds\n    x_mean = tf_nan_mean(x, axis=0)\n    x_std = tf_nan_std(x, axis=0)\n\n    x_out = tf.concat([x_mean, x_std], axis=0)\n    x_out = tf.reshape(x_out, (1, INPUT_SHAPE[1] * 2))\n    x_out = tf.where(tf.math.is_finite(x_out), x_out, tf.zeros_like(x_out))\n    return x_out","metadata":{"execution":{"iopub.status.busy":"2023-03-09T00:47:16.990006Z","iopub.execute_input":"2023-03-09T00:47:16.990966Z","iopub.status.idle":"2023-03-09T00:47:17.006656Z","shell.execute_reply.started":"2023-03-09T00:47:16.990894Z","shell.execute_reply":"2023-03-09T00:47:17.005198Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class FeatureGenTF(tf.keras.layers.Layer):\n    def __init__(self):\n        super().__init__()\n\n    def call(self, x_in):\n        if DROP_Z:\n            x_in = x_in[:, :, 0:2]\n        x_list = [\n            tf.expand_dims(\n                tf_nan_mean(x_in[:, av_set[0] : av_set[0] + av_set[1], :], axis=1),\n                axis=1,\n            )\n            for av_set in averaging_sets\n        ]\n        x_list.append(tf.gather(x_in, point_landmarks, axis=1))\n        x = tf.concat(x_list, 1)\n\n        x_padded = x\n        for i in range(SEGMENTS):\n            p0 = tf.where(\n                ((tf.shape(x_padded)[0] % SEGMENTS) > 0) & ((i % 2) != 0), 1, 0\n            )\n            p1 = tf.where(\n                ((tf.shape(x_padded)[0] % SEGMENTS) > 0) & ((i % 2) == 0), 1, 0\n            )\n            paddings = [[p0, p1], [0, 0], [0, 0]]\n            x_padded = tf.pad(x_padded, paddings, mode=\"SYMMETRIC\")\n        x_list = tf.split(x_padded, SEGMENTS)\n        x_list = [flatten_means_and_stds(_x, axis=0) for _x in x_list]\n\n        x_list.append(flatten_means_and_stds(x, axis=0))\n\n        ## Resize only dimension 0. Resize can't handle nan, so replace nan with that dimension's avg value to reduce impact.\n        x = tf.image.resize(\n            tf.where(tf.math.is_finite(x), x, tf_nan_mean(x, axis=0)),\n            [NUM_FRAMES, LANDMARKS],\n        )\n        x = tf.reshape(x, (1, INPUT_SHAPE[0] * INPUT_SHAPE[1]))\n        x = tf.where(tf.math.is_nan(x), tf.zeros_like(x), x)\n        x_list.append(x)\n        x = tf.concat(x_list, axis=1)\n        return x","metadata":{"execution":{"iopub.status.busy":"2023-03-09T00:47:17.010801Z","iopub.execute_input":"2023-03-09T00:47:17.011346Z","iopub.status.idle":"2023-03-09T00:47:17.028245Z","shell.execute_reply.started":"2023-03-09T00:47:17.011290Z","shell.execute_reply":"2023-03-09T00:47:17.026638Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class ASLInferModel(tf.keras.layers.Layer):\n    def __init__(self, tf_model_path):\n        super().__init__()\n\n        self.feature_gen = FeatureGenTF()\n        self.model = tf.saved_model.load(tf_model_path)\n        self.feature_gen.trainable = False\n        self.model.trainable = False\n\n    @tf.function(\n        input_signature=[\n            tf.TensorSpec(shape=[None, 543, 3], dtype=tf.float32, name=\"inputs\")\n        ]\n    )\n    def call(self, inputs):\n        features = self.feature_gen(tf.cast(inputs, dtype=tf.float32))\n        outputs = self.model(input=features)\n        return outputs\n\n\nmytfmodel = ASLInferModel(tf_model_path)","metadata":{"execution":{"iopub.status.busy":"2023-03-09T00:47:17.029962Z","iopub.execute_input":"2023-03-09T00:47:17.030710Z","iopub.status.idle":"2023-03-09T00:47:18.253076Z","shell.execute_reply.started":"2023-03-09T00:47:17.030667Z","shell.execute_reply":"2023-03-09T00:47:18.251734Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## Models are too big, can't combine!\n# models.append(mytfmodel)\n# weights.append(0.3)\n\n# print(models[-1](tf.keras.Input(shape=(543, 3))))","metadata":{"execution":{"iopub.status.busy":"2023-03-09T00:47:18.257759Z","iopub.execute_input":"2023-03-09T00:47:18.258530Z","iopub.status.idle":"2023-03-09T00:47:18.263766Z","shell.execute_reply.started":"2023-03-09T00:47:18.258480Z","shell.execute_reply":"2023-03-09T00:47:18.262034Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Ensemble Model","metadata":{}},{"cell_type":"code","source":"class TFLiteEnsemble(tf.keras.Model):\n    def __init__(self, models, weights):\n        super(TFLiteEnsemble, self).__init__()\n        self.weight_list = weights\n        self.models = models\n    \n    @tf.function(input_signature=[tf.TensorSpec(shape=[None, 543, 3], dtype=tf.float32, name='inputs')])\n    def call(self, inputs):\n        x = tf.cast(inputs, dtype=tf.float32)\n        ## The commented out line might work better for KFold, I haven't tested it yet.\n        # model_outputs = [model(x) for model in self.models]\n\n        ## This version with '.popitem()[1]' requires that the 'model(inputs)' call always returns a dict with only one key: value pair.\n        ## It is a workaround due to different models having dict['output'] vs dict['outputs']\n        ## Second workaround: tf.reshape to handle either (1, 250) or (250)\n        model_outputs = [tf.reshape(model(x).popitem()[1], [-1]) for model in self.models]\n        ## NOTE: this assumes weights add to 1.0!\n        outputs = tf.add_n([tf.multiply(w, inp) for (w, inp) in zip(self.weight_list, model_outputs)])\n\n        # Return a dictionary with the output tensor\n        return {'outputs': outputs}\n\nensemble_model = TFLiteEnsemble(models, weights)","metadata":{"execution":{"iopub.status.busy":"2023-03-09T00:47:18.265241Z","iopub.execute_input":"2023-03-09T00:47:18.265592Z","iopub.status.idle":"2023-03-09T00:47:18.285322Z","shell.execute_reply.started":"2023-03-09T00:47:18.265560Z","shell.execute_reply":"2023-03-09T00:47:18.283799Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# TFLite Submission","metadata":{}},{"cell_type":"code","source":"keras_model_converter = tf.lite.TFLiteConverter.from_keras_model(ensemble_model)\ntflite_model = keras_model_converter.convert()\nwith open('model.tflite', 'wb') as f:\n    f.write(tflite_model)\n!zip submission.zip model.tflite\n\nprint(\"done\")","metadata":{"execution":{"iopub.status.busy":"2023-03-09T00:47:18.286886Z","iopub.execute_input":"2023-03-09T00:47:18.287518Z","iopub.status.idle":"2023-03-09T00:47:32.410439Z","shell.execute_reply.started":"2023-03-09T00:47:18.287475Z","shell.execute_reply":"2023-03-09T00:47:32.408671Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Test that it worked!","metadata":{}},{"cell_type":"code","source":"ROWS_PER_FRAME = 543  # number of landmarks per frame\ndef load_relevant_data_subset(pq_path):\n    data_columns = ['x', 'y', 'z']\n    data = pd.read_parquet(pq_path, columns=data_columns)\n    n_frames = int(len(data) / ROWS_PER_FRAME)\n    data = data.values.reshape(n_frames, ROWS_PER_FRAME, len(data_columns))\n    return data.astype(np.float32)","metadata":{"execution":{"iopub.status.busy":"2023-03-09T00:47:32.412567Z","iopub.execute_input":"2023-03-09T00:47:32.412978Z","iopub.status.idle":"2023-03-09T00:47:32.421284Z","shell.execute_reply.started":"2023-03-09T00:47:32.412936Z","shell.execute_reply":"2023-03-09T00:47:32.419835Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Manually add decoder\ndecoder = {v:k for k, v in {'tv': 0, 'after': 1, 'airplane': 2, 'all': 3, 'alligator': 4, 'animal': 5, 'another': 6, 'any': 7, 'apple': 8, 'arm': 9, 'aunt': 10, 'awake': 11, 'backyard': 12, 'bad': 13, 'balloon': 14, \n           'bath': 15, 'because': 16, 'bed': 17, 'bedroom': 18, 'bee': 19, 'before': 20, 'beside': 21, 'better': 22, 'bird': 23, 'black': 24, 'blow': 25, 'blue': 26, 'boat': 27, 'book': 28, 'boy': 29, \n           'brother': 30, 'brown': 31, 'bug': 32, 'bye': 33, 'callonphone': 34, 'can': 35, 'car': 36, 'carrot': 37, 'cat': 38, 'cereal': 39, 'chair': 40, 'cheek': 41, 'child': 42, 'chin': 43, 'chocolate': 44, \n           'clean': 45, 'close': 46, 'closet': 47, 'cloud': 48, 'clown': 49, 'cow': 50, 'cowboy': 51, 'cry': 52, 'cut': 53, 'cute': 54, 'dad': 55, 'dance': 56, 'dirty': 57, 'dog': 58, 'doll': 59, 'donkey': 60, \n           'down': 61, 'drawer': 62, 'drink': 63, 'drop': 64, 'dry': 65, 'dryer': 66, 'duck': 67, 'ear': 68, 'elephant': 69, 'empty': 70, 'every': 71, 'eye': 72, 'face': 73, 'fall': 74, 'farm': 75, 'fast': 76, \n           'feet': 77, 'find': 78, 'fine': 79, 'finger': 80, 'finish': 81, 'fireman': 82, 'first': 83, 'fish': 84, 'flag': 85, 'flower': 86, 'food': 87, 'for': 88, 'frenchfries': 89, 'frog': 90, 'garbage': 91, \n           'gift': 92, 'giraffe': 93, 'girl': 94, 'give': 95, 'glasswindow': 96, 'go': 97, 'goose': 98, 'grandma': 99, 'grandpa': 100, 'grass': 101, 'green': 102, 'gum': 103, 'hair': 104, 'happy': 105, 'hat': 106, \n           'hate': 107, 'have': 108, 'haveto': 109, 'head': 110, 'hear': 111, 'helicopter': 112, 'hello': 113, 'hen': 114, 'hesheit': 115, 'hide': 116, 'high': 117, 'home': 118, 'horse': 119, 'hot': 120, 'hungry': 121, \n           'icecream': 122, 'if': 123, 'into': 124, 'jacket': 125, 'jeans': 126, 'jump': 127, 'kiss': 128, 'kitty': 129, 'lamp': 130, 'later': 131, 'like': 132, 'lion': 133, 'lips': 134, 'listen': 135, 'look': 136, \n           'loud': 137, 'mad': 138, 'make': 139, 'man': 140, 'many': 141, 'milk': 142, 'minemy': 143, 'mitten': 144, 'mom': 145, 'moon': 146, 'morning': 147, 'mouse': 148, 'mouth': 149, 'nap': 150, 'napkin': 151, \n           'night': 152, 'no': 153, 'noisy': 154, 'nose': 155, 'not': 156, 'now': 157, 'nuts': 158, 'old': 159, 'on': 160, 'open': 161, 'orange': 162, 'outside': 163, 'owie': 164, 'owl': 165, 'pajamas': 166, 'pen': 167,\n           'pencil': 168, 'penny': 169, 'person': 170, 'pig': 171, 'pizza': 172, 'please': 173, 'police': 174, 'pool': 175, 'potty': 176, 'pretend': 177, 'pretty': 178, 'puppy': 179, 'puzzle': 180, 'quiet': 181, 'radio': 182, \n           'rain': 183, 'read': 184, 'red': 185, 'refrigerator': 186, 'ride': 187, 'room': 188, 'sad': 189, 'same': 190, 'say': 191, 'scissors': 192, 'see': 193, 'shhh': 194, 'shirt': 195, 'shoe': 196, 'shower': 197, \n           'sick': 198, 'sleep': 199, 'sleepy': 200, 'smile': 201, 'snack': 202, 'snow': 203, 'stairs': 204, 'stay': 205, 'sticky': 206, 'store': 207, 'story': 208, 'stuck': 209, 'sun': 210, 'table': 211, 'talk': 212, \n           'taste': 213, 'thankyou': 214, 'that': 215, 'there': 216, 'think': 217, 'thirsty': 218, 'tiger': 219, 'time': 220, 'tomorrow': 221, 'tongue': 222, 'tooth': 223, 'toothbrush': 224, 'touch': 225, 'toy': 226, \n           'tree': 227, 'uncle': 228, 'underwear': 229, 'up': 230, 'vacuum': 231, 'wait': 232, 'wake': 233, 'water': 234, 'wet': 235, 'weus': 236, 'where': 237, 'white': 238, 'who': 239, 'why': 240, 'will': 241, \n           'wolf': 242, 'yellow': 243, 'yes': 244, 'yesterday': 245, 'yourself': 246, 'yucky': 247, 'zebra': 248, 'zipper': 249}.items()}","metadata":{"execution":{"iopub.status.busy":"2023-03-09T00:47:32.422866Z","iopub.execute_input":"2023-03-09T00:47:32.424132Z","iopub.status.idle":"2023-03-09T00:47:32.469436Z","shell.execute_reply.started":"2023-03-09T00:47:32.424086Z","shell.execute_reply":"2023-03-09T00:47:32.467973Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install tflite-runtime\nimport tflite_runtime.interpreter as tflite\n\ninterpreter = tflite.Interpreter(\"model.tflite\")\nfound_signatures = list(interpreter.get_signature_list().keys())\nprediction_fn = interpreter.get_signature_runner(\"serving_default\")\n\noutput = prediction_fn(inputs=load_relevant_data_subset(f'/kaggle/input/asl-signs/{pd.read_csv(\"/kaggle/input/asl-signs/train.csv\").path[0]}'))\nsign = np.argmax(output[\"outputs\"])\n\nprint(\"PRED : \", decoder[sign])\nprint(\"GT   : \", pd.read_csv(\"/kaggle/input/asl-signs/train.csv\").sign[0])","metadata":{"execution":{"iopub.status.busy":"2023-03-09T00:47:32.471012Z","iopub.execute_input":"2023-03-09T00:47:32.471389Z","iopub.status.idle":"2023-03-09T00:47:45.953296Z","shell.execute_reply.started":"2023-03-09T00:47:32.471348Z","shell.execute_reply":"2023-03-09T00:47:45.951493Z"},"trusted":true},"execution_count":null,"outputs":[]}]}