{"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\n\nimport os\nprint(\"Input Directory:\")\nprint(os.listdir(\"../input\"))\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\nimport sys\nimport matplotlib.pyplot as plt\nimport skimage.io\nfrom skimage.transform import resize\nfrom imgaug import augmenters as iaa\nfrom tqdm import tqdm\n\n\n'''--------------- Load Training Data --------------'''\n\n#read train.csv\ndata = pd.read_csv('../input/train.csv')\nprint(\"\\nFew samples from train.csv:\")\nprint(data[:3])\n\npath_to_train = '../input/train/'\nprint(\"\\nPath to training images:\" + path_to_train)\n\n#from train.csv - generate dataset info [{path:\"image_path\", labels:[targets]},...,{}]\ntrain_dataset_info = []\nfor name, labels in zip(data['Id'], data['Target'].str.split(' ')):\n    train_dataset_info.append({\n        'path':os.path.join(path_to_train, name),\n        'labels':np.array([int(label) for label in labels]),\n        'id':'orig'})\n\nprint(\"\\nFew samples from train dataset info:\")\nprint(train_dataset_info[:3])\n\nprint(\"\\nNo. of training images:\")\nnTrainImages = (len)(train_dataset_info)\nprint(nTrainImages)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"eabe55d32e0d83bab464112581b6330d5f8b1c80","_kg_hide-input":false,"_kg_hide-output":true},"cell_type":"code","source":"#Target Distibution In Training Data\n'''\nlabel_names = {\n    0:  \"Nucleoplasm\",  \n    1:  \"Nuclear membrane\",   \n    2:  \"Nucleoli\",   \n    3:  \"Nucleoli fibrillar center\",   \n    4:  \"Nuclear speckles\",\n    5:  \"Nuclear bodies\",   \n    6:  \"Endoplasmic reticulum\",   \n    7:  \"Golgi apparatus\",   \n    8:  \"Peroxisomes\",   \n    9:  \"Endosomes\",   \n    10:  \"Lysosomes\",   \n    11:  \"Intermediate filaments\",   \n    12:  \"Actin filaments\",   \n    13:  \"Focal adhesion sites\",   \n    14:  \"Microtubules\",   \n    15:  \"Microtubule ends\",   \n    16:  \"Cytokinetic bridge\",   \n    17:  \"Mitotic spindle\",   \n    18:  \"Microtubule organizing center\",   \n    19:  \"Centrosome\",   \n    20:  \"Lipid droplets\",   \n    21:  \"Plasma membrane\",   \n    22:  \"Cell junctions\",   \n    23:  \"Mitochondria\",   \n    24:  \"Aggresome\",   \n    25:  \"Cytosol\",   \n    26:  \"Cytoplasmic bodies\",   \n    27:  \"Rods & rings\"\n}\n\nfor key in label_names.keys():\n    data[label_names[key]] = 0\n\ndef fill_targets(row):\n    row.Target = np.array(row.Target.split(\" \")).astype(np.int)\n    for num in row.Target:\n        name = label_names[int(num)]\n        row.loc[name] = 1\n    return row\n\ndata = data.apply(fill_targets, axis=1) \n\n#plot\nimport seaborn as sns\nsns.set()\n\ntarget_counts = data.drop([\"Id\", \"Target\"],axis=1).sum(axis=0).sort_values(ascending=False)\nplt.figure(figsize=(15,15))\nsns.barplot(y=target_counts.index.values, x=target_counts.values, order=target_counts.index)\n'''","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6c37040f0ff28ba3596033d789abf0b878bdaa7c"},"cell_type":"code","source":"'''--------------- Generate Dataset for Augmentation --------------'''\n\ntrain_dataset_info_aug = [] #duplicate data for augmentation\n\ntrain_dataset_info_aug0 = []\ntrain_dataset_info_aug1 = []\ntrain_dataset_info_aug2 = []\ntrain_dataset_info_aug3 = []\n\nfor name, labels in zip(data['Id'], data['Target'].str.split(' ')):\n    #1 19 3 4(speckels):\n    #18 6 14 11(filaments)\n    #16 13 12 22(cell junction)\n    #27 15 10 9 8 20 17 24 26(cytoplasmic bodies) \n    #L2R and B2T sample count inc -> 27(rods&rings): min count and 4(Nuclear Speckels): max count\n    #Others with higher sample count ignored in duplication\n    if ((\"27\" in labels) or (\"15\" in labels) or (\"10\" in labels) or (\"9\" in labels) or (\"8\" in labels) or (\"20\" in labels) or (\"17\" in labels) or \n        (\"24\" in labels) or (\"26\" in labels) or(\"16\" in labels) or(\"13\" in labels) or (\"12\" in labels) or (\"22\" in labels) or (\"18\" in labels) or\n        (\"6\" in labels) or (\"14\" in labels) or(\"11\" in labels) or (\"1\" in labels) or (\"19\" in labels) or (\"3\" in labels) or (\"4\" in labels)):\n        train_dataset_info_aug0.append({\n            'path':os.path.join(path_to_train, name),\n            'labels':np.array([int(label) for label in labels]),\n            'id': \"set0\"})\n    if (((\"27\" in labels) or (\"15\" in labels) or (\"10\" in labels) or (\"9\" in labels) or (\"8\" in labels) or (\"20\" in labels) or (\"17\" in labels) or \n        (\"24\" in labels) or (\"26\" in labels) or(\"16\" in labels) or(\"13\" in labels) or (\"12\" in labels) or (\"22\" in labels) or (\"18\" in labels) or\n        (\"6\" in labels) or (\"14\" in labels) or(\"11\" in labels) or (\"1\" in labels) or (\"19\" in labels) or (\"3\" in labels) or (\"4\" in labels)) and (\"0\" not in labels and \"25\" not in labels)):\n        train_dataset_info_aug1.append({\n            'path':os.path.join(path_to_train, name),\n            'labels':np.array([int(label) for label in labels]),\n            'id': \"set1\"})\n    if (((\"27\" in labels) or (\"15\" in labels) or (\"10\" in labels) or (\"9\" in labels) or (\"8\" in labels) or (\"20\" in labels) or (\"17\" in labels) or \n        (\"24\" in labels) or (\"26\" in labels) or(\"16\" in labels) or(\"13\" in labels) or (\"12\" in labels) or (\"22\" in labels) or (\"18\" in labels) or\n        (\"6\" in labels) or (\"14\" in labels) or(\"11\" in labels)) and (\"0\" not in labels and \"25\" not in labels)):\n        train_dataset_info_aug2.append({\n            'path':os.path.join(path_to_train, name),\n            'labels':np.array([int(label) for label in labels]),\n            'id': \"set2\"})\n    if (((\"27\" in labels) or (\"15\" in labels) or (\"10\" in labels) or (\"9\" in labels) or (\"8\" in labels) or (\"20\" in labels) or (\"17\" in labels) or \n        (\"24\" in labels) or (\"26\" in labels) or(\"16\" in labels) or(\"13\" in labels) or (\"12\" in labels) or (\"22\" in labels)) and (\"0\" not in labels and \"25\" not in labels)):\n        train_dataset_info_aug3.append({\n            'path':os.path.join(path_to_train, name),\n            'labels':np.array([int(label) for label in labels]),\n            'id': \"set3\"})\n        \nfor sample in train_dataset_info_aug0:\n    train_dataset_info_aug.append(sample)\nfor sample in train_dataset_info_aug1:\n    train_dataset_info_aug.append(sample)\nfor sample in train_dataset_info_aug2:\n    train_dataset_info_aug.append(sample)\nfor sample in train_dataset_info_aug3:\n    train_dataset_info_aug.append(sample)\n\nnp.random.shuffle(train_dataset_info_aug)\n\nnSamplesOrig = (len)(train_dataset_info)\nnSamplesAug = (len)(train_dataset_info_aug)\n\ntrain_dataset_info = np.array(train_dataset_info)\nprint(\"\\nOrig train dataset samples:\")\nprint(nSamplesOrig)\nprint(\"Duplicated train dataset samples(for Aug):\")\nprint(nSamplesAug)\n\nfrom random import randint\nif(nSamplesAug < nSamplesOrig):\n    for i in range(0,nSamplesOrig - nSamplesAug):\n        randIdx = randint(0, nSamplesOrig - 1)\n        train_dataset_info_aug.append(train_dataset_info[randIdx])\n        \n    nSamplesOrig = (len)(train_dataset_info)\n    nSamplesAug = (len)(train_dataset_info_aug)\n\n    print(\"Augmentation set extended...\")\n    print(\"Orig train dataset samples:\")\n    print(nSamplesOrig)\n    print(\"Duplicated train dataset samples(for Aug):\")\n    print(nSamplesAug)\n\nIMG_SIZE = 512\nCHANNELS = 3","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"4ca6ef8ba85f33bcf2b1dc7403f9fea9e238e0da"},"cell_type":"code","source":"''' Data generator '''\nfrom sys import getsizeof\nclass data_generator:\n    #Note: If using augument = True, batch size should be even num\n    def create_train(dataset_info, batch_size, shape, augument=True):\n        assert shape[2] == CHANNELS\n        AUG_BATCH_SIZE = 0\n        if augument == True:\n            batch_size = (int)(batch_size/2)\n            AUG_BATCH_SIZE = batch_size\n            \n        start = 0 \n        rev_start = (len)(train_dataset_info_aug) - AUG_BATCH_SIZE - 1\n        while True:\n            batch_images = np.empty((batch_size + AUG_BATCH_SIZE, shape[0], shape[1], shape[2]))\n            batch_labels = np.zeros((batch_size  + AUG_BATCH_SIZE, 28))\n\n            indexes = np.arange(start,start + batch_size)\n            for i, idx in enumerate(indexes):\n                image = data_generator.load_image(\n                    dataset_info[idx]['path'], shape)\n                batch_images[i] = image\n                batch_labels[i][dataset_info[idx]['labels']] = 1\n            start = start + batch_size\n            \n            if augument and rev_start > 0:\n                rev_indexes = np.arange(rev_start, rev_start + AUG_BATCH_SIZE)\n                for i, idx in enumerate(rev_indexes):\n                    image = data_generator.load_image(\n                        train_dataset_info_aug[idx]['path'], shape, bNormalize = False)\n                    image = data_generator.augment(image, train_dataset_info_aug[idx]['id'])\n                    batch_images[batch_size+i] = image\n                    batch_labels[batch_size+i][train_dataset_info_aug[idx]['labels']] = 1\n                rev_start = rev_start - AUG_BATCH_SIZE\n\n            yield batch_images, batch_labels\n    \n    def load_image(path, shape, bNormalize = True):\n        image_red_ch = skimage.io.imread(path+'_red.png')\n        #image_yellow_ch = skimage.io.imread(path+'_yellow.png')\n        image_green_ch = skimage.io.imread(path+'_green.png')\n        image_blue_ch = skimage.io.imread(path+'_blue.png')\n        \n        image = np.stack((\n            image_red_ch, #red: microtubules\n            image_green_ch, #[green: target protein]\n            image_blue_ch), -1) # blue: neucleous\n            #yellow: endoplasmic reticulum\n        \n        return image\n            \n    def augment(image, strId):\n        augment_img = iaa.Sequential([\n            iaa.SomeOf(2, [\n                iaa.Affine(rotate=90),\n                iaa.MultiplyElementwise((0.8, 1.2))\n            ])], random_order=True)\n        augment_img0 = iaa.Sequential([\n            iaa.SomeOf(2, [\n                iaa.Affine(rotate=180),\n                iaa.MultiplyElementwise((0.95, 1.05))\n            ])], random_order=True)\n        augment_img1 = iaa.Sequential([\n            iaa.SomeOf(2, [\n                iaa.Affine(rotate=270),\n                iaa.MultiplyElementwise((0.9, 1.1))\n            ])], random_order=True)\n        augment_img2 = iaa.Sequential([\n            iaa.SomeOf(2, [\n                iaa.Affine(rotate=90),\n                iaa.MultiplyElementwise((0.8, 1.2))\n            ])], random_order=True)\n        augment_img3 = iaa.Sequential([\n            iaa.SomeOf(2, [\n                iaa.Affine(rotate=180),\n                iaa.MultiplyElementwise((0.7, 1.3))\n            ])], random_order=True)\n        \n        \n        if strId == \"set0\":\n            image_aug = augment_img0.augment_image(image)\n        elif strId == \"set1\":\n            image_aug = augment_img1.augment_image(image)\n        elif strId == \"set2\":\n            image_aug = augment_img2.augment_image(image)\n        elif strId == \"set3\":\n            image_aug = augment_img3.augment_image(image)\n        else:\n            image_aug = augment_img.augment_image(image)\n            \n        return image_aug","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6fba83e2b2157aab18308ffb3ed6503b87d7d9a6"},"cell_type":"code","source":"# create train data generator and show few train samples\ntrain_datagen = data_generator.create_train(\n    train_dataset_info, 4, (IMG_SIZE,IMG_SIZE,CHANNELS), augument=False)\n\nimages, labels = next(train_datagen)\n\nfig, ax = plt.subplots(1,4,figsize=(25,5))\nfor i in range(4):\n    ax[i].imshow(images[i])\n    print([i for i, x in enumerate(labels[i]) if x == 1.0])\nprint('min: {0}, max: {1}'.format(images.min(), images.max()))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b47cb2b3f193a71747e7cd59c5da8d6507b211c0"},"cell_type":"code","source":"from keras.preprocessing.image import ImageDataGenerator\nfrom keras.models import Sequential, load_model\nfrom keras.layers import Input, Activation, Dropout, Flatten, Dense, Conv2D, SeparableConv2D, GlobalAveragePooling2D, MaxPooling2D, AveragePooling2D, BatchNormalization, concatenate\nfrom keras.initializers import TruncatedNormal, lecun_normal\nfrom keras.regularizers import l2\nfrom keras.applications.inception_resnet_v2 import InceptionResNetV2\nfrom keras.applications.resnet50 import ResNet50\nfrom keras.applications.inception_v3 import InceptionV3\nfrom keras.applications.xception import Xception\nfrom keras.callbacks import ModelCheckpoint\nfrom keras.models import Model\nfrom keras import metrics\nfrom keras.optimizers import Adam, SGD\nfrom keras import backend as K\nimport keras\n\n\ndef create_model(input_shape, n_out):\n    \n    pretrain_model = Xception(\n        include_top=False, \n        weights='imagenet', \n        input_shape=(IMG_SIZE,IMG_SIZE, 3))\n    \n    model = Sequential()\n    model.add(BatchNormalization(input_shape = input_shape))\n    #model.add(SeparableConv2D(filters=3, kernel_size=(3, 3), strides=(1, 1), use_bias=True, padding='valid',activation = 'relu',\n                           #kernel_initializer=\"glorot_uniform\", kernel_regularizer=l2(1e-5)))\n    model.add(pretrain_model) #input_shape should match first layer input dim of pre-trained model \n    model.add(GlobalAveragePooling2D(data_format=None))\n    \n    model.add(Dense(n_out, activation = 'sigmoid',activity_regularizer=keras.regularizers.l2(1e-5))) #instead of \"softmax\" use sigmoid (https://www.dlology.com/blog/how-to-choose-last-layer-activation-and-loss-function/)\n    return model\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1a9121a4f1687c7562439ed350e102ceae65e444","scrolled":true},"cell_type":"code","source":"keras.backend.clear_session()\n\nmodel = create_model(\n    input_shape=(IMG_SIZE,IMG_SIZE, CHANNELS), #4 ip channels but for Xception specify 3\n    n_out=28)\n'''\nmodel = create_model(\n    input_shape=Input(shape=(IMG_SIZE,IMG_SIZE,CHANNELS)), \n    n_out=28)\n'''\nimport tensorflow as tf\nimport keras.backend as K\nfrom sklearn.metrics import f1_score\n#Ref: https://en.wikipedia.org/wiki/F1_score\ndef f1_Macro(y_true, y_pred):\n    tp = K.sum(K.cast(y_true*y_pred, 'float'), axis=0)\n    tn = K.sum(K.cast((1-y_true)*(1-y_pred), 'float'), axis=0)\n    fp = K.sum(K.cast((1-y_true)*y_pred, 'float'), axis=0)\n    fn = K.sum(K.cast(y_true*(1-y_pred), 'float'), axis=0)\n\n    p = tp / (tp + fp + K.epsilon()) #K.epsilon() for non-zero denominator\n    r = tp / (tp + fn + K.epsilon())\n\n    f1 = (2*p*r) / (p+r + K.epsilon())\n    return f1\n\nmodel.compile(\n    loss='binary_crossentropy', #categorical_crossentropy(when target is single label)\n    optimizer=Adam(1e-4),\n    metrics=['accuracy', f1_Macro])\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"199ec38235416dfe48c881948999d2e4076d92ba","scrolled":true},"cell_type":"code","source":"#orig:197x5x30->(29550 of 30000)  samples with aug:197x5x30->(29550)\ntotal_epochs = 198; batch_size = 10 \nstepsPerEpoch = 30\n\ncheckpointer = ModelCheckpoint(\n    '../working/XceptionSig.model', \n    verbose=2, \n    save_best_only=True)\n\n# split and suffle data, Generate Train and Validation sets\nnp.random.seed(2500)\nindexes = np.arange(train_dataset_info.shape[0])\nnp.random.shuffle(indexes)\ntrain_indexes = indexes[:30000] \nvalid_indexes = indexes[30000:]\n\n# create train and validaion data generators\ntrain_generator = data_generator.create_train(\n    train_dataset_info[train_indexes], batch_size, (IMG_SIZE,IMG_SIZE,CHANNELS), augument=True)\nvalidation_generator = data_generator.create_train(\n    train_dataset_info[valid_indexes], 500, (IMG_SIZE,IMG_SIZE,CHANNELS), augument=False)\n\n# train model\nhistory = model.fit_generator(\n    train_generator, #can specifiy x, y OR do it by train data generator\n    steps_per_epoch = stepsPerEpoch, #no. of batches per epoch\n    #if you are keeping epochs = 1(default) then steps_per_epoch = total samples / batch size\n    #if epochs = 20 then each epoch have steps_per_epoch = total samples / (batch size*20)\n    validation_data=next(validation_generator),\n    epochs = total_epochs,\n    verbose=1,\n    callbacks=[checkpointer])\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":"d3012e6007ad53430f5d0c7351db73cb12f342db"},"cell_type":"code","source":"print(\"Started predicting test set....\")\nsubmit = pd.read_csv('../input/sample_submission.csv')\n\npredicted = []\nfor name in tqdm(submit['Id']):\n    path = os.path.join('../input/test/', name)\n    image = data_generator.load_image(path, (IMG_SIZE,IMG_SIZE,CHANNELS))\n    score_predict = model.predict(image[np.newaxis])[0]\n    \n    indicesMaxScoresDesc = score_predict.argsort()[-3:][::-1] #array of size 3: indices of max score        \n    #print(\"max scores:\" + (str)(score_predict[indicesMaxScoresDesc[0]]) + \" | \" + (str)(score_predict[indicesMaxScoresDesc[1]]) + \" | \" + (str)(score_predict[indicesMaxScoresDesc[2]]))\n    \n    label_predict = np.arange(28)[score_predict>=0.40]\n    if (len)(label_predict) == 2:\n        if score_predict[indicesMaxScoresDesc[2]] > 0.30:\n            label_predict = np.append(label_predict, indicesMaxScoresDesc[2])\n    if (len)(label_predict) == 1: #only one above 40\n        if score_predict[indicesMaxScoresDesc[1]] > 0.25: #(25 - 40)\n            label_predict = np.append(label_predict, indicesMaxScoresDesc[1])\n        if score_predict[indicesMaxScoresDesc[2]] > 0.25:\n            label_predict = np.append(label_predict, indicesMaxScoresDesc[2])\n    elif (len)(label_predict) == 0: #None above 40, all 20-40\n        label_predict = np.append(label_predict, indicesMaxScoresDesc[0])                \n        if (score_predict[indicesMaxScoresDesc[1]]) > 0.20:\n            label_predict = np.append(label_predict, indicesMaxScoresDesc[1])\n        if (score_predict[indicesMaxScoresDesc[2]]) > 0.20:\n            label_predict = np.append(label_predict, indicesMaxScoresDesc[2])\n    \n    str_predict_label = ' '.join(str(l) for l in label_predict)\n    predicted.append(str_predict_label)\n    #print((str)(str_predict_label))\n    \nsubmit['Predicted'] = predicted\nsubmit.to_csv('BN_Xception_GAP_Predictions.csv', index=False)\n\nprint(\"Done...\")","execution_count":null,"outputs":[]}],"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}