{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install ../input/weights/timm-0.3.1-py3-none-any.whl","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import random\nimport time\nimport math\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.nn.parameter import Parameter\nimport torch.optim as optim\nfrom torch.utils.data import DataLoader\nimport torchvision.transforms as transforms\nfrom torchvision.transforms import functional as FT\nfrom PIL import Image,  ImageChops\nimport cv2\n\nfrom sklearn.metrics import cohen_kappa_score\nimport timm\n\ndevice = \"cuda:0\"\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torchvision\nimport csv\nimport timm\nimport time\nimport glob\nimport copy\nimport os\nimport json\nimport cv2\nimport numpy as np\nimport pickle\nimport torch.optim as optim\nimport torch\nimport torch.nn.functional as F\nfrom torch import nn as nn\nfrom torch.optim import lr_scheduler\nfrom timm.models import *\nfrom torch.utils.data import Dataset, DataLoader, random_split\nfrom torchvision import transforms, utils, models, datasets\nfrom PIL import Image\nfrom PIL import Image, ImageEnhance, ImageOps\nfrom torchvision.models._utils import IntermediateLayerGetter\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor\nfrom torchvision.models.detection.backbone_utils import resnet_fpn_backbone\nfrom torchvision.ops.feature_pyramid_network import (\n    FeaturePyramidNetwork,\n    LastLevelMaxPool,\n)\nfrom torchvision.models.detection import FasterRCNN\nfrom torchvision.models.detection.mask_rcnn import MaskRCNNPredictor\nfrom torchvision.ops.misc import FrozenBatchNorm2d\nfrom torchvision.models.detection.rpn import AnchorGenerator\nfrom torchvision.ops import misc as misc_nn_ops\nfrom torch import Tensor, Size\nfrom torch.jit.annotations import List, Optional, Tuple\nfrom torch.nn.parameter import Parameter\n\n\ndef gem(x, p=3, eps=1e-6):\n    return F.avg_pool2d(x.clamp(min=eps).pow(p), (x.size(-2), x.size(-1))).pow(1./p)\n\n\nclass GeM(nn.Module):\n    def __init__(self, p=3, eps=1e-6, flatten=False):\n        super(GeM,self).__init__()\n        self.p = Parameter(torch.ones(1)*p)\n        self.eps = eps\n        self.flatten = flatten\n    def forward(self, x):\n        x = gem(x, p=self.p, eps=self.eps)\n        if self.flatten:\n            x = x.flatten(1)\n        return x\n    def __repr__(self):\n        return self.__class__.__name__ + '(' + 'p=' + '{:.4f}'.format(self.p.data.tolist()[0]) + ', ' + 'eps=' + str(self.eps) + ')'\n\n\n\n\nclass FrozenBatchNorm2d(torch.nn.Module):\n    \"\"\"\n    BatchNorm2d where the batch statistics and the affine parameters\n    are fixed\n    \"\"\"\n\n    def __init__(\n        self,\n        num_features: int,\n        eps: float = 1e-5,\n        n: Optional[int] = None,\n    ):\n        # n=None for backward-compatibility\n        if n is not None:\n            warnings.warn(\"`n` argument is deprecated and has been renamed `num_features`\",\n                          DeprecationWarning)\n            num_features = n\n        super(FrozenBatchNorm2d, self).__init__()\n        self.eps = eps\n        self.register_buffer(\"weight\", torch.ones(num_features))\n        self.register_buffer(\"bias\", torch.zeros(num_features))\n        self.register_buffer(\"running_mean\", torch.zeros(num_features))\n        self.register_buffer(\"running_var\", torch.ones(num_features))\n\n    def _load_from_state_dict(\n        self,\n        state_dict: dict,\n        prefix: str,\n        local_metadata: dict,\n        strict: bool,\n        missing_keys: List[str],\n        unexpected_keys: List[str],\n        error_msgs: List[str],\n    ):\n        num_batches_tracked_key = prefix + 'num_batches_tracked'\n        if num_batches_tracked_key in state_dict:\n            del state_dict[num_batches_tracked_key]\n\n        super(FrozenBatchNorm2d, self)._load_from_state_dict(\n            state_dict, prefix, local_metadata, strict,\n            missing_keys, unexpected_keys, error_msgs)\n\n    def forward(self, x: Tensor) -> Tensor:\n        # move reshapes to the beginning\n        # to make it fuser-friendly\n        w = self.weight.reshape(1, -1, 1, 1)\n        b = self.bias.reshape(1, -1, 1, 1)\n        rv = self.running_var.reshape(1, -1, 1, 1)\n        rm = self.running_mean.reshape(1, -1, 1, 1)\n        scale = w * (rv + self.eps).rsqrt()\n        bias = b - rm * scale\n        return x * scale + bias\n\n    def __repr__(self) -> str:\n        return f\"{self.__class__.__name__}({self.weight.shape[0]}, eps={self.eps})\"\n    \n\nclass Linear(nn.Linear):\n    def forward(self, input: torch.Tensor) -> torch.Tensor:\n        if torch.jit.is_scripting():\n            bias = self.bias.to(dtype=input.dtype) if self.bias is not None else None\n            return F.linear(input, self.weight.to(dtype=input.dtype), bias=bias)\n        else:\n            return F.linear(input, self.weight, self.bias)\n    \n    \n    \n    \nclass backboneNet_efficient(nn.Module):\n    def __init__(self):\n        super(backboneNet_efficient, self).__init__()\n#         norm_layer=FrozenBatchNorm2d\n        net = timm.create_model('tf_efficientnet_b4_ns', pretrained=False)       \n        layers_to_train = ['blocks']       \n        for name, parameter in net.named_parameters():\n            if all([not name.startswith(layer) for layer in layers_to_train]):\n                parameter.requires_grad_(False)\n#         self.num_features = 1408\n        self.num_features = 1792\n        self.conv_stem = net.conv_stem\n        self.bn1 = net.bn1\n        self.act1 = net.act1       \n        self.block0 = net.blocks[0]\n        self.block1 = net.blocks[1]\n        self.block2 = net.blocks[2]\n        self.block3 = net.blocks[3]\n        self.block4 = net.blocks[4]\n        self.block5 = net.blocks[5]\n        self.block6 = net.blocks[6]       \n        self.conv_head = net.conv_head\n        self.bn2 = net.bn2\n        self.act2 = net.act2\n        self.global_pool =  net.global_pool\n        self.drop_rate = 0.4\n        \n#         self.dense1 = Linear(self.num_features, self.num_features, bias=True)\n        \n        self.rg_cls = Linear(self.num_features, 1, bias=True)\n        self.cls_cls = Linear(self.num_features, 5, bias=True)\n        self.ord_cls = Linear(self.num_features, 4, bias=True)\n        \n    def forward(self, x):\n        \n        x1 = self.conv_stem(x)\n        x2 = self.bn1(x1)\n        x3 = self.act1(x2)\n        x4 = self.block0(x1)\n        x5 = self.block1(x4)\n        x6 = self.block2(x5)\n        x7 = self.block3(x6)\n        x8 = self.block4(x7)\n        x9 = self.block5(x8)\n        x10 = self.block6(x9)       \n        x11 = self.conv_head(x10)\n        x12 = self.bn2(x11)\n        x13 = self.act2(x12)\n        x14  = self.global_pool(x13)\n        if self.drop_rate > 0.:\n            x14 = F.dropout(x14, p=self.drop_rate, training=self.training)\n            \n#         x15 = self.dense1(x14)\n#         x15 = self.act2(x15)\n        \n#         x16 = self.dense1(x14)\n#         x16 = self.act2(x16)\n        \n#         x17 = self.dense1(x14)\n#         x17 = self.act2(x17)\n            \n        x15 = self.rg_cls(x14)\n        x16 = self.cls_cls(x14)\n        x17 = self.ord_cls(x14)\n       \n        return x15, x16, x17\n    \n#     'test_Cpixel': transforms.Compose([\n#         transforms.Resize((280,280)),\n#         transforms.CenterCrop(256),\n#         transforms.ToTensor(),\n#         transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n#     ]),\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# utils\nthreshold = [0.75, 1.5, 2.5, 3.5]\ndef regress2class(out):\n    prediction = 0\n    \n    for i in range(4):\n        prediction += (out.data >= threshold[i]).squeeze().cpu().item()\n    \n    return prediction\n\ndef ordinal2class_prob(out):\n    pred_prob = torch.zeros(out.size(0), 5).cuda()\n    pred_prob[:, 0] = (1 - out[:, 0]).squeeze()\n    pred_prob[:, 1] = (out[:, 0] * (1 - out[:, 1])).squeeze()\n    pred_prob[:, 2] = (out[:, 1] * (1 - out[:, 2])).squeeze()\n    pred_prob[:, 3] = (out[:, 2] * (1 - out[:, 3])).squeeze()\n    pred_prob[:, 4] = out[:, 3].squeeze().cpu()\n    \n    return F.softmax(pred_prob, dim=1)\n\n\ndef regress2class_prob(out):\n    pred_prob = torch.zeros((out.size(0), 5)).cuda()\n\n    for i in range(out.size(0)):\n        if out[i] < 4.:\n            l1 = int(math.floor(out[i]))\n            l2 = int(math.ceil(out[i]))\n            pred_prob[i][l1] = 1 - (out[i] - l1)\n            pred_prob[i][l2] = 1 - (l2 - out[i])\n        else:\n            pred_prob[i][4] = 1.\n    \n    return pred_prob\n\ndef combine3output(r_out, c_out, o_out):\n    R = regress2class(r_out.data)\n    _, C = torch.max(c_out.data, 1)\n    C = C.squeeze().item()\n    _, O = torch.max(o_out.data, 1)\n    O = O.squeeze().item()\n    \n    P = (R + C + O) / 3.\n    P = int(round(P))\n    \n    return P","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# models\ndef gem(x, p=3, eps=1e-6):\n    return F.avg_pool2d(x.clamp(min=eps).pow(p), (x.size(-2), x.size(-1))).pow(1./p)\n\n\nclass GeM(nn.Module):\n    def __init__(self, p=3, eps=1e-6, flatten=False):\n        super(GeM,self).__init__()\n        self.p = Parameter(torch.ones(1)*p)\n        self.eps = eps\n        self.flatten = flatten\n    def forward(self, x):\n        x = gem(x, p=self.p, eps=self.eps)\n        if self.flatten:\n            x = x.flatten(1)\n        return x\n    def __repr__(self):\n        return self.__class__.__name__ + '(' + 'p=' + '{:.4f}'.format(self.p.data.tolist()[0]) + ', ' + 'eps=' + str(self.eps) + ')'\n\n\nclass Regressor(nn.Module):\n    def __init__(self):\n        super(Regressor, self).__init__()\n\n        self.backbone = timm.models.tf_efficientnet_b5_ns(pretrained=False)\n        self.backbone.global_pool = GeM(flatten=True)\n        self.regressor = nn.Linear(1000, 1)\n\n    def forward(self, x):\n        x = self.backbone(x)\n        out = self.regressor(x)\n        out = torch.sigmoid(out) * 4.5\n        \n        return out\n\n\nclass ThreeStage_Model(nn.Module):\n    def __init__(self, backbone=None):\n        super(ThreeStage_Model, self).__init__()\n        \n        self.backbone = timm.models.tf_efficientnet_b4_ns(pretrained=False)\n        self.backbone.global_pool = GeM(flatten=True)\n\n        self.classifier = nn.Sequential(\n                nn.SiLU(),\n                nn.Linear(1000, 500),\n                nn.SiLU(),\n                nn.Linear(500, 5),\n            )\n        \n        self.regressor = nn.Sequential(\n                nn.SiLU(),\n                nn.Linear(1000, 500),\n                nn.SiLU(),\n                nn.Linear(500, 1),\n            )\n\n        self.ordinal = nn.Sequential(\n                nn.SiLU(),\n                nn.Linear(1000, 500),\n                nn.SiLU(),\n                nn.Linear(500, 4),\n            )\n        \n        self.final_regressor = nn.Sequential(\n                nn.SiLU(),\n                nn.Linear(10, 1),\n            )\n\n    def forward(self, x, final=False):\n        x = self.backbone(x)\n        \n        c_out = self.classifier(x)\n        r_out = self.regressor(x)\n        o_out = self.ordinal(x)\n        \n        if final:\n            out = torch.cat((c_out, r_out, o_out), 1)\n            out = self.final_regressor(out)\n            out = torch.sigmoid(out) * 4.5\n            return out\n        else:\n            r_out = torch.sigmoid(r_out) * 4.5\n            o_out = torch.sigmoid(o_out)\n            return c_out, r_out, o_out","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# image transformation\nclass photometric_distort(object):\n    def __call__(self, image):\n        distortions = [FT.adjust_brightness,\n                       FT.adjust_contrast,\n                       FT.adjust_saturation,\n                       FT.adjust_hue]\n\n        random.shuffle(distortions)\n\n        for d in distortions:\n            if random.random() < 0.5:\n                if d.__name__ is 'adjust_hue':\n                    adjust_factor = random.uniform(-16 / 255., 16 / 255.)\n                else:\n                    adjust_factor = random.uniform(0.7, 1.3)\n                # Apply this distortion\n                image = d(image, adjust_factor)\n\n        return image\n\n\nclass cropTo4_3(object):\n    def __call__(self, image):\n        w, h = image.size\n        \n        if (w / h) >= (4 / 3):\n            new_h = h\n            new_w = int(h * 4 / 3)\n        else:\n            new_h = int(w * 3 / 4)\n            new_w = w\n            \n        left = (w - new_w)/2\n        top = (h - new_h)/2\n        right = left + new_w\n        bottom = top + new_h\n\n        return image.crop((left, top, right, bottom))\n\n    \nclass trim(object):\n    def __call__(self, image):\n        bg = Image.new(image.mode, image.size, image.getpixel((0,0)))\n        diff = ImageChops.difference(image, bg)\n        diff = ImageChops.add(diff, diff, 2.0, -10)\n        bbox = diff.getbbox()\n        if bbox:\n             return image.crop(bbox)\n            \n            \ndef crop_image_from_gray(img,tol=7):\n    if img.ndim ==2:\n        mask = img>tol\n        return img[np.ix_(mask.any(1),mask.any(0))]\n    elif img.ndim==3:\n        gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n        mask = gray_img>tol\n        \n        check_shape = img[:,:,0][np.ix_(mask.any(1),mask.any(0))].shape[0]\n        if (check_shape == 0): # image is too dark so that we crop out everything,\n            return img # return original image\n        else:\n            img1=img[:,:,0][np.ix_(mask.any(1),mask.any(0))]\n            img2=img[:,:,1][np.ix_(mask.any(1),mask.any(0))]\n            img3=img[:,:,2][np.ix_(mask.any(1),mask.any(0))]\n    #         print(img1.shape,img2.shape,img3.shape)\n            img = np.stack([img1,img2,img3],axis=-1)\n    #         print(img.shape)\n        return img","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"test_ids = pd.read_csv('../input/aptos2019-blindness-detection/test.csv')\ntest_ids = np.squeeze(test_ids.values)\n\ntransform1 = transforms.Compose([\n                trim(),\n                cropTo4_3(),\n                transforms.Resize((288, 384)),\n                transforms.ToTensor(),\n                transforms.Normalize(mean=[0.384, 0.258, 0.174], std=[0.124, 0.089, 0.094]),\n            ])\n\ntransform2 = transforms.Compose([\n                transforms.Resize((280,280)),\n                transforms.CenterCrop(256),\n                transforms.ToTensor(),\n                transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n            ])\n\n\nnet1 = ThreeStage_Model()\nnet1.load_state_dict(torch.load(\"../input/weights/0.926_B4_3stage_5epoch_320finetune.pkl\"))\nnet1 = net1.to(device)\nnet1.eval()\n\nnet2 = backboneNet_efficient()\nnet2.load_state_dict(torch.load(\"../input/weights/1.pth\", map_location='cpu'))\nnet2 = net2.to(device)\nnet2.eval()\n\nnet3 = backboneNet_efficient()\nnet3.load_state_dict(torch.load(\"../input/weights/2.pth\", map_location='cpu'))\nnet3 = net3.to(device)\nnet3.eval()\n\n# net4 = backboneNet_efficient()\n# net4.load_state_dict(torch.load(\"../input/weights/3.pth\", map_location='cpu'))\n# net4 = net4.to(device)\n# net4.eval()\n\nnet5 = backboneNet_efficient()\nnet5.load_state_dict(torch.load(\"../input/weights/0.929292_4\", map_location='cpu'))\nnet5 = net5.to(device)\nnet5.eval()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission = []\nthrs = [0.7, 1.5, 2.5, 3.5]\nwith torch.no_grad():\n    for i, idx in enumerate(test_ids):\n        print(i)\n        image_name = \"../input/aptos2019-blindness-detection/test_images/{}.png\".format(idx)\n        img1 = Image.open(image_name).convert('RGB')\n        img1 = transform1(img1).unsqueeze(0).to(device)\n        \n        img2 = cv2.imread(image_name)\n        img2 = crop_image_from_gray(img2)\n        img2 = Image.fromarray(cv2.cvtColor(img2,cv2.COLOR_BGR2RGB))\n        img2 = transform2(img2).unsqueeze(0).to(device)\n        \n        # model 1\n        _, r_out, _ = net1(img1)\n        pred1 = int(regress2class(r_out.data.squeeze(1)))\n        \n        # model 2\n        rg_outputs, cls_outputs, ord_outputs = net2(img2)\n        rg_outputs = torch.sigmoid(rg_outputs) * 4.5\n        \n        cls_softmax = torch.nn.Softmax(dim=1)\n        cls_outputs = cls_softmax(cls_outputs)\n        _, cls_preds = torch.max(cls_outputs, 1)\n        cls_predict = cls_preds.cpu().numpy()\n        \n        ord_outputs = torch.sigmoid(ord_outputs)\n        rg_outputs = rg_outputs.unsqueeze(1)                    \n        rg_outputs[rg_outputs < thrs[0]] = 0\n        rg_outputs[(rg_outputs >= thrs[0]) & (rg_outputs < thrs[1])] = 1\n        rg_outputs[(rg_outputs >= thrs[1]) & (rg_outputs < thrs[2])] = 2\n        rg_outputs[(rg_outputs >= thrs[2]) & (rg_outputs < thrs[3])] = 3\n        rg_outputs[rg_outputs >= thrs[3]] = 4                                           \n        rg_preds = rg_outputs.tolist()\n        rg_predict = rg_preds[0][0]\n\n        ord_outputs[ord_outputs >= 0.5] = 1\n        ord_outputs[ord_outputs < 0.5] = 0\n        ord_predict = sum(ord_outputs[0].cpu().numpy())\n        \n        pred2 = int(round((rg_predict[0] + cls_predict[0] + ord_predict) / 3.))\n        \n        # model 3\n        rg_outputs, cls_outputs, ord_outputs = net3(img2)\n        rg_outputs = torch.sigmoid(rg_outputs) * 4.5\n        \n        cls_softmax = torch.nn.Softmax(dim=1)\n        cls_outputs = cls_softmax(cls_outputs)\n        _, cls_preds = torch.max(cls_outputs, 1)\n        cls_predict = cls_preds.cpu().numpy()\n        \n        ord_outputs = torch.sigmoid(ord_outputs)\n        rg_outputs = rg_outputs.unsqueeze(1)                    \n        rg_outputs[rg_outputs < thrs[0]] = 0\n        rg_outputs[(rg_outputs >= thrs[0]) & (rg_outputs < thrs[1])] = 1\n        rg_outputs[(rg_outputs >= thrs[1]) & (rg_outputs < thrs[2])] = 2\n        rg_outputs[(rg_outputs >= thrs[2]) & (rg_outputs < thrs[3])] = 3\n        rg_outputs[rg_outputs >= thrs[3]] = 4                                           \n        rg_preds = rg_outputs.tolist()\n        rg_predict = rg_preds[0][0]\n\n        ord_outputs[ord_outputs >= 0.5] = 1\n        ord_outputs[ord_outputs < 0.5] = 0\n        ord_predict = sum(ord_outputs[0].cpu().numpy())\n        \n        pred3 = int(round((rg_predict[0] + cls_predict[0] + ord_predict) / 3.))\n        \n#         # model 4\n#         rg_outputs, cls_outputs, ord_outputs = net4(img2)\n#         rg_outputs = torch.sigmoid(rg_outputs) * 4.5\n        \n#         cls_softmax = torch.nn.Softmax(dim=1)\n#         cls_outputs = cls_softmax(cls_outputs)\n#         _, cls_preds = torch.max(cls_outputs, 1)\n#         cls_predict = cls_preds.cpu().numpy()\n        \n#         ord_outputs = torch.sigmoid(ord_outputs)\n#         rg_outputs = rg_outputs.unsqueeze(1)                    \n#         rg_outputs[rg_outputs < thrs[0]] = 0\n#         rg_outputs[(rg_outputs >= thrs[0]) & (rg_outputs < thrs[1])] = 1\n#         rg_outputs[(rg_outputs >= thrs[1]) & (rg_outputs < thrs[2])] = 2\n#         rg_outputs[(rg_outputs >= thrs[2]) & (rg_outputs < thrs[3])] = 3\n#         rg_outputs[rg_outputs >= thrs[3]] = 4                                           \n#         rg_preds = rg_outputs.tolist()\n#         rg_predict = rg_preds[0][0]\n\n#         ord_outputs[ord_outputs >= 0.5] = 1\n#         ord_outputs[ord_outputs < 0.5] = 0\n#         ord_predict = sum(ord_outputs[0].cpu().numpy())\n        \n#         pred4 = int(round((rg_predict[0] + cls_predict[0] + ord_predict) / 3.))\n        \n        # model 5\n        rg_outputs, cls_outputs, ord_outputs = net5(img2)\n        rg_outputs = torch.sigmoid(rg_outputs) * 4.5\n        \n        cls_softmax = torch.nn.Softmax(dim=1)\n        cls_outputs = cls_softmax(cls_outputs)\n        _, cls_preds = torch.max(cls_outputs, 1)\n        cls_predict = cls_preds.cpu().numpy()\n        \n        ord_outputs = torch.sigmoid(ord_outputs)\n        rg_outputs = rg_outputs.unsqueeze(1)                    \n        rg_outputs[rg_outputs < thrs[0]] = 0\n        rg_outputs[(rg_outputs >= thrs[0]) & (rg_outputs < thrs[1])] = 1\n        rg_outputs[(rg_outputs >= thrs[1]) & (rg_outputs < thrs[2])] = 2\n        rg_outputs[(rg_outputs >= thrs[2]) & (rg_outputs < thrs[3])] = 3\n        rg_outputs[rg_outputs >= thrs[3]] = 4                                           \n        rg_preds = rg_outputs.tolist()\n        rg_predict = rg_preds[0][0]\n\n        ord_outputs[ord_outputs >= 0.5] = 1\n        ord_outputs[ord_outputs < 0.5] = 0\n        ord_predict = sum(ord_outputs[0].cpu().numpy())\n        \n        pred5 = int(round((rg_predict[0] + cls_predict[0] + ord_predict) / 3.))\n        \n#         P = int(round((pred1 + pred2 + pred3 + pred4 + pred5) / 5.))\n        P = int(round((pred1 + pred2 + pred3 + pred5) / 4.))\n        submission.append([idx, P])\n\nsubmission = np.array(submission)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"df = pd.DataFrame(submission, columns=[\"id_code\", \"diagnosis\"])\ndf.to_csv(\"submission.csv\", index=False)","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}