├── Dataset ├── extract_clips.py ├── SEP-28k Dataset Download.ipynb └── Augmentation of Clips.ipynb ├── README.md ├── WordRep - Deep Learning.ipynb └── SoundRep - Deep Learning.ipynb /Dataset/extract_clips.py: -------------------------------------------------------------------------------- 1 | # 2 | # For licensing see accompanying LICENSE file. 3 | # Copyright (C) 2021 Apple Inc. All Rights Reserved. 4 | # 5 | 6 | """ 7 | For each podcast episode: 8 | * Get all clip information for that episode 9 | * Save each clip as a new wav file. 10 | """ 11 | 12 | import os 13 | import pathlib 14 | import subprocess 15 | 16 | import numpy as np 17 | import pandas as pd 18 | from scipy.io import wavfile 19 | 20 | import argparse 21 | 22 | parser = argparse.ArgumentParser(description='Extract clips from SEP-28k or FluencyBank.') 23 | parser.add_argument('--labels', type=str, required=True, 24 | help='Path to the labels csv files (e.g., SEP-28k_labels.csv)') 25 | parser.add_argument('--wavs', type=str, default="wavs", 26 | help='Path where audio files from download_audio.py are saved') 27 | parser.add_argument('--clips', type=str, default="clips", 28 | help='Path where clips should be extracted') 29 | parser.add_argument("--progress", action="store_true", 30 | help="Show progress") 31 | 32 | args = parser.parse_args() 33 | label_file = args.labels 34 | data_dir = args.wavs 35 | output_dir = args.clips 36 | 37 | 38 | # Load label/clip file 39 | data = pd.read_csv(label_file, dtype={"EpId":str}) 40 | 41 | # Get label columns from data file 42 | shows = data.Show 43 | episodes = data.EpId 44 | clip_idxs = data.ClipId 45 | starts = data.Start 46 | stops = data.Stop 47 | labels = data.iloc[:,5:].values 48 | 49 | n_items = len(shows) 50 | 51 | loaded_wav = "" 52 | cur_iter = range(n_items) 53 | if args.progress: 54 | from tqdm import tqdm 55 | cur_iter = tqdm(cur_iter) 56 | 57 | for i in cur_iter: 58 | clip_idx = clip_idxs[i] 59 | show_abrev = shows[i] 60 | episode = episodes[i].strip() 61 | 62 | # Setup paths 63 | wav_path = f"{data_dir}/{shows[i]}/{episode}.wav" 64 | clip_dir = pathlib.Path(f"{output_dir}/{show_abrev}/{episode}/") 65 | clip_path = f"{clip_dir}/{shows[i]}_{episode}_{clip_idx}.wav" 66 | 67 | if not os.path.exists(wav_path): 68 | print("Missing", wav_path) 69 | continue 70 | 71 | # Verify clip directory exists 72 | os.makedirs(clip_dir, exist_ok=True) 73 | 74 | # Load audio. For efficiency reasons don't reload if we've already open the file. 75 | if wav_path != loaded_wav: 76 | sample_rate, audio = wavfile.read(wav_path) 77 | assert sample_rate == 16000, "Sample rate must be 16 khz" 78 | 79 | # Keep track of the open file 80 | loaded_wav = wav_path 81 | 82 | # Save clip to file 83 | clip = audio[starts[i]:stops[i]] 84 | wavfile.write(clip_path, sample_rate, clip) 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stutter Detection and Classification 2 | 3 | Stuttering is a neuro-developmental speech disorder that interrupts the flow of speech due to involuntary pauses and sound repetitions. It has profound psychological impacts that affect social interactions and professional advancements. 4 | 5 | Automatically detecting stuttering events in speech recordings could assist speech therapists or speech pathologists track the fluency of people who stutter (PWS). It will also assist in the improvement of the existing speech recognition system for PWS. 6 | 7 | In this project, the SEP-28k dataset is utilized to perform comparative analysis to assess the performance of various machine learning models in classifying the five dysfluency types namely Prolongation, Interjection, Word Repetition, Sound Repetition and Blocks. 8 | 9 | ## Research Paper 10 | Read the full publication of this work here: https://www.sciencedirect.com/science/article/pii/S2215016124005016 11 | 12 | ## Contributions: 13 | 14 | 1. Developing robust machine learning models for classifying the five classes of Stutter- Interjection, Prolongation, Blocks, Sound Repetitions and Word Repetitions. 15 | 2. Conducting analysis on the impact of various features extracted manually as well as using pre-trained models. 16 | 3. Performing comparative analysis on each class of stutter using various machine learning models. 17 | 18 | ## Dataset 19 | The SEP-28k dataset, published by Apple Machine Learning Research, is used for training and evaluation.It consists of audio recordings from six podcast shows and is annotated with various dysfluency types. The dataset is multi-label and multi-class, with annotations done by at least three annotators. 20 | 21 | Annotations: The SEP-28k dataset includes annotations for audio clips, labeled by at least three annotators. These labels cover various categories such as 'Unsure', 'PoorAudioQuality', 'Music', 'DifficultToUnderstand', 'Interjection', 'Prolongation', 'Blocks', 'WordRep', 'SoundRep', 'NoStutteredWords', 'NoSpeech', and 'NaturalPause'. Each 3-second clip can have multiple labels, making the dataset both multi-label and multi-class. 22 | 23 |

24 | image 25 |

26 | 27 | ## Preprocessing: 28 | The following preprocessing steps were done before proceeding further: 29 | - Deleted audio clips not exactly 3 seconds long. 30 | - Ensured all audio clips had a 16kHz sampling rate. 31 | - Reduced classes from 11 to fewer due to lack of meaningful contribution. 32 | - Dropped the 'Unsure' column. 33 | - Removed clips labeled as music (introductory or concluding music). 34 | - Dropped the 'Music' column. 35 | - Removed clips labeled as 'DifficultToUnderstand' by two or more annotators. 36 | - Dropped the 'DifficultToUnderstand' column. 37 | - Class Imbalance was handled 38 | 39 | ## Feature Extraction: 40 | The following features were extracted: 41 | - MFCCs (Mel-Frequency Cepstral Coefficients): Capture the power spectrum of audio signals. 42 | - Zero Crossing Rate: Measure the rate at which the signal changes sign. 43 | - Jitter: Measure the frequency variation from cycle to cycle. 44 | - Shimmer: Measure the amplitude variation from cycle to cycle. 45 | 46 | ## Model Training: 47 | After the extracted features are concatenated into an array, these features are given to the models for training. Here individual models have been considered for each class- namely, K-Nearest Neighbors (KNN), Support Vector Machine (SVM), Random Forest, Decision Tree and Naive Bayes. All the above mentioned models are trained for all the classes and the model which gives the highest accuracy is chosen for that particular class. 48 | 49 | ## Hyperparameter Tuning: 50 | Hyperparameter tuning and cross validation techniques were applied on each of the models i.e., KNN, Logistic Regression, Decision Tree, Random Forest, and SVM, and just cross validation (with 10-fold cross-validation) for Naïve Bayes as it is a non-parametric model. 51 | 52 | ## Evaluation Metrics: 53 | Both training and testing were done on the SEP-28k dataset where the train to test ratio is 70:30. The main evaluation metric considered for choosing the models for each class is accuracy, as the data for each class was balanced. Other metrics considered are F1-score, accuracy, precision, recall, confusion matrix and ROC-AUC. 54 | 55 | ## Deployment: 56 | https://github.com/Ramitha-V/Stutter-Detection-and-Classification/assets/162662008/0f9b8ac6-bcea-439d-857a-e8e0754d3081 57 | -------------------------------------------------------------------------------- /Dataset/SEP-28k Dataset Download.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "4e08bf4d", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import requests\n", 11 | "import pandas as pd\n", 12 | "import os\n", 13 | "import time" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 2, 19 | "id": "2d9dd988", 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "df = pd.read_csv(\"D:\\SEM 4\\Project\\\\SEP-28k_episodes.csv\", header=None)" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 3, 29 | "id": "d5ffacca", 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "df.columns = ['name', 'desc', 'link', 'podcast_name', 'pod_id']" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 4, 39 | "id": "c1129cd6", 40 | "metadata": {}, 41 | "outputs": [ 42 | { 43 | "data": { 44 | "text/html": [ 45 | "
\n", 46 | "\n", 59 | "\n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | "
namedesclinkpodcast_namepod_id
0He_Stutters_Podcast_–_Make_Room_For_The_Stutte...episode-208-with-kelsey-hhttps://stutterrockstar.files.wordpress.com/2...HeStutters0
1He_Stutters_Podcast_–_Make_Room_For_The_Stutte...episode-208-with-kelsey-hhttps://stutterrockstar.files.wordpress.com/2...HeStutters1
2He_Stutters_Podcast_–_Make_Room_For_The_Stutte...episode-208-with-kelsey-hhttps://stutterrockstar.files.wordpress.com/2...HeStutters2
3He_Stutters_Podcast_–_Make_Room_For_The_Stutte...episode-208-with-kelsey-hhttps://stutterrockstar.files.wordpress.com/2...HeStutters3
4He_Stutters_Podcast_–_Make_Room_For_The_Stutte...episode-208-with-kelsey-hhttps://stutterrockstar.files.wordpress.com/2...HeStutters4
..................
380Women_Who_Stutter_Podcast_–_Make_Room_For_The_...cool148https://stutterrockstar.files.wordpress.com/2...WomenWhoStutter105
381Women_Who_Stutter_Podcast_–_Make_Room_For_The_...cool148https://stutterrockstar.files.wordpress.com/2...WomenWhoStutter106
382Women_Who_Stutter_Podcast_–_Make_Room_For_The_...cool148https://stutterrockstar.files.wordpress.com/2...WomenWhoStutter107
383Women_Who_Stutter_Podcast_–_Make_Room_For_The_...cool148https://stutterrockstar.files.wordpress.com/2...WomenWhoStutter108
384Women_Who_Stutter_Podcast_–_Make_Room_For_The_...cool148https://stutterrockstar.files.wordpress.com/2...WomenWhoStutter109
\n", 161 | "

385 rows × 5 columns

