{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":70203,"databundleVersionId":8068726}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport librosa\nimport librosa.display\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import LabelEncoder\n\nimport tensorflow as tf\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout\nfrom tensorflow.keras.utils import to_categorical","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-05-18T14:56:54.542819Z","iopub.execute_input":"2026-05-18T14:56:54.543119Z","iopub.status.idle":"2026-05-18T14:57:24.972962Z","shell.execute_reply.started":"2026-05-18T14:56:54.543093Z","shell.execute_reply":"2026-05-18T14:57:24.972064Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"metadata = pd.read_csv(\"/kaggle/input/competitions/birdclef-2024/train_metadata.csv\")\n\nselected_birds = ['comsan', 'comros', 'barswa', 'litegr', 'hoopoe']\ndf = metadata[metadata['primary_label'].isin(selected_birds)].copy()\n\nprint(\"Selected birds:\", df['primary_label'].value_counts())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T14:57:31.213040Z","iopub.execute_input":"2026-05-18T14:57:31.213819Z","iopub.status.idle":"2026-05-18T14:57:31.386557Z","shell.execute_reply.started":"2026-05-18T14:57:31.213783Z","shell.execute_reply":"2026-05-18T14:57:31.385519Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def audio_to_mel(file_path, n_mels=128, duration=5): # n_mel => frequency band\n    try:\n        y, sr = librosa.load(file_path, sr=22050, duration=duration, mono=True) # sr => standard sample rate in hz sample/sec\n        # y => raw audio wave as np array\n        mel = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=n_mels, \n                                             fmax=8000, hop_length=512)\n        mel_db = librosa.power_to_db(mel, ref=np.max)\n        return mel_db\n    except:\n        return None","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T14:57:38.255501Z","iopub.execute_input":"2026-05-18T14:57:38.256289Z","iopub.status.idle":"2026-05-18T14:57:38.261008Z","shell.execute_reply.started":"2026-05-18T14:57:38.256256Z","shell.execute_reply":"2026-05-18T14:57:38.260172Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DATA_DIR = \"/kaggle/input/competitions/birdclef-2024/train_audio\"\n\nX = []\ny = []\n\nfor _, row in df.iterrows():\n    file_path = os.path.join(DATA_DIR, row['primary_label'], row['filename']) # concatination for the path\n    \n    if not os.path.exists(file_path):\n        file_path = os.path.join(DATA_DIR, row['filename'])\n    \n    if os.path.exists(file_path):\n        mel = audio_to_mel(file_path)\n        if mel is not None:\n            mel = mel[:, :240]\n            if mel.shape[1] < 240:\n                mel = np.pad(mel, ((0,0), (0, 240 - mel.shape[1])), mode='constant')\n            \n            mel = mel[..., np.newaxis] # add to the shape to allow conv2d\n            X.append(mel)\n            y.append(row['primary_label'])\n\nX = np.array(X)\n# n-> total num of samples \nX = (X - X.min()) / (X.max() - X.min()) # minmax normalization\nprint(\"Final Data Shape:\", X.shape)\nprint(\"Samples loaded:\", len(y))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T14:58:32.608254Z","iopub.execute_input":"2026-05-18T14:58:32.608554Z","iopub.status.idle":"2026-05-18T15:00:10.788829Z","shell.execute_reply.started":"2026-05-18T14:58:32.608530Z","shell.execute_reply":"2026-05-18T15:00:10.787982Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if len(y) == 0:\n    print(\"No data loaded\")\nelse:\n    label_encoder = LabelEncoder()\n    y_encoded = label_encoder.fit_transform(y)\n    y_cat = to_categorical(y_encoded)\n\n    print(\"Classes:\", label_encoder.classes_)\n    print(\"Number of classes:\", len(label_encoder.classes_))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T16:04:45.434287Z","iopub.execute_input":"2026-05-18T16:04:45.434694Z","iopub.status.idle":"2026-05-18T16:04:45.441638Z","shell.execute_reply.started":"2026-05-18T16:04:45.434666Z","shell.execute_reply":"2026-05-18T16:04:45.440979Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X_train, X_test, y_train, y_test = train_test_split(\n    X, y_cat, test_size=0.2, random_state=42, stratify=y_encoded\n)\n\nprint(\"Train shape:\", X_train.shape)\nprint(\"Test shape:\", X_test.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T16:05:02.220339Z","iopub.execute_input":"2026-05-18T16:05:02.220811Z","iopub.status.idle":"2026-05-18T16:05:02.317729Z","shell.execute_reply.started":"2026-05-18T16:05:02.220779Z","shell.execute_reply":"2026-05-18T16:05:02.316836Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = Sequential()\n\nmodel.add(Conv2D(32, (3,3), activation='relu', input_shape=(128, 240, 1)))\nmodel.add(MaxPooling2D(2,2))\n\nmodel.add(Conv2D(64, (3,3), activation='relu'))\nmodel.add(MaxPooling2D(2,2))\n\nmodel.add(Conv2D(128, (3,3), activation='relu'))\nmodel.add(MaxPooling2D(2,2))\n\nmodel.add(Flatten())\nmodel.add(Dense(128, activation='relu'))\nmodel.add(Dropout(0.5))\nmodel.add(Dense(len(label_encoder.classes_), activation='softmax'))\n\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T16:05:07.058157Z","iopub.execute_input":"2026-05-18T16:05:07.059003Z","iopub.status.idle":"2026-05-18T16:05:10.489126Z","shell.execute_reply.started":"2026-05-18T16:05:07.058973Z","shell.execute_reply":"2026-05-18T16:05:10.488539Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.compile(\n    optimizer='adam',\n    loss='categorical_crossentropy',\n    metrics=['accuracy']\n)\n\nprint(\"Model compiled successfully\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T16:05:12.823456Z","iopub.execute_input":"2026-05-18T16:05:12.824111Z","iopub.status.idle":"2026-05-18T16:05:12.839198Z","shell.execute_reply.started":"2026-05-18T16:05:12.824080Z","shell.execute_reply":"2026-05-18T16:05:12.838584Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.callbacks import EarlyStopping\n\nearly_stop = EarlyStopping(monitor='val_accuracy', patience=5, restore_best_weights=True)\n\nhistory = model.fit(\n    X_train, y_train,\n    epochs=50,          # بدل 10\n    batch_size=32,\n    validation_split=0.2,\n    callbacks=[early_stop],\n    verbose=1\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T16:05:14.758819Z","iopub.execute_input":"2026-05-18T16:05:14.759573Z","iopub.status.idle":"2026-05-18T16:05:57.088281Z","shell.execute_reply.started":"2026-05-18T16:05:14.759539Z","shell.execute_reply":"2026-05-18T16:05:57.087604Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)\nprint(f\"Test Accuracy: {test_acc*100:.2f}%\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T16:07:11.452301Z","iopub.execute_input":"2026-05-18T16:07:11.453042Z","iopub.status.idle":"2026-05-18T16:07:11.863338Z","shell.execute_reply.started":"2026-05-18T16:07:11.453011Z","shell.execute_reply":"2026-05-18T16:07:11.862203Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample = X_test[0:1]\npred = model.predict(sample, verbose=0)\npredicted_idx = np.argmax(pred)\nbird_name = label_encoder.inverse_transform([predicted_idx])[0]\n\nprint(f\" Predicted Bird: {bird_name}\")\nprint(\"Probabilities:\")\nfor i, prob in enumerate(pred[0]):\n    print(f\"  {label_encoder.classes_[i]}: {prob*100:.2f}%\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T16:07:14.777839Z","iopub.execute_input":"2026-05-18T16:07:14.778728Z","iopub.status.idle":"2026-05-18T16:07:15.250062Z","shell.execute_reply.started":"2026-05-18T16:07:14.778695Z","shell.execute_reply":"2026-05-18T16:07:15.249242Z"}},"outputs":[],"execution_count":null}]}