{"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\n\nimport warnings\nwarnings.filterwarnings(action='ignore')\n\nimport pandas as pd\nimport librosa\nimport numpy as np\n\nimport seaborn as sns \n\nfrom sklearn.utils import shuffle\nfrom PIL import Image\nfrom tqdm import tqdm\nimport matplotlib.pyplot as plt\n\nimport tensorflow as tf\n\n# Global vars\nRANDOM_SEED = 1337\nSAMPLE_RATE = 32000\nSIGNAL_LENGTH = 5 # seconds\nSPEC_SHAPE = (48, 128) # height x width\nFMIN = 500\nFMAX = 12500\nMAX_AUDIO_FILES = 5000","metadata":{"execution":{"iopub.status.busy":"2021-06-07T11:25:04.232673Z","iopub.execute_input":"2021-06-07T11:25:04.233381Z","iopub.status.idle":"2021-06-07T11:25:12.969821Z","shell.execute_reply.started":"2021-06-07T11:25:04.233225Z","shell.execute_reply":"2021-06-07T11:25:12.968237Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = pd.read_csv('../input/birdclef-2021/train_metadata.csv',)","metadata":{"execution":{"iopub.status.busy":"2021-06-07T11:25:12.973091Z","iopub.execute_input":"2021-06-07T11:25:12.973562Z","iopub.status.idle":"2021-06-07T11:25:13.540724Z","shell.execute_reply.started":"2021-06-07T11:25:12.973514Z","shell.execute_reply":"2021-06-07T11:25:13.539531Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f'Number of species in the data {train.primary_label.nunique()}')\n\n#plot of ratings of audio data :\nplt.figure(figsize=(16,8))\nsns.countplot(x=train.rating,data=train)\nplt.title('Recordings Ratings')","metadata":{"execution":{"iopub.status.busy":"2021-06-07T11:25:13.542822Z","iopub.execute_input":"2021-06-07T11:25:13.543131Z","iopub.status.idle":"2021-06-07T11:25:13.895599Z","shell.execute_reply.started":"2021-06-07T11:25:13.543101Z","shell.execute_reply":"2021-06-07T11:25:13.894342Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"highest_recorded=train['common_name'].value_counts().sort_values(ascending=False)[:20]\nleast_recorded=train['common_name'].value_counts().sort_values()[:20]\n\nplt.subplots(2,1,figsize=(16,16))\n\nplt.subplot(2,1,1)\nplt.bar(x=highest_recorded.index,height=highest_recorded.values)\nplt.xticks(rotation=45)\nplt.ylabel('Count')\nplt.title('Most Recorded birds')\n\nplt.subplot(2,1,2)\nplt.bar(x=least_recorded.index,height=least_recorded.values)\nplt.xticks(rotation=45)\nplt.ylabel('Count')\nplt.title('Least Recorded birds')\n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-07T11:25:13.89807Z","iopub.execute_input":"2021-06-07T11:25:13.898545Z","iopub.status.idle":"2021-06-07T11:25:14.81348Z","shell.execute_reply.started":"2021-06-07T11:25:13.898496Z","shell.execute_reply":"2021-06-07T11:25:14.812444Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = train.query('rating>=3') # High quality samples\n\nbirds_count = {}\nfor bird_species, count in zip(train.primary_label.unique(), \n                               train.groupby('primary_label')['primary_label'].count().values):\n    birds_count[bird_species] = count\nmost_represented_birds = [key for key,value in birds_count.items() if value >= 30] \n\nTRAIN = train.query('primary_label in @most_represented_birds')\nLABELS = sorted(TRAIN.primary_label.unique())\n\nprint('NUMBER OF SPECIES IN TRAIN DATA:', len(LABELS))\nprint('NUMBER OF SAMPLES IN TRAIN DATA:', len(TRAIN))\nprint('LABELS:', most_represented_birds)","metadata":{"execution":{"iopub.status.busy":"2021-06-07T11:25:14.815055Z","iopub.execute_input":"2021-06-07T11:25:14.815743Z","iopub.status.idle":"2021-06-07T11:25:14.900432Z","shell.execute_reply.started":"2021-06-07T11:25:14.815703Z","shell.execute_reply":"2021-06-07T11:25:14.899017Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Split signal function:","metadata":{}},{"cell_type":"code","source":"def split_sig(sig):\n    sig_splits = []\n    for i in range(0, len(sig), int(SIGNAL_LENGTH * SAMPLE_RATE)):\n        split = sig[i:i + int(SIGNAL_LENGTH * SAMPLE_RATE)]\n        \n        # End of signal?\n        if len(split) < int(SIGNAL_LENGTH * SAMPLE_RATE):\n            break\n\n        sig_splits.append(split)\n    return sig_splits","metadata":{"execution":{"iopub.status.busy":"2021-06-07T11:25:14.901884Z","iopub.execute_input":"2021-06-07T11:25:14.902228Z","iopub.status.idle":"2021-06-07T11:25:14.908357Z","shell.execute_reply.started":"2021-06-07T11:25:14.902195Z","shell.execute_reply":"2021-06-07T11:25:14.907372Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TRAIN = shuffle(TRAIN, random_state=RANDOM_SEED)[:MAX_AUDIO_FILES]\n\ndef get_spectrograms(filepath, primary_label, output_dir):\n    \n    sig, rate = librosa.load(filepath, sr=SAMPLE_RATE, offset=None, duration=15)\n    \n    sig_splits = split_sig(sig)\n    \n    s_cnt = 0\n    saved_samples = []\n    for chunk in sig_splits:\n        \n        hop_length = int(SIGNAL_LENGTH * SAMPLE_RATE / (SPEC_SHAPE[1] - 1))\n        mel_spec = librosa.feature.melspectrogram(y=chunk, \n                                                  sr=SAMPLE_RATE, \n                                                  n_fft=1024, \n                                                  hop_length=hop_length, \n                                                  n_mels=SPEC_SHAPE[0], \n                                                  fmin=FMIN, \n                                                  fmax=FMAX)\n    \n        mel_spec = librosa.power_to_db(mel_spec, 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        \n        saved_samples.append(save_path)\n        s_cnt += 1\n        \n        \n    return saved_samples\n\nprint('FINAL NUMBER OF AUDIO FILES IN TRAINING DATA:', len(TRAIN))","metadata":{"execution":{"iopub.status.busy":"2021-06-07T11:25:14.909693Z","iopub.execute_input":"2021-06-07T11:25:14.91Z","iopub.status.idle":"2021-06-07T11:25:14.949975Z","shell.execute_reply.started":"2021-06-07T11:25:14.90997Z","shell.execute_reply":"2021-06-07T11:25:14.949065Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"input_dir = '../input/birdclef-2021/train_short_audio/'\noutput_dir = '../working/melspectrogram_dataset/'\nsamples = []\nwith tqdm(total=len(TRAIN)) as pbar:\n    for idx, row in TRAIN.iterrows():\n        pbar.update(1)\n        \n        if row.primary_label in most_represented_birds:\n            audio_file_path = os.path.join(input_dir, row.primary_label, row.filename)\n            samples += get_spectrograms(audio_file_path, row.primary_label, output_dir)\n            \nTRAIN_SPECS = shuffle(samples, random_state=RANDOM_SEED)\nprint('SUCCESSFULLY EXTRACTED {} SPECTROGRAMS'.format(len(TRAIN_SPECS)))","metadata":{"execution":{"iopub.status.busy":"2021-06-07T11:25:14.951509Z","iopub.execute_input":"2021-06-07T11:25:14.951858Z","iopub.status.idle":"2021-06-07T11:32:07.566568Z","shell.execute_reply.started":"2021-06-07T11:25:14.951829Z","shell.execute_reply":"2021-06-07T11:32:07.55967Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(20, 10))\nfor i in range(24):\n    spec = Image.open(TRAIN_SPECS[i])\n    plt.subplot(6, 4, i + 1)\n    plt.axis('off')\n    plt.title(TRAIN_SPECS[i].split(os.sep)[-1])\n    plt.imshow(spec, origin='lower')","metadata":{"execution":{"iopub.status.busy":"2021-06-07T11:32:07.583126Z","iopub.execute_input":"2021-06-07T11:32:07.584485Z","iopub.status.idle":"2021-06-07T11:32:10.528455Z","shell.execute_reply.started":"2021-06-07T11:32:07.584249Z","shell.execute_reply":"2021-06-07T11:32:10.527239Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_specs, train_labels = [], []\nwith tqdm(total=len(TRAIN_SPECS)) as pbar:\n    for path in TRAIN_SPECS:\n        pbar.update(1)\n\n        spec = Image.open(path)\n\n        spec = np.array(spec, dtype='float32')\n        \n        spec -= spec.min()\n        spec /= spec.max()\n        if not spec.max() == 1.0 or not spec.min() == 0.0:\n            continue\n\n        spec = np.expand_dims(spec, -1)\n\n        spec = np.expand_dims(spec, 0)\n\n        if len(train_specs) == 0:\n            train_specs = spec\n        else:\n            train_specs = np.vstack((train_specs, spec))\n\n        target = np.zeros((len(LABELS)), dtype='float32')\n        bird = path.split(os.sep)[-2]\n        target[LABELS.index(bird)] = 1.0\n        if len(train_labels) == 0:\n            train_labels = target\n        else:\n            train_labels = np.vstack((train_labels, target))","metadata":{"execution":{"iopub.status.busy":"2021-06-07T11:32:10.531051Z","iopub.execute_input":"2021-06-07T11:32:10.531887Z","iopub.status.idle":"2021-06-07T11:56:31.149709Z","shell.execute_reply.started":"2021-06-07T11:32:10.531837Z","shell.execute_reply":"2021-06-07T11:56:31.148677Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_labels.shape","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf.random.set_seed(RANDOM_SEED)\n\n# CONV --> RELU --> BNORM --> MAXPOOL.\nmodel = tf.keras.Sequential([\n    \n    # liczba conv block\n    #rozmiar okienka\n    #MaxPooling -> AveragePooling\n    #Dense block 256-> 64,\n    \n    # First conv block\n    tf.keras.layers.Conv2D(16, (3, 3), activation='relu', \n                           input_shape=(SPEC_SHAPE[0], SPEC_SHAPE[1], 1)),\n    tf.keras.layers.BatchNormalization(),\n    tf.keras.layers.MaxPooling2D((2, 2)),\n    \n     tf.keras.layers.Dropout(0.08),  \n    \n    # Second conv block\n    tf.keras.layers.Conv2D(32, (3, 3), activation='relu'),\n    tf.keras.layers.BatchNormalization(),\n    tf.keras.layers.MaxPooling2D((2, 2)), \n    \n     tf.keras.layers.Dropout(0.08),  \n    \n    # Third conv block\n    tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),\n    tf.keras.layers.BatchNormalization(),\n    tf.keras.layers.MaxPooling2D((2, 2)), \n    \n    tf.keras.layers.Dropout(0.08),  \n    \n    # Fourth conv block\n    tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),\n    tf.keras.layers.BatchNormalization(),\n    tf.keras.layers.MaxPooling2D((2, 2)),\n    \n    # Global pooling instead of flatten()\n    tf.keras.layers.GlobalAveragePooling2D(), \n      \n    tf.keras.layers.Dropout(0.05),  \n    \n    # Classification layer\n    tf.keras.layers.Dense(len(LABELS), activation='softmax')\n])\nprint('MODEL HAS {} PARAMETERS.'.format(model.count_params()))","metadata":{"execution":{"iopub.status.busy":"2021-06-07T11:56:31.151444Z","iopub.execute_input":"2021-06-07T11:56:31.151763Z","iopub.status.idle":"2021-06-07T11:56:31.425371Z","shell.execute_reply.started":"2021-06-07T11:56:31.151729Z","shell.execute_reply":"2021-06-07T11:56:31.423983Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.008),  #zalezy od zadania\n              loss=tf.keras.losses.CategoricalCrossentropy(label_smoothing=0.01),\n              metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2021-06-07T11:56:31.427032Z","iopub.execute_input":"2021-06-07T11:56:31.427397Z","iopub.status.idle":"2021-06-07T11:56:31.451312Z","shell.execute_reply.started":"2021-06-07T11:56:31.427362Z","shell.execute_reply":"2021-06-07T11:56:31.449946Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"callbacks = [tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', \n                                                  patience=2, \n                                                  verbose=1, \n                                                  factor=0.5),\n             tf.keras.callbacks.EarlyStopping(monitor='val_loss', \n                                              verbose=1,\n                                              patience=10),\n             tf.keras.callbacks.ModelCheckpoint(filepath='best_model.h5', \n                                                monitor='val_loss',\n                                                verbose=0,\n                                                save_best_only=True)]","metadata":{"execution":{"iopub.status.busy":"2021-06-07T11:56:31.453297Z","iopub.execute_input":"2021-06-07T11:56:31.453755Z","iopub.status.idle":"2021-06-07T11:56:31.460627Z","shell.execute_reply.started":"2021-06-07T11:56:31.453708Z","shell.execute_reply":"2021-06-07T11:56:31.459601Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Train\nhistory = model.fit(train_specs, \n                  train_labels,\n                  batch_size=32,\n                  validation_split=0.2, # sprobowac 0.1\n                  callbacks=callbacks,\n                  epochs=50) # nie wiecej niz 100, ale tak zeby loss byl mn w staly","metadata":{"execution":{"iopub.status.busy":"2021-06-07T11:56:31.461817Z","iopub.execute_input":"2021-06-07T11:56:31.462275Z","iopub.status.idle":"2021-06-07T12:19:55.789463Z","shell.execute_reply.started":"2021-06-07T11:56:31.462241Z","shell.execute_reply":"2021-06-07T12:19:55.788178Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.history['loss'])\nplt.plot(history.history['val_loss'])\nplt.title('model loss')\nplt.ylabel('loss')\nplt.xlabel('epoch')\nplt.legend(['train', 'val'], loc='upper left')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-07T12:19:55.79139Z","iopub.execute_input":"2021-06-07T12:19:55.791722Z","iopub.status.idle":"2021-06-07T12:19:55.9789Z","shell.execute_reply.started":"2021-06-07T12:19:55.791689Z","shell.execute_reply":"2021-06-07T12:19:55.977709Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.history['accuracy'])\nplt.plot(history.history['val_accuracy'])\nplt.title('model accuracy')\nplt.ylabel('accuracy')\nplt.xlabel('epoch')\nplt.legend(['train', 'val'], loc='upper left')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-07T12:19:55.980375Z","iopub.execute_input":"2021-06-07T12:19:55.980672Z","iopub.status.idle":"2021-06-07T12:19:56.142097Z","shell.execute_reply.started":"2021-06-07T12:19:55.980642Z","shell.execute_reply":"2021-06-07T12:19:56.140786Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = tf.keras.models.load_model('best_model.h5')\n\n\nsoundscape_path = '../input/birdclef-2021/train_soundscapes/28933_SSW_20170408.ogg'\n\n\nsig, rate = librosa.load(soundscape_path, sr=SAMPLE_RATE)\n\n# Store results\ndata = {'row_id': [], 'prediction': [], 'score': [], 'prediction2': [], 'score2': [], 'p': []}\n\n\nsig_splits = split_sig(sig)\n\n\nseconds, scnt = 0, 0\nfor chunk in sig_splits:\n    seconds += 5\n        \n    # Get the spectrogram\n    hop_length = int(SIGNAL_LENGTH * SAMPLE_RATE / (SPEC_SHAPE[1] - 1))\n    mel_spec = librosa.feature.melspectrogram(y=chunk, \n                                              sr=SAMPLE_RATE, \n                                              n_fft=1024, \n                                              hop_length=hop_length, \n                                              n_mels=SPEC_SHAPE[0], \n                                              fmin=FMIN, \n                                              fmax=FMAX)\n\n    mel_spec = librosa.power_to_db(mel_spec, ref=np.max) \n\n\n    mel_spec -= mel_spec.min()\n    mel_spec /= mel_spec.max()\n    \n\n    mel_spec = np.expand_dims(mel_spec, -1)\n\n    mel_spec = np.expand_dims(mel_spec, 0)\n    \n    # Predict\n    p = model.predict(mel_spec)[0]\n    \n    data['p'].append(p)\n    \n    idx = p.argmax()\n    species = LABELS[idx]\n    score = p[idx]\n\n    data['row_id'].append(soundscape_path.split(os.sep)[-1].rsplit('_', 1)[0] + \n                          '_' + str(seconds))    \n    \n    #\"nocall\"\n    if score > 0.25:\n        data['prediction'].append(species)\n        scnt += 1\n    else:\n        data['prediction'].append('nocall')\n        \n    \n    data['score'].append(score)\n    \n    p[idx] = 0\n    \n    idx = p.argmax()\n    species = LABELS[idx]\n    score = p[idx]\n    \n    if score > 0.15:\n        data['prediction2'].append(species)\n        scnt += 1\n    else:\n        data['prediction2'].append('')\n        \n    data['score2'].append(score)\n\n        \nprint('SOUNSCAPE ANALYSIS DONE. FOUND {} BIRDS.'.format(scnt))","metadata":{"execution":{"iopub.status.busy":"2021-06-07T12:19:56.143608Z","iopub.execute_input":"2021-06-07T12:19:56.143942Z","iopub.status.idle":"2021-06-07T12:20:06.381014Z","shell.execute_reply.started":"2021-06-07T12:19:56.143911Z","shell.execute_reply":"2021-06-07T12:20:06.376717Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Make a new data frame\nresults = pd.DataFrame(data, columns = ['row_id', 'prediction', 'score', 'prediction2', 'score2'])\n\n# Merge with ground truth so we can inspect\ngt = pd.read_csv('../input/birdclef-2021/train_soundscape_labels.csv',)\nresults = pd.merge(gt, results, on='row_id')","metadata":{"execution":{"iopub.status.busy":"2021-06-07T12:20:06.383156Z","iopub.execute_input":"2021-06-07T12:20:06.383596Z","iopub.status.idle":"2021-06-07T12:20:06.432869Z","shell.execute_reply.started":"2021-06-07T12:20:06.383551Z","shell.execute_reply":"2021-06-07T12:20:06.432102Z"},"trusted":true},"execution_count":null,"outputs":[]}]}