{"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 numpy as np\nimport pandas as pd\nimport os\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport IPython.display as ipd\nfrom tqdm import tqdm\nfrom PIL import Image\nimport tensorflow as tf\nimport cv2\nimport skimage.io\n\n#to play audio\nimport librosa\nimport librosa.display\nimport sklearn.model_selection as sk\nimport tensorflow as tf\nfrom keras.callbacks import EarlyStopping\nfrom keras.callbacks import ModelCheckpoint","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_datadir = \"../input/birdclef-2021/train_short_audio\"\nsoundscapes = '../input/birdclef-2021/train_soundscapes'\ntrain_csv = \"../input/birdclef-2021/train_metadata.csv\"\ntest_csv = \"../input/birdclef-2021/test.csv\"\ntrain_soundscape = \"../input/birdclef-2021/train_soundscape_labels.csv\"\noutput_dir = \"../output/kaggle/working\"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_rate = 32000\nduration = 10.0\noffset = 1.0\nhop_length = 512 # number of samples per time-step in spectrogram\nn_mels = 128 # number of bins in spectrogram. Height of image\ntime_steps = 384 # number of time-steps. Width of image\nthreshold = 0.01","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train_metadata = pd.read_csv(train_csv)\ndf_train_soundscape = pd.read_csv(train_soundscape)\ndf_test = pd.read_csv(test_csv)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train_metadata.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train_metadata.hist(column='rating', figsize=(10, 5))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train_metadata['primary_label'].value_counts()[:100].plot(kind=\"bar\", figsize=(20, 10), rot=90)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train_soundscape.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def scale_minmax(x, min=0.0, max=1.0):\n    x_std = (x - x.min()) / (x.max() - x.min())\n    x_scaled = x_std * (max - min) + min\n    return x_scaled","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def spectrogram_image(y, sr, out, hop_length, n_mels):\n    # use log-melspectrogram\n    mels = librosa.feature.melspectrogram(\n        y=y, \n        sr=sr, \n        n_mels=n_mels,                   \n        n_fft=hop_length*2, \n        hop_length=hop_length\n    )\n    mels = np.log(mels + 1e-9) # add small number to avoid log(0)\n\n    # min-max scale to fit inside 8-bit range\n    img = scale_minmax(mels, 0, 255).astype(np.uint8)\n    img = np.flip(img, axis=0) # put low frequencies at the bottom in image\n    img = 255-img # invert. make black==more energy\n\n    # save as PNG\n    skimage.io.imsave(out, img)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def extract_links_and_labels(data_dir):\n    audio_clips = []\n    folder_names = []\n    file_names = []\n    birds = os.listdir(data_dir)\n    labels = []\n\n    for bird in birds:\n        for clip in os.listdir(data_dir + \"/\" + bird):\n            folder_names.append(bird)\n            file_names.append(clip.split(\".ogg\")[0])\n            audio_clips.append(data_dir +  \"/\" + bird + \"/\" + clip)\n            labels.append(bird)\n    \n    return folder_names, file_names, audio_clips, labels","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"folder_names, file_names, train_audio_clips, labels = extract_links_and_labels(train_datadir)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_audio_clips = []\nfolder_names = []\nfile_names = []\nbirds = os.listdir(train_datadir)\nlabels = []\n\nfor bird in birds:\n    for clip in os.listdir(train_datadir +  \"/\" + bird):\n        folder_names.append(bird)\n        file_names.append(clip.split(\".ogg\")[0])\n        train_audio_clips.append(train_datadir +  \"/\" + bird + \"/\" + clip)\n        labels.append(bird)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!rm -rf kaggle/working","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!mkdir train_images","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def extract_spectogram(path, folder_name, file_name):\n    start_sample = 0 # starting at beginning\n    length_samples = time_steps * hop_length\n    counter = 0\n    y, sr = librosa.load(path, offset=offset, duration=duration, sr=sample_rate)\n    while (start_sample <= len(y) and start_sample + length_samples <= len(y)):\n        # extract a fixed length window\n        window = y[start_sample: start_sample + length_samples]\n        # convert to PNG\n        if not os.path.exists('train_images/' + folder_name):\n            os.makedirs('train_images/' + folder_name)\n        spectrogram_image(window, \n                          sr=sr, \n                          out='train_images/' + folder_name + \"/\" + file_name + \"_\" + str(counter) + \".png\", \n                          hop_length=hop_length, \n                          n_mels=n_mels)\n        start_sample = start_sample + length_samples\n        counter += 1","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"extract_spectogram(train_audio_clips[0], folder_names[0], file_names[0])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for i in tqdm(range(len(train_audio_clips))):\n    extract_spectogram(train_audio_clips[i], folder_names[i], file_names[i])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def imagetensor(imagedir):  \n    for i, im in enumerate(os.listdir(imagedir)):\n\n        image= cv2.imread(os.path.join(imagedir, im), 0)\n        image.resize(32, 96)\n#         image = image.resize(48,144)\n#         print(image.shape)\n\n        if i == 0:\n            images= np.expand_dims(np.array(image, dtype= float) / 255, axis= 0)\n        else:\n            image= np.expand_dims(np.array(image, dtype= float) / 255, axis= 0)\n            images= np.append(images, image, axis= 0)\n    return images","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels = []\nfor label in os.listdir('./train_images/'):\n    if (not '.ipynb' in label and \n        not 'h5'in label and \n        not '.npy' in label and \n        not '.txt' in label and \n        not 'out' in label):\n        labels.append(label)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(labels)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x_train = np.array([])\ny_train = []\nfor idx, label in tqdm(enumerate(tqdm(labels))):\n    if idx == 0:\n        x_train= imagetensor('./train_images/' + label)\n        y_train.extend([label] * len(x_train))\n    else:\n        images = imagetensor('./train_images/' + label)\n        y_train.extend([label] * len(images))\n        x_train = np.vstack((x_train, images))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(len(x_train), len(y_train))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"inputs = x_train.reshape((61440, 32, 96, 1))\noutputs = pd.get_dummies(pd.Series(y_train)).to_numpy()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(inputs.shape)\nprint(outputs.shape)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"np.savez_compressed('batch_reduced_32_96', x=inputs, y=outputs)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"b = os.path.getsize(\"batch_reduced_32_96.npz\")\nprint(b)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_1 = np.load('batch_reduced_32_96.npz')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"inputs = batch_1['x']\noutputs = batch_1['y']","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# x_train, x_val, y_train, y_val = sk.train_test_split(inputs, outputs, test_size=0.2, random_state = 42)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# print(x_train.shape, y_train.shape, x_val.shape, y_val.shape)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"SPEC_SHAPE = inputs[0].shape\nOUTPUT_SHAPE = outputs[0].shape\nSEED = 8000","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.utils import shuffle\ninputs, outputs = shuffle(inputs, outputs)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Make sure your experiments are reproducible\ntf.random.set_seed(SEED)\n\n# Build a simple model as a sequence of  convolutional blocks.\n# Each block has the sequence CONV --> RELU --> BNORM --> MAXPOOL.\n# Finally, perform global average pooling and add 2 dense layers.\n# The last layer is our classification layer and is softmax activated.\n# (Well it's a multi-label task so sigmoid might actually be a better choice)\nmodel = tf.keras.Sequential([\n    \n    # First conv block\n    tf.keras.layers.Conv2D(16, (3, 3), \n                           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    # 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    # 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#     # Fourth 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    # Global pooling instead of flatten()\n    tf.keras.layers.GlobalAveragePooling2D(), \n    \n    # Dense block\n    tf.keras.layers.Dense(128, activation='relu'),   \n    tf.keras.layers.Dropout(0.5),  \n    tf.keras.layers.Dense(128, activation='relu'),   \n    tf.keras.layers.Dropout(0.5),\n    \n    # Classification layer\n    tf.keras.layers.Dense(OUTPUT_SHAPE[0], activation='softmax')\n])\nprint('MODEL HAS {} PARAMETERS.'.format(model.count_params()))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Compile the model and specify optimizer, loss and metric\ninitial_learning_rate = 0.1\ndecay_steps = 1.0\ndecay_rate = 0.5\nlearning_rate_fn = tf.keras.optimizers.schedules.InverseTimeDecay(\n  initial_learning_rate, decay_steps, decay_rate\n)\nmodel.compile(\n    optimizer=tf.keras.optimizers.Adam(learning_rate=0.0015),\n    loss=tf.keras.losses.CategoricalCrossentropy(),\n    metrics=['accuracy', tf.keras.metrics.AUC()]\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"early_stopping_monitor = EarlyStopping(\n    monitor='val_accuracy',\n    patience=30,\n    verbose=1,\n    mode='auto',\n    restore_best_weights=True\n)\n\nmcp_save = ModelCheckpoint(\n    './best_model.h5', \n    save_best_only=True, \n    monitor='val_accuracy',\n    verbose=1\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.fit(\n    inputs, \n    outputs, \n    epochs=100,\n    batch_size=256, \n    validation_split=0.2, \n    callbacks=[early_stopping_monitor, mcp_save]\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!rm rf train_soundscapes","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!mkdir train_soundscapes_2","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"soundscape_links = []\nfilenames = []\nfor soundscape in os.listdir(soundscapes):\n    soundscape_link = soundscapes + '/' + soundscape\n    soundscape_links.append(soundscape_link)\n    filenames.append(soundscape.split('.')[0])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(soundscape_links[0])\nprint(filenames[0])\noutput_links = []","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def extract_soundscape_spectogram(path, file_name):\n    start_sample = 0 # starting at beginning\n    length_samples = time_steps * hop_length\n    y, sr = librosa.load(path, offset=offset, duration=duration, sr=sample_rate)\n    counter = 5\n#     output_links = []\n    while (start_sample <= len(y) and start_sample + length_samples <= len(y)):\n        # extract a fixed length window\n        window = y[start_sample: start_sample + length_samples]\n        # convert to PNG\n        spectrogram_image(window, \n                          sr=sr, \n                          out='train_soundscapes_2/' + file_name + \"_\" + str(counter) + \".png\", \n                          hop_length=hop_length, \n                          n_mels=n_mels)\n        start_sample = start_sample + length_samples\n        output_links.append(file_name + \"_\" + str(counter) + \".png\")\n        counter += 5","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for i in tqdm(range(len(soundscape_links))):\n    extract_soundscape_spectogram(soundscape_links[i], filenames[i])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(soundscape_links), len(output_links)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"output_links","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x_test = imagetensor('./train_soundscapes_2/')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x_test.shape","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x_test = x_test.reshape((20, 32, 96, 1))\nnp.savez_compressed('test_reduced_32_96', x=x_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow import keras\nmodel = keras.models.load_model('./best_model.h5')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"p = model.predict(x_test)\ny_prob = np.argmax(p, axis=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = []\nfor i in range(len(p)):\n    data = {}\n    label = output_links[i].split('_')[0] + '_' + output_links[i].split('_')[1] + '_' + output_links[i].split('_')[-1].split('.png')[0]\n    data['row_id'] = label\n    if (p[i][y_prob[i]]) < threshold:\n        data['birds'] = 'nocall'\n    else:\n        data['birds'] = labels[y_prob[i]]\n    submission.append(data)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_submission = pd.DataFrame(submission)\ndf_submission.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_submission.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}