{"cells":[{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","trusted":true},"cell_type":"code","source":"import os\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport numpy as np\nimport sys\nimport cv2\nimport gc\nimport random\nimport tensorflow as tf\nimport keras.backend as K\nimport imgaug as ia\n\nfrom tqdm import tqdm\nfrom imgaug import augmenters as iaa\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.utils import shuffle\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.models import Sequential\nfrom keras.optimizers import RMSprop, Adam\nfrom keras import regularizers\nfrom keras.utils import Sequence\nfrom keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"root_dir='../input/human-protein-atlas-image-classification'\ntrain_dir=os.path.join(root_dir, \"train\")\ntest_dir=os.path.join(root_dir, \"test\")\ntrain_csv_path=os.path.join(root_dir,\"train.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"42734077df2e83f59a49211148574c1ea2ae0822"},"cell_type":"code","source":"import os\nos.listdir(\"../input/human-protein-atlas-image-classification\")","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c26966c177671e0ab4f0ec04e0b6aac2ddb55da4","trusted":true},"cell_type":"code","source":"IMAGE_SIZE=224 #256# 512","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5c0e1b81d836688f116a97c6a06d2d8af23e0bb4","trusted":true},"cell_type":"code","source":"# read the training csv\ntrain_csv = pd.read_csv(train_csv_path)\nprint(train_csv.shape)\ntrain_csv.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4c81cc8d22856480ae999dd7e395dcfaabaf6032","trusted":true},"cell_type":"code","source":"class_names = {\n    0:\"Nucleoplasm\", 1:\"Nuclear membrane\", 2:\"Nucleoli\", 3:\"Nucleoli fibrillar center\", 4:\"Nuclear speckles\", \n    5:\"Nuclear bodies\",  6:\"Endoplasmic reticulum\", 7:\"Golgi apparatus\", 8:\"Peroxisomes\", 9:\"Endosomes\", \n    10:\"Lysosomes\", 11:\"Intermediate filaments\", 12:\"Actin filaments\", 13:\"Focal adhesion sites\",14:\"Microtubules\", \n    15:\"Microtubule ends\", 16:\"Cytokinetic bridge\", 17:\"Mitotic spindle\", 18:\"Microtubule organizing center\", \n    19:\"Centrosome\", 20:\"Lipid droplets\", 21:\"Plasma membrane\", 22:\"Cell junctions\", 23:\"Mitochondria\", \n    24:\"Aggresome\",  25:\"Cytosol\", 26:\"Cytoplasmic bodies\", 27:\"Rods & rings\" \n}","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"eccbdfad85d8c23f25e31432b699cc8c8bf25b55","trusted":true},"cell_type":"code","source":"# split the targets in train csv\ndef split_classes(row):\n    for cls_num in row[\"Target\"].split():\n        train_csv.loc[row.name, class_names[int(cls_num)]]=1\n\nfor cls_num, cls_name in class_names.items():\n    train_csv[cls_name]=0\n\n# train_csv[\"splitted\"] = train_csv[\"Target\"].apply(lambda x: i+1 for i in x.split())\ntrain_csv.apply(split_classes, axis=1)\ntrain_csv.head()\n\n#DISABLE BELOW\n# train_csv = pd.read_csv(root_dir+\"/train_csv.csv\")\n# train_csv.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2384a03cde4b4d47e6562626f4c4f869e7f5a73d","trusted":true},"cell_type":"code","source":"# load the data batch wise from the disk on the fly\n# https://stanford.edu/~shervine/blog/keras-how-to-generate-data-on-the-fly\n\nclass BatchDataGenerator(Sequence):\n    # 'Generates data for Keras'\n    def __init__(self, paths, labels, batch_size, shape, shuffle = True, augment = False, load_green_only=True, \n                 load_3chnls=False, return_paths=False):\n         # 'Initialization'\n        self.paths = paths\n        self.labels = labels\n        self.batch_size = batch_size\n        self.shape = shape\n        self.shuffle = shuffle\n        self.augment = augment\n        self.load_green_only = load_green_only\n        self.load_3chnls = load_3chnls\n        self.on_epoch_end()\n        self.return_paths = return_paths\n        \n    def __len__(self):\n        'Denotes the number of batches per epoch'\n        return int(np.floor(len(self.paths) / self.batch_size))\n    \n    def __getitem__(self, idx):\n        # Generate indexes of a batch\n        indexes = self.indexes[idx * self.batch_size : (idx+1) * self.batch_size]        \n        paths = self.paths[indexes]\n        X = np.zeros((paths.shape[0], self.shape[0], self.shape[1], self.shape[2]))\n        # Generate data\n        for i, path in enumerate(paths):\n            X[i] = self.__load_image(path)\n            \n        y = self.labels[indexes]\n                \n        if self.augment == True:\n            seq = iaa.Sequential([\n                iaa.OneOf([\n                    iaa.Fliplr(0.5), # horizontal flips\n                    iaa.Flipud(0.5),\n                    iaa.Crop(percent=(0, 0.1)), # random crops\n                    # Small gaussian blur with random sigma between 0 and 0.5.\n                    # But we only blur about 50% of all images.\n                    iaa.Sometimes(0.5,\n                        iaa.GaussianBlur(sigma=(0, 0.5))\n                    ),\n                    # Strengthen or weaken the contrast in each image.\n                    iaa.ContrastNormalization((0.75, 1.5)),\n                    # Add gaussian noise.\n                    # For 50% of all images, we sample the noise once per pixel.\n                    # For the other 50% of all images, we sample the noise per pixel AND\n                    # channel. This can change the color (not only brightness) of the\n                    # pixels.\n                    iaa.AdditiveGaussianNoise(loc=0, scale=(0.0, 0.05*255), per_channel=0.5),\n                    # Make some images brighter and some darker.\n                    # In 20% of all cases, we sample the multiplier once per channel,\n                    # which can end up changing the color of the images.\n                    iaa.Multiply((0.8, 1.2), per_channel=0.2),\n                    # Apply affine transformations to each image.\n                    # Scale/zoom them, translate/move them, rotate them and shear them.\n                    iaa.Affine(\n                        scale={\"x\": (0.8, 1.2), \"y\": (0.8, 1.2)},\n                        translate_percent={\"x\": (-0.2, 0.2), \"y\": (-0.2, 0.2)},\n                        rotate=(-180, 180),\n                        shear=(-8, 8)\n                    )\n                ])], random_order=True)\n\n            X = np.concatenate((X, seq.augment_images(X),  seq.augment_images(X)), 0)#, seq.augment_images(X), seq.augment_images(X)), 0)\n            y = np.concatenate((y, y, y),0) # y, y), 0)\n            \n        if self.return_paths:\n            return paths, X, y\n        else:\n            return X, y\n    \n    def __load_image(self, path):\n        if self.load_green_only:\n            im = cv2.imread(path + '_green.png')\n            cv2.resize(im, (IMAGE_SIZE, IMAGE_SIZE))\n            im.resize(IMAGE_SIZE, IMAGE_SIZE, 1)\n        elif load_3chnls:\n            all_images = np.empty((512,512,3))\n            reds = plt.imread(path + '_red.png')\n            greens = plt.imread(path + '_green.png')\n            blues = plt.imread(path + '_blue.png')\n             \n            all_images[:,:,0] = reds\n            all_images[:,:,1] = greens\n            all_images[:,:,2] = blues\n            \n            im = all_images.reshape(all_images.shape[0], all_images.shape[0], 3)\n            im = cv2.resize(im, (IMAGE_SIZE, IMAGE_SIZE))\n        else:\n            all_images = np.empty((512,512,4))\n            all_images[:,:,0] = cv2.imread(path + '_red.png')\n            all_images[:,:,1] = cv2.imread(path + '_green.png')\n            all_images[:,:,2] = cv2.imread(path + '_blue.png')\n            all_images[:,:,3] = cv2.imread(path + '_yellow.png')\n\n            # define transformation matrix\n            # note that yellow is made usign red and green\n            # but you can tune this color conversion yourself\n            T = np.array([\n                #r g y b\n                [1,0,1,0],\n                [0,1,1,0],\n                [0,0,0,1]])\n            \n            rgb_image = np.matmul(all_images.reshape(-1, 4), np.transpose(T))\n            rgb_image = rgb_image.reshape(all_images.shape[0], all_images.shape[0], 3)\n            rgb_image = np.clip(rgb_image, 0, 1)\n            \n            \n            im = cv2.resize(im, (IMAGE_SIZE, IMAGE_SIZE))\n        return im\n    \n    def __iter__(self):\n        \"\"\"Create a generator that iterate over the Sequence.\"\"\"\n        for item in (self[i] for i in range(len(self))):\n            yield item\n    \n    def on_epoch_end(self):\n        'Updates indexes after each epoch'\n        self.indexes = np.arange(len(self.paths))\n        if self.shuffle == True:\n            np.random.shuffle(self.indexes)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"cb15ed9df07875f787bc80667a0e4e3dd87f9908","trusted":true},"cell_type":"code","source":"# Load the images in train and test\nimport platform\n\nif platform.system() == 'Windows':\n    train_csv[\"train_paths\"] =  train_dir + \"\\\\\" + train_csv[\"Id\"].astype(str)\nelse:\n    train_csv[\"train_paths\"] =  train_dir + \"/\" + train_csv[\"Id\"].astype(str)\n\ngc.collect()\nshuffle(train_csv)\n\nMAX_IMG_FOR_MODELING = 31072 #15000 # choosing only this much images to avoid memory error or timeout error\nshuffle(train_csv)\nsubset_data=train_csv[:MAX_IMG_FOR_MODELING]\n\ntrain_paths, valid_paths, train_labels, valid_labels = train_test_split(subset_data[\"train_paths\"].values, \n                                                                    subset_data[list(class_names.values())].values, \n                                                                    test_size=0.25)\n                                                                    #stratify=subset_data[class_names.values()].values)\nprint(train_paths.shape)\nprint(train_labels.shape)\nprint(valid_paths.shape)\nprint(valid_labels.shape)\n\nprint(train_paths[:5])\nprint(train_labels[:5])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"67e1bf66dbc734ea51355fd6889864492a9c0e32"},"cell_type":"code","source":"# check class wise train and valid distrib\ntc = train_csv.set_index(\"Id\")\ntrain_ids = []\nvalid_ids = []\n\ndef get_distrib(dataset, lst):\n    for path in dataset:\n        lst.append(path.split(os.path.sep)[-1])\n        \n    data = train_csv[train_csv[\"Id\"].isin(lst)]\n    counts=data[list(class_names.values())].sum()\n    counts = counts.to_frame(\"cnts\")\n    plt.figure(figsize=(20, 10))\n    sns.barplot(counts.index, counts.cnts)\n    plt.xticks(rotation=70)\n    \n    counts.columns = [\"counts\"]\n    print(counts.shape)\n    print(counts)\n    return counts\n        \ntd = get_distrib(train_paths, train_ids)\nplt.show()\n\nvd = get_distrib(valid_paths, valid_ids)\nplt.show()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"14bc7cfee2a767e735d66de3338207b159f91d36"},"cell_type":"code","source":"y_integers = np.argmax(train_labels, axis=1)\n\nweights = train_labels.shape[0]/(len(class_names)*td[\"counts\"].values)\nclass_weights = {}\nfor cls_num, w in zip(class_names.keys(),weights):\n    class_weights[cls_num] = w\n\nprint(class_weights)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ce021d3cbea77b7653ec39650125ead455710b44","trusted":true},"cell_type":"code","source":"# Data generation\n\nbatch_size=16\n\nload_green_only = False\nload_3chnls = True\nimg_shape = (IMAGE_SIZE, IMAGE_SIZE, 1) if load_green_only else (IMAGE_SIZE, IMAGE_SIZE, 3) \\\n                                        if load_3chnls else (IMAGE_SIZE, IMAGE_SIZE, 3)\nprint(img_shape)\ntrain_gen = BatchDataGenerator(train_paths, train_labels, batch_size, img_shape, load_green_only=load_green_only, \n                               load_3chnls=load_3chnls, augment=True, shuffle=False)\nval_gen = BatchDataGenerator(valid_paths, valid_labels, batch_size, img_shape, load_green_only=load_green_only, \n                             load_3chnls=load_3chnls, augment=True, shuffle=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b85da257312d9d639afc6af230359c6e7f367bdf"},"cell_type":"code","source":"model_dir = './model'\n\nif not os.path.exists(model_dir):\n    os.makedirs(model_dir)\n    \ncheckpoint = ModelCheckpoint(os.path.join(model_dir, 'base.model'), monitor='val_loss', verbose=1, save_best_only=True, save_weights_only=False, mode='min', period=1)\nreduce_LR_on_plateu = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=3, verbose=1, mode='min')\nearly_stopping = EarlyStopping(monitor='val_loss', min_delta=0, patience=5)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"590d796b605c7509d1d4fac55af85aae60e9d525"},"cell_type":"code","source":"def f1(y_true, y_pred):\n    y_pred = K.round(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())\n    r = tp / (tp + fn + K.epsilon())\n\n    f1 = 2*p*r / (p+r+K.epsilon())\n    f1 = tf.where(tf.is_nan(f1), tf.zeros_like(f1), f1)\n    return K.mean(f1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"aeae65b0a130bc7da47a9c1ea1ad968b9df1d2ed"},"cell_type":"code","source":"import tensorflow as tf\nfrom keras.applications.vgg16 import VGG16\nfrom keras.applications.inception_v3 import InceptionV3\nfrom keras.models import Model\nfrom keras.layers import Conv2D, Flatten, Dense, MaxPooling2D , BatchNormalization, \\\n                        Input, GaussianNoise, GlobalMaxPooling2D, GlobalAveragePooling2D\nconfig = tf.ConfigProto()\nconfig.gpu_options.allow_growth = True\nsession = tf.Session(config=config)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9409231870b2b7623125d3c0e6cca7d20a00cce4","trusted":true},"cell_type":"code","source":"# Train vs Validation accuracy and loss\n\ndef loss_over_epochs(model, loss_type='loss', add_valid=True):\n    hist=model.history.history\n    plt.plot(list(range(epochs)), hist['loss'], color=\"blue\", label=\"train\")\n    if add_valid:\n        plt.plot(list(range(epochs)), hist['val_loss'], color=\"orange\", label=\"valid\")\n    plt.xlabel(\"Epochs\")\n    plt.ylabel(\"loss\")\n    plt.legend()\n    plt.title(\"Losses over the Epochs\")\n\n# accuracy vs epochs\ndef acc_over_epochs(model, acc_type='acc', add_valid=True):\n    hist=model.history.history\n    plt.plot(list(range(epochs)), hist[acc_type], color=\"blue\", label=\"train\")\n    if add_valid:\n        plt.plot(list(range(epochs)), hist[\"val_\"+acc_type], color=\"orange\", label=\"valid\")\n    plt.xlabel(\"Epochs\")\n    plt.ylabel(acc_type)\n    plt.legend()\n    plt.title(acc_type + \" over the Epochs\")","execution_count":null,"outputs":[]},{"metadata":{"scrolled":false,"trusted":true,"_uuid":"560ec9a51c7b9af47974bc096b0e0c9fcbf66b4d"},"cell_type":"code","source":"vgg_model = VGG16(include_top=False, input_shape=img_shape)\nvgg_model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"501af679376e605747238087b05f56c8d9c731ef"},"cell_type":"code","source":"gaus_noise = 0.1\nDENSE_COUNT = 1024\n\nvgg_model.trainable = False\nin_layer = Input(shape=(img_shape))\nnoise_layer =  GaussianNoise(0.1)(in_layer)\nfeatures_layer = vgg_model(noise_layer)\nbatch_norm = BatchNormalization()(features_layer)\n#gmp_dr = GlobalMaxPooling2D()(batch_norm)\nx = GlobalAveragePooling2D()(batch_norm)\nx = Dense(DENSE_COUNT, activation = 'relu')(x)\npredictions = Dense(len(class_names), activation = 'sigmoid')(x)\nmodel = Model(inputs = [in_layer], outputs = [predictions], name = 'vgg_gnoise_model')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7771916de0c8a242266a371ef7db6918c446fff4"},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c406a048137b731a7cd7ffbb3e336586cbff1c4d"},"cell_type":"code","source":"opt = Adam(lr=0.01)\nmodel.compile(loss=\"binary_crossentropy\", optimizer=opt, metrics=[\"accuracy\", f1])\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"797b27b29b9dab8aa47c4591dc5da1220e1acf9a"},"cell_type":"code","source":"epochs = 30\n\nuse_multiprocessing = True # DO NOT COMBINE MULTIPROCESSING WITH CACHE! \nworkers = 6 # DO NOT COMBINE MULTIPROCESSING WITH CACHE! \n\nmodel.fit_generator(\n                    train_gen,\n                    steps_per_epoch=len(train_gen), \n                    validation_data=val_gen,\n                    validation_steps=50,\n                    epochs=epochs,\n                    use_multiprocessing=use_multiprocessing,\n                    workers=workers,\n                    class_weight=class_weights,\n                    callbacks=[checkpoint, reduce_LR_on_plateu])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f33d2a606e9c6eb061cd3183420422fa0c27ee34"},"cell_type":"code","source":"loss_over_epochs(model)\nplt.show()\nacc_over_epochs(model)\nplt.show()\nacc_over_epochs(model, acc_type=\"f1\")\nplt.show()\nacc_over_epochs(model, add_valid=False)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"35eccb4a1ec1470c3c08495ba62147fba0a516ed"},"cell_type":"markdown","source":"## Test Data and Submission"},{"metadata":{"trusted":true,"_uuid":"686336d8c61653923a3ee49c128c347a8fd1e509"},"cell_type":"code","source":"# Get the test data\ntest_paths = []\nsample_test_labels = []\n\nsample_submit = os.path.join(root_dir, 'sample_submission.csv')\ndata = pd.read_csv(sample_submit)\n    \nfor name in data['Id']:\n    y = np.ones(28)\n    test_paths.append(os.path.join(test_dir, name))\n    sample_test_labels.append(y)\n\ntest_paths = np.array(test_paths)\nsample_test_labels = np.array(sample_test_labels)\n\nprint(test_paths[:3])\nprint(sample_test_labels[:3])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"bbd1ab5bd1006cc8cb5eb90c512910a3aef18071"},"cell_type":"code","source":"def load_test_images(load_all=False):\n    \"\"\"\n    If load_all==False then it will return the iterator or it will return the all test images in numpy array.\n    \"\"\"\n    test_gen = BatchDataGenerator(test_paths, sample_test_labels, 1, img_shape, load_green_only=load_green_only, \n                               load_3chnls=load_3chnls, augment=False, shuffle=False, return_paths=True)\n    if load_all:\n        images = []\n        for img in test_gen:\n            images.append(img)\n        \n        return np.array(images)\n    \n    return test_gen","execution_count":null,"outputs":[]},{"metadata":{"scrolled":true,"trusted":true,"_uuid":"27a667748bb07d0416acc56ba92b7f481f87f97f"},"cell_type":"code","source":"full_val_pred = np.empty((0, 28))\nfor i in tqdm(range(len(val_gen))): \n    im, lbl = val_gen[i]\n    scores = model.predict(im)\n    full_val_pred = np.append(full_val_pred, scores, axis=0)\nprint(full_val_pred.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f73d6fd87fb28ff926d21a52bc478c8411641ebc"},"cell_type":"code","source":"# Take \"perc\" percentile score of each class a threshold\nperc = 85\n\nthresholds = np.empty(len(class_names))\nfor i in range(len(class_names)):\n    thresholds[i] = np.percentile(full_val_pred[:,i], perc)\nprint('Probability threshold for each class score:')\nprint(thresholds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"02d08f0859a97d55f88d6957975974a5ad88667a"},"cell_type":"code","source":"preds = {\"Id\":[], \"Predicted\":[]}\n\n\ntest_images = load_test_images()\n\ni=0\nfor img_data in tqdm(test_images):\n    paths, test_imgs, labels = img_data\n    score = model.predict(test_imgs)\n    tmp = []\n    for i in range(len(class_names)):\n        if score[0][i] >= thresholds[i]:\n            tmp.append(str(i))\n    preds[\"Id\"].append(paths[0].split(os.path.sep)[-1])\n    preds[\"Predicted\"].append(\" \".join(tmp))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6150f549001717254272d2234079431d7b30f6ce"},"cell_type":"code","source":"submit = pd.DataFrame(preds)\nprint(submit.shape)\nprint(submit.head(5))\nsubmit.to_csv(\"submission1.csv\", index=False)","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}