{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"Importing the Necessary Libraries","metadata":{}},{"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport seaborn as sns\nimport matplotlib.pyplot as plt\n%matplotlib inline\nfrom PIL import Image\nimport cv2\n\nfrom scipy.misc import imread\nfrom imgaug import augmenters as iaa\nfrom tqdm import tqdm\n\nimport tensorflow as tf\nsns.set()\n\nimport os\nprint(os.listdir(\"../input\"))\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Playing with Data","metadata":{}},{"cell_type":"markdown","source":"The Data is given in the form of 'train' and 'test' folders, each containing multiple 512x512 PNG images. Each of these images in the 'train' folder is named using an ID. The ID of the image is linked to target classes in the train.csv file.\nEg : The first image below  has protiens 16 and 0 which are Cytokinetic bridge and Nucleoplasm.","metadata":{}},{"cell_type":"code","source":"train_labels = pd.read_csv(\"../input/train.csv\")\ntrain_labels.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There are a total of 11702 test images that need to be used to make predictions","metadata":{}},{"cell_type":"code","source":"test_path = \"../input/test/\"\nsubmission = pd.read_csv(\"../input/sample_submission.csv\")\nsubmission.head()\ntest_names = submission.Id.values\nprint(len(test_names))\nprint(test_names[0])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"label_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\nreverse_train_labels = dict((v,k) for k,v in label_names.items())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Creating helper functions to extract train targets:\n - We append the 27 proteins as features to the training dataset and initially keep their values as 0 for all images.\n - We then change the values to 1 for those protein organelle localisations present in the image","metadata":{}},{"cell_type":"code","source":"def 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","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for key in label_names.keys():\n    train_labels[label_names[key]] = 0","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_labels = train_labels.apply(fill_targets, axis=1)\ntrain_labels.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_labels = pd.DataFrame(data=test_names, columns=[\"Id\"])\nfor col in train_labels.columns.values:\n    if col != \"Id\":\n        test_labels[col] = 0\ntest_labels.head(1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Which proteins occur most often in train images?\n\nTakeaway:\n\n1)Most common protein structures belong to cellular components like cytosol and plasma membrame.\n2)Small components like lipids and rods and rings dont occur as much in our training set","metadata":{}},{"cell_type":"code","source":"target_counts = train_labels.drop([\"Id\", \"Target\"],axis=1).sum(axis=0).sort_values(ascending=False) #vertically\nplt.figure(figsize=(8,8))\nsns.barplot(y=target_counts.index.values, x=target_counts.values, order=target_counts.index)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"How many targets for each image are the most common:\n1)90 % of the images have 1 or 2 labels\n2)Few have more than 2 labels","metadata":{}},{"cell_type":"code","source":"train_labels[\"number_of_targets\"] = train_labels.drop([\"Id\", \"Target\"],axis=1).sum(axis=1) #horizontally\ncount_perc = np.round(100 * train_labels[\"number_of_targets\"].value_counts() / train_labels.shape[0], 2)\nplt.figure(figsize=(20,5))\nsns.barplot(x=count_perc.index.values, y=count_perc.values, palette=\"Reds\")\nplt.xlabel(\"Number of targets per image\")\nplt.ylabel(\"% of train data\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Check for correlation between the protein classes\n - This will help us see that some proteins come together often","metadata":{}},{"cell_type":"markdown","source":"Takeaway:\n1)Many targets have slight correlation\n2)Endosomes and Lysosomes often occur together","metadata":{}},{"cell_type":"code","source":"# For those with more than one class, we check the degree of correlation\nplt.figure(figsize=(7,7))\nsns.heatmap(train_labels[train_labels.number_of_targets>1].drop(\n    [\"Id\", \"Target\", \"number_of_targets\"],axis=1\n).corr(), cmap=\"RdYlBu\", vmin=-1, vmax=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Further exploration of groups showing some degree of correlation","metadata":{}},{"cell_type":"code","source":"def find_counts(special_target, labels):\n    counts = labels[labels[special_target] == 1].drop(\n        [\"Id\", \"Target\", \"number_of_targets\"],axis=1\n    ).sum(axis=0)\n    counts = counts[counts > 0]\n    counts = counts.sort_values()\n    return counts","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lyso_endo_counts = find_counts(\"Lysosomes\", train_labels)\n\nplt.figure(figsize=(10,3))\nsns.barplot(x=lyso_endo_counts.index.values, y=lyso_endo_counts.values, palette=\"Blues\")\nplt.ylabel(\"Counts in train data\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rod_rings_counts = find_counts(\"Rods & rings\", train_labels)\nplt.figure(figsize=(15,3))\nsns.barplot(x=rod_rings_counts.index.values, y=rod_rings_counts.values, palette=\"Greens\")\nplt.ylabel(\"Counts in train data\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"peroxi_counts = find_counts(\"Peroxisomes\", train_labels)\n\nplt.figure(figsize=(15,3))\nsns.barplot(x=peroxi_counts.index.values, y=peroxi_counts.values, palette=\"Reds\")\nplt.ylabel(\"Counts in train data\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Images in the train folder","metadata":{}},{"cell_type":"code","source":"from os import listdir\n\nfiles = listdir(\"../input/train\")\nfor n in range(10):\n    print(files[n])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Understanding the 4 color channels of the subcellular protein images (R,G,B,Y).\n1. The green scale image is used to identify the protein whereas the others are used for reference.\n2. Each color channel is represented by an image with the same base name but the color name appended to the base name.","metadata":{}},{"cell_type":"code","source":"train_path = \"../input/train/\"\ndef load_image(basepath, image_id):\n    images = np.zeros(shape=(4,512,512))\n    images[0,:,:] = imread(basepath + image_id + \"_green\" + \".png\")\n    images[1,:,:] = imread(basepath + image_id + \"_red\" + \".png\")\n    images[2,:,:] = imread(basepath + image_id + \"_blue\" + \".png\")\n    images[3,:,:] = imread(basepath + image_id + \"_yellow\" + \".png\")\n    return images\n\ndef make_image_row(image, subax, title):\n    subax[0].imshow(image[0], cmap=\"Greens\")\n    subax[1].imshow(image[1], cmap=\"Reds\")\n    subax[1].set_title(\"stained microtubules\")\n    subax[2].imshow(image[2], cmap=\"Blues\")\n    subax[2].set_title(\"stained nucleus\")\n    subax[3].imshow(image[3], cmap=\"Oranges\")\n    subax[3].set_title(\"stained endoplasmatic reticulum\")\n    subax[0].set_title(title)\n    return subax\n\ndef make_title(file_id):\n    file_targets = train_labels.loc[train_labels.Id==file_id, \"Target\"].values[0]\n    title = \" - \"\n    for n in file_targets:\n        title += label_names[n] + \" - \"\n    return title\nclass TargetGroupIterator:\n    \n    def __init__(self, target_names, batch_size, basepath):\n        self.target_names = target_names\n        self.target_list = [reverse_train_labels[key] for key in target_names]\n        self.batch_shape = (batch_size, 4, 512, 512)\n        self.basepath = basepath\n    \n    def find_matching_data_entries(self):\n        train_labels[\"check_col\"] = train_labels.Target.apply(\n            lambda l: self.check_subset(l)\n        )\n        self.images_identifier = train_labels[train_labels.check_col==1].Id.values\n        train_labels.drop(\"check_col\", axis=1, inplace=True)\n    \n    def check_subset(self, targets):\n        return np.where(set(targets).issubset(set(self.target_list)), 1, 0)\n    \n    def get_loader(self):\n        filenames = []\n        idx = 0\n        images = np.zeros(self.batch_shape)\n        for image_id in self.images_identifier:\n            images[idx,:,:,:] = load_image(self.basepath, image_id)\n            filenames.append(image_id)\n            idx += 1\n            if idx == self.batch_shape[0]:\n                yield filenames, images\n                filenames = []\n                images = np.zeros(self.batch_shape)\n                idx = 0\n        if idx > 0:\n            yield filenames, images","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"your_choice = [\"Lysosomes\", \"Endosomes\"]\nyour_batch_size = 20\nimageloader = TargetGroupIterator(your_choice, your_batch_size, train_path)\nimageloader.find_matching_data_entries()\niterator = imageloader.get_loader()\nfile_ids, images = next(iterator)\n\nfig, ax = plt.subplots(len(file_ids),4,figsize=(20,5*len(file_ids)))\nif ax.shape == (4,):\n    ax = ax.reshape(1,-1)\nfor n in range(len(file_ids)):\n    make_image_row(images[n], ax[n], make_title(file_ids[n]))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"INPUT_SHAPE = (299,299,3)\nBATCH_SIZE = 10","metadata":{"_uuid":"fd738656b83fbd6d92f3c0e9fd83bafca8856d49","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Processing the data to feed into the model","metadata":{}},{"cell_type":"code","source":"path_to_train = '/kaggle/input/train/'\ndata = pd.read_csv('/kaggle/input/train.csv')\n\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])})\ntrain_dataset_info = np.array(train_dataset_info)","metadata":{"_uuid":"42315d01b95b8a901088befa4100b014a1416c7a","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We've formed a numpy array of dictionaries, each dictionary holding two values:\n1. Path of the image [Not including the colors, only the absolute path]\n2. Classes of proteins in the image","metadata":{}},{"cell_type":"code","source":"train_dataset_info","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Splitting the data into Train and Test Sets","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\ntrain_ids, test_ids, train_targets, test_target = train_test_split(\n    data['Id'], data['Target'], test_size=0.2, random_state=42)","metadata":{"_uuid":"79baa15c0f198d5fa32242ad2fe33d26a29c2970","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Create datagenerator\n- It is a helper class that is used to generate batches of training input into our model","metadata":{"_uuid":"ae3dcb3e4a000051fc8947502a28d399d200a924"}},{"cell_type":"code","source":"class data_generator:\n    \n    def create_train(dataset_info, batch_size, shape, augument=True):\n        assert shape[2] == 3\n        while True:\n            random_indexes = np.random.choice(len(dataset_info), batch_size)\n            batch_images = np.empty((batch_size, shape[0], shape[1], shape[2]))\n            batch_labels = np.zeros((batch_size, 28)) # Creating label tensors for each batch where all 28 values are originally zero\n            for i, idx in enumerate(random_indexes):\n                image = data_generator.load_image(\n                    dataset_info[idx]['path'], shape)   \n                if augument:\n                    image = data_generator.augment(image)\n                batch_images[i] = image\n                batch_labels[i][dataset_info[idx]['labels']] = 1 # Change those values to one which are present in the image\n            yield batch_images, batch_labels\n            \n    # We club the four color channels into one image and that to our set. This can be seen below where we visualise the first five images in our set\n    def load_image(path, shape):\n        R = np.array(Image.open(path+'_red.png'))\n        G = np.array(Image.open(path+'_green.png'))\n        B = np.array(Image.open(path+'_blue.png'))\n        Y = np.array(Image.open(path+'_yellow.png'))\n\n        image = np.stack((\n            R/2 + Y/2, \n            G/2 + Y/2, \n            B),-1)\n        \n        image = cv2.resize(image, (shape[0], shape[1])) # resizing the image\n        image = np.divide(image, 255) # Normalising the image\n        return image  \n                \n    # Random augmentation based modification. This means each image appended to our set is rotated or flipped by some degree if augmentation is set to True which it is.\n    def augment(image):\n        augment_img = iaa.Sequential([\n            iaa.OneOf([\n                iaa.Affine(rotate=0),\n                iaa.Affine(rotate=90),\n                iaa.Affine(rotate=180),\n                iaa.Affine(rotate=270),\n                iaa.Fliplr(0.5),\n                iaa.Flipud(0.5),\n            ])], random_order=True)\n        \n        image_aug = augment_img.augment_image(image)\n        return image_aug","metadata":{"_uuid":"c21509d05e2882e6315fc7390d27658c0654fc15","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create train datagen\ntrain_datagen = data_generator.create_train(\n    train_dataset_info, 5, (299,299,3), augument=True)","metadata":{"_uuid":"3f2ae48955c4b75b13dd9e9ad0d9e1c84214b019","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images, labels = next(train_datagen)\n\nfig, ax = plt.subplots(1,5,figsize=(25,5))\nfor i in range(5):\n    ax[i].imshow(images[i])\nprint('min: {0}, max: {1}'.format(images.min(), images.max()))","metadata":{"_uuid":"5f261d54682cbd326a01e09a0f92598228145d2d","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Create model\n - Tools - Keras and Tensorflow","metadata":{"_uuid":"ddbc11bf72ecab4028380d64a08660a70a2da028","trusted":true}},{"cell_type":"code","source":"from keras.preprocessing.image import ImageDataGenerator\nfrom keras.models import Sequential, load_model\nfrom keras.layers import Activation\nfrom keras.layers import Dropout\nfrom keras.layers import Flatten\nfrom keras.layers import Dense\nfrom keras.layers import Input\nfrom keras.layers import BatchNormalization\nfrom keras.layers import Conv2D\nfrom keras.models import Model\nfrom keras.applications import InceptionResNetV2\nfrom keras.callbacks import ModelCheckpoint\nfrom keras.callbacks import LambdaCallback\nfrom keras.callbacks import Callback\nfrom keras import metrics\nfrom keras.optimizers import Adam \nfrom keras import backend as K\nimport tensorflow as tf\nimport keras\n\ndef create_model(input_shape, n_out):\n    \n    pretrain_model = InceptionResNetV2(\n        include_top=False, \n        weights='imagenet', \n        input_shape=input_shape)    \n    \n    input_tensor = Input(shape=input_shape)\n    bn = BatchNormalization()(input_tensor)\n    x = pretrain_model(bn)\n    x = Conv2D(128, kernel_size=(1,1), activation='relu')(x)\n    x = Flatten()(x)\n    x = Dropout(0.5)(x)\n    x = Dense(512, activation='relu')(x)\n    x = Dropout(0.5)(x)\n    output = Dense(n_out, activation='sigmoid')(x)\n    model = Model(input_tensor, output)\n    \n    return model","metadata":{"_uuid":"64bba0326be38da7add3594002563bea1c9703db","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def f1(y_true, y_pred):\n    tp = K.sum(K.cast(y_true*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)","metadata":{"_uuid":"f1d143e285b01408b2263a946712131ea87c3b74","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_history(history):\n    fig, ax = plt.subplots(1, 3, figsize=(15,3))\n    ax[0].set_title('loss')\n    ax[0].plot(history.epoch, history.history[\"loss\"], label=\"Train loss\")\n    ax[0].plot(history.epoch, history.history[\"val_loss\"], label=\"Validation loss\")\n    ax[1].set_title('f1')\n    ax[1].plot(history.epoch, history.history[\"f1\"], label=\"Train f1\")\n    ax[1].plot(history.epoch, history.history[\"val_f1\"], label=\"Validation f1\")\n    ax[2].set_title('acc')\n    ax[2].plot(history.epoch, history.history[\"acc\"], label=\"Train acc\")\n    ax[2].plot(history.epoch, history.history[\"val_acc\"], label=\"Validation acc\")\n    ax[0].legend()\n    ax[1].legend()\n    ax[2].legend()","metadata":{"_uuid":"f450d5ecc60bd6833f2673127103a7cc49f6ead9","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"keras.backend.clear_session()\n\nmodel = create_model(\n    input_shape=(299,299,3), \n    n_out=28)\n\nmodel.summary()","metadata":{"_uuid":"33936d2e6a7d0d69dda9b96a8dba829f52c2c800","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.utils.vis_utils import plot_model\nplot_model(model, to_file='model_plot.png', show_shapes=True, show_layer_names=True)\nImage.open('model_plot.png')\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Train model","metadata":{"_uuid":"2fbffd71262d7d7e591ad5955feb6b0c5ee61737"}},{"cell_type":"code","source":"\ncheckpoint_path = \"training_2/cp-{epoch:04d}.ckpt\"\ncheckpoint_dir = os.path.dirname(checkpoint_path)\n\n\ncheckpointer = ModelCheckpoint(\n    '/kaggle/working/InceptionResNetV2.model',\n    verbose=2, save_weights_only=True, save_best_only=True)\n\ntrain_generator = data_generator.create_train(\n    train_dataset_info[train_ids.index], BATCH_SIZE, INPUT_SHAPE, augument=False)\nvalidation_generator = data_generator.create_train(\n    train_dataset_info[test_ids.index], 256, INPUT_SHAPE, augument=False)\n\n\nmodel.layers[2].trainable = False\n\nmodel.compile(\n    loss='binary_crossentropy',  \n    optimizer=Adam(1e-4),\n    metrics=['acc', f1])\n\n# model.save_weights(checkpoint_path.format(epoch=0))\n\nhistory = model.fit_generator(\n    train_generator,\n    steps_per_epoch=100,\n    validation_data=next(validation_generator),\n    epochs=100, \n    verbose=1,\n    callbacks=[checkpointer])","metadata":{"_uuid":"0343374956494b98425448b7aa9092a037aee401","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_history(history)","metadata":{"_uuid":"87c8e7f4219275aa7e2bcb99b195bcb4b5b276c2","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Testing the model using Examples:","metadata":{"_uuid":"2a52b306cd27fc030cfd3f7583009945de7828ac"}},{"cell_type":"markdown","source":"Example from Test and Train sets","metadata":{}},{"cell_type":"markdown","source":"For train:\n\n0020af02-bbba-11e8-b2ba-ac1f6b6435d0\n\n006f3dde-bbc9-11e8-b2bc-ac1f6b6435d0\n\n0089bdfe-bbc8-11e8-b2bc-ac1f6b6435d0\n","metadata":{}},{"cell_type":"code","source":"path = os.path.join('../input/train','0089bdfe-bbc8-11e8-b2bc-ac1f6b6435d0')\nimage = data_generator.load_image(path, INPUT_SHAPE)\nplt.imshow(image)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Thresholds between 0.05 to 0.2 are working well at predicting the protein classes","metadata":{}},{"cell_type":"code","source":"def generate_classes(image,model):\n    score_predict = model.predict(image[np.newaxis])[0]\n    label_predict = np.arange(28)[score_predict>=0.05]\n    str_predict_label = ' '.join(str(l) for l in label_predict)\n    return str_predict_label\nresult = generate_classes(image,model)\nresult_ = result.split(' ')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"linter = []\nfor i in result_:\n    linter.append(label_names[int(i)])\nprint(result)\nprint(linter)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Takeaway from printing predicted for every image in test and even train set:\n* Majority of them had 0 and/or 25 which concludes that the amount of images containing Nucleoplasm and Cytosol where huge and highlights the imbalance in the dataset.\n* Thresholds for the sigmoid functions worked well between 0.05 to 0.2.\n - In the case of 0.05 more classes were being predicted but it would contain most of the true predictions.\n - In the case of 1.0 some gave accurate results whereas some gave only 'Nucleoplasm' as class.\n - In the case of 2.0, most of them were predicting 'Nucleoplasm' and/or 'Cytosol', which also highlights the imbalance in the dataset. \n- Mean accuracy of the model on the classification task was around 94%\n- Mean f1 score of the model varied around 0.03 - 0.05","metadata":{}},{"cell_type":"code","source":"model.save('Human Protein Atlas Model')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from IPython.display import FileLink\nFileLink('Human Protein Atlas Model')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"FileLink('InceptionResNetV2.model')","metadata":{},"execution_count":null,"outputs":[]}]}