{"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":"code","source":"!pip install tflite_runtime 2> /dev/null","metadata":{"execution":{"iopub.status.busy":"2023-04-30T18:46:04.329572Z","iopub.execute_input":"2023-04-30T18:46:04.329887Z","iopub.status.idle":"2023-04-30T18:46:18.033591Z","shell.execute_reply.started":"2023-04-30T18:46:04.329858Z","shell.execute_reply":"2023-04-30T18:46:18.032290Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Imports\n\n# activate interactive mode of pd.dataframe\nimport pandas as pd\n\nimport os\n\nimport json\nfrom tqdm import tqdm\nimport numpy as np\nimport itertools\n\n#tf model\nimport tensorflow as tf\nimport tensorflow_addons as tfa\nfrom tensorflow import keras\nfrom tensorflow.keras.layers import LSTM, Dense, BatchNormalization, Dropout, LayerNormalization\nfrom tensorflow.keras import layers, optimizers\nimport time","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-04-30T18:46:18.036372Z","iopub.execute_input":"2023-04-30T18:46:18.037094Z","iopub.status.idle":"2023-04-30T18:46:25.524386Z","shell.execute_reply.started":"2023-04-30T18:46:18.037047Z","shell.execute_reply":"2023-04-30T18:46:25.523199Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ROWS_PER_FRAME = 543\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-04-30T18:46:25.526313Z","iopub.execute_input":"2023-04-30T18:46:25.527210Z","iopub.status.idle":"2023-04-30T18:46:25.535490Z","shell.execute_reply.started":"2023-04-30T18:46:25.527166Z","shell.execute_reply":"2023-04-30T18:46:25.534184Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Feature processing","metadata":{}},{"cell_type":"code","source":"FIXED_FRAMES = 25 # reduced from 37 to 25 for experiments","metadata":{"execution":{"iopub.status.busy":"2023-04-30T18:46:45.342677Z","iopub.execute_input":"2023-04-30T18:46:45.343062Z","iopub.status.idle":"2023-04-30T18:46:45.348958Z","shell.execute_reply.started":"2023-04-30T18:46:45.343027Z","shell.execute_reply":"2023-04-30T18:46:45.347703Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class FeaturePreprocess(tf.keras.layers.Layer):\n    def __init__(self):\n        super(FeaturePreprocess, self).__init__()\n        self.fixed_frames = FIXED_FRAMES\n        \n    def call(self, x_in):        \n        \n        n_frames = tf.shape(x_in)[0]\n        \n\n        # Landmarks reduction\n        # only lips \n        LIPS = [61, 185, 40, 39, 37,  0, 267, 269, 270, 409,\n                291,146, 91,181, 84, 17, 314, 405, 321, 375, \n                78, 191, 80, 81, 82, 13, 312, 311, 310, 415, \n                95, 88, 178, 87, 14,317, 402, 318, 324, 308]\n        \n        contours = tf.gather(x_in, LIPS, axis=1)\n        lhand    = x_in[:, 468:489]\n        # pose     = x_in[:, IDX_MAP['upper_body']]\n        rhand    = x_in[:, 522:543]\n       \n        x_in = tf.concat([contours,\n                          lhand,\n                          rhand], 1) # (n_frames, 82, 2)\n        \n        # Replace nan with 0 before Interpolation\n        x_in = tf.where(tf.math.is_nan(x_in), tf.zeros_like(x_in), x_in)\n        \n        # Frames interpolation inspired by Robert Hatch [C2]\n        # If n_frames < k, use linear interpolation,\n        # else, use nearest neighbor interpolation\n        if n_frames < self.fixed_frames:\n            x_in = tf.image.resize(x_in, [self.fixed_frames, 82],method='bilinear')\n        else:\n            x_in = tf.image.resize(x_in, [self.fixed_frames, 82],method='nearest')\n        \n        x_in = tf.reshape(x_in, (1,25,82*3)) \n        attention_mask = tf.where(\n                # Checks if RH frame is non-empty\n                tf.reduce_sum(x_in[:,:,183:246], axis=2, keepdims=True) > 0,\n                # If so, mask it to 1\n                1,\n                # Otherwise check if LH frame is non-empty\n                # if so, mask it to 1, otherwise, mask it to 0\n                tf.where(tf.reduce_sum(x_in[:,:,120:183], axis=2, keepdims=True) > 0,\n                         1,0)        \n            )\n        \n        return x_in, attention_mask","metadata":{"execution":{"iopub.status.busy":"2023-04-30T18:46:45.706881Z","iopub.execute_input":"2023-04-30T18:46:45.707293Z","iopub.status.idle":"2023-04-30T18:46:45.721216Z","shell.execute_reply.started":"2023-04-30T18:46:45.707256Z","shell.execute_reply":"2023-04-30T18:46:45.720065Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"markdown","source":"## Transformer","metadata":{}},{"cell_type":"code","source":"# Epsilon value for layer normalisation\nLAYER_NORM_EPS = 1e-6\n\n# Dense layer units for landmarks\nLIPS_UNITS = 384\nHANDS_UNITS = 384\nPOSE_UNITS = 384\n# final embedding and transformer embedding size\nUNITS = 368\n\n# Transformer\nNUM_BLOCKS = 1\nMLP_RATIO = 2\n\n# Dropout\nEMBEDDING_DROPOUT = 0.00\nMLP_DROPOUT_RATIO = 0.30\nCLASSIFIER_DROPOUT_RATIO = 0.10\n\n# Initiailizers\nINIT_HE_UNIFORM = tf.keras.initializers.he_uniform\nINIT_GLOROT_UNIFORM = tf.keras.initializers.glorot_uniform\nINIT_ZEROS = tf.keras.initializers.constant(0.0)\n# Activations\nGELU = tf.keras.activations.gelu","metadata":{"execution":{"iopub.status.busy":"2023-04-30T18:46:49.802917Z","iopub.execute_input":"2023-04-30T18:46:49.803653Z","iopub.status.idle":"2023-04-30T18:46:49.812247Z","shell.execute_reply.started":"2023-04-30T18:46:49.803611Z","shell.execute_reply":"2023-04-30T18:46:49.811278Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# based on: https://stackoverflow.com/questions/67342988/verifying-the-implementation-of-multihead-attention-in-transformer\n# replaced softmax with softmax layer to support masked softmax\ndef scaled_dot_product(q,k,v, softmax, attention_mask):\n    #calculates Q . K(transpose)\n    qkt = tf.matmul(q,k,transpose_b=True)\n    #caculates scaling factor\n    dk = tf.math.sqrt(tf.cast(q.shape[-1],dtype=tf.float32))\n    scaled_qkt = qkt/dk\n    softmax = softmax(scaled_qkt, mask=attention_mask)\n    \n    z = tf.matmul(softmax,v)\n    #shape: (m,Tx,depth), same shape as q,k,v\n    return z\n\nclass MultiHeadAttention(tf.keras.layers.Layer):\n    def __init__(self,d_model,num_of_heads):\n        super(MultiHeadAttention,self).__init__()\n        self.d_model = d_model\n        self.num_of_heads = num_of_heads\n        self.depth = d_model//num_of_heads\n        # print(self.depth)\n        self.wq = [tf.keras.layers.Dense(self.depth) for i in range(num_of_heads)]\n        self.wk = [tf.keras.layers.Dense(self.depth) for i in range(num_of_heads)]\n        self.wv = [tf.keras.layers.Dense(self.depth) for i in range(num_of_heads)]\n        self.wo = tf.keras.layers.Dense(d_model)\n        self.softmax = tf.keras.layers.Softmax()\n        \n    def call(self,x, attention_mask):\n        \n        multi_attn = []\n        for i in range(self.num_of_heads):\n            Q = self.wq[i](x)\n            K = self.wk[i](x)\n            V = self.wv[i](x)\n            multi_attn.append(scaled_dot_product(Q,K,V, self.softmax, attention_mask))\n            \n        multi_head = tf.concat(multi_attn,axis=-1)\n        multi_head_attention = self.wo(multi_head)\n        return multi_head_attention","metadata":{"execution":{"iopub.status.busy":"2023-04-30T18:46:51.577010Z","iopub.execute_input":"2023-04-30T18:46:51.577525Z","iopub.status.idle":"2023-04-30T18:46:51.593621Z","shell.execute_reply.started":"2023-04-30T18:46:51.577481Z","shell.execute_reply":"2023-04-30T18:46:51.592084Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Full Transformer\nclass Transformer(tf.keras.Model):\n    def __init__(self, num_blocks):\n        super(Transformer, self).__init__(name='transformer')\n        self.num_blocks = num_blocks\n    \n    def build(self, input_shape):\n        self.ln_1s = []\n        self.mhas = []\n        self.ln_2s = []\n        self.mlps = []\n        # Make Transformer Blocks\n        for i in range(self.num_blocks):\n            # First Layer Normalisation\n            self.ln_1s.append(tf.keras.layers.BatchNormalization())\n            # Multi Head Attention\n            self.mhas.append(MultiHeadAttention(UNITS, 8))\n            # Second Layer Normalisation\n            self.ln_2s.append(tf.keras.layers.BatchNormalization())\n            # Multi Layer Perception\n            self.mlps.append(tf.keras.Sequential([\n                tf.keras.layers.Dense(UNITS),\n                BatchNormalization(),\n                tfa.layers.GELU(),\n                tf.keras.layers.Dropout(0.3),\n            ]))\n        \n    def call(self, x, attention_mask):\n        # Iterate input over transformer blocks\n        for ln_1, mha, ln_2, mlp in zip(self.ln_1s,self.mhas, self.ln_2s,self.mlps):\n            x1 = ln_1(x)\n            attention_output = mha(x, attention_mask)\n            x2 = x1 + attention_output\n            x3 = ln_2(x2)\n            x3 = mlp(x3)\n            x = x3 + x2\n    \n        return x","metadata":{"execution":{"iopub.status.busy":"2023-04-30T18:46:52.862814Z","iopub.execute_input":"2023-04-30T18:46:52.864000Z","iopub.status.idle":"2023-04-30T18:46:52.883223Z","shell.execute_reply.started":"2023-04-30T18:46:52.863954Z","shell.execute_reply":"2023-04-30T18:46:52.882192Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_model():\n    # Inputs\n    frames = tf.keras.layers.Input([25, 82*3], dtype=tf.float32, name='frames')\n    non_empty_frame_idxs = tf.keras.layers.Input([25], dtype=tf.float32, name='non_empty_frame_idxs')\n    # Padding Mask\n    mask = tf.cast(tf.math.not_equal(non_empty_frame_idxs, -1), tf.float32)\n    mask = tf.expand_dims(mask, axis=2)\n    # print(mask.shape)\n    # Embedding layer\n    x=frames\n    LIPS = x[:,:,:120]\n    LH   = x[:,:,120:183]\n    RH   = x[:,:,183:246]\n    \n    lips_embedding = Dense(256,name='lip_embedding')(LIPS)\n    lh_embedding   = Dense(256,name='lh_embedding')(LH)\n    rh_embedding   = Dense(256,name='rh_embedding')(RH)\n    \n    landmark_embedding = tf.concat([lips_embedding, lh_embedding, rh_embedding], axis=2)\n    \n    combined_embedding = tf.keras.Sequential([\n            Dense(396, name='fully_connected_1'),\n            # BatchNormalization(),\n            tfa.layers.GELU(),\n            Dense(396, name='fully_connected_2'),\n            # BatchNormalization(),\n            # tfa.layers.GELU(),\n        ], name='combined_embedding')(landmark_embedding)\n    \n    gru_out,_ = layers.GRU(368, \n                     return_sequences=True,\n                     return_state=True,\n                     name='gru_layer_1')(combined_embedding)\n    \n    # Encoder Transformer Blocks\n    x = Transformer(NUM_BLOCKS)(gru_out, mask)\n    \n#     x_1,_ = layers.GRU(468, \n#                      return_sequences=True,\n#                      return_state=True,\n#                      name='gru_layer_1')(combined_embedding)\n    \n    x = tf.keras.Sequential([\n            layers.Conv1D(filters=396, kernel_size=5, \n                          padding=\"valid\"),\n            BatchNormalization(),\n            tfa.layers.GELU(),\n            layers.GlobalMaxPooling1D(),\n        ],name='pooling')(x)        \n\n        # Define the dense layer\n    x = tf.keras.Sequential([Dense(1024),\n                             BatchNormalization(),\n                             tfa.layers.GELU(),\n                             Dropout(rate=0.3),\n                             ],name='dense_layer')(x)\n   \n    # Classification Layer\n    x = tf.keras.Sequential([Dense(250),\n                                   BatchNormalization(),\n                                   Dropout(rate=0.3),\n                                   layers.Activation('softmax', dtype='float32')],\n                            name='classifier')(x)\n    \n    outputs = x\n    \n    # Create Tensorflow Model\n    model = tf.keras.models.Model(inputs=[frames, non_empty_frame_idxs], outputs=outputs)\n    \n    # Simple Categorical Crossentropy Loss\n    loss = tf.keras.losses.SparseCategoricalCrossentropy()\n    \n    # Adam Optimizer with weight decay\n    optimizer = tf.optimizers.Adam(learning_rate=5e-4)\n    \n    # TopK Metrics\n    metrics = [\n        tf.keras.metrics.SparseCategoricalAccuracy(name='acc'),\n        tf.keras.metrics.SparseTopKCategoricalAccuracy(k=5, name='top_5_acc'),\n        tf.keras.metrics.SparseTopKCategoricalAccuracy(k=10, name='top_10_acc'),\n    ]\n    \n    model.compile(loss=loss, optimizer=optimizer, metrics=metrics)\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2023-04-30T18:46:53.216643Z","iopub.execute_input":"2023-04-30T18:46:53.217158Z","iopub.status.idle":"2023-04-30T18:46:53.243134Z","shell.execute_reply.started":"2023-04-30T18:46:53.217073Z","shell.execute_reply":"2023-04-30T18:46:53.241759Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## GRU","metadata":{}},{"cell_type":"code","source":"class GRUNet(tf.keras.Model):\n    def __init__(self, lstm_units=368):\n        super(GRUNet, self).__init__()\n        self.hidden_dim_1 = lstm_units\n        self._1_feature = 1024\n        self.out_feature = 250\n        self.embeddim = 256\n        self.units = 256\n\n        \n        self.lips_embedding = Dense(self.embeddim,name='lip_embedding')\n        self.lh_embedding   = Dense(self.embeddim,name='lh_embedding')\n        self.rh_embedding   = Dense(self.embeddim,name='rh_embedding')\n        \n        self.combined_embedding = tf.keras.Sequential([\n            Dense(self.units, name='fully_connected_1'),\n            tfa.layers.GELU(),\n            Dense(self.units, name='fully_connected_2'),\n            # tfa.layers.GELU(),\n\n        ], name='combined_embedding')\n        \n        # self.positional_embedding = PositionalEmbedding(sequence_length=25, embedding_dim=self.units)\n\n        # Define the LSTM layer\n        self.lstm_layer_1 = layers.GRU(self.hidden_dim_1, \n                                    return_sequences=True,\n                                    return_state=True,\n                                    name='gru_layer_1')\n        \n        # Define the convolutional layer\n        self.conv_layer = tf.keras.Sequential([\n            layers.Conv1D(filters=256, kernel_size=5, \n                          padding=\"valid\"),\n            BatchNormalization(),\n            tfa.layers.GELU(),\n            layers.GlobalMaxPooling1D(),\n        ])\n        \n\n        # Define the dense layer\n        self.l2 = tf.keras.Sequential([Dense(self._1_feature),\n                                       BatchNormalization(),\n                                       tfa.layers.GELU(),\n                                       Dropout(rate=0.3)])\n        \n\n        self.l3 = tf.keras.Sequential([Dense(self.out_feature),\n                                       BatchNormalization(),\n                                       tfa.layers.GELU(),\n                                       Dropout(rate=0.3),\n                                       layers.Activation('softmax', dtype='float32')])\n                              \n        \n    def call(self, inputs,attention_mask):\n        LIPS = inputs[:,:,:120]\n        LH   = inputs[:,:,120:183]\n        RH   = inputs[:,:,183:246]\n        \n        # HANDS = LH+RH\n        # print(LH.shape, RH.shape, LIPS.shape)\n        \n        # landmark embedding\n        lips_embedding = self.lips_embedding(LIPS)\n        lh_embedding   = self.lh_embedding(LH)\n        rh_embedding   = self.rh_embedding(RH)\n        \n        # Concat to one landmark\n        landmark_embedding = tf.concat([lips_embedding, lh_embedding, rh_embedding], axis=2)\n        \n        combined_embedding = self.combined_embedding(landmark_embedding)\n        \n        # positional_embedding = self.positional_embedding(combined_embedding)       \n        # embedding_attention = combined_embedding + attention_output\n        \n        gru_out, state_h1= self.lstm_layer_1(combined_embedding)\n        \n        # residual block\n        conv_out = self.conv_layer(gru_out)\n        \n        \n        output = self.l2(conv_out)\n        output = self.l3(output)\n                \n        return output","metadata":{"execution":{"iopub.status.busy":"2023-04-30T18:47:35.451415Z","iopub.execute_input":"2023-04-30T18:47:35.452342Z","iopub.status.idle":"2023-04-30T18:47:35.469713Z","shell.execute_reply.started":"2023-04-30T18:47:35.452302Z","shell.execute_reply":"2023-04-30T18:47:35.468617Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## BiGRU","metadata":{}},{"cell_type":"code","source":"class BiGRU(tf.keras.Model):\n    def __init__(self, lstm_units=768):\n        super(BiGRU, self).__init__()\n        self.hidden_dim_1 = lstm_units\n        self.hidden_dim_2 = 396\n        self.embeddim = 128\n        self._1_feature = 512\n        self.out_feature = 250\n        self.attention_units = 512\n        \n        self.lip_embedding = Dense(self.embeddim,name='lip_embedding')\n        self.lh_embedding  = Dense(self.embeddim,name='lh_embedding')\n        self.rh_embedding  = Dense(self.embeddim,name='rh_embedding')\n\n        # Define the LSTM layer\n        self.lstm_layer_1 = layers.GRU(self.hidden_dim_1, \n                                       return_sequences=True,\n                                       return_state=True,\n                                       name='gru_layer_1')\n        \n        self.lstm_layer_2 = layers.Bidirectional(layers.GRU(self.hidden_dim_2, \n                                                            return_sequences=True,\n                                                            return_state=True,\n                                                            name='gru_layer_2'),name='bigru_layer')\n        \n\n        # Define the convolutional layer\n        self.conv_layer = tf.keras.Sequential([\n            layers.Conv1D(filters=396, kernel_size=5, \n                          padding=\"valid\"),\n            BatchNormalization(),\n            tfa.layers.GELU(),\n            layers.MaxPool1D(),\n            layers.GlobalMaxPooling1D(),\n        ],name='conv_layer')        \n\n        # Define the dense layer\n        self.l2 = tf.keras.Sequential([Dense(self._1_feature*2),\n                                       BatchNormalization(),\n                                       tfa.layers.GELU(),\n                                       Dropout(rate=0.3),\n                                      ],name='dense_layer')\n\n\n        self.l3 = tf.keras.Sequential([Dense(self.out_feature),\n                                       BatchNormalization(),\n                                       Dropout(rate=0.3),\n                                       tf.keras.layers.Softmax()],name='classifier')\n        \n    def call(self, inputs, attention_mask):\n        LIPS = inputs[:,:,:120]\n        LH   = inputs[:,:,120:183]\n        RH   = inputs[:,:,183:246]\n        # print(LH.shape, RH.shape, LIPS.shape)\n        \n        # landmark embedding\n        lips_embedding = self.lip_embedding(LIPS)\n        lh_embedding   = self.lh_embedding(LH)\n        rh_embedding   = self.rh_embedding(RH)\n        \n        # Concat to one landmark\n        landmark_embedding = tf.concat([lips_embedding, lh_embedding, rh_embedding], axis=2)\n        \n        # Define the forward pass of the model\n        gru_out, _= self.lstm_layer_1(landmark_embedding)\n        gru_out_2,_,_= self.lstm_layer_2(gru_out)\n        \n        conv_out = self.conv_layer(gru_out_2)\n        \n        output = self.l2(conv_out)  \n        output = self.l3(output)\n        \n        return output","metadata":{"execution":{"iopub.status.busy":"2023-04-30T18:47:38.577209Z","iopub.execute_input":"2023-04-30T18:47:38.577579Z","iopub.status.idle":"2023-04-30T18:47:38.591163Z","shell.execute_reply.started":"2023-04-30T18:47:38.577546Z","shell.execute_reply":"2023-04-30T18:47:38.589627Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Save and Submit","metadata":{}},{"cell_type":"code","source":"class TFLiteModel(tf.Module):\n    \"\"\"\n    TensorFlow Lite model that takes input tens|ors and applies:\n        – a preprocessing model\n        – the ISLR model \n    \"\"\"\n\n    def __init__(self, islr_models):\n        \"\"\"\n        Initializes the TFLiteModel with the specified preprocessing model and ISLR model.\n        \"\"\"\n        super(TFLiteModel, self).__init__()\n\n        # Load the feature generation and main models\n        self.prep_inputs = FeaturePreprocess()\n        self.islr_models = islr_models\n    \n    @tf.function(input_signature=[tf.TensorSpec(shape=[None, 543, 3], dtype=tf.float32, name='inputs')])\n    def __call__(self, inputs):\n        \"\"\"\n        Applies the feature generation model and main model to the input tensors.\n\n        Args:\n            inputs: Input tensor with shape [batch_size, 543, 3].\n\n        Returns:\n            A dictionary with a single key 'outputs' and corresponding output tensor.\n        \"\"\"\n        x, attention_mask = self.prep_inputs(tf.cast(inputs, dtype=tf.float32))\n        outputs = tf.concat([_model({ 'frames': x, 'non_empty_frame_idxs': attention_mask}) for _model in self.islr_models], axis=0)\n        outputs = tf.reduce_mean(outputs, axis=0, keepdims=True)\n\n        # Return a dictionary with the output tensor\n        return {'outputs': outputs[0,:]}","metadata":{"execution":{"iopub.status.busy":"2023-04-30T18:47:39.860552Z","iopub.execute_input":"2023-04-30T18:47:39.861610Z","iopub.status.idle":"2023-04-30T18:47:39.873289Z","shell.execute_reply.started":"2023-04-30T18:47:39.861569Z","shell.execute_reply":"2023-04-30T18:47:39.872078Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pq_path = \"/kaggle/input/asl-signs/train_landmark_files/53618/1001379621.parquet\"\nmodel_0 = get_model()\nmodel_0.load_weights(\"/kaggle/input/gislr-transformers/model_transformer_v23.h5\")\n\ninputs = tf.keras.Input(shape=(None,82*3), ragged=False,name='frames')\nattention_mask =  tf.keras.Input(shape=(None,1), ragged=False, name='non_empty_frame_idxs')\nmodel_1 = GRUNet()\nmodel_1 = tf.keras.Model(inputs=[inputs, attention_mask], outputs=model_1.call(inputs, attention_mask))\nmodel_1.load_weights(\"/kaggle/input/gislr-model-grus/model_gru_v42i.h5\")\n\nmodel_2 = BiGRU()\nmodel_2 = tf.keras.Model(inputs=[inputs, attention_mask], outputs=model_2.call(inputs, attention_mask))\nmodel_2.load_weights(\"/kaggle/input/gislr-models/model_gru_bigru_v35.h5\")\n\ntflite_keras_model = TFLiteModel(islr_models=[model_0,model_1,model_2])","metadata":{"execution":{"iopub.status.busy":"2023-04-30T18:47:40.597147Z","iopub.execute_input":"2023-04-30T18:47:40.599842Z","iopub.status.idle":"2023-04-30T18:47:45.098092Z","shell.execute_reply.started":"2023-04-30T18:47:40.599800Z","shell.execute_reply":"2023-04-30T18:47:45.096924Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"keras_model_converter = tf.lite.TFLiteConverter.from_keras_model(tflite_keras_model)\nkeras_model_converter.optimizations = [tf.lite.Optimize.DEFAULT]\nkeras_model_converter.target_spec.supported_types = [tf.float16]\ntflite_model = keras_model_converter.convert()\n\ntflite_model_path = \"model.tflite\"\n\n# Save the model\nwith open(tflite_model_path, \"wb\") as f:\n    f.write(tflite_model)","metadata":{"execution":{"iopub.status.busy":"2023-04-30T18:47:57.743665Z","iopub.execute_input":"2023-04-30T18:47:57.744776Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\nimport tflite_runtime.interpreter as tflite\n\ninterpreter = tflite.Interpreter(tflite_model_path)\nfound_signatures = list(interpreter.get_signature_list().keys())\n# if REQUIRED_SIGNATURE not in found_signatures:\n#     raise KernelEvalException('Required input signature not found.')\nprediction_fn = interpreter.get_signature_runner(\"serving_default\")\n\noutput = prediction_fn(inputs=load_relevant_data_subset(pq_path))\nsign = np.argmax(output[\"outputs\"])\n\nprint(sign, output[\"outputs\"].shape)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!zip submission.zip $tflite_model_path","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}