{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":91844,"databundleVersionId":11361821,"sourceType":"competition"},{"sourceId":11662893,"sourceType":"datasetVersion","datasetId":7319360},{"sourceId":11740346,"sourceType":"datasetVersion","datasetId":7370174},{"sourceId":384760,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":317470,"modelId":338032}],"dockerImageVersionId":31012,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\n\nimport os","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:04:20.736140Z","iopub.execute_input":"2025-05-10T01:04:20.736363Z","iopub.status.idle":"2025-05-10T01:04:22.264882Z","shell.execute_reply.started":"2025-05-10T01:04:20.736344Z","shell.execute_reply":"2025-05-10T01:04:22.264163Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels = sorted(os.listdir('/kaggle/input/birdclef-2025/train_audio/'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:04:22.265926Z","iopub.execute_input":"2025-05-10T01:04:22.266316Z","iopub.status.idle":"2025-05-10T01:04:22.273579Z","shell.execute_reply.started":"2025-05-10T01:04:22.266290Z","shell.execute_reply":"2025-05-10T01:04:22.272786Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"file_paths = []\nbase_path = '/kaggle/input/birdclef-2025/train_audio'\nsub_dir = []","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:04:22.275483Z","iopub.execute_input":"2025-05-10T01:04:22.276039Z","iopub.status.idle":"2025-05-10T01:04:22.304282Z","shell.execute_reply.started":"2025-05-10T01:04:22.276020Z","shell.execute_reply":"2025-05-10T01:04:22.303694Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for dir in os.listdir(base_path):\n    subdir_path = os.path.join(base_path, dir)\n    if os.path.isdir(subdir_path):\n        for file in os.listdir(subdir_path):\n            file_paths.append(f\"{dir}/{file}\")\n            sub_dir.append(dir)\ndf = pd.DataFrame({'classes': sub_dir, 'filename': file_paths})\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:04:22.305116Z","iopub.execute_input":"2025-05-10T01:04:22.305412Z","iopub.status.idle":"2025-05-10T01:04:23.305252Z","shell.execute_reply.started":"2025-05-10T01:04:22.305391Z","shell.execute_reply":"2025-05-10T01:04:23.304511Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df['classes'].astype(\"string\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:04:23.306071Z","iopub.execute_input":"2025-05-10T01:04:23.306333Z","iopub.status.idle":"2025-05-10T01:04:23.314806Z","shell.execute_reply.started":"2025-05-10T01:04:23.306309Z","shell.execute_reply":"2025-05-10T01:04:23.313910Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tqdm import tqdm\nimport librosa\nfrom joblib import Parallel, delayed","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:04:23.315746Z","iopub.execute_input":"2025-05-10T01:04:23.316009Z","iopub.status.idle":"2025-05-10T01:04:23.362165Z","shell.execute_reply.started":"2025-05-10T01:04:23.315982Z","shell.execute_reply":"2025-05-10T01:04:23.361527Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nimport numpy as np\nfrom tqdm import tqdm\nimport os\nimport librosa\nfrom joblib import Parallel, delayed\n\ndef features_extractor(file):\n    try:\n        audio, sample_rate = librosa.load(file, sr=32000)\n        mfccs = librosa.feature.mfcc(y=audio, sr=sample_rate, n_mfcc=20)\n        mfccs_scaled = (mfccs - np.mean(mfccs, axis=1, keepdims=True)) / (np.std(mfccs, axis=1, keepdims=True) + 1e-8)\n        \n        return mfccs_scaled\n    except Exception as e:\n        print(f\"Error processing file {file}: {e}\")\n        return None\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-09T00:43:33.941792Z","iopub.execute_input":"2025-05-09T00:43:33.942078Z","iopub.status.idle":"2025-05-09T00:43:33.947721Z","shell.execute_reply.started":"2025-05-09T00:43:33.942054Z","shell.execute_reply":"2025-05-09T00:43:33.946842Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Function to process a single file\ndef process_file(filename, base_path):\n    file_path = os.path.join(base_path, filename)\n    features = features_extractor(file_path)\n    return features","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-09T00:43:35.010917Z","iopub.execute_input":"2025-05-09T00:43:35.011186Z","iopub.status.idle":"2025-05-09T00:43:35.014750Z","shell.execute_reply.started":"2025-05-09T00:43:35.011168Z","shell.execute_reply":"2025-05-09T00:43:35.014145Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def extract_features_parallel(df_train, base_path, n_jobs=4):\n\n    extracted_features = Parallel(n_jobs=n_jobs)(\n        delayed(process_file)(filename, base_path) for filename in tqdm(df['filename'])\n    )\n    extracted_features = [features for features in extracted_features if features is not None]\n    \n    return extracted_features\n\nbase_path = '/kaggle/input/birdclef-2025/train_audio'\nextracted_features = extract_features_parallel(df, base_path, n_jobs=4)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-09T00:43:36.462980Z","iopub.execute_input":"2025-05-09T00:43:36.463243Z","iopub.status.idle":"2025-05-09T01:00:14.758578Z","shell.execute_reply.started":"2025-05-09T00:43:36.463224Z","shell.execute_reply":"2025-05-09T01:00:14.757283Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pickle\n\nwith open('/kaggle/working/features.pkl', 'wb') as f:\n    pickle.dump(extracted_features, f)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-09T01:02:37.860406Z","iopub.execute_input":"2025-05-09T01:02:37.861243Z","iopub.status.idle":"2025-05-09T01:02:51.870620Z","shell.execute_reply.started":"2025-05-09T01:02:37.861218Z","shell.execute_reply":"2025-05-09T01:02:51.869855Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pickle\nwith open('/kaggle/input/mfcc-features/features.pkl', 'rb') as f:\n    extracted_features = pickle.load(f)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:04:23.363212Z","iopub.execute_input":"2025-05-10T01:04:23.363847Z","iopub.status.idle":"2025-05-10T01:04:59.974658Z","shell.execute_reply.started":"2025-05-10T01:04:23.363823Z","shell.execute_reply":"2025-05-10T01:04:59.974009Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\ndef pad_or_truncate(features, target_length=250): \n    if features.shape[1] > target_length:\n        return features[:, :target_length] \n    else:\n        padding = np.zeros((features.shape[0], target_length - features.shape[1]))\n        return np.concatenate((features, padding), axis=1)\n\nextracted_features_padded = [pad_or_truncate(features) for features in extracted_features]\n\nextracted_features_array = np.array(extracted_features_padded)\n\nprint(f\"{extracted_features_array.shape}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:04:59.975472Z","iopub.execute_input":"2025-05-10T01:04:59.975729Z","iopub.status.idle":"2025-05-10T01:05:00.450814Z","shell.execute_reply.started":"2025-05-10T01:04:59.975711Z","shell.execute_reply":"2025-05-10T01:05:00.450064Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_x = extracted_features_array\ndata_y = df['classes']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:05:00.452621Z","iopub.execute_input":"2025-05-10T01:05:00.452851Z","iopub.status.idle":"2025-05-10T01:05:00.456676Z","shell.execute_reply.started":"2025-05-10T01:05:00.452833Z","shell.execute_reply":"2025-05-10T01:05:00.456047Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder\nfrom tensorflow.keras.utils import to_categorical\nlabel_encoder = LabelEncoder()\ninteger_encoded = label_encoder.fit_transform(data_y)\n\ndata_y_encoded = to_categorical(integer_encoded, num_classes=206)\ndata_y_encoded","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:05:00.457318Z","iopub.execute_input":"2025-05-10T01:05:00.457478Z","iopub.status.idle":"2025-05-10T01:05:15.875044Z","shell.execute_reply.started":"2025-05-10T01:05:00.457465Z","shell.execute_reply":"2025-05-10T01:05:15.874465Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split, StratifiedKFold","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:05:15.875776Z","iopub.execute_input":"2025-05-10T01:05:15.876292Z","iopub.status.idle":"2025-05-10T01:05:16.001985Z","shell.execute_reply.started":"2025-05-10T01:05:15.876269Z","shell.execute_reply":"2025-05-10T01:05:16.001438Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X_train, X_test, y_train, y_test = train_test_split(data_x, data_y_encoded, test_size=0.3, random_state=42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:13:03.276304Z","iopub.execute_input":"2025-05-10T01:13:03.276686Z","iopub.status.idle":"2025-05-10T01:13:03.657436Z","shell.execute_reply.started":"2025-05-10T01:13:03.276663Z","shell.execute_reply":"2025-05-10T01:13:03.656889Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def adjust_learning_rate(epochs):\n  learning_rate = 1e-1\n  if epochs > 160:\n    learning_rate *= 5e-4\n  elif epochs > 120:\n    learning_rate *= 1e-3\n  elif epochs > 80:\n    learning_rate *= 5e-3\n  elif epochs > 40:\n    learning_rate *= 5e-2\n  elif epochs >= 0:\n    learning_rate *= 1e-1\n  return learning_rate","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:05:32.423870Z","iopub.execute_input":"2025-05-10T01:05:32.424168Z","iopub.status.idle":"2025-05-10T01:05:32.428915Z","shell.execute_reply.started":"2025-05-10T01:05:32.424147Z","shell.execute_reply":"2025-05-10T01:05:32.428182Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import layers, models\nfrom keras.optimizers import Adam\nfrom keras.models import Model\nfrom tensorflow.keras.models import Sequential\nfrom keras import layers\nfrom keras.layers import Dense, Input, BatchNormalization, Activation, Flatten, Dropout, TimeDistributed\nfrom keras.layers import Conv2D, SeparableConv2D, MaxPooling2D, GlobalAveragePooling2D, GlobalMaxPooling2D, ConvLSTM2D\nfrom keras.callbacks import ModelCheckpoint, LearningRateScheduler\nfrom keras.callbacks import ReduceLROnPlateau, EarlyStopping\nfrom keras.regularizers import l2\nfrom tensorflow.keras.models import load_model\n\nlr_scheduler = LearningRateScheduler(adjust_learning_rate)\n\nlr_reducer = ReduceLROnPlateau(factor=np.sqrt(0.1),\n                               cooldown=0,\n                               patience=5,\n                               min_lr=5e-6)\n\ndef cnn_model(input_shape=(20, 250, 1), num_classes=206):\n    inputs = tf.keras.Input(shape=input_shape)\n\n    x = layers.Conv2D(64, (3, 3), activation='relu', padding='same', kernel_initializer='he_normal', kernel_regularizer=tf.keras.regularizers.l2(1e-3))(inputs)\n    x = layers.BatchNormalization()(x)\n    x = layers.MaxPooling2D((2, 2))(x)\n\n    x = layers.Conv2D(128, (3, 3), activation='relu', padding='same', kernel_initializer='he_normal', kernel_regularizer=tf.keras.regularizers.l2(1e-3))(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.MaxPooling2D((2, 2))(x)\n    x = layers.Dropout(0.2)(x)\n\n    x = layers.Conv2D(256, (3, 3), activation='relu', padding='same', kernel_initializer='he_normal', kernel_regularizer=tf.keras.regularizers.l2(1e-3))(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.MaxPooling2D((2, 2))(x)\n    x = layers.Dropout(0.2)(x)\n\n    x = layers.Conv2D(512, (3, 3), activation='relu', padding='same', kernel_initializer='he_normal', kernel_regularizer=tf.keras.regularizers.l2(1e-3))(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.MaxPooling2D((2, 2))(x)\n    x = layers.Dropout(0.2)(x)\n\n    x = layers.Conv2D(512, (3, 3), activation='relu', padding='same', kernel_initializer='he_normal', kernel_regularizer=tf.keras.regularizers.l2(1e-3))(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.GlobalAveragePooling2D()(x)\n\n    x = layers.Dense(256, activation='relu')(x)\n    outputs = layers.Dense(num_classes, activation='softmax', kernel_initializer='he_normal', kernel_regularizer=tf.keras.regularizers.l2(1e-3))(x)\n\n    return models.Model(inputs, outputs)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:07:32.730598Z","iopub.execute_input":"2025-05-10T01:07:32.730982Z","iopub.status.idle":"2025-05-10T01:07:32.745890Z","shell.execute_reply.started":"2025-05-10T01:07:32.730961Z","shell.execute_reply":"2025-05-10T01:07:32.745207Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import backend as K\n\ndef focal_loss(gamma=2.0, alpha=0.25):\n    def loss(y_true, y_pred):\n        y_true = tf.cast(y_true, tf.float32)\n        y_pred = tf.clip_by_value(y_pred, K.epsilon(), 1. - K.epsilon())\n        \n        cross_entropy = -y_true * tf.math.log(y_pred)\n        weight = alpha * tf.pow(1 - y_pred, gamma)\n        focal = weight * cross_entropy\n        return tf.reduce_mean(tf.reduce_sum(focal, axis=1))\n    return loss\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:05:34.787138Z","iopub.execute_input":"2025-05-10T01:05:34.787932Z","iopub.status.idle":"2025-05-10T01:05:34.794392Z","shell.execute_reply.started":"2025-05-10T01:05:34.787899Z","shell.execute_reply":"2025-05-10T01:05:34.793534Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_type = 'CNN'\nsave_dir = os.path.join(os.getcwd(), 'saved_models') \nmodel_name = f'BirdClef_{model_type}_model.{{epoch:03d}}.keras'\nfilepath = os.path.join(save_dir, model_name)\nif not os.path.isdir(save_dir): \n    os.makedirs(save_dir) \nfilepath = os.path.join(save_dir, model_name)\ncheckpoint = ModelCheckpoint(filepath=filepath, \n                              monitor='val_auc_roc', \n                              verbose=1, \n                              save_best_only=True,\n                            mode='max') \ncallbacks = [checkpoint, lr_reducer, lr_scheduler]\n\ncnn = cnn_model()\ncnn.compile(\n        optimizer=Adam(learning_rate=adjust_learning_rate(0)), \n        loss=focal_loss(gamma=2.0, alpha=0.25), \n        metrics=['accuracy', tf.keras.metrics.AUC(curve='ROC', name='auc_roc')]\n)\ncnn.fit(X_train, y_train, epochs=200, batch_size=32, validation_data=(X_test, y_test),  shuffle=True, callbacks=callbacks)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-09T04:57:03.183991Z","iopub.execute_input":"2025-05-09T04:57:03.184336Z","execution_failed":"2025-05-09T05:47:06.558Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\ndef preprocess_mfcc_to_rgb(mfcc_sample):\n    resized = cv2.resize(mfcc_sample, (224, 224), interpolation=cv2.INTER_LINEAR)\n    \n    rgb = np.stack([resized] * 3, axis=-1)  \n    \n    rgb = rgb.astype(np.float32) / 255.0\n    return rgb","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:07:40.386089Z","iopub.execute_input":"2025-05-10T01:07:40.386762Z","iopub.status.idle":"2025-05-10T01:07:40.856973Z","shell.execute_reply.started":"2025-05-10T01:07:40.386742Z","shell.execute_reply":"2025-05-10T01:07:40.856422Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_dataset(X, y, batch_size=32, shuffle=True):\n    def _map_fn(mfcc, label):\n        img = tf.numpy_function(preprocess_mfcc_to_rgb, [mfcc], tf.float32)\n        img.set_shape((224, 224, 3))\n        return img, label\n\n    dataset = tf.data.Dataset.from_tensor_slices((X, y))\n    if shuffle:\n        dataset = dataset.shuffle(buffer_size=1000)\n    dataset = dataset.map(_map_fn, num_parallel_calls=tf.data.AUTOTUNE)\n    dataset = dataset.batch(batch_size).prefetch(tf.data.AUTOTUNE)\n    return dataset\ntrain = create_dataset(X_train, y_train)\ntest = create_dataset(X_test, y_test)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:13:08.763114Z","iopub.execute_input":"2025-05-10T01:13:08.763599Z","iopub.status.idle":"2025-05-10T01:13:11.648690Z","shell.execute_reply.started":"2025-05-10T01:13:08.763575Z","shell.execute_reply":"2025-05-10T01:13:11.647951Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.applications import EfficientNetB0\ndef EfficientNet(num_classes=206):\n    base_model = EfficientNetB0(include_top=False, weights='/kaggle/input/efficientb0/keras/default/1/efficientnetb0_notop.h5', input_shape=(224, 224, 3))\n\n    inputs = Input(shape=(224, 224, 3))\n    x = base_model(inputs, training=False)\n    x = GlobalAveragePooling2D()(x)\n    outputs = Dense(num_classes, activation='softmax')(x)\n\n    model = Model(inputs, outputs)\n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:16:55.345024Z","iopub.execute_input":"2025-05-10T01:16:55.345323Z","iopub.status.idle":"2025-05-10T01:16:55.350245Z","shell.execute_reply.started":"2025-05-10T01:16:55.345302Z","shell.execute_reply":"2025-05-10T01:16:55.349557Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_type = 'EfficientNetB0'\nsave_dir = os.path.join(os.getcwd(), 'saved_models') \nmodel_name = f'BirdClef_{model_type}_model.{{epoch:03d}}.keras'\nfilepath = os.path.join(save_dir, model_name)\nif not os.path.isdir(save_dir): \n    os.makedirs(save_dir) \nfilepath = os.path.join(save_dir, model_name)\ncheckpoint = ModelCheckpoint(filepath=filepath, \n                              monitor='val_auc_roc', \n                              verbose=1, \n                              save_best_only=True,\n                            mode='max') \ncallbacks = [checkpoint, lr_reducer, lr_scheduler]\n\neff = EfficientNet()\neff.compile(\n        optimizer=Adam(learning_rate=adjust_learning_rate(0)), \n        loss=focal_loss(gamma=2.0, alpha=0.25), \n        metrics=['accuracy', tf.keras.metrics.AUC(curve='ROC', name='auc_roc')]\n)\neff.fit(train, epochs=200, batch_size=32, validation_data=test,  shuffle=True, callbacks=callbacks)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-10T01:16:56.172060Z","iopub.execute_input":"2025-05-10T01:16:56.172582Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}