{"cells":[{"metadata":{},"cell_type":"markdown","source":"Hey guys, this kernel is a very simple baseline for the competition and I train the images using Keras VGG16. \n\nI'll keep making changes to the kernel as I'm trying to improve the model. If you like the kernel, **Don't forget to upvote**.\n\nthis work is inspired from: https://www.kaggle.com/ibtesama/simple-baseline-keras-vgg16 \n\nThis just still a work in progress.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## About the competition\n\nWith more than 1 million new diagnoses reported every year, prostate cancer (PCa) is the second most common cancer among males worldwide that results in more than 350,000 deaths annually. The key to decreasing mortality is developing more precise diagnostics. Diagnosis of PCa is based on the grading of prostate tissue biopsies. These tissue samples are examined by a pathologist and scored according to the Gleason grading system. In this challenge, we have to develop models for detecting PCa on images of prostate tissue samples.\n\nThe training set consists of around 11,000 whole-slide(WSI) images of digitized H&E-stained biopsies(a standard way of staining the originally transparent tissue to produce some contrast) originating from Radboud University Medical Center and Karolinska Institute(the data_provider field in train/test corresponds to this).\n\nThe data is provided in 4 parts:-\n* train.csv:- That contains the image_id,name of either of the two data provider, gleason and ISUP grade.\n* test.csv:- containing just image_ids and data_provider.\n* train_images:- A folder containing biopsy images in a large multilevel .tiff file.(some of these images will be used for testing).\n* tarin_label_masks:-A folder containing segmentation masks showing which parts of the image led to the ISUP grade. Not all training images have label masks, and there may be false positives or false negatives in the label masks for a variety of reasons. These masks are provided to assist with the development of strategies for selecting the most useful subsamples of the images. The mask values also depend on the data provider.","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\nimport openslide\nimport os\nimport cv2\nimport PIL\nfrom IPython.display import Image, display\nfrom keras.applications.vgg16 import VGG16,preprocess_input\n# Plotly for the interactive viewer (see last section)\nimport plotly.graph_objs as go\nfrom sklearn.metrics import cohen_kappa_score\nfrom sklearn.model_selection import train_test_split\nfrom keras.models import Sequential, Model,load_model\nfrom keras.applications.vgg16 import VGG16,preprocess_input\nfrom keras.applications.resnet50 import ResNet50\nfrom keras.preprocessing.image import ImageDataGenerator,load_img, img_to_array\nfrom keras.models import Sequential\nfrom keras.layers import Conv2D, MaxPooling2D, Dense, Dropout, Input, Flatten,BatchNormalization,Activation\nfrom keras.layers import GlobalMaxPooling2D\nfrom keras.models import Model\nfrom keras.optimizers import Adam, SGD, RMSprop\nfrom keras.callbacks import ModelCheckpoint, Callback, EarlyStopping\nfrom keras.utils import to_categorical\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\n# Option 2: Load images using skimage (requires that tifffile is installed)\nimport skimage.io\nimport random\nimport seaborn as sns\n\n\n# General packages\nimport matplotlib\nimport matplotlib.pyplot as plt\nimport PIL\nfrom IPython.display import Image, display\n\n# Plotly for the interactive viewer (see last section)\nimport plotly.graph_objs as go\n\nfrom keras.models import Sequential, Model, load_model\nfrom keras import applications\nfrom keras import optimizers\nfrom keras.layers import Dropout, Flatten, Dense\nfrom keras.layers import Input\n\nfrom keras.applications.vgg16 import VGG16\nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.applications.vgg16 import preprocess_input\n\nimport tensorflow as tf\nfrom tensorflow.keras.optimizers import SGD\nfrom sklearn import preprocessing, metrics\nfrom sklearn.model_selection import cross_validate\nfrom sklearn.metrics import cohen_kappa_score \nimport gc\nimport skimage.io\nfrom sklearn.model_selection import KFold\n# for dirname, _, filenames in os.walk('/kaggle/input'):\n#     for filename in filenames:\n#         print(os.path.join(dirname, filename))\n\n# Any results you write to the current directory are saved as output.\nimport tensorflow as tf\nfrom tensorflow.python.keras import backend as K\nsess = K.get_session()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"train=pd.read_csv('/kaggle/input/prostate-cancer-grade-assessment/train.csv')\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"\nLet's take a look at one of the biopsy.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"img=openslide.OpenSlide('/kaggle/input/prostate-cancer-grade-assessment/train_images/2fd1c7dc4a0f3a546a59717d8e9d28c3.tiff')\ndisplay(img.get_thumbnail(size=(512,512)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img.dimensions","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"These images are pretty big in size for training I'll be using the resized 512x512 dataset uploaded by @xhlulu.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"patch = img.read_region((18500,4100), 0, (256, 256))\n\n# Display the image\ndisplay(patch)\n# Close the opened slide after use\nimg.close()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We are asked to predict ISUP grade(scale 0-5) for each prostate biopsy image, which is in turn derived from the gleason score(three categories 3,4,5).Before diving deeper into the competition let's try to understand these first.\n\n## Gleason Score:-\nSince prostate tumors are often made up of cancerous cells that have different grades, two grades are assigned for each patient.  A primary grade is given to describe the cells that make up the largest area of the tumor and a secondary grade is given to describe the cells of the next largest area.  For instance, if the Gleason Score is written as 3+4=7, it means most of the tumor is grade 3 and the next largest section of the tumor is grade 4, together they make up the total Gleason Score.  If the cancer is almost entirely made up of cells with the same score, the grade for that area is counted twice to calculated the total Gleason Score. \n\nThe samples are made up of glandular tissue and connective tissue. The glands are hollow structures, which can be seen as white “holes” or branched cavities in the WSI. The appearance of the glands forms the basis of the Gleason grading system.\n\n![](https://www.prostateconditions.org/images/about/murtagh7e_c114_f04-2.png)\n\n\nThis is how Gleason score is decided from(3-5), 5 being the most severe. To understand more [read this](https://www.kaggle.com/c/prostate-cancer-grade-assessment/overview/additional-resources).\n\n\n## ISUP grade\nAccording to current guidelines by the International Society of Urological Pathology (ISUP), the Gleason scores are summarized into an ISUP grade on a scale from 1 to 5 according to the following rule:\n\n* Gleason score 6 = ISUP grade 1\n* Gleason score 7 (3 + 4) = ISUP grade 2\n* Gleason score 7 (4 + 3) = ISUP grade 3\n* Gleason score 8 = ISUP grade 4\n* Gleason score 9-10 = ISUP grade 5.\n\nAn example as provided on the official page of the competition can make us understand better.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"![](https://storage.googleapis.com/kaggle-media/competitions/PANDA/Screen%20Shot%202020-04-08%20at%202.03.53%20PM.png)\n\n\n\nThe most common (blue outline, Gleason pattern 3) and second most common (red outline, Gleason pattern 4) cancer growth patterns present in the biopsy dictate the Gleason score (3+4 for this biopsy), which in turn is converted into an ISUP grade (2 for this biopsy) following guidelines of the International Society of Urological Pathology. Biopsies not containing cancer are represented by an ISUP grade of 0 in this challenge.\n\nLet's also look at the class distribution.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train['isup_grade'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The classes are imbalanced, more severe cases are underrepresented.\n\nLet's start preparing the images for training.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train['gleason_score'].unique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train[(train['isup_grade'] == 2) & (train['gleason_score'] == '4+3')]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.drop([7273],inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train['gleason_score'] = train['gleason_score'].apply(lambda x: \"0+0\" if x==\"negative\" else x)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(len(train[train['gleason_score']=='negative']['isup_grade']))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"temp = train.groupby('isup_grade').count()['image_id'].reset_index().sort_values(by='image_id',ascending=False)\ntemp.style.background_gradient(cmap='Purples')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"temp = train.groupby('gleason_score').count()['image_id'].reset_index().sort_values(by='image_id',ascending=False)\ntemp.style.background_gradient(cmap='Reds')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"labels=[]\ndata=[]\ndata_dir='/kaggle/input/panda-resized-train-data-512x512/train_images/train_images/'\nfor i in range(train.shape[0]):\n    data.append(data_dir + train['image_id'].iloc[i]+'.png')\n    labels.append(train['isup_grade'].iloc[i])\ndf=pd.DataFrame(data)\ndf.columns=['images']\ndf['isup_grade']=labels","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nX_train, X_test, y_train, y_test  = train_test_split(df['images'],df['isup_grade'], test_size=0.05, random_state=1234)\nX_train, X_val, y_train, y_val = train_test_split(df['images'],df['isup_grade'], test_size=0.35, random_state=1234)\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train=pd.DataFrame(X_train)\ntrain.columns=['images']\ntrain['isup_grade']=y_train\n\nvalidation=pd.DataFrame(X_val)\nvalidation.columns=['images']\nvalidation['isup_grade']=y_val\n\ntest=pd.DataFrame(X_test)\ntest.columns=['images']\ntest['isup_grade']=y_test\n\n\ntrain['isup_grade']=train['isup_grade'].astype(str)\nvalidation['isup_grade']=validation['isup_grade'].astype(str)\ntest['isup_grade']=test['isup_grade'].astype(str)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"So the basic preprocessing I've done is:-\n* Normalizing the images.\n* Reshape the images to be of shape 224,224,3\n* Basic image augmentation like rotation, flipping etc.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train_datagen = ImageDataGenerator(rescale=1./255,rotation_range=20,\n    width_shift_range=0.2,\n    height_shift_range=0.2,horizontal_flip=True)\nval_datagen=train_datagen = ImageDataGenerator(rescale=1./255)\ntest_datagen=train_datagen = ImageDataGenerator(rescale=1./255)\n\ntrain_generator = train_datagen.flow_from_dataframe(\n    train,\n    x_col='images',\n    y_col='isup_grade',\n    target_size=(224, 224),\n    batch_size=32,\n    class_mode='categorical')\n\nvalidation_generator = val_datagen.flow_from_dataframe(\n    validation,\n    x_col='images',\n    y_col='isup_grade',\n    target_size=(224, 224),\n    batch_size=32,\n    class_mode='categorical')\ntest_generator = test_datagen.flow_from_dataframe(\n    test,\n    x_col='images',\n    y_col='isup_grade',\n    target_size=(224, 224),\n    batch_size=32,\n    class_mode='categorical')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def vgg16_model( num_classes=None):\n\n    model = VGG16(weights='/kaggle/input/keras-pretrained-models/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5', include_top=False, input_shape=(224, 224, 3))\n    x=Flatten()(model.output)\n    output=Dense(num_classes,activation='softmax')(x)\n    model=Model(model.input,output)\n    return model\n\nvgg_conv=vgg16_model(6)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's take a look at the architecture.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"vgg_conv.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def kappa_score(y_true, y_pred):\n    \n    y_true=tf.math.argmax(y_true)\n    y_pred=tf.math.argmax(y_pred)\n    return tf.compat.v1.py_func(cohen_kappa_score ,(y_true, y_pred),tf.double)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"opt = SGD(lr=0.001)\nvgg_conv.compile(loss='categorical_crossentropy',optimizer=opt,metrics=[kappa_score, 'accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"nb_epochs = 50\nbatch_size=32\nnb_train_steps = train.shape[0]//batch_size\nnb_val_steps=validation.shape[0]//batch_size\nprint(\"Number of training and validation steps: {} and {}\".format(nb_train_steps,nb_val_steps))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history = vgg_conv.fit_generator(\n    train_generator,\n    steps_per_epoch=nb_train_steps,\n    epochs=nb_epochs,\n    validation_data=validation_generator,\n    validation_steps=nb_val_steps)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Check Performance\nacc = history.history['accuracy']\nval_acc = history.history['val_accuracy']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\nkappa = history.history['kappa_score']\nval_kappa = history.history['val_kappa_score']\n\nepochs = range(len(loss))\n\nplt.plot(epochs, acc, 'b', label='Training accuracy')\nplt.plot(epochs, val_acc, 'r', label='Validation accuracy')\nplt.title('Training and validation accuracy')\nplt.legend()\n\nplt.figure()\n\nplt.plot(epochs, loss, 'b', label='Training loss')\nplt.plot(epochs, val_loss, 'r', label='Validation loss')\nplt.title('Training and validation loss')\nplt.legend()\n\nplt.show()\n\nplt.plot(epochs, loss, 'b', label='kappa')\nplt.plot(epochs, val_loss, 'r', label='val_kappa')\nplt.title('Training and validation kappa')\nplt.legend()\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Submission ","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# submission code from https://www.kaggle.com/frlemarchand/high-res-samples-into-multi-input-cnn-keras\ndef predict_submission(df, path):\n    \n    df[\"image_path\"] = [path+image_id+\".tiff\" for image_id in df[\"image_id\"]]\n    df[\"isup_grade\"] = 0\n    predictions = []\n    for idx, row in df.iterrows():\n        print(row.image_path)\n        img=skimage.io.imread(str(row.image_path))\n        img = cv2.resize(img, (224,224))\n        img = cv2.resize(img, (224,224))\n        img = img.astype(np.float32)/255.\n        img=np.reshape(img,(1,224,224,3))\n        prediction=vgg_conv.predict(img)\n        predictions.append(np.argmax(prediction))\n            \n    df[\"isup_grade\"] = predictions\n    df = df.drop('image_path', 1)\n    return df[[\"image_id\",\"isup_grade\"]]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_path = \"../input/prostate-cancer-grade-assessment/test_images/\"\nsubmission_df = pd.read_csv(\"../input/prostate-cancer-grade-assessment/sample_submission.csv\")\n\nif os.path.exists(test_path):\n    test_df = pd.read_csv(\"../input/prostate-cancer-grade-assessment/test.csv\")\n    submission_df = predict_submission(test_df, test_path)\n\nsubmission_df.to_csv('submission.csv', index=False)\nsubmission_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## References:-\n* https://www.prostateconditions.org/about-prostate-conditions/prostate-cancer/newly-diagnosed/gleason-score","execution_count":null}],"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":4,"nbformat_minor":4}