{"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":"# Import the libraries","metadata":{}},{"cell_type":"code","source":"DEBUG = False\nALL_DATA = True\n\nimport os\nimport shutil\nimport numpy as np\nimport pandas as pd\nimport pyarrow.parquet as pq\nimport tensorflow as tf\nimport json\nimport matplotlib\nimport matplotlib.pyplot as plt\nimport random\nimport math\nfrom skimage.transform import resize\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nfrom tqdm.notebook import tqdm\nfrom matplotlib import animation, rc\nimport tensorflow_addons as tfa\nfrom tensorflow.python.keras import backend as K","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-08-21T06:57:04.152224Z","iopub.execute_input":"2023-08-21T06:57:04.152596Z","iopub.status.idle":"2023-08-21T06:57:13.587971Z","shell.execute_reply.started":"2023-08-21T06:57:04.152565Z","shell.execute_reply":"2023-08-21T06:57:13.587037Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"TensorFlow v\" + tf.__version__)\n# print(\"Mediapipe v\" + mediapipe.__version__)","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:57:13.593017Z","iopub.execute_input":"2023-08-21T06:57:13.596196Z","iopub.status.idle":"2023-08-21T06:57:13.606369Z","shell.execute_reply.started":"2023-08-21T06:57:13.596156Z","shell.execute_reply":"2023-08-21T06:57:13.605346Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load the Dataset","metadata":{}},{"cell_type":"code","source":"dataset_df = pd.read_csv('/kaggle/input/asl-fingerspelling/train.csv')\nprint(\"Full train dataset shape is {}\".format(dataset_df.shape))\n\nsupp_df = pd.read_csv('/kaggle/input/asl-fingerspelling/supplemental_metadata.csv')\nprint(\"Full supplemental dataset shape is {}\".format(dataset_df.shape))","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:57:13.610264Z","iopub.execute_input":"2023-08-21T06:57:13.611823Z","iopub.status.idle":"2023-08-21T06:57:13.943008Z","shell.execute_reply.started":"2023-08-21T06:57:13.611791Z","shell.execute_reply":"2023-08-21T06:57:13.941938Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The data is composed of 5 columns and 67208 entries. We can see all 5 dimensions of our dataset by printing out the first 5 entries using the following code:","metadata":{}},{"cell_type":"code","source":"dataset_df.head()","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:57:13.945491Z","iopub.execute_input":"2023-08-21T06:57:13.946661Z","iopub.status.idle":"2023-08-21T06:57:13.965365Z","shell.execute_reply.started":"2023-08-21T06:57:13.946623Z","shell.execute_reply":"2023-08-21T06:57:13.964447Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Pose coordinates for hand movement.\nLPOSE = [13, 15, 17, 19, 21]\nRPOSE = [14, 16, 18, 20, 22]\nPOSE = LPOSE + RPOSE\n\n# LIPS_LANDMARK_IDXS = np.array([\n#         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\n","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:57:13.966756Z","iopub.execute_input":"2023-08-21T06:57:13.967703Z","iopub.status.idle":"2023-08-21T06:57:13.973635Z","shell.execute_reply.started":"2023-08-21T06:57:13.967669Z","shell.execute_reply":"2023-08-21T06:57:13.972581Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create x,y,z label names from coordinates","metadata":{}},{"cell_type":"code","source":"X = [f'x_right_hand_{i}' for i in range(21)] + [f'x_left_hand_{i}' for i in range(21)] + [f'x_pose_{i}' for i in POSE] # + [f'x_face_{i}' for i in LIPS_LANDMARK_IDXS]\nY = [f'y_right_hand_{i}' for i in range(21)] + [f'y_left_hand_{i}' for i in range(21)] + [f'y_pose_{i}' for i in POSE] # + [f'y_face_{i}' for i in LIPS_LANDMARK_IDXS]\n# Z = [f'z_right_hand_{i}' for i in range(21)] + [f'z_left_hand_{i}' for i in range(21)] + [f'z_pose_{i}' for i in POSE]","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:57:13.975308Z","iopub.execute_input":"2023-08-21T06:57:13.975666Z","iopub.status.idle":"2023-08-21T06:57:13.985345Z","shell.execute_reply.started":"2023-08-21T06:57:13.975635Z","shell.execute_reply":"2023-08-21T06:57:13.984548Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Create feature columns from the extracted coordinates.","metadata":{}},{"cell_type":"code","source":"FEATURE_COLUMNS = X + Y #+ Z","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:57:13.988608Z","iopub.execute_input":"2023-08-21T06:57:13.988896Z","iopub.status.idle":"2023-08-21T06:57:13.996184Z","shell.execute_reply.started":"2023-08-21T06:57:13.988866Z","shell.execute_reply":"2023-08-21T06:57:13.995229Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Store ids of each coordinate labels to lists","metadata":{}},{"cell_type":"code","source":"X_IDX = [i for i, col in enumerate(FEATURE_COLUMNS)  if \"x_\" in col]\nY_IDX = [i for i, col in enumerate(FEATURE_COLUMNS)  if \"y_\" in col]\n# Z_IDX = [i for i, col in enumerate(FEATURE_COLUMNS)  if \"z_\" in col]\n\nRHAND_IDX = [i for i, col in enumerate(FEATURE_COLUMNS)  if \"right\" in col]\nLHAND_IDX = [i for i, col in enumerate(FEATURE_COLUMNS)  if  \"left\" in col]\nRPOSE_IDX = [i for i, col in enumerate(FEATURE_COLUMNS)  if  \"pose\" in col and int(col[-2:]) in RPOSE]\nLPOSE_IDX = [i for i, col in enumerate(FEATURE_COLUMNS)  if  \"pose\" in col and int(col[-2:]) in LPOSE]\n# LIPS_IDX = [i for i, col in enumerate(FEATURE_COLUMNS)  if  \"face\" in col and int(col[:]) in LIPS_LANDMARK_IDXS]\n","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:58:23.510178Z","iopub.execute_input":"2023-08-21T06:58:23.510566Z","iopub.status.idle":"2023-08-21T06:58:23.518048Z","shell.execute_reply.started":"2023-08-21T06:58:23.510536Z","shell.execute_reply":"2023-08-21T06:58:23.516796Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nFRAME_LEN = 256\n\n# # Create directory to store the new data\n# if not os.path.isdir(\"preprocessed\"):\n#     os.mkdir(\"preprocessed\")\n# else:\n#     shutil.rmtree(\"preprocessed\")\n#     os.mkdir(\"preprocessed\")\n\n# # Loop through each file_id\n# for file_id in tqdm(dataset_df.file_id.unique()):\n#     # Parquet file name\n#     pq_file = f\"/kaggle/input/asl-fingerspelling/train_landmarks/{file_id}.parquet\"\n#     # Filter train.csv and fetch entries only for the relevant file_id\n#     file_df = dataset_df.loc[dataset_df[\"file_id\"] == file_id]\n#     # Fetch the parquet file\n#     parquet_df = pq.read_table(f\"/kaggle/input/asl-fingerspelling/train_landmarks/{str(file_id)}.parquet\",\n#                               columns=['sequence_id'] + FEATURE_COLUMNS).to_pandas()\n#     # File name for the updated data\n#     tf_file = f\"preprocessed/{file_id}.tfrecord\"\n#     parquet_numpy = parquet_df.to_numpy()\n#     # Initialize the pointer to write the output of \n#     # each `for loop` below as a sequence into the file.\n#     with tf.io.TFRecordWriter(tf_file) as file_writer:\n#         # Loop through each sequence in file.\n#         for seq_id, phrase in zip(file_df.sequence_id, file_df.phrase):\n#             # Fetch sequence data\n#             frames = parquet_numpy[parquet_df.index == seq_id]\n            \n#             # Calculate the number of NaN values in each hand landmark\n#             r_nonan = np.sum(np.sum(np.isnan(frames[:, RHAND_IDX]), axis = 1) == 0)\n#             l_nonan = np.sum(np.sum(np.isnan(frames[:, LHAND_IDX]), axis = 1) == 0)\n#             no_nan = max(r_nonan, l_nonan)\n            \n#             if 2*len(phrase)<no_nan:\n#                 features = {FEATURE_COLUMNS[i]: tf.train.Feature(\n#                     float_list=tf.train.FloatList(value=frames[:, i])) for i in range(len(FEATURE_COLUMNS))}\n#                 features[\"phrase\"] = tf.train.Feature(bytes_list=tf.train.BytesList(value=[bytes(phrase, 'utf-8')]))\n#                 record_bytes = tf.train.Example(features=tf.train.Features(feature=features)).SerializeToString()\n#                 file_writer.write(record_bytes)","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:58:23.818122Z","iopub.execute_input":"2023-08-21T06:58:23.818511Z","iopub.status.idle":"2023-08-21T06:58:23.824498Z","shell.execute_reply.started":"2023-08-21T06:58:23.81848Z","shell.execute_reply":"2023-08-21T06:58:23.823588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Get the saved TFRecord files into a list","metadata":{}},{"cell_type":"code","source":"tf_records = dataset_df.participant_id.map(lambda x: f'/kaggle/input/aslfl-split-by-pid/preprocessed/{x}.tfrecord').unique()\nprint(f\"List of {len(tf_records)} TFRecord files.\")\n\nsupp_tf_records = supp_df.participant_id.map(lambda x: f'/kaggle/input/aslfr-supplementaldata-pid/preprocessed-supplemental/{x}.tfrecord').unique()\nprint(f\"List of {len(tf_records)} TFRecord files.\")\n\n# tf_records = dataset_df.file_id.map(lambda x: f'/kaggle/input/aslfrt-preprocessed-from-gusthema/preprocessed/{x}.tfrecord').unique()\n# print(f\"List of {len(tf_records)} TFRecord files.\")\n\n# tf_records = dataset_df.file_id.map(lambda x: f'/kaggle/working/preprocessed/{x}.tfrecord').unique()\n# print(f\"List of {len(tf_records)} TFRecord files.\")","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:58:24.769042Z","iopub.execute_input":"2023-08-21T06:58:24.769908Z","iopub.status.idle":"2023-08-21T06:58:24.861459Z","shell.execute_reply.started":"2023-08-21T06:58:24.769865Z","shell.execute_reply":"2023-08-21T06:58:24.860448Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load character_to_prediction json file","metadata":{}},{"cell_type":"markdown","source":"This json file contains a character and its value. We will add three new characters, \"<\" and \">\" to mark the start and end of each phrase, and \"P\" for padding.","metadata":{}},{"cell_type":"code","source":"with open (\"/kaggle/input/asl-fingerspelling/character_to_prediction_index.json\", \"r\") as f:\n    char_to_num = json.load(f)  \n\n# Add pad_token, start pointer and end pointer to the dict\npad_token = 'P'\nstart_token = '<'\nend_token = '>'\npad_token_idx = 59\n\nchar_to_num[pad_token] = pad_token_idx\nnum_to_char = {j:i for i,j in char_to_num.items()}","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:58:28.262298Z","iopub.execute_input":"2023-08-21T06:58:28.263328Z","iopub.status.idle":"2023-08-21T06:58:28.272072Z","shell.execute_reply.started":"2023-08-21T06:58:28.263289Z","shell.execute_reply":"2023-08-21T06:58:28.270999Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Reference: https://www.kaggle.com/code/irohith/aslfr-transformer/notebook\n\n# Function to resize and add padding.\ndef resize_pad(x):\n    original_dtype = x.dtype\n    if tf.shape(x)[0] < FRAME_LEN:\n        x = tf.pad(x, ([[0, FRAME_LEN-tf.shape(x)[0]], [0, 0], [0, 0]]))\n    else:\n        x = tf.image.resize(x, (FRAME_LEN, tf.shape(x)[1]))\n        x = tf.cast(x, original_dtype)\n    return x\n\n# Detect the dominant hand from the number of NaN values.\n# Dominant hand will have less NaN values since it is in frame moving.\ndef pre_process(x):\n    rhand = tf.gather(x, RHAND_IDX, axis=1)\n    lhand = tf.gather(x, LHAND_IDX, axis=1)\n    rpose = tf.gather(x, RPOSE_IDX, axis=1)\n    lpose = tf.gather(x, LPOSE_IDX, axis=1)\n    \n    rnan_idx = tf.reduce_any(tf.math.is_nan(rhand), axis=1)\n    lnan_idx = tf.reduce_any(tf.math.is_nan(lhand), axis=1)\n    \n    rnans = tf.math.count_nonzero(rnan_idx)\n    lnans = tf.math.count_nonzero(lnan_idx)\n    \n    # For dominant hand\n    if rnans > lnans:\n        hand = lhand\n        pose = lpose\n        \n        hand_x = hand[:, 0*(len(LHAND_IDX)//2) : 1*(len(LHAND_IDX)//2)]\n        hand_y = hand[:, 1*(len(LHAND_IDX)//2) : 2*(len(LHAND_IDX)//2)]\n#         hand_z = hand[:, 2*(len(LHAND_IDX)//3) : 3*(len(LHAND_IDX)//3)]\n#         hand = tf.concat([1-hand_x, hand_y, hand_z], axis=1)\n        hand = tf.concat([1-hand_x, hand_y], axis=1)\n        \n        pose_x = pose[:, 0*(len(LPOSE_IDX)//2) : 1*(len(LPOSE_IDX)//2)]\n        pose_y = pose[:, 1*(len(LPOSE_IDX)//2) : 2*(len(LPOSE_IDX)//2)]\n#         pose_z = pose[:, 2*(len(LPOSE_IDX)//3) : 3*(len(LPOSE_IDX)//3)]\n#         pose = tf.concat([1-pose_x, pose_y, pose_z], axis=1)\n        pose = tf.concat([1-pose_x, pose_y], axis=1)\n    else:\n        hand = rhand\n        pose = rpose\n    \n    hand_x = hand[:, 0*(len(LHAND_IDX)//2) : 1*(len(LHAND_IDX)//2)]\n    hand_y = hand[:, 1*(len(LHAND_IDX)//2) : 2*(len(LHAND_IDX)//2)]\n#     hand_z = hand[:, 2*(len(LHAND_IDX)//3) : 3*(len(LHAND_IDX)//3)]\n#     hand = tf.concat([hand_x[..., tf.newaxis], hand_y[..., tf.newaxis], hand_z[..., tf.newaxis]], axis=-1)\n    hand = tf.concat([hand_x[..., tf.newaxis], hand_y[..., tf.newaxis]], axis=-1)\n    \n#     mean = tf.math.reduce_mean(hand, axis=1)[:, tf.newaxis, :]\n#     std = tf.math.reduce_std(hand, axis=1)[:, tf.newaxis, :]\n#     hand = (hand - mean) / std\n\n    pose_x = pose[:, 0*(len(LPOSE_IDX)//2) : 1*(len(LPOSE_IDX)//2)]\n    pose_y = pose[:, 1*(len(LPOSE_IDX)//2) : 2*(len(LPOSE_IDX)//2)]\n#     pose_z = pose[:, 2*(len(LPOSE_IDX)//3) : 3*(len(LPOSE_IDX)//3)]\n#     pose = tf.concat([pose_x[..., tf.newaxis], pose_y[..., tf.newaxis], pose_z[..., tf.newaxis]], axis=-1)\n    pose = tf.concat([pose_x[..., tf.newaxis], pose_y[..., tf.newaxis]], axis=-1)\n    \n    x = tf.concat([hand, pose], axis=1)\n    x = resize_pad(x)\n    \n    x = tf.where(tf.math.is_nan(x), tf.zeros_like(x), x)\n    x = tf.reshape(x, (FRAME_LEN, len(LHAND_IDX) + len(LPOSE_IDX)))\n    return x\n\n\n\ndef decode_fn(record_bytes):\n    schema = {COL: tf.io.VarLenFeature(dtype=tf.float32) for COL in FEATURE_COLUMNS}\n    schema[\"phrase\"] = tf.io.FixedLenFeature([], dtype=tf.string)\n    features = tf.io.parse_single_example(record_bytes, schema)\n    phrase = features[\"phrase\"]\n    landmarks = ([tf.sparse.to_dense(features[COL]) for COL in FEATURE_COLUMNS])\n    # Transpose to maintain the original shape of landmarks data.\n    landmarks = tf.transpose(landmarks)\n    \n    return landmarks, phrase\n\ntable = tf.lookup.StaticHashTable(\n    initializer=tf.lookup.KeyValueTensorInitializer(\n        keys=list(char_to_num.keys()),\n        values=list(char_to_num.values()),\n    ),\n    default_value=tf.constant(-1),\n    name=\"class_weight\"\n)\n\ndef convert_fn(landmarks, phrase, preprocess = True):\n    # Add start and end pointers to phrase.\n#     phrase = start_token + phrase + end_token\n    phrase = tf.strings.bytes_split(phrase)\n    phrase = table.lookup(phrase)\n    # Vectorize and add padding.\n    phrase = tf.pad(phrase, paddings=[[0, 64 - tf.shape(phrase)[0]]], mode = 'CONSTANT',\n                    constant_values = pad_token_idx)\n    # Apply pre_process function to the landmarks.\n    if preprocess:\n        return pre_process(landmarks), phrase\n    else:\n        return landmarks, phrase\n\n    \n\nbatch_size = 64\ntrain_len = len(tf_records) - 10\n","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:58:28.817723Z","iopub.execute_input":"2023-08-21T06:58:28.818135Z","iopub.status.idle":"2023-08-21T06:58:28.848176Z","shell.execute_reply.started":"2023-08-21T06:58:28.818102Z","shell.execute_reply":"2023-08-21T06:58:28.847084Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# itr = tf.data.TFRecordDataset( np.concatenate((supp_tf_records , tf_records)) ).map(decode_fn).prefetch(buffer_size=tf.data.AUTOTUNE).cache().as_numpy_iterator()","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:58:29.76621Z","iopub.execute_input":"2023-08-21T06:58:29.766603Z","iopub.status.idle":"2023-08-21T06:58:29.77094Z","shell.execute_reply.started":"2023-08-21T06:58:29.766572Z","shell.execute_reply":"2023-08-21T06:58:29.769991Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# all_data = []\n# for x in tqdm(itr):\n#     x = x[0]\n#     rhand = x[:,RHAND_IDX]\n#     lhand = x[:,LHAND_IDX]\n#     rpose = x[:,RPOSE_IDX]\n#     lpose = x[:,LPOSE_IDX]\n    \n#     rnan_idx = np.any(np.isnan(rhand), axis=0)\n#     lnan_idx = np.any(np.isnan(lhand), axis=0)\n    \n#     rnans = np.count_nonzero(rnan_idx)\n#     lnans = np.count_nonzero(lnan_idx)\n    \n#     # For dominant hand\n#     if rnans > lnans:\n#         hand = lhand\n#         pose = lpose\n        \n#         hand_x = hand[:, 0*(len(LHAND_IDX)//2) : 1*(len(LHAND_IDX)//2)]\n#         hand_y = hand[:, 1*(len(LHAND_IDX)//2) : 2*(len(LHAND_IDX)//2)]\n# #         hand_z = hand[:, 2*(len(LHAND_IDX)//3) : 3*(len(LHAND_IDX)//3)]\n# #         hand = np.concatenate([1-hand_x, hand_y, hand_z], axis=1)\n#         hand = np.concatenate([1-hand_x, hand_y], axis=1)\n        \n#         pose_x = pose[:, 0*(len(LPOSE_IDX)//2) : 1*(len(LPOSE_IDX)//2)]\n#         pose_y = pose[:, 1*(len(LPOSE_IDX)//2) : 2*(len(LPOSE_IDX)//2)]\n# #         pose_z = pose[:, 2*(len(LPOSE_IDX)//3) : 3*(len(LPOSE_IDX)//3)]\n# #         pose = np.concatenate([1-pose_x, pose_y, pose_z], axis=1)\n#         pose = np.concatenate([1-pose_x, pose_y], axis=1)\n#     else:\n#         hand = rhand\n#         pose = rpose\n    \n#     hand_x = hand[:, 0*(len(LHAND_IDX)//2) : 1*(len(LHAND_IDX)//2)]\n#     hand_y = hand[:, 1*(len(LHAND_IDX)//2) : 2*(len(LHAND_IDX)//2)]\n# #     hand_z = hand[:, 2*(len(LHAND_IDX)//3) : 3*(len(LHAND_IDX)//3)]\n# #     hand = np.concatenate([hand_x[..., np.newaxis], hand_y[..., np.newaxis], hand_z[..., np.newaxis]], axis=-1)\n#     hand = np.concatenate([hand_x[..., np.newaxis], hand_y[..., np.newaxis]], axis=-1)\n#     pose_x = pose[:, 0*(len(LPOSE_IDX)//2) : 1*(len(LPOSE_IDX)//2)]\n#     pose_y = pose[:, 1*(len(LPOSE_IDX)//2) : 2*(len(LPOSE_IDX)//2)]\n# #     pose_z = pose[:, 2*(len(LPOSE_IDX)//3) : 3*(len(LPOSE_IDX)//3)]\n# #     pose = np.concatenate([pose_x[..., np.newaxis], pose_y[..., np.newaxis], pose_z[..., np.newaxis]], axis=-1)\n#     pose = np.concatenate([pose_x[..., np.newaxis], pose_y[..., np.newaxis]], axis=-1)\n#     x = np.concatenate([hand, pose], axis=1)\n# #     x = np.where(np.isnan(x), np.zeros_like(x), x)\n#     x = np.reshape(x, (-1, len(LHAND_IDX) + len(LPOSE_IDX)))\n#     all_data.extend(x)\n\n# MEANS = np.nanmean(all_data,axis=0)\n# STDS = np.nanstd(all_data,axis=0)\n\n# np.save('means.npy',MEANS)\n# np.save('stds.npy',STDS)","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:58:30.184528Z","iopub.execute_input":"2023-08-21T06:58:30.185918Z","iopub.status.idle":"2023-08-21T06:58:30.192506Z","shell.execute_reply.started":"2023-08-21T06:58:30.185876Z","shell.execute_reply":"2023-08-21T06:58:30.191444Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"MEANS = np.load(\"/kaggle/input/aslfr-modelcheckpooints/means_alldata_hands_hpose.npy.npy\")\nVARS = np.load(\"/kaggle/input/aslfr-modelcheckpooints/stds_alldata_hands_hpose.npy\")\nVARS = VARS**2","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:58:30.962118Z","iopub.execute_input":"2023-08-21T06:58:30.962505Z","iopub.status.idle":"2023-08-21T06:58:30.970331Z","shell.execute_reply.started":"2023-08-21T06:58:30.962474Z","shell.execute_reply":"2023-08-21T06:58:30.969189Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if not DEBUG:\n    if not ALL_DATA:\n        train_ds = tf.data.TFRecordDataset( np.concatenate((supp_tf_records , tf_records[:train_len])) ).map(decode_fn).map(convert_fn).batch(batch_size).prefetch(buffer_size=tf.data.AUTOTUNE).cache()\n        valid_ds = tf.data.TFRecordDataset(tf_records[train_len:]).map(decode_fn).map(convert_fn).batch(batch_size).prefetch(buffer_size=tf.data.AUTOTUNE).cache()\n    else:\n        train_ds = tf.data.TFRecordDataset( np.concatenate((supp_tf_records , tf_records)) ).map(decode_fn).map(convert_fn).batch(batch_size).prefetch(buffer_size=tf.data.AUTOTUNE).cache()\n        valid_ds = tf.data.TFRecordDataset(tf_records[train_len:]).map(decode_fn).map(convert_fn).batch(batch_size).prefetch(buffer_size=tf.data.AUTOTUNE).cache()\nelse:\n    train_ds = tf.data.TFRecordDataset( tf_records[:2]).map(decode_fn).map(convert_fn).batch(batch_size).prefetch(buffer_size=tf.data.AUTOTUNE).cache()\n    valid_ds = tf.data.TFRecordDataset(tf_records[train_len:]).map(decode_fn).map(convert_fn).batch(batch_size).prefetch(buffer_size=tf.data.AUTOTUNE).cache()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"valid_ds = tf.data.TFRecordDataset(tf_records[train_len:]).map(decode_fn).map(convert_fn).batch(batch_size).prefetch(buffer_size=tf.data.AUTOTUNE).cache()","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:58:33.245019Z","iopub.execute_input":"2023-08-21T06:58:33.245406Z","iopub.status.idle":"2023-08-21T06:58:33.69739Z","shell.execute_reply.started":"2023-08-21T06:58:33.245363Z","shell.execute_reply":"2023-08-21T06:58:33.69645Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch = next(iter(valid_ds))\nN_EPOCHS = 50\nN_WARMUP_EPOCHS = 10\nLR_MAX = 4e-4\nWD_RATIO = 0.05\nWARMUP_METHOD = \"exp\"\nINPUT_SHAPE = batch[0].shape[1:]\n\n#Copied from previous comp 1st place model: https://www.kaggle.com/code/hoyso48/1st-place-solution-training\nclass 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 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\n\nclass 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\n\ndef CTCLoss(labels, logits):\n    label_length = tf.reduce_sum(tf.cast(labels != pad_token_idx, tf.int32), axis=-1)\n    logit_length = tf.ones(tf.shape(logits)[0], dtype=tf.int32) * tf.shape(logits)[1]\n    loss = tf.nn.ctc_loss(\n            labels=labels,\n            logits=logits,\n            label_length=label_length,\n            logit_length=logit_length,\n            blank_index=pad_token_idx,\n            logits_time_major=False\n        )\n    loss = tf.reduce_mean(loss)\n    return loss\n\nclass SimpleAugmentation(tf.keras.layers.Layer):\n    def __init__(self, p):\n        super(SimpleAugmentation, self).__init__()\n        self.p = p\n                                      \n    def call(self, inputs, training=None):\n        if training is None:\n            training = K.learning_phase()\n        \n        def augmented_inputs():\n            x = inputs\n            toss = tf.random.normal(shape=[2])\n            inp_shape = tf.shape(x)\n            if toss[0] < self.p:\n                factor = tf.random.normal(mean=0., stddev=0.03, shape=inp_shape)\n                x = x + factor\n                x = tf.clip_by_value(x, clip_value_min=0, clip_value_max=1)\n\n            if toss[1] < self.p:\n                factor = tf.random.normal(mean=1., stddev=0.01, shape=(inp_shape[0],inp_shape[2]))\n                x = tf.multiply(x, factor[:,tf.newaxis,:])\n                x = tf.clip_by_value(x, clip_value_min=0, clip_value_max=1)\n                \n            return x\n\n        output = tf.cond(tf.cast(training, tf.bool),augmented_inputs,lambda: tf.identity(inputs))\n        \n        return output\n\ndef get_model(dim = 384, dropout_step=0, use_aug = True):\n    inp = tf.keras.Input(INPUT_SHAPE)\n    x = inp\n    ksize = 11\n    if use_aug:\n        x = SimpleAugmentation(p=0.3)(x)\n        \n    x = tf.keras.layers.Normalization(mean = MEANS, variance=VARS)(x)\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.25)(x)\n    x = Conv1DBlock(dim,ksize,drop_rate=0.25)(x)\n    x = Conv1DBlock(dim,ksize,drop_rate=0.25)(x)\n    x = TransformerBlock(dim,expand=2)(x)\n    \n    x = Conv1DBlock(dim,ksize,drop_rate=0.25)(x)\n    x = Conv1DBlock(dim,ksize,drop_rate=0.25)(x)\n    x = Conv1DBlock(dim,ksize,drop_rate=0.25)(x)\n    x = TransformerBlock(dim,expand=2)(x)\n    \n    x = Conv1DBlock(dim,ksize,drop_rate=0.3)(x)\n    x = Conv1DBlock(dim,ksize,drop_rate=0.3)(x)\n    x = Conv1DBlock(dim,ksize,drop_rate=0.3)(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.AveragePooling1D(2)(x)\n    x = tf.keras.layers.Dropout(0.25)(x)\n    x = tf.keras.layers.Dense(len(char_to_num))(x)\n\n    model = tf.keras.Model(inp, x)\n\n    loss = CTCLoss\n    \n    # Adam Optimizer\n    optimizer = tfa.optimizers.RectifiedAdam(sma_threshold=4)\n    optimizer = tfa.optimizers.Lookahead(optimizer, sync_period=5)\n\n    model.compile(loss=loss, optimizer=optimizer)\n\n    return model\n\ntf.keras.backend.clear_session()\nmodel = get_model(use_aug=False)\nmodel(batch[0])\nmodel.summary()\n\n\n\ndef num_to_char_fn(y):\n    return [num_to_char.get(x, \"\") for x in y]\n\n@tf.function()\ndef decode_phrase(pred):\n    x = tf.argmax(pred, axis=1)\n    diff = tf.not_equal(x[:-1], x[1:])\n    adjacent_indices = tf.where(diff)[:, 0]\n    x = tf.gather(x, adjacent_indices)\n    mask = x != pad_token_idx\n    x = tf.boolean_mask(x, mask, axis=0)\n    return x\n\n# A utility function to decode the output of the network\ndef decode_batch_predictions(pred):\n    output_text = []\n    for result in pred:\n        result = \"\".join(num_to_char_fn(decode_phrase(result).numpy()))\n        output_text.append(result)\n    return output_text\n\n# A callback class to output a few transcriptions during training\nclass CallbackEval(tf.keras.callbacks.Callback):\n    \"\"\"Displays a batch of outputs after every epoch.\"\"\"\n\n    def __init__(self, dataset):\n        super().__init__()\n        self.dataset = dataset\n\n    def on_epoch_end(self, epoch: int, logs=None):\n        model.save_weights(\"model.h5\")\n        if epoch%5 == 0:\n            model.save_weights(f\"model_{epoch}.h5\")\n        predictions = []\n        targets = []\n        for batch in self.dataset:\n            X, y = batch\n            batch_predictions = model(X)\n            batch_predictions = decode_batch_predictions(batch_predictions)\n            predictions.extend(batch_predictions)\n            for label in y:\n                label = \"\".join(num_to_char_fn(label.numpy()))\n                targets.append(label)\n        print(\"-\" * 100)\n        # for i in np.random.randint(0, len(predictions), 2):\n        for i in range(32):\n            print(f\"Target    : {targets[i]}\")\n            print(f\"Prediction: {predictions[i]}, len: {len(predictions[i])}\")\n            print(\"-\" * 100)\n\n# Callback function to check transcription on the val set.\nvalidation_callback = CallbackEval(valid_ds.take(1))\n\n\ndef lrfn(current_step, num_warmup_steps, lr_max, num_cycles=0.50, num_training_steps=N_EPOCHS):\n    \n    if current_step < num_warmup_steps:\n        if WARMUP_METHOD == 'log':\n            return lr_max * 0.10 ** (num_warmup_steps - current_step)\n        else:\n            return lr_max * 2 ** -(num_warmup_steps - current_step)\n    else:\n        progress = float(current_step - num_warmup_steps) / float(max(1, num_training_steps - num_warmup_steps))\n\n        return max(0.0, 0.5 * (1.0 + math.cos(math.pi * float(num_cycles) * 2.0 * progress))) * lr_max\n    \ndef plot_lr_schedule(lr_schedule, epochs):\n    fig = plt.figure(figsize=(20, 10))\n    plt.plot([None] + lr_schedule + [None])\n    # X Labels\n    x = np.arange(1, epochs + 1)\n    x_axis_labels = [i if epochs <= 40 or i % 5 == 0 or i == 1 else None for i in range(1, epochs + 1)]\n    plt.xlim([1, epochs])\n    plt.xticks(x, x_axis_labels) # set tick step to 1 and let x axis start at 1\n    \n    # Increase y-limit for better readability\n    plt.ylim([0, max(lr_schedule) * 1.1])\n    \n    # Title\n    schedule_info = f'start: {lr_schedule[0]:.1E}, max: {max(lr_schedule):.1E}, final: {lr_schedule[-1]:.1E}'\n    plt.title(f'Step Learning Rate Schedule, {schedule_info}', size=18, pad=12)\n    \n    # Plot Learning Rates\n    for x, val in enumerate(lr_schedule):\n        if epochs <= 40 or x % 5 == 0 or x is epochs - 1:\n            if x < len(lr_schedule) - 1:\n                if lr_schedule[x - 1] < val:\n                    ha = 'right'\n                else:\n                    ha = 'left'\n            elif x == 0:\n                ha = 'right'\n            else:\n                ha = 'left'\n            plt.plot(x + 1, val, 'o', color='black');\n            offset_y = (max(lr_schedule) - min(lr_schedule)) * 0.02\n            plt.annotate(f'{val:.1E}', xy=(x + 1, val + offset_y), size=12, ha=ha)\n    \n    plt.xlabel('Epoch', size=16, labelpad=5)\n    plt.ylabel('Learning Rate', size=16, labelpad=5)\n    plt.grid()\n    plt.show()\n\n# Learning rate for encoder\nLR_SCHEDULE = [lrfn(step, num_warmup_steps=N_WARMUP_EPOCHS, lr_max=LR_MAX, num_cycles=0.50) for step in range(N_EPOCHS)]\n# Plot Learning Rate Schedule\nplot_lr_schedule(LR_SCHEDULE, epochs=N_EPOCHS)\n# Learning Rate Callback\nlr_callback = tf.keras.callbacks.LearningRateScheduler(lambda step: LR_SCHEDULE[step], verbose=0)\n\n# Custom callback to update weight decay with learning rate\nclass WeightDecayCallback(tf.keras.callbacks.Callback):\n    def __init__(self, wd_ratio=WD_RATIO):\n        self.step_counter = 0\n        self.wd_ratio = wd_ratio\n    \n    def on_epoch_begin(self, epoch, logs=None):\n        model.optimizer.weight_decay = model.optimizer.learning_rate * self.wd_ratio\n        print(f'learning rate: {model.optimizer.learning_rate.numpy():.2e}, weight decay: {model.optimizer.weight_decay.numpy():.2e}')\n\nearlystop_cb = tf.keras.callbacks.EarlyStopping(\n    monitor='val_loss',\n    min_delta=0.001,\n    patience=5,\n    verbose=0,\n    mode='auto',\n    baseline=None,\n    restore_best_weights=True,\n    start_from_epoch=0\n)","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:58:37.074605Z","iopub.execute_input":"2023-08-21T06:58:37.074962Z","iopub.status.idle":"2023-08-21T06:58:46.698055Z","shell.execute_reply.started":"2023-08-21T06:58:37.074933Z","shell.execute_reply":"2023-08-21T06:58:46.696246Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"callbacks=[\n        validation_callback\n        ,lr_callback\n        ,WeightDecayCallback()\n        ,\n    ]\n\nif not ALL_DATA:\n    callbacks += [earlystop_cb]\n    ","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:58:46.699743Z","iopub.execute_input":"2023-08-21T06:58:46.700038Z","iopub.status.idle":"2023-08-21T06:58:46.705801Z","shell.execute_reply.started":"2023-08-21T06:58:46.700012Z","shell.execute_reply":"2023-08-21T06:58:46.704917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.load_weights(\"/kaggle/input/aslfr-modelcheckpooints/big_model.h5\", by_name=True)","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:58:46.707414Z","iopub.execute_input":"2023-08-21T06:58:46.708116Z","iopub.status.idle":"2023-08-21T06:58:47.961987Z","shell.execute_reply.started":"2023-08-21T06:58:46.708084Z","shell.execute_reply":"2023-08-21T06:58:47.960996Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(\n    train_ds,\n    validation_data=valid_ds,\n    epochs=27,\n    callbacks = callbacks\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.history","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"try:\n    plt.plot(history.history['loss'])\n    plt.plot(history.history['val_loss'])\n    plt.legend(['training loss', 'val_loss'])\n    plt.show()\nexcept:\n    print(\"OOPS\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import gc\n\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:41:50.067062Z","iopub.execute_input":"2023-08-21T06:41:50.067438Z","iopub.status.idle":"2023-08-21T06:41:50.328054Z","shell.execute_reply.started":"2023-08-21T06:41:50.067409Z","shell.execute_reply":"2023-08-21T06:41:50.327008Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nclass TFLiteModel(tf.Module):\n    def __init__(self, model):\n        super(TFLiteModel, self).__init__()\n        self.model = model\n    \n    @tf.function(input_signature=[tf.TensorSpec(shape=[None, len(FEATURE_COLUMNS)], dtype=tf.float32, name='inputs')])\n    def __call__(self, inputs, training=False):\n        # Preprocess Data\n        x = tf.cast(inputs, tf.float32)\n        x = x[None]\n        x = tf.cond(tf.shape(x)[1] == 0, lambda: tf.zeros((1, 1, len(FEATURE_COLUMNS))), lambda: tf.identity(x))\n        x = x[0]\n        x = pre_process(x)\n#         x = tf.reshape(x, INPUT_SHAPE)\n        x = x[None]\n        x = self.model(x, training=False)\n        x = x[0]\n        x = decode_phrase(x)\n        x = tf.cond(tf.shape(x)[0] == 0, lambda: tf.zeros(1, tf.int64), lambda: tf.identity(x))\n        x = tf.one_hot(x, 59)\n        return {'outputs': x}\n\ntflitemodel_base = TFLiteModel(model)\n\n","metadata":{"execution":{"iopub.status.busy":"2023-08-21T07:05:22.648125Z","iopub.execute_input":"2023-08-21T07:05:22.648627Z","iopub.status.idle":"2023-08-21T07:05:22.662955Z","shell.execute_reply.started":"2023-08-21T07:05:22.648589Z","shell.execute_reply":"2023-08-21T07:05:22.661762Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"keras_model_converter = tf.lite.TFLiteConverter.from_keras_model(tflitemodel_base)\nkeras_model_converter.optimizations = [tf.lite.Optimize.DEFAULT]\nkeras_model_converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS]#, tf.lite.OpsSet.SELECT_TF_OPS]\nkeras_model_converter.target_spec.supported_types = [tf.float16]\ntflite_model = keras_model_converter.convert()\nwith open('model.tflite', 'wb') as f:\n    f.write(tflite_model)\nwith open('inference_args.json', \"w\") as f:\n    json.dump({\"selected_columns\" : FEATURE_COLUMNS}, f)\n    \n!zip submission.zip  './model.tflite' './inference_args.json'","metadata":{"execution":{"iopub.status.busy":"2023-08-21T07:05:29.831138Z","iopub.execute_input":"2023-08-21T07:05:29.83153Z","iopub.status.idle":"2023-08-21T07:06:24.471271Z","shell.execute_reply.started":"2023-08-21T07:05:29.831498Z","shell.execute_reply":"2023-08-21T07:06:24.469992Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open (\"inference_args.json\", \"r\") as f:\n    FEATURE_COLUMNS = json.load(f)[\"selected_columns\"]","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:45:12.128194Z","iopub.execute_input":"2023-08-21T06:45:12.128607Z","iopub.status.idle":"2023-08-21T06:45:12.135077Z","shell.execute_reply.started":"2023-08-21T06:45:12.128572Z","shell.execute_reply":"2023-08-21T06:45:12.134066Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import gc\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:45:12.847624Z","iopub.execute_input":"2023-08-21T06:45:12.84814Z","iopub.status.idle":"2023-08-21T06:45:13.577927Z","shell.execute_reply.started":"2023-08-21T06:45:12.8481Z","shell.execute_reply":"2023-08-21T06:45:13.5765Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import gc\ngc.collect()\n\nfrom functools import partial\n\n\ninterpreter = tf.lite.Interpreter(\"model.tflite\")\n\nREQUIRED_SIGNATURE = \"serving_default\"\nREQUIRED_OUTPUT = \"outputs\"\n\nwith open (\"/kaggle/input/asl-fingerspelling/character_to_prediction_index.json\", \"r\") as f:\n    character_map = json.load(f)\nrev_character_map = {j:i for i,j in character_map.items()}\n\nprediction_fn = interpreter.get_signature_runner(REQUIRED_SIGNATURE)\n\n# valid_ds = tf.data.TFRecordDataset(tf_records[-10:]).map(decode_fn).map(partial(convert_fn, preprocess=False)).map(lambda x,y : (tf.cast(x,tf.float16),y) ).prefetch(buffer_size=tf.data.AUTOTUNE)\nvalid_ds = tf.data.TFRecordDataset(tf_records[-10:]).map(decode_fn).map(partial(convert_fn, preprocess=False)).prefetch(buffer_size=tf.data.AUTOTUNE)\nfor frame, target in valid_ds.take(50):\n    output = prediction_fn(inputs=frame)\n    prediction_str = \"\".join([rev_character_map.get(s, \"\") for s in np.argmax(output[REQUIRED_OUTPUT], axis=1)])\n    target = \"\".join([rev_character_map.get(s, \"\") for s in target.numpy()])\n    print(\"pred =\", prediction_str, \"; target =\", target)\n\n","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2023-08-21T06:45:23.822779Z","iopub.execute_input":"2023-08-21T06:45:23.823164Z","iopub.status.idle":"2023-08-21T06:45:34.474705Z","shell.execute_reply.started":"2023-08-21T06:45:23.823135Z","shell.execute_reply":"2023-08-21T06:45:34.473333Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%timeit -n 10\noutput = prediction_fn(inputs=frame)","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:45:34.479335Z","iopub.execute_input":"2023-08-21T06:45:34.479638Z","iopub.status.idle":"2023-08-21T06:45:48.171307Z","shell.execute_reply.started":"2023-08-21T06:45:34.479611Z","shell.execute_reply":"2023-08-21T06:45:48.170134Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from Levenshtein import distance\n\nscores = []\n\nfor i, (frame, target) in tqdm(enumerate(valid_ds.take(1000))):\n    output = prediction_fn(inputs=frame)\n    prediction_str = \"\".join([rev_character_map.get(s, \"\") for s in np.argmax(output[REQUIRED_OUTPUT], axis=1)])\n    target = \"\".join([rev_character_map.get(s, \"\") for s in target.numpy()])\n    score = (len(target) - distance(prediction_str, target)) / len(target)\n    scores.append(score)\n    if i % 50 == 0:\n        print(np.sum(scores) / len(scores))\n    \nscores = np.array(scores)\nprint(np.sum(scores) / len(scores))\n\n","metadata":{"execution":{"iopub.status.busy":"2023-08-21T06:46:06.811819Z","iopub.execute_input":"2023-08-21T06:46:06.812199Z","iopub.status.idle":"2023-08-21T06:47:42.70501Z","shell.execute_reply.started":"2023-08-21T06:46:06.812169Z","shell.execute_reply":"2023-08-21T06:47:42.703462Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}