{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\n\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as T\nfrom PIL import Image\n\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torchvision.models as models\n\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\nfrom typing import List, Dict","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"TEST_CSV = '/kaggle/input/human-protein-atlas-image-classification/sample_submission.csv'\nTEST_DIR = '/kaggle/input/human-protein-atlas-image-classification/test'\n\ntest_df = pd.read_csv(TEST_CSV)\ntest_df.Predicted = test_df.Predicted.astype(str)\n\nTRAIN_STATS = '/kaggle/input/human-protein-atlas-data-stats/stats.pt'\nstats = torch.load(TRAIN_STATS)\n\nPRETAINED_WEIGHTS = '/kaggle/input/human-protein-atlas-resnet34-focalloss/protein-resnet.pth'\n\ntest_df.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"text_labels = {\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}\n\nNUM_LABELS = len(text_labels)\nprint(f\"There are {NUM_LABELS} labels\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"FILTERS = ['red', 'green', 'blue', 'yellow']\n\ndef load_image(image_id, ddir):\n    \"\"\"\n    return: 4-channel PIL Image\n    \"\"\"\n    return Image.merge('RGBA', [Image.open(f\"{ddir}/{image_id}_{f}.png\") for f in FILTERS])\n\n\ndef encode(image_labels: str):\n    \"\"\"\n    image_labels: label(s) of an image, e.g. \"25 0\"\n    return: tensor of size (28)\n    \"\"\"\n    target = torch.zeros(NUM_LABELS)\n    for label in image_labels.split():\n        target[int(label)] = 1\n    return target\n\n\ndef decode():\n    pass\n\n\nclass FocalLoss(nn.Module):\n    def __init__(self, gamma):\n        super().__init__()\n        self.gamma = gamma\n        \n    def forward(self, preds, targets):\n        loss = targets * torch.log(preds) * (1 - preds) ** self.gamma \\\n               + (1 - targets) * torch.log(1 - preds) * preds ** self.gamma\n    \n        return -torch.mean(loss)\n\nclass ProteinLocalizationDataset(Dataset):\n    def __init__(self, df, ddir, transform=None):\n        self.df = df\n        self.ddir = ddir\n        self.transform = transform\n    \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, idx):\n        image_id, image_labels = self.df.loc[idx]\n        image = load_image(image_id, self.ddir)\n        if self.transform:\n            image = self.transform(image)\n        return image, encode(image_labels)\n\n\nclass MultiLocalizationClassification(nn.Module):\n    def training_step(self, batch):\n        imgs, targets = batch\n        out = self(imgs)\n        loss = CRITERION(out, targets)\n        return loss\n  \n\n    def validation_step(self, batch):\n        imgs, targets = batch\n        out = self(imgs)\n        loss = CRITERION(out, targets)\n        score = f_score(out, targets)\n        return {'val_loss': loss.detach(), 'val_score': score.detach()}\n    \n    \n    @staticmethod\n    def validation_epoch_end(outputs: List):\n        val_losses = [o['val_loss'] for o in outputs]\n        val_scores = [o['val_score'] for o in outputs]\n        \n        val_loss = torch.mean(torch.stack(val_losses))\n        val_score = torch.mean(torch.stack(val_scores))\n        return {'val_loss': val_loss.item(), 'val_score': val_score.item()}\n\n    \n    @staticmethod\n    def epoch_end(epoch_num: int, result: Dict):\n        train_loss, val_loss, val_score = result['train_loss'], result['val_loss'], result['val_score']\n        print(f\"Epoch {epoch_num}, train_loss: {train_loss}, val_loss: {val_loss}, val_score:{val_score}\")\n\n        \n        \nclass Resnet34(MultiLocalizationClassification):\n    def __init__(self):\n        super().__init__()\n        self.network = models.resnet34(pretrained=True)\n        # weight for RGB is from Resnet34, weight for Y is set to mean(weight of RGB)\n        weight = self.network.conv1.weight.clone()\n        self.network.conv1 = nn.Conv2d(4, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)\n        with torch.no_grad():\n            self.network.conv1.weight[:,:3] = weight\n            self.network.conv1.weight[:, 3] = torch.mean(weight, dim=1)\n        # update out_features to NUM_LABELS\n        in_features = self.network.fc.in_features\n        self.network.fc = nn.Linear(in_features, NUM_LABELS)\n        \n            \n    def forward(self, xb):\n        return torch.sigmoid(self.network(xb))\n    \n    \n    def freeze(self):\n        for param in self.network.parameters():\n            param.requires_grad = False\n        for param in self.network.fc.parameters():\n            param.requires_grad = True\n        for param in self.network.conv1.parameters():\n            param.requires_grad = True\n    \n    \n    def unfreeze(self):\n        for param in self.network.parameters():\n            param.requires_grad = True\n\n            \ndef get_default_device():\n    if torch.cuda.is_available():\n        return torch.device('cuda')\n    return torch.device('cpu')\n\n\ndef to_device(data, device):\n    if isinstance(data, (list, tuple)):\n        return [to_device(d, device) for d in data]\n    return data.to(device, non_blocking=True)\n\n\nclass DeviceDataLoader():\n    def __init__(self, dl, device):\n        self.dl = dl\n        self.device = device\n    \n    def __len__(self):\n        return len(self.dl)\n    \n    def __iter__(self):\n        for batch in self.dl:\n            yield to_device(batch, self.device)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"tfms = T.Compose([T.ToTensor(), T.Normalize(*stats)])\n\ntest_ds = ProteinLocalizationDataset(test_df, TEST_DIR, transform=tfms)\n\nbatch_size = 32\ntest_dl = DataLoader(test_ds, batch_size=batch_size, shuffle=False, \n                     num_workers=2, pin_memory=True)\n\ndevice = get_default_device()\n\ntest_dl = DeviceDataLoader(test_dl, device)\n\nCRITERION = FocalLoss(gamma=1)\nmodel = to_device(Resnet34(), device)\nmodel.load_state_dict(torch.load(PRETAINED_WEIGHTS, map_location=device))\nmodel.eval();","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"th = torch.load('/kaggle/input/human-protein-atlas-tune-thresholds/thresholds.pt')\nth = torch.tensor(th)\nth","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"help(torch.abs)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"EPSILON = 1e-6 \n\ndef decode(pred, th=th, text=False):\n    label = [idx for idx, true in enumerate(pred > th) if true]\n    \n    if label == []:\n        label = [np.argmax(torch.abs((pred - th) / (th + EPSILON))).item()]\n    \n    if text:\n        return ' '.join([text_labels[l] + ' (' + str(l) +')' for l in label])\n    else:\n        return ' '.join(map(str, label))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time \n\n@torch.no_grad()\ndef predict_dl(dl, model):\n    torch.cuda.empty_cache()\n    batch_probs = []\n    for xb, _ in dl:\n        probs = model(xb)\n        batch_probs.append(probs.cpu().detach())\n    batch_probs = torch.cat(batch_probs)\n    batch_labels = [decode(x) for x in batch_probs]\n    return batch_probs, batch_labels\n\ntest_probs, test_labels = predict_dl(test_dl, model)\ntorch.save(test_probs, 'test_probs.pt')\ntorch.save(test_labels, 'test_labels.pt')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df['Predicted'] = pd.Series(test_labels)\ntest_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df.sort_values(by='Id').set_index('Id').to_csv(\n    'submission.csv', header=True)","execution_count":null,"outputs":[]},{"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}