{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":46105,"databundleVersionId":5087314,"sourceType":"competition"},{"sourceId":5600436,"sourceType":"datasetVersion","datasetId":3221731}],"dockerImageVersionId":30408,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"**NOTE: This submission utilizes the maximum inference time limit, so depending on the situation, a submission scoring error may occur. \n\nHowever, you can succeed by trying multiple times.**","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv('/kaggle/input/asl-signs/train.csv')\nprint(\"\\n\\n... LOAD SIGN TO PREDICTION INDEX MAP FROM JSON FILE ...\\n\")\ns2p_map = {k.lower():v for k,v in read_json_file(os.path.join(\"/kaggle/input/asl-signs/sign_to_prediction_index_map.json\")).items()}\np2s_map = {v:k for k,v in read_json_file(os.path.join(\"/kaggle/input/asl-signs/sign_to_prediction_index_map.json\")).items()}\nencoder = lambda x: s2p_map.get(x.lower())\ndecoder = lambda x: p2s_map.get(x)\n# print(s2p_map)\ntrain_df['label'] = train_df.sign.map(encoder)","metadata":{"execution":{"iopub.status.busy":"2025-03-26T20:56:45.306075Z","iopub.execute_input":"2025-03-26T20:56:45.306846Z","iopub.status.idle":"2025-03-26T20:56:45.455833Z","shell.execute_reply.started":"2025-03-26T20:56:45.306809Z","shell.execute_reply":"2025-03-26T20:56:45.454877Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nimport numpy as np\nimport pandas as pd\nimport json\nimport os\nfrom multiprocessing import cpu_count\n\ndef read_json_file(file_path):\n    \"\"\"Read a JSON file and parse it into a Python object.\n\n    Args:\n        file_path (str): The path to the JSON file to read.\n\n    Returns:\n        dict: A dictionary object representing the JSON data.\n        \n    Raises:\n        FileNotFoundError: If the specified file path does not exist.\n        ValueError: If the specified file path does not contain valid JSON data.\n    \"\"\"\n    try:\n        # Open the file and load the JSON data into a Python object\n        with open(file_path, 'r') as file:\n            json_data = json.load(file)\n        return json_data\n    except FileNotFoundError:\n        # Raise an error if the file path does not exist\n        raise FileNotFoundError(f\"File not found: {file_path}\")\n    except ValueError:\n        # Raise an error if the file does not contain valid JSON data\n        raise ValueError(f\"Invalid JSON data in file: {file_path}\")\n\ncpu_count()","metadata":{"execution":{"iopub.status.busy":"2025-03-26T20:41:09.931575Z","iopub.execute_input":"2025-03-26T20:41:09.931839Z","iopub.status.idle":"2025-03-26T20:41:17.338255Z","shell.execute_reply.started":"2025-03-26T20:41:09.931814Z","shell.execute_reply":"2025-03-26T20:41:17.33721Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"ROWS_PER_FRAME = 543\nMAX_LEN = 384\nCROP_LEN = MAX_LEN\nNUM_CLASSES  = 250\nPAD = -100.\nNOSE=[\n    1,2,98,327\n]\nLNOSE = [98]\nRNOSE = [327]\nLIP = [ 0, \n    61, 185, 40, 39, 37, 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]\nLLIP = [84,181,91,146,61,185,40,39,37,87,178,88,95,78,191,80,81,82]\nRLIP = [314,405,321,375,291,409,270,269,267,317,402,318,324,308,415,310,311,312]\n\nPOSE = [500, 502, 504, 501, 503, 505, 512, 513]\nLPOSE = [513,505,503,501]\nRPOSE = [512,504,502,500]\n\nREYE = [\n    33, 7, 163, 144, 145, 153, 154, 155, 133,\n    246, 161, 160, 159, 158, 157, 173,\n]\nLEYE = [\n    263, 249, 390, 373, 374, 380, 381, 382, 362,\n    466, 388, 387, 386, 385, 384, 398,\n]\n\nLHAND = np.arange(468, 489).tolist()\nRHAND = np.arange(522, 543).tolist()\n\nPOINT_LANDMARKS = LIP + LHAND + RHAND + NOSE + REYE + LEYE #+POSE\n\nNUM_NODES = len(POINT_LANDMARKS)\nCHANNELS = 6*NUM_NODES\n\nprint(NUM_NODES)\nprint(CHANNELS)\n\ndef tf_nan_mean(x, axis=0, keepdims=False):\n    return tf.reduce_sum(tf.where(tf.math.is_nan(x), tf.zeros_like(x), x), axis=axis, keepdims=keepdims) / tf.reduce_sum(tf.where(tf.math.is_nan(x), tf.zeros_like(x), tf.ones_like(x)), axis=axis, keepdims=keepdims)\n\ndef tf_nan_std(x, center=None, axis=0, keepdims=False):\n    if center is None:\n        center = tf_nan_mean(x, axis=axis,  keepdims=True)\n    d = x - center\n    return tf.math.sqrt(tf_nan_mean(d * d, axis=axis, keepdims=keepdims))\n\nclass Preprocess(tf.keras.layers.Layer):\n    def __init__(self, max_len=MAX_LEN, point_landmarks=POINT_LANDMARKS, **kwargs):\n        super().__init__(**kwargs)\n        self.max_len = max_len\n        self.point_landmarks = point_landmarks\n\n    def call(self, inputs):\n        if tf.rank(inputs) == 3:\n            x = inputs[None,...]\n        else:\n            x = inputs\n        \n        mean = tf_nan_mean(tf.gather(x, [17], axis=2), axis=[1,2], keepdims=True)\n        mean = tf.where(tf.math.is_nan(mean), tf.constant(0.5,x.dtype), mean)\n        x = tf.gather(x, self.point_landmarks, axis=2) #N,T,P,C\n        std = tf_nan_std(x, center=mean, axis=[1,2], keepdims=True)\n        \n        x = (x - mean)/std\n\n        if self.max_len is not None:\n            x = x[:,:self.max_len]\n        length = tf.shape(x)[1]\n        x = x[...,:2]\n\n        dx = tf.cond(tf.shape(x)[1]>1,lambda:tf.pad(x[:,1:] - x[:,:-1], [[0,0],[0,1],[0,0],[0,0]]),lambda:tf.zeros_like(x))\n\n        dx2 = tf.cond(tf.shape(x)[1]>2,lambda:tf.pad(x[:,2:] - x[:,:-2], [[0,0],[0,2],[0,0],[0,0]]),lambda:tf.zeros_like(x))\n\n        x = tf.concat([\n            tf.reshape(x, (-1,length,2*len(self.point_landmarks))),\n            tf.reshape(dx, (-1,length,2*len(self.point_landmarks))),\n            tf.reshape(dx2, (-1,length,2*len(self.point_landmarks))),\n        ], axis = -1)\n        \n        x = tf.where(tf.math.is_nan(x),tf.constant(0.,x.dtype),x)\n        \n        return x","metadata":{"execution":{"iopub.status.busy":"2025-03-26T20:41:17.595259Z","iopub.execute_input":"2025-03-26T20:41:17.595531Z","iopub.status.idle":"2025-03-26T20:41:17.616589Z","shell.execute_reply.started":"2025-03-26T20:41:17.595506Z","shell.execute_reply":"2025-03-26T20:41:17.615601Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class ECA(tf.keras.layers.Layer):\n    def __init__(self, kernel_size=5, **kwargs):\n        super().__init__(**kwargs)\n        self.supports_masking = True\n        self.kernel_size = kernel_size\n        self.conv = tf.keras.layers.Conv1D(1, kernel_size=kernel_size, strides=1, padding=\"same\", use_bias=False)\n\n    def call(self, inputs, mask=None):\n        nn = tf.keras.layers.GlobalAveragePooling1D()(inputs, mask=mask)\n        nn = tf.expand_dims(nn, -1)\n        nn = self.conv(nn)\n        nn = tf.squeeze(nn, -1)\n        nn = tf.nn.sigmoid(nn)\n        nn = nn[:,None,:]\n        return inputs * nn\n\nclass LateDropout(tf.keras.layers.Layer):\n    def __init__(self, rate, noise_shape=None, start_step=0, **kwargs):\n        super().__init__(**kwargs)\n        self.supports_masking = True\n        self.rate = rate\n        self.start_step = start_step\n        self.dropout = tf.keras.layers.Dropout(rate, noise_shape=noise_shape)\n      \n    def build(self, input_shape):\n        super().build(input_shape)\n        agg = tf.VariableAggregation.ONLY_FIRST_REPLICA\n        self._train_counter = tf.Variable(0, dtype=\"int64\", aggregation=agg, trainable=False)\n\n    def call(self, inputs, training=False):\n        x = tf.cond(self._train_counter < self.start_step, lambda:inputs, lambda:self.dropout(inputs, training=training))\n        if training:\n            self._train_counter.assign_add(1)\n        return x\n\nclass CausalDWConv1D(tf.keras.layers.Layer):\n    def __init__(self, \n        kernel_size=17,\n        dilation_rate=1,\n        use_bias=False,\n        depthwise_initializer='glorot_uniform',\n        name='', **kwargs):\n        super().__init__(name=name,**kwargs)\n        self.causal_pad = tf.keras.layers.ZeroPadding1D((dilation_rate*(kernel_size-1),0),name=name + '_pad')\n        self.dw_conv = tf.keras.layers.DepthwiseConv1D(\n                            kernel_size,\n                            strides=1,\n                            dilation_rate=dilation_rate,\n                            padding='valid',\n                            use_bias=use_bias,\n                            depthwise_initializer=depthwise_initializer,\n                            name=name + '_dwconv')\n        self.supports_masking = True\n        \n    def call(self, inputs):\n        x = self.causal_pad(inputs)\n        x = self.dw_conv(x)\n        return x\n\ndef Conv1DBlock(channel_size,\n          kernel_size,\n          dilation_rate=1,\n          drop_rate=0.0,\n          expand_ratio=2,\n          se_ratio=0.25,\n          activation='swish',\n          name=None):\n    '''\n    efficient conv1d block, @hoyso48\n    '''\n    if name is None:\n        name = str(tf.keras.backend.get_uid(\"mbblock\"))\n    # Expansion phase\n    def apply(inputs):\n        channels_in = tf.keras.backend.int_shape(inputs)[-1]\n        channels_expand = channels_in * expand_ratio\n\n        skip = inputs\n\n        x = tf.keras.layers.Dense(\n            channels_expand,\n            use_bias=True,\n            activation=activation,\n            name=name + '_expand_conv')(inputs)\n\n        # Depthwise Convolution\n        x = CausalDWConv1D(kernel_size,\n            dilation_rate=dilation_rate,\n            use_bias=False,\n            name=name + '_dwconv')(x)\n\n        x = tf.keras.layers.BatchNormalization(momentum=0.95, name=name + '_bn')(x)\n\n        x  = ECA()(x)\n\n        x = tf.keras.layers.Dense(\n            channel_size,\n            use_bias=True,\n            name=name + '_project_conv')(x)\n\n        if drop_rate > 0:\n            x = tf.keras.layers.Dropout(drop_rate, noise_shape=(None,1,1), name=name + '_drop')(x)\n\n        if (channels_in == channel_size):\n            x = tf.keras.layers.add([x, skip], name=name + '_add')\n        return x\n\n    return apply","metadata":{"execution":{"iopub.status.busy":"2025-03-26T20:41:17.618205Z","iopub.execute_input":"2025-03-26T20:41:17.618807Z","iopub.status.idle":"2025-03-26T20:41:17.63704Z","shell.execute_reply.started":"2025-03-26T20:41:17.618769Z","shell.execute_reply":"2025-03-26T20:41:17.636091Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class MultiHeadSelfAttention(tf.keras.layers.Layer):\n    def __init__(self, dim=256, num_heads=4, dropout=0, **kwargs):\n        super().__init__(**kwargs)\n        self.dim = dim\n        self.scale = self.dim ** -0.5\n        self.num_heads = num_heads\n        self.qkv = tf.keras.layers.Dense(3 * dim, use_bias=False)\n        self.drop1 = tf.keras.layers.Dropout(dropout)\n        self.proj = tf.keras.layers.Dense(dim, use_bias=False)\n        self.supports_masking = True\n\n    def call(self, inputs, mask=None):\n        qkv = self.qkv(inputs)\n        qkv = tf.keras.layers.Permute((2, 1, 3))(tf.keras.layers.Reshape((-1, self.num_heads, self.dim * 3 // self.num_heads))(qkv))\n        q, k, v = tf.split(qkv, [self.dim // self.num_heads] * 3, axis=-1)\n\n        attn = tf.matmul(q, k, transpose_b=True) * self.scale\n\n        if mask is not None:\n            mask = mask[:, None, None, :]\n\n        attn = tf.keras.layers.Softmax(axis=-1)(attn, mask=mask)\n        attn = self.drop1(attn)\n\n        x = attn @ v\n        x = tf.keras.layers.Reshape((-1, self.dim))(tf.keras.layers.Permute((2, 1, 3))(x))\n        x = self.proj(x)\n        return x\n\n\ndef TransformerBlock(dim=256, num_heads=4, expand=4, attn_dropout=0.2, drop_rate=0.2, activation='swish'):\n    def apply(inputs):\n        x = inputs\n        x = tf.keras.layers.BatchNormalization(momentum=0.95)(x)\n        x = MultiHeadSelfAttention(dim=dim,num_heads=num_heads,dropout=attn_dropout)(x)\n        x = tf.keras.layers.Dropout(drop_rate, noise_shape=(None,1,1))(x)\n        x = tf.keras.layers.Add()([inputs, x])\n        attn_out = x\n\n        x = tf.keras.layers.BatchNormalization(momentum=0.95)(x)\n        x = tf.keras.layers.Dense(dim*expand, use_bias=False, activation=activation)(x)\n        x = tf.keras.layers.Dense(dim, use_bias=False)(x)\n        x = tf.keras.layers.Dropout(drop_rate, noise_shape=(None,1,1))(x)\n        x = tf.keras.layers.Add()([attn_out, x])\n        return x\n    return apply","metadata":{"execution":{"iopub.status.busy":"2025-03-26T20:41:17.638321Z","iopub.execute_input":"2025-03-26T20:41:17.63908Z","iopub.status.idle":"2025-03-26T20:41:17.653304Z","shell.execute_reply.started":"2025-03-26T20:41:17.639042Z","shell.execute_reply":"2025-03-26T20:41:17.652527Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_model(max_len=MAX_LEN, dropout_step=0, dim=192):\n    inp = tf.keras.Input((max_len,CHANNELS))\n    #x = tf.keras.layers.Masking(mask_value=PAD,input_shape=(max_len,CHANNELS))(inp) #we don't need masking layer with inference\n    x = inp\n    ksize = 17\n    x = tf.keras.layers.Dense(dim, use_bias=False,name='stem_conv')(x)\n    x = tf.keras.layers.BatchNormalization(momentum=0.95,name='stem_bn')(x)\n\n    x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n    x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n    x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n    x = TransformerBlock(dim,expand=2)(x)\n\n    x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n    x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n    x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n    x = TransformerBlock(dim,expand=2)(x)\n\n    if dim == 384: #for the 4x sized model\n        x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n        x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n        x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n        x = TransformerBlock(dim,expand=2)(x)\n\n        x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n        x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n        x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n        x = TransformerBlock(dim,expand=2)(x)\n\n    x = tf.keras.layers.Dense(dim*2,activation=None,name='top_conv')(x)\n    x = tf.keras.layers.GlobalAveragePooling1D()(x)\n    x = LateDropout(0.8, start_step=dropout_step)(x)\n    x = tf.keras.layers.Dense(NUM_CLASSES,name='classifier')(x)\n    return tf.keras.Model(inp, x)","metadata":{"execution":{"iopub.status.busy":"2025-03-26T20:41:17.654328Z","iopub.execute_input":"2025-03-26T20:41:17.654549Z","iopub.status.idle":"2025-03-26T20:41:17.669121Z","shell.execute_reply.started":"2025-03-26T20:41:17.654528Z","shell.execute_reply":"2025-03-26T20:41:17.668071Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"models_path = [\n              '/kaggle/input/islr-models/islr-fp16-192-8-seed42-foldall-last.h5', #comment out other weights to check single model score\n               '/kaggle/input/islr-models/islr-fp16-192-8-seed43-foldall-last.h5',\n               '/kaggle/input/islr-models/islr-fp16-192-8-seed44-foldall-last.h5',\n               #'/kaggle/input/islr-models/islr-fp16-192-8-seed45-foldall-last.h5',\n              ]\nmodels = [get_model() for _ in models_path]\nfor model,path in zip(models,models_path):\n    model.load_weights(path)\nmodels[0].summary()","metadata":{"execution":{"iopub.status.busy":"2025-03-26T20:41:17.672395Z","iopub.execute_input":"2025-03-26T20:41:17.673238Z","iopub.status.idle":"2025-03-26T20:41:23.827017Z","shell.execute_reply.started":"2025-03-26T20:41:17.67321Z","shell.execute_reply":"2025-03-26T20:41:23.826123Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class TFLiteModel(tf.Module):\n    \"\"\"\n    TensorFlow Lite model that takes input tensors 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 = Preprocess()\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 = self.prep_inputs(tf.cast(inputs, dtype=tf.float32))\n        outputs = [model(x) for model in self.islr_models]\n        outputs = tf.keras.layers.Average()(outputs)[0]\n        return {'outputs': outputs}","metadata":{"execution":{"iopub.status.busy":"2025-03-26T20:41:23.828231Z","iopub.execute_input":"2025-03-26T20:41:23.828527Z","iopub.status.idle":"2025-03-26T20:41:23.836222Z","shell.execute_reply.started":"2025-03-26T20:41:23.8285Z","shell.execute_reply":"2025-03-26T20:41:23.835178Z"},"trusted":true},"outputs":[],"execution_count":null},{"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('/kaggle/input/asl-signs/' + 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":"2025-03-26T20:41:23.837336Z","iopub.execute_input":"2025-03-26T20:41:23.837642Z","iopub.status.idle":"2025-03-26T20:41:23.848193Z","shell.execute_reply.started":"2025-03-26T20:41:23.837616Z","shell.execute_reply":"2025-03-26T20:41:23.847157Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"tflite_keras_model = TFLiteModel(islr_models=models)\ndemo_output = tflite_keras_model(load_relevant_data_subset(train_df.path[0]))[\"outputs\"]\ndecoder(np.argmax(demo_output.numpy(), axis=-1))","metadata":{"execution":{"iopub.status.busy":"2025-03-26T20:41:23.849253Z","iopub.execute_input":"2025-03-26T20:41:23.849502Z","iopub.status.idle":"2025-03-26T20:41:31.839965Z","shell.execute_reply.started":"2025-03-26T20:41:23.849479Z","shell.execute_reply":"2025-03-26T20:41:31.839068Z"},"trusted":true},"outputs":[],"execution_count":null},{"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()\nwith open('/kaggle/working/model.tflite', 'wb') as f:\n    f.write(tflite_model)\n!zip submission.zip /kaggle/working/model.tflite","metadata":{"execution":{"iopub.status.busy":"2025-03-26T20:41:31.841191Z","iopub.execute_input":"2025-03-26T20:41:31.841566Z","iopub.status.idle":"2025-03-26T20:42:35.025298Z","shell.execute_reply.started":"2025-03-26T20:41:31.841522Z","shell.execute_reply":"2025-03-26T20:42:35.02427Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#check inference time\n#code from @hengck23\nmode = 's' #'d'ebug #'s'ubmit\n\nimport pandas as pd\nimport numpy as np\nimport os\nimport shutil\nfrom datetime import datetime\nfrom timeit import default_timer as timer\n\n\nif mode in ['d']:  \n    try:\n        import tflite_runtime\n    except:\n        !pip install tflite-runtime\n\n    import tflite_runtime.interpreter as tflite   \n    import tflite_runtime\n    print(tflite_runtime.__version__)\n\nprint('import ok')\n'''\nYour model must also require less than 40 MB in memory and \nperform inference with less than 100 milliseconds of latency per video. \nExpect to see approximately 40,000 videos in the test set. \nWe allow an additional 10 minute buffer for loading the data and miscellaneous overhead.\n\n'''\ndef time_to_str(t, mode='min'):\n    if mode=='min':\n        t  = int(t)/60\n        hr = t//60\n        min = t%60\n        return '%2d hr %02d min'%(hr,min)\n\n    elif mode=='sec':\n        t   = int(t)\n        min = t//60\n        sec = t%60\n        return '%2d min %02d sec'%(min,sec)\n\n    else:\n        raise NotImplementedError\n\n        \nROWS_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)\n\nif mode in ['s']: \n \n    interpreter = tflite.Interpreter('/kaggle/working/model.tflite')\n    prediction_fn = interpreter.get_signature_runner('serving_default')\n#     valid_df = pd.read_csv('/kaggle/input/asl-demo/train_prepared.csv') \n#     valid_df = train_df[train_df.fold==0].reset_index(drop=True)\n#     valid_df = valid_df[:1000]\n    valid_df = train_df[:1000]\n    valid_num = len(valid_df)\n    valid = {\n        'sign':[],\n    }\n\n    start_timer = timer()\n    for t, d in valid_df.iterrows():\n\n        pq_file = f'/kaggle/input/asl-signs/{d.path}'\n        #print(pq_file)\n        xyz = load_relevant_data_subset(pq_file)\n\n        output = prediction_fn(inputs=xyz)\n        p = output['outputs'].reshape(-1)\n\n        valid['sign'].append(p)\n\n        #---\n        if t%100==0:\n            time_taken = timer() - start_timer\n            print('\\r %8d / %d  %s'%(t,valid_num,time_to_str(time_taken,'sec')),end='',flush=True)\n\n    print('\\n')\n\n\n    truth = valid_df.label.values\n    sign  = np.stack(valid['sign'])\n    predict = np.argsort(-sign, -1)\n    correct = predict==truth.reshape(valid_num,1)\n    topk = correct.cumsum(-1).mean(0)[:5]\n\n\n    print(f'time_taken = {time_to_str(time_taken,\"sec\")}')\n    print(f'time_taken for LB = {time_taken*1000/valid_num:05f} msec\\n')\n    for i in range(5):\n        print(f'topk[{i}] = {topk[i]}')  \n    print('----- end -----\\n')","metadata":{"execution":{"iopub.status.busy":"2025-03-26T20:46:33.394547Z","iopub.execute_input":"2025-03-26T20:46:33.394963Z","iopub.status.idle":"2025-03-26T20:47:33.66024Z","shell.execute_reply.started":"2025-03-26T20:46:33.394928Z","shell.execute_reply":"2025-03-26T20:47:33.659209Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport numpy as np\n\ndef preprocess_video(video_path):\n    \"\"\"\n    Extracts frames from a video file and preprocesses them into landmark data.\n\n    Args:\n        video_path (str): Path to the video file.\n\n    Returns:\n        np.ndarray: Preprocessed landmark data ready for inference.\n    \"\"\"\n    # Load video\n    cap = cv2.VideoCapture(video_path)\n    frames = []\n    \n    while cap.isOpened():\n        ret, frame = cap.read()\n        if not ret:\n            break\n        # Resize frame to expected dimensions (optional)\n        frame = cv2.resize(frame, (1280, 720))\n        frames.append(frame)\n    \n    cap.release()\n    \n    # Convert frames into landmark data (mock example; replace with actual landmark extraction logic)\n    # Assuming ROWS_PER_FRAME landmarks per frame\n    n_frames = len(frames)\n    landmark_data = np.random.rand(n_frames, ROWS_PER_FRAME, 3).astype(np.float32)  # Replace with real data\n    \n    return landmark_data\n\ndef predict_hand_sign(video_path):\n    \"\"\"\n    Predicts the hand sign from a given video file using the TFLite model.\n\n    Args:\n        video_path (str): Path to the video file.\n\n    Returns:\n        str: Predicted hand sign label.\n    \"\"\"\n    # Preprocess video\n    landmark_data = preprocess_video(video_path)\n    \n    # Load TFLite model\n    interpreter = tf.lite.Interpreter('/kaggle/working/model.tflite')\n    prediction_fn = interpreter.get_signature_runner('serving_default')\n    \n    # Perform inference\n    output = prediction_fn(inputs=landmark_data)\n    predictions = output['outputs'].reshape(-1)\n    \n    # Decode prediction\n    predicted_label_index = np.argmax(predictions)\n    predicted_label = decoder(predicted_label_index)\n    \n    return predicted_label\n\n# Example usage\nvideo_path = '/kaggle/input/asl-signs/sample_video.mp4'  # Replace with your video path\npredicted_sign = predict_hand_sign(video_path)\nprint(f\"Predicted Hand Sign: {predicted_sign}\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}