{"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 warnings\nwarnings.filterwarnings(action='ignore')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\npd.set_option('display.max_columns', None)\npd.set_option('display.max_colwidth', None)\n\nimport librosa\nimport librosa.display\nimport soundfile as sf\nfrom sklearn.model_selection import train_test_split\nimport plotly.express as px\nfrom plotly.offline import iplot\nimport cufflinks as cf\nimport tensorflow as tf\nimport gc\nimport wave\nfrom scipy.io import wavfile\nfrom IPython.display import Audio\nimport IPython.display as display\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nsns.set_palette('Set3')\n%matplotlib inline\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Input data files are available in the read-only \"../input/\" directory\nimport os\nPATH = '/kaggle/input/birdclef-2021/'\nos.listdir(PATH)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load train data\ntrain_data = pd.read_csv(PATH + 'train_metadata.csv')\nprint(f'Len train data: {len(train_data)}')\ntrain_data.head(3)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load train labels\ntrain_labels = pd.read_csv(PATH + 'train_soundscape_labels.csv')\nprint(f'Len train labels: {len(train_labels)}')\ntrain_labels.head(3)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load test data\ntest_data = pd.read_csv(PATH + 'test.csv')\nprint(f'Len test data: {len(test_data)}')\ntest_data.head(3)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num = 0\nlabel = train_data.loc[num, 'primary_label']\nfn = train_data.loc[num, 'filename']\n\nprint(f'{train_data.iloc[num]}')\nprint(f'Train Data shape={train_data.shape}')\nprint(f'Train Labels shape={train_labels.shape}')\nprint('----------------------------')\nprint(f'{train_data.info()}')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load sample submission\nsample_submission = pd.read_csv(PATH + 'sample_submission.csv')\nprint(f'Len test data: {len(sample_submission)}')\nprint(f\"Birds in train_short_audio: {len(os.listdir(PATH + 'train_short_audio/'))}\")\nprint(f\"Audio files in train_soundscapes: {len(os.listdir(PATH + 'train_soundscapes/'))}\")\nsample_submission.head(3)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Recordings Count by Year\ntrain_data['year'] = train_data['date'].apply(lambda x: x.split('-')[0])\ntrain_data['month'] = train_data['date'].apply(lambda x: x.split('-')[1])\ntrain_data['day'] = train_data['date'].apply(lambda x: x.split('-')[2])\n\ntrain_data['year'] = train_data['year'].apply(lambda x: x if x[:2] in ['19', '20'] else np.nan)\ntrain_data['year'].fillna(train_data['year'].value_counts().index[0], inplace = True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp = train_data['year'].value_counts()\npx.bar(x = temp.index, y = temp.values, title = 'Recordings by Year', \n       labels = {'x': 'Year', 'y': 'Count'})","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load Audio File\nsample_audio = PATH + 'train_short_audio/rucwar/XC133150.ogg'\nsignal, sr = librosa.load(sample_audio)\n\nprint(f'Rate: {sr}')\nprint(f'Signal: {signal}')\nprint(f'Lenght: {len(signal)}')\nprint(f'Duration signal: {round(len(signal)/sr, 3)}')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"signal, _ = librosa.load(sample_audio, sr = 44100, duration = 20)\n\n# Signal\nplt.figure(figsize=(10, 6))\nlibrosa.display.waveplot(signal)\nplt.xlabel('Time')\nplt.ylabel('Amplitude')\nplt.show()\n\n# Melspectrogram\nplt.figure(figsize=(10, 6))\nmels = librosa.feature.melspectrogram(y = signal, sr = 44100, n_mels = 256, fmax = 8000)\nlibrosa.display.specshow(librosa.power_to_db(mels, ref = np.max), x_axis = 'time', y_axis = 'mel')\nplt.title('Melspectrogram')\nplt.colorbar()\nplt.show()\n\n# Fourier Transform\nplt.figure(figsize = (10, 6))\nstft = librosa.stft(y = signal)\nstft_db = librosa.amplitude_to_db(stft)\nlibrosa.display.specshow(stft_db, x_axis = 'time', y_axis = 'hz')\nplt.title('Spectrogram - STFT')\nplt.colorbar()\nplt.show()\n\n#Log Frequency Axis\nplt.figure(figsize = (10, 6))\nlibrosa.display.specshow(stft_db, sr = 44100, x_axis = 'time', y_axis = 'log')\nplt.colorbar()\nplt.title('Log Frequency Axis')\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Audio(sample_audio, rate = 44100)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check the birds and their associated audio files\naudio_path = PATH + 'train_short_audio/'\nbirds_audio = {}\nfor bird in os.listdir(audio_path):\n    birds_audio[bird] = len(os.listdir(audio_path + bird))\nbirds_df = pd.DataFrame(birds_audio.items())\nbirds_df.columns = ['Birds', 'Num_Audio']\nbirds_df = birds_df.sort_values(by = 'Num_Audio', ascending = False)\npx.bar(birds_df, x = 'Birds', y = 'Num_Audio')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Bird Recording Location on World Map\nimport geopandas as gpd\ngdf = gpd.GeoDataFrame(train_data, geometry=gpd.points_from_xy(train_data.longitude,train_data.latitude)) \n\nworld = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))\nfig,ax = plt.subplots(figsize=(24,12))\nworld.plot(ax=ax, color='black', edgecolor='black')\ngdf.plot(ax=ax, color='red', markersize=2)\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Extract all label of the train data\nlabels = []\nfor row in train_labels.index:\n    labels.extend(train_labels.loc[row, 'birds'].split(' '))\nlabels = list(set(labels))\n\nprint(f'Len of unique bird labels: {len(labels)}')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Encode the labels\ndf_encode = pd.DataFrame(index=train_labels.index, columns=labels)\nfor row in train_labels.index:\n    birds = train_labels.loc[row, 'birds'].split(' ')\n    for bird in birds:\n        df_encode.loc[row, bird] = 1\ndf_encode.fillna(0, inplace=True)\n\n#  Set a dummy value for the target label in the test data\ntest_data['birds'] = 'nocall'\n\ndf_labels_test = pd.DataFrame(index=test_data.index, columns=labels)\nfor row in test_data.index:\n    birds = test_data.loc[row, 'birds'].split(' ')\n    for bird in birds:\n        df_labels_test.loc[row, bird] = 1\ndf_labels_test.fillna(0, inplace=True)\n\ntrain_labels = pd.concat([train_labels, df_encode], axis=1)\ntest_data = pd.concat([test_data, df_labels_test], axis=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"file = os.listdir(PATH+'train_soundscapes')[0]\naudio_id = file.split('_')[0]\nsite = file.split('_')[1]\nprint('audio_id:', audio_id, ', site:', site)\ntrain_labels[(train_labels['audio_id']==int(audio_id)) & (train_labels['site']==site) \n             & (train_labels['birds']!='nocall')]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras.utils import Sequence, to_categorical, plot_model\nfrom keras.models import Sequential\nfrom keras.layers import Dense, Dropout, Flatten, Conv1D, MaxPool1D, BatchNormalization\nfrom keras.optimizers import RMSprop, Adam\nfrom keras.applications import VGG19, VGG16, ResNet50","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Parameters\ndata_lenght = 160000\naudio_lenght = 5\nnum_labels = len(labels)\nbatch_size = 16","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Split data to train, val, test\ntrain, val = train_test_split(list(train_labels.index), test_size=0.3, random_state=2021)\ntest = list(sample_submission.index)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Read file and return np.array\ndef get_read_file(PATH, fn):\n    date, sample_rate = sf.read(PATH + fn)\n    return date, sample_rate\n\n# Built Audio Generator\nclass AudioDataGen(tf.keras.utils.Sequence):\n    def __init__(self, PATH, id_, data, batch_size):\n        self.data = data\n        self.id_ = id_\n        self.path = PATH\n        self.batch_size = batch_size\n        self.indexes = np.arange(len(self.id_))\n        \n    def __len__(self):\n        len_ = int(len(self.id_)/self.batch_size)\n        if len_*self.batch_size < len(self.id_):\n            len_ += 1\n        return len_\n    \n    def __getitem__(self, index):\n        indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]\n        id_temp = [self.id_[k] for k in indexes]\n        X, y = self.__data_generation(id_temp)\n        X = X.reshape((self.batch_size, 100, 1600//2))\n        return X, y\n    \n    def __data_generation(self, id_temp):\n        X = np.zeros((self.batch_size, data_lenght//2))\n        y = np.zeros((self.batch_size, num_labels))\n        for i, ID in enumerate(id_temp):\n            prefix = str(self.data.loc[ID, 'audio_id'])+'_'+self.data.loc[ID, 'site']\n            file_list = [s for s in os.listdir(self.path) if prefix in s]\n            if len(file_list) == 0:\n                audio_file_fft = np.zeros((data_lenght//2))\n            else:\n                file = file_list[0]\n                audio_file, audio_sr = get_read_file(self.path, file)\n                audio_file = audio_file[int((self.data.loc[ID, 'seconds']-5)/audio_lenght)*data_lenght:int(self.data.loc[ID, 'seconds']/audio_lenght)*data_lenght]\n                audio_file_fft = np.abs(np.fft.fft(audio_file)[: len(audio_file)//2])\n                audio_file_fft = (audio_file_fft-audio_file_fft.mean())/audio_file_fft.std()\n            X[i, ] = audio_file_fft\n            y[i, ] = self.data.loc[ID, self.data.columns[5:]].values\n        return X,y","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Get data from AudioDataGen\ntrain_gen = AudioDataGen(PATH+'train_soundscapes/', train, train_labels, batch_size)\nval_gen = AudioDataGen(PATH+'train_soundscapes/', val, train_labels, batch_size)\ntest_gen = AudioDataGen(PATH+'test_soundscapes/', test, test_data, batch_size)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create model\ndef create_model_first():\n    model = Sequential()\n    model.add(Conv1D(64, input_shape=(100, 1600//2,), kernel_size=5, strides=4, activation='relu'))\n    model.add(BatchNormalization())\n    model.add(MaxPool1D(pool_size=(4)))\n    model.add(Conv1D(64, kernel_size=3, activation='relu'))\n    model.add(BatchNormalization())\n    model.add(Flatten())\n    model.add(Dense(256, activation='relu'))\n    model.add(Dense(len(labels), activation='sigmoid'))\n    model.compile(optimizer=Adam(lr=2e-3), loss='binary_crossentropy', metrics=['binary_accuracy'])\n    return model","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = create_model_first()\nmodel.summary()\nplot_model(model, to_file='model.png')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit_generator(generator=train_gen, validation_data=val_gen, epochs=5, workers=4)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.history[\"binary_accuracy\"])\nplt.plot(history.history[\"val_binary_accuracy\"])\nsns.set()\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.save('./best_model.h5')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred = model.predict_generator(test_gen, verbose=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Test model\ny_test = np.where(y_pred > 0.5, 1, 0)\n\nfor row in sample_submission.index:\n    string = ''\n    for col in range(len(y_test[row])):\n        if y_test[row][col] == 1:\n            if string == '':\n                string += labels[col]\n            else:\n                string += ' ' + labels[col]\n    if string == '':\n        string = 'nocall'\n    sample_submission.loc[row, 'birds'] = string","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"output = sample_submission\noutput.to_csv('submission.csv', index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"output","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}