\n", 162 | "
" 163 | ], 164 | "text/plain": [ 165 | " name \\\n", 166 | "0 He_Stutters_Podcast_–_Make_Room_For_The_Stutte... \n", 167 | "1 He_Stutters_Podcast_–_Make_Room_For_The_Stutte... \n", 168 | "2 He_Stutters_Podcast_–_Make_Room_For_The_Stutte... \n", 169 | "3 He_Stutters_Podcast_–_Make_Room_For_The_Stutte... \n", 170 | "4 He_Stutters_Podcast_–_Make_Room_For_The_Stutte... \n", 171 | ".. ... \n", 172 | "380 Women_Who_Stutter_Podcast_–_Make_Room_For_The_... \n", 173 | "381 Women_Who_Stutter_Podcast_–_Make_Room_For_The_... \n", 174 | "382 Women_Who_Stutter_Podcast_–_Make_Room_For_The_... \n", 175 | "383 Women_Who_Stutter_Podcast_–_Make_Room_For_The_... \n", 176 | "384 Women_Who_Stutter_Podcast_–_Make_Room_For_The_... \n", 177 | "\n", 178 | " desc \\\n", 179 | "0 episode-208-with-kelsey-h \n", 180 | "1 episode-208-with-kelsey-h \n", 181 | "2 episode-208-with-kelsey-h \n", 182 | "3 episode-208-with-kelsey-h \n", 183 | "4 episode-208-with-kelsey-h \n", 184 | ".. ... \n", 185 | "380 cool148 \n", 186 | "381 cool148 \n", 187 | "382 cool148 \n", 188 | "383 cool148 \n", 189 | "384 cool148 \n", 190 | "\n", 191 | " link podcast_name \\\n", 192 | "0 https://stutterrockstar.files.wordpress.com/2... HeStutters \n", 193 | "1 https://stutterrockstar.files.wordpress.com/2... HeStutters \n", 194 | "2 https://stutterrockstar.files.wordpress.com/2... HeStutters \n", 195 | "3 https://stutterrockstar.files.wordpress.com/2... HeStutters \n", 196 | "4 https://stutterrockstar.files.wordpress.com/2... HeStutters \n", 197 | ".. ... ... \n", 198 | "380 https://stutterrockstar.files.wordpress.com/2... WomenWhoStutter \n", 199 | "381 https://stutterrockstar.files.wordpress.com/2... WomenWhoStutter \n", 200 | "382 https://stutterrockstar.files.wordpress.com/2... WomenWhoStutter \n", 201 | "383 https://stutterrockstar.files.wordpress.com/2... WomenWhoStutter \n", 202 | "384 https://stutterrockstar.files.wordpress.com/2... WomenWhoStutter \n", 203 | "\n", 204 | " pod_id \n", 205 | "0 0 \n", 206 | "1 1 \n", 207 | "2 2 \n", 208 | "3 3 \n", 209 | "4 4 \n", 210 | ".. ... \n", 211 | "380 105 \n", 212 | "381 106 \n", 213 | "382 107 \n", 214 | "383 108 \n", 215 | "384 109 \n", 216 | "\n", 217 | "[385 rows x 5 columns]" 218 | ] 219 | }, 220 | "execution_count": 4, 221 | "metadata": {}, 222 | "output_type": "execute_result" 223 | } 224 | ], 225 | "source": [ 226 | "df" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": 5, 232 | "id": "5a93449e", 233 | "metadata": {}, 234 | "outputs": [], 235 | "source": [ 236 | "path = r\"D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\"" 237 | ] 238 | }, 239 | { 240 | "cell_type": "code", 241 | "execution_count": 6, 242 | "id": "96bff8d8", 243 | "metadata": {}, 244 | "outputs": [ 245 | { 246 | "name": "stderr", 247 | "output_type": "stream", 248 | "text": [ 249 | "Downloading: 100%|██████████████████████████| 53.8M/53.8M [01:34<00:00, 570kB/s]" 250 | ] 251 | }, 252 | { 253 | "name": "stdout", 254 | "output_type": "stream", 255 | "text": [ 256 | "Audio file downloaded successfully: downloaded_audio.mp3\n" 257 | ] 258 | }, 259 | { 260 | "name": "stderr", 261 | "output_type": "stream", 262 | "text": [ 263 | "\n" 264 | ] 265 | } 266 | ], 267 | "source": [ 268 | "import requests\n", 269 | "from tqdm import tqdm # Import tqdm for the progress bar\n", 270 | "import pandas as pd\n", 271 | "\n", 272 | "url = \"https://stutterrockstar.files.wordpress.com/2011/05/male-episode-1-with-alan1.mp3\"\n", 273 | "output_file = \"downloaded_audio.mp3\"\n", 274 | "\n", 275 | "response = requests.get(url, stream=True)\n", 276 | "\n", 277 | "# Check if the request was successful (status code 200)\n", 278 | "if response.status_code == 200:\n", 279 | " # Get the total file size in bytes (content length)\n", 280 | " total_size = int(response.headers.get('content-length', 0))\n", 281 | "\n", 282 | " # Create a progress bar using tqdm\n", 283 | " with tqdm(total=total_size, unit='B', unit_scale=True, desc='Downloading', ncols=80) as bar:\n", 284 | " with open(output_file, 'wb') as f:\n", 285 | " for data in response.iter_content(chunk_size=1024):\n", 286 | " f.write(data)\n", 287 | " bar.update(len(data))\n", 288 | "\n", 289 | " print(f\"Audio file downloaded successfully: {output_file}\")\n", 290 | "else:\n", 291 | " print(f\"Failed to download audio file. Status code: {response.status_code}\")\n" 292 | ] 293 | }, 294 | { 295 | "cell_type": "code", 296 | "execution_count": 7, 297 | "id": "9427ba0e", 298 | "metadata": {}, 299 | "outputs": [], 300 | "source": [ 301 | "def download_audio_(row):\n", 302 | " url = row['link'].lstrip()\n", 303 | " audio_name = str(row['pod_id']) + \".mp3\"\n", 304 | " output_file = os.path.join(pod_path, audio_name)\n", 305 | " \n", 306 | " response = requests.get(url)\n", 307 | "\n", 308 | " \n", 309 | " if response.status_code == 200:\n", 310 | " with open(output_file, 'wb') as f:\n", 311 | " f.write(response.content)\n", 312 | " print(f\"Audio file downloaded successfully: {output_file}\")\n", 313 | " else:\n", 314 | " print(f\"Failed to download audio file. Status code: {response.status_code}\")" 315 | ] 316 | }, 317 | { 318 | "cell_type": "code", 319 | "execution_count": 8, 320 | "id": "da72ea0a", 321 | "metadata": {}, 322 | "outputs": [], 323 | "source": [ 324 | "def download_audio(row):\n", 325 | " url = row['link'].lstrip()\n", 326 | " audio_name = str(row['pod_id']) + \".mp3\"\n", 327 | " output_file = os.path.join(pod_path, audio_name)\n", 328 | " \n", 329 | " response = requests.get(url)\n", 330 | "\n", 331 | " \n", 332 | " if response.status_code == 200:\n", 333 | " # Get the total file size in bytes (content length)\n", 334 | " total_size = int(response.headers.get('content-length', 0))\n", 335 | "\n", 336 | " # Create a progress bar using tqdm\n", 337 | " with tqdm(total=total_size, unit='B', unit_scale=True, desc=f'Downloading {audio_name}', ncols=80) as bar:\n", 338 | " with open(output_file, 'wb') as f:\n", 339 | " for data in response.iter_content(chunk_size=1024):\n", 340 | " f.write(data)\n", 341 | " bar.update(len(data)) \n", 342 | " print(f\"Audio file downloaded successfully: {output_file}\")\n", 343 | " \n", 344 | " else:\n", 345 | " print(f\"Failed to download audio file. Status code: {response.status_code}\")" 346 | ] 347 | }, 348 | { 349 | "cell_type": "code", 350 | "execution_count": 10, 351 | "id": "22c25ad8", 352 | "metadata": {}, 353 | "outputs": [ 354 | { 355 | "name": "stderr", 356 | "output_type": "stream", 357 | "text": [ 358 | "Downloading 0.mp3: 17.0MB [00:00, 589MB/s]\n" 359 | ] 360 | }, 361 | { 362 | "name": "stdout", 363 | "output_type": "stream", 364 | "text": [ 365 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\0.mp3\n" 366 | ] 367 | }, 368 | { 369 | "name": "stderr", 370 | "output_type": "stream", 371 | "text": [ 372 | "Downloading 1.mp3: 38.8MB [00:00, 638MB/s]\n" 373 | ] 374 | }, 375 | { 376 | "name": "stdout", 377 | "output_type": "stream", 378 | "text": [ 379 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\1.mp3\n" 380 | ] 381 | }, 382 | { 383 | "name": "stderr", 384 | "output_type": "stream", 385 | "text": [ 386 | "Downloading 2.mp3: 37.6MB [00:00, 639MB/s]\n" 387 | ] 388 | }, 389 | { 390 | "name": "stdout", 391 | "output_type": "stream", 392 | "text": [ 393 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\2.mp3\n" 394 | ] 395 | }, 396 | { 397 | "name": "stderr", 398 | "output_type": "stream", 399 | "text": [ 400 | "Downloading 3.mp3: 40.2MB [00:00, 235MB/s]\n" 401 | ] 402 | }, 403 | { 404 | "name": "stdout", 405 | "output_type": "stream", 406 | "text": [ 407 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\3.mp3\n" 408 | ] 409 | }, 410 | { 411 | "name": "stderr", 412 | "output_type": "stream", 413 | "text": [ 414 | "Downloading 4.mp3: 43.2MB [00:00, 278MB/s]\n" 415 | ] 416 | }, 417 | { 418 | "name": "stdout", 419 | "output_type": "stream", 420 | "text": [ 421 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\4.mp3\n" 422 | ] 423 | }, 424 | { 425 | "name": "stderr", 426 | "output_type": "stream", 427 | "text": [ 428 | "Downloading 5.mp3: 60.6MB [00:00, 253MB/s]\n" 429 | ] 430 | }, 431 | { 432 | "name": "stdout", 433 | "output_type": "stream", 434 | "text": [ 435 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\5.mp3\n" 436 | ] 437 | }, 438 | { 439 | "name": "stderr", 440 | "output_type": "stream", 441 | "text": [ 442 | "Downloading 6.mp3: 55.0MB [00:00, 262MB/s]\n" 443 | ] 444 | }, 445 | { 446 | "name": "stdout", 447 | "output_type": "stream", 448 | "text": [ 449 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\6.mp3\n" 450 | ] 451 | }, 452 | { 453 | "name": "stderr", 454 | "output_type": "stream", 455 | "text": [ 456 | "Downloading 7.mp3: 74.8MB [00:00, 296MB/s]\n" 457 | ] 458 | }, 459 | { 460 | "name": "stdout", 461 | "output_type": "stream", 462 | "text": [ 463 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\7.mp3\n" 464 | ] 465 | }, 466 | { 467 | "name": "stderr", 468 | "output_type": "stream", 469 | "text": [ 470 | "Downloading 8.mp3: 16.0MB [00:00, 138MB/s]\n" 471 | ] 472 | }, 473 | { 474 | "name": "stdout", 475 | "output_type": "stream", 476 | "text": [ 477 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\8.mp3\n" 478 | ] 479 | }, 480 | { 481 | "name": "stderr", 482 | "output_type": "stream", 483 | "text": [ 484 | "Downloading 9.mp3: 35.4MB [00:00, 206MB/s]\n" 485 | ] 486 | }, 487 | { 488 | "name": "stdout", 489 | "output_type": "stream", 490 | "text": [ 491 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\9.mp3\n" 492 | ] 493 | }, 494 | { 495 | "name": "stderr", 496 | "output_type": "stream", 497 | "text": [ 498 | "Downloading 10.mp3: 41.3MB [00:00, 215MB/s]\n" 499 | ] 500 | }, 501 | { 502 | "name": "stdout", 503 | "output_type": "stream", 504 | "text": [ 505 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\10.mp3\n" 506 | ] 507 | }, 508 | { 509 | "name": "stderr", 510 | "output_type": "stream", 511 | "text": [ 512 | "Downloading 11.mp3: 27.1MB [00:00, 192MB/s]\n" 513 | ] 514 | }, 515 | { 516 | "name": "stdout", 517 | "output_type": "stream", 518 | "text": [ 519 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\11.mp3\n" 520 | ] 521 | }, 522 | { 523 | "name": "stderr", 524 | "output_type": "stream", 525 | "text": [ 526 | "Downloading 12.mp3: 20.5MB [00:00, 174MB/s]\n" 527 | ] 528 | }, 529 | { 530 | "name": "stdout", 531 | "output_type": "stream", 532 | "text": [ 533 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\12.mp3\n" 534 | ] 535 | }, 536 | { 537 | "name": "stderr", 538 | "output_type": "stream", 539 | "text": [ 540 | "Downloading 13.mp3: 24.7MB [00:00, 190MB/s]\n" 541 | ] 542 | }, 543 | { 544 | "name": "stdout", 545 | "output_type": "stream", 546 | "text": [ 547 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\13.mp3\n" 548 | ] 549 | }, 550 | { 551 | "name": "stderr", 552 | "output_type": "stream", 553 | "text": [ 554 | "Downloading 14.mp3: 22.4MB [00:00, 178MB/s]\n" 555 | ] 556 | }, 557 | { 558 | "name": "stdout", 559 | "output_type": "stream", 560 | "text": [ 561 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\14.mp3\n" 562 | ] 563 | }, 564 | { 565 | "name": "stderr", 566 | "output_type": "stream", 567 | "text": [ 568 | "Downloading 15.mp3: 36.8MB [00:00, 350MB/s]\n" 569 | ] 570 | }, 571 | { 572 | "name": "stdout", 573 | "output_type": "stream", 574 | "text": [ 575 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\15.mp3\n" 576 | ] 577 | }, 578 | { 579 | "name": "stderr", 580 | "output_type": "stream", 581 | "text": [ 582 | "Downloading 16.mp3: 41.7MB [00:00, 238MB/s]\n" 583 | ] 584 | }, 585 | { 586 | "name": "stdout", 587 | "output_type": "stream", 588 | "text": [ 589 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\16.mp3\n" 590 | ] 591 | }, 592 | { 593 | "name": "stderr", 594 | "output_type": "stream", 595 | "text": [ 596 | "Downloading 17.mp3: 226MB [00:00, 325MB/s] \n" 597 | ] 598 | }, 599 | { 600 | "name": "stdout", 601 | "output_type": "stream", 602 | "text": [ 603 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\17.mp3\n" 604 | ] 605 | }, 606 | { 607 | "name": "stderr", 608 | "output_type": "stream", 609 | "text": [ 610 | "Downloading 18.mp3: 48.3MB [00:00, 243MB/s]\n" 611 | ] 612 | }, 613 | { 614 | "name": "stdout", 615 | "output_type": "stream", 616 | "text": [ 617 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\18.mp3\n" 618 | ] 619 | }, 620 | { 621 | "name": "stderr", 622 | "output_type": "stream", 623 | "text": [ 624 | "Downloading 19.mp3: 43.0MB [00:00, 243MB/s]\n" 625 | ] 626 | }, 627 | { 628 | "name": "stdout", 629 | "output_type": "stream", 630 | "text": [ 631 | "Audio file downloaded successfully: D:\\\\SEM 4\\Project\\\\StutterDataset\\\\wavs\\StutterTalk\\19.mp3\n" 632 | ] 633 | } 634 | ], 635 | "source": [ 636 | "for index, row in df.iloc[108:128].iterrows():\n", 637 | " pod_name = row['podcast_name'].lstrip()\n", 638 | " pod_path = os.path.join(path, pod_name)\n", 639 | " if os.path.exists(pod_path):\n", 640 | " download_audio(row)\n", 641 | " time.sleep(5)\n", 642 | " \n", 643 | " else:\n", 644 | " os.makedirs(pod_path)\n", 645 | " download_audio(row)\n", 646 | " time.sleep(5)\n", 647 | "\n", 648 | " " 649 | ] 650 | }, 651 | { 652 | "cell_type": "code", 653 | "execution_count": null, 654 | "id": "a4435633", 655 | "metadata": {}, 656 | "outputs": [], 657 | "source": [] 658 | }, 659 | { 660 | "cell_type": "code", 661 | "execution_count": null, 662 | "id": "198d9929", 663 | "metadata": {}, 664 | "outputs": [], 665 | "source": [] 666 | } 667 | ], 668 | "metadata": { 669 | "kernelspec": { 670 | "display_name": "Python 3 (ipykernel)", 671 | "language": "python", 672 | "name": "python3" 673 | }, 674 | "language_info": { 675 | "codemirror_mode": { 676 | "name": "ipython", 677 | "version": 3 678 | }, 679 | "file_extension": ".py", 680 | "mimetype": "text/x-python", 681 | "name": "python", 682 | "nbconvert_exporter": "python", 683 | "pygments_lexer": "ipython3", 684 | "version": "3.11.3" 685 | } 686 | }, 687 | "nbformat": 4, 688 | "nbformat_minor": 5 689 | } 690 | -------------------------------------------------------------------------------- /Dataset/Augmentation of Clips.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 9, 6 | "id": "9d3fcce2", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "# Importing the libraries\n", 11 | "import numpy as np\n", 12 | "import pandas as pd\n", 13 | "import librosa\n", 14 | "import matplotlib.pyplot as plt\n", 15 | "import os\n", 16 | "import soundfile as sf\n", 17 | "import random" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 10, 23 | "id": "b556fa5f", 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "# # Load DataFrame\n", 28 | "df = pd.read_csv('D:\\SEM 4\\Project\\\\SEP-28k_labels.csv')" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 11, 34 | "id": "160b2796", 35 | "metadata": {}, 36 | "outputs": [ 37 | { 38 | "data": { 39 | "text/html": [ 40 | "
\n", 41 | "\n", 54 | "\n", 55 | " \n", 56 | " \n", 57 | " \n", 58 | " \n", 59 | " \n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | "
ShowEpIdClipIdStartStopUnsurePoorAudioQualityProlongationBlockSoundRepWordRepDifficultToUnderstandInterjectionNoStutteredWordsNaturalPauseMusicNoSpeech
0HeStutters003190032031948320000000003100
1HeStutters013197712032025120000000003100
2HeStutters023480976034857760000000003000
3HeStutters033520064035248640001000002000
4HeStutters043572192035769920000000003000
\n", 180 | "
" 181 | ], 182 | "text/plain": [ 183 | " Show EpId ClipId Start Stop Unsure PoorAudioQuality \\\n", 184 | "0 HeStutters 0 0 31900320 31948320 0 0 \n", 185 | "1 HeStutters 0 1 31977120 32025120 0 0 \n", 186 | "2 HeStutters 0 2 34809760 34857760 0 0 \n", 187 | "3 HeStutters 0 3 35200640 35248640 0 0 \n", 188 | "4 HeStutters 0 4 35721920 35769920 0 0 \n", 189 | "\n", 190 | " Prolongation Block SoundRep WordRep DifficultToUnderstand \\\n", 191 | "0 0 0 0 0 0 \n", 192 | "1 0 0 0 0 0 \n", 193 | "2 0 0 0 0 0 \n", 194 | "3 1 0 0 0 0 \n", 195 | "4 0 0 0 0 0 \n", 196 | "\n", 197 | " Interjection NoStutteredWords NaturalPause Music NoSpeech \n", 198 | "0 0 3 1 0 0 \n", 199 | "1 0 3 1 0 0 \n", 200 | "2 0 3 0 0 0 \n", 201 | "3 0 2 0 0 0 \n", 202 | "4 0 3 0 0 0 " 203 | ] 204 | }, 205 | "execution_count": 11, 206 | "metadata": {}, 207 | "output_type": "execute_result" 208 | } 209 | ], 210 | "source": [ 211 | "df.head()" 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": 12, 217 | "id": "fc95f46b", 218 | "metadata": {}, 219 | "outputs": [ 220 | { 221 | "data": { 222 | "text/plain": [ 223 | "array(['HeStutters', 'HVSA', 'IStutterSoWhat', 'MyStutteringLife',\n", 224 | " 'StrongVoices', 'StutterTalk', 'StutteringIsCool',\n", 225 | " 'WomenWhoStutter'], dtype=object)" 226 | ] 227 | }, 228 | "execution_count": 12, 229 | "metadata": {}, 230 | "output_type": "execute_result" 231 | } 232 | ], 233 | "source": [ 234 | "df['Show'].unique()" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": 13, 240 | "id": "18a17fd2", 241 | "metadata": {}, 242 | "outputs": [], 243 | "source": [ 244 | "#Reading the audio files\n", 245 | "main_folder = 'D:\\\\SEM 4\\\\Project\\\\sep28k-final'\n", 246 | "def list_files(directory):\n", 247 | " for root, _, files in os.walk(directory):\n", 248 | " for file in files:\n", 249 | " yield os.path.join(root, file)" 250 | ] 251 | }, 252 | { 253 | "cell_type": "code", 254 | "execution_count": 17, 255 | "id": "d7ffddf9", 256 | "metadata": {}, 257 | "outputs": [], 258 | "source": [ 259 | "def count_files(directory):\n", 260 | " file_count = 0\n", 261 | " for root, _, files in os.walk(directory):\n", 262 | " file_count += len(files)\n", 263 | " return file_count" 264 | ] 265 | }, 266 | { 267 | "cell_type": "code", 268 | "execution_count": 18, 269 | "id": "a03ede16", 270 | "metadata": {}, 271 | "outputs": [ 272 | { 273 | "name": "stdout", 274 | "output_type": "stream", 275 | "text": [ 276 | "Number of files in main directory: 21836\n" 277 | ] 278 | } 279 | ], 280 | "source": [ 281 | "num_files = count_files(main_folder)\n", 282 | "print(\"Number of files in main directory:\", num_files)" 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "execution_count": 8, 288 | "id": "f570fecf", 289 | "metadata": {}, 290 | "outputs": [], 291 | "source": [ 292 | "def remove_short_clips(directory):\n", 293 | " removed_count = 0\n", 294 | " for file_path in list_files(directory):\n", 295 | " # Load audio and get its duration\n", 296 | " audio, sr = librosa.load(file_path, sr=None)\n", 297 | " duration = librosa.get_duration(y=audio, sr=sr)\n", 298 | " # Check if duration is less than 3 seconds\n", 299 | " if duration < 3.0:\n", 300 | " # Remove the file\n", 301 | " os.remove(file_path)\n", 302 | " removed_count += 1\n", 303 | " print(f\"Removed {file_path} (duration: {duration:.2f} seconds)\")\n", 304 | " return removed_count\n" 305 | ] 306 | }, 307 | { 308 | "cell_type": "code", 309 | "execution_count": 9, 310 | "id": "b0ff8305", 311 | "metadata": {}, 312 | "outputs": [ 313 | { 314 | "name": "stdout", 315 | "output_type": "stream", 316 | "text": [ 317 | "Removed D:\\SEM 4\\Project\\sep28k-final\\HeStutters\\17\\HeStutters_17_0.wav (duration: 2.90 seconds)\n", 318 | "Removed D:\\SEM 4\\Project\\sep28k-final\\HeStutters\\2\\HeStutters_2_41.wav (duration: 2.70 seconds)\n", 319 | "Removed D:\\SEM 4\\Project\\sep28k-final\\HVSA\\0\\HVSA_0_0.wav (duration: 2.63 seconds)\n", 320 | "Removed D:\\SEM 4\\Project\\sep28k-final\\HVSA\\3\\HVSA_3_37.wav (duration: 2.86 seconds)\n", 321 | "Removed D:\\SEM 4\\Project\\sep28k-final\\IStutterSoWhat\\2\\IStutterSoWhat_2_37.wav (duration: 2.88 seconds)\n", 322 | "Removed D:\\SEM 4\\Project\\sep28k-final\\MyStutteringLife\\0\\MyStutteringLife_0_10.wav (duration: 2.56 seconds)\n", 323 | "Removed D:\\SEM 4\\Project\\sep28k-final\\MyStutteringLife\\18\\MyStutteringLife_18_1.wav (duration: 2.69 seconds)\n", 324 | "Removed D:\\SEM 4\\Project\\sep28k-final\\MyStutteringLife\\23\\MyStutteringLife_23_3.wav (duration: 2.69 seconds)\n", 325 | "Removed D:\\SEM 4\\Project\\sep28k-final\\MyStutteringLife\\7\\MyStutteringLife_7_13.wav (duration: 2.73 seconds)\n", 326 | "Removed D:\\SEM 4\\Project\\sep28k-final\\StutterTalk\\5\\StutterTalk_5_8.wav (duration: 2.83 seconds)\n", 327 | "Removed D:\\SEM 4\\Project\\sep28k-final\\WomenWhoStutter\\101\\WomenWhoStutter_101_0.wav (duration: 2.58 seconds)\n", 328 | "Removed D:\\SEM 4\\Project\\sep28k-final\\WomenWhoStutter\\101\\WomenWhoStutter_101_35.wav (duration: 2.58 seconds)\n", 329 | "Removed D:\\SEM 4\\Project\\sep28k-final\\WomenWhoStutter\\47\\WomenWhoStutter_47_1.wav (duration: 2.63 seconds)\n", 330 | "Removed D:\\SEM 4\\Project\\sep28k-final\\WomenWhoStutter\\73\\WomenWhoStutter_73_0.wav (duration: 2.55 seconds)\n", 331 | "Removed D:\\SEM 4\\Project\\sep28k-final\\WomenWhoStutter\\74\\WomenWhoStutter_74_0.wav (duration: 2.54 seconds)\n", 332 | "Removed D:\\SEM 4\\Project\\sep28k-final\\WomenWhoStutter\\80\\WomenWhoStutter_80_9.wav (duration: 2.58 seconds)\n", 333 | "Removed D:\\SEM 4\\Project\\sep28k-final\\WomenWhoStutter\\85\\WomenWhoStutter_85_0.wav (duration: 2.55 seconds)\n", 334 | "Removed D:\\SEM 4\\Project\\sep28k-final\\WomenWhoStutter\\86\\WomenWhoStutter_86_0.wav (duration: 2.55 seconds)\n", 335 | "Removed D:\\SEM 4\\Project\\sep28k-final\\WomenWhoStutter\\87\\WomenWhoStutter_87_0.wav (duration: 2.56 seconds)\n", 336 | "Removed D:\\SEM 4\\Project\\sep28k-final\\WomenWhoStutter\\97\\WomenWhoStutter_97_0.wav (duration: 2.59 seconds)\n", 337 | "Total files removed: 20\n" 338 | ] 339 | } 340 | ], 341 | "source": [ 342 | "removed_count = remove_short_clips(main_folder)\n", 343 | "print(\"Total files removed:\", removed_count)" 344 | ] 345 | }, 346 | { 347 | "cell_type": "code", 348 | "execution_count": 10, 349 | "id": "bed7c219", 350 | "metadata": {}, 351 | "outputs": [ 352 | { 353 | "name": "stdout", 354 | "output_type": "stream", 355 | "text": [ 356 | "Number of files after removal: 21836\n" 357 | ] 358 | } 359 | ], 360 | "source": [ 361 | "num_files_after = count_files(main_folder)\n", 362 | "print(\"Number of files after removal:\", num_files_after)" 363 | ] 364 | }, 365 | { 366 | "cell_type": "code", 367 | "execution_count": 11, 368 | "id": "4efe6e8a", 369 | "metadata": {}, 370 | "outputs": [], 371 | "source": [ 372 | "def check_sampling_rate(directory, target_sr=16000):\n", 373 | " non_matching_files = []\n", 374 | " for file_path in list_files(directory):\n", 375 | " # Load audio and get its sampling rate\n", 376 | " audio, sr = librosa.load(file_path, sr=None)\n", 377 | " # Check if sampling rate is not the target rate\n", 378 | " if sr != target_sr:\n", 379 | " non_matching_files.append((file_path, sr))\n", 380 | " return non_matching_files" 381 | ] 382 | }, 383 | { 384 | "cell_type": "code", 385 | "execution_count": 12, 386 | "id": "812f048e", 387 | "metadata": {}, 388 | "outputs": [], 389 | "source": [ 390 | "# Check sampling rate of audio files\n", 391 | "non_matching_files = check_sampling_rate(main_folder)" 392 | ] 393 | }, 394 | { 395 | "cell_type": "code", 396 | "execution_count": 13, 397 | "id": "f42d92b0", 398 | "metadata": {}, 399 | "outputs": [ 400 | { 401 | "name": "stdout", 402 | "output_type": "stream", 403 | "text": [ 404 | "All files have the desired sampling rate (16000)\n" 405 | ] 406 | } 407 | ], 408 | "source": [ 409 | "if non_matching_files:\n", 410 | " print(\"Files with non-matching sampling rates:\")\n", 411 | " for file_path, sr in non_matching_files:\n", 412 | " print(f\"{file_path}: Sampling rate = {sr}\")\n", 413 | "else:\n", 414 | " print(\"All files have the desired sampling rate (16000)\")" 415 | ] 416 | }, 417 | { 418 | "cell_type": "code", 419 | "execution_count": 14, 420 | "id": "a5c2cb78", 421 | "metadata": {}, 422 | "outputs": [ 423 | { 424 | "name": "stdout", 425 | "output_type": "stream", 426 | "text": [ 427 | "Number of files after checking: 21836\n" 428 | ] 429 | } 430 | ], 431 | "source": [ 432 | "num_files_after = count_files(main_folder)\n", 433 | "print(\"Number of files after checking:\", num_files_after)" 434 | ] 435 | }, 436 | { 437 | "cell_type": "code", 438 | "execution_count": 15, 439 | "id": "9bbd0968", 440 | "metadata": {}, 441 | "outputs": [], 442 | "source": [ 443 | "def augment_all_files_music(input_folder, output_folder, music_folder):\n", 444 | " # Create the output folder if it doesn't exist\n", 445 | " if not os.path.exists(output_folder):\n", 446 | " os.makedirs(output_folder)\n", 447 | " \n", 448 | " # Loop through all files in the input folder and its subdirectories\n", 449 | " for root, _, files in os.walk(input_folder):\n", 450 | " # Create corresponding output subdirectory structure\n", 451 | " output_subfolder = os.path.join(output_folder, os.path.relpath(root, input_folder))\n", 452 | " os.makedirs(output_subfolder, exist_ok=True)\n", 453 | " \n", 454 | " for file_name in files:\n", 455 | " if file_name.endswith('.wav'): # Assuming all files are in WAV format\n", 456 | " # Construct the full paths for input and output files\n", 457 | " input_file_path = os.path.join(root, file_name)\n", 458 | " output_file_path = os.path.join(output_subfolder, f\"{os.path.splitext(file_name)[0]}_aug.wav\")\n", 459 | " \n", 460 | " # Load stuttered speech sample (ensure duration is 3 seconds)\n", 461 | " audio, sr = librosa.load(input_file_path, sr=None, duration=3.0)\n", 462 | " \n", 463 | " # Randomly select a music file from the music folder\n", 464 | " music_files = os.listdir(music_folder)\n", 465 | " selected_music_file = np.random.choice(music_files)\n", 466 | " music_file = os.path.join(music_folder, selected_music_file)\n", 467 | " \n", 468 | " # Load selected music file\n", 469 | " music, sr_music = librosa.load(music_file, sr=None, duration=len(audio)/sr)\n", 470 | " \n", 471 | " # Perform augmentation\n", 472 | " snr = np.random.uniform(5, 15)\n", 473 | " scaling_factor = np.sqrt(np.var(audio) / (np.var(music) * 10 ** (snr / 10)))\n", 474 | " augmented_audio = audio + scaling_factor * music\n", 475 | " \n", 476 | " # Write augmented audio to the specified output path\n", 477 | " sf.write(output_file_path, augmented_audio, sr)\n" 478 | ] 479 | }, 480 | { 481 | "cell_type": "code", 482 | "execution_count": 16, 483 | "id": "3b1f1292", 484 | "metadata": {}, 485 | "outputs": [], 486 | "source": [ 487 | "def augment_all_files_noise(input_folder, output_folder, noise_folder, snr_range=(0, 15)):\n", 488 | " # Create the output folder if it doesn't exist\n", 489 | " if not os.path.exists(output_folder):\n", 490 | " os.makedirs(output_folder)\n", 491 | " \n", 492 | " # Loop through all files in the input folder and its subdirectories\n", 493 | " for root, _, files in os.walk(input_folder):\n", 494 | " # Create corresponding output subdirectory structure\n", 495 | " output_subfolder = os.path.join(output_folder, os.path.relpath(root, input_folder))\n", 496 | " os.makedirs(output_subfolder, exist_ok=True)\n", 497 | " \n", 498 | " for file_name in files:\n", 499 | " if file_name.endswith('.wav'): # Assuming all files are in WAV format\n", 500 | " # Construct the full paths for input and output files\n", 501 | " input_file_path = os.path.join(root, file_name)\n", 502 | " output_file_path = os.path.join(output_subfolder, f\"{os.path.splitext(file_name)[0]}_noise_aug.wav\")\n", 503 | " \n", 504 | " # Load stuttered speech sample (ensure duration is 3 seconds)\n", 505 | " audio, sr = librosa.load(input_file_path, sr=None, duration=3.0)\n", 506 | " \n", 507 | " # Initialize augmented audio\n", 508 | " augmented_audio = np.copy(audio)\n", 509 | " \n", 510 | " # Randomly select a noise file from the noise folder\n", 511 | " noise_files = os.listdir(noise_folder)\n", 512 | " selected_noise_file = np.random.choice(noise_files)\n", 513 | " noise_file = os.path.join(noise_folder, selected_noise_file)\n", 514 | " \n", 515 | " # Load selected noise file with duration matching the length of the stuttered speech clip\n", 516 | " noise, sr_noise = librosa.load(noise_file, sr=None, duration=3.0)\n", 517 | " \n", 518 | " # Ensure noise matches the length of the audio segment\n", 519 | " while len(noise) < len(audio):\n", 520 | " noise = np.concatenate([noise, noise[:len(audio) - len(noise)]])\n", 521 | " \n", 522 | " # Add noise at 1-second intervals\n", 523 | " for i in range(sr, len(audio), sr):\n", 524 | " # Compute SNR\n", 525 | " snr = np.random.uniform(snr_range[0], snr_range[1])\n", 526 | " \n", 527 | " # Compute scaling factor for noise\n", 528 | " scaling_factor = np.sqrt(np.var(audio[i-sr:i]) / (np.var(noise) * 10 ** (snr / 10)))\n", 529 | " \n", 530 | " # Add scaled noise to audio\n", 531 | " augmented_audio[i-sr:i] += scaling_factor * noise[i-sr:i]\n", 532 | " \n", 533 | " # Write augmented audio to the specified output path\n", 534 | " sf.write(output_file_path, augmented_audio, sr)\n" 535 | ] 536 | }, 537 | { 538 | "cell_type": "code", 539 | "execution_count": 17, 540 | "id": "50e7bfb7", 541 | "metadata": {}, 542 | "outputs": [], 543 | "source": [ 544 | "def augment_all_files_babble(input_folder, output_folder, speech_folder, snr_range=(13, 20), num_speakers_range=(3, 7)):\n", 545 | " # Create the output folder if it doesn't exist\n", 546 | " if not os.path.exists(output_folder):\n", 547 | " os.makedirs(output_folder)\n", 548 | " \n", 549 | " # Loop through all files in the input folder and its subdirectories\n", 550 | " for root, _, files in os.walk(input_folder):\n", 551 | " # Create corresponding output subdirectory structure\n", 552 | " output_subfolder = os.path.join(output_folder, os.path.relpath(root, input_folder))\n", 553 | " os.makedirs(output_subfolder, exist_ok=True)\n", 554 | " \n", 555 | " for file_name in files:\n", 556 | " if file_name.endswith('.wav'): # Assuming all files are in WAV format\n", 557 | " # Construct the full paths for input and output files\n", 558 | " input_file_path = os.path.join(root, file_name)\n", 559 | " output_file_path = os.path.join(output_subfolder, f\"{os.path.splitext(file_name)[0]}_babble_aug.wav\")\n", 560 | " \n", 561 | " # Load stuttered speech sample (ensure duration is 3 seconds)\n", 562 | " audio, sr = librosa.load(input_file_path, sr=None, duration=3.0)\n", 563 | " \n", 564 | " # Initialize augmented audio\n", 565 | " augmented_audio = np.copy(audio)\n", 566 | " \n", 567 | " # Randomly select speech files from the speech folder to create babble\n", 568 | " babble_audio = np.zeros_like(audio)\n", 569 | " num_speakers = random.randint(num_speakers_range[0], num_speakers_range[1])\n", 570 | " for _ in range(num_speakers):\n", 571 | " speech_files = os.listdir(speech_folder)\n", 572 | " selected_speech_file = np.random.choice(speech_files)\n", 573 | " speech_file = os.path.join(speech_folder, selected_speech_file)\n", 574 | " \n", 575 | " # Load selected speech file with duration matching the length of the stuttered speech clip\n", 576 | " speech, _ = librosa.load(speech_file, sr=None, duration=3.0)\n", 577 | " \n", 578 | " # Ensure speech matches the length of the audio segment\n", 579 | " while len(speech) < len(audio):\n", 580 | " speech = np.concatenate([speech, speech[:len(audio) - len(speech)]])\n", 581 | " \n", 582 | " # Mix speech\n", 583 | " babble_audio += speech\n", 584 | " \n", 585 | " # Compute SNR\n", 586 | " snr = np.random.uniform(snr_range[0], snr_range[1])\n", 587 | " \n", 588 | " # Compute scaling factor for babble\n", 589 | " scaling_factor = np.sqrt(np.var(audio) / (np.var(babble_audio) * 10 ** (snr / 10)))\n", 590 | " \n", 591 | " # Add scaled babble to audio\n", 592 | " augmented_audio += scaling_factor * babble_audio\n", 593 | " \n", 594 | " # Write augmented audio to the specified output path\n", 595 | " sf.write(output_file_path, augmented_audio, sr)" 596 | ] 597 | }, 598 | { 599 | "cell_type": "code", 600 | "execution_count": 14, 601 | "id": "d9e52a6f", 602 | "metadata": {}, 603 | "outputs": [], 604 | "source": [ 605 | "def augment_all_files_rirs(input_folder, output_folder, rirs_folder):\n", 606 | " # Create the output folder if it doesn't exist\n", 607 | " if not os.path.exists(output_folder):\n", 608 | " os.makedirs(output_folder)\n", 609 | " \n", 610 | " # Loop through all files in the input folder and its subdirectories\n", 611 | " for root, _, files in os.walk(input_folder):\n", 612 | " # Create corresponding output subdirectory structure\n", 613 | " output_subfolder = os.path.join(output_folder, os.path.relpath(root, input_folder))\n", 614 | " os.makedirs(output_subfolder, exist_ok=True)\n", 615 | " \n", 616 | " for file_name in files:\n", 617 | " if file_name.endswith('.wav'): # Assuming all files are in WAV format\n", 618 | " # Construct the full paths for input and output files\n", 619 | " input_file_path = os.path.join(root, file_name)\n", 620 | " output_file_path = os.path.join(output_subfolder, f\"{os.path.splitext(file_name)[0]}_rirs_aug.wav\")\n", 621 | " \n", 622 | " # Load stuttered speech sample (ensure duration is 3 seconds)\n", 623 | " audio, sr = librosa.load(input_file_path, sr=None, duration=3.0)\n", 624 | " \n", 625 | " # Randomly select an RIR file from the folder\n", 626 | " rirs_files = os.listdir(rirs_folder)\n", 627 | " selected_rirs_file = np.random.choice(rirs_files)\n", 628 | " rirs_file = os.path.join(rirs_folder, selected_rirs_file)\n", 629 | " \n", 630 | " # Load selected RIR\n", 631 | " rirs, sr_rirs = librosa.load(rirs_file, sr=None)\n", 632 | " \n", 633 | " # Ensure RIRs is mono\n", 634 | " if len(rirs.shape) > 1:\n", 635 | " rirs = rirs[:, 0]\n", 636 | " \n", 637 | " # Convolve audio with RIRs\n", 638 | " augmented_audio = np.convolve(audio, rirs, mode='same')\n", 639 | " \n", 640 | " # Write augmented audio to the specified output path\n", 641 | " sf.write(output_file_path, augmented_audio, sr)" 642 | ] 643 | }, 644 | { 645 | "cell_type": "code", 646 | "execution_count": 15, 647 | "id": "77b7f524", 648 | "metadata": {}, 649 | "outputs": [], 650 | "source": [ 651 | "input_folder = \"D:\\\\SEM 4\\\\Project\\\\sep28k-final\"\n", 652 | "output_folder_music = \"D:\\\\SEM 4\\\\Project\\\\augmented\\\\music\"\n", 653 | "output_folder_noise = \"D:\\\\SEM 4\\\\Project\\\\augmented\\\\noise\"\n", 654 | "output_folder_babble = \"D:\\\\SEM 4\\\\Project\\\\augmented\\\\babble\"\n", 655 | "output_folder_rirs = \"D:\\\\SEM 4\\\\Project\\\\augmented\\\\rirs\"\n", 656 | "music_folder = \"D:\\\\SEM 4\\\\Project\\\\musan\\\\music\"\n", 657 | "noise_folder=\"D:\\\\SEM 4\\\\Project\\\\musan\\\\noise\"\n", 658 | "speech_folder=\"D:\\\\SEM 4\\\\Project\\\\musan\\\\speech\"\n", 659 | "rirs_folder = \"D:\\\\SEM 4\\\\Project\\\\musan\\\\rirs\"" 660 | ] 661 | }, 662 | { 663 | "cell_type": "code", 664 | "execution_count": 20, 665 | "id": "993e06bb", 666 | "metadata": {}, 667 | "outputs": [], 668 | "source": [ 669 | "augment_all_files_music(input_folder, output_folder_music, music_folder)" 670 | ] 671 | }, 672 | { 673 | "cell_type": "code", 674 | "execution_count": 21, 675 | "id": "55f28917", 676 | "metadata": {}, 677 | "outputs": [], 678 | "source": [ 679 | "augment_all_files_noise(input_folder, output_folder_noise, noise_folder)" 680 | ] 681 | }, 682 | { 683 | "cell_type": "code", 684 | "execution_count": 22, 685 | "id": "83a0d505", 686 | "metadata": {}, 687 | "outputs": [], 688 | "source": [ 689 | "augment_all_files_babble(input_folder,output_folder_babble,speech_folder)" 690 | ] 691 | }, 692 | { 693 | "cell_type": "code", 694 | "execution_count": 16, 695 | "id": "9f330998", 696 | "metadata": {}, 697 | "outputs": [], 698 | "source": [ 699 | "augment_all_files_rirs(input_folder,output_folder_rirs,rirs_folder)" 700 | ] 701 | }, 702 | { 703 | "cell_type": "code", 704 | "execution_count": 18, 705 | "id": "873486ba", 706 | "metadata": {}, 707 | "outputs": [], 708 | "source": [ 709 | "def count_wav_files(folder):\n", 710 | " count = 0\n", 711 | " for root, _, files in os.walk(folder):\n", 712 | " for file_name in files:\n", 713 | " if file_name.endswith('.wav'):\n", 714 | " count += 1\n", 715 | " return count" 716 | ] 717 | }, 718 | { 719 | "cell_type": "code", 720 | "execution_count": 42, 721 | "id": "2ec0acde", 722 | "metadata": {}, 723 | "outputs": [ 724 | { 725 | "name": "stdout", 726 | "output_type": "stream", 727 | "text": [ 728 | "Number of WAV files: 20091\n" 729 | ] 730 | } 731 | ], 732 | "source": [ 733 | "number_of_files = count_wav_files(output_folder_music)\n", 734 | "print(\"Number of WAV files:\", number_of_files)" 735 | ] 736 | }, 737 | { 738 | "cell_type": "code", 739 | "execution_count": 20, 740 | "id": "1631e19f", 741 | "metadata": {}, 742 | "outputs": [ 743 | { 744 | "name": "stdout", 745 | "output_type": "stream", 746 | "text": [ 747 | "Number of WAV files: 21836\n" 748 | ] 749 | } 750 | ], 751 | "source": [ 752 | "number_of_files = count_wav_files(output_folder_noise)\n", 753 | "print(\"Number of WAV files:\", number_of_files)" 754 | ] 755 | }, 756 | { 757 | "cell_type": "code", 758 | "execution_count": 21, 759 | "id": "b873e174", 760 | "metadata": {}, 761 | "outputs": [ 762 | { 763 | "name": "stdout", 764 | "output_type": "stream", 765 | "text": [ 766 | "Number of WAV files: 21836\n" 767 | ] 768 | } 769 | ], 770 | "source": [ 771 | "number_of_files = count_wav_files(output_folder_babble)\n", 772 | "print(\"Number of WAV files:\", number_of_files)" 773 | ] 774 | }, 775 | { 776 | "cell_type": "code", 777 | "execution_count": 19, 778 | "id": "f0315eb9", 779 | "metadata": {}, 780 | "outputs": [ 781 | { 782 | "name": "stdout", 783 | "output_type": "stream", 784 | "text": [ 785 | "Number of WAV files: 21836\n" 786 | ] 787 | } 788 | ], 789 | "source": [ 790 | "number_of_files = count_wav_files(output_folder_rirs)\n", 791 | "print(\"Number of WAV files:\", number_of_files) " 792 | ] 793 | }, 794 | { 795 | "cell_type": "code", 796 | "execution_count": null, 797 | "id": "63af372c", 798 | "metadata": {}, 799 | "outputs": [], 800 | "source": [] 801 | } 802 | ], 803 | "metadata": { 804 | "kernelspec": { 805 | "display_name": "Python 3 (ipykernel)", 806 | "language": "python", 807 | "name": "python3" 808 | }, 809 | "language_info": { 810 | "codemirror_mode": { 811 | "name": "ipython", 812 | "version": 3 813 | }, 814 | "file_extension": ".py", 815 | "mimetype": "text/x-python", 816 | "name": "python", 817 | "nbconvert_exporter": "python", 818 | "pygments_lexer": "ipython3", 819 | "version": "3.11.3" 820 | } 821 | }, 822 | "nbformat": 4, 823 | "nbformat_minor": 5 824 | } 825 | -------------------------------------------------------------------------------- /WordRep - Deep Learning.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "d4512109-72c3-4639-9f84-c4ded9559659", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import numpy as np\n", 11 | "import os\n", 12 | "import librosa\n", 13 | "import librosa.display\n", 14 | "import pandas as pd\n", 15 | "import matplotlib.pyplot as plt\n", 16 | "import sklearn.preprocessing\n", 17 | "from scipy.signal import lfilter\n", 18 | "from joblib import Parallel, delayed\n", 19 | "from sklearn.model_selection import train_test_split\n", 20 | "from sklearn.ensemble import RandomForestClassifier\n", 21 | "from sklearn.model_selection import GridSearchCV\n", 22 | "import parselmouth\n", 23 | "from sklearn.decomposition import PCA" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 2, 29 | "id": "e26e9fbd-fd8d-4a1b-8dc3-d9a68e8ffbb8", 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "df = pd.read_csv(r\"C:\\Users\\jmdgo\\Downloads\\binary_labeled_dataset.csv\")" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 3, 39 | "id": "82127c18-f3c7-4c59-91e1-96ea6e2d7acf", 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "clip_path = r\"C:\\Users\\jmdgo\\Downloads\\extracted_clips\\extracted_clips\"" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 4, 49 | "id": "c8e02825-5606-4530-ae17-0e5eea811e28", 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [ 53 | "audio_paths = []\n", 54 | "for folder in os.listdir(clip_path):\n", 55 | " folder_path = os.path.join(clip_path, folder)\n", 56 | " #episode_paths = []\n", 57 | " for episode in os.listdir(folder_path):\n", 58 | " episode_path = os.path.join(folder_path, episode)\n", 59 | " for wav in os.listdir(episode_path):\n", 60 | " wav_path = os.path.join(episode_path, wav)\n", 61 | " audio_paths.append(wav_path)" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 5, 67 | "id": "cded2107-5a65-41cc-80fd-7862a35a912a", 68 | "metadata": {}, 69 | "outputs": [], 70 | "source": [ 71 | "df['audio_path'] = ['default'] * len(df)" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 6, 77 | "id": "49178e08-ce96-4858-97fa-387a1c7106f0", 78 | "metadata": {}, 79 | "outputs": [], 80 | "source": [ 81 | "for path in audio_paths:\n", 82 | " filename = os.path.basename(path)\n", 83 | " parts = filename.split('_')\n", 84 | " podcast_name = parts[0]\n", 85 | " episode_number = int(parts[1])\n", 86 | " clip_number = int(parts[2].split('.')[0]) \n", 87 | "\n", 88 | " match_row = df[(df['Show'] == podcast_name) & (df['EpId'] == episode_number) & (df['ClipId'] == clip_number)]\n", 89 | " if not match_row.empty:\n", 90 | " match_index = match_row.index[0]\n", 91 | " df.at[match_index, 'audio_path'] = path" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 7, 97 | "id": "1a039cfe-617b-4fab-9f73-9cf73262b00a", 98 | "metadata": {}, 99 | "outputs": [ 100 | { 101 | "name": "stdout", 102 | "output_type": "stream", 103 | "text": [ 104 | "0 60.677123\n", 105 | "1 39.322877\n", 106 | "Name: Stutter, dtype: float64\n" 107 | ] 108 | } 109 | ], 110 | "source": [ 111 | "value_counts = df['Stutter'].value_counts()\n", 112 | "total_rows = df.shape[0]\n", 113 | "\n", 114 | "percentage_per_class = (value_counts / total_rows) * 100\n", 115 | "\n", 116 | "print(percentage_per_class)" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": 9, 122 | "id": "99d679ea-5661-4f3d-912c-f8bcec07633e", 123 | "metadata": {}, 124 | "outputs": [], 125 | "source": [ 126 | "def extract_mfcc(audio_file, num_mfcc=40):\n", 127 | " audio, sr = librosa.load(audio_file, sr=None)\n", 128 | " mfccs = librosa.feature.mfcc(y=audio, sr=sr, n_mfcc=num_mfcc)\n", 129 | " mfccs_flat = mfccs.T.flatten()\n", 130 | " return mfccs_flat\n", 131 | "\n", 132 | "def extract_zcr(audio_file, frame_length=2048, hop_length=512):\n", 133 | " audio, sr = librosa.load(audio_file, sr=None)\n", 134 | " zcr = librosa.feature.zero_crossing_rate(audio, frame_length=frame_length, hop_length=hop_length)\n", 135 | " return zcr.flatten()\n", 136 | "\n", 137 | "def extract_jitter_shimmer(audio_file):\n", 138 | " sound = parselmouth.Sound(audio_file)\n", 139 | " pitch = sound.to_pitch()\n", 140 | " pulses = parselmouth.praat.call([sound, pitch], \"To PointProcess (cc)\")\n", 141 | " jitter = parselmouth.praat.call(pulses, \"Get jitter (local)\", 0, 0, 0.0001, 0.02, 1.3)\n", 142 | " shimmer = parselmouth.praat.call([sound, pulses], \"Get shimmer (local)\", 0, 0, 0.0001, 0.02, 1.3, 1.6)\n", 143 | " return jitter, shimmer\n", 144 | "\n", 145 | "def extract_all_features(audio_file, num_mfcc=40, frame_length=2048, hop_length=512):\n", 146 | " mfcc_features = extract_mfcc(audio_file, num_mfcc)\n", 147 | " zcr_features = extract_zcr(audio_file, frame_length, hop_length)\n", 148 | " jitter, shimmer = extract_jitter_shimmer(audio_file)\n", 149 | " return np.concatenate([mfcc_features, zcr_features, [jitter, shimmer]])" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": 10, 155 | "id": "1986acfd-999f-4b6d-a5ef-83c4283fa41e", 156 | "metadata": {}, 157 | "outputs": [], 158 | "source": [ 159 | "audio_files = df['audio_path'] \n", 160 | "labels = df['WordRep']" 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": 11, 166 | "id": "f18f0517-edf7-48ac-beb9-455c724add88", 167 | "metadata": {}, 168 | "outputs": [], 169 | "source": [ 170 | "df_WordRep = df[['audio_path', 'WordRep']]" 171 | ] 172 | }, 173 | { 174 | "cell_type": "code", 175 | "execution_count": 12, 176 | "id": "6a98512a-db92-42d3-be8d-7faf74367b19", 177 | "metadata": {}, 178 | "outputs": [], 179 | "source": [ 180 | "df_WordRep_1 = df_WordRep[df_WordRep['WordRep']==1]" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": 13, 186 | "id": "4f4f7e7f-0148-4642-be12-1366c45aa674", 187 | "metadata": {}, 188 | "outputs": [], 189 | "source": [ 190 | "df_WordRep_0 = df[(df['Prolongation']==0) & \n", 191 | " (df['Block']==0) & \n", 192 | " (df['Interjection']==0) & \n", 193 | " (df['WordRep']==0) & \n", 194 | " (df['SoundRep']==0) &\n", 195 | " (df['NoStutteredWords']==1)]\n" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": 14, 201 | "id": "58215a72-ffed-45fc-a98d-c83c3d79b42a", 202 | "metadata": {}, 203 | "outputs": [ 204 | { 205 | "data": { 206 | "text/plain": [ 207 | "(2358, 2)" 208 | ] 209 | }, 210 | "execution_count": 14, 211 | "metadata": {}, 212 | "output_type": "execute_result" 213 | } 214 | ], 215 | "source": [ 216 | "df_WordRep_1.shape" 217 | ] 218 | }, 219 | { 220 | "cell_type": "code", 221 | "execution_count": 16, 222 | "id": "77dfe2ad-b0ed-4291-93b1-c79b1719201c", 223 | "metadata": {}, 224 | "outputs": [], 225 | "source": [ 226 | "df_WordRep_0_sampled = df_WordRep_0.sample(2358)" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": 17, 232 | "id": "695a90ae-1f44-43a7-bdd2-5bdde9340ee5", 233 | "metadata": {}, 234 | "outputs": [ 235 | { 236 | "data": { 237 | "text/plain": [ 238 | "(2358, 17)" 239 | ] 240 | }, 241 | "execution_count": 17, 242 | "metadata": {}, 243 | "output_type": "execute_result" 244 | } 245 | ], 246 | "source": [ 247 | "df_WordRep_0_sampled.shape" 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "execution_count": 18, 253 | "id": "ce16530e-e3c0-4322-a556-bc0eadab17ba", 254 | "metadata": {}, 255 | "outputs": [], 256 | "source": [ 257 | "df_WordRep_data = pd.concat([df_WordRep_0_sampled, df_WordRep_1], ignore_index=True, axis=0)" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": 19, 263 | "id": "e76bd344-df9c-4b5c-a4d6-7992f5e2aece", 264 | "metadata": {}, 265 | "outputs": [ 266 | { 267 | "data": { 268 | "text/plain": [ 269 | "(4716, 17)" 270 | ] 271 | }, 272 | "execution_count": 19, 273 | "metadata": {}, 274 | "output_type": "execute_result" 275 | } 276 | ], 277 | "source": [ 278 | "df_WordRep_data.shape" 279 | ] 280 | }, 281 | { 282 | "cell_type": "code", 283 | "execution_count": 20, 284 | "id": "91a4fd62-172b-416e-8c72-b2b942c8dc22", 285 | "metadata": {}, 286 | "outputs": [ 287 | { 288 | "data": { 289 | "text/html": [ 290 | "
\n", 291 | "\n", 304 | "\n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | "
audio_pathWordRep
0C:\\Users\\jmdgo\\Downloads\\extracted_clips\\extra...0
1C:\\Users\\jmdgo\\Downloads\\extracted_clips\\extra...0
\n", 325 | "
" 326 | ], 327 | "text/plain": [ 328 | " audio_path WordRep\n", 329 | "0 C:\\Users\\jmdgo\\Downloads\\extracted_clips\\extra... 0\n", 330 | "1 C:\\Users\\jmdgo\\Downloads\\extracted_clips\\extra... 0" 331 | ] 332 | }, 333 | "execution_count": 20, 334 | "metadata": {}, 335 | "output_type": "execute_result" 336 | } 337 | ], 338 | "source": [ 339 | "df_WordRep.head(2)" 340 | ] 341 | }, 342 | { 343 | "cell_type": "code", 344 | "execution_count": 21, 345 | "id": "659f2a48-a4ec-4b22-ab53-0439f4bea6a3", 346 | "metadata": {}, 347 | "outputs": [ 348 | { 349 | "name": "stdout", 350 | "output_type": "stream", 351 | "text": [ 352 | "0 50.0\n", 353 | "1 50.0\n", 354 | "Name: WordRep, dtype: float64\n" 355 | ] 356 | } 357 | ], 358 | "source": [ 359 | "value_counts = df_WordRep_data['WordRep'].value_counts()\n", 360 | "total_rows = df_WordRep_data.shape[0]\n", 361 | "\n", 362 | "percentage_per_class = (value_counts / total_rows) * 100\n", 363 | "\n", 364 | "print(percentage_per_class)" 365 | ] 366 | }, 367 | { 368 | "cell_type": "code", 369 | "execution_count": 22, 370 | "id": "6ac7b6a0-0b0b-4eb1-92b2-6d4b834e12aa", 371 | "metadata": {}, 372 | "outputs": [], 373 | "source": [ 374 | "X = np.array(df_WordRep_data['audio_path'])\n", 375 | "y = np.array(df_WordRep_data['WordRep'])" 376 | ] 377 | }, 378 | { 379 | "cell_type": "code", 380 | "execution_count": 23, 381 | "id": "02ad3a9a-237b-4e62-8d65-506c7ad0472f", 382 | "metadata": {}, 383 | "outputs": [], 384 | "source": [ 385 | "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=40, stratify = y)" 386 | ] 387 | }, 388 | { 389 | "cell_type": "code", 390 | "execution_count": 24, 391 | "id": "30457ffd-8255-4ebc-974d-38f33db7afcb", 392 | "metadata": {}, 393 | "outputs": [], 394 | "source": [ 395 | "mfcc_features_train = Parallel(n_jobs=-1)(delayed(extract_mfcc)(audio_file) for audio_file in X_train)\n", 396 | "mfcc_features_test = Parallel(n_jobs=-1)(delayed(extract_mfcc)(audio_file) for audio_file in X_test)\n", 397 | "zcr_features_train = Parallel(n_jobs=-1)(delayed(extract_zcr)(audio_file) for audio_file in X_train)\n", 398 | "zcr_features_test = Parallel(n_jobs=-1)(delayed(extract_zcr)(audio_file) for audio_file in X_test)\n", 399 | "\n", 400 | "jitter_shimmer_train = Parallel(n_jobs=-1)(delayed(extract_jitter_shimmer)(audio_file) for audio_file in X_train)\n", 401 | "jitter_shimmer_test = Parallel(n_jobs=-1)(delayed(extract_jitter_shimmer)(audio_file) for audio_file in X_test)\n", 402 | "\n", 403 | "jitter_train, shimmer_train = zip(*jitter_shimmer_train)\n", 404 | "jitter_test, shimmer_test = zip(*jitter_shimmer_test)" 405 | ] 406 | }, 407 | { 408 | "cell_type": "markdown", 409 | "id": "6973590c-5fc5-40f4-a7fb-10d05dd9df47", 410 | "metadata": {}, 411 | "source": [ 412 | "zcr_features_train = Parallel(n_jobs=-1)(delayed(extract_zcr)(audio_file) for audio_file in X_train)\n", 413 | "zcr_features_test = Parallel(n_jobs=-1)(delayed(extract_zcr)(audio_file) for audio_file in X_test)" 414 | ] 415 | }, 416 | { 417 | "cell_type": "markdown", 418 | "id": "660938cb-e39a-450a-9061-6c24c02bd983", 419 | "metadata": {}, 420 | "source": [ 421 | "features_train = np.array([np.hstack((mfcc, zcr)) for mfcc, zcr in zip(mfcc_features_train, zcr_features_train)])\n", 422 | "features_test = np.array([np.hstack((mfcc, zcr)) for mfcc, zcr in zip(mfcc_features_test, zcr_features_test)])" 423 | ] 424 | }, 425 | { 426 | "cell_type": "code", 427 | "execution_count": 25, 428 | "id": "ef378e5f", 429 | "metadata": {}, 430 | "outputs": [ 431 | { 432 | "name": "stdout", 433 | "output_type": "stream", 434 | "text": [ 435 | "(3301, 3856)\n", 436 | "(1415, 3856)\n" 437 | ] 438 | } 439 | ], 440 | "source": [ 441 | "merged_features_train = np.column_stack((mfcc_features_train, zcr_features_train, jitter_train, shimmer_train))\n", 442 | "merged_features_test = np.column_stack((mfcc_features_test, zcr_features_test, jitter_test, shimmer_test))\n", 443 | "\n", 444 | "print(merged_features_train.shape)\n", 445 | "print(merged_features_test.shape)" 446 | ] 447 | }, 448 | { 449 | "cell_type": "code", 450 | "execution_count": 26, 451 | "id": "edabd8ce", 452 | "metadata": {}, 453 | "outputs": [ 454 | { 455 | "data": { 456 | "text/plain": [ 457 | "((3301,), (1415,), (3301,), (1415,))" 458 | ] 459 | }, 460 | "execution_count": 26, 461 | "metadata": {}, 462 | "output_type": "execute_result" 463 | } 464 | ], 465 | "source": [ 466 | "X_train.shape,X_test.shape,y_train.shape,y_test.shape" 467 | ] 468 | }, 469 | { 470 | "cell_type": "code", 471 | "execution_count": 27, 472 | "id": "b0716fea", 473 | "metadata": {}, 474 | "outputs": [ 475 | { 476 | "name": "stdout", 477 | "output_type": "stream", 478 | "text": [ 479 | "NaN values found in training data at indices: [[ 96 3854]\n", 480 | " [ 96 3855]\n", 481 | " [1100 3855]\n", 482 | " [1496 3854]\n", 483 | " [1496 3855]\n", 484 | " [2520 3854]\n", 485 | " [2520 3855]]\n", 486 | "NaN values found in testing data at indices: [[ 589 3854]\n", 487 | " [ 589 3855]\n", 488 | " [ 614 3854]\n", 489 | " [ 614 3855]]\n" 490 | ] 491 | } 492 | ], 493 | "source": [ 494 | "nan_indices_train = np.argwhere(np.isnan(merged_features_train))\n", 495 | "if len(nan_indices_train) > 0:\n", 496 | " print(\"NaN values found in training data at indices:\", nan_indices_train)\n", 497 | "else:\n", 498 | " print(\"No NaN values found in training data\")\n", 499 | "\n", 500 | "# Check for NaN values in testing data\n", 501 | "nan_indices_test = np.argwhere(np.isnan(merged_features_test))\n", 502 | "if len(nan_indices_test) > 0:\n", 503 | " print(\"NaN values found in testing data at indices:\", nan_indices_test)\n", 504 | "else:\n", 505 | " print(\"No NaN values found in testing data\")" 506 | ] 507 | }, 508 | { 509 | "cell_type": "code", 510 | "execution_count": 28, 511 | "id": "d47130de", 512 | "metadata": {}, 513 | "outputs": [ 514 | { 515 | "name": "stdout", 516 | "output_type": "stream", 517 | "text": [ 518 | "No NaN values found in imputed training data\n", 519 | "No NaN values found in imputed testing data\n" 520 | ] 521 | } 522 | ], 523 | "source": [ 524 | "from sklearn.impute import KNNImputer\n", 525 | "# KNN imputation\n", 526 | "imputer = KNNImputer(n_neighbors=5) # You can adjust the number of neighbors as needed\n", 527 | "\n", 528 | "# Fit imputer on training data and transform both training and testing data\n", 529 | "merged_features_train = imputer.fit_transform(merged_features_train)\n", 530 | "merged_features_test = imputer.transform(merged_features_test)\n", 531 | "\n", 532 | "# Check if any NaN values remain after imputation\n", 533 | "nan_indices_train = np.argwhere(np.isnan(merged_features_train))\n", 534 | "if len(nan_indices_train) > 0:\n", 535 | " print(\"NaN values still present in imputed training data at indices:\", nan_indices_train)\n", 536 | "else:\n", 537 | " print(\"No NaN values found in imputed training data\")\n", 538 | "\n", 539 | "nan_indices_test = np.argwhere(np.isnan(merged_features_test))\n", 540 | "if len(nan_indices_test) > 0:\n", 541 | " print(\"NaN values still present in imputed testing data at indices:\", nan_indices_test)\n", 542 | "else:\n", 543 | " print(\"No NaN values found in imputed testing data\")\n" 544 | ] 545 | }, 546 | { 547 | "cell_type": "code", 548 | "execution_count": 30, 549 | "id": "ab2ae65f", 550 | "metadata": {}, 551 | "outputs": [ 552 | { 553 | "name": "stdout", 554 | "output_type": "stream", 555 | "text": [ 556 | "Explained variance ratio: [0.24778653 0.15632687 0.04659932 0.03814196 0.03333837 0.0299441\n", 557 | " 0.0278395 0.01992707 0.01829503 0.01710236 0.01471269 0.01259337\n", 558 | " 0.01109808 0.01105278 0.00942105 0.00850567 0.0083739 0.00720376\n", 559 | " 0.00638069 0.006122 0.00581438 0.0056173 0.00542596 0.00520031\n", 560 | " 0.00464309 0.00440965 0.00424653 0.00408088 0.00395583 0.00368943\n", 561 | " 0.00366224 0.00354939 0.00344957 0.00311403 0.00306417 0.00293423\n", 562 | " 0.00285715 0.00275122 0.00269917 0.00259841 0.00254493 0.00249555\n", 563 | " 0.00235417 0.00230372 0.00229554 0.00220197 0.00213064 0.00209418\n", 564 | " 0.0020142 0.00196921]\n" 565 | ] 566 | } 567 | ], 568 | "source": [ 569 | "from sklearn.decomposition import PCA\n", 570 | "\n", 571 | "# Assuming merged_features_train and merged_features_test are your feature arrays\n", 572 | "\n", 573 | "# Merge the training and testing data\n", 574 | "merged_data = np.concatenate((merged_features_train, merged_features_test), axis=0)\n", 575 | "\n", 576 | "# Apply PCA\n", 577 | "pca = PCA(n_components=50) # You can specify the number of principal components as needed\n", 578 | "transformed_data = pca.fit_transform(merged_data)\n", 579 | "\n", 580 | "# Print the explained variance ratio\n", 581 | "print(\"Explained variance ratio:\", pca.explained_variance_ratio_)\n" 582 | ] 583 | }, 584 | { 585 | "cell_type": "code", 586 | "execution_count": 31, 587 | "id": "3f94b2af-6ef7-4b4c-bb18-f970a4e39fda", 588 | "metadata": {}, 589 | "outputs": [ 590 | { 591 | "name": "stdout", 592 | "output_type": "stream", 593 | "text": [ 594 | "Distribution of 0s and 1s in y_train:\n", 595 | "1 1651\n", 596 | "0 1650\n", 597 | "dtype: int64\n", 598 | "\n", 599 | "Distribution of 0s and 1s in y_test:\n", 600 | "0 708\n", 601 | "1 707\n", 602 | "dtype: int64\n" 603 | ] 604 | } 605 | ], 606 | "source": [ 607 | "y_train_series = pd.Series(y_train)\n", 608 | "y_test_series = pd.Series(y_test)\n", 609 | "\n", 610 | "# Count the occurrences of each unique value in y_train\n", 611 | "train_distribution = y_train_series.value_counts()\n", 612 | "\n", 613 | "# Count the occurrences of each unique value in y_test\n", 614 | "test_distribution = y_test_series.value_counts()\n", 615 | "\n", 616 | "print(\"Distribution of 0s and 1s in y_train:\")\n", 617 | "print(train_distribution)\n", 618 | "\n", 619 | "print(\"\\nDistribution of 0s and 1s in y_test:\")\n", 620 | "print(test_distribution)" 621 | ] 622 | }, 623 | { 624 | "cell_type": "code", 625 | "execution_count": 32, 626 | "id": "890da51e", 627 | "metadata": {}, 628 | "outputs": [ 629 | { 630 | "name": "stdout", 631 | "output_type": "stream", 632 | "text": [ 633 | "Epoch 1/10\n", 634 | "104/104 [==============================] - 10s 93ms/step - loss: 12.1015 - accuracy: 0.5338 - val_loss: 0.7845 - val_accuracy: 0.5845\n", 635 | "Epoch 2/10\n", 636 | "104/104 [==============================] - 10s 92ms/step - loss: 0.6080 - accuracy: 0.6871 - val_loss: 0.6952 - val_accuracy: 0.6092\n", 637 | "Epoch 3/10\n", 638 | "104/104 [==============================] - 9s 91ms/step - loss: 0.4433 - accuracy: 0.8207 - val_loss: 0.7501 - val_accuracy: 0.6106\n", 639 | "Epoch 4/10\n", 640 | "104/104 [==============================] - 10s 92ms/step - loss: 0.2989 - accuracy: 0.9006 - val_loss: 0.8258 - val_accuracy: 0.5951\n", 641 | "Epoch 5/10\n", 642 | "104/104 [==============================] - 10s 92ms/step - loss: 0.1583 - accuracy: 0.9621 - val_loss: 0.9792 - val_accuracy: 0.5816\n", 643 | "Epoch 6/10\n", 644 | "104/104 [==============================] - 10s 95ms/step - loss: 0.0864 - accuracy: 0.9870 - val_loss: 1.1257 - val_accuracy: 0.5837\n", 645 | "Epoch 7/10\n", 646 | "104/104 [==============================] - 10s 94ms/step - loss: 0.0430 - accuracy: 0.9973 - val_loss: 1.2844 - val_accuracy: 0.5830\n", 647 | "Epoch 8/10\n", 648 | "104/104 [==============================] - 10s 93ms/step - loss: 0.0186 - accuracy: 0.9994 - val_loss: 1.4938 - val_accuracy: 0.5682\n", 649 | "Epoch 9/10\n", 650 | "104/104 [==============================] - 10s 92ms/step - loss: 0.0094 - accuracy: 1.0000 - val_loss: 1.5207 - val_accuracy: 0.5795\n", 651 | "Epoch 10/10\n", 652 | "104/104 [==============================] - 10s 93ms/step - loss: 0.0049 - accuracy: 1.0000 - val_loss: 1.6116 - val_accuracy: 0.5788\n" 653 | ] 654 | }, 655 | { 656 | "data": { 657 | "text/plain": [ 658 | "" 659 | ] 660 | }, 661 | "execution_count": 32, 662 | "metadata": {}, 663 | "output_type": "execute_result" 664 | } 665 | ], 666 | "source": [ 667 | "import numpy as np\n", 668 | "from sklearn.model_selection import train_test_split\n", 669 | "from tensorflow.keras.models import Sequential\n", 670 | "from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense\n", 671 | "from tensorflow.keras.utils import to_categorical\n", 672 | "\n", 673 | "X_train = np.array(merged_features_train)\n", 674 | "X_test = np.array(merged_features_test)\n", 675 | "y_train = np.array(y_train)\n", 676 | "y_test = np.array(y_test)\n", 677 | "\n", 678 | "# Convert labels to categorical\n", 679 | "y_train_categorical = to_categorical(y_train, num_classes=2)\n", 680 | "y_test_categorical = to_categorical(y_test, num_classes=2)\n", 681 | "\n", 682 | "# Reshape features for Conv1D input shape\n", 683 | "X_train = X_train.reshape(X_train.shape[0], X_train.shape[1], 1)\n", 684 | "X_test = X_test.reshape(X_test.shape[0], X_test.shape[1], 1)\n", 685 | "\n", 686 | "# Define the CNN model\n", 687 | "model = Sequential()\n", 688 | "model.add(Conv1D(32, 3, activation='relu', input_shape=(X_train.shape[1], 1)))\n", 689 | "model.add(MaxPooling1D(pool_size=2))\n", 690 | "model.add(Conv1D(64, 3, activation='relu'))\n", 691 | "model.add(MaxPooling1D(pool_size=2))\n", 692 | "model.add(Flatten())\n", 693 | "model.add(Dense(128, activation='relu'))\n", 694 | "model.add(Dense(2, activation='sigmoid')) # Output layer with sigmoid activation for binary classification\n", 695 | "\n", 696 | "# Compile the model\n", 697 | "model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])\n", 698 | "\n", 699 | "# Train the model\n", 700 | "model.fit(X_train, y_train_categorical, epochs=10, batch_size=32, validation_data=(X_test, y_test_categorical))\n" 701 | ] 702 | }, 703 | { 704 | "cell_type": "code", 705 | "execution_count": 37, 706 | "id": "ed530069", 707 | "metadata": {}, 708 | "outputs": [ 709 | { 710 | "name": "stdout", 711 | "output_type": "stream", 712 | "text": [ 713 | "Epoch 1/10\n", 714 | "104/104 [==============================] - 11s 95ms/step - loss: 16.1136 - accuracy: 0.5183 - val_loss: 4.1389 - val_accuracy: 0.4996\n", 715 | "Epoch 2/10\n", 716 | "104/104 [==============================] - 10s 97ms/step - loss: 1.1178 - accuracy: 0.6122 - val_loss: 0.7899 - val_accuracy: 0.5633\n", 717 | "Epoch 3/10\n", 718 | "104/104 [==============================] - 10s 92ms/step - loss: 0.4696 - accuracy: 0.7776 - val_loss: 0.7654 - val_accuracy: 0.5753\n", 719 | "Epoch 4/10\n", 720 | "104/104 [==============================] - 10s 92ms/step - loss: 0.3207 - accuracy: 0.8812 - val_loss: 0.8578 - val_accuracy: 0.5682\n", 721 | "Epoch 5/10\n", 722 | "104/104 [==============================] - 10s 95ms/step - loss: 0.2096 - accuracy: 0.9400 - val_loss: 1.1416 - val_accuracy: 0.5576\n", 723 | "Epoch 6/10\n", 724 | "104/104 [==============================] - 10s 94ms/step - loss: 0.1408 - accuracy: 0.9670 - val_loss: 1.0305 - val_accuracy: 0.5625\n" 725 | ] 726 | } 727 | ], 728 | "source": [ 729 | "import numpy as np\n", 730 | "from sklearn.model_selection import train_test_split\n", 731 | "from tensorflow.keras.models import Sequential\n", 732 | "from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense\n", 733 | "from tensorflow.keras.utils import to_categorical\n", 734 | "\n", 735 | "# Assuming merged_features_train contains merged features for training data\n", 736 | "# Assuming merged_features_test contains merged features for test data\n", 737 | "# Assuming y_train contains labels for training data\n", 738 | "# Assuming y_test contains labels for test data\n", 739 | "\n", 740 | "# Convert lists to numpy arrays\n", 741 | "X_train = np.array(merged_features_train)\n", 742 | "X_test = np.array(merged_features_test)\n", 743 | "y_train = np.array(y_train)\n", 744 | "y_test = np.array(y_test)\n", 745 | "\n", 746 | "# Convert labels to categorical\n", 747 | "y_train_categorical = to_categorical(y_train, num_classes=2)\n", 748 | "y_test_categorical = to_categorical(y_test, num_classes=2)\n", 749 | "\n", 750 | "# Reshape features for Conv1D input shape\n", 751 | "X_train = X_train.reshape(X_train.shape[0], X_train.shape[1], 1)\n", 752 | "X_test = X_test.reshape(X_test.shape[0], X_test.shape[1], 1)\n", 753 | "\n", 754 | "# Define the CNN model\n", 755 | "model = Sequential()\n", 756 | "model.add(Conv1D(32, 3, activation='relu', input_shape=(X_train.shape[1], 1)))\n", 757 | "model.add(MaxPooling1D(pool_size=2))\n", 758 | "model.add(Conv1D(64, 3, activation='relu'))\n", 759 | "model.add(MaxPooling1D(pool_size=2))\n", 760 | "model.add(Flatten())\n", 761 | "model.add(Dense(128, activation='relu'))\n", 762 | "model.add(Dense(2, activation='sigmoid')) # Output layer with sigmoid activation for binary classification\n", 763 | "\n", 764 | "# Compile the model\n", 765 | "model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])\n", 766 | "\n", 767 | "from tensorflow.keras.callbacks import EarlyStopping\n", 768 | "\n", 769 | "# Define early stopping callback\n", 770 | "early_stopping = EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True)\n", 771 | "\n", 772 | "# Train the model with early stopping\n", 773 | "history = model.fit(X_train, y_train_categorical, epochs=10, batch_size=32, \n", 774 | " validation_data=(X_test, y_test_categorical), callbacks=[early_stopping])\n" 775 | ] 776 | }, 777 | { 778 | "cell_type": "code", 779 | "execution_count": 38, 780 | "id": "0d06238d", 781 | "metadata": {}, 782 | "outputs": [ 783 | { 784 | "name": "stdout", 785 | "output_type": "stream", 786 | "text": [ 787 | "dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])\n" 788 | ] 789 | }, 790 | { 791 | "data": { 792 | "image/png": "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+EpEyietuRFxcf379+fBBx8kPj6ebt26ERQUVCr7PXvumXvvvZdBgwadd5tmzZoV6zl3797N2rVrAahXr16h78+ePZthw4YVs9KLu9AMjs1mu+Bj/jlLc1bv3r1ZtWoVTz/9NNHR0VSqVAm73c4tt9xyWefpGThwIAsWLGDVqlU0bdqUb775hkceeQSrVb+ziijciLi4u+66i3//+9+sXr2a+fPnX3C7qKgofvrpJ9LT0wvM3uzYsSP/+2e/2u32/JmRs3bu3Fng+c4eSWWz2ejSpYtTXsvs2bPx8PDgv//9L25ubgW+t3LlSt577z0OHTpEzZo1qVu3Ln/++Se5ubl4eHic9/nq1q3L0qVLSUlJueDsTeXKlQE4efJkgfGzM1lFceLECWJiYhg3bhwvv/xy/vju3bsLbBcSEkJAQABbt2695HPecssthISEMHv2bNq1a8epU6e47777ilyTiCtTxBdxcZUqVWL69OmMHTuW7t27X3C7W2+9FZvNxpQpUwqMv/POO1gslvwjrs5+Pfdoq8mTJxe47+bmRs+ePfnyyy/P+2GdlJRU7Ncye/Zsrr/+evr06UOvXr0K3J5++mmA/MOge/bsSXJycqHXA+QfwdSzZ08Mw2DcuHEX3CYgIIDg4GBWrFhR4PvTpk0rct1ng5hxziH1575nVquVHj168L///S//UPTz1QTg7u5Ov379+OKLL5g1axZNmzYt9kyYiKvSzI1IBXChttA/de/enc6dO/PCCy9w4MABmjdvzo8//sjXX3/N448/nr/GJjo6mn79+jFt2jRSU1Pp0KEDMTEx7Nmzp9Bzvv766/zyyy+0a9eOBx98kEaNGpGSksKGDRv46aefSElJKfJr+PPPP9mzZw8jRow47/erV69Oy5YtmT17Ns8++ywDBw7ks88+Y9SoUaxZs4brr7+ezMxMfvrpJx555BHuvPNOOnfuzH333cd7773H7t2781tEv/32G507d87f19ChQ3n99dcZOnQorVu3ZsWKFezatavItQcEBNCxY0fefPNNcnNzqV69Oj/++CP79+8vtO348eP58ccfueGGGxg2bBgNGzbk2LFjLFiwgJUrVxZoKw4cOJD33nuPX375hTfeeKPI9Yi4PPMO1BKRkvDPQ8Ev5txDwQ3DMNLT040nnnjCiIiIMDw8PIx69eoZEydOzD8E+azTp08b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", 793 | "text/plain": [ 794 | "
" 795 | ] 796 | }, 797 | "metadata": {}, 798 | "output_type": "display_data" 799 | } 800 | ], 801 | "source": [ 802 | "import matplotlib.pyplot as plt\n", 803 | "# Print the keys of the history\n", 804 | "print(history.history.keys())\n", 805 | "\n", 806 | "# Summarize history for accuracy\n", 807 | "plt.plot(history.history['accuracy'])\n", 808 | "plt.plot(history.history['val_accuracy'])\n", 809 | "plt.title('Model Accuracy')\n", 810 | "plt.ylabel('Accuracy')\n", 811 | "plt.xlabel('Epoch')\n", 812 | "plt.legend(['Train', 'Validation'], loc='upper left')\n", 813 | "plt.show()" 814 | ] 815 | }, 816 | { 817 | "cell_type": "code", 818 | "execution_count": 39, 819 | "id": "387b3171", 820 | "metadata": {}, 821 | "outputs": [ 822 | { 823 | "name": "stdout", 824 | "output_type": "stream", 825 | "text": [ 826 | "Model saved successfully to: C:\\Users\\jmdgo\\Downloads\n" 827 | ] 828 | } 829 | ], 830 | "source": [ 831 | "model_file_path = r'C:\\Users\\jmdgo\\Downloads'\n", 832 | "model.save(\"WordRep_mzjs_model.h5\")\n", 833 | "print(\"Model saved successfully to:\", model_file_path)" 834 | ] 835 | } 836 | ], 837 | "metadata": { 838 | "kernelspec": { 839 | "display_name": "Python 3 (ipykernel)", 840 | "language": "python", 841 | "name": "python3" 842 | }, 843 | "language_info": { 844 | "codemirror_mode": { 845 | "name": "ipython", 846 | "version": 3 847 | }, 848 | "file_extension": ".py", 849 | "mimetype": "text/x-python", 850 | "name": "python", 851 | "nbconvert_exporter": "python", 852 | "pygments_lexer": "ipython3", 853 | "version": "3.11.4" 854 | } 855 | }, 856 | "nbformat": 4, 857 | "nbformat_minor": 5 858 | } 859 | -------------------------------------------------------------------------------- /SoundRep - Deep Learning.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "d4512109-72c3-4639-9f84-c4ded9559659", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import numpy as np\n", 11 | "import os\n", 12 | "import librosa\n", 13 | "import librosa.display\n", 14 | "import pandas as pd\n", 15 | "import matplotlib.pyplot as plt\n", 16 | "import sklearn.preprocessing\n", 17 | "from scipy.signal import lfilter\n", 18 | "from joblib import Parallel, delayed\n", 19 | "from sklearn.model_selection import train_test_split\n", 20 | "from sklearn.ensemble import RandomForestClassifier\n", 21 | "from sklearn.model_selection import GridSearchCV\n", 22 | "import parselmouth\n", 23 | "from sklearn.decomposition import PCA" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 2, 29 | "id": "e26e9fbd-fd8d-4a1b-8dc3-d9a68e8ffbb8", 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "df = pd.read_csv(r\"C:\\Users\\jmdgo\\Downloads\\binary_labeled_dataset.csv\")" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 3, 39 | "id": "82127c18-f3c7-4c59-91e1-96ea6e2d7acf", 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "clip_path = r\"C:\\Users\\jmdgo\\Downloads\\extracted_clips\\extracted_clips\"" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 4, 49 | "id": "c8e02825-5606-4530-ae17-0e5eea811e28", 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [ 53 | "audio_paths = []\n", 54 | "for folder in os.listdir(clip_path):\n", 55 | " folder_path = os.path.join(clip_path, folder)\n", 56 | " #episode_paths = []\n", 57 | " for episode in os.listdir(folder_path):\n", 58 | " episode_path = os.path.join(folder_path, episode)\n", 59 | " for wav in os.listdir(episode_path):\n", 60 | " wav_path = os.path.join(episode_path, wav)\n", 61 | " audio_paths.append(wav_path)" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 5, 67 | "id": "cded2107-5a65-41cc-80fd-7862a35a912a", 68 | "metadata": {}, 69 | "outputs": [], 70 | "source": [ 71 | "df['audio_path'] = ['default'] * len(df)" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 6, 77 | "id": "49178e08-ce96-4858-97fa-387a1c7106f0", 78 | "metadata": {}, 79 | "outputs": [], 80 | "source": [ 81 | "for path in audio_paths:\n", 82 | " filename = os.path.basename(path)\n", 83 | " parts = filename.split('_')\n", 84 | " podcast_name = parts[0]\n", 85 | " episode_number = int(parts[1])\n", 86 | " clip_number = int(parts[2].split('.')[0]) \n", 87 | "\n", 88 | " match_row = df[(df['Show'] == podcast_name) & (df['EpId'] == episode_number) & (df['ClipId'] == clip_number)]\n", 89 | " if not match_row.empty:\n", 90 | " match_index = match_row.index[0]\n", 91 | " df.at[match_index, 'audio_path'] = path" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 7, 97 | "id": "1a039cfe-617b-4fab-9f73-9cf73262b00a", 98 | "metadata": {}, 99 | "outputs": [ 100 | { 101 | "name": "stdout", 102 | "output_type": "stream", 103 | "text": [ 104 | "0 60.677123\n", 105 | "1 39.322877\n", 106 | "Name: Stutter, dtype: float64\n" 107 | ] 108 | } 109 | ], 110 | "source": [ 111 | "value_counts = df['Stutter'].value_counts()\n", 112 | "total_rows = df.shape[0]\n", 113 | "\n", 114 | "percentage_per_class = (value_counts / total_rows) * 100\n", 115 | "\n", 116 | "print(percentage_per_class)" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": 8, 122 | "id": "99d679ea-5661-4f3d-912c-f8bcec07633e", 123 | "metadata": {}, 124 | "outputs": [], 125 | "source": [ 126 | "def extract_mfcc(audio_file, num_mfcc=40):\n", 127 | " audio, sr = librosa.load(audio_file, sr=None)\n", 128 | " mfccs = librosa.feature.mfcc(y=audio, sr=sr, n_mfcc=num_mfcc)\n", 129 | " mfccs_flat = mfccs.T.flatten()\n", 130 | " return mfccs_flat\n", 131 | "\n", 132 | "def extract_zcr(audio_file, frame_length=2048, hop_length=512):\n", 133 | " audio, sr = librosa.load(audio_file, sr=None)\n", 134 | " zcr = librosa.feature.zero_crossing_rate(audio, frame_length=frame_length, hop_length=hop_length)\n", 135 | " return zcr.flatten()\n", 136 | "\n", 137 | "def extract_jitter_shimmer(audio_file):\n", 138 | " sound = parselmouth.Sound(audio_file)\n", 139 | " pitch = sound.to_pitch()\n", 140 | " pulses = parselmouth.praat.call([sound, pitch], \"To PointProcess (cc)\")\n", 141 | " jitter = parselmouth.praat.call(pulses, \"Get jitter (local)\", 0, 0, 0.0001, 0.02, 1.3)\n", 142 | " shimmer = parselmouth.praat.call([sound, pulses], \"Get shimmer (local)\", 0, 0, 0.0001, 0.02, 1.3, 1.6)\n", 143 | " return jitter, shimmer\n", 144 | "\n", 145 | "def extract_all_features(audio_file, num_mfcc=40, frame_length=2048, hop_length=512):\n", 146 | " mfcc_features = extract_mfcc(audio_file, num_mfcc)\n", 147 | " zcr_features = extract_zcr(audio_file, frame_length, hop_length)\n", 148 | " jitter, shimmer = extract_jitter_shimmer(audio_file)\n", 149 | " return np.concatenate([mfcc_features, zcr_features, [jitter, shimmer]])" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": 9, 155 | "id": "1986acfd-999f-4b6d-a5ef-83c4283fa41e", 156 | "metadata": {}, 157 | "outputs": [], 158 | "source": [ 159 | "audio_files = df['audio_path'] \n", 160 | "labels = df['SoundRep']" 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": 10, 166 | "id": "f18f0517-edf7-48ac-beb9-455c724add88", 167 | "metadata": {}, 168 | "outputs": [], 169 | "source": [ 170 | "df_SoundRep = df[['audio_path', 'SoundRep']]" 171 | ] 172 | }, 173 | { 174 | "cell_type": "code", 175 | "execution_count": 11, 176 | "id": "6a98512a-db92-42d3-be8d-7faf74367b19", 177 | "metadata": {}, 178 | "outputs": [], 179 | "source": [ 180 | "df_SoundRep_1 = df_SoundRep[df_SoundRep['SoundRep']==1]" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": 12, 186 | "id": "4f4f7e7f-0148-4642-be12-1366c45aa674", 187 | "metadata": {}, 188 | "outputs": [], 189 | "source": [ 190 | "df_SoundRep_0 = df[(df['Prolongation']==0) & \n", 191 | " (df['Block']==0) & \n", 192 | " (df['Interjection']==0) & \n", 193 | " (df['WordRep']==0) & \n", 194 | " (df['SoundRep']==0) &\n", 195 | " (df['NoStutteredWords']==1)]\n" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": 13, 201 | "id": "58215a72-ffed-45fc-a98d-c83c3d79b42a", 202 | "metadata": {}, 203 | "outputs": [ 204 | { 205 | "data": { 206 | "text/plain": [ 207 | "(1950, 2)" 208 | ] 209 | }, 210 | "execution_count": 13, 211 | "metadata": {}, 212 | "output_type": "execute_result" 213 | } 214 | ], 215 | "source": [ 216 | "df_SoundRep_1.shape" 217 | ] 218 | }, 219 | { 220 | "cell_type": "code", 221 | "execution_count": 15, 222 | "id": "77dfe2ad-b0ed-4291-93b1-c79b1719201c", 223 | "metadata": {}, 224 | "outputs": [], 225 | "source": [ 226 | "df_SoundRep_0_sampled = df_SoundRep_0.sample(1950)" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": 16, 232 | "id": "695a90ae-1f44-43a7-bdd2-5bdde9340ee5", 233 | "metadata": {}, 234 | "outputs": [ 235 | { 236 | "data": { 237 | "text/plain": [ 238 | "(1950, 17)" 239 | ] 240 | }, 241 | "execution_count": 16, 242 | "metadata": {}, 243 | "output_type": "execute_result" 244 | } 245 | ], 246 | "source": [ 247 | "df_SoundRep_0_sampled.shape" 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "execution_count": 17, 253 | "id": "ce16530e-e3c0-4322-a556-bc0eadab17ba", 254 | "metadata": {}, 255 | "outputs": [], 256 | "source": [ 257 | "df_SoundRep_data = pd.concat([df_SoundRep_0_sampled, df_SoundRep_1], ignore_index=True, axis=0)" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": 18, 263 | "id": "e76bd344-df9c-4b5c-a4d6-7992f5e2aece", 264 | "metadata": {}, 265 | "outputs": [ 266 | { 267 | "data": { 268 | "text/plain": [ 269 | "(3900, 17)" 270 | ] 271 | }, 272 | "execution_count": 18, 273 | "metadata": {}, 274 | "output_type": "execute_result" 275 | } 276 | ], 277 | "source": [ 278 | "df_SoundRep_data.shape" 279 | ] 280 | }, 281 | { 282 | "cell_type": "code", 283 | "execution_count": 19, 284 | "id": "91a4fd62-172b-416e-8c72-b2b942c8dc22", 285 | "metadata": {}, 286 | "outputs": [ 287 | { 288 | "data": { 289 | "text/html": [ 290 | "
\n", 291 | "\n", 304 | "\n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | "
audio_pathSoundRep
0C:\\Users\\jmdgo\\Downloads\\extracted_clips\\extra...0
1C:\\Users\\jmdgo\\Downloads\\extracted_clips\\extra...0
\n", 325 | "
" 326 | ], 327 | "text/plain": [ 328 | " audio_path SoundRep\n", 329 | "0 C:\\Users\\jmdgo\\Downloads\\extracted_clips\\extra... 0\n", 330 | "1 C:\\Users\\jmdgo\\Downloads\\extracted_clips\\extra... 0" 331 | ] 332 | }, 333 | "execution_count": 19, 334 | "metadata": {}, 335 | "output_type": "execute_result" 336 | } 337 | ], 338 | "source": [ 339 | "df_SoundRep.head(2)" 340 | ] 341 | }, 342 | { 343 | "cell_type": "code", 344 | "execution_count": 20, 345 | "id": "659f2a48-a4ec-4b22-ab53-0439f4bea6a3", 346 | "metadata": {}, 347 | "outputs": [ 348 | { 349 | "name": "stdout", 350 | "output_type": "stream", 351 | "text": [ 352 | "0 50.0\n", 353 | "1 50.0\n", 354 | "Name: SoundRep, dtype: float64\n" 355 | ] 356 | } 357 | ], 358 | "source": [ 359 | "value_counts = df_SoundRep_data['SoundRep'].value_counts()\n", 360 | "total_rows = df_SoundRep_data.shape[0]\n", 361 | "\n", 362 | "percentage_per_class = (value_counts / total_rows) * 100\n", 363 | "\n", 364 | "print(percentage_per_class)" 365 | ] 366 | }, 367 | { 368 | "cell_type": "code", 369 | "execution_count": 21, 370 | "id": "6ac7b6a0-0b0b-4eb1-92b2-6d4b834e12aa", 371 | "metadata": {}, 372 | "outputs": [], 373 | "source": [ 374 | "X = np.array(df_SoundRep_data['audio_path'])\n", 375 | "y = np.array(df_SoundRep_data['SoundRep'])" 376 | ] 377 | }, 378 | { 379 | "cell_type": "code", 380 | "execution_count": 22, 381 | "id": "02ad3a9a-237b-4e62-8d65-506c7ad0472f", 382 | "metadata": {}, 383 | "outputs": [], 384 | "source": [ 385 | "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=40, stratify = y)" 386 | ] 387 | }, 388 | { 389 | "cell_type": "code", 390 | "execution_count": 23, 391 | "id": "30457ffd-8255-4ebc-974d-38f33db7afcb", 392 | "metadata": {}, 393 | "outputs": [], 394 | "source": [ 395 | "mfcc_features_train = Parallel(n_jobs=-1)(delayed(extract_mfcc)(audio_file) for audio_file in X_train)\n", 396 | "mfcc_features_test = Parallel(n_jobs=-1)(delayed(extract_mfcc)(audio_file) for audio_file in X_test)\n", 397 | "zcr_features_train = Parallel(n_jobs=-1)(delayed(extract_zcr)(audio_file) for audio_file in X_train)\n", 398 | "zcr_features_test = Parallel(n_jobs=-1)(delayed(extract_zcr)(audio_file) for audio_file in X_test)\n", 399 | "\n", 400 | "jitter_shimmer_train = Parallel(n_jobs=-1)(delayed(extract_jitter_shimmer)(audio_file) for audio_file in X_train)\n", 401 | "jitter_shimmer_test = Parallel(n_jobs=-1)(delayed(extract_jitter_shimmer)(audio_file) for audio_file in X_test)\n", 402 | "\n", 403 | "jitter_train, shimmer_train = zip(*jitter_shimmer_train)\n", 404 | "jitter_test, shimmer_test = zip(*jitter_shimmer_test)" 405 | ] 406 | }, 407 | { 408 | "cell_type": "markdown", 409 | "id": "6973590c-5fc5-40f4-a7fb-10d05dd9df47", 410 | "metadata": {}, 411 | "source": [ 412 | "zcr_features_train = Parallel(n_jobs=-1)(delayed(extract_zcr)(audio_file) for audio_file in X_train)\n", 413 | "zcr_features_test = Parallel(n_jobs=-1)(delayed(extract_zcr)(audio_file) for audio_file in X_test)" 414 | ] 415 | }, 416 | { 417 | "cell_type": "markdown", 418 | "id": "660938cb-e39a-450a-9061-6c24c02bd983", 419 | "metadata": {}, 420 | "source": [ 421 | "features_train = np.array([np.hstack((mfcc, zcr)) for mfcc, zcr in zip(mfcc_features_train, zcr_features_train)])\n", 422 | "features_test = np.array([np.hstack((mfcc, zcr)) for mfcc, zcr in zip(mfcc_features_test, zcr_features_test)])" 423 | ] 424 | }, 425 | { 426 | "cell_type": "code", 427 | "execution_count": 24, 428 | "id": "ef378e5f", 429 | "metadata": {}, 430 | "outputs": [ 431 | { 432 | "name": "stdout", 433 | "output_type": "stream", 434 | "text": [ 435 | "(2730, 3856)\n", 436 | "(1170, 3856)\n" 437 | ] 438 | } 439 | ], 440 | "source": [ 441 | "merged_features_train = np.column_stack((mfcc_features_train, zcr_features_train, jitter_train, shimmer_train))\n", 442 | "merged_features_test = np.column_stack((mfcc_features_test, zcr_features_test, jitter_test, shimmer_test))\n", 443 | "\n", 444 | "print(merged_features_train.shape)\n", 445 | "print(merged_features_test.shape)" 446 | ] 447 | }, 448 | { 449 | "cell_type": "code", 450 | "execution_count": 25, 451 | "id": "edabd8ce", 452 | "metadata": {}, 453 | "outputs": [ 454 | { 455 | "data": { 456 | "text/plain": [ 457 | "((2730,), (1170,), (2730,), (1170,))" 458 | ] 459 | }, 460 | "execution_count": 25, 461 | "metadata": {}, 462 | "output_type": "execute_result" 463 | } 464 | ], 465 | "source": [ 466 | "X_train.shape,X_test.shape,y_train.shape,y_test.shape" 467 | ] 468 | }, 469 | { 470 | "cell_type": "code", 471 | "execution_count": 26, 472 | "id": "b0716fea", 473 | "metadata": {}, 474 | "outputs": [ 475 | { 476 | "name": "stdout", 477 | "output_type": "stream", 478 | "text": [ 479 | "NaN values found in training data at indices: [[ 147 3854]\n", 480 | " [ 147 3855]\n", 481 | " [ 325 3855]\n", 482 | " [1870 3854]\n", 483 | " [1870 3855]\n", 484 | " [2060 3854]\n", 485 | " [2060 3855]]\n", 486 | "NaN values found in testing data at indices: [[ 138 3854]\n", 487 | " [ 138 3855]\n", 488 | " [ 140 3854]\n", 489 | " [ 140 3855]\n", 490 | " [ 161 3854]\n", 491 | " [ 161 3855]\n", 492 | " [ 605 3854]\n", 493 | " [ 605 3855]]\n" 494 | ] 495 | } 496 | ], 497 | "source": [ 498 | "nan_indices_train = np.argwhere(np.isnan(merged_features_train))\n", 499 | "if len(nan_indices_train) > 0:\n", 500 | " print(\"NaN values found in training data at indices:\", nan_indices_train)\n", 501 | "else:\n", 502 | " print(\"No NaN values found in training data\")\n", 503 | "\n", 504 | "# Check for NaN values in testing data\n", 505 | "nan_indices_test = np.argwhere(np.isnan(merged_features_test))\n", 506 | "if len(nan_indices_test) > 0:\n", 507 | " print(\"NaN values found in testing data at indices:\", nan_indices_test)\n", 508 | "else:\n", 509 | " print(\"No NaN values found in testing data\")" 510 | ] 511 | }, 512 | { 513 | "cell_type": "code", 514 | "execution_count": 27, 515 | "id": "d47130de", 516 | "metadata": {}, 517 | "outputs": [ 518 | { 519 | "name": "stdout", 520 | "output_type": "stream", 521 | "text": [ 522 | "No NaN values found in imputed training data\n", 523 | "No NaN values found in imputed testing data\n" 524 | ] 525 | } 526 | ], 527 | "source": [ 528 | "from sklearn.impute import KNNImputer\n", 529 | "# KNN imputation\n", 530 | "imputer = KNNImputer(n_neighbors=5) # You can adjust the number of neighbors as needed\n", 531 | "\n", 532 | "# Fit imputer on training data and transform both training and testing data\n", 533 | "merged_features_train = imputer.fit_transform(merged_features_train)\n", 534 | "merged_features_test = imputer.transform(merged_features_test)\n", 535 | "\n", 536 | "# Check if any NaN values remain after imputation\n", 537 | "nan_indices_train = np.argwhere(np.isnan(merged_features_train))\n", 538 | "if len(nan_indices_train) > 0:\n", 539 | " print(\"NaN values still present in imputed training data at indices:\", nan_indices_train)\n", 540 | "else:\n", 541 | " print(\"No NaN values found in imputed training data\")\n", 542 | "\n", 543 | "nan_indices_test = np.argwhere(np.isnan(merged_features_test))\n", 544 | "if len(nan_indices_test) > 0:\n", 545 | " print(\"NaN values still present in imputed testing data at indices:\", nan_indices_test)\n", 546 | "else:\n", 547 | " print(\"No NaN values found in imputed testing data\")\n" 548 | ] 549 | }, 550 | { 551 | "cell_type": "code", 552 | "execution_count": 29, 553 | "id": "ab2ae65f", 554 | "metadata": {}, 555 | "outputs": [ 556 | { 557 | "name": "stdout", 558 | "output_type": "stream", 559 | "text": [ 560 | "Explained variance ratio: [0.23046092 0.1690381 0.05182512 0.03873228 0.03267255 0.03213632\n", 561 | " 0.03040406 0.01967926 0.01881117 0.01597497 0.01437103 0.01180179\n", 562 | " 0.01135941 0.01020829 0.00928691 0.00887731 0.00776032 0.00679666\n", 563 | " 0.00657214 0.00648516 0.00598973 0.00572877 0.00556341 0.0049202\n", 564 | " 0.00474634 0.00465325 0.00444663 0.00401209 0.00388667 0.00380322\n", 565 | " 0.00367577 0.00361095 0.00345658 0.00316666 0.00307042 0.00297792\n", 566 | " 0.00292586 0.00288976 0.00276818 0.00265818 0.00263326 0.00248504\n", 567 | " 0.00245014 0.00236614 0.00228997 0.00225381 0.0022253 0.00220008\n", 568 | " 0.00202645 0.00197055]\n" 569 | ] 570 | } 571 | ], 572 | "source": [ 573 | "from sklearn.decomposition import PCA\n", 574 | "\n", 575 | "# Assuming merged_features_train and merged_features_test are your feature arrays\n", 576 | "\n", 577 | "# Merge the training and testing data\n", 578 | "merged_data = np.concatenate((merged_features_train, merged_features_test), axis=0)\n", 579 | "\n", 580 | "# Apply PCA\n", 581 | "pca = PCA(n_components=50) # You can specify the number of principal components as needed\n", 582 | "transformed_data = pca.fit_transform(merged_data)\n", 583 | "\n", 584 | "# Print the explained variance ratio\n", 585 | "print(\"Explained variance ratio:\", pca.explained_variance_ratio_)\n" 586 | ] 587 | }, 588 | { 589 | "cell_type": "code", 590 | "execution_count": 30, 591 | "id": "3f94b2af-6ef7-4b4c-bb18-f970a4e39fda", 592 | "metadata": {}, 593 | "outputs": [ 594 | { 595 | "name": "stdout", 596 | "output_type": "stream", 597 | "text": [ 598 | "Distribution of 0s and 1s in y_train:\n", 599 | "1 1365\n", 600 | "0 1365\n", 601 | "dtype: int64\n", 602 | "\n", 603 | "Distribution of 0s and 1s in y_test:\n", 604 | "0 585\n", 605 | "1 585\n", 606 | "dtype: int64\n" 607 | ] 608 | } 609 | ], 610 | "source": [ 611 | "y_train_series = pd.Series(y_train)\n", 612 | "y_test_series = pd.Series(y_test)\n", 613 | "\n", 614 | "# Count the occurrences of each unique value in y_train\n", 615 | "train_distribution = y_train_series.value_counts()\n", 616 | "\n", 617 | "# Count the occurrences of each unique value in y_test\n", 618 | "test_distribution = y_test_series.value_counts()\n", 619 | "\n", 620 | "print(\"Distribution of 0s and 1s in y_train:\")\n", 621 | "print(train_distribution)\n", 622 | "\n", 623 | "print(\"\\nDistribution of 0s and 1s in y_test:\")\n", 624 | "print(test_distribution)" 625 | ] 626 | }, 627 | { 628 | "cell_type": "code", 629 | "execution_count": 31, 630 | "id": "890da51e", 631 | "metadata": {}, 632 | "outputs": [ 633 | { 634 | "name": "stdout", 635 | "output_type": "stream", 636 | "text": [ 637 | "Epoch 1/10\n", 638 | "86/86 [==============================] - 9s 99ms/step - loss: 18.9509 - accuracy: 0.5524 - val_loss: 0.7147 - val_accuracy: 0.5966\n", 639 | "Epoch 2/10\n", 640 | "86/86 [==============================] - 8s 94ms/step - loss: 0.6035 - accuracy: 0.6905 - val_loss: 0.6925 - val_accuracy: 0.6120\n", 641 | "Epoch 3/10\n", 642 | "86/86 [==============================] - 8s 94ms/step - loss: 0.4626 - accuracy: 0.7916 - val_loss: 0.7216 - val_accuracy: 0.6137\n", 643 | "Epoch 4/10\n", 644 | "86/86 [==============================] - 8s 92ms/step - loss: 0.3684 - accuracy: 0.8502 - val_loss: 0.8918 - val_accuracy: 0.5863\n", 645 | "Epoch 5/10\n", 646 | "86/86 [==============================] - 8s 94ms/step - loss: 0.2461 - accuracy: 0.9190 - val_loss: 0.8337 - val_accuracy: 0.6026\n", 647 | "Epoch 6/10\n", 648 | "86/86 [==============================] - 8s 92ms/step - loss: 0.1465 - accuracy: 0.9674 - val_loss: 0.8887 - val_accuracy: 0.6000\n", 649 | "Epoch 7/10\n", 650 | "86/86 [==============================] - 8s 93ms/step - loss: 0.0811 - accuracy: 0.9901 - val_loss: 1.0207 - val_accuracy: 0.6068\n", 651 | "Epoch 8/10\n", 652 | "86/86 [==============================] - 8s 92ms/step - loss: 0.0490 - accuracy: 0.9974 - val_loss: 1.0908 - val_accuracy: 0.5957\n", 653 | "Epoch 9/10\n", 654 | "86/86 [==============================] - 8s 92ms/step - loss: 0.0274 - accuracy: 0.9993 - val_loss: 1.2084 - val_accuracy: 0.5991\n", 655 | "Epoch 10/10\n", 656 | "86/86 [==============================] - 8s 92ms/step - loss: 0.0161 - accuracy: 1.0000 - val_loss: 1.2317 - val_accuracy: 0.5974\n" 657 | ] 658 | }, 659 | { 660 | "data": { 661 | "text/plain": [ 662 | "" 663 | ] 664 | }, 665 | "execution_count": 31, 666 | "metadata": {}, 667 | "output_type": "execute_result" 668 | } 669 | ], 670 | "source": [ 671 | "import numpy as np\n", 672 | "from sklearn.model_selection import train_test_split\n", 673 | "from tensorflow.keras.models import Sequential\n", 674 | "from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense\n", 675 | "from tensorflow.keras.utils import to_categorical\n", 676 | "\n", 677 | "X_train = np.array(merged_features_train)\n", 678 | "X_test = np.array(merged_features_test)\n", 679 | "y_train = np.array(y_train)\n", 680 | "y_test = np.array(y_test)\n", 681 | "\n", 682 | "# Convert labels to categorical\n", 683 | "y_train_categorical = to_categorical(y_train, num_classes=2)\n", 684 | "y_test_categorical = to_categorical(y_test, num_classes=2)\n", 685 | "\n", 686 | "# Reshape features for Conv1D input shape\n", 687 | "X_train = X_train.reshape(X_train.shape[0], X_train.shape[1], 1)\n", 688 | "X_test = X_test.reshape(X_test.shape[0], X_test.shape[1], 1)\n", 689 | "\n", 690 | "# Define the CNN model\n", 691 | "model = Sequential()\n", 692 | "model.add(Conv1D(32, 3, activation='relu', input_shape=(X_train.shape[1], 1)))\n", 693 | "model.add(MaxPooling1D(pool_size=2))\n", 694 | "model.add(Conv1D(64, 3, activation='relu'))\n", 695 | "model.add(MaxPooling1D(pool_size=2))\n", 696 | "model.add(Flatten())\n", 697 | "model.add(Dense(128, activation='relu'))\n", 698 | "model.add(Dense(2, activation='sigmoid')) # Output layer with sigmoid activation for binary classification\n", 699 | "\n", 700 | "# Compile the model\n", 701 | "model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])\n", 702 | "\n", 703 | "# Train the model\n", 704 | "model.fit(X_train, y_train_categorical, epochs=10, batch_size=32, validation_data=(X_test, y_test_categorical))\n" 705 | ] 706 | }, 707 | { 708 | "cell_type": "code", 709 | "execution_count": 35, 710 | "id": "ed530069", 711 | "metadata": {}, 712 | "outputs": [ 713 | { 714 | "name": "stdout", 715 | "output_type": "stream", 716 | "text": [ 717 | "Epoch 1/10\n", 718 | "86/86 [==============================] - 9s 96ms/step - loss: 14.9529 - accuracy: 0.5513 - val_loss: 0.7588 - val_accuracy: 0.5607\n", 719 | "Epoch 2/10\n", 720 | "86/86 [==============================] - 8s 94ms/step - loss: 0.5402 - accuracy: 0.7374 - val_loss: 0.6884 - val_accuracy: 0.6077\n", 721 | "Epoch 3/10\n", 722 | "86/86 [==============================] - 8s 94ms/step - loss: 0.3890 - accuracy: 0.8421 - val_loss: 0.7183 - val_accuracy: 0.6120\n", 723 | "Epoch 4/10\n", 724 | "86/86 [==============================] - 8s 94ms/step - loss: 0.2228 - accuracy: 0.9330 - val_loss: 0.7829 - val_accuracy: 0.6197\n", 725 | "Epoch 5/10\n", 726 | "86/86 [==============================] - 8s 94ms/step - loss: 0.1110 - accuracy: 0.9839 - val_loss: 0.9572 - val_accuracy: 0.6162\n" 727 | ] 728 | } 729 | ], 730 | "source": [ 731 | "import numpy as np\n", 732 | "from sklearn.model_selection import train_test_split\n", 733 | "from tensorflow.keras.models import Sequential\n", 734 | "from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense\n", 735 | "from tensorflow.keras.utils import to_categorical\n", 736 | "\n", 737 | "# Assuming merged_features_train contains merged features for training data\n", 738 | "# Assuming merged_features_test contains merged features for test data\n", 739 | "# Assuming y_train contains labels for training data\n", 740 | "# Assuming y_test contains labels for test data\n", 741 | "\n", 742 | "# Convert lists to numpy arrays\n", 743 | "X_train = np.array(merged_features_train)\n", 744 | "X_test = np.array(merged_features_test)\n", 745 | "y_train = np.array(y_train)\n", 746 | "y_test = np.array(y_test)\n", 747 | "\n", 748 | "# Convert labels to categorical\n", 749 | "y_train_categorical = to_categorical(y_train, num_classes=2)\n", 750 | "y_test_categorical = to_categorical(y_test, num_classes=2)\n", 751 | "\n", 752 | "# Reshape features for Conv1D input shape\n", 753 | "X_train = X_train.reshape(X_train.shape[0], X_train.shape[1], 1)\n", 754 | "X_test = X_test.reshape(X_test.shape[0], X_test.shape[1], 1)\n", 755 | "\n", 756 | "# Define the CNN model\n", 757 | "model = Sequential()\n", 758 | "model.add(Conv1D(32, 3, activation='relu', input_shape=(X_train.shape[1], 1)))\n", 759 | "model.add(MaxPooling1D(pool_size=2))\n", 760 | "model.add(Conv1D(64, 3, activation='relu'))\n", 761 | "model.add(MaxPooling1D(pool_size=2))\n", 762 | "model.add(Flatten())\n", 763 | "model.add(Dense(128, activation='relu'))\n", 764 | "model.add(Dense(2, activation='sigmoid')) # Output layer with softmax activation for binary classification\n", 765 | "\n", 766 | "# Compile the model\n", 767 | "model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])\n", 768 | "\n", 769 | "from tensorflow.keras.callbacks import EarlyStopping\n", 770 | "\n", 771 | "# Define early stopping callback\n", 772 | "early_stopping = EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True)\n", 773 | "\n", 774 | "# Train the model with early stopping\n", 775 | "history = model.fit(X_train, y_train_categorical, epochs=10, batch_size=32, \n", 776 | " validation_data=(X_test, y_test_categorical), callbacks=[early_stopping])\n" 777 | ] 778 | }, 779 | { 780 | "cell_type": "code", 781 | "execution_count": 36, 782 | "id": "0d06238d", 783 | "metadata": {}, 784 | "outputs": [ 785 | { 786 | "name": "stdout", 787 | "output_type": "stream", 788 | "text": [ 789 | "dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])\n" 790 | ] 791 | }, 792 | { 793 | "data": { 794 | "image/png": "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", 795 | "text/plain": [ 796 | "
" 797 | ] 798 | }, 799 | "metadata": {}, 800 | "output_type": "display_data" 801 | } 802 | ], 803 | "source": [ 804 | "import matplotlib.pyplot as plt\n", 805 | "# Print the keys of the history\n", 806 | "print(history.history.keys())\n", 807 | "\n", 808 | "# Summarize history for accuracy\n", 809 | "plt.plot(history.history['accuracy'])\n", 810 | "plt.plot(history.history['val_accuracy'])\n", 811 | "plt.title('Model Accuracy')\n", 812 | "plt.ylabel('Accuracy')\n", 813 | "plt.xlabel('Epoch')\n", 814 | "plt.legend(['Train', 'Validation'], loc='upper left')\n", 815 | "plt.show()" 816 | ] 817 | }, 818 | { 819 | "cell_type": "code", 820 | "execution_count": 37, 821 | "id": "387b3171", 822 | "metadata": {}, 823 | "outputs": [ 824 | { 825 | "name": "stdout", 826 | "output_type": "stream", 827 | "text": [ 828 | "Model saved successfully to: C:\\Users\\jmdgo\\Downloads\n" 829 | ] 830 | } 831 | ], 832 | "source": [ 833 | "model_file_path = r'C:\\Users\\jmdgo\\Downloads'\n", 834 | "model.save(\"SoundRep_mzjs_model.h5\")\n", 835 | "print(\"Model saved successfully to:\", model_file_path)" 836 | ] 837 | } 838 | ], 839 | "metadata": { 840 | "kernelspec": { 841 | "display_name": "Python 3 (ipykernel)", 842 | "language": "python", 843 | "name": "python3" 844 | }, 845 | "language_info": { 846 | "codemirror_mode": { 847 | "name": "ipython", 848 | "version": 3 849 | }, 850 | "file_extension": ".py", 851 | "mimetype": "text/x-python", 852 | "name": "python", 853 | "nbconvert_exporter": "python", 854 | "pygments_lexer": "ipython3", 855 | "version": "3.11.4" 856 | } 857 | }, 858 | "nbformat": 4, 859 | "nbformat_minor": 5 860 | } 861 | --------------------------------------------------------------------------------