{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.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":70203,"databundleVersionId":8068726,"sourceType":"competition"},{"sourceId":8033468,"sourceType":"datasetVersion","datasetId":4735360}],"dockerImageVersionId":30683,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport os\nimport glob\n\nfrom sklearn.model_selection import train_test_split\n\nimport tensorflow as tf\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\nfrom tensorflow.keras import layers, models\n\nfrom tensorflow.keras.utils import to_categorical\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.applications import NASNetMobile\nfrom tensorflow.keras.layers import Input, Dense, GlobalAveragePooling2D, concatenate, LSTM, Bidirectional, Reshape\nfrom tensorflow.keras.models import Model\n\nfrom sklearn.preprocessing import LabelBinarizer\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import roc_auc_score, roc_curve, auc\n\nAUTOTUNE = tf.data.experimental.AUTOTUNE","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-04-14T08:35:31.026941Z","iopub.execute_input":"2024-04-14T08:35:31.027203Z","iopub.status.idle":"2024-04-14T08:35:52.469215Z","shell.execute_reply.started":"2024-04-14T08:35:31.027178Z","shell.execute_reply":"2024-04-14T08:35:52.468149Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Base directory where the folders are stored\nimage_folder = \"/kaggle/input/birdclef-2024-mel-spectrograms/train_images/\"\n\n# Mapping of classes to numerical labels\n# Classes are alphabetically sorted - so we can easily restore class order when we load\nclass_labels = {class_name: i for i, class_name in enumerate(sorted(os.listdir(image_folder)))}\nnum_classes = len(class_labels)\n\n# Collect all file paths and their corresponding class labels\nfile_paths = []\nlabels = []\n\n# New structure to keep track of groups\nsamples = {}\n\nfor class_name in os.listdir(image_folder):\n    class_dir = os.path.join(image_folder, class_name)\n    for filename in os.listdir(class_dir):\n        # Extract base sample name from filename (files split at \"_\")\n        sample_base = filename.split('_')[0] \n        full_path = os.path.join(class_dir, filename)\n        \n        if sample_base not in samples:\n            samples[sample_base] = {'files': [], 'label': class_labels[class_name]}\n        samples[sample_base]['files'].append(full_path)\n","metadata":{"execution":{"iopub.status.busy":"2024-04-14T08:35:52.470947Z","iopub.execute_input":"2024-04-14T08:35:52.471505Z","iopub.status.idle":"2024-04-14T08:35:57.526502Z","shell.execute_reply.started":"2024-04-14T08:35:52.471476Z","shell.execute_reply":"2024-04-14T08:35:57.525747Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_size = 0.2\nbatch_size = 32\n\n# Convert the samples dictionary into a list for splitting\nsamples_list = list(samples.items())\n\n# Split the list of tuples into training and validation sets\ntrain_samples, val_samples = train_test_split(samples_list, test_size=test_size, random_state=42)\n\ndef preprocess_image(file_path, label):\n    img = tf.io.read_file(file_path)\n    img = tf.image.decode_jpeg(img, channels=3)\n    img = tf.image.random_contrast(img, lower=0.2, upper=1.8)\n    img = tf.image.random_brightness(img, max_delta=0.2)\n\n    #scale 0-1\n    img = tf.cast(img, tf.float32) / 255.0\n\n    #scale -1 to +1\n    #img = tf.cast(img, tf.float32) / 255.0  # Normalize to [0, 1]\n#     img = img * 2.0 - 1.0  # Scale to [-1, +1]\n    \n#     label = tf.one_hot(label, depth=num_classes)\n    return img, label\n\n# Function to extract file paths and labels from the split samples\ndef extract_files_and_labels(sample_list):\n    file_paths = []\n    labels = []\n    for _, sample_info in sample_list:\n        file_paths.extend(sample_info['files'])\n        labels.extend([sample_info['label']] * len(sample_info['files']))\n    return file_paths, labels\n\ntrain_files, train_labels = extract_files_and_labels(train_samples)\nval_files, val_labels = extract_files_and_labels(val_samples)\n\nnum_classes = np.max(train_labels) + 1\n\n# Create a tf.data.Dataset from file paths and labels\ntrain_dataset = tf.data.Dataset.from_tensor_slices((train_files, train_labels))\ntrain_dataset = train_dataset.map(preprocess_image, num_parallel_calls=AUTOTUNE)\ntrain_dataset = train_dataset.shuffle(buffer_size=1000).batch(batch_size).prefetch(AUTOTUNE)\n\nval_dataset = tf.data.Dataset.from_tensor_slices((val_files, val_labels))\nval_dataset = val_dataset.map(preprocess_image, num_parallel_calls=AUTOTUNE)\nval_dataset = val_dataset.batch(batch_size).prefetch(AUTOTUNE)","metadata":{"execution":{"iopub.status.busy":"2024-04-14T08:35:57.531994Z","iopub.execute_input":"2024-04-14T08:35:57.532274Z","iopub.status.idle":"2024-04-14T08:35:58.814986Z","shell.execute_reply.started":"2024-04-14T08:35:57.532249Z","shell.execute_reply":"2024-04-14T08:35:58.814035Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras.applications import NASNetMobile\n\n# Define input shape for NASNetMobile\ninput_shape_nasnet = (224, 224, 3)\n\n# Create input for NASNetMobile\ninput_nasnet = Input(shape=input_shape_nasnet, name='input_nasnet')\n\n# Load NASNetMobile model\nbase_model_nasnet = NASNetMobile(weights='imagenet', include_top=False, input_tensor=input_nasnet)\nbase_model_nasnet.trainable = False\n\n# Global average pooling for NASNetMobile\nx_nasnet = GlobalAveragePooling2D()(base_model_nasnet.output)\n\n# x_reshaped = Reshape((-1, 1))(x_nasnet)  # Assuming you want to treat each feature independently\n\n# # Add BiLSTM layer\n# x_lstm = Bidirectional(LSTM(128, return_sequences=False))(x_reshaped)\n\nx = Dense(1024, activation='relu')(x_nasnet)\nx = Dense(512, activation='relu')(x)\nx = Dense(256, activation='relu')(x)\n\n# Add a logistic layer matching class count\npredictions = Dense(num_classes, activation='softmax')(x)\n\n# Define learning rate scheduler\ninitial_learning_rate = 0.001\nlr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(\n    initial_learning_rate=initial_learning_rate,\n    decay_steps=10,\n    decay_rate=0.96,\n    staircase=True)\n\n# Define optimizer\noptimizer = tf.keras.optimizers.Adam(learning_rate=lr_schedule)\n\n# Define the model with two inputs\nmodel = Model(inputs= input_nasnet , outputs=predictions)\n\n# Compile the model\nmodel.compile(optimizer=optimizer,\n              loss='sparse_categorical_crossentropy',\n              metrics=['accuracy'])\n\n","metadata":{"execution":{"iopub.status.busy":"2024-04-14T08:35:58.816322Z","iopub.execute_input":"2024-04-14T08:35:58.816641Z","iopub.status.idle":"2024-04-14T08:36:03.994389Z","shell.execute_reply.started":"2024-04-14T08:35:58.816591Z","shell.execute_reply":"2024-04-14T08:36:03.993632Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Turn off all warnings except for errors\ntf.get_logger().setLevel('ERROR')\n\n# Fit the model with callbacks\nhistory = model.fit(train_dataset, \n                                     epochs=500,\n                                     steps_per_epoch=len(train_dataset),\n                                     validation_data=val_dataset,\n                                     validation_steps=int(len(val_dataset)),\n                                    )","metadata":{"execution":{"iopub.status.busy":"2024-04-14T08:39:33.659961Z","iopub.execute_input":"2024-04-14T08:39:33.660344Z","iopub.status.idle":"2024-04-14T08:40:56.256509Z","shell.execute_reply.started":"2024-04-14T08:39:33.660311Z","shell.execute_reply":"2024-04-14T08:40:56.255658Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Assuming you have defined and trained your model already\n\n# Get predictions on validation data\nval_predictions = model.predict(val_dataset)\n\n# Convert tensors to numpy arrays\nval_labels_np = np.concatenate([y.numpy() for x, y in val_dataset], axis=0)\n","metadata":{"execution":{"iopub.status.busy":"2024-04-14T08:44:35.876963Z","iopub.execute_input":"2024-04-14T08:44:35.877793Z","iopub.status.idle":"2024-04-14T08:45:10.851229Z","shell.execute_reply.started":"2024-04-14T08:44:35.877755Z","shell.execute_reply":"2024-04-14T08:45:10.850360Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"p = list()\nt = list()\n\nfor i in range(len(val_predictions)):\n    p.append(np.argmax(val_predictions[i]))\n    t.append(val_labels_np[i])","metadata":{"execution":{"iopub.status.busy":"2024-04-14T08:45:21.534981Z","iopub.execute_input":"2024-04-14T08:45:21.535370Z","iopub.status.idle":"2024-04-14T08:45:21.560721Z","shell.execute_reply.started":"2024-04-14T08:45:21.535337Z","shell.execute_reply":"2024-04-14T08:45:21.559828Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import roc_curve, auc\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n# Example true labels (multi-class)\ny_true = val_labels_np\n\n# Compute ROC curve and ROC area for each class\nfpr = dict()\ntpr = dict()\nroc_auc = dict()\nn_classes = val_predictions.shape[1]\nselected_classes = []\n\nfor i in range(n_classes):\n    fpr[i], tpr[i], _ = roc_curve((y_true == i).astype(int), val_predictions[:, i])\n    roc_auc[i] = auc(fpr[i], tpr[i])\n    if roc_auc[i] > 0.85:\n        selected_classes.append(i)\n\n# Plot ROC curve for each class with AUC > 0.8\nplt.figure(figsize=(8, 6))\n\nfor i in selected_classes:\n    plt.plot(fpr[i], tpr[i], label=f'Class {i} (AUC = {roc_auc[i]:.2f})')\n\nplt.plot([0, 1], [0, 1], 'k--')\nplt.xlim([0.0, 1.0])\nplt.ylim([0.0, 1.05])\nplt.xlabel('False Positive Rate')\nplt.ylabel('True Positive Rate')\nplt.title('ROC curve for multi-class (AUC > 0.85)')\nplt.legend(loc=\"lower right\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-14T08:48:54.135148Z","iopub.execute_input":"2024-04-14T08:48:54.135524Z","iopub.status.idle":"2024-04-14T08:48:54.780633Z","shell.execute_reply.started":"2024-04-14T08:48:54.135493Z","shell.execute_reply":"2024-04-14T08:48:54.779635Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def calculate_accuracy(predicted, actual):\n    \"\"\"\n    Calculate accuracy score.\n\n    Parameters:\n        predicted (list): List of predicted values.\n        actual (list): List of actual values.\n\n    Returns:\n        float: Accuracy score.\n    \"\"\"\n    correct = sum(1 for pred, act in zip(predicted, actual) if pred == act)\n    total = len(actual)\n    accuracy = correct / total\n    return accuracy","metadata":{"execution":{"iopub.status.busy":"2024-04-14T08:49:03.204582Z","iopub.execute_input":"2024-04-14T08:49:03.205455Z","iopub.status.idle":"2024-04-14T08:49:03.210934Z","shell.execute_reply.started":"2024-04-14T08:49:03.205421Z","shell.execute_reply":"2024-04-14T08:49:03.209987Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"accuracy = calculate_accuracy(p, t)\nprint(\"Accuracy:\", accuracy)","metadata":{"execution":{"iopub.status.busy":"2024-04-14T08:49:03.569244Z","iopub.execute_input":"2024-04-14T08:49:03.569627Z","iopub.status.idle":"2024-04-14T08:49:03.575655Z","shell.execute_reply.started":"2024-04-14T08:49:03.569579Z","shell.execute_reply":"2024-04-14T08:49:03.574758Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#initialize with columns from sample_submission\nsample_submit = pd.read_csv(\"/kaggle/input/birdclef-2024/sample_submission.csv\")\nsubmit = pd.DataFrame(columns=sample_submit.columns)\n\nsubmit","metadata":{"execution":{"iopub.status.busy":"2024-04-14T08:36:50.404055Z","iopub.status.idle":"2024-04-14T08:36:50.404377Z","shell.execute_reply.started":"2024-04-14T08:36:50.404218Z","shell.execute_reply":"2024-04-14T08:36:50.404231Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#determine filenames\nsoundscapes_folder = \"/kaggle/input/birdclef-2024/test_soundscapes\"\nfilenames_with_path = glob.glob(f\"{soundscapes_folder}/*.ogg\")\nfilenames = [os.path.basename(filename) for filename in filenames_with_path]\n\nfor filename in filenames:\n    start_time = time.time()\n    #generate array of spectrograms for each file\n    images = get_spectrograms_for_ogg(soundscapes_folder, filename)\n    \n    time_index = 0\n\n    #predict for all images\n    prediction_batch_results = make_prediction_batch(images)\n    \n    #predictions to DF\n    for predictions in prediction_batch_results:\n        print(\".\", end=\"\")\n        filename_no_prefix = filename.replace(\".ogg\", \"\")\n\n        # Flatten predictions if necessary\n        predictions = predictions.flatten()\n\n        #make same prediction for multiple \n        for duplicate_pred_index in range(0, duplicate_predictions_count):\n            # Create a new row dictionary with 'row_id' and prediction values\n            time_index += audio_duration\n            row_id = f\"{filename_no_prefix}_{int(time_index)}\"\n            new_row_dict = {'row_id': row_id}\n            for i, col_name in enumerate(submit.columns[1:]):  # Skip 'row_id' column\n                new_row_dict[col_name] = predictions[i]\n\n            # Convert the new row dictionary to a DataFrame\n            new_row_df = pd.DataFrame(new_row_dict, index=[0])\n\n            submit = pd.concat([submit, new_row_df], ignore_index=True)\n        \n    #needs to be <6.5 seconds to handle 1100 files in 7200 seconds (2 hours)\n    print(f\"\\nTime to process file {time.time() - start_time}\")\n    #exit after first file processed if just doing a quick test\n    if quick_test: break","metadata":{"execution":{"iopub.status.busy":"2024-04-14T08:36:50.405273Z","iopub.status.idle":"2024-04-14T08:36:50.405574Z","shell.execute_reply.started":"2024-04-14T08:36:50.405425Z","shell.execute_reply":"2024-04-14T08:36:50.405437Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submit.to_csv('submission.csv', index=False)\nsubmit","metadata":{"execution":{"iopub.status.busy":"2024-04-14T08:36:50.406646Z","iopub.status.idle":"2024-04-14T08:36:50.406999Z","shell.execute_reply.started":"2024-04-14T08:36:50.406824Z","shell.execute_reply":"2024-04-14T08:36:50.406838Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}