{"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},{"sourceId":225548830,"sourceType":"kernelVersion"},{"sourceId":228891573,"sourceType":"kernelVersion"}],"dockerImageVersionId":30408,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Using just left and right hands for model\n\n\nBased from work on https://www.kaggle.com/code/mrgeislinger/just-hands-1st-place-solution-training\n\nInference: https://www.kaggle.com/code/mrgeislinger/just-hands-1st-place-solution-inference","metadata":{}},{"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":"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-03T23:29:21.428575Z","iopub.execute_input":"2025-03-03T23:29:21.428817Z","iopub.status.idle":"2025-03-03T23:29:28.954285Z","shell.execute_reply.started":"2025-03-03T23:29:21.428792Z","shell.execute_reply":"2025-03-03T23:29:28.953212Z"},"trusted":true},"outputs":[],"execution_count":null},{"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-03T23:29:28.956264Z","iopub.execute_input":"2025-03-03T23:29:28.957443Z","iopub.status.idle":"2025-03-03T23:29:29.201256Z","shell.execute_reply.started":"2025-03-03T23:29:28.957409Z","shell.execute_reply":"2025-03-03T23:29:29.200095Z"},"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\nPOINT_LANDMARKS = LHAND + RHAND# + [1, 33, 263] + 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-03T23:29:29.202521Z","iopub.execute_input":"2025-03-03T23:29:29.202811Z","iopub.status.idle":"2025-03-03T23:29:29.224913Z","shell.execute_reply.started":"2025-03-03T23:29:29.202784Z","shell.execute_reply":"2025-03-03T23:29:29.2238Z"},"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-03T23:29:29.226531Z","iopub.execute_input":"2025-03-03T23:29:29.226776Z","iopub.status.idle":"2025-03-03T23:29:29.246642Z","shell.execute_reply.started":"2025-03-03T23:29:29.226754Z","shell.execute_reply":"2025-03-03T23:29:29.245608Z"},"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-03T23:29:29.248223Z","iopub.execute_input":"2025-03-03T23:29:29.248578Z","iopub.status.idle":"2025-03-03T23:29:29.267386Z","shell.execute_reply.started":"2025-03-03T23:29:29.248543Z","shell.execute_reply":"2025-03-03T23:29:29.266337Z"},"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-03T23:29:29.268656Z","iopub.execute_input":"2025-03-03T23:29:29.268989Z","iopub.status.idle":"2025-03-03T23:29:29.28499Z","shell.execute_reply.started":"2025-03-03T23:29:29.268954Z","shell.execute_reply":"2025-03-03T23:29:29.283982Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# comment out other weights to check single model score\nmodels_path = [\n    # Note this is a model trained on just hands\n    '/kaggle/input/just-hands-1st-place-solution-training/islr-fp16-192-8-seed42-fold0-best.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-03T23:29:29.289047Z","iopub.execute_input":"2025-03-03T23:29:29.289918Z","iopub.status.idle":"2025-03-03T23:29:33.26227Z","shell.execute_reply.started":"2025-03-03T23:29:29.289889Z","shell.execute_reply":"2025-03-03T23:29:33.261292Z"},"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-03T23:29:33.263489Z","iopub.execute_input":"2025-03-03T23:29:33.263772Z","iopub.status.idle":"2025-03-03T23:29:33.271065Z","shell.execute_reply.started":"2025-03-03T23:29:33.263745Z","shell.execute_reply":"2025-03-03T23:29:33.27016Z"},"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-03T23:29:33.27245Z","iopub.execute_input":"2025-03-03T23:29:33.273093Z","iopub.status.idle":"2025-03-03T23:29:33.285973Z","shell.execute_reply.started":"2025-03-03T23:29:33.273051Z","shell.execute_reply":"2025-03-03T23:29:33.284938Z"},"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-03T23:29:33.287058Z","iopub.execute_input":"2025-03-03T23:29:33.28765Z","iopub.status.idle":"2025-03-03T23:29:39.286293Z","shell.execute_reply.started":"2025-03-03T23:29:33.287624Z","shell.execute_reply":"2025-03-03T23:29:39.285235Z"},"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-03T23:29:39.287629Z","iopub.execute_input":"2025-03-03T23:29:39.287921Z","iopub.status.idle":"2025-03-03T23:30:01.463108Z","shell.execute_reply.started":"2025-03-03T23:29:39.287894Z","shell.execute_reply":"2025-03-03T23:30:01.461816Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Kaggle data","metadata":{}},{"cell_type":"code","source":"#check inference time\n#code from @hengck23\nmode = 'd' #'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 ['d']: \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":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Parquet files for Landmarks (sign: `TV`)","metadata":{}},{"cell_type":"code","source":"import os\n\n#check inference time\n#code from @hengck23\nmode = 'd' #'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 ['d']: \n    print('debugging')\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    fnames = []\n    valid = {\n        'sign':[],\n    }\n\n    start_timer = timer()\n    # Walk the directory\n    \n    # for t, d in valid_df.iterrows():\n    for dirname, _, filenames in os.walk(f'/kaggle/input/demo-asl-video-isolated-sign-to-landmarks-data'):\n        # print(filenames)\n        for filename in filenames:\n            if '.parquet' not in filename: continue\n            input_fpath = os.path.join(dirname, filename)\n\n            pq_file = input_fpath\n            fnames.append(input_fpath)\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')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-03T23:30:01.465013Z","iopub.execute_input":"2025-03-03T23:30:01.465413Z","iopub.status.idle":"2025-03-03T23:30:16.977676Z","shell.execute_reply.started":"2025-03-03T23:30:01.465354Z","shell.execute_reply":"2025-03-03T23:30:16.976433Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(valid['sign'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-03T23:30:16.979427Z","iopub.execute_input":"2025-03-03T23:30:16.979945Z","iopub.status.idle":"2025-03-03T23:30:16.98733Z","shell.execute_reply.started":"2025-03-03T23:30:16.979897Z","shell.execute_reply":"2025-03-03T23:30:16.986364Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Everything is TV (0)\ntruth = np.full((len(valid['sign']),),0)\nsign  = np.stack(valid['sign'])\npredict = np.argsort(-sign, -1)\ncorrect = predict==truth.reshape(len(valid['sign']),1)\n\n# top k\nk = 20\ntopk = correct.cumsum(-1).mean(0)[:k]\n\n\nfor i in range(k):\n    print(f'topk[{i}] = {topk[i]}')  \nprint('----- end -----\\n') ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-03T23:30:16.988651Z","iopub.execute_input":"2025-03-03T23:30:16.989012Z","iopub.status.idle":"2025-03-03T23:30:17.00358Z","shell.execute_reply.started":"2025-03-03T23:30:16.988975Z","shell.execute_reply":"2025-03-03T23:30:17.002497Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# TV is first sign in mapping\nsign_index = 0\nk = 12\n\nfor fname,r in zip(fnames,predict):\n    print(sign_index in r[:k], [p2s_map[i] for i in r[:k]])\n    print(f'Sign Position: {np.where(r == sign_index)[0]}')\n    print('\\n')\n    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-03T23:30:31.499558Z","iopub.execute_input":"2025-03-03T23:30:31.500345Z","iopub.status.idle":"2025-03-03T23:30:31.517525Z","shell.execute_reply.started":"2025-03-03T23:30:31.500309Z","shell.execute_reply":"2025-03-03T23:30:31.516433Z"}},"outputs":[],"execution_count":null}]}