{"cells":[{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"from PIL import Image\nimport math\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader, Subset, TensorDataset\nfrom sklearn.model_selection import train_test_split\nfrom tqdm import notebook\nimport torchvision\nfrom torchvision import transforms\nfrom torchvision import models\nfrom collections import Counter\nfrom pathlib import Path\nfrom sklearn.metrics import confusion_matrix, recall_score\nimport seaborn as sn\nimport pyarrow.parquet as pq\nfrom skimage.filters import threshold_otsu\nfrom skimage.transform import AffineTransform, SimilarityTransform, warp, resize","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_test = pd.read_csv('/kaggle/input/bengaliai-cv19/test.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def thresh(t):\n    t = t.clone().detach()\n    t.mul_(-1)\n    nn.functional.threshold_(t, -200, -255)\n    t.mul_(-1)\n    return t\ndef make_tensordataset_from_dfs(parquet_locs, label_loc=None):\n    ids = []\n    X = []\n    for parquet_loc in parquet_locs:\n        df = pd.read_parquet(parquet_loc)\n        ids.extend(df.image_id.tolist())\n        x = df.iloc[:, 1:].to_numpy(dtype=np.uint8)\n        del df\n        X.append(x)\n    X = np.vstack(X)\n    X = X.reshape(-1, 1, 137, 236)\n    X = torch.from_numpy(X)\n#     thresh(X)\n    ids = dict((s,i) for (i,s) in enumerate(ids))\n    if label_loc is None:\n        return TensorDataset(X)\n    else:\n        graphemes = torch.zeros(X.shape[0], dtype=torch.long)\n        vowel_diacs = torch.zeros(X.shape[0], dtype=torch.long)\n        consonant_diacs = torch.zeros(X.shape[0], dtype=torch.long)\n        lbl_df = pd.read_csv(label_loc)\n        for row in lbl_df.itertuples():\n            if row.image_id not in ids:\n                continue\n            idx = ids[row.image_id]\n            graphemes[idx] = row.grapheme_root\n            vowel_diacs[idx] = row.vowel_diacritic\n            consonant_diacs[idx] = row.consonant_diacritic\n        return TensorDataset(X, graphemes, vowel_diacs, consonant_diacs)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class DatasetWithImageTransforms(Dataset):\n    def __init__(self, ds, transforms):\n        super(DatasetWithImageTransforms, self).__init__()\n        self.ds = ds\n        self.tr = transforms\n        self.nt = len(self.ds[0])\n        self.ln = len(self.ds)\n        \n    def __getitem__(self, index):\n        img, *rest = self.ds[index]\n        img = self.tr(img)\n        return (img,) + tuple(rest)\n    \n    def __len__(self):\n        return self.ln","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Returns binary image\ndef thresh(img):\n    thresh_val = int(threshold_otsu(img))\n    img = (img > thresh_val)\n    return img\n\n# For binary image\ndef bounding_box(img):\n    img = thresh(img).astype(np.uint8)\n    # find the min value of each column\n    col_min_val = np.min(img, axis=0)\n    # find the min value of each row\n    row_min_val = np.min(img, axis=1)\n    # argwhere finds the non-zero elements we want to find the zero elements (zeros are part of character)\n    col = np.argwhere(1 - col_min_val).flatten()\n    row = np.argwhere(1 - row_min_val).flatten()\n    return row.min(), row.max(), col.min(), col.max()\n\ndef scale_to_bb(img):\n    height = img.shape[0]\n    width = img.shape[1]\n    t, b, l, r = bounding_box(img)\n    box_width = r - l\n    box_height = b - t\n    t, l = max(0, t - 10), max(0, l - 10)\n    b, r = min(height, b + 10), min(width, r + 10)\n#     print(l, r, t, b)\n    img = resize(img[t:b, l:r], output_shape=(256, 256), preserve_range=True, order=3, cval=1.0)\n    return img\n\ndef random_scale(img):\n    height = img.shape[0]\n    width = img.shape[1]\n    t, b, l, r = bounding_box(img)\n    box_width = r - l\n    box_height = b - t\n    max_width_scale = (box_width + min(l, width - r)) / box_width\n    max_height_scale = (box_height + min(t, height - b)) / box_height\n    max_scale = min(max_width_scale, max_height_scale)\n    min_scale = min(1.0, 0.25 * max((height / box_height), (width / box_width)))\n    scale = random.uniform(min_scale, max_scale)\n    tfm = SimilarityTransform(\n        scale=(scale, scale),\n    )\n    img = warp(img, tfm.inverse, cval=1.0, order=3)\n    return img\n\ndef random_translate(img):\n    height = img.shape[0]\n    width = img.shape[1]\n    t, b, l, r = bounding_box(img)\n    box_width = r - l\n    box_height = b - t\n    translate_height = random.uniform(-t, height - b)\n    translate_width = random.uniform(-l, width - r)\n    tfm = SimilarityTransform(\n        translation=(translate_width, translate_height),\n    )\n    img = warp(img, tfm.inverse, cval=1.0, order=3)\n    return img\n\ndef random_rotate_and_shear(img):\n    max_theta = math.pi / 16\n    theta = random.uniform(-max_theta, max_theta)\n    max_shear_theta = math.pi / 8\n    shear_theta = random.uniform(-max_shear_theta, max_shear_theta)\n    tfm = AffineTransform(rotation=theta, shear=shear_theta)\n    img = warp(img, tfm.inverse, cval=1.0, order=3)\n    return img\n\ndef invert_color(t):\n    t.mul_(-1)\n    t.add_(255)\n    return t\n\ndef affine_transforms(img):\n    img = img.reshape(137, 236).numpy()\n    img = thresh(img).astype(np.float32)\n#     img = random_translate(random_scale(random_rotate_and_shear(img)))\n    img = random_translate(random_scale(img))\n    img = img.reshape(1, 137, 236)\n    return torch.from_numpy(img)\n\ndef tfms(img):\n    img = img.reshape(137, 236).numpy()\n    img = thresh(img).astype(np.float32)\n    img = scale_to_bb(img)\n    img = img.reshape(1, 256, 256)\n    return torch.from_numpy(img)\n\ndef va_tfms(img):\n    img = img.reshape(137, 236).numpy()\n    img = thresh(img).astype(np.float32)\n    img = img.reshape(1, 137, 236)\n    return torch.from_numpy(img)\n\naffine_transforms = transforms.Lambda(affine_transforms)\nmult = transforms.Lambda(lambda img: img * 255)\nto_float = transforms.Lambda(lambda img: img.float())\ninvert_color = transforms.Lambda(invert_color)\ntfms = transforms.Compose([\n#     transforms.RandomApply([\n        tfms,\n#         mult,\n#     ], p=0.90),\n    to_float,\n])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"n_graphemes, n_vowel_diacs, n_consonant_diacs = 168, 11, 7","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class MultiTaskNN(nn.Module):\n    def __init__(self, base, task_predictors):\n        super(MultiTaskNN, self).__init__()\n        self.base = base\n        self.task_predictors = nn.ModuleList(task_predictors)\n        \n    def freeze(self):\n        for p in self.base.parameters():\n            p.requires_grad = False\n        \n    def unfreeze(self):\n        for p in self.base.parameters():\n            p.requires_grad = True\n        \n    def forward(self, x):\n        features = self.base(x)\n        preds = [predictor(features) for predictor in self.task_predictors]\n        return preds","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!ls /kaggle/input/","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_model(name, num_tasks):\n    base = torch.jit.load(name + '-base.trace')\n    task_predictors = [torch.jit.load(name + '-task-predictor-{}.trace'.format(i)) for i in range(num_tasks)]\n    return MultiTaskNN(base, task_predictors)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = load_model('/kaggle/input/bhgd-post-exp/r18-post-exp-1', 3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# # base, feature_size = models.resnet152(pretrained=False), 2048\n# # base.fc = nn.Identity()\n# # conv1 = nn.Conv2d(3, 96, kernel_size=(3, 3), stride=(2, 2), bias=False)\n# # conv1.weight.data = torch.sum(base.conv1.weight.data, dim=1, keepdim=True)\n# # base.conv1 = conv1\n\n# base = pretrainedmodels.__dict__['se_resnext101_32x4d'](pretrained=None)\n# base.avg_pool = nn.AdaptiveAvgPool2d((1, 1))\n# base.last_linear = nn.Identity()\n# feature_size = 2048\n# conv1 = nn.Conv2d(1, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)\n# conv1.weight.data = torch.sum(base.layer0.conv1.weight.data, dim=1, keepdim=True)\n# base.layer0.conv1 = conv1\n\n# # base = pretrainedmodels.__dict__['dpn107']()\n# # # base.avg_pool = nn.AdaptiveAvgPool2d((1, 1))\n# # base.last_linear = nn.Identity()\n# # feature_size = 2688\n# # conv = nn.Conv2d(1, 128, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)\n# # conv.weight.data = torch.sum(base.features.conv1_1.conv.weight.data, dim=1, keepdim=True)\n# # base.features.conv1_1.conv = conv\n\n# # base = pretrainedmodels.__dict__['pnasnet5large'](num_classes=1000)\n# # base.avg_pool = nn.AdaptiveAvgPool2d((1, 1))\n# # base.last_linear = nn.Identity()\n# # base.dropout = nn.Identity()\n# # feature_size = 4320\n# # conv = nn.Conv2d(1, 96, kernel_size=(3, 3), stride=(2, 2), bias=False)\n# # conv.weight.data = torch.sum(base.conv_0.conv.weight.data, dim=1, keepdim=True)\n# # base.conv_0.conv = conv\n\n# n_classes_tasks = [n_graphemes, n_vowel_diacs, n_consonant_diacs]\n# # depth_tasks = [2, 1, 1]\n# # task_predictors = [\n# #     make_ff_predictor(feature_size, 512, n_classes, depth) \n# #     for n_classes, depth in zip(n_classes_tasks, depth_tasks)\n# # ]\n# task_predictors = [nn.Linear(feature_size, n_classes, bias=False) for n_classes in n_classes_tasks]\n\n# model = MultiTaskNN(base, task_predictors).to(device)\n\n# model.load_state_dict(torch.load('/kaggle/input/bhgd-seresnext-101/seresnext101-itstrat-sgd-12-1e1-12-1e0-16-8.pth', map_location=device))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = model.to(device)\nmodel.eval();","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"results = []","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with torch.no_grad():\n    for i in range(4):\n        te_ds = make_tensordataset_from_dfs(\n            ['/kaggle/input/bengaliai-cv19' + '/test_image_data_{}.parquet'.format(i)]\n        )\n        # TTA\n        te_ds = DatasetWithImageTransforms(te_ds, tfms)\n        num_tta = 1\n        te_dl = DataLoader(te_ds, batch_size=256, num_workers=2, pin_memory=True)\n        tta_results = [[] for i in range(num_tta)]\n        for i in range(num_tta):\n            for imgs, in te_dl:\n                imgs = imgs.to(device)\n#                 imgs = imgs / 255.0\n                g_pred, v_pred, c_pred, *rest = model(imgs)\n                tta_results[i].append([g_pred, v_pred, c_pred])\n        \n        for i in range(len(te_dl)):\n            g_preds = [results[i][0] for results in tta_results]\n            v_preds = [results[i][1] for results in tta_results]\n            c_preds = [results[i][2] for results in tta_results]\n            g_pred = torch.stack(g_preds).mean(dim=0)\n            v_pred = torch.stack(v_preds).mean(dim=0)\n            c_pred = torch.stack(c_preds).mean(dim=0)\n            g_pred = g_pred.argmax(1).tolist()\n            v_pred = v_pred.argmax(1).tolist()\n            c_pred = c_pred.argmax(1).tolist()\n            \n            for g, v, c in zip(g_pred, v_pred, c_pred):\n                results.extend([c, 0, v])\n        del imgs\n        del te_ds\n        del te_dl\n        del tta_results","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"del model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_df = pd.read_csv('/kaggle/input/bengaliai-cv19' + '/sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_df['target'] = results","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_df.to_csv('./submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_df","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}