{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"accelerator":"GPU","colab":{"gpuType":"T4","machine_shape":"hm","provenance":[]},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":80670,"databundleVersionId":8695879,"sourceType":"competition"},{"sourceId":10342457,"sourceType":"datasetVersion","datasetId":6404483}],"dockerImageVersionId":30839,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false},"vscode":{"interpreter":{"hash":"b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e"}}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# HW1: Frame-Level Speech Recognition","metadata":{"id":"F9ERgBpbcMmB"}},{"cell_type":"markdown","source":"In this homework, you will be working with MFCC data consisting of 28 features at each time step/frame. Your model should be able to recognize the phoneme occured in that frame.","metadata":{"id":"CLkH6GMGcWcE"}},{"cell_type":"markdown","source":"# Dataset Description\n\nLet's start by understanding the dataset for this homework.\n\nOur data consists of 3 folders (train-clean-100, dev-clean and test-clean). The training and validation datasets (train-clean-100 and dev-clean) each contain 2 subfolders (mfcc and transcript). The 'mfcc' subfolder contains mel spectrograms (explained below and in writeup), while the 'transcript' subfolder contains their corresponding transcripts. However, the test dataset (test-clean) contains only the 'mfcc' subfolder without the corresponding transcripts, which will later be predicted by your model.\n\n\n## 1. Audio Representation.\nThe 'mfcc' subfolders contain many `*.npy` files of mel spectrograms. .npy files are used to store numpy arrays.\n\nEach .npy file represents a short speech recording. For example, one recording might be someone saying, \"This is the age of AI.\" This recording is converted into a mel spectrogram, which is used to represent all forms of audio signals in a computer. Such representation is important in signal and speech processing tasks, especially in machine learning.\n\nCompared to raw audio, mel spectrograms are better for speech processing because they capture both the timing and the frequencies of the sound. At each moment in time, they show which frequencies are present in the sound. This makes it easier for computers to understand and process speech.\n\nWhen converting raw audio to spectrograms, you do not process the whole audio at once. Instead, you process small frames at a time as you stride over the entire audio length. This means that if you have an audio file of 100 seconds, you may decide to process 10 seconds at a time, striding by one second. In this case, the frame size is 10 seconds. The frame size and the number of timesteps (seconds, milliseconds, etc.) depend on individual choice.\n\nWhen processing each frame, you extract a number of features that represent that frame's audio. For instance, in the audio recording of \"This is the age of AI,\" the frame corresponding to \"AI\" will have features that represent how \"AI\" is pronounced, the vocal tract, and the effect of the environment in which it was recorded. For clarity, when we say features, you should think of columns. One feature/column may have information about the gender of the person who made the speech. Another may have information about the age of the person. Another may have information about the environment where the speech was recorded. Basically, the main properties that make up a speech are encoded in those features, which combine in some way to make the audio.\n\nSince we want to recognize the word as it was pronounced despite the environment and other variabilities, we usually normalize to eliminate or minimize such effects.\n\nOur spectrograms contain 28 features. Essentially, the number of features may be different. They may depend on how the raw audio data was converted into mel spectrograms.\n\n## 2. Transcripts\nRemember where we mentioned frames? Well, in our dataset, audio frames have corresponding target transcripts. For instance the abbreviation \"AI\", in our example above, if present in the recordings, will have transcripts: /eɪ aɪ/. This means that you will have two frames one for  /eɪ/ and another for /aɪ/.\n\nThis way of representing pronounciation in text form is called ***phonetic transcription***, \"the conversion of spoken words the way they are pronounced instead of how they are written\"[[link]](https://www.google.com/url?sa=t&source=web&rct=j&opi=89978449&url=https://krisp.ai/blog/phonetic-transcription/%23:~:text%3Dphonetic%2520transcriptions%2520done.-,What%2520are%2520Phonetic%2520Transcriptions%253F,verbatim%2520to%2520intelligent%2520verbatim%2520transcriptions.&ved=2ahUKEwiV6LO6hrSHAxUKSvEDHcvwAAsQFnoECB0QAw&usg=AOvVaw0VqoWceOzdVwe-AvdyyWqJ). In this case letters 'A' and 'I' are pronounce /eɪ/ and /aɪ/, respectively. Both letters in different words may be pronounced differently.\n\nThe produced representation of the speech is referred to as phonemes. Various .npy files that contain recordings of the sentence **\"This is the age of AI.\"** would map to **\"/ðɪs ɪz ðə eɪdʒ əv eɪ aɪ/.\"** The phonemes representation for **Chelsea sucks** would be **/ˈtʃɛl.si sʌks/**\n\nGoing inside the .npy files. Each .npy file contains vectors which have 28 features/dimensions/columns. The number of vectors in the file corresponds to the number of frames in the recording. And each single frame has a corresponding phoneme in the transcript.\n\nFor instance the .npy file for \"This is the age of AI\" --> \"/ðɪs ɪz ðə eɪdʒ əv eɪ aɪ/\" might have 13 frames (13 vectors):\n\n- /ðɪs/ has 3 phonemes: /ð/, /ɪ/, /s/  \n- /ɪz/ has 2 phonemes: /ɪ/, /z/\n- /ðə/ has 2 phonemes: /ð/, /ə/\n- /eɪdʒ/ has 2 phonemes: /eɪ/, /dʒ/\n- /əv/ has 2 phonemes: /ə/, /v/\n- /eɪ aɪ/ has 2 phonemes: /eɪ/, /aɪ/\n\n**Chelsea sucks** --> **/ˈtʃɛl.si sʌks/** might have 8 frames (8 vectors):\n\n- /ˈtʃɛl.si/ has 4 phonemes: /tʃ/, /ɛ/, /l/, /si/\n- /sʌks/ has 4 phonemes: /s/, /ʌ/, /k/, /s/\n\nNote that recordings of different sentences may have different number of frames.\n\nThe model you will produce must take a vector of a particular frame and predict the frame's transcript as accurately as possible.\n\nTherefore, the **__getitem__** method of your dataset class must return a 28 dimensional vector of a particular frame and its corresponding phoneme transcript.\n\nThis means that, while you are doing your data preprocessing in the **__init__** method, you need stack all vectors from all recordings on top of each other. You must do this for all transcripts as well and remember to ensure the correspondance between frames and their phoneme mapping is maintained.\n\nFor our dataset of two samples above, if you stack the recordings together, you get:\n\n\n| Frame | Feature 1 | Feature 2 | ... | Feature 28 | Phoneme |\n|-------|-----------|-----------|-----|------------|---------|\n| 0     | v0_1      | v0_2      | ... | v0_28      | /ð/     |\n| 1     | v1_1      | v1_2      | ... | v1_28      | /ɪ/     |\n| 2     | v2_1      | v2_2      | ... | v2_28      | /s/     |\n| 3     | v3_1      | v3_2      | ... | v3_28      | /ɪ/     |\n| 4     | v4_1      | v4_2      | ... | v4_28      | /z/     |\n| 5     | v5_1      | v5_2      | ... | v5_28      | /ð/     |\n| 6     | v6_1      | v6_2      | ... | v6_28      | /ə/     |\n| 7     | v7_1      | v7_2      | ... | v7_28      | /eɪ/    |\n| 8     | v8_1      | v8_2      | ... | v8_28      | /dʒ/    |\n| 9     | v9_1      | v9_2      | ... | v9_28      | /ə/     |\n| 10    | v10_1     | v10_2     | ... | v10_28     | /v/     |\n| 11    | v11_1     | v11_2     | ... | v11_28     | /eɪ/    |\n| 12    | v12_1     | v12_2     | ... | v12_28     | /aɪ/    |\n| 13    | v13_1     | v13_2     | ... | v13_28     | /tʃ/    |\n| 14    | v14_1     | v14_2     | ... | v14_28     | /ɛ/     |\n| 15    | v15_1     | v15_2     | ... | v15_28     | /l/     |\n| 16    | v16_1     | v16_2     | ... | v16_28     | /si/     |\n| 17    | v17_1     | v17_2     | ... | v17_28     | /s/     |\n| 18    | v18_1     | v18_2     | ... | v18_28     | /ʌ/     |\n| 19    | v19_1     | v19_2     | ... | v19_28     | /k/     |\n| 20    | v20_1     | v20_2     | ... | v20_28     | /s/     |\n\n\nSo, if you pass index 5 to **__getitem__**, you will get back vector v5 (v5_1, v5_2, ..., v5_28) and transcript **/ð/**. Ideally, if you have a well trained model, it should take v5 and return **/ð/**. And the call to **__len__** would return 21 which the training loop would use to go through the whole dataset.\n\n## Context\n\nIn the dataset we are using, a few millisecs were used to convert raw audio to mel spectrogram and extract the 28 features.\nSince each vector represents only a few millisecs of speech, it may not be sufficient to feed only a single vector into the network at a time. Instead, it may be useful to provide the network with some “context” of size K around each vector in terms of additional vectors from the speech input.\n\nConcretely, a context of size 3 would mean that we provide an input of size (7, 28) to the network - the size 7 can be explained as: the vector to predict the label for, 3 vectors preceding this vector, and 3 vectors following it. It is worth thinking about how you would handle providing context before one of the first K frames of an utterance or after one of the last K frames.\n\nThere are several ways to implement this, but you could try the simplest one:\n- Concatenating all utterances and padding with K 0-valued vectors before and after the resulting matrix\n\nIf you use a context of 3 on the above table, you get the following table:\n\n| Frame | Feature 1 | Feature 2 | ... | Feature 28 | Phoneme | Context Vectors |\n|-------|-----------|-----------|-----|------------|---------|----------------|\n| 0     | v0_1      | v0_2      | ... | v0_28      | /ð/     | [0, 0, 0, ..., 0] (Padding), [0, 0, 0, ..., 0] (Padding), [0, 0, 0, ..., 0] (Padding), v0, v1, v2, v3 |\n| 1     | v1_1      | v1_2      | ... | v1_28      | /ɪ/     | [0, 0, 0, ..., 0] (Padding), [0, 0, 0, ..., 0] (Padding), v0, v1, v2, v3, v4 |\n| 2     | v2_1      | v2_2      | ... | v2_28      | /s/     | [0, 0, 0, ..., 0] (Padding), v0, v1, v2, v3, v4, v5 |\n| 3     | v3_1      | v3_2      | ... | v3_28      | /ɪ/     | v0, v1, v2, v3, v4, v5, v6 |\n| 4     | v4_1      | v4_2      | ... | v4_28      | /z/     | v1, v2, v3, v4, v5, v6, v7 |\n| 5     | v5_1      | v5_2      | ... | v5_28      | /ð/     | v2, v3, v4, v5, v6, v7, v8 |\n| 6     | v6_1      | v6_2      | ... | v6_28      | /ə/     | v3, v4, v5, v6, v7, v8, v9 |\n| 7     | v7_1      | v7_2      | ... | v7_28      | /eɪ/    | v4, v5, v6, v7, v8, v9, v10 |\n| 8     | v8_1      | v8_2      | ... | v8_28      | /dʒ/    | v5, v6, v7, v8, v9, v10, v11 |\n| 9     | v9_1      | v9_2      | ... | v9_28      | /ə/     | v6, v7, v8, v9, v10, v11, v12 |\n| 10    | v10_1     | v10_2     | ... | v10_28     | /v/     | v7, v8, v9, v10, v11, v12, v13 |\n| 11    | v11_1     | v11_2     | ... | v11_28     | /eɪ/    | v8, v9, v10, v11, v12, v13, v14 |\n| 12    | v12_1     | v12_2     | ... | v12_28     | /aɪ/    | v9, v10, v11, v12, v13, v14, v15 |\n| 13    | v13_1     | v13_2     | ... | v13_28     | /tʃ/    | v10, v11, v12, v13, v14, v15, v16 |\n| 14    | v14_1     | v14_2     | ... | v14_28     | /ɛ/     | v11, v12, v13, v14, v15, v16, v17 |\n| 15    | v15_1     | v15_2     | ... | v15_28     | /l/     | v12, v13, v14, v15, v16, v17, v18 |\n| 16    | v16_1     | v16_2     | ... | v16_28     | /s/     | v13, v14, v15, v16, v17, v18, v19 |\n| 17    | v17_1     | v17_2     | ... | v17_28     | /i/     | v14, v15, v16, v17, v18, v19, v20 |\n| 18    | v18_1     | v18_2     | ... | v18_28     | /s/     | v15, v16, v17, v18, v19, v20, v21 |\n| 19    | v19_1     | v19_2     | ... | v19_28     | /ʌ/     | v16, v17, v18, v19, v20, v21, [0, 0, 0, ..., 0] (Padding) |\n| 20    | v20_1     | v20_2     | ... | v20_28     | /k/     | v17, v18, v19, v20, v21, [0, 0, 0, ..., 0] (Padding), [0, 0, 0, ..., 0] (Padding) |\n| 21    | v21_1     | v21_2     | ... | v21_28     | /s/     | v18, v19, v20, v21, [0, 0, 0, ..., 0] (Padding), [0, 0, 0, ..., 0] (Padding), [0, 0, 0, ..., 0] (Padding) |\n\n\nNow, if you want to predict the output of vector v5, you won't just pass vector v5 alone. You will concatenate 3 vectors before it and 3 vectors after, which makes it 7 vectors ([v2, v3, v4, v5, v6, v7, v8 ]) . This needs to be reflected in your **__getitem__** method. Meaning it should return an array of shape (7, 28), in this example.\n\nHence your model is going to be taking a tensor (array) of shape (7, 28) in this example.","metadata":{"id":"P2vp3N7qr_5V"}},{"cell_type":"markdown","source":"# Libraries","metadata":{"id":"z4vZbDmJvMp1"}},{"cell_type":"code","source":"!pip install torchsummaryX >=1.1.0 wandb --quiet\n","metadata":{"id":"rwYu9sSUnSho","trusted":true,"execution":{"iopub.status.busy":"2025-01-19T23:46:03.321695Z","iopub.execute_input":"2025-01-19T23:46:03.32208Z","iopub.status.idle":"2025-01-19T23:49:23.940326Z","shell.execute_reply.started":"2025-01-19T23:46:03.32205Z","shell.execute_reply":"2025-01-19T23:49:23.939033Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install torchaudio --quiet","metadata":{"execution":{"iopub.status.busy":"2025-01-19T23:44:18.362871Z","iopub.execute_input":"2025-01-19T23:44:18.363232Z","iopub.status.idle":"2025-01-19T23:44:23.04761Z","shell.execute_reply.started":"2025-01-19T23:44:18.363202Z","shell.execute_reply":"2025-01-19T23:44:23.046343Z"},"id":"ijYNIOkpYrXf","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport numpy as np\nfrom torchsummaryX import summary\nimport sklearn\nimport gc\nimport zipfile\nimport bisect\nimport pandas as pd\nfrom tqdm.auto import tqdm\nimport os\nimport datetime\nimport wandb\nimport yaml\nimport torchaudio.transforms as tat\nimport torchaudio\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'\nprint(\"Device: \", device)","metadata":{"execution":{"iopub.status.busy":"2025-01-19T23:44:23.04954Z","iopub.execute_input":"2025-01-19T23:44:23.049924Z","iopub.status.idle":"2025-01-19T23:44:26.706225Z","shell.execute_reply.started":"2025-01-19T23:44:23.049888Z","shell.execute_reply":"2025-01-19T23:44:26.704821Z"},"id":"qI4qfx7tiBZt","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Mount Google Drive","metadata":{"id":"eqsFLqa6rCuc"}},{"cell_type":"code","source":"''' If you are using colab, you can import google drive to save model checkpoints in a folder\n    If you want to use it, uncomment the two lines below\n'''\n# from google.colab import drive\n# drive.mount('/content/drive')","metadata":{"id":"Z23Nag1jq_yA"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### PHONEME LIST\nPHONEMES = [\n            '[SIL]',   'AA',    'AE',    'AH',    'AO',    'AW',    'AY',\n            'B',     'CH',    'D',     'DH',    'EH',    'ER',    'EY',\n            'F',     'G',     'HH',    'IH',    'IY',    'JH',    'K',\n            'L',     'M',     'N',     'NG',    'OW',    'OY',    'P',\n            'R',     'S',     'SH',    'T',     'TH',    'UH',    'UW',\n            'V',     'W',     'Y',     'Z',     'ZH',    '[SOS]', '[EOS]']","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:17:20.484621Z","iopub.status.busy":"2024-12-31T15:17:20.484276Z","iopub.status.idle":"2024-12-31T15:17:20.489243Z","shell.execute_reply":"2024-12-31T15:17:20.488394Z","shell.execute_reply.started":"2024-12-31T15:17:20.484588Z"},"id":"N-9qE20hmCgQ"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Kaggle","metadata":{"id":"ZIi0Big7vPa9"}},{"cell_type":"markdown","source":"This section contains code that helps you install kaggle's API, creating kaggle.json with you username and API key details. Make sure to input those in the given code to ensure you can download data from the competition successfully.","metadata":{"id":"BBCbeRhixGM7"}},{"cell_type":"code","source":"!pip install --upgrade kaggle==1.6.17 --force-reinstall --no-deps\n!mkdir /root/.kaggle\n\nwith open(\"/root/.kaggle/kaggle.json\", \"w+\") as f:\n    # Put your kaggle username & key here\n    f.write('{\"username\":\"\",\"key\":\"\"}')\n\n!chmod 600 /root/.kaggle/kaggle.json","metadata":{"execution":{"iopub.execute_input":"2024-12-24T01:51:36.557771Z","iopub.status.busy":"2024-12-24T01:51:36.557557Z","iopub.status.idle":"2024-12-24T01:51:39.853407Z","shell.execute_reply":"2024-12-24T01:51:39.852241Z","shell.execute_reply.started":"2024-12-24T01:51:36.557752Z"},"id":"TPBUd7Cnl-Rx"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# commands to download data from kaggle\n!kaggle competitions download -c 11785-spring-25-hw-1-p-2\n\n# Unzip downloaded data\n!unzip -qo /content/11785-spring-25-hw-1-p-2.zip -d '/content'","metadata":{"execution":{"iopub.execute_input":"2024-12-24T01:51:39.854726Z","iopub.status.busy":"2024-12-24T01:51:39.854463Z","iopub.status.idle":"2024-12-24T01:52:39.96803Z","shell.execute_reply":"2024-12-24T01:52:39.967153Z","shell.execute_reply.started":"2024-12-24T01:51:39.854703Z"},"id":"if2Somqfbje1"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Parameters Configuration","metadata":{"id":"qNacQ8bpt9nw"}},{"cell_type":"markdown","source":"Storing your parameters and hyperparameters in a single configuration dictionary makes it easier to keep track of them during each experiment. It can also be used with weights and biases to log your parameters for each experiment and keep track of them across multiple experiments.","metadata":{"id":"WE7tsinAuLNy"}},{"cell_type":"code","source":"config = {\n    'Name': '', # Write your name here\n    'subset': 1.0, # Subset of dataset to use (1.0 == 100% of data)\n    'context': 30,\n    'archetype': 'diamond', # Default Values: pyramid, diamond, inverse-pyramid,cylinder\n    'activations': 'GELU',\n    'learning_rate': 0.001,\n    'dropout': 0.25,\n    'optimizers': 'SGD',\n    'scheduler': 'ReduceLROnPlateau',\n    'epochs': 30,\n    'batch_size': 2048,\n    'weight_decay': 0.05,\n    'weight_initialization': None, # e.g kaiming_normal, kaiming_uniform, uniform, xavier_normal or xavier_uniform\n    'augmentations': 'Both', # Options: [\"FreqMask\", \"TimeMask\", \"Both\", null]\n    'freq_mask_param': 4,\n    'time_mask_param': 8\n }","metadata":{"id":"S5gMTwnSnp8K"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"config","metadata":{"id":"vzeqgWS9pumb"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Dataset Class","metadata":{"id":"FYeyFHQ1yRi4"}},{"cell_type":"markdown","source":"This section covers the dataset/dataloader class for speech data. You will have to spend time writing code to create this class successfully. We have given you a lot of comments guiding you on what code to write at each stage, from top to bottom of the class. Please try and take your time figuring this out, as it will immensely help in creating dataset/dataloader classes for future homeworks.\n\nBefore running the following cells, please take some time to analyse the structure of data. Try loading a single MFCC and its transcipt, print out the shapes and print out the values. Do the transcripts look like phonemes?","metadata":{"id":"2_7QgMbBdgPp"}},{"cell_type":"code","source":"# Dataset class to load train and validation data\n\nclass AudioDataset(torch.utils.data.Dataset):\n\n    def __init__(self, root, phonemes = PHONEMES, context=0, partition= \"train-clean-100\"): # Feel free to add more arguments\n\n        self.context    = context\n        self.phonemes   = phonemes\n        self.subset = config['subset']\n\n        # TODO: Initialize augmentations. Read the Pytorch torchaudio documentations on timemasking and frequencymasking\n        self.freq_masking = NotImplemented\n        self.time_masking = NotImplemented\n\n\n        # TODO: MFCC directory - use partition to acces train/dev directories from kaggle data using root\n        self.mfcc_dir       = NotImplemented\n        # TODO: Transcripts directory - use partition to acces train/dev directories from kaggle data using root\n        self.transcript_dir = NotImplemented\n\n        # TODO: List files in sefl.mfcc_dir using os.listdir in SORTED order\n        mfcc_names          = NotImplemented\n        # TODO: List files in self.transcript_dir using os.listdir in SORTED order\n        transcript_names    = NotImplemented\n\n        # Compute size of data subset\n        subset_size = int(self.subset * len(mfcc_names))\n\n        # Select subset of data to use\n        mfcc_names = mfcc_names[:subset_size]\n        transcript_names = transcript_names[:subset_size]\n\n        # Making sure that we have the same no. of mfcc and transcripts\n        assert len(mfcc_names) == len(transcript_names)\n\n        self.mfccs, self.transcripts = [], []\n\n\n        # TODO: Iterate through mfccs and transcripts\n        for i in tqdm(range(len(mfcc_names))):\n\n            # TODO: Load a single mfcc. Hint: Use numpy\n            mfcc             = NotImplemented\n            # TODO: Do Cepstral Normalization of mfcc along the Time Dimension (Think about the correct axis)\n            mfccs_normalized = NotImplemented\n\n            # Convert mfcc to tensor\n            mfccs_normalized = torch.tensor(mfccs_normalized, dtype=torch.float32)\n\n            # TODO: Load the corresponding transcript\n            # Remove [SOS] and [EOS] from the transcript\n            # (Is there an efficient way to do this without traversing through the transcript?)\n            # Note that SOS will always be in the starting and EOS at end, as the name suggests.\n            transcript  = NotImplemented\n\n            # The available phonemes in the transcript are of string data type\n            # But the neural network cannot predict strings as such.\n            # Hence, we map these phonemes to integers\n\n            # TODO: Map the phonemes to their corresponding list indexes in self.phonemes\n            transcript_indices = NotImplemented\n            # Now, if an element in the transcript is 0, it means that it is 'SIL' (as per the above example)\n\n            # Convert transcript to tensor\n            transcript_indices = torch.tensor(transcript_indices, dtype=torch.int64)\n\n            # Append each mfcc to self.mfcc, transcript to self.transcript\n            self.mfccs.append(mfccs_normalized)\n            self.transcripts.append(transcript_indices)\n\n        # NOTE:\n        # Each mfcc is of shape T1 x 28, T2 x 28, ...\n        # Each transcript is of shape (T1+2), (T2+2) before removing [SOS] and [EOS]\n\n        # TODO: Concatenate all mfccs in self.mfccs such that\n        # the final shape is T x 28 (Where T = T1 + T2 + ...)\n        # Hint: Use torch to concatenate\n        self.mfccs          = NotImplemented\n\n        # TODO: Concatenate all transcripts in self.transcripts such that\n        # the final shape is (T,) meaning, each time step has one phoneme output\n        # Hint: Use torch to concatenate\n        self.transcripts    = NotImplemented\n\n        # Length of the dataset is now the length of concatenated mfccs/transcripts\n        self.length = len(self.mfccs)\n\n        # Take some time to think about what we have done.\n        # self.mfcc is an array of the format (Frames x Features).\n        # Our goal is to recognize phonemes of each frame\n\n        # We can introduce context by padding zeros on top and bottom of self.mfcc\n        # Hint: Use torch.nn.functional.pad\n        # torch.nn.functional.pad takes the padding in the form of (left, right, top, bottom) for 2D data\n        self.mfccs = NotImplemented # TODO\n\n\n    def __len__(self):\n        return self.length\n\n    def collate_fn(self, batch):\n      x, y = zip(*batch)\n      x = torch.stack(x, dim=0)\n\n      # Apply augmentations with 70% probability (You can modify the probability)\n      if np.random.rand() < 0.70:\n        x = x.transpose(1, 2)  # Shape: (batch_size, freq, time)\n        x = self.freq_masking(x)\n        x = self.time_masking(x)\n        x = x.transpose(1, 2)  # Shape back to: (batch_size, time, freq)\n\n      return x, torch.tensor(y)\n\n    def __getitem__(self, ind):\n        # TODO: Based on context and offset, return a frame at given index with context frames to the left, and right.\n        frames = NotImplemented\n\n        # After slicing, you get an array of shape 2*context+1 x 28.\n\n        phonemes = self.transcripts[ind]\n\n        return frames, phonemes\n","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:17:54.383981Z","iopub.status.busy":"2024-12-31T15:17:54.383641Z","iopub.status.idle":"2024-12-31T15:17:54.394276Z","shell.execute_reply":"2024-12-31T15:17:54.393413Z","shell.execute_reply.started":"2024-12-31T15:17:54.383952Z"},"id":"HYU4NAH65dSb"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class AudioTestDataset(torch.utils.data.Dataset):\n    pass\n\n    # TODO: Create a test dataset class similar to the previous class but you dont have transcripts for this\n    # Imp: Read the mfccs in sorted order, do NOT shuffle the data here or in your dataloader.\n    # IMPORTANT: Load complete test data to use, DO NOT select subset of test data, else you will get errors when submitting on Kaggle.","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:18:40.554498Z","iopub.status.busy":"2024-12-31T15:18:40.554136Z","iopub.status.idle":"2024-12-31T15:18:40.561523Z","shell.execute_reply":"2024-12-31T15:18:40.560566Z","shell.execute_reply.started":"2024-12-31T15:18:40.554472Z"},"id":"C0rme6iT5dSb"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Create Datasets","metadata":{"id":"2mlwaKlDt_2c"}},{"cell_type":"code","source":"ROOT = \"\" # Define the root directory of the dataset here\n\n# TODO: Create a dataset object using the AudioDataset class for the training data\ntrain_data = NotImplemented\n\n# TODO: Create a dataset object using the AudioDataset class for the validation data\nval_data = NotImplemented\n\n# TODO: Create a dataset object using the AudioTestDataset class for the test data\ntest_data = NotImplemented","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:19:09.189955Z","iopub.status.busy":"2024-12-31T15:19:09.189592Z","iopub.status.idle":"2024-12-31T15:24:30.163981Z","shell.execute_reply":"2024-12-31T15:24:30.163061Z","shell.execute_reply.started":"2024-12-31T15:19:09.189927Z"},"id":"gJvMzHhB5dSc"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define dataloaders for train, val and test datasets\n# Dataloaders will yield a batch of frames and phonemes of given batch_size at every iteration\n# We shuffle train dataloader but not val & test dataloader. Why?\n\ntrain_loader = torch.utils.data.DataLoader(\n    dataset     = train_data,\n    num_workers = 4,\n    batch_size  = config['batch_size'],\n    pin_memory  = True,\n    shuffle     = True,\n    collate_fn = train_data.collate_fn\n)\n\nval_loader = torch.utils.data.DataLoader(\n    dataset     = val_data,\n    num_workers = 0,\n    batch_size  = config['batch_size'],\n    pin_memory  = True,\n    shuffle     = False\n)\n\ntest_loader = torch.utils.data.DataLoader(\n    dataset     = test_data,\n    num_workers = 2,\n    batch_size  = config['batch_size'], \n    pin_memory  = True,\n    shuffle     = False\n)\n\n\nprint(\"Batch size     : \", config['batch_size'])\nprint(\"Context        : \", config['context'])\nprint(\"Input size     : \", (2*config['context']+1)*28)\nprint(\"Output symbols : \", len(PHONEMES))\n\nprint(\"Train dataset samples = {}, batches = {}\".format(train_data.__len__(), len(train_loader)))\nprint(\"Validation dataset samples = {}, batches = {}\".format(val_data.__len__(), len(val_loader)))\nprint(\"Test dataset samples = {}, batches = {}\".format(test_data.__len__(), len(test_loader)))","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:24:37.1051Z","iopub.status.busy":"2024-12-31T15:24:37.104785Z","iopub.status.idle":"2024-12-31T15:24:37.113609Z","shell.execute_reply":"2024-12-31T15:24:37.112725Z","shell.execute_reply.started":"2024-12-31T15:24:37.105072Z"},"id":"4mzoYfTKu14s"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Testing code to check if your data loaders are working\nfor i, data in enumerate(train_loader):\n    frames, phoneme = data\n    print(frames.shape, phoneme.shape)\n\n    # Visualize sample mfcc to inspect and verify everything is correctly done, especially augmentations\n    plt.figure(figsize=(10, 6))\n    plt.imshow(frames[0].numpy().T, aspect='auto', origin='lower', cmap='viridis')\n    plt.xlabel('Time')\n    plt.ylabel('Features')\n    plt.title('Feature Representation')\n    plt.show()\n\n    break","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:27:30.225789Z","iopub.status.busy":"2024-12-31T15:27:30.225475Z","iopub.status.idle":"2024-12-31T15:27:36.866313Z","shell.execute_reply":"2024-12-31T15:27:36.8651Z","shell.execute_reply.started":"2024-12-31T15:27:30.225762Z"},"id":"n-GV3UvgLSoF"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Testing code to check if your validation data loaders are working\nall = []\nfor i, data in enumerate(val_loader):\n    frames, phoneme = data\n    all.append(phoneme)\n    break","metadata":{"execution":{"iopub.execute_input":"2024-12-24T02:04:28.807971Z","iopub.status.busy":"2024-12-24T02:04:28.807726Z","iopub.status.idle":"2024-12-24T02:04:58.177819Z","shell.execute_reply":"2024-12-24T02:04:58.176831Z","shell.execute_reply.started":"2024-12-24T02:04:28.807951Z"},"id":"dJTrLe7J5dSc"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Network Architecture\n","metadata":{"id":"Nxjwve20JRJ2"}},{"cell_type":"markdown","source":"This section defines your network architecture for the homework. We have given you a sample architecture that can easily clear the very low cutoff for the early submission deadline.","metadata":{"id":"3NJzT-mRw6iy"}},{"cell_type":"code","source":"# This architecture will make you cross the very low cutoff\n# However, you need to run a lot of experiments to cross the medium or high cutoff\n\nclass Network(nn.Module):\n    def __init__(self, input_size, output_size):\n        super(Network, self).__init__()\n\n        self.model = nn.Sequential(\n            torch.nn.Linear(input_size, 512),\n            torch.nn.ReLU(),\n            torch.nn.Linear(512, output_size)\n        )\n\n        if config['weight_initialization'] is not None:\n            self.initialize_weights()\n\n    def initialize_weights(self):\n        for m in self.modules():\n            if isinstance(m, torch.nn.Linear):\n                if config[\"weight_initialization\"] == \"xavier_normal\":\n                    torch.nn.init.xavier_normal_(m.weight)\n                elif config[\"weight_initialization\"] == \"xavier_uniform\":\n                    torch.nn.init.xavier_uniform_(m.weight)\n                elif config[\"weight_initialization\"] == \"kaiming_normal\":\n                    torch.nn.init.kaiming_normal_(m.weight, nonlinearity='relu')\n                elif config[\"weight_initialization\"] == \"kaiming_uniform\":\n                    torch.nn.init.kaiming_uniform_(m.weight, nonlinearity='relu')\n                elif config[\"weight_initialization\"] == \"uniform\":\n                    torch.nn.init.uniform_(m.weight)\n                else:\n                    raise ValueError(\"Invalid weight_initialization value\")\n\n                # Initialize bias to 0\n                m.bias.data.fill_(0)\n\n\n    def forward(self, x):\n\n        # Flatten to a 1D vector for each data point\n        x = torch.flatten(x, start_dim=1)  # Keeps batch size, flattens the rest\n\n        return self.model(x)","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:29:20.193972Z","iopub.status.busy":"2024-12-31T15:29:20.193622Z","iopub.status.idle":"2024-12-31T15:29:20.203743Z","shell.execute_reply":"2024-12-31T15:29:20.202883Z","shell.execute_reply.started":"2024-12-31T15:29:20.193944Z"},"id":"-YsMpN-Exafq"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Define Model, Loss Function and Optimizer","metadata":{"id":"HejoSXe3vMVU"}},{"cell_type":"markdown","source":"Here we define the model, loss function, optimizer and optionally a learning rate scheduler.","metadata":{"id":"xAhGBH7-xxth"}},{"cell_type":"code","source":"INPUT_SIZE  = (2*config['context'] + 1) * 28 # Why is this the case?\nmodel       = Network(INPUT_SIZE, len(train_data.phonemes)).to(device).cuda()\nsummary(model, frames.to(device))\n# Check number of parameters of your network\n# Remember, you are limited to 20 million parameters for HW1 (including ensembles)","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:29:23.891053Z","iopub.status.busy":"2024-12-31T15:29:23.890697Z","iopub.status.idle":"2024-12-31T15:29:24.267793Z","shell.execute_reply":"2024-12-31T15:29:24.2671Z","shell.execute_reply.started":"2024-12-31T15:29:23.891023Z"},"id":"_qtrEM1ZvLje"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Define Model, Loss Function and Optimizer","metadata":{"id":"uSk4YP63TBnD"}},{"cell_type":"markdown","source":"Here we define the model, loss function, optimizer and optionally a learning rate scheduler.","metadata":{"id":"cwdxl4RiTBnD"}},{"cell_type":"code","source":"criterion = torch.nn.CrossEntropyLoss() # Defining Loss function.\n# We use CE because the task is multi-class classification\n\n# Choose an appropriate optimizer of your choice\noptimizer = torch.optim.AdamW(model.parameters(), lr=config['learning_rate'])\n\n# Recommended : Define Scheduler for Learning Rate,\n# including but not limited to StepLR, MultiStep, CosineAnnealing, CosineAnnealingWithWarmRestarts, ReduceLROnPlateau, etc.\n# You can refer to Pytorch documentation for more information on how to use them.\nscheduler = NotImplemented\n\n# Is your training time very high?\n# Look into mixed precision training if your GPU (Tesla T4, V100, etc) can make use of it\n# Refer - https://pytorch.org/docs/stable/notes/amp_examples.html\n# Mixed Precision Training with AMP for speedup\nscaler = torch.amp.GradScaler('cuda', enabled=True)","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:29:28.681502Z","iopub.status.busy":"2024-12-31T15:29:28.681153Z","iopub.status.idle":"2024-12-31T15:29:29.386622Z","shell.execute_reply":"2024-12-31T15:29:29.385517Z","shell.execute_reply.started":"2024-12-31T15:29:28.681476Z"},"id":"kZgQ7AgyTBnE"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Training and Validation Functions","metadata":{"id":"IBwunYpyugFg"}},{"cell_type":"markdown","source":"This section covers the training, and validation functions for each epoch of running your experiment with a given model architecture. The code has been provided to you, but we recommend going through the comments to understand the workflow to enable you to write these loops for future HWs.","metadata":{"id":"1JgeNhx4x2-P"}},{"cell_type":"code","source":"# CLEAR RAM!!\ntorch.cuda.empty_cache()\ngc.collect()","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:29:33.552602Z","iopub.status.busy":"2024-12-31T15:29:33.551839Z","iopub.status.idle":"2024-12-31T15:29:33.739892Z","shell.execute_reply":"2024-12-31T15:29:33.739136Z","shell.execute_reply.started":"2024-12-31T15:29:33.552569Z"},"id":"XblOHEVtKab2"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train(model, dataloader, optimizer, criterion):\n\n    model.train()\n    tloss, tacc = 0, 0 # Monitoring loss and accuracy\n    batch_bar   = tqdm(total=len(train_loader), dynamic_ncols=True, leave=False, position=0, desc='Train')\n\n    for i, (frames, phonemes) in enumerate(dataloader):\n\n        ### Initialize Gradients\n        optimizer.zero_grad()\n\n        frames      = frames.to(device)\n        phonemes    = phonemes.to(device)\n\n        with torch.autocast(device_type=device, dtype=torch.float16):\n            ### Forward Propagation\n            logits  = model(frames)\n\n            ### Loss Calculation\n            loss    = criterion(logits, phonemes)\n\n        ### Backward Propagation\n        scaler.scale(loss).backward()\n\n        # OPTIONAL: You can add gradient clipping here, if you face issues of exploding gradients\n\n        ### Gradient Descent\n        scaler.step(optimizer)\n        scaler.update()\n\n        tloss   += loss.item()\n        tacc    += torch.sum(torch.argmax(logits, dim= 1) == phonemes).item()/logits.shape[0]\n\n        batch_bar.set_postfix(loss=\"{:.04f}\".format(float(tloss / (i + 1))),\n                              acc=\"{:.04f}%\".format(float(tacc*100 / (i + 1))))\n        batch_bar.update()\n\n        ### Release memory\n        del frames, phonemes, logits\n        torch.cuda.empty_cache()\n\n\n    batch_bar.close()\n    tloss   /= len(train_loader)\n    tacc    /= len(train_loader)\n\n\n    return tloss, tacc","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:29:35.53331Z","iopub.status.busy":"2024-12-31T15:29:35.532955Z","iopub.status.idle":"2024-12-31T15:29:35.539902Z","shell.execute_reply":"2024-12-31T15:29:35.539084Z","shell.execute_reply.started":"2024-12-31T15:29:35.53328Z"},"id":"8wjPz7DHqKcL"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def eval(model, dataloader):\n\n    model.eval() # set model in evaluation mode\n    vloss, vacc = 0, 0 # Monitoring loss and accuracy\n    batch_bar   = tqdm(total=len(val_loader), dynamic_ncols=True, position=0, leave=False, desc='Val')\n\n    for i, (frames, phonemes) in enumerate(dataloader):\n\n        ### Move data to device (ideally GPU)\n        frames      = frames.to(device)\n        phonemes    = phonemes.to(device)\n\n        # makes sure that there are no gradients computed as we are not training the model now\n        with torch.inference_mode():\n            ### Forward Propagation\n            logits  = model(frames)\n            ### Loss Calculation\n            loss    = criterion(logits, phonemes)\n\n        vloss   += loss.item()\n        vacc    += torch.sum(torch.argmax(logits, dim= 1) == phonemes).item()/logits.shape[0]\n\n        # Do you think we need loss.backward() and optimizer.step() here?\n\n        batch_bar.set_postfix(loss=\"{:.04f}\".format(float(vloss / (i + 1))),\n                              acc=\"{:.04f}%\".format(float(vacc*100 / (i + 1))))\n        batch_bar.update()\n\n        ### Release memory\n        del frames, phonemes, logits\n        torch.cuda.empty_cache()\n\n    batch_bar.close()\n    vloss   /= len(val_loader)\n    vacc    /= len(val_loader)\n\n    return vloss, vacc","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:29:39.02401Z","iopub.status.busy":"2024-12-31T15:29:39.023658Z","iopub.status.idle":"2024-12-31T15:29:39.030046Z","shell.execute_reply":"2024-12-31T15:29:39.029273Z","shell.execute_reply.started":"2024-12-31T15:29:39.02398Z"},"id":"Q5npQNFH315V"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Weights and Biases Setup","metadata":{"id":"yMd_XxPku5qp"}},{"cell_type":"markdown","source":"This section is to enable logging metrics and files with Weights and Biases. Please refer to wandb documentationa and recitation 0 that covers the use of weights and biases for logging, hyperparameter tuning and monitoring your runs for your homeworks. Using this tool makes it very easy to show results when submitting your code and models for homeworks, and also extremely useful for study groups to organize and run ablations under a single team in wandb.\n\nWe have written code for you to make use of it out of the box, so that you start using wandb for all your HWs from the beginning.","metadata":{"id":"tjIbhR1wwbgI"}},{"cell_type":"code","source":"wandb.login(key=\"<API key>\") #API Key is in your wandb account, under settings (wandb.ai/settings)","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:29:45.702653Z","iopub.status.busy":"2024-12-31T15:29:45.702239Z","iopub.status.idle":"2024-12-31T15:29:52.086338Z","shell.execute_reply":"2024-12-31T15:29:52.085568Z","shell.execute_reply.started":"2024-12-31T15:29:45.702611Z"},"id":"SCDYx5VEu6qI"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create your wandb run\nrun = wandb.init(\n    name    = \"first-run1\", ### Wandb creates random run names if you skip this field, we recommend you give useful names\n    reinit  = True, ### Allows reinitalizing runs when you re-run this cell\n    #id     = \"\", ### Insert specific run id here if you want to resume a previous run\n    #resume = \"must\", ### You need this to resume previous runs, but comment out reinit = True when using this\n    project = \"hw1p2\", ### Project should be created in your wandb account\n    config  = config ### Wandb Config for your run\n)","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:29:54.895747Z","iopub.status.busy":"2024-12-31T15:29:54.895254Z","iopub.status.idle":"2024-12-31T15:30:01.107921Z","shell.execute_reply":"2024-12-31T15:30:01.106993Z","shell.execute_reply.started":"2024-12-31T15:29:54.895723Z"},"id":"xvUnYd3Bw2up"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### Save your model architecture as a string with str(model)\nmodel_arch  = str(model)\n\n### Save it in a txt file\narch_file   = open(\"model_arch.txt\", \"w\")\nfile_write  = arch_file.write(model_arch)\narch_file.close()\n\n### log it in your wandb run with wandb.save()\nwandb.save('model_arch.txt')","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:30:12.132356Z","iopub.status.busy":"2024-12-31T15:30:12.131957Z","iopub.status.idle":"2024-12-31T15:30:12.142067Z","shell.execute_reply":"2024-12-31T15:30:12.14128Z","shell.execute_reply.started":"2024-12-31T15:30:12.132322Z"},"id":"wft15E_IxYFi"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Experiment","metadata":{"id":"nclx_04fu7Dd"}},{"cell_type":"markdown","source":"Now, it is time to finally run your ablations! Have fun!","metadata":{"id":"MdLMWfEpyGOB"}},{"cell_type":"code","source":"# Iterate over number of epochs to train and evaluate your model\ntorch.cuda.empty_cache()\ngc.collect()\nwandb.watch(model, log=\"all\")\n\nfor epoch in range(config['epochs']):\n\n    print(\"\\nEpoch {}/{}\".format(epoch+1, config['epochs']))\n\n    curr_lr                 = float(optimizer.param_groups[0]['lr'])\n    train_loss, train_acc   = train(model, train_loader, optimizer, criterion)\n    val_loss, val_acc       = eval(model, val_loader)\n\n    print(\"\\tTrain Acc {:.04f}%\\tTrain Loss {:.04f}\\t Learning Rate {:.07f}\".format(train_acc*100, train_loss, curr_lr))\n    print(\"\\tVal Acc {:.04f}%\\tVal Loss {:.04f}\".format(val_acc*100, val_loss))\n\n    ## Log metrics at each epoch in your run\n    # Optionally, you can log at each batch inside train/eval functions\n    # (explore wandb documentation/wandb recitation)\n    wandb.log({'train_acc': train_acc*100, 'train_loss': train_loss,\n               'val_acc': val_acc*100, 'valid_loss': val_loss, 'lr': curr_lr})\n\n    # If using a scheduler, step the learning rate here, otherwise comment this line\n    # Depending on the scheduler in use, you may or may not need to pass in a metric into the step function, so read the docs well\n    scheduler.step(val_acc)\n\n    ## Highly Recommended: Save checkpoint in drive and/or wandb if accuracy is better than your current best","metadata":{"execution":{"iopub.execute_input":"2024-12-31T15:30:23.248062Z","iopub.status.busy":"2024-12-31T15:30:23.247745Z"},"id":"4NNCA5DDTBnO"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Testing and submission to Kaggle","metadata":{"id":"_kXwf5YUo_4A"}},{"cell_type":"markdown","source":"Before we get to the following code, make sure to see the format of submission given in *sample_submission.csv*. Once you have done so, it is time to fill the following function to complete your inference on test data. Refer the eval function from previous cells to get an idea of how to go about completing this function.","metadata":{"id":"WI1hSFYLpJvH"}},{"cell_type":"code","source":"def test(model, test_loader):\n    ### What you call for model to perform inference?\n    model.____() # TODO train or eval?\n\n    ### List to store predicted phonemes of test data\n    test_predictions = []\n\n    ### Which mode do you need to avoid gradients?\n    with torch._____(): # TODO\n\n        for i, mfccs in enumerate(tqdm(test_loader)):\n\n            mfccs   = mfccs.to(device)\n\n            logits  = model(mfccs)\n\n            ### Get most likely predicted phoneme with argmax\n            predicted_phonemes = NotImplemented\n\n            ### How do you store predicted_phonemes with test_predictions? Hint, look at eval\n            # Remember the phonemes were converted to their corresponding integer indices earlier, and the results of the argmax is a list of the indices of the predicted phonemes.\n            # So how do you get and store the actual predicted phonemes\n            # TODO: Store predicted_phonemes\n\n    return test_predictions","metadata":{"execution":{"iopub.execute_input":"2024-12-24T02:20:10.371165Z","iopub.status.busy":"2024-12-24T02:20:10.370733Z","iopub.status.idle":"2024-12-24T02:20:10.378449Z","shell.execute_reply":"2024-12-24T02:20:10.37734Z","shell.execute_reply.started":"2024-12-24T02:20:10.371126Z"},"id":"ijLrIJFl5dSf"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predictions = test(model, test_loader)","metadata":{"execution":{"iopub.execute_input":"2024-12-24T02:21:22.050782Z","iopub.status.busy":"2024-12-24T02:21:22.050471Z","iopub.status.idle":"2024-12-24T02:22:10.946756Z","shell.execute_reply":"2024-12-24T02:22:10.945858Z","shell.execute_reply.started":"2024-12-24T02:21:22.050753Z"},"id":"wG9v6Xmxu7wp"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### Create CSV file with predictions\nwith open(\"./submission.csv\", \"w+\") as f:\n    f.write(\"id,label\\n\")\n    for i in range(len(predictions)):\n        f.write(\"{},{}\\n\".format(i, predictions[i]))","metadata":{"execution":{"iopub.execute_input":"2024-12-24T02:22:12.849873Z","iopub.status.busy":"2024-12-24T02:22:12.849571Z","iopub.status.idle":"2024-12-24T02:22:14.184114Z","shell.execute_reply":"2024-12-24T02:22:14.183417Z","shell.execute_reply.started":"2024-12-24T02:22:12.849849Z"},"id":"_I6AVEY45dSg"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### Finish your wandb run\nrun.finish()","metadata":{"execution":{"iopub.execute_input":"2024-12-24T02:22:17.280785Z","iopub.status.busy":"2024-12-24T02:22:17.28051Z","iopub.status.idle":"2024-12-24T02:22:18.714924Z","shell.execute_reply":"2024-12-24T02:22:18.714234Z","shell.execute_reply.started":"2024-12-24T02:22:17.280761Z"},"id":"6Wf-P25TXU0N"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### Submit to kaggle competition using kaggle API (Uncomment below to use)\n!kaggle competitions submit -c 11785-spring-25-hw-1-p-2 -f /content/submission.csv -m \"Test Submission\"\n\n### However, its always safer to download the csv file and then upload to kaggle","metadata":{"execution":{"execution_failed":"2024-12-24T01:53:07.886Z"},"id":"LjcammuCxMKN"},"outputs":[],"execution_count":null}]}