{"cells":[{"metadata":{"_uuid":"23eb068e38b5faeb99abf325db9d32bc95deff4c"},"cell_type":"markdown","source":"Another interesting competiton. Let's deep dive into the data"},{"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 os\nimport cv2\nimport glob\nimport shutil\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mimg\nimport imgaug.augmenters as iaa\nimport imgaug as aug\nfrom os import listdir, makedirs, getcwd, remove\nfrom os.path import isfile, join, abspath, exists, isdir, expanduser\nfrom PIL import Image\nfrom pathlib import Path\nfrom keras.models import Sequential, Model\nfrom keras.applications.vgg16 import VGG16, preprocess_input\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, Conv2DTranspose, UpSampling2D\nfrom keras.layers import GlobalMaxPooling2D\nfrom keras.layers.normalization import BatchNormalization\nfrom keras.layers.merge import Concatenate\nfrom keras.models import Model\nfrom keras.optimizers import Adam, RMSprop\nfrom keras.callbacks import ModelCheckpoint, Callback, EarlyStopping, ReduceLROnPlateau\nfrom keras.utils import to_categorical\nfrom keras.applications import resnet50\nfrom keras.applications import densenet\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import StandardScaler\nfrom skimage.io import imread, imshow\nfrom skimage.transform import resize\nfrom sklearn.preprocessing import MultiLabelBinarizer\nimport imgaug as ia\nfrom imgaug import augmenters as iaa\nfrom keras import backend as K\nimport tensorflow as tf\nfrom collections import defaultdict, Counter\nprint(os.listdir(\"../input\"))\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"72168738d5a50a4d4946a0843d3ded30aeca5a34"},"cell_type":"code","source":"seed=1234\n\n# Set the seed for hash based operations in python\nos.environ['PYTHONHASHSEED'] = '0'\n\n# Set the numpy seed\nnp.random.seed(seed)\n\n# Set the random seed in tensorflow at graph level\ntf.set_random_seed(seed)\n\n# Make the augmentation sequence deterministic\naug.seed(seed)\n\ncolor = sns.color_palette()\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"# Define some paths for future use\ninput_path = Path(\"../input/human-protein-atlas-image-classification\")\ntrain_dir = input_path / \"train\"\ntest_dir = input_path / \"test\"\ntrain_csv = input_path / \"train.csv\"\nsubmission_file = input_path / \"sample_submission.csv\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e6c6793a514392a55ec3320ecc60c3af5498b8ea"},"cell_type":"code","source":"# Load keras weights into keras cache folder\n# Check for the directory and if it doesn't exist, make one.\ncache_dir = expanduser(join('~', '.keras'))\nif not exists(cache_dir):\n    makedirs(cache_dir)\n    \n# make the models sub-directory\nmodels_dir = join(cache_dir, 'models')\nif not exists(models_dir):\n    makedirs(models_dir)\n\n# Copy the weights from your input files to the cache directory\n!cp ../input/resnet50/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5 ~/.keras/models/","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"dc870aff6b69a0c3720556d8f7e422130d972931"},"cell_type":"code","source":"# Load the training CSV as it contains all the information\ntrain_df = pd.read_csv(str(train_csv))\ntrain_df.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"416dbdf1b73edf8bc07b30e508f5888581775028"},"cell_type":"markdown","source":"How many samples are there in the training set? More importatntly, how may unqiue samples are present?"},{"metadata":{"trusted":true,"_uuid":"b8cefb760e5fccc78faaaf1b6fd172f9cca4adc3"},"cell_type":"code","source":"print(f\"Total number of samples in the training data: {train_df.shape[0]}\")\nprint(f\"Total number of unique IDs in the training data: {len(train_df['Id'].unique())}\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"49fdc8de0bc90a269be887e0f4c3a90ad4eb9b4f"},"cell_type":"markdown","source":"For each image, there can be multiple labels as it is a multiclass-multilabel classification problem. We are going to create another column\nin our dataframe which tracks the number of labels associated with each image"},{"metadata":{"trusted":true,"_uuid":"e804f4d75f62b5be0f61610726eb7f1a360b3920"},"cell_type":"code","source":"# Lets' split up the target column and see how many files containing multiple labels\ntrain_df[\"nb_labels\"] = train_df[\"Target\"].apply(lambda x: len(x.split(\" \")))\nprint(f\"Maximum number of labels attached to a single sample: {train_df['nb_labels'].max()}\")\nprint(f\"Minimum number of labels attached to a single sample: {train_df['nb_labels'].min()}\")\nprint(\"All counts:\")\nprint(train_df[\"nb_labels\"].value_counts())","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a85dc1ef1d57000457ee8bbfbf2fca6c20eacd75"},"cell_type":"markdown","source":"Nothing is complete in data analysis without visualizations. Plus, it is the most fun part of an EDA. "},{"metadata":{"trusted":true,"_uuid":"de8089bffa2afb3c7d35f51ee1939514a775491c"},"cell_type":"code","source":"plt.figure(figsize=(12,8))\ntrain_df['nb_labels'].value_counts().plot('bar')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"10a6cd1ee61092c9a3952a42c53fc52cc3c2e59f"},"cell_type":"code","source":"single_labels_count = train_df[train_df['nb_labels']==1]['nb_labels'].count()\nmulti_labels_count = train_df[train_df['nb_labels']>1]['nb_labels'].count()\n\n# Plot the value counts for each count\nplt.figure(figsize=(12,8))\nsns.barplot(x=['Single label', 'Multi-label'], y=[single_labels_count, multi_labels_count])\nplt.title(\"Single vs Multi label distribution\", fontsize=16)\nplt.xlabel(\"Label type\", fontsize=16)\nplt.ylabel(\"Count\", fontsize=16)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"398120676ecb4cbdcfc4232243ca7e053cc6cc2b"},"cell_type":"markdown","source":"There are a total of 28 labels in our training set. Before ding anything further, create a mapping for the labels. Some people go with the fancy word **\"labelmap\"**"},{"metadata":{"trusted":true,"_uuid":"f074f834f53c3e8ef20b648a18f6e6963af55a90"},"cell_type":"code","source":"labels_dict={\n0:  \"Nucleoplasm\", \n1:  \"Nuclear membrane\",   \n2:  \"Nucleoli\",   \n3:  \"Nucleoli fibrillar center\" ,  \n4:  \"Nuclear speckles\"   ,\n5:  \"Nuclear bodies\"   ,\n6:  \"Endoplasmic reticulum\",   \n7:  \"Golgi apparatus\"   ,\n8:  \"Peroxisomes\"   ,\n9:  \"Endosomes\"   ,\n10:  \"Lysosomes\"   ,\n11:  \"Intermediate filaments\",   \n12:  \"Actin filaments\"   ,\n13:  \"Focal adhesion sites\",   \n14:  \"Microtubules\"   ,\n15:  \"Microtubule ends\",   \n16:  \"Cytokinetic bridge\",   \n17:  \"Mitotic spindle\"   ,\n18:  \"Microtubule organizing center\" ,  \n19:  \"Centrosome\"   ,\n20:  \"Lipid droplets\",   \n21:  \"Plasma membrane\",   \n22:  \"Cell junctions\"  , \n23:  \"Mitochondria\"   ,\n24:  \"Aggresome\"   ,\n25:  \"Cytosol\",\n26:  \"Cytoplasmic bodies\",   \n27:  \"Rods & rings\" \n}","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4133ab5f0a0790d0ef09934a295c9956a88e31fe"},"cell_type":"markdown","source":"One of the things that is always important to check before assuming anything about the data is the distribution of the labels in the training set. Come on, why the hell on this earth we created that label map! For the visualization, of course."},{"metadata":{"trusted":true,"_uuid":"270418a837a3400b8bd686785944d3c43b5b2746"},"cell_type":"code","source":"# Split the labels\nlabels = train_df[\"Target\"].apply(lambda x: x.split(\" \"))\n\n# Create a counter. This initializes the count for each class with a value of zero\nlabels_count = defaultdict(int)\n\n# Update the counter \nfor label in labels:\n    if len(labels) > 1:\n        for l in label:\n            labels_count[labels_dict[int(l)]]+=1\n    else:\n        labels_count[labels_dict[int(label)]]+=1\n\n# Plot         \nplt.figure(figsize=(20,15))\nsns.barplot(x=list(labels_count.values()), y=list(labels_count.keys()), color=color[3], orient='h')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"84017de777eb081c1ef7b739689ed31a884c2458"},"cell_type":"markdown","source":"Woah! Huge imbalance. We need to be very careful about this when we are going to a build a model. "},{"metadata":{"trusted":true,"_uuid":"b0798909865527b257777d648d115d4b6a01a90b"},"cell_type":"markdown","source":"Each Id in our training set consists of four corresposnding images: Red, Yellow, Blue and Green. (Pardon me, I broke your RGB order here, lol). Now, the ideal thing is to do these steps:\n\n* Check some images that have only one label.\n* Check some images that consists of more than one label\n* Investigate  further. (Hold on, don't jump on models directly. Stop treating DL as a bazooka without looking at the data first)"},{"metadata":{"trusted":true,"_uuid":"b2ed5ceabd0e89af0a04dc4e073293d4cf131ed4"},"cell_type":"code","source":"# Let's see some samples that have single label\nsample_indices = train_df.index[train_df['nb_labels']==1][:3]\nsingle_label_samples = train_df['Id'][sample_indices].tolist()\nsingle_label_samples_labels = train_df['Target'][sample_indices].tolist()\nsingle_label_samples_labels = [labels_dict[int(x)] for x in single_label_samples_labels]\n\nf,ax = plt.subplots(3,4, figsize=(40,40), sharex=True, sharey=True)\nfor i in range(3):\n    img_path = str(train_dir / single_label_samples[i])\n    red_img = imread(img_path + \"_red.png\")\n    yellow_img = imread(img_path + \"_yellow.png\")\n    blue_img = imread(img_path + \"_blue.png\")\n    green_img = imread(img_path + \"_green.png\")\n    \n    ax[i,0].imshow(red_img)\n    ax[i,1].imshow(yellow_img)\n    ax[i,2].imshow(blue_img)\n    ax[i,3].imshow(green_img)\n    \n    sup_title = single_label_samples_labels[i] + \"-\" +single_label_samples[i]\n    ax[i,0].set_title(sup_title + \"_red\")\n    ax[i,1].set_title(sup_title + \"_yellow\")\n    ax[i,2].set_title(sup_title + \"_blue\")\n    ax[i,3].set_title(sup_title + \"_green\")\n    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"62b87d308e2495306f6967ec0b96542fa6f34326"},"cell_type":"code","source":"# Convert labels into a format that can later be used by multilabel binarizer\ndef get_labels(x):\n    labels = x.split(\" \")\n    labels = [int(x) for x in labels]\n    return labels\n\ntrain_df['labels']= train_df['Target'].apply(get_labels)\ntrain_df.head(10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"45a674b0697b19cd2fc6507a8cc1174a17a392a8"},"cell_type":"code","source":"# Some pseudo-constants\ndesired_height, desired_width, nb_channels = 224,224,3\nnb_classes = len(labels_dict)\nimages_path = train_dir\n\n# Multilabel binarizer\nmlb = MultiLabelBinarizer(classes=np.array(list(labels_dict.keys())))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"eb745e25d20b6137c8187b1a464ab899e59bbd51"},"cell_type":"code","source":"# Custom generator\ndef data_generator(data, batch_size=16):\n    batch_data = np.zeros((batch_size, desired_height, desired_width, nb_channels), dtype=np.float32)\n    \n    n = len(data)\n    steps = n//batch_size\n    \n    # Get a numpy array of all the indices of the input data\n    indices = np.arange(n)\n    np.random.shuffle(indices)\n    \n    # Initialize a counter\n    i =0\n    while True: \n        batch_labels = []\n        # Get the next batch \n        next_batch = indices[(i*batch_size):(i+1)*batch_size]\n        \n        for j, idx in enumerate(next_batch):\n            #print(str(images_path/data.iloc[idx]['Id']))\n            img = cv2.imread(str(images_path/data.iloc[idx]['Id']) + \"_green.png\")\n            label = data.iloc[idx]['labels']\n            #print(label)\n            \n            # Resize\n            img = cv2.resize(img, (224,224)).astype(np.float32)\n            batch_data[j] = img\n            batch_labels.append(label)\n            \n            if j==batch_size-1:\n                break     \n    \n        i+=1\n        batch_data = resnet50.preprocess_input(batch_data)\n        batch_labels = mlb.fit_transform(batch_labels)\n        batch_labels = np.array(batch_labels).astype(np.float32)\n        yield batch_data, batch_labels\n        del batch_labels\n            \n        if i>=steps:\n            i=0","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"bd0f27021b50e36cb76dc92dc0f75b3d4faa4be2"},"cell_type":"code","source":"training_data, validation_data = train_test_split(train_df, random_state=seed, test_size=0.2, \n                                                  stratify=train_df['nb_labels'])\n\nprint(f\"Number of training samples: {len(training_data)}\")\nprint(f\"Number of validation samples: {len(validation_data)}\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0d0e91606808510c4e88027abd618d7701b4f8e2"},"cell_type":"code","source":"# Reset the index of the two dataframes we got\ntraining_data = training_data.reset_index(drop=True)\nvalidation_data = validation_data.reset_index(drop=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f25eabf17b6929d974eb332d6bda57dbc7d6ff76"},"cell_type":"code","source":"# Generator instances for training anf validation data\ntrain_data_gen = data_generator(training_data)\nvalid_data_gen = data_generator(validation_data)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0de2b381082371f16558d121dbfb9697a7f023bc"},"cell_type":"code","source":"# Get a pretrained model you want to use \ndef get_base_model():\n    model = resnet50.ResNet50(input_shape=(224,224,3), include_top=False, weights=\"imagenet\")\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"755b842d484a101a5293d031d03e9d20c9020c15"},"cell_type":"code","source":"base_model = get_base_model()\nbase_model_output = base_model.output\n\n# Add layers on the top of base model\nx = Flatten(name='flat')(base_model_output)\nx = Dense(1024, activation='relu', name='fc1')(x)\nx = Dropout(0.5, name='dp1')(x)\nx = Dense(512, activation='relu', name='fc2')(x)\nx = Dropout(0.25, name='dp2')(x)\nx = Dense(nb_classes, activation='sigmoid', name='out')(x)\n\nmodel = Model(inputs=base_model.inputs, outputs=x)\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7bfcbadfcdd0bc303087a5765278c6ed037411a2"},"cell_type":"code","source":"opt = RMSprop(lr=0.0001)\nmodel.compile(optimizer=opt, loss='binary_crossentropy', metrics=[\"accuracy\"])\n\nearlystopper = EarlyStopping(patience=10, verbose=1)\ncheckpointer = ModelCheckpoint('best_model.h5', verbose=1, save_best_only=True, save_weights_only=True)\nreduce_lr = ReduceLROnPlateau(factor=0.5, patience=10, min_lr=0.00001, verbose=1, mode='min')\n\nbatch_size = 16\ntrain_steps = len(training_data)//batch_size\nvalid_steps = len(validation_data)//batch_size","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"363d6c90e3b649eaf9f6b2533f82ef18cee47f70"},"cell_type":"code","source":"results = model.fit_generator(train_data_gen, \n                              steps_per_epoch=train_steps,\n                              validation_data=valid_data_gen, \n                              validation_steps=valid_steps,epochs=1, \n                              callbacks=[earlystopper, checkpointer, reduce_lr])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7b95e6add483f38403089cec383cbdbf92fc4634"},"cell_type":"markdown","source":"A few things to which you can contribute:\n* The data generator is slow. Can you make it fast?\n* Accuracy isn't the true metric here. Even in real word, accuracy is of no use in such cases.\n* Validation strategy has to be very clever here\n\n**Wait for more...I WILL BE BACK!**"},{"metadata":{"trusted":true,"_uuid":"249157889d7463fdb1c0c33d67c0e05a04bdb5a3"},"cell_type":"code","source":"","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}