{"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":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport plotly.express as px\nimport plotly.graph_objects as go\nfrom tqdm import tqdm\nfrom tqdm import tqdm,tnrange,tqdm_notebook\nimport librosa\nimport librosa.display\nfrom PIL import Image\nimport shutil\nimport warnings\nwarnings.filterwarnings(action='ignore')\nfrom mpl_toolkits.axes_grid1 import ImageGrid\n\n''' HELPER FUNCTIONS '''\n\n# Just Seaborn Barplot w/ Common Input Format\ndef bar_plot(x, y,title='Training Soundscape : 5 second segment identification', xlim = None, ylim = None, \n             xticklabels = None, yticklabels = None,xlabel = None, ylabel = None, \n             figsize = (10,4),axis_grid = 'x',xrotation=None, yrotation=None ):\n        \n    cmap = sns.color_palette(\"mako\")\n    fig, ax = plt.subplots(figsize = figsize)\n    plt.title(title)\n\n    for i in ['top', 'right', 'bottom', 'left']:\n        ax.spines[i].set_color('black')\n    \n    ax.spines['top'].set_visible(True);ax.spines['right'].set_visible(False)\n    ax.spines['bottom'].set_visible(False);ax.spines['left'].set_visible(False)\n\n    sns.barplot(x = x, y = y, edgecolor = 'black', ax = ax,palette = cmap)\n    ax.set_xlim(xlim);ax.set_ylim(ylim)    \n#     ax.set_xticklabels(xticklabels);ax.set_yticklabels(yticklabels)\n    plt.xlabel(xlabel);plt.ylabel(ylabel)\n    ax.grid(axis = axis_grid,ls='--',alpha = 0.3)\n    plt.xticks(rotation=xrotation)\n    plt.yticks(rotation=yrotation)\n    plt.savefig('bar_out.png');plt.show();\n    \ndef show_grid(image_list,nrows,ncols,label_list=None,show_labels=False,savename=None,figsize=(20,10),showaxis='off'):\n    if type(image_list) is not list:\n        if(image_list.shape[-1]==1):\n            image_list = [image_list[i,:,:,0] for i in range(image_list.shape[0])]\n        elif(image_list.shape[-1]==3):\n            image_list = [image_list[i,:,:,:] for i in range(image_list.shape[0])]\n    fig = plt.figure(None, figsize,frameon=False)\n    grid = ImageGrid(fig, 111,  # similar to subplot(111)\n                     nrows_ncols=(nrows, ncols),  # creates 2x2 grid of axes\n                     axes_pad=0.3,  # pad between axes in inch.\n                     share_all=True,\n                     )\n    for i in range(nrows*ncols):\n        ax = grid[i]\n        img = Image.open(image_list[i])\n        ax.imshow(img,cmap='Greys_r')  # The AxesGrid object work as a list of axes.\n        ax.axis('off')\n        if show_labels:\n            ax.set_title(class_mapping[y_int[i]])\n    if savename != None:\n        plt.savefig(savename,bbox_inches='tight')\n        \n''' Extracts spectrograms and saves them in a working directory '''\ndef get_spectrograms(filepath, primary_label, output_dir):\n\n    # load one signal via librosa\n    # split signal into parts, storing them in a list\n\n    sig, rate = librosa.load(filepath, sr=cfg.sr, offset=None, duration=cfg.cutoff)\n    sig_splits = split_signal(sig) # split the signal into parts (exactly 5s segments)\n\n    # Extract mel spectrograms for each audio chunk\n    s_cnt = 0\n    saved_samples = []\n    for chunk in sig_splits:\n\n        s_cnt += 5\n        \n        hop_length = int(cfg.sl * cfg.sr / (cfg.sshape[1] - 1))\n        mel_spec = librosa.feature.melspectrogram(y=chunk, \n                                                  sr=cfg.sr, \n                                                  n_fft=1024, \n                                                  hop_length=hop_length, \n                                                  n_mels=cfg.sshape[0], \n                                                  fmin=cfg.fmin, \n                                                  fmax=cfg.fmax)\n    \n        mel_spec = librosa.power_to_db(mel_spec**2, ref=np.max) \n        \n        # Normalize\n        mel_spec -= mel_spec.min()\n        mel_spec /= mel_spec.max()\n        \n        # Save as image file\n        save_dir = os.path.join(output_dir, primary_label)\n        if not os.path.exists(save_dir):\n            os.makedirs(save_dir)\n        save_path = os.path.join(save_dir, filepath.rsplit(os.sep, 1)[-1].rsplit('.', 1)[0] + \n                                 '_' + str(s_cnt) + '.png')\n        im = Image.fromarray(mel_spec * 255.0).convert(\"L\")\n        im.save(save_path)        \n        saved_samples.append(save_path)\n\n    return saved_samples\n\n''' CREATE SPECTOGRAMS FROM DATAFRAME '''\n# Create Spetograms from dataframe, containing pathwys to short audio, .ogg\ndef df_to_spectogram(ldf):\n\n    path_temp = DIR_SPEC_OUT + 'bird'\n    if(os.path.exists(path_temp)):\n        shutil.rmtree(path_temp)\n\n    samples = []\n    with tqdm_notebook(total=len(ldf)) as pbar:\n        for idx, row in ldf.iterrows():   # cycle through each row in df\n            pbar.update(1)\n\n            audio_file_path = ldf.loc[idx,'path']\n            samples += get_spectrograms(audio_file_path, row.primary_label,path_temp)\n                \n    print(f'CREATED # OF SPECTOGRAMS: {len(samples)} FILES')\n    \n''' Split librosa signal the into segments '''\ndef split_signal(sig):\n    sig_splits = []\n    for i in range(0, len(sig), int(cfg.sl * cfg.sr)):\n        split = sig[i:i + int(cfg.sl * cfg.sr)]\n        if len(split) < int(cfg.sl * cfg.sr):\n            break\n        sig_splits.append(split)\n    \n    return sig_splits","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <sub>I.</sub> <span style='color:#F7765E'><sub>SOUNDSCAPE DATA</sub></span>\n#### <b>GENERAL OVERVIEW</b>\n- Envronment recordings can be referred to as <b>soundscapes</b>; typically a long recording without labels.\n<b>In this competition</b>:\n- The one big recording is to be <b>split into 5 second segments</b> & for each segment we are required to indicate either of the two:\n    - (a) whether a bird is present, and if so which one.\n    - (b) no bird is present.\n\n<b>Sample Recording</b>\n\nWhether you analyse the recording in time domain only or split it into time & frequency domain, let's view what the recording would look like:\n\n#### <b>train_short_audio RELATION</b>\n- In this competition, we are given a set of short audio slips (located in folder: <b>train_short_audio</b>), all of which are all labeled.\n- These collections of recordings contain audio signals of a particular specie with varying degree of background/foreground noise (<code>train_metadata.csv</code>'s <b>rating data</b>). The noise a bird makes should fundamentally be cleaner than in the soundscape recording. \n- In this competition, we are provided with a file <code>train_metadata.csv</code>, which contains the information about how clean each of these recordings is; <code>rating</code>.\n- They are useful to extract patterns that can be present in the <b>soundscape data</b> we will be given.\n\n#### <b>TRAINING & TEST RECORDING LOCATIONS</b>\nWe can extract location data from <code>txt</code> located in the <b>test_soundscapes</b> folder.","metadata":{}},{"cell_type":"code","source":"tdf = pd.read_csv('../input/birdclef-2021/train_soundscape_labels.csv')\n\n# latitude, longitude\nCOL = [5.57,-75.85,200,'Jardín, Departamento de Antioquia','Colombia']\nCOR = [10.12,-84.51,200,'Alajuela, San Ramón','Costa Rica']\nSNE = [38.49,-119.95,200,'Sierra Nevada, California','USA'] \nSSW = [42.47,-76.45,200,'Ithaca, New York','USA']\nindex = ['COL','COR','SNE','SSW']\ncolumns = ['latitude','longitude','size','location','country']\ndata = [COL,COR,SNE,SSW]\ntest_tdf = pd.DataFrame(data,index=index,columns=columns)\ntest_tdf","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### <b>TRAINING SOUNDSCAPE : COUNTS INFORMATION</b>\n- Let's view the value counts difference between <b>nocall</b> and <b>call</b> labels in the <b>training soundscape</b> data.\n- Splitting the whole soundscape recording into <b>5 second</b> segments, let's also see how many segments exist in each recording, in the <b>training soundscape</b> data.","metadata":{}},{"cell_type":"code","source":"# Training Given Environment Recordings\ntdf = pd.read_csv('../input/birdclef-2021/train_soundscape_labels.csv')\ntdf0 = pd.read_csv('../input/birdclef-2021/train_metadata.csv')\nval = tdf.birds.value_counts(); y = val.to_list(); x = val.index.to_list()\n\nprint('CALLS vs NOCALLS INFO in All Recordings')\nprint(f\"Training Soundscape Identifiers: {tdf[tdf.birds!='nocall'].shape[0]}\")\nprint(f\"Training Soundscapes Nocalls: {tdf[tdf.birds=='nocall'].shape[0]}\")\n\nprint('\\nTRAINING SOUNDSCAPE RECORDINGS:')\ntdf.site.value_counts() # 2/4 TEST LOCATIONS","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### <b>TRAINING SOUNDSCAPE BIRD COUNTS</b>\n- We are given the labels for all <b>training soundscape</b> intervals in the file, <code>train_soundscape_labels.csv</code>\n- Let's see which birds are present in these recordings at the two locations (<b>COR</b> & <b>SSW</b>)","metadata":{}},{"cell_type":"code","source":"# Visualise the Birds present in Recordings\nbar_plot(x=x[1:],y=y[1:],figsize=(20,5),xrotation=90,title='Soundscape Data: Birds Labeled in All Recordings')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### <b>SOUNDSCAPE RECORDNG LOCATIONS</b>\n- Haven been given the locations of each recording location, in the <b>test_soundscapes</b> folder, we know the locations of both <b>training</b> & <b>test</b> recording locations.\n- Let's plot, both the soundscape locations (<b>orange</b>) & train_short_audio recording locations (<b>hexbin map</b>) which are from xeno-canto.","metadata":{}},{"cell_type":"code","source":"# Unique Token ID\nmapbox_access_token = 'pk.eyJ1Ijoic2h0cmF1c3NhcnQiLCJhIjoiY2tqcDU2dW56MDVkNjJ6angydDF3NXVvbyJ9.nx2c5XzUH9MwIv4KcWVGLA'\nplot_hex = True\nimport plotly.figure_factory as ff\nif(plot_hex):\n\n    fig = ff.create_hexbin_mapbox(\n        data_frame=tdf0, lat=\"latitude\", lon=\"longitude\",\n        nx_hexagon=200, opacity=0.6,min_count=1, labels={\"color\": \"Point Count\"},\n        color_continuous_scale=\"mint\",\n        range_color = [0,100],\n        show_original_data=True, # show point data\n        original_data_marker=dict(size=2, opacity=0.05,color='black'), # point data options\n        zoom = 10,height=500)\n    fig2 = go.Scattermapbox(\n            lat=test_tdf['latitude'],\n            lon=test_tdf['longitude'],\n            text=[test_tdf['location'][i]+': Soundscape' for i in range(test_tdf.shape[0])],\n            mode='markers',\n            marker=go.scattermapbox.Marker(\n                size=30,color='rgb(255, 87, 51)',opacity=0.3)\n    )\n    fig.add_trace(fig2)\n    fig.update_layout(\n        hovermode='closest',\n        mapbox=dict(\n            accesstoken=mapbox_access_token,\n            bearing=0,pitch=0,zoom=1))\n    fig.update_layout(title=\"<b>Train Short Audio</b> | Soundscape Locations\",\n                      margin={\"r\":0,\"t\":80,\"l\":0,\"b\":0},mapbox_style=\"light\");\n    fig.update_layout(coloraxis_showscale=False,showlegend=False);fig.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### <b>LOCATION SEGMENT LABELS: SSW </b>\n- One of the locations available to us in the <b>train_soundscapes</b> data.\n- Let's plot a heatmap of <b>all the soundscape segments (120 per recording)</b> & the <b>corresponding label</b> at location <b>SSW</b>.\n- SSW: Ithaca, New York, USA Recording Sightings.","metadata":{}},{"cell_type":"code","source":"lst_tdfs = []; ii=-1\nfor i in tdf.audio_id.value_counts().index:\n    height_id = [2,1,1,2,2,\n                 3,5,4,1.5,1.5]\n\n    loc_tdf = tdf[tdf.audio_id == i].reset_index()\n    if(loc_tdf.loc[0,'site']=='SSW'):\n        loc_id = str(loc_tdf.loc[0,'site']) + '_' + str(+ loc_tdf.loc[0,'audio_id'])\n        ii+=1; lst_tdfs.append(loc_tdf)\n\n        # get heatmap\n        heatmap = lst_tdfs[ii].pivot_table(index='birds',columns=lst_tdfs[ii].index+1,values='seconds')\n        fig,ax = plt.subplots(figsize=(30,height_id[ii]))\n        cmap = sns.color_palette(\"mako\")\n        sns.heatmap(heatmap,ax=ax,cbar=False,linecolor='k',lw=1,cmap=cmap)\n        plt.yticks(rotation=0);plt.title(loc_id)\n        plt.savefig(loc_id+'.png');\n        plt.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### <b>LOCATION SEGMENT LABELS: COR </b>\n- The second & final location available to us in the <b>train_soundscapes</b> data.\n- Let's plot a heatmap of <b>all the soundscape segments (120 per recording)</b> & the <b>corresponding label</b> at location <b>COR</b> as well.\n- COR: Alajuela, San Ramón, Costa Rica Recording Sightings.","metadata":{}},{"cell_type":"code","source":"lst_tdfs = []; ii=-1\nfor i in tdf.audio_id.value_counts().index:\n    height_id = [0.5,3,3,0.5,2,\n                 2,3,1,0.5,2]\n\n    loc_tdf = tdf[tdf.audio_id == i].reset_index()\n    if(loc_tdf.loc[0,'site']=='COR'):\n        loc_id = str(loc_tdf.loc[0,'site']) + '_' + str(+ loc_tdf.loc[0,'audio_id'])\n        ii+=1; lst_tdfs.append(loc_tdf)\n\n        # get heatmap\n        heatmap = lst_tdfs[ii].pivot_table(index='birds',columns=lst_tdfs[ii].index+1,values='seconds')\n        fig,ax = plt.subplots(figsize=(30,height_id[ii]))\n        cmap = sns.color_palette(\"mako\")\n        sns.heatmap(heatmap,ax=ax,cbar=False,linecolor='k',lw=1,cmap=cmap)\n        plt.yticks(rotation=0);plt.title(loc_id)\n        plt.savefig(loc_id+'.png');\n        plt.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <sub>II.</sub> <span style='color:#F7765E'><sub>SHORT RECORDING RELATIVE TO SOUNDSCAPE LOCATIONS</sub></span>\n\n- Short Audio Clips in relation to <b>Training & Test Soundscape</b> locations. \n- Soundscape recording locations are not precise, unlike Short Audio clips, as indicated in this [reply](https://www.kaggle.com/c/birdclef-2021/discussion/232238):\n> Each location description is just a rough estimation of the area that we used as recording site. We use recorder arrays which are often distributed across a habitat. So there is no precise location, I used the center of the recording cluster and then rounded lat and lon which still provides a good indication for a potential species mix.\n- Let's plot the recorded locations of each bird specie (<b>primary</b>) as well as the <b>soundscape locations</b>, to do that we can create a small class to help us keep things clean.","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nimport matplotlib.pyplot as plt\nimport seaborn as sns;sns.set(style='whitegrid')\nfrom matplotlib import cm\nimport librosa\nimport librosa.display\nimport IPython.display as ipd\nimport warnings\nwarnings.filterwarnings(action='ignore')\nimport datetime\npd.set_option('display.max_columns', None) \nmapbox_access_token = 'pk.eyJ1Ijoic2h0cmF1c3NhcnQiLCJhIjoiY2tqcDU2dW56MDVkNjJ6angydDF3NXVvbyJ9.nx2c5XzUH9MwIv4KcWVGLA'\nimport plotly.figure_factory as ff\nimport plotly.graph_objects as go\n\n# global config file\nclass config:\n    base_dir = '/kaggle/input/birdclef-2021/'\n    os.chdir(base_dir)\n    print(f'cwd: {os.getcwd()}')\n\n# class for dealing with soundscapes\nclass birdclef:\n\n    def __init__(self):\n        \n        ''' SHORT TRAINING FILES '''\n        self.path_short_audio = './train_short_audio/' \n        self.pd_short_audio = pd.read_csv('train_metadata.csv')\n        self.pd_short_audio['path'] = self.path_short_audio + \"/\" + self.pd_short_audio['primary_label'] + '/' + self.pd_short_audio['filename']\n\n        ''' TRAINING SOUNDSCAPE FILES '''\n        self.so_path_tr = './train_soundscapes/'  # path to train soundcape files\n        self.so_path_te = './test_soundscapes/'  # path to test soundcape files\n        self.sscape_audio = pd.read_csv(config.base_dir+'train_soundscape_labels.csv')   # read soundscape related CSV\n\n        lst_sounds = os.listdir(self.so_path_tr)\n        self.path_scape = [self.so_path_tr + i for i in lst_sounds]\n        self.path_scape.sort()\n        \n        ''' TEST SANDSCAPE INFORMATION '''\n        COL = [5.57,-75.85,200,'Jardín, Departamento de Antioquia','Colombia']\n        COR = [10.12,-84.51,200,'Alajuela, San Ramón','Costa Rica']\n        SNE = [38.49,-119.95,200,'Sierra Nevada, California','USA'] \n        SSW = [42.47,-76.45,200,'Ithaca, New York','USA']\n        index = ['COL','COR','SNE','SSW']\n        columns = ['latitude','longitude','size','location','country']\n        data = [COL,COR,SNE,SSW]\n        self.df_tsi = pd.DataFrame(data,index=index,columns=columns)\n\n    # Show DataFrame with relevant Training Soundcape Information\n    def info_scape(self,path):\n#         self.load_id = path.split('_')[1].split(\"\\\\\")[1]  # get file identifier name from pathway\n        self.load_id = path.split('_')[1].split(\"/\")[1]  # get file identifier name from pathway\n\n        tdf = self.sscape_audio[self.sscape_audio.audio_id == int(self.load_id)].copy()\n        tdf['time'] = tdf.seconds.apply(lambda x: str(datetime.timedelta(seconds=x)))\n        display(tdf.T)\n        \n    ''' [MAIN] TRAINING FILES RELATED STUFF'''\n\n    # get various subsets of dataframe\n    def get_bird_subset(self,name='acafly'):\n        return self.pd_short_audio[self.pd_short_audio['primary_label'] == name].copy().reset_index()\n    # get rating subset\n    def get_rating_subset(self,rating=2):\n        return self.pd_short_audio[self.pd_short_audio['rating'] == rating].copy().reset_index()\n    # get bird & rating subset\n    def get_bird_rating(self,name='acafly',rating=4):\n        return self.pd_short_audio[(self.pd_short_audio['primary_label'] == name)&(self.pd_short_audio['rating'] == rating)].copy().reset_index()\n\n    # get all birds available in short sound files\n    def get_short_labels(self):\n        primary_labels = self.pd_short_audio.primary_label.unique()\n        primary_labels.sort()\n        return primary_labels\n    \n    # Check where each primary label was observed\n    def check_map(self,ldf,anim,bins):\n        fig = ff.create_hexbin_mapbox(\n            data_frame=ldf, lat=\"latitude\", lon=\"longitude\",nx_hexagon=bins,\n            opacity=0.6,min_count=1, labels={\"color\": \"Point Count\"},\n            color_continuous_scale=\"viridis\",\n            range_color = [0,10],\n            show_original_data=True, # show point data\n            original_data_marker=dict(size=2, opacity=0.05,color='black'),\n            animation_frame = anim, # point data options\n            zoom = 10,height=500)\n        fig2 = go.Scattermapbox(\n                lat=self.df_tsi['latitude'],\n                lon=self.df_tsi['longitude'],\n                text=[self.df_tsi['location'][i]+': Soundscape' for i in range(self.df_tsi.shape[0])],\n                mode='markers',\n                marker=go.scattermapbox.Marker(\n                    size=30,color='rgb(255, 87, 51)',opacity=0.3)\n        )\n        fig.add_trace(fig2)\n        fig.update_layout(\n            hovermode='closest',\n            mapbox=dict(\n                accesstoken=mapbox_access_token,\n                bearing=0,pitch=0,zoom=1))\n        fig.update_layout(title=\"<b>Short Audio Bird Recording Locations</b> | Soundscape Locations\",\n                          margin={\"r\":0,\"t\":80,\"l\":0,\"b\":0},mapbox_style=\"light\");\n        fig.update_layout(coloraxis_showscale=False,showlegend=False);\n        fig.layout.updatemenus[0].pad.t=40;fig.show()\n        \nmain = birdclef()\nmain.pd_short_audio.head(1)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### <b>RECORD PERIOD VARIATION</b>\n- We can check for a given <b>subset</b>, for example, when were audio clips recorded, using the handy plotly map. \n- You can easily create your own functions by modifying the <b>class birdclef</b> above, if you need more specific combinations; \n\nHere are some to get us started (available in the class):\n- <code>def get_bird_subset(self,name='acafly'):</code> to select a specific <b>primary</b> label (specie) subset.\n- <code>def get_rating_subset(self,rating=2):</code> to select a specific rating subset.\n- <code>def get_bird_rating(self,name='acafly',rating=4):</code> to select both a specific <b>primary label</b> & <b>rating</b>.\n\nTo use the class plot, let's simply call main.check_map(), having already instantiated the class, the function needs three arguments\n- <b>dataframe</b> : any of the three above will do, eg. <b>main.get_bird_subset('littin1')</b>\n- <b>animation column</b> : Desired animation column in the dataframe, eg. <b>'date'</b>\n- <b>hexbin size</b> : Some adjustments of the hexbin size may be needed for better visualisation, eg. <b>80</b>\n\nLet's try an example visualisation, in both cases I've limited the amount of data input into the current map to reduce the load on my end.","metadata":{}},{"cell_type":"code","source":"main.get_short_labels()[:10] # get list of primary labels\nmain.check_map(main.get_bird_subset('littin1')[:100],'date',10)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### <b>PRIMARY BIRD SPECIE VARIATION </b>\n- Let's try another example, perhaps a more useful one.\n- We can use the same animation feature, to cycle through all bird species and check their recorded locations.\n- Let's check all recordings with a rating of <b>rating=4</b>, to do that we simply pass <b>'primary_label'</b> to the second argument & some fitting value for the <b>hexbin</b> count.","metadata":{}},{"cell_type":"code","source":"main.check_map(main.get_rating_subset(rating=4)[:100],'primary_label',30)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <sub>III.</sub> <span style='color:#F7765E'><sub>SOUNDSCAPE NOISE EXTRATOR</sub></span>\n- The training soundscape recordings have been annotate by experts for each of the <b>120 segments x 5 seconds/ 20 recordings.</b>\n- Some segments are <b>labelled as a specific primary_label</b> (including multiple primary labels) & others labelled as <b>nocalls</b>.\n- Aside from creating noise during augmentation, recording overlapping & alike , we can utilise the soundscape data and extract <b>nocall</b> segments as well.","metadata":{}},{"cell_type":"code","source":"class cfg:\n\n    # Generate Subset\n    rat_id = 4 # rating subset limiter \n    recs = 200 # each specie must have X recodings\n    max_files = 1500 # general last limit for rows\n    thresh = 0.25 # label probability selection threshold\n    submission = True # For Submission Only (Less Inference Output)\n    \n    # Global vars\n    seed = 1337\n    sr = 32000        # librosa sample rate input\n    sl = 5 # seconds   \n    sshape = (48*3,128*3) # height x width\n    fmin = 500      # spectrum min frequency\n    fmax = 12500    # spectrum max frequency\n    n_epoch = 100   # training epochs\n    cutoff = 600     # 3 sample spectogram (training) overwritten for inference\n    \nos.chdir('../..') # go two back\nBASE_DIR = '/kaggle/input/birdclef-2021/'\nDIR_SPEC_IN = '/kaggle/input/birdclef-2021/train_short_audio/'\nDIR_SPEC_OUT = '/kaggle/working/spec_temp/'\nCSV_IN_TRAIN = '/kaggle/input/birdclef-2021/train_metadata.csv'\nos.getcwd()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Main Data Class\nclass get_subset:\n\n    def __init__(self):\n\n        ''' SHORT TRAINING FILES '''\n        self.__SHORTAUDIO__ = DIR_SPEC_IN\n        # main short audio info CSV file\n        self.pd_short_audio = pd.read_csv(BASE_DIR+'/train_metadata.csv')\n        self.pd_short_audio['path'] = self.__SHORTAUDIO__ + \"/\" + self.pd_short_audio['primary_label'] + '/' + self.pd_short_audio['filename']\n        \n        ''' TRAINING SOUNDSCAPE FILES '''\n        self.__SO_PATH_TR__ = BASE_DIR+'./train_soundscapes/'  # path to train soundcape files\n        self.__SO_PATH_TE__ = BASE_DIR+'./test_soundscapes/'  # path to test soundcape files\n        # main soundscape info CSV file\n        path_soundscape_audio = BASE_DIR+'train_soundscape_labels.csv'   # read soundscape related CSV\n        self.pd_scape = pd.read_csv(path_soundscape_audio)\n\n        # list of filest to soundscape .ogg\n        lst_sounds = os.listdir(self.__SO_PATH_TR__)\n        self.PATH_SCAPE = [self.__SO_PATH_TR__ + i for i in lst_sounds]\n        self.PATH_SCAPE.sort()\n\n    # get all birds available in short sound files\n    def get_short_labels(self):\n        primary_labels = self.pd_short_audio.primary_label.unique()\n        primary_labels.sort()\n        return primary_labels\n\n    # get various subsets of dataframe\n    def get_bird_subset(self,name='acafly'):\n        return self.pd_short_audio[self.pd_short_audio['primary_label'] == name].copy().reset_index()\n    # get rating subset\n    def get_rating_subset(self,rating=2):\n        return self.pd_short_audio[self.pd_short_audio['rating'] == rating].copy().reset_index()\n    # get bird & rating subset\n    def get_bird_rating(self,name='acafly',rating=4):\n        return self.pd_short_audio[(self.pd_short_audio['primary_label'] == name)&(self.pd_short_audio['rating'] == rating)].copy().reset_index()\n    # # show name of primary label\n    def primary_to_common(self,primary='cangoo'):\n        specie = self.pd_short_audio[self.pd_short_audio['primary'] == primary].sample(1)\n        return specie\n\nsubset = get_subset()\n# Training soundscape csv (w/ weak labels)\n# print(subset.pd_scape)\nprint('NUMBER OF NO CALL SEGMENTS AVAILABLE: ')\nprint(subset.pd_scape['birds'].value_counts()[:5])","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"''' CREATE SPECTOGRAMS FROM SOUNDSCAPE DATA '''\n# list_scape -> list of pathways to soundscape files (.ogg)\n# remove_primary -> list of 'primary_labels' weak labels to be removed from data\ndef scape_to_spectogram(lst_scape,remove_primary=None):\n\n    print('1. CREATING ALL TRAINING SPECTOGRAMS w/ WEAK LABELS')\n    path_temp = DIR_SPEC_OUT + 'scape'\n    # before prediction clear read folder if it exists\n    if(os.path.exists(path_temp)):\n        shutil.rmtree(path_temp)\n\n    # for soundcape data, let's change cfg.cutoff to output all segment data\n    cfg.cutoff = 600; lst_remove = []; lst_primary_removed = []\n    with tqdm_notebook(total=len(lst_scape)) as pbar:\n        # loop over all soundcape files available to us\n        for path in lst_scape:\n            pbar.update(1)\n\n            # get dataframe we'll need \n            tid = path.split(os.sep)[-1].rsplit('_', 1)[0].rsplit('_', 1)[0]   # get soundscape id\n            pname = path.split(os.sep)[-1].split('.ogg')[0]               # get soundscape id\n            df_temp = subset.pd_scape[subset.pd_scape.audio_id == int(tid)] # get local soundcape df\n\n            # 1. [MAKE] Get all soundscape spectograms for one soundscape .ogg file \n            get_spectrograms(path,tid,path_temp)\n\n            # 2. [REMOVE] identify & remove spectograms (add pathways) with specified primary weak labels\n            for label in remove_primary:\n                found = df_temp.loc[df_temp['birds'] == label]\n                if(not found.empty):\n                    time_id = found.seconds.unique()\n                    for time in time_id:\n    #                     lst_remove.append('\\\\'+tid+'\\\\'+pname+'_'+str(time)+'.png')\n                        lst_remove.append('/'+tid+'/'+pname+'_'+str(time)+'.png')\n                        lst_primary_removed.append(label)    \n    \n    # [REMOVE] remove all files associated with specie\n    print(\"2. REMOVING SEGMENTS W/ SPECIFIED 'PRIMARY_LABEL' WEAK LABEL\")\n    with tqdm_notebook(total=len(lst_remove)) as pbar:\n        ii=-1\n        for file in lst_remove:\n            pbar.update(1)\n#             print(f'{file} : {lst_primary_removed[ii]}')\n            os.remove(path_temp+file)\n            \n''' CREATE SPECTOGRAMS '''\n# Create Spectograms & Remove Primary Weak Labels\n\nremove_id = subset.get_short_labels().tolist() # get list of all primary_labels\nlst_scape = subset.PATH_SCAPE # get list of soundscape files\n\nscape_to_spectogram(lst_scape,remove_id)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_path_list(TPATH):\n    scape_files = [] \n    SCAPE_FOLDER = os.listdir(TPATH)\n    for folder in SCAPE_FOLDER:\n        onlyfiles = next(os.walk(TPATH+folder))[2] #dir is your directory path as string\n        print(f'{TPATH+folder} : {len(onlyfiles)} files')\n        files = os.listdir(TPATH+folder)\n        for file in files:\n            scape_files.append(file)\n        \nprint('LIST OF AVAILABLE NOCALL SEGMENTS:')\nget_path_list('/kaggle/working/spec_temp/scape/')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Get list of noise samples\ntpath = '/kaggle/working/spec_temp/scape/11254/'\nlst_show = [tpath+i for i in os.listdir(tpath)]\n\n# plot grid of examples\nshow_grid(lst_show,5,6,figsize=(25,15))","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}