{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport os\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport random\n\n#Importation de la librairie FastAI\nfrom fastai import *\nfrom fastai.vision import *\nfrom torchvision.models import *\n\n#Utilisation de la séparation train/test de sklearn\nfrom sklearn.model_selection import train_test_split  \n\nprint(\"Affichage de notre environnement de travail\")\nprint(os.listdir(\"../input\"))\n\ndata = pd.read_csv('/kaggle/input/train_labels.csv')\n#Configuration du chemin d'entrainement\ntrain_path = '/kaggle/input/train/'\n#Configuration du chemin de test\ntest_path = '/kaggle/input/test/'","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Préparation des données et séparation du set d'entrainement\n\nSéparation des données avec les proportions suivantes : 90% pour l'entrainement et 10% pour la validation."},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = data.set_index('id')\ntrain_names = train_df.index.values\ntrain_labels = np.asarray(train_df['label'].values)\ntr_n, tr_idx, val_n, val_idx = train_test_split(train_names, range(len(train_names)), test_size=0.1, stratify=train_labels, random_state=123)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"On créé ensuite un panda dataframe pour l'entrainement et un panda dataframe pour le test"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Création du dataframe d'entrainement\ntrain_dict = {'name': train_path + train_names, 'label': train_labels}\ndf = pd.DataFrame(data=train_dict)\n# Création du dataset de test\ntest_names = []\nfor f in os.listdir(test_path):\n    test_names.append(test_path + f)\ndf_test = pd.DataFrame(np.asarray(test_names), columns=['name'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Chargement et visualisation des données\n\nFastAI dispose d'objets spécifiques appelés \"DataBunch\" alimentant les modèles. Ces données nous permettent de charger notre ensemble d'entrainement à partir d'un DataFrame, de spécifier l'ensemble de test, nous permets de spécifier des transformations, et d'appliquer une normalisation"},{"metadata":{"trusted":true},"cell_type":"code","source":"#On créé ici notre dataBunch, équivalent d'un flow de données alimentant notre modèle de deep learning\ntfms = get_transforms()\nBATCH_SIZE=128\nSIZE=90\ndata = ImageList.from_df(path='/', df=df, suffix='.tif').split_by_idx(val_idx).label_from_df(cols='label').add_test(ImageList.from_df(path='/', df=df_test)).databunch(bs=BATCH_SIZE).normalize(imagenet_stats)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Maintenant que notre DataBunch a été généré, nous pouvons obtenir d'avantages d'informations sur nos données. Commençons par une visualisation : "},{"metadata":{"trusted":true},"cell_type":"code","source":"#Affichage de données sans et avec cancer\ndata.show_batch(rows=3, figsize=(7, 8))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Regardons de plus près notre objet ImageDataBunch. Nous pouvons récupérer les informations suivantes : \n* Notre ensemble d'entrainement est composé de 198022 éléments\n* Notre ensemble de validation est composé de 22003 éléments\n* Notre ensemble de test est composé de 57458 éléments\n* Chaque image est de dimension 3 (R,G,B) et de taille 96 par 96.\n* Notre ensemble d'entrainement possède une image et son label, mais par notre ensemble de validation"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(data)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Création du modèle et entrainement initial\n\nNous utiliserons un modèle de deeplearning, pré entrainé, appelé densenet169 préformé et nous appliquerons la technique du \"transfert learning\" pour ajuster les paramètres à nos données. L'adoption d'une architecture deep learning permettra de converger plus rapidement et d'obtenir une solution de meilleure qualité.\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"# L'architecture de notre modèle, ici densenet169 \narch = densenet169    \n# Exraction du nom du modèle\nMODEL_PATH = str(arch).split()[1] \n#Création de notre learner, réseau convolutif d'architecture densenet169\nlearn = create_cnn(data, arch, metrics=error_rate)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Nous utiliserons la méthode du \"One cycle policy\" proposée par Leslie Smith,[arXiv, avril 2018] (https://arxiv.org/abs/1803.09820). Il s'agit d'appliqué une certaine discipline dans la sélection des hyperparamètres tels que le taux d'apprentissage. \nAfin d'appliquer cette approche, la bibliothèque FastAI a mis en œuvre une fonction, \"fit_one_cycle\"."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Utilisation de la GPU\ndefaults.device = torch.device('cuda') \n# Premier entrainement du modèle\nlearn.fit_one_cycle(4)\n#Enregistrement du modèle\nlearn.save('cancer-detection-1')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Amélioration de notre modèle initial\nFastAI fournit une autre technique pour améliorer l'apprentissage par transfert learning appelé \"differential learning rate\", qui nous permet de définir différents taux d'apprentissage pour les différentes couches du réseau.\nPour trouver le meilleur taux d'apprentissage, nous pouvons utiliser les méthodes lr_find et recorder.plot qui créent une courbe reliant le taux d'apprentissage à la perte."},{"metadata":{"trusted":true},"cell_type":"code","source":"# On dégèle les dernière couches du modèles pour l'entrainer une seconde fois par la suite\nlearn.unfreeze() \n#Avant de réentrainer le modèle, on recherche du meilleur taux d'apprentissage en suivant la technique \"différential learning late\".\nlearn.lr_find()\nlearn.recorder.plot()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Nous recherchons ici le point le plus bas, ici 1e-4\nPour former maintenant le modèle en utilisant des taux d'apprentissage différentiels, nous devons passer l'argument max_lr à la méthode fit_one_cycle."},{"metadata":{"trusted":true},"cell_type":"code","source":"#Via l'analyse graphique, le meilleur taux d'apprentissage se trouver être 4e-4\nlearn.fit_one_cycle(4, max_lr=1e-4)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Enregistrement du modèle\nlearn.save('cancer-detection-2')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Vérification de notre modèle"},{"metadata":{"trusted":true},"cell_type":"code","source":"interp = ClassificationInterpretation.from_learner(learn)\ninterp.plot_confusion_matrix()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"La matrice de confusion peut nous aider à comprendre le taux de faux négatifs et de faux positifs afin de nous permettre d'éxaminer les performances de notre modèle. Ici, nous pouvons voir que le modèle a appris à distinguer la tumeur et l'échantillon négatif et qu'il fonctionne comme nous le désirons."},{"metadata":{"trusted":true},"cell_type":"code","source":"learn.recorder.plot_lr()\nlearn.recorder.plot_losses()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Nous pouvons voir que le taux d'apprentissage commence au plus bas et atteint finalement le max_lr (4e-4) au milieu. Puis il ralentit vers la fin. L'idée est de commencer avec un faible taux d'apprentissage pour l'augmenter jusqu'à un niveau élevé. Le taux plus élevé a un effet de régularisation et évite de tomber dans des minimums locaux en forçant le modèle à apprendre de la manière la plus large possible"},{"metadata":{},"cell_type":"markdown","source":"# Validation du modèle\n\nEn prenant en compte le set de validation, la précision est la suivante:"},{"metadata":{"trusted":true},"cell_type":"code","source":"preds,y, loss = learn.get_preds(with_loss=True)\nacc = accuracy(preds, y)\nprint('The accuracy is {0} %.'.format(acc))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Affichage de l'air sous la courbe"},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.metrics import roc_curve, auc\nprobs = np.exp(preds[:,1])\nfpr, tpr, thresholds = roc_curve(y, probs, pos_label=1)\n\nroc_auc = auc(fpr, tpr)\nprint('ROC area is {0}'.format(roc_auc))\nplt.figure()\nplt.plot(fpr, tpr, color='darkorange', label='ROC curve (area = %0.2f)' % roc_auc)\nplt.plot([0, 1], [0, 1], color='navy', linestyle='--')\nplt.xlim([-0.01, 1.0])\nplt.ylim([0.0, 1.01])\nplt.xlabel('False Positive Rate')\nplt.ylabel('True Positive Rate')\nplt.title('Receiver operating characteristic')\nplt.legend(loc=\"lower right\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Soumission des résultats\n\nNous soumettons nos prédictions en appliquant une inférence sur l'ensemble de nos données de test. Le résultat est une probabilité entre 0 et 1 d'avoir évalué une cellule cancereuse."},{"metadata":{"trusted":true},"cell_type":"code","source":"#Inférence sur notre test_set\npreds,y = learn.get_preds(ds_type=DatasetType.Test, with_loss=False)\ntumor_preds = preds[:, 1]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Exporter sous le bon format pour la soumission\nSAMPLE_SUB = '/kaggle/input/sample_submission.csv'\nsample_df = pd.read_csv(SAMPLE_SUB)\nsample_list = list(sample_df.id)\npred_list = [float(p) for p in tumor_preds]\npred_dic = dict((key, value) for (key, value) in zip(learn.data.test_ds.items, pred_list))\npred_list_cor = [pred_dic['///kaggle/input/test/' + id + '.tif'] for id in sample_list]\ndf_sub = pd.DataFrame({'id':sample_list,'label':pred_list_cor})\ndf_sub.to_csv('{0}_submission.csv'.format(MODEL_PATH), header=True, index=False)\ndf_sub","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}