{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# Part1 Import all the library \n\n# Built In Imports\nimport os\nfrom collections import defaultdict\nfrom tqdm import tqdm_notebook as tqdm\nimport sys; \nsys.path.insert(0,'../input/timm-nfnet')\nimport timm\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\n# Visualization Imports\nimport matplotlib.pyplot as plt \nimport seaborn as sns\nimport cv2 \nimport torch\nfrom PIL import Image\n\n# Machine Learning and Data Science Imports\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader, random_split\nimport torchvision\nimport torchvision.transforms as tfms\nimport numpy as np\nimport pandas as pd ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Define the path to the root data directory & competition data directory\n\nTRAIN_DF_PATH = \"../input/hpa-single-cell-image-classification/train.csv\"\nTRAIN_IMG_PATH = \"../input/hpa-single-cell-image-classification/train\"\nTEST_IMG_PATH = \"../input/hpa-single-cell-image-classification/test\"\nSAMPLE_SUB = \"../input/hpa-single-cell-image-classification/sample_submission.csv\"\nCELL_LABEL = {\n0:  \"Nucleoplasm\", \n1:  \"Nuclear membrane\",   \n2:  \"Nucleoli\",   \n3:  \"Nucleoli fibrillar center\" ,  \n4:  \"Nuclear speckles\",\n5:  \"Nuclear bodies\",\n6:  \"Endoplasmic reticulum\",   \n7:  \"Golgi apparatus\",\n8:  \"Intermediate filaments\",\n9:  \"Actin filaments\", \n10: \"Microtubules\",\n11:  \"Mitotic spindle\",\n12:  \"Centrosome\",   \n13:  \"Plasma membrane\",\n14:  \"Mitochondria\",   \n15:  \"Aggresome\",\n16:  \"Cytosol\",   \n17:  \"Vesicles and punctate cytosolic patterns\",   \n18:  \"Negative\"\n}\n\nprint(\"\\n\\n... IMPORTS COMPLETE ...\\n\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create the relevant dataframe objects\ntrain_df = pd.read_csv(TRAIN_DF_PATH)\ntrain_df['label_count'] = train_df['Label'].apply(lambda x: len(x.split(\"|\")))\ntrain_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Part2 Visualization of dataset\n# class count for multi classes\n\nplt.title(\"Class count\")\nsns.countplot(train_df['label_count'],palette=\"Set3\")\nplt.show()\n\n#This shows that most of the samples are single classes compared to multi classes","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Compare between single vs Multi label distribution\n\nsingle_class = train_df[train_df['label_count'] == 1]['label_count'].count()\nmulti_class = train_df[train_df['label_count'] > 1]['label_count'].count()\n\n# Label - in the training data, this represents the labels assigned to each sample\nplt.figure(figsize=(10, 8))\nplt.title(\"Single VS Mutli distribution\")\nsns.barplot(x=['Single', 'Multi'], y=[single_class, multi_class],palette='Set3')\n\n#palette : flare to Set3\nplt.show()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Compare between single vs multi label distribution\nlabels = train_df[\"Label\"].apply(lambda x: x.split(\"|\"))\nlabels_count = defaultdict(int)\n\n# Update the counter \nfor label in labels:\n    if len(label) > 1:\n        for l in label:\n            labels_count[CELL_LABEL[int(l)]]+=1\n    else:\n        labels_count[CELL_LABEL[int(label[0])]]+=1\n        \nplt.figure(figsize=(10, 8))\nplt.xticks(rotation=45)\nplt.title(\"Target counts\")\nsns.barplot(list(labels_count.keys()),list(labels_count.values()), palette='Set3')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Part3 show the four channel images\n\n# Images are given in the form of red green blue and yellow\ndef show_image(img_path):\n    \n    sns.reset_orig()\n\n    #get image id\n    im_id = train_df.loc[1, \"ID\"]\n\n    cdict1 = {'red':   ((0.0,  0.0, 0.0),\n                       (1.0,  0.0, 0.0)),\n\n             'green': ((0.0,  0.0, 0.0),\n                       (0.75, 1.0, 1.0),\n                       (1.0,  1.0, 1.0)),\n\n             'blue':  ((0.0,  0.0, 0.0),\n                       (1.0,  0.0, 0.0))}\n\n    cdict2 = {'red':   ((0.0,  0.0, 0.0),\n                       (0.75, 1.0, 1.0),\n                       (1.0,  1.0, 1.0)),\n\n             'green': ((0.0,  0.0, 0.0),\n                       (1.0,  0.0, 0.0)),\n\n             'blue':  ((0.0,  0.0, 0.0),\n                       (1.0,  0.0, 0.0))}\n\n    cdict3 = {'red':   ((0.0,  0.0, 0.0),\n                       (1.0,  0.0, 0.0)),\n\n             'green': ((0.0,  0.0, 0.0),\n                       (1.0,  0.0, 0.0)),\n\n             'blue':  ((0.0,  0.0, 0.0),\n                       (0.75, 1.0, 1.0),\n                       (1.0,  1.0, 1.0))}\n\n    cdict4 = {'red': ((0.0,  0.0, 0.0),\n                       (0.75, 1.0, 1.0),\n                       (1.0,  1.0, 1.0)),\n\n             'green': ((0.0,  0.0, 0.0),\n                       (0.75, 1.0, 1.0),\n                       (1.0,  1.0, 1.0)),\n\n             'blue':  ((0.0,  0.0, 0.0),\n                       (1.0,  0.0, 0.0))}\n\n    plt.register_cmap(name='greens', data=cdict1)\n    plt.register_cmap(name='reds', data=cdict2)\n    plt.register_cmap(name='blues', data=cdict3)\n    plt.register_cmap(name='yellows', data=cdict4)\n\n    #get each image channel as a greyscale image (second argument 0 in imread)\n    green = cv2.imread('../input/hpa-single-cell-image-classification/train/{}_green.png'.format(img_path), 0)\n    red = cv2.imread('../input/hpa-single-cell-image-classification/train/{}_red.png'.format(img_path), 0)\n    blue = cv2.imread('../input/hpa-single-cell-image-classification/train/{}_blue.png'.format(img_path), 0)\n    yellow = cv2.imread('../input/hpa-single-cell-image-classification/train/{}_yellow.png'.format(img_path), 0)\n\n\n    #display each channel separately\n    fig, ax = plt.subplots(nrows = 2, ncols=2, figsize=(15, 15))\n    ax[0, 0].imshow(green, cmap=\"greens\")\n    ax[0, 0].set_title(\"Protein of interest\", fontsize=18)\n    ax[0, 1].imshow(red, cmap=\"reds\")\n    ax[0, 1].set_title(\"Microtubules\", fontsize=18)\n    ax[1, 0].imshow(blue, cmap=\"blues\")\n    ax[1, 0].set_title(\"Nucleus\", fontsize=18)\n    ax[1, 1].imshow(yellow, cmap=\"yellows\")\n    ax[1, 1].set_title(\"Endoplasmic reticulum\", fontsize=18)\n    for i in range(2):\n        for j in range(2):\n            ax[i, j].set_xticklabels([])\n            ax[i, j].set_yticklabels([])\n            ax[i, j].tick_params(left=False, bottom=False)\n    plt.show()\n    \n\n    \n#All image samples are represented by four filters (stored as individual files), \n#the protein of interest (green) plus three cellular landmarks: nucleus (blue), microtubules (red), \n#endoplasmic reticulum (yellow). \n#The green filter should be used to predict the label and the other filters are used as references. \nshow_image(train_df.iloc[1,0])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#hyperparameters\nCLASS = 19\nBATCH_SIZE = 64\nEPOCHS = 5\nLR = 1e-4\nRESIZE = 256\nDEVICE = torch.device('cuda') if torch.cuda.is_available() \\\n         else torch.device('cpu')\nPATH = '../input/hpa-single-cell-image-classification/'\nTRAIN_DIR = PATH + 'train/'\nTEST_DIR = PATH + 'test/'\n\n#imagenet transform\nimg_tfms = tfms.Compose(\n    [tfms.ToTensor(),\n     tfms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))])\nDEVICE","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class HPADataset(Dataset):\n    def __init__(self,csv_path,ids,label,resize=None,transforms=None):\n        self.csv_path = csv_path\n        self.ids = ids\n        self.label = label\n        self.resize = resize\n        self.transforms = transforms\n        \n    def __len__(self):\n        return len(self.ids)\n    \n    def __getitem__(self, item):\n        _ids = self.ids[item]\n        image = cv2.imread(os.path.join(self.csv_path,_ids +'_green.png'))\n        if self.resize:\n            image = cv2.resize(image, (self.resize, self.resize))\n            image = image / 255.0\n        \n        #setting the target to one hot encoded form\n        if \"train\" in self.csv_path:\n            y = self.label[item]\n            y = y.split('|')\n            y = list(map(int, y))\n            y = np.eye(CLASS, dtype='float')[y]\n            y = y.sum(axis=0)\n            return self.transforms(image), y\n        elif \"test\" in self.csv_path:\n            return self.transforms(image), _ids","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#model\nclass NFNet(nn.Module):\n    def __init__(self,output_features, model_name = 'nfnet_f1', pertrained=True):\n        super(NFNet, self).__init__()\n        self.model = timm.create_model(model_name, pretrained=pertrained)\n        self.model.head.fc = nn.Sequential(nn.Linear(self.model.head.fc.in_features, 512),\n                                 nn.ReLU(),\n                                 nn.Linear(512, output_features))\n    \n        \n        \n    def forward(self, x):\n        x = self.model(x)\n        return x\n\nclass CNNet(nn.Module):\n    def __init__(self, input_features, output_features):\n        super(CNNet, self).__init__()\n        self.model = torchvision.models.resnet34(pretrained=True)\n        self.model.fc = nn.Sequential(nn.Linear(input_features, 100),\n                                 nn.ReLU(),\n                                 nn.Linear(100, output_features))\n\n    def forward(self, x):\n        out = self.model(x)\n        return out\n    \n# class PNASNet5Large(nn.Module):\n#     def __init__(self, num_classes, odel_name = 'pnasnet5large', pretrained = True):\n#         super(PNASNet5Large, self).__init__()\n#         model = pretrainedmodels.pnasnet5large(num_classes=1000,pretrained=\"imagenet\")\n#         model.last_linear = nn.Linear(model.last_linear.in_features,\n#                                       num_classes)\n        \n        \n#     def forward(self, x):\n#         x = self.model(x)\n#         return x","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = NFNet(CLASS)\n#model = PNASNet5Large(CLASS)\nmodel = model.to(DEVICE)\nloss_fn = nn.BCEWithLogitsLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=LR)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Since we are experimenting we will only be taking a small batch of 5000 sample"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv(PATH + \"train.csv\")\ntrain_df =train_df.sample(frac=1).reset_index(drop=True)\ntrain_df = train_df.iloc[:5000,:]\nX_train, y_train = train_df.loc[:,'ID'].values,\\\n                    train_df['Label'].values\nX_ds = HPADataset(TRAIN_DIR, X_train, y_train, RESIZE, img_tfms)\ntrain_ds, valid_ds = random_split(X_ds,[4000,1000])  \ntrain_dl = DataLoader(train_ds, batch_size=BATCH_SIZE,shuffle=True)\nvalid_dl = DataLoader(valid_ds, batch_size=BATCH_SIZE,shuffle=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#train loop\nloss_hist = []\nfor epoch in tqdm(range(EPOCHS)):\n    losses = []\n    model = model.train()\n    for batch_idx, (image, label) in enumerate(train_dl):\n        image = image.to(DEVICE)\n        label = label.to(DEVICE)\n        output = model(image.float())\n        loss = loss_fn(output, label)\n        losses.append(loss.item())\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n    loss_hist.append(sum(losses)/len(losses))\n    print(f\"epoch: {epoch} loss:{sum(losses)/len(losses)}\")\n\nplt.figure(figsize=(15, 8))\nplt.title('Train Loss')\nplt.xlabel('epochs')\nplt.ylabel('loss')\nplt.plot(loss_hist)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def check_accuracy(loader, model):\n    correct = 0.\n    total = 0.\n    with torch.no_grad():\n        for images, labels in loader:\n            images = images.to(DEVICE)\n            outputs = model(images.float())\n            outputs = torch.sigmoid(outputs).cpu() \n            predicted = np.round(outputs)\n            total += labels.size(0)\n            correct += (predicted == labels).sum().item()\n            break\n    accuracy = 100 * correct / total\n    print(\"Accuracy: {}%\".format(accuracy))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_Test = [name.rstrip('green.png').rstrip('_') for name in (os.listdir(TEST_DIR)) if '_green.png' in name]\n\ntest_ds = HPADataset(TEST_DIR, X_Test, None, RESIZE, img_tfms)\ntest_dl = DataLoader(test_ds, batch_size=1, shuffle=False)\n\nsubmission_lst = []\n\nwith torch.no_grad():\n    model.eval()\n    for image, file in test_dl:     \n        image = image.to(DEVICE)        \n        output = model(image.float())                          \n        prob = torch.softmax(output, dim=1)\n        p, top_class = prob.topk(1, dim=1)\n        sp = ' '.join(str(e) for e in [top_class[0][0].item(), p[0][0].item()])               \n        img = cv2.imread(TEST_DIR + file[0] + '_green.png')\n        \n        if img.shape[0] == 2048:\n            sp = sp + ' eNoLCAgIMAEABJkBdQ=='\n        elif img.shape[0] == 1728:\n            sp = sp + ' eNoLCAjJNgIABNkBkg=='\n        else:\n            sp = sp + ' eNoLCAgIsAQABJ4Beg=='\n        \n        submission_lst.append([file[0], img.shape[1], img.shape[0], sp])\n        \nsub = pd.DataFrame.from_records(submission_lst, columns=['ID', 'ImageWidth', 'ImageHeight', 'PredictionString'])\nsub.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub.to_csv(\"submission.csv\", index=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Thanks to @ateplyuk for the dataset and inference pipelines\n\n**if you found this notebook helpful, please leave an upvote!**"},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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}