{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":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\n\nimport glob\nglob.glob('..s/input/prostate-cancer-grade-assessment/*')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(glob.glob('../input/prostate-cancer-grade-assessment/train_images/*.tiff'))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"!pip install -qq ../input/efficientnet/efficientnet-1.0.0-py3-none-any.whl","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport cv2\nimport time\nimport skimage.io\nimport numpy as np\nimport pandas as pd\nimport imgaug as ia\nfrom PIL import Image\nfrom tqdm import tqdm\nfrom random import shuffle\nimport matplotlib.pyplot as plt\nimport efficientnet.keras as efn\nfrom imgaug import augmenters as iaa\n\nfrom sklearn.model_selection import train_test_split\n\nfrom keras import Model\nimport keras.backend as K\nfrom keras.layers import *\nfrom keras.optimizers import Adam, RMSprop\nfrom keras.applications.nasnet import  preprocess_input\nfrom keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# QWK loss\n\nImplementation has some changes for probabilistic output"},{"metadata":{"trusted":true},"cell_type":"code","source":"def quadratic_kappa_coefficient(y_true, y_pred):\n    y_true = K.cast(y_true, \"float32\")\n    n_classes = K.cast(y_pred.shape[-1], \"float32\")\n    weights = K.arange(0, n_classes, dtype=\"float32\") / (n_classes - 1)\n    weights = (weights - K.expand_dims(weights, -1)) ** 2\n\n    hist_true = K.sum(y_true, axis=0)\n    hist_pred = K.sum(y_pred, axis=0)\n\n    E = K.expand_dims(hist_true, axis=-1) * hist_pred\n    E = E / K.sum(E, keepdims=False)\n\n    O = K.transpose(K.transpose(y_true) @ y_pred)  # confusion matrix\n    O = O / K.sum(O)\n\n    num = weights * O\n    den = weights * E\n\n    QWK = (1 - K.sum(num) / K.sum(den))\n    return QWK\n\ndef quadratic_kappa_loss(scale=2.0):\n    def _quadratic_kappa_loss(y_true, y_pred):\n        QWK = quadratic_kappa_coefficient(y_true, y_pred)\n        loss = -K.log(K.sigmoid(scale * QWK))\n        return loss\n        \n    return _quadratic_kappa_loss","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"I = Input((256,256,3))\nefnb3 = efn.EfficientNetB3(weights = None, include_top = False, input_tensor = I, pooling = 'avg', classes = None)\nfor layer in efnb3.layers:\n    layer.trainable = True\nx = Dropout(0.5)(efnb3.output)\nx = Dense(64, activation='relu')(x)\nx = Dense(6,activation='softmax')(x)\n\nmodel = Model(inputs = efnb3.input, outputs = x)\n\nmodel.compile(optimizer=Adam(1e-4), loss=quadratic_kappa_loss(scale=6.0), metrics=['acc',quadratic_kappa_coefficient])\n# model.compile(optimizer=Adam(1e-4), loss='sparse_categorical_crossentropy', metrics=['acc'])\n# model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Augmentation function"},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_seq():\n    sometimes = lambda aug: iaa.Sometimes(0.5, aug)\n    seq = iaa.Sequential(\n        [\n            # apply the following augmenters to most images\n            iaa.Fliplr(0.5), # horizontally flip 50% of all images\n            iaa.Flipud(0.2), # vertically flip 20% of all images\n            sometimes(iaa.Affine(\n                scale={\"x\": (0.9, 1.1), \"y\": (0.9, 1.1)}, # scale images to 80-120% of their size, individually per axis\n                translate_percent={\"x\": (-0.1, 0.1), \"y\": (-0.1, 0.1)}, # translate by -20 to +20 percent (per axis)\n                rotate=(-10, 10), # rotate by -45 to +45 degrees\n                shear=(-5, 5), # shear by -16 to +16 degrees\n                order=[0, 1], # use nearest neighbour or bilinear interpolation (fast)\n                cval=(0, 255), # if mode is constant, use a cval between 0 and 255\n                mode=ia.ALL # use any of scikit-image's warping modes\n            )),\n            # execute 0 to 5 of the following (less important) augmenters per image\n            # don't execute all of them, as that would often be way too strong\n            iaa.SomeOf((0, 5),\n                [\n                    sometimes(iaa.Superpixels(p_replace=(0, 1.0), n_segments=(20, 200))), # convert images into their superpixel representation\n                    iaa.OneOf([\n                        iaa.GaussianBlur((0, 1.0)), # blur images with a sigma between 0 and 3.0\n                        iaa.AverageBlur(k=(3, 5)), # blur image using local means with kernel sizes between 2 and 7\n                        iaa.MedianBlur(k=(3, 5)), # blur image using local medians with kernel sizes between 2 and 7\n                    ]),\n                    iaa.Sharpen(alpha=(0, 1.0), lightness=(0.9, 1.1)), # sharpen images\n                    iaa.Emboss(alpha=(0, 1.0), strength=(0, 2.0)), # emboss images\n                    # search either for all edges or for directed edges,\n                    # blend the result with the original image using a blobby mask\n                    iaa.SimplexNoiseAlpha(iaa.OneOf([\n                        iaa.EdgeDetect(alpha=(0.5, 1.0)),\n                        iaa.DirectedEdgeDetect(alpha=(0.5, 1.0), direction=(0.0, 1.0)),\n                    ])),\n                    iaa.AdditiveGaussianNoise(loc=0, scale=(0.0, 0.01*255), per_channel=0.5), # add gaussian noise to images\n                    iaa.OneOf([\n                        iaa.Dropout((0.01, 0.05), per_channel=0.5), # randomly remove up to 10% of the pixels\n                        iaa.CoarseDropout((0.01, 0.03), size_percent=(0.01, 0.02), per_channel=0.2),\n                    ]),\n                    iaa.Invert(0.01, per_channel=True), # invert color channels\n                    iaa.Add((-2, 2), per_channel=0.5), # change brightness of images (by -10 to 10 of original value)\n                    iaa.AddToHueAndSaturation((-1, 1)), # change hue and saturation\n                    # either change the brightness of the whole image (sometimes\n                    # per channel) or change the brightness of subareas\n                    iaa.OneOf([\n                        iaa.Multiply((0.9, 1.1), per_channel=0.5),\n                        iaa.FrequencyNoiseAlpha(\n                            exponent=(-1, 0),\n                            first=iaa.Multiply((0.9, 1.1), per_channel=True),\n                            second=iaa.ContrastNormalization((0.9, 1.1))\n                        )\n                    ]),\n                    sometimes(iaa.ElasticTransformation(alpha=(0.5, 3.5), sigma=0.25)), # move pixels locally around (with random strengths)\n                    sometimes(iaa.PiecewiseAffine(scale=(0.01, 0.05))), # sometimes move parts of the image around\n                    sometimes(iaa.PerspectiveTransform(scale=(0.01, 0.1)))\n                ],\n                random_order=True\n            )\n        ],\n        random_order=True\n    )\n    return seq","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data generator"},{"metadata":{"trusted":true},"cell_type":"code","source":"def chunker(seq, size):\n    return (seq[pos:pos + size] for pos in range(0, len(seq), size))\n\ndef get_image(img_name):\n    data_dir = '../input/prostate-cancer-grade-assessment/train_images'\n    img_path = os.path.join(data_dir, f'{img_name}.tiff')\n    img = skimage.io.MultiImage(img_path)\n    img = cv2.resize(img[-1], (256,256))\n    return img\n\ndef data_gen(list_files, id_label_map, batch_size, augment=False):\n    seq = get_seq()\n    while True:\n        shuffle(list_files)\n        for batch in chunker(list_files, batch_size):\n            X = [get_image(x) for x in batch]\n            Y = np.zeros((len(batch),6))\n            for i in range(len(batch)):\n                Y[i,id_label_map[get_id_from_file_path(batch[i])]] = 1.0\n            if augment:\n                X = seq.augment_images(X)\n            X = [preprocess_input(x) for x in X]\n\n            yield np.array(X), np.array(Y)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_id_from_file_path(file_path):\n    return file_path.split(os.path.sep)[-1].replace('.tiff', '')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"batch_size=32\ndf_train = pd.read_csv(\"../input/prostate-cancer-grade-assessment/train.csv\")\nid_label_map = {k:v for k,v in zip(df_train.image_id.values, df_train.isup_grade.values)}","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Train-val split"},{"metadata":{"trusted":true},"cell_type":"code","source":"labeled_files = pd.read_csv(\"../input/prostate-cancer-grade-assessment/train.csv\").image_id.values\ntest_files = pd.read_csv(\"../input/prostate-cancer-grade-assessment/test.csv\").image_id.values\n\ntrain, val = train_test_split(labeled_files, test_size=0.1, random_state=101010)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Callbacks for saving, earlystopping, and reducing learning rate"},{"metadata":{"trusted":true},"cell_type":"code","source":"check_point = ModelCheckpoint('./model.h5',monitor='val_loss',verbose=True, save_best_only=True, save_weights_only=True)\nearly_stop = EarlyStopping(monitor='val_loss',patience=5,verbose=True)\nreduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Train"},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit_generator(\n    data_gen(train, id_label_map, batch_size, augment=True),\n    validation_data=data_gen(val, id_label_map, batch_size),\n    epochs=15, verbose=1,\n    callbacks=[check_point,early_stop,reduce_lr],\n    steps_per_epoch=len(train) // batch_size,\n    validation_steps=len(val) // batch_size)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Click [here](https://www.kaggle.com/prateekagnihotri/efficientnet-keras-infernce-tta) for inference kernel"},{"metadata":{},"cell_type":"markdown","source":"Thanks for reading. Please upvote if you found it helpful."}],"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}