{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# Import required libraries\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport matplotlib\nimport os\nimport matplotlib.pyplot as plt\nfrom matplotlib import patches\nimport cv2\nfrom keras.callbacks import Callback\nfrom keras_preprocessing.image import ImageDataGenerator\nfrom keras.models import Sequential\nfrom keras.layers.convolutional import Conv2D, MaxPooling2D\nfrom keras.layers.core import Activation, Flatten, Dense\nfrom keras.layers import BatchNormalization\nfrom keras.layers import Dropout\nfrom keras.optimizers import Adam\nfrom keras.callbacks import ModelCheckpoint\nfrom sklearn.metrics import roc_curve,auc, confusion_matrix","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c0719746d290d1ea785e804c3f63ff58534f6bfc"},"cell_type":"code","source":"print (\"Number of train files:\",len(os.listdir(\"../input/train\")))\nprint (\"Number of test files:\",len(os.listdir(\"../input/test\")))\n\ndftrain=pd.read_csv(\"../input/train_labels.csv\",dtype=str)\ndftrain.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2491a515cd98b10656b4931799ab7f8496f4a2e3"},"cell_type":"code","source":"print(\"Counts of negative and postive labels in training data:\")\ndftrain.groupby(['label']).count()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d15fa7fc1cc4a7e8d2778b1acc6d153d24587841"},"cell_type":"code","source":"def add_ext(id):\n    return id+\".tif\"\n\ndftrain[\"id\"]=dftrain[\"id\"].apply(add_ext)\n\ndef addpath(col):\n    return '../input/train/' + col \n\ndftrain['Path']=dftrain['id'].apply(addpath)\ndftrain.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"937f77628b0ae852a6757f574efef37489746de8"},"cell_type":"code","source":"## function to plot historgrams\n\ndef plothist(plot_img,axnum):\n    color = ('b','g','r')\n    for j,col in enumerate(color):\n         histr = cv2.calcHist([plot_img],[j],None,[256],[0,256])\n         ax[axnum,i].plot(histr,color = col)\n         ax[axnum,i].set_xlim([0,256])\n         ax[axnum,i].set_xlabel(\"Pixel Values\")\n         ax[axnum,0].set_ylabel(\"# of Pixels\")\n    return ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3cc53703119dbfdaf31709e78b33b7332707a8c8"},"cell_type":"code","source":"## print a sample of the images\nnums = [76, 46, 69, 20, 17] # random.sample(range(1, 100), 5)\nnum_pics = len(nums)\nf,ax = plt.subplots(3,num_pics,figsize=(15,15))\n\nfor i in range(5):\n    img = plt.imread(dftrain.iloc[nums[i]]['Path'])\n   # ax[i].imshow(img)\n   # ax[i].set_title(dfdata.iloc[i]['label'],fontweight=\"bold\", size=20)\n    ax[0,i].imshow(img)\n    ax[0,i].set_title(dftrain.iloc[i]['label'],fontweight=\"bold\", size=20)\n    # Create a Rectangle patch\n    rect = patches.Rectangle((32,32),32,32,linewidth=3,edgecolor='r',facecolor='none')\n    # Add the patch to the Axes\n    ax[0,i].add_patch(rect)\n    ## plot histograms of full image and cancer patch\n    plothist(img,1)\n    plothist(img[32:64, 32:64],2)\n    \nplt.show() ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"df2027b16645cddfe0ee63d9b552145cc4363ada"},"cell_type":"code","source":"## use flow from directory\ndatagen=ImageDataGenerator(rescale=1./255.,validation_split=0.2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6eefdeed1f11465c2c77111b4b777d042dbdc46e"},"cell_type":"code","source":"batch_size = 20\nimage_size = (96,96)\n\ntrain_generator=datagen.flow_from_dataframe(\ndataframe=dftrain,\ndirectory=\"../input/train/\",\nx_col=\"id\",\ny_col=\"label\",\nsubset=\"training\",\nbatch_size=batch_size,\nseed=42,\nshuffle=True,\nclass_mode='categorical', #class_mode=\"binary\",\ntarget_size=image_size)\n\nvalidation_generator=datagen.flow_from_dataframe(\ndataframe=dftrain,\ndirectory=\"../input/train/\",\nx_col=\"id\",\ny_col=\"label\",\nsubset=\"validation\",\nbatch_size=batch_size,\nseed=42,\nshuffle=True,\nclass_mode='categorical', #class_mode=\"binary\",\ntarget_size=image_size)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"87af595b4375bb1e1e5d50ad6c2556a521b24310"},"cell_type":"code","source":"kernel_size = (3,3)\npool_size= (2,2)\nfirst_filters = 32\nsecond_filters = 64\nthird_filters = 128\n\ndropout_conv = 0.3\ndropout_dense = 0.3\n\nmodel = Sequential()\nmodel.add(Conv2D(first_filters, kernel_size, activation = 'relu', input_shape = (96, 96, 3)))\nmodel.add(Conv2D(first_filters, kernel_size, activation = 'relu'))\nmodel.add(MaxPooling2D(pool_size = pool_size)) \nmodel.add(Dropout(dropout_conv))\n\nmodel.add(Flatten())\nmodel.add(Dense(256, activation = \"relu\"))\nmodel.add(Dropout(dropout_dense))\nmodel.add(Dense(2, activation = \"softmax\"))\n\nmodel.summary()\n\nmodel.compile('Adam', loss = \"binary_crossentropy\", metrics=[\"accuracy\"])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"23f17003e056b3c8219b59fe936d641a23117fd1"},"cell_type":"markdown","source":"thank you to @fmarazzi for CNN architecture:\nhttps://www.kaggle.com/fmarazzi/baseline-keras-cnn-roc-fast-5min-0-8253-lb\n"},{"metadata":{"trusted":true,"_uuid":"babae9bd686119a12fa566a4112711017f3f8198"},"cell_type":"code","source":"kernel_size = (3,3)\npool_size= (2,2)\nfirst_filters = 32\nsecond_filters = 64\nthird_filters = 128\n\ndropout_conv = 0.3\ndropout_dense = 0.3\n\n\nmodel = Sequential()\nmodel.add(Conv2D(first_filters, kernel_size, activation = 'relu', input_shape = (96, 96, 3)))\nmodel.add(Conv2D(first_filters, kernel_size, activation = 'relu'))\nmodel.add(Conv2D(first_filters, kernel_size, activation = 'relu'))\nmodel.add(MaxPooling2D(pool_size = pool_size)) \nmodel.add(Dropout(dropout_conv))\n\nmodel.add(Conv2D(second_filters, kernel_size, activation ='relu'))\nmodel.add(Conv2D(second_filters, kernel_size, activation ='relu'))\nmodel.add(Conv2D(second_filters, kernel_size, activation ='relu'))\nmodel.add(MaxPooling2D(pool_size = pool_size))\nmodel.add(Dropout(dropout_conv))\n\nmodel.add(Conv2D(third_filters, kernel_size, activation ='relu'))\nmodel.add(Conv2D(third_filters, kernel_size, activation ='relu'))\nmodel.add(Conv2D(third_filters, kernel_size, activation ='relu'))\nmodel.add(MaxPooling2D(pool_size = pool_size))\nmodel.add(Dropout(dropout_conv))\n\nmodel.add(Flatten())\nmodel.add(Dense(256, activation = \"relu\"))\nmodel.add(Dropout(dropout_dense))\nmodel.add(Dense(2, activation = \"softmax\"))\n\nmodel.summary()\n\nmodel.compile(Adam(0.0001), loss = \"binary_crossentropy\", metrics=[\"accuracy\"])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"cfc4797c3eee994558aa1ab96287e4096709ccc8"},"cell_type":"code","source":"trainstep=train_generator.n//train_generator.batch_size\nvalstep=validation_generator.n//validation_generator.batch_size\n\nfilepath=\"weights-best.hdf5\"\ncheckpoint = ModelCheckpoint(filepath, monitor='val_acc', verbose=1, save_best_only=True, mode='max')\n\nhistory=model.fit_generator(generator=train_generator,\n                    steps_per_epoch=trainstep,\n                    validation_data=validation_generator,\n                    validation_steps=valstep,\n                    epochs=20,\n                    callbacks=[checkpoint]\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"94b8d86d653c8131c335a1a15ecaedab2d8d39e3"},"cell_type":"code","source":"# plot learning curves\nfilepath=\"weights-best.hdf5\"\n# summarize history for accuracy\nplt.plot(history.history['acc'])\nplt.plot(history.history['val_acc'])\nplt.title('model accuracy')\nplt.ylabel('accuracy')\nplt.xlabel('epoch')\nplt.legend(['train', 'test'], loc='upper left')\nplt.show()\n\n# summarize history for loss\nplt.plot(history.history['loss'])\nplt.plot(history.history['val_loss'])\nplt.title('model loss')\nplt.ylabel('loss')\nplt.xlabel('epoch')\nplt.legend(['train', 'test'], loc='upper left')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"14f3819ba009b9a0cbfb8f1608f8162fae67049a"},"cell_type":"code","source":"## Create test generator and evaluate model \n\nmodel.load_weights(filepath) #load saved weights\ntest_datagen=ImageDataGenerator(rescale=1./255)\n\ntest_generator=datagen.flow_from_dataframe(\ndataframe=dftrain,\ndirectory=\"../input/train/\",\nx_col=\"id\",\ny_col=\"label\",\nsubset=\"validation\",\nbatch_size=5,   # want to divide num samples evenly \nseed=42,\nshuffle=False,  # don't shuffle\nclass_mode='categorical', #class_mode=\"binary\",\ntarget_size=image_size)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"de863d00f7528a05be23c6cfb19b5569f117a166"},"cell_type":"code","source":"scores = model.evaluate_generator(test_generator)\nprint('Test loss:', round(100*scores[0],2))\nprint('Test accuracy:', round(100*scores[1],2))\nprint(\"%s: %.2f%%\" % (model.metrics_names[1], scores[1]*100))\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d143305ba52598887f11d54405c7aa5c8bcbb622"},"cell_type":"code","source":"test_labels = test_generator.classes\ny_preds = model.predict_generator(test_generator,verbose=1,steps=test_generator.n/5)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e9d3ae09382854fc4c700717706e587764c586d0"},"cell_type":"code","source":"y_pred_keras=np.argmax(y_preds, axis=-1)\nfpr_keras, tpr_keras, thresholds_keras = roc_curve(test_labels, y_pred_keras)\nauc_keras = auc(fpr_keras, tpr_keras)\nprint('AUC score :', + auc_keras)\n\nfrom sklearn.metrics import classification_report\nprint(classification_report(test_labels, y_pred_keras))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9127e6fd33b3d6b42fe486178144d284c4546469"},"cell_type":"code","source":"# plot ROC curve\nplt.figure(1)\nplt.plot([0, 1], [0, 1], 'k--')\nplt.plot(fpr_keras, tpr_keras, label='Keras (area = {:.3f})'.format(auc_keras))\nplt.xlabel('False positive rate')\nplt.ylabel('True positive rate')\nplt.title('ROC curve')\nplt.legend(loc='best')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"92beea0b9d25965e1c537fb4b9b7ba833092d2e5","scrolled":false},"cell_type":"code","source":"classes=list((test_generator.class_indices).values())\ncm=confusion_matrix(test_labels,y_pred_keras)\n\nplt.ylabel('True label')\nplt.xlabel('Predicted label')\ntick_marks = np.arange(len(classes))\nplt.xticks(tick_marks, classes)\nplt.yticks(tick_marks, classes)\nplt.imshow(cm, cmap=plt.cm.Blues)\nprint(cm)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c916887e0443046edad76df23ae4718b34b79044"},"cell_type":"code","source":"len(test_generator.filenames)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"281893aa3f682b1c6a809679ef8dc9546eb158c5"},"cell_type":"code","source":"test_frame=pd.DataFrame({'id':(test_generator.filenames)})\ntest_frame['true_label']=test_labels\ntest_frame['predicted'] = y_pred_keras\ntest_frame['no_cancer'] = y_preds[:,0]\ntest_frame['cancer'] = y_preds[:,1]\ntest_frame['Path']=test_frame['id'].apply(addpath)","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":false,"trusted":true,"_uuid":"868dbc6baa928c6fef08ac889c8e9c82644b9905"},"cell_type":"code","source":"incorrect_preds=(test_frame[test_frame.true_label != test_frame.predicted]).head()\nno_cancer=incorrect_preds.nlargest(3, columns='no_cancer')\nno_cancer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b33a2aa4d29d3946df399bc5d29eb9c60451eefc"},"cell_type":"code","source":"cancer=(incorrect_preds.nlargest(3, columns='cancer'))[(incorrect_preds.true_label==0)]\ncancer_list=cancer['id'].values.tolist()\ncancer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b0c6066c60203761060e0a18ed298fb027884333"},"cell_type":"code","source":"## plot the \"most incorrect\" images\n\nf,ax = plt.subplots(1,2,figsize=(15,15))\n\nfor i in range(len(cancer)):\n    img = plt.imread(cancer.iloc[i]['Path'])\n    ax[i].imshow(img)\n    ax[i].set_title(cancer.iloc[i]['true_label'],fontweight=\"bold\", size=20)  \n    \nplt.show() \n\nf,ax = plt.subplots(1,2,figsize=(15,15))\n\nfor i in range(2):\n    img = plt.imread(no_cancer.iloc[i]['Path'])\n    ax[i].imshow(img)\n    ax[i].set_title(no_cancer.iloc[i]['true_label'],fontweight=\"bold\", size=20)  \n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fe903fcadd95671f37043f694c39166db60157ce"},"cell_type":"code","source":"## look at the \"most correct\" submission\nno_cancer_true=test_frame.nlargest(3, columns='no_cancer')\ncancer_true=test_frame.nlargest(3, columns='cancer')\nno_cancer_true.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7ab9c5264106fd3977797a1666448d43af3250d5"},"cell_type":"code","source":"cancer_true.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"173cd9311507fc1c18bbf1edef9f92fb0ca9e437"},"cell_type":"code","source":"## plot the \"most incorrect\" images\n\nf,ax = plt.subplots(1,3,figsize=(15,15))\n\nfor i in range(3):\n    img = plt.imread(cancer_true.iloc[i]['Path'])\n    ax[i].imshow(img)\n    ax[i].set_title(cancer_true.iloc[i]['true_label'],fontweight=\"bold\", size=20)  \n    \nplt.show() \n\nf,ax = plt.subplots(1,3,figsize=(15,15))\n\nfor i in range(3):\n    img = plt.imread(no_cancer_true.iloc[i]['Path'])\n    ax[i].imshow(img)\n    ax[i].set_title(no_cancer_true.iloc[i]['true_label'],fontweight=\"bold\", size=20)  \n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9ad1cd814b441c2c42f611148ddf8deb25395653"},"cell_type":"markdown","source":"Generate perdictions for submission"},{"metadata":{"trusted":true,"_uuid":"4b2516b5bdf925004fa8264552e13cf3c844c83c"},"cell_type":"code","source":"test_results=pd.DataFrame({'id':os.listdir(\"../input/test/\")})\ntest_datagen=ImageDataGenerator(rescale=1./255)\n\nsubmit_generator=datagen.flow_from_dataframe(\ndataframe=test_results,\ndirectory=\"../input/test/\",\nx_col=\"id\",\nbatch_size=2,   # want to divide num samples evenly \nshuffle=False,  # don't shuffle\nclass_mode=None,\ntarget_size=image_size)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a8a1299669097999fcbcd210c238d610e581e556"},"cell_type":"code","source":"## use 0.5 as threshold to assign to class 0 or 1 \ny_test_prob=model.predict_generator(submit_generator,verbose=1,steps=submit_generator.n/2)\ny_test_pred=np.argmax(y_test_prob, axis=-1)  #y_test_prob.round()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"be2877dbbc8f7e1a309d94953732595e44c700e1"},"cell_type":"code","source":"results = pd.DataFrame({'id':(submit_generator.filenames)})\n\ndef remove_ext(id):\n    return (id.split('.'))[0]\nresults['id']=results['id'].apply(remove_ext)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a8278d9e57a351a1b135100e09d74b7d3baac19c"},"cell_type":"code","source":"results['label'] = y_test_pred\nresults.to_csv(\"submission.csv\",index=False)\nresults.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"595d873d5a2dd68be6c6b39ddc9e3383e44472b3"},"cell_type":"markdown","source":"**Reference Material:**\n\nI found the following kernels and resources very helpful as I worked through my first Kaggle entry! Thank you!\n\nhttps://www.kaggle.com/vbookshelf/cnn-how-to-use-160-000-images-without-crashing <br>\nhttps://www.kaggle.com/fmarazzi/baseline-keras-cnn-roc-fast-10min-0-925-lb <br>\n (more to come)\n"}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}