{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":21669,"databundleVersionId":1692278,"sourceType":"competition"},{"sourceId":14042123,"sourceType":"datasetVersion","datasetId":8939675},{"sourceId":14043675,"sourceType":"datasetVersion","datasetId":8940556},{"sourceId":675251,"sourceType":"modelInstanceVersion","modelInstanceId":511871,"modelId":526526}],"dockerImageVersionId":31192,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# General settings","metadata":{}},{"cell_type":"markdown","source":"## Import","metadata":{}},{"cell_type":"code","source":"#Data handling\nimport os\nimport pandas as pd\nfrom PIL import Image\nfrom glob import glob\n\n# Randomization\nimport random\n\n# Audio handling\nimport librosa\n\n# Visualization\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\n# Feedback with progress bar\nfrom tqdm.notebook import tqdm\n\n# Math & Algorithms\nimport numpy as np\n\n# Model\nimport keras\nfrom keras import layers\nimport tensorflow as tf\nfrom keras.models import load_model\nfrom tensorflow.keras import models\nfrom tensorflow.keras.layers import Resizing\n\n# Clustering\nfrom sklearn.model_selection import train_test_split","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-10T21:24:13.124543Z","iopub.execute_input":"2025-12-10T21:24:13.125247Z","iopub.status.idle":"2025-12-10T21:24:36.796930Z","shell.execute_reply.started":"2025-12-10T21:24:13.125223Z","shell.execute_reply":"2025-12-10T21:24:36.796260Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Variable setting","metadata":{}},{"cell_type":"code","source":"# NN training parameters\nsegment_length = 0.8\nbatch_size = 32\nlr = 1e-3\npatience = 40\nepochs = 1000\n\n# Initialize random number generation\nrandom_seed = 42\nrandom.seed(random_seed)\nrng = np.random.default_rng()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T21:24:36.797913Z","iopub.execute_input":"2025-12-10T21:24:36.798443Z","iopub.status.idle":"2025-12-10T21:24:36.803033Z","shell.execute_reply.started":"2025-12-10T21:24:36.798420Z","shell.execute_reply":"2025-12-10T21:24:36.802300Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## File paths","metadata":{}},{"cell_type":"code","source":"# Inputs\nlabeled_files_path='/kaggle/input/spectrograms-training-labeled-multiple'\ntest_path='/kaggle/input/rfcx-species-audio-detection/test'\nautoencoder_filepath=\"/kaggle/input/model-38/keras/default/1/model_epoch_38.keras\"\n\n# Outputs\ncheckpoint_frozen_filepath=\"/kaggle/working/checkpoint_frozen/model_epoch_{epoch}.keras\"\nlogger_frozen_filename=\"training_frozen.log\"\ncheckpoint_full_filepath=\"/kaggle/working/checkpoint_full/model_epoch_{epoch}.keras\"\nlogger_full_filename=\"training_full.log\"\nlogger_combined=\"training_combined.log\"\nsubmission_dir = '/kaggle/working/csv'\n\n# Create folders\nos.makedirs(\"/kaggle/working/checkpoint_frozen\", exist_ok=True)\nos.makedirs(\"/kaggle/working/checkpoint_full\", exist_ok=True)\nos.makedirs(submission_dir, exist_ok=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T21:24:36.803909Z","iopub.execute_input":"2025-12-10T21:24:36.804200Z","iopub.status.idle":"2025-12-10T21:24:36.846615Z","shell.execute_reply.started":"2025-12-10T21:24:36.804175Z","shell.execute_reply":"2025-12-10T21:24:36.846019Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Data loading","metadata":{}},{"cell_type":"markdown","source":"## Encoder","metadata":{}},{"cell_type":"code","source":"# Loading autoencoder\nautoencoder=load_model(autoencoder_filepath)\n\n# Getting encoder\nencoder=autoencoder.get_layer(\"encoder\")\nencoder.summary()\n\n# Getting latent dim\nlatent_dim=encoder.output_shape[-1]\nprint(latent_dim)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T21:24:36.848246Z","iopub.execute_input":"2025-12-10T21:24:36.848704Z","iopub.status.idle":"2025-12-10T21:24:41.775233Z","shell.execute_reply.started":"2025-12-10T21:24:36.848678Z","shell.execute_reply":"2025-12-10T21:24:41.774655Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Data loader class","metadata":{}},{"cell_type":"code","source":"# Data augmentation\ndata_augmentation=keras.Sequential([\n    layers.RandomTranslation(\n        height_factor=0,\n        width_factor=0.1,\n        fill_mode='nearest'\n    ),\n    layers.RandomContrast(0.2),\n    layers.RandomZoom(\n        height_factor=0,\n        width_factor=0.1\n    )\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T21:24:41.775897Z","iopub.execute_input":"2025-12-10T21:24:41.776147Z","iopub.status.idle":"2025-12-10T21:24:41.787416Z","shell.execute_reply.started":"2025-12-10T21:24:41.776118Z","shell.execute_reply":"2025-12-10T21:24:41.786898Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class AudioDataset(keras.utils.Sequence):\n    \n    # Initialization\n    def __init__(self, files, num_species, batch_size=16, shuffle=False, seed=None, **kwargs):\n        \"\"\" Spectrogram dataset loader - reproducible\n            \n            Arguments:\n            files: list of paths to images\n            num_species: number of labels\n            batch_size: number of files in a batch\n            shuffle: whether to shuffle images\n            seed: seed for reproducibility\n        \"\"\"\n        super().__init__()      \n\n        self.files=files.copy()\n        self.num_species=num_species\n        self.batch_size=batch_size\n        self.shuffle=shuffle\n        self.seed=seed\n        self.rng=np.random.RandomState(seed) if seed is not None else np.random\n        \n        # setting seeds\n        if seed is not None:\n            np.random.seed(seed)\n            tf.random.set_seed(seed)\n            random.seed(seed)\n\n        # detecting image shape\n        with Image.open(self.files[0]) as image:\n            self.input_shape=(image.size[1], image.size[0], 1)\n\n        self.end_of_epoch()\n\n\n    # Number of batches\n    def __len__(self):\n        return int(np.ceil(len(self.files)/self.batch_size))\n\n\n    # Creates a single batch\n    def __getitem__(self, index):\n        batch_files=self.files[index*self.batch_size:(index+1)*self.batch_size]\n\n        batch_images=[]\n        batch_labels=[]\n        \n        for f in batch_files:\n            with Image.open(f) as image:\n                image=image.resize(self.input_shape[:2][::-1])\n                image=np.array(image, dtype=np.float32)/255.0\n                if image.ndim==2:\n                    image=image[...,np.newaxis]\n\n            \n            batch_images.append(image)\n\n            label=int(os.path.basename(os.path.dirname(f)))\n            one_hot=np.zeros(self.num_species, dtype=np.float32)\n            one_hot[label]=1.0\n            batch_labels.append(one_hot)\n\n        return np.stack(batch_images), np.stack(batch_labels)\n\n    def get_all_items(self):\n        data_images=[]\n        data_labels=[]\n        \n        for f in self.files:\n            with Image.open(f) as image:\n                image=image.resize(self.input_shape[:2][::-1])\n                image=np.array(image, dtype=np.float32)/255.0\n                if image.ndim==2:\n                    image=image[...,np.newaxis]\n            data_images.append(image)\n\n            label=int(os.path.basename(os.path.dirname(f)))\n            one_hot=np.zeros(self.num_species, dtype=np.float32)\n            one_hot[label]=1.0\n            data_labels.append(one_hot)\n\n        return np.stack(data_images), np.stack(data_labels)\n\n    \n    # Shuffles files\n    def end_of_epoch(self):\n        if self.shuffle:\n            if self.seed is not None:\n                permutation=self.rng.permutation(len(self.files))\n                self.files=[self.files[i] for i in permutation]\n            else:\n                np.random.shuffle(self.files)\n        \n\n    # Shape of an image\n    def image_shape(self):\n        return self.input_shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T21:24:41.788110Z","iopub.execute_input":"2025-12-10T21:24:41.788814Z","iopub.status.idle":"2025-12-10T21:24:41.843677Z","shell.execute_reply.started":"2025-12-10T21:24:41.788782Z","shell.execute_reply":"2025-12-10T21:24:41.842907Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Datasets","metadata":{}},{"cell_type":"code","source":"# All files\nall_files = glob(\"/kaggle/input/spectrograms-training-labeled-multiple/*/*.png\")\nprint(f\"Total files: {len(all_files)}\")\n\n# Getting number of species\nnum_species=len([int(d) for d in os.listdir(labeled_files_path) if os.path.isdir(os.path.join(labeled_files_path, d))])\nprint(num_species)\n\n# Class weights\nclass_weights = np.ones([num_species])\nfor i in range(num_species):\n    dir_path = os.path.join(labeled_files_path, str(i))\n    class_weights[i] = 1/len(os.listdir(dir_path))\nclass_weights /= np.max(class_weights)\nweight_dict = {}\nfor i, value in enumerate(class_weights):\n    weight_dict[i] = value\nprint(weight_dict)\n\n# Separating training and validation data\ntrain_files, val_files = train_test_split(all_files, test_size=0.1, random_state=random_seed)\ntrain_dataset=AudioDataset(files=train_files, num_species=num_species, batch_size=batch_size, shuffle=True, seed=random_seed)\nval_dataset=AudioDataset(files=val_files, num_species=num_species, batch_size=batch_size, shuffle=False, seed=random_seed)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T21:24:41.844430Z","iopub.execute_input":"2025-12-10T21:24:41.844772Z","iopub.status.idle":"2025-12-10T21:24:42.165370Z","shell.execute_reply.started":"2025-12-10T21:24:41.844750Z","shell.execute_reply":"2025-12-10T21:24:42.164706Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Getting input shape\ntarget_shape=train_dataset.image_shape()\nprint(target_shape)\nprint(f\"Input shape: {target_shape}\")\nprint(len(train_dataset))\nprint(len(val_dataset))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T21:24:42.166055Z","iopub.execute_input":"2025-12-10T21:24:42.166331Z","iopub.status.idle":"2025-12-10T21:24:42.170464Z","shell.execute_reply.started":"2025-12-10T21:24:42.166300Z","shell.execute_reply":"2025-12-10T21:24:42.169929Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model - Frozen","metadata":{}},{"cell_type":"markdown","source":"## Classifier","metadata":{}},{"cell_type":"code","source":"def make_classifier(latent_dim, num_species):\n    classifier_input=layers.Input(shape=(latent_dim,))\n    # x=layers.Dense(256, activation='relu')(classifier_input)\n    # x=layers.Dropout(rate=0.3, seed=random_seed)(x)\n    x=layers.Dense(128, activation='relu')(classifier_input)\n    x=layers.Dropout(rate=0.2, seed=random_seed)(x)\n    classifier_output=layers.Dense(num_species, activation='softmax')(x)\n    # classifier_output=layers.Dense(num_species, activation='softmax')(classifier_input)\n    classifier=keras.Model(classifier_input, classifier_output)\n    return classifier","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T21:24:42.171155Z","iopub.execute_input":"2025-12-10T21:24:42.171466Z","iopub.status.idle":"2025-12-10T21:24:42.188419Z","shell.execute_reply.started":"2025-12-10T21:24:42.171448Z","shell.execute_reply":"2025-12-10T21:24:42.187713Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Make classifier\nclassifier=make_classifier(latent_dim, num_species)\n# Freeze encoder layers\nencoder.trainable=False\n# Setting up model\nmodel_input=layers.Input(shape=target_shape)\nlatent=encoder(model_input)\nmodel_output=classifier(latent)\nmodel=keras.Model(model_input, model_output)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T21:24:42.190512Z","iopub.execute_input":"2025-12-10T21:24:42.190835Z","iopub.status.idle":"2025-12-10T21:24:42.244661Z","shell.execute_reply.started":"2025-12-10T21:24:42.190811Z","shell.execute_reply":"2025-12-10T21:24:42.244145Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Training logic","metadata":{}},{"cell_type":"code","source":"# Optimizer\noptimizer=keras.optimizers.Adam(learning_rate = lr)\n\n# Callbacks\nreduce_lr = keras.callbacks.ReduceLROnPlateau(factor = 0.5, patience = patience / 2, verbose=1)\nearly_stop = keras.callbacks.EarlyStopping(patience = patience, verbose = 1, restore_best_weights = True)\ncheckpoint=keras.callbacks.ModelCheckpoint(\n    filepath=checkpoint_frozen_filepath,\n    verbose=1\n)\ncsv_logger=keras.callbacks.CSVLogger(\n    filename=logger_frozen_filename,\n    append=True\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T21:24:42.245230Z","iopub.execute_input":"2025-12-10T21:24:42.245413Z","iopub.status.idle":"2025-12-10T21:24:42.254258Z","shell.execute_reply.started":"2025-12-10T21:24:42.245399Z","shell.execute_reply":"2025-12-10T21:24:42.253587Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Compile model","metadata":{}},{"cell_type":"code","source":"# Compile model\nmodel.compile(\n    optimizer=optimizer,\n    loss=\"categorical_crossentropy\",\n    metrics=[\"accuracy\"]\n)\nencoder.summary(show_trainable=True)\nmodel.summary(expand_nested=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T21:24:42.255182Z","iopub.execute_input":"2025-12-10T21:24:42.255427Z","iopub.status.idle":"2025-12-10T21:24:42.301298Z","shell.execute_reply.started":"2025-12-10T21:24:42.255405Z","shell.execute_reply":"2025-12-10T21:24:42.300783Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Training","metadata":{}},{"cell_type":"code","source":"history_frozen=model.fit(\n    train_dataset,\n    validation_data=val_dataset,\n    epochs=epochs,\n    class_weight = weight_dict,\n    # callbacks = [early_stop, reduce_lr, csv_logger, checkpoint],\n    callbacks = [early_stop, reduce_lr, csv_logger],\n    verbose=1\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T21:24:42.301982Z","iopub.execute_input":"2025-12-10T21:24:42.302267Z","iopub.status.idle":"2025-12-10T23:24:12.317460Z","shell.execute_reply.started":"2025-12-10T21:24:42.302252Z","shell.execute_reply":"2025-12-10T23:24:12.316897Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model - Full","metadata":{}},{"cell_type":"markdown","source":"## Compile model","metadata":{}},{"cell_type":"code","source":"# Unfreeze encoder layers\nencoder.trainable=True\nencoder.summary(show_trainable=True)\n# Setting lower learning rate\nlr=1e-4\n\n# Setting different paths\ncheckpoint=keras.callbacks.ModelCheckpoint(\n    filepath=checkpoint_full_filepath,\n    verbose=1\n)\ncsv_logger=keras.callbacks.CSVLogger(\n    filename=logger_full_filename,\n    append=True\n)\n\n# Compile model\nmodel.compile(\n    optimizer=keras.optimizers.Adam(learning_rate=lr),\n    loss=\"categorical_crossentropy\",\n    metrics=[\"accuracy\"]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T23:24:12.318532Z","iopub.execute_input":"2025-12-10T23:24:12.318757Z","iopub.status.idle":"2025-12-10T23:24:12.347389Z","shell.execute_reply.started":"2025-12-10T23:24:12.318741Z","shell.execute_reply":"2025-12-10T23:24:12.346708Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Training","metadata":{}},{"cell_type":"code","source":"history_full = model.fit(\n    train_dataset,\n    validation_data=val_dataset,\n    epochs=epochs,\n    class_weight = weight_dict,\n    # callbacks=[early_stop, reduce_lr, checkpoint, csv_logger],\n    callbacks=[early_stop, reduce_lr, csv_logger],\n    verbose=1\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T23:24:12.348253Z","iopub.execute_input":"2025-12-10T23:24:12.348431Z","iopub.status.idle":"2025-12-11T00:54:58.990769Z","shell.execute_reply.started":"2025-12-10T23:24:12.348417Z","shell.execute_reply":"2025-12-11T00:54:58.990209Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Visualization - Losses","metadata":{}},{"cell_type":"code","source":"# Read logger files\ndf_frozen=pd.read_csv(logger_frozen_filename)\ndf_full=pd.read_csv(logger_full_filename)\n\n# Combine logger files\ndf_full[\"epoch\"]=df_full[\"epoch\"]+df_frozen[\"epoch\"].max()+1\ndf_combined=pd.concat([df_frozen, df_full], ignore_index=True)\nprint(df_combined.head())\n\n# Save combined file\ndf_combined.to_csv(logger_combined, index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-11T00:54:58.991743Z","iopub.execute_input":"2025-12-11T00:54:58.991956Z","iopub.status.idle":"2025-12-11T00:54:59.049976Z","shell.execute_reply.started":"2025-12-11T00:54:58.991938Z","shell.execute_reply":"2025-12-11T00:54:59.049449Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"log=pd.read_csv(logger_combined)\n\nplt.figure()\nplt.subplot(1, 2, 1)\nplt.plot(log['loss'], label='Training loss')\nplt.plot(log['val_loss'], label='Validation loss')\nplt.title('Losses')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.legend()\n\nplt.subplot(1, 2, 2)\nplt.plot(log['accuracy'], label='Training accuracy')\nplt.plot(log['val_accuracy'], label='Validation accuracy')\nplt.title('Accuracy')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy')\nplt.legend()\n\nplt.tight_layout()\nplt.savefig('/kaggle/working/loss_acc.png', bbox_inches='tight')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-11T00:54:59.050572Z","iopub.execute_input":"2025-12-11T00:54:59.050787Z","iopub.status.idle":"2025-12-11T00:54:59.764828Z","shell.execute_reply.started":"2025-12-11T00:54:59.050772Z","shell.execute_reply":"2025-12-11T00:54:59.764204Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import accuracy_score, log_loss, precision_score, recall_score, f1_score, roc_curve, confusion_matrix\n\n# Create predictions for the test images\ntest_data, test_labels = val_dataset.get_all_items()\ntest_confidences = model.predict(test_data, verbose=0)\ntest_labels = np.argmax(test_labels, 1)\ntest_preds = np.argmax(test_confidences, 1)\n\nprint(\"Test accuracy: %g\" %(accuracy_score(test_labels, test_preds)))\nprint(\"Test loss:\", log_loss(test_labels, test_confidences)) # Average loss, not sum\nprint(\"Test precision:\", precision_score(test_labels, test_preds, average = \"macro\"))\nprint(\"Test recall:\", recall_score(test_labels, test_preds, average=\"macro\"))\nprint(\"Test f1_score:\", f1_score(test_labels, test_preds, average=\"macro\"))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-11T00:54:59.765528Z","iopub.execute_input":"2025-12-11T00:54:59.765776Z","iopub.status.idle":"2025-12-11T00:55:01.424654Z","shell.execute_reply.started":"2025-12-11T00:54:59.765750Z","shell.execute_reply":"2025-12-11T00:55:01.423870Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"conf = confusion_matrix(test_labels, test_preds)\n\nfig = plt.figure(figsize=(10, 10))\nax = fig.add_subplot(111)\nax.set_aspect(1)\n\nres = sns.heatmap(conf, annot=True, vmin=0.0, fmt='d', cmap = plt.get_cmap('Blues'))\n\nplt.ylim([0, 24])\nplt.ylabel('True label')\nplt.xlim([0, 24])\nplt.xlabel('Predicted label')\nplt.title('Confusion Matrix')\n\nres.invert_yaxis()\n\nplt.show()\nplt.close()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-11T00:55:01.425499Z","iopub.execute_input":"2025-12-11T00:55:01.425771Z","iopub.status.idle":"2025-12-11T00:55:02.617059Z","shell.execute_reply.started":"2025-12-11T00:55:01.425749Z","shell.execute_reply":"2025-12-11T00:55:02.616312Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Saving the model\nmodel.save(\"model.keras\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Prediction","metadata":{}},{"cell_type":"code","source":"# Generate spectrograms from a given file\ndef gen_test_spectrograms(file_path, segment_length, target_shape):\n    \n    # Load audio\n    audio, sr = librosa.core.load(file_path, sr=None)\n\n    # Number of (full) segments\n    spectrograms=[]\n    sample_length=int(segment_length*sr)\n    num_segments=len(audio)//sample_length\n\n    for i in range(num_segments):\n        # Calculating start and end of the segment\n        start = i * sample_length\n        end = start + sample_length\n        audio_short = audio[start:end]\n        \n        # Creating spectrograms\n        S = librosa.feature.melspectrogram(y=audio_short, sr=sr, n_mels=target_shape[0])\n        S_db = librosa.power_to_db(S, ref=np.max)      \n\n        if S_db.shape[1]>target_shape[1]:\n            S_db=S_db[:, :target_shape[1]]\n        elif S_db.shape[1]<target_shape[1]:\n            pad_width=[(0, 0), (0, target_shape[1]-S_db.shape[1])]\n            S_db=np.pad(S_db, pad_width=pad_width, mode='constant')\n\n        S_norm = (S_db - S_db.min()) / (S_db.max() - S_db.min())\n        spectrograms.append(S_norm[..., None])  # Channel dimension\n\n    return spectrograms","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-11T00:55:02.618523Z","iopub.execute_input":"2025-12-11T00:55:02.618775Z","iopub.status.idle":"2025-12-11T00:55:02.624680Z","shell.execute_reply.started":"2025-12-11T00:55:02.618759Z","shell.execute_reply":"2025-12-11T00:55:02.624018Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Prediction on test files\ndef predict_test(model, spectrograms, threshold=0.):\n    inputs=np.array(spectrograms)\n    outputs=model.predict(inputs, verbose=0)\n    pred=np.max(outputs, axis=0)\n    binary_pred=(pred>threshold).astype(int)\n    return pred, binary_pred","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-11T00:55:02.625386Z","iopub.execute_input":"2025-12-11T00:55:02.625634Z","iopub.status.idle":"2025-12-11T00:55:02.640862Z","shell.execute_reply.started":"2025-12-11T00:55:02.625613Z","shell.execute_reply":"2025-12-11T00:55:02.640183Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Creating .csv file for submission\ndef create_csv(model, test_path, segment_length, target_shape, csv_file=None):\n    rows = []\n    test_paths = os.listdir(test_path)\n\n    for i in tqdm(range(len(test_paths))):\n        file = test_paths[i]\n        \n        if file.endswith('.flac'):\n            file_path = os.path.join(test_path, file)\n            recording_id = file.replace('.flac', '')\n            spectrograms = gen_test_spectrograms(file_path, segment_length=segment_length, target_shape=target_shape)\n            pred, _ = predict_test(model, spectrograms)\n            rows.append([recording_id] + list(pred))\n            # _, binary_pred=predict_test(model_keras, spectrograms)\n            # rows.append([recording_id]+list(binary_pred))\n\n    df = pd.DataFrame(rows, columns=['recording_id']+[f\"s{i}\" for i in range(num_species)])\n    if csv_file:\n        df.to_csv(csv_file, float_format='%.5f', index=False)\n    else:\n        print(df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-11T00:55:02.641657Z","iopub.execute_input":"2025-12-11T00:55:02.641958Z","iopub.status.idle":"2025-12-11T00:55:02.658393Z","shell.execute_reply.started":"2025-12-11T00:55:02.641936Z","shell.execute_reply":"2025-12-11T00:55:02.657891Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Saving submission file\ncsv_file = os.path.join(submission_dir, 'rainForest_submission_keras.csv')\ncreate_csv(model, test_path, segment_length, target_shape, csv_file=csv_file)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-11T00:55:02.659051Z","iopub.execute_input":"2025-12-11T00:55:02.659271Z","iopub.status.idle":"2025-12-11T01:15:37.701674Z","shell.execute_reply.started":"2025-12-11T00:55:02.659257Z","shell.execute_reply":"2025-12-11T01:15:37.701145Z"}},"outputs":[],"execution_count":null}]}