{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Introduction","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"This is an example notebook for testing initial models on Birds Dataset.\nThe focus is to start to explore some dataset characteristics, some preprocessing strategies and models.\nThe phases you can see here are:\n* Filtering: The birds dataset is very large, with several classes and audios with different quality. Filtering are performed based on the train metadata and other selections.\n* Audio interval selection: As the audio files present several other sounds, as backgrounds and noises, I defined a strategy to select 5 sec with maximum energy expecting it is more representative from an long audio file.  \n* Preprocessing: Initially I using mfcc features, a very common approach for audio applications.\n* Classification Model: I start using the simple KNN method. Although it is not so advanced in audio detection as CNNs, it is fast enought to perform several tests.\n\nPlease, use this notebook as a didactical one. \nIf you enjoy it, please, leave your upvote and comments.\n\nThanks!","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"# Imports","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# feature extractoring and preprocessing data\nimport librosa\nimport librosa.display\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\n%matplotlib inline\nfrom PIL import Image\nfrom pathlib import Path\nimport csv\n# Preprocessing\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import LabelEncoder, StandardScaler\n#Reports\nfrom sklearn.metrics import classification_report, confusion_matrix\n\nimport warnings\nwarnings.filterwarnings('ignore')\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Reading Dataset","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## Testing some samples","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"sr=16000\nn_mels = 64\ncmap = plt.get_cmap('gray')\n\ne_file = '/kaggle/input/birdsong-recognition/train_audio/aldfly/XC134874.mp3'#XC167210.mp3 XC124067.mp3\n\ny, sr = librosa.load(e_file, mono=True, sr=sr)#duration=5\ny = librosa.util.normalize(y, axis=0)\nD = np.abs(librosa.stft(y, n_fft=int(0.040*sr),\n                                hop_length=int(0.020*sr),\n                                window='hann'))**2\nS = librosa.feature.melspectrogram(S=D,sr=sr, n_mels=64)\nplt.figure(figsize=(16,16))\nsub = plt.subplot(3,1,1)\nlibrosa.display.waveplot(y,sr=sr, x_axis='time')\nsub.set_title('Wave')\nsub2 = plt.subplot(3,1,2)\nlibrosa.display.specshow(librosa.power_to_db(S,ref=np.max),\n                                 y_axis='mel', fmax=8000,\n                                 x_axis='time',\n                                 cmap = cmap)\nsub2.set_title('Log-melspectogram')\nsub3 = plt.subplot(3,1,3)\nrms = librosa.feature.rms(y=y,frame_length=1024, hop_length=512)\nplt.semilogy(rms.T)\nsub3.set_title('Energy')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Function to select 5 sec of audio based on energy","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"sr=16000\nn_mels = 64\n\ndef max_5s(file, sr):\n    #open file\n    y, sr = librosa.load(file, mono=True, sr=sr)\n    y = librosa.util.normalize(y, axis=0)\n    # if audio < 5s, append and cut\n    if len(y) < 5*sr:\n        for i in range(int(0.5+5*sr/len(y))):\n            y = np.append(y,y)\n        return y[:5*sr] #nothing more to do\n    # get max energy point\n    rms = librosa.feature.rms(y=y,frame_length=1024, hop_length=512)\n    me = np.argmax(rms)*512\n    # Check bounds (for audios >= 5s only)\n    if me > 2.5*sr:\n        if len(y) < me+2.5*sr: # check for upper bound\n            y5 = y[int(me-2.5*sr):int(me+2.5*sr)] #2.5 seg before and 2.5 after\n        else:\n            y5 = y[len(y)-5*sr:len(y)] # get the last 5 s\n    else:\n        y5 = y[:5*sr] # get the first 5 s\n    return y5\n\ny = max_5s(e_file, sr)\nlibrosa.display.waveplot(y,sr=sr, x_axis='time')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Filtering dataset based on metada","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/birdsong-recognition/train.csv')\ndf.info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Selecting high-rated sound only\ndff = df[df['rating'] > 4.0]\n# Selecting shorter files only, less data to process\ndff = dff[dff['duration'] < 20]\nprint(len(dff))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Selecting birds with more than 10 examples left\ndfc = dff.groupby('ebird_code')['ebird_code'].count()\ndff = dff[~dff['ebird_code'].isin(dfc[dfc.values < 10].index)]\nprint(len(dff))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Not all classes may be represented according to filtering\n# Several classes decreased a lot\ndfc = dff.groupby('ebird_code')['ebird_code'].count()\nplt.figure(figsize=(16,8))\ndfc.plot.bar()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Navigating through the selected files do generate a 5 sec dataset","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"audio_path = Path('/kaggle/input/birdsong-recognition/train_audio')\n\nsound_categories = dff['ebird_code'].unique()\n\naudios = []\nY = []\nY_classes = []\nlabel = 0\nfor category_name in sound_categories:\n    #Walk through the dataframe filename values\n    l_files = dff[dff['ebird_code'] == category_name]['filename'].values\n    for file_name in l_files:\n        try:\n            sound_path = audio_path/category_name/file_name\n            y = max_5s(sound_path, sr)\n            mfcc = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=n_mels)\n            to_append = ''\n            for e in mfcc:\n                to_append += f' {np.mean(e)} {np.std(e)}'\n            S = np.fromstring(to_append, dtype=float, sep=\" \")\n            audios.append(S)\n            Y.append(label)\n            Y_classes.append(category_name)\n        except:\n            print(sound_path)\n            pass\n    label +=1\n    if label == 20:\n        break\nX = np.array(audios)\nY = np.array(Y)\nnum_classes = len(sound_categories)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Spliting Dataset for trainning and test","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"perc_test = 0.2\n\nx_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=perc_test)\nprint(x_train.shape)\nprint(x_test.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Creating the Model","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## Starting with a simple KNN","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.neighbors import KNeighborsClassifier\nclf = KNeighborsClassifier(n_neighbors=3)\nclf.fit(x_train, y_train)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Evaluating","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"y_pred = clf.predict(x_test)\nprint(\"Total de exemplos: \"+ str(len(x_test)))\n\n#score = clf.evaluate(x_test, y_test, verbose=0)\n#print('Loss de Teste:', score[0])\nprint('Acurácia de Teste:', len(y_pred[y_pred==y_test])/len(y_pred))\n#print(y_pred)\n#print(y_test)\n\nprint('Confusion Matrix')\nprint(confusion_matrix(y_test, y_pred))\nprint('Classification Report')\nprint(classification_report(y_test, y_pred, target_names=np.unique(Y_classes)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Submission","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_test_clip(path, start_time, duration=5):\n    return librosa.load(path, offset=start_time, duration=duration, sr=sr)[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"TEST_FOLDER = '../input/birdsong-recognition/test_audio/'\ntest_info = pd.read_csv('../input/birdsong-recognition/test.csv')\ntest_info.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pred_limit = 0.6\ndef make_prediction(sound_clip, birds):\n    mfcc = librosa.feature.mfcc(y=sound_clip, sr=sr, n_mfcc=n_mels)\n    to_append = ''\n    for e in mfcc:\n        to_append += f' {np.mean(e)} {np.std(e)}'\n    S = np.fromstring(to_append, dtype=float, sep=\" \")\n    ret = clf.predict_proba(S)\n    pred = np.argmax(ret[0])\n    if ret[0][pred] > pred_limit:\n        return Y_classes(pred)\n    else:\n        return 'noclass'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"try:\n    preds = []\n    for index, row in test_info.iterrows():\n        # Get test row information\n        site = row['site']\n        start_time = row['seconds'] - 5\n        row_id = row['row_id']\n        audio_id = row['audio_id']\n\n        # Get the test sound clip\n        if site == 'site_1' or site == 'site_2':\n            sound_clip = load_test_clip(TEST_FOLDER + audio_id + '.mp3', start_time)\n        else:\n            sound_clip = load_test_clip(TEST_FOLDER + audio_id + '.mp3', 0, duration=None)\n\n        # Make the prediction\n        pred = make_prediction(sound_clip, birds)\n\n        # Store prediction\n        preds.append([row_id, pred])\n\n    preds = pd.DataFrame(preds, columns=['row_id', 'birds'])\nexcept:\n    preds = pd.read_csv('../input/birdsong-recognition/sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}