{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Objective \n**To Classify birds based on sound recordings provided in the training set, and to predict the birds species present in the test set. The Image meta-data is given in the train_metadata.csv .**","metadata":{}},{"cell_type":"markdown","source":"# Resources:\n\n* Research Paper  [ http://ceur-ws.org/Vol-1866/paper_143.pdf ]\n* Guide Notebook [ https://www.kaggle.com/stefankahl/birdclef2021-model-training ]\n* My notebook on Rainforest Connect Audio : [ https://www.kaggle.com/virajkadam/rainforest-connect-custom-cnn ]\n* [ https://www.kaggle.com/kmldas/birdclef-2021-eda-model ]\n\n","metadata":{}},{"cell_type":"markdown","source":"**My notebook on BirdClef EDA:** [ https://www.kaggle.com/virajkadam/birdclef-exploratory-data-analysis ]\n**Notebook on Birdclef training** [ https://www.kaggle.com/virajkadam/birdclef-bird-sound-classification/edit ]","metadata":{}},{"cell_type":"markdown","source":"# Imports ","metadata":{}},{"cell_type":"code","source":"pip install audiomentations","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#basic libraries\nimport numpy as np\nimport os,gc\nimport pandas as pd \nimport matplotlib.pyplot as plt \n\n#audio\nimport librosa \nfrom audiomentations import Compose,AddGaussianSNR,Shift,TimeStretch,TimeMask,FrequencyMask,PolarityInversion\nfrom IPython.display import Audio\n\n#Image\nfrom PIL import Image \n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loading Data ","metadata":{}},{"cell_type":"code","source":"train_labels=pd.read_csv('../input/birdclef-2021/train_soundscape_labels.csv')\nmetadata=pd.read_csv('../input/birdclef-2021/train_metadata.csv')\ntest=pd.read_csv('../input/birdclef-2021/test.csv')\n\ntrain_dir='../input/birdclef-2021/train_short_audio'\ntest_dir='../input/birdclef-2021/test_soundscapes'","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Filtering audio data \n**Limiting the training data to 'rating'>=4. So to not take data with a lot of noise.**","metadata":{}},{"cell_type":"code","source":"train=metadata.query('rating >= 4.0')\n\n#lets see the distribution of count numbers\nrec_count=pd.Series(train.primary_label.value_counts())\nplt.hist(rec_count.values,width=15,bins=30)\nplt.xlabel('Num Recordings')\nplt.ylabel('count')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**I will use recordings with more than 150 instances.**","metadata":{}},{"cell_type":"code","source":"count_gt_100=rec_count[rec_count.values>150].index\n\n#taking the data that has atleast 100 recordings rated >4:\n\ntrain_ds=train[train['primary_label'].isin(count_gt_100)]\nprint(f'Number of species in data are : {train_ds.primary_label.nunique()}')\nprint(f'Number of audio samples : {len(train_ds)}')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Extracting Mel Spectrograms:","metadata":{}},{"cell_type":"markdown","source":"**Augmenting Data using Audiomentations Library**","metadata":{}},{"cell_type":"code","source":"#Audio Augmentation:\naugmentations = Compose([\n            FrequencyMask(min_frequency_band=0.005, max_frequency_band=0.10, p=0.25),\n            TimeStretch(min_rate=0.15,max_rate=.25,p=0.25),\n            AddGaussianSNR(min_SNR=0.001, max_SNR=.25, p=0.25)])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Loading Data as mel-spectrograms**","metadata":{}},{"cell_type":"code","source":"#Global Params\nSample_rate = 32000\nSignal_length = 5 # seconds\nshape= (64, 256) # height x width\nFMIN = 500\nFMAX = 12500\nhop_len=(Sample_rate* Signal_length // (shape[1]-1))\n\n#Number of species in data\nnum_classes=train_ds.primary_label.nunique()\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#making new dir to save spectrograms\ncwd=os.path.abspath(os.getcwd())\n\nos.mkdir(os.path.join(cwd,'Mel_specs'))\n\nspec_dir=os.path.join(cwd,'Mel_specs')\nspec_dir","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#function to save stfts\n\ndef save_stft(path,label=None,idx=None,Augment=False,dir_path=spec_dir):\n    '''extracting mel-specs from given audio data and saving them to given folder'''\n    \n    \n    #loading files:\n    if label:\n        file_path=os.path.join(path,label,idx)\n    else:\n        file_path=path\n        \n        \n    sig,sr=librosa.load(file_path,sr=Sample_rate)\n    \n    stft_id=[]\n    labels=[]\n    n=0\n    for i in range(0,len(sig),int(Signal_length*Sample_rate)):\n        \n        window = sig[i:i + int(Signal_length * Sample_rate)]\n\n        # End of signal\n        if len(window) < int(Signal_length * Sample_rate):\n            break\n            \n            \n            \n        #Augment :   \n        if Augment:\n            window=augmentations(window,sample_rate=sr)\n            \n        # extracting mel-spectrograms:\n        mel_spec = librosa.feature.melspectrogram(window,sr,n_mels=shape[0],\n                                                hop_length=hop_len,\n                                                fmin=FMIN,fmax=FMAX)\n        \n        mel_spec = librosa.core.amplitude_to_db(mel_spec,ref=np.max)\n        \n        # Normalize\n        mel_spec -= mel_spec.min()\n        mel_spec /= mel_spec.max()\n        \n        \n        #saving Image\n        \n        #image_id\n        ids=idx.split('.')[0]\n        \n        save_id=f'{ids}_{n}.jpg'\n        save_path=os.path.join(dir_path,save_id)\n        \n        n+=1\n        \n        image = Image.fromarray(mel_spec * 255.0).convert(\"L\")\n        image.save(save_path)\n        \n        #saving_image ids and labels\n        stft_id.append(save_id)\n        labels.append(label)\n        \n    return stft_id,labels","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**extracting specs for selected species**","metadata":{}},{"cell_type":"code","source":"spec_ids=[]\nlabels=[]\nnum_species=train_ds.primary_label.nunique()\nfor i,ids in enumerate(train_ds.primary_label.unique()):\n    \n    spec_df=train_ds[train_ds.primary_label==ids]\n    \n    #taking lesser number of samples from each species:\n    \n#     sampling n from given species\n    n=int(len(spec_df)/3)\n    \n    for sound_ids in spec_df['filename'].sample(n):\n        spec_id,label=save_stft(path=train_dir,label=ids,idx=sound_ids,Augment=True)\n        \n        #appending to final list:\n        spec_ids.extend(spec_id)\n        labels.extend(label)\n        \n\nassert len(spec_ids) == len(labels)\nlen(labels)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**saving ids and labels saved for further use**","metadata":{}},{"cell_type":"code","source":"#making a dataframe of recording_ids and labels:\ntrain_specs=pd.DataFrame({'Image_Id':spec_ids,'label':labels})\n\ndel spec_ids, labels ; gc.collect()\n\n#saving csv for further use:\ntrain_specs.to_csv('train_specs.csv',index=False)\ntrain_specs.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**checking some sample Images**","metadata":{}},{"cell_type":"code","source":"sampled_df=train_specs.sample(25)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_image(path,title):\n    plt.subplots(figsize=(8,4))\n    image=Image.open(path)\n    \n    plt.title(name)\n    plt.axis('off')\n    plt.grid(b=None)\n    plt.imshow(image)\n    \nfor i,row in sampled_df.iterrows():\n    idx=row.Image_Id\n    name=row.label\n    show_image(os.path.join(spec_dir,idx),name)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Will do the training and inference part in a seperate notebook, linked above.**","metadata":{}}]}