{"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":"markdown","source":"#Alexandre HOMO et Mathis DA SILVA Master BMC\n\n# Création du modèle et entrainement \n\n#2eme script\n\n#Maintenenant que nous avons obtenus nos spectrogrammes de mel, nous allons pouvoir créer notre CNN et faire la classification de nos oiseaux. \n\n\n","metadata":{}},{"cell_type":"code","source":"#Import des packages\n\nimport numpy as np\nimport pandas as pd\nimport os\nimport pathlib\nimport PIL\nimport PIL.Image\nimport librosa\nimport tensorflow as tf\nimport matplotlib.pyplot as plt\n\nfrom tensorflow.keras import layers","metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","papermill":{"duration":6.557353,"end_time":"2020-09-05T13:03:50.137872","exception":false,"start_time":"2020-09-05T13:03:43.580519","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-12-31T17:33:50.913604Z","iopub.execute_input":"2021-12-31T17:33:50.913963Z","iopub.status.idle":"2021-12-31T17:33:58.941443Z","shell.execute_reply.started":"2021-12-31T17:33:50.91393Z","shell.execute_reply":"2021-12-31T17:33:58.939624Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Définition du chemin d'accès\n# Ici le chemin d'acces renvoi au dossier contenant les spectres de mel de tout les chants d'oiseaux enregistrés.\n\n\ndata_dir = \"../input/cornell-bird-sounds-preprocessing\"\ndata_path = pathlib.Path(data_dir)\n\n## total images\ntotal_images = len(list(data_path.glob(\"*/*.png\")))","metadata":{"papermill":{"duration":0.526142,"end_time":"2020-09-05T13:03:50.672223","exception":false,"start_time":"2020-09-05T13:03:50.146081","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-12-31T17:33:58.944152Z","iopub.execute_input":"2021-12-31T17:33:58.944801Z","iopub.status.idle":"2021-12-31T17:34:11.149194Z","shell.execute_reply.started":"2021-12-31T17:33:58.944754Z","shell.execute_reply":"2021-12-31T17:34:11.147898Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Chargement des images pour le modele\n\nBATCH_SIZE = 32 # Nous pouvons modifier la taille du batch pour diminuer le temps de calcul\nIMG_HEIGHT = 128\nIMG_WIDTH = 128\nSEED = np.random.randint(100)\n\ntrain_ds = tf.keras.preprocessing.image_dataset_from_directory(\n  data_dir,\n  validation_split=0.1,\n  subset=\"training\",\n  seed=SEED,\n  image_size=(IMG_HEIGHT, IMG_WIDTH),\n  batch_size=BATCH_SIZE)\n\nval_ds = tf.keras.preprocessing.image_dataset_from_directory(\n  data_dir,\n  validation_split=0.1,\n  subset=\"validation\",\n  seed=SEED,\n  image_size=(IMG_HEIGHT, IMG_WIDTH),\n  batch_size=BATCH_SIZE)","metadata":{"papermill":{"duration":4.925101,"end_time":"2020-09-05T13:03:55.605217","exception":false,"start_time":"2020-09-05T13:03:50.680116","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-12-31T17:34:11.150984Z","iopub.execute_input":"2021-12-31T17:34:11.151461Z","iopub.status.idle":"2021-12-31T17:34:19.84152Z","shell.execute_reply.started":"2021-12-31T17:34:11.151415Z","shell.execute_reply":"2021-12-31T17:34:19.840236Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cache_train_ds = train_ds.cache().prefetch(tf.data.experimental.AUTOTUNE)\ncache_val_ds = val_ds.cache().prefetch(tf.data.experimental.AUTOTUNE)","metadata":{"papermill":{"duration":0.022058,"end_time":"2020-09-05T13:03:55.63682","exception":false,"start_time":"2020-09-05T13:03:55.614762","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-12-31T17:34:19.843294Z","iopub.execute_input":"2021-12-31T17:34:19.84363Z","iopub.status.idle":"2021-12-31T17:34:19.854582Z","shell.execute_reply.started":"2021-12-31T17:34:19.843596Z","shell.execute_reply":"2021-12-31T17:34:19.853589Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Architecture du CNN\n\nnum_classes = 264 # Nombre d'especes d'oiseaux \n\n# Le nombre ainsi que la nature des couches peut etre modifié, par exemple nouspouvons rajouter des couches de conv2D,dropout\n#\nmodel = tf.keras.Sequential([ #Keras = package pour faire du machine learning sur Python\n  layers.experimental.preprocessing.Rescaling(1./255), # Changement d\"echelle de 0:255 a 0:1\n  layers.Conv2D(32, 3, activation='relu'), # 32 filtres de 3x3 avec une fonction d'activation = relu\n  layers.MaxPooling2D(), # Filtre de convolution selectionnant le(s) pixel(s) avec la plus forte intensité \n  layers.Dropout(0.2), # Permet de reduire a moindre cout le sur-apprentissage \n  layers.Conv2D(32, 3, activation='relu'),\n  layers.MaxPooling2D(),\n  layers.Dropout(0.2),\n  layers.Conv2D(32, 3, activation='relu'),\n  layers.MaxPooling2D(),\n  layers.Flatten(), # Applatissmeent des données necéssaire au réseau \n  layers.Dense(128, activation='relu'), # Couche dense (argument d'entrée = 128)\n  layers.Dense(num_classes)\n])\n\nmodel.compile(\n  optimizer='adam',\n  loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),\n  metrics=['accuracy'])","metadata":{"papermill":{"duration":0.071575,"end_time":"2020-09-05T13:03:55.718012","exception":false,"start_time":"2020-09-05T13:03:55.646437","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-12-31T17:34:19.85771Z","iopub.execute_input":"2021-12-31T17:34:19.858198Z","iopub.status.idle":"2021-12-31T17:34:19.915896Z","shell.execute_reply.started":"2021-12-31T17:34:19.858145Z","shell.execute_reply":"2021-12-31T17:34:19.914976Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"epochs = 10 # Nombre de fois ou le jeu de données passe dans le CNN avant de réactualiser les poids des neurones \n# Nous pouvons diminuer cette valeur pour réduire le temps de calcul. Attention à ne pas trop réduire cette valeur car cela\n# pourrait affecter la précision du modèle.\n\nhistory = model.fit(\n  cache_train_ds,\n  validation_data=val_ds,\n  shuffle=True,\n  epochs=epochs\n)","metadata":{"papermill":{"duration":9677.882495,"end_time":"2020-09-05T15:45:13.610356","exception":false,"start_time":"2020-09-05T13:03:55.727861","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-12-31T17:34:19.920941Z","iopub.execute_input":"2021-12-31T17:34:19.921366Z","iopub.status.idle":"2021-12-31T19:02:01.278807Z","shell.execute_reply.started":"2021-12-31T17:34:19.921327Z","shell.execute_reply":"2021-12-31T19:02:01.277625Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ci-dessus, nous avons les epochs avec les valeurs de la loss et de l'accuracy. Nous avons une epoch par ligne avec une durée moyenne de 520s.\n# On observe une augmentation de l'accuracy plus rapide lors des premières epochs et une diminution plus forte de la loss lors des premières epochs. \n# En effet, on atteint un palier lorsque l'on augmente le nombre d'epochs ( si l'on avait mis 50 epochs nous aurions pu l'observer)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Permet de tracer les courbes de précision et de perte\n\nimport matplotlib.pyplot as plt\n\nacc = history.history['accuracy']\nval_acc = history.history['val_accuracy']\n\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nepochs_range = range(epochs)\n\nplt.figure(figsize=(8, 8))\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, acc, label='Training Accuracy')\nplt.plot(epochs_range, val_acc, label='Validation Accuracy')\nplt.legend(loc='lower right')\nplt.title('Training and Validation Accuracy')\n\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, loss, label='Training Loss')\nplt.plot(epochs_range, val_loss, label='Validation Loss')\nplt.legend(loc='upper right')\nplt.title('Training and Validation Loss')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-31T19:02:01.281062Z","iopub.execute_input":"2021-12-31T19:02:01.281422Z","iopub.status.idle":"2021-12-31T19:02:01.671713Z","shell.execute_reply.started":"2021-12-31T19:02:01.281386Z","shell.execute_reply":"2021-12-31T19:02:01.6705Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Résultats \n\n#Ici sont représentées les courbes de précision et de perte. L'accuracy est le rapport entre le nombre de bonnes prédictions \n# et le nombre de prédictions totales. Quand à elle, la loss est un indicateur de la performance du modèle. Plus elle baisse, plus le modèle est performant. \n# On observe aussi la présence de 2 courbes (bleu et orange). Cela permet de comparer le modèle entre le jeu de training et de validation.\n# Dans notre cas, les 2 courbes sont très similaires, cela indique que le modèle n'est pas sur-entrainé au jeu de training. \n\n# Pour le graphique d'accuracy on observe une augmentation qui monte de 0.0965 lors de la première epoch jusque 0.6573 (10ème epoch). On observe aussi une augmentation forte qui correspond aux premières epochs\n# et un palier qui se met en place lors des dernières epochs comme décrit précedemment. \n\n# Pour le graphique de la loss. Celle-ci passe de 4.6329 (1ère epoch) à 2.0103 (10ème epoch). Cela démontre l'amélioration de la performance du modèle au cours des epochs. \n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.save(\"./model_backup.h5\")\nnp.save(\"class_indices.npy\", np.array(train_ds.class_names))","metadata":{"execution":{"iopub.status.busy":"2021-12-31T19:02:01.673216Z","iopub.execute_input":"2021-12-31T19:02:01.673521Z","iopub.status.idle":"2021-12-31T19:02:01.735637Z","shell.execute_reply.started":"2021-12-31T19:02:01.673491Z","shell.execute_reply":"2021-12-31T19:02:01.734441Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for x, y in cache_val_ds.take(1):\n    predicts = model.predict(x)\n    for index, y_real in enumerate(y):\n        y_pred = predicts[index]\n        score = tf.nn.softmax(y_pred)\n        print(f'Class: {train_ds.class_names[y_real]} -  Predict as {train_ds.class_names[np.argmax(y_pred)]} with score {np.max(score) * 100}%')","metadata":{"execution":{"iopub.status.busy":"2021-12-31T19:02:01.737587Z","iopub.execute_input":"2021-12-31T19:02:01.739438Z","iopub.status.idle":"2021-12-31T19:02:02.373006Z","shell.execute_reply.started":"2021-12-31T19:02:01.739359Z","shell.execute_reply":"2021-12-31T19:02:02.371845Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Exemples de prédictions \n# On observe quelques exemples de chants avec leur prédiction par le modèle. On observe une tendance: les bonnes prédictions d'espèces ont un score élevé\n# et les erreurs ont un score faible. \n# Par exemple un individu normoc a été prédit normoc avec 99.84%. Un individu lobdow a été prédit lobdow avec 35.7%. \n# Un comrav a été prédit mallar3 avec 3.33%.\n\n\n# Perspectives\n# L'étude des chants d'oiseaux s'avére être une tâche délicate. Malgré une accuracy de plus de 65% notre modèle semble perfectible. \n# Nous pourrions essayer de modifier de nombreux paramètres ou bien l'architecture du réseau. Des réseaux performants existent comme les resnet, alexnet....\n# De plus, certaines espèces contennaient peu d'individus. Avoir une répartition plus homogéne du nombre d'individus par classe pourrait être une perspective d'amélioration du modèle.\n# Le projet posséde aussi de nombreuses difficultées. Par exemple, la présence de pollution sonore (environnement, autres oiseaux...) affecte fortement le modèle.\n# Nous avons aussi une limite géographique. Des oiseaux d'une même espèce provenant de zones géographiques différentes sont regroupées au sein de la même catégorie. \n# La prise en compte de la localisation pourrait être une piste d'amèlioration. \n# Une autre piste d'amélioration concerne la variabilité des chants au sein d'une même espèce. Un oiseau peut émettre plusieurs chants en fonction des saisons (reproduction,...).","metadata":{},"execution_count":null,"outputs":[]}]}