{"cells":[{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"!pip install /kaggle/input/timm-model/timm-0.3.2-py3-none-any.whl","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import pandas as pd\nimport cv2\nimport numpy as np\nfrom tqdm.auto import tqdm\nfrom matplotlib import pyplot as plt\nimport time\nimport pyarrow.parquet as pq","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_SIZE=128\nN_CHANNELS=1\ndef resize(df, size=128, need_progress_bar=True):\n    resized = {}\n    resize_size=128\n    if need_progress_bar:\n        for i in range(df.shape[0]):\n            image=df.loc[df.index[i]].values.reshape(137,236)\n            _, thresh = cv2.threshold(image, 30, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) #  \n            contours, _ = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)[-2:]\n\n            idx = 0 \n            ls_xmin = []\n            ls_ymin = []\n            ls_xmax = []\n            ls_ymax = []\n            for cnt in contours:\n                idx += 1\n                x,y,w,h = cv2.boundingRect(cnt)\n                ls_xmin.append(x)\n                ls_ymin.append(y)\n                ls_xmax.append(x + w)\n                ls_ymax.append(y + h)\n            xmin = min(ls_xmin)\n            ymin = min(ls_ymin)\n            xmax = max(ls_xmax)\n            ymax = max(ls_ymax)\n\n            roi = image[ymin:ymax,xmin:xmax]\n            #roi = image\n            resized_roi = cv2.resize(roi, (resize_size, resize_size),interpolation=cv2.INTER_AREA)\n            resized[df.index[i]] = resized_roi.reshape(-1)\n    resized = pd.DataFrame(resized).T\n    return resized","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch\nimport numpy as np\nimport tqdm\nimport csv\nimport os\nimport cv2\nimport pandas as pd\nfrom timm.models import create_model\nimport torch.autograd.profiler as profiler\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision.datasets import ImageFolder\nfrom torchvision.transforms import transforms\nfrom PIL import Image\n\n\nclass BengaliDataset(Dataset):\n  def __init__(self, label_csv, unique_csv, train_folder, parquet_path, transforms, cache=True, test=True):\n    self.label_csv = label_csv\n    self.unique_csv = unique_csv\n    self.train_folder = train_folder\n    self.parquet_path = parquet_path\n    self.label = pd.read_csv(self.label_csv)\n    self.label = self.label[self.label['component']=='grapheme_root']\n    self.label = self.label.reset_index(drop=True)\n    #self.label = pd.read_csv(self.label_csv)\n    unique_df = pd.read_csv(self.unique_csv)\n\n    self.names = self.label['image_id'].values\n    self.uniques = unique_df.grapheme.unique()\n    self.transforms = transforms\n    self.img = [None] * self.label.shape[0]\n    self.test = test\n\n    if cache:\n      self.cache_images()\n\n  def cache_images(self):\n    count = 0\n    root = './test_graphemes/'\n#     for ii in range(4):\n#         p = pd.read_parquet(f'/kaggle/input/bengaliai-cv19/test_image_data_{ii}.parquet').drop(['image_id'], axis=1)#pd.read_parquet('/kaggle/input/bengaliai-cv19/test_image_data_0.parquet')\n#     #     p2 = pq.read_pandas('/kaggle/input/bengaliai-cv19/train_image_data_1.parquet').to_pandas()#pd.read_parquet('/kaggle/input/bengaliai-cv19/test_image_data_1.parquet')\n#     #     p3 = pq.read_pandas('/kaggle/input/bengaliai-cv19/train_image_data_2.parquet').to_pandas()#pd.read_parquet('/kaggle/input/bengaliai-cv19/test_image_data_2.parquet')\n#     #     p4 = pq.read_pandas('/kaggle/input/bengaliai-cv19/train_image_data_3.parquet').to_pandas()#pd.read_parquet('/kaggle/input/bengaliai-cv19/test_image_data_3.parquet')\n#     #     self.test_df = pd.concat([p1, p2, p3, p4]).reset_index(drop=True).drop(['image_id'], axis=1)\n\n\n#         pbar = tqdm.tqdm(range(p.shape[0]), position=0, leave=True)\n#         pbar.set_description('writing images...')\n#         for i, _ in enumerate(pbar):\n#           name = self.names[count]\n#           #self.img[count] = self.transforms(resize(p.iloc[[i]]).values.astype(np.uint8).reshape(-1).reshape(IMG_SIZE, IMG_SIZE))\n#           cv2.imwrite(root+name+'.jpg', resize(p.iloc[[i]]).values.reshape(-1).reshape(IMG_SIZE, IMG_SIZE).astype(np.uint8))\n#           count += 1\n        \n#         del p\n\n    self.p = p = pd.read_parquet(self.parquet_path).drop(['image_id'], axis=1)\n    \n#     count = 0\n#     pbar = tqdm.tqdm(range(self.label.shape[0]))\n#     pbar.set_description('caching images...')\n#     for i, _ in enumerate(pbar):\n#         name = self.names[i]\n#         img = Image.open(os.path.join('./test_graphemes/', name+'.jpg'))\n#         self.img[i] = self.transforms(img)\n\n  def load_image(self, idx):\n    img = resize(self.p.iloc[[idx]]).values.reshape(-1).reshape(IMG_SIZE, IMG_SIZE).astype(np.uint8)\n    return self.transforms(img)\n        \n    img = self.img[idx]\n    if img is None:\n      #name = self.label.loc[idx]['image_id']\n      img = resize(p.iloc[[i]]).values.reshape(-1).reshape(IMG_SIZE, IMG_SIZE).astype(np.uint8)\n      #img = Image.open(os.path.join(self.train_folder, name+'.jpg'))\n      return self.transforms(img)\n    else:\n      return self.transforms(img)\n\n  def __getitem__(self, idx):\n    if not self.test:\n      img = self.load_image(idx)\n      #img = self.img[idx]\n      root = self.label.loc[idx]['grapheme_root']\n      consonant = self.label.loc[idx]['consonant_diacritic']\n      vowel = self.label.loc[idx]['vowel_diacritic']\n      unique = np.where(self.uniques == self.label.grapheme[idx])[0][0]\n      return transforms.ToTensor()(img), root, consonant, vowel, unique\n    else:\n      img = self.load_image(idx)\n      #img = self.img[idx]\n      root = 0\n      consonant = 0\n      vowel = 0\n      unique = 0\n      return transforms.ToTensor()(img), root, consonant, vowel, unique\n\n  def __len__(self):\n    return self.p.shape[0]\n\ndef postprocess(preds, num_classes, EXP = -1.2):\n    p0 = np.argmax(preds,axis=1)\n\n    s = pd.Series(p0)\n    vc = s.value_counts().sort_index()\n    df = pd.DataFrame({'a':np.arange(num_classes),'b':np.ones(num_classes)})\n    df.b = df.a.map(vc)\n    df.fillna(df.b.min(),inplace=True)\n    mat1 = np.diag(df.b.astype('float32')**EXP)\n\n    p0 = np.argmax(preds.dot(mat1), axis=1)\n    \n    return p0\n\nclass Tester:\n    def __init__(self,\n               dataset_path='./drive/MyDrive/datasets/car classification/train_data', \n               batch_size=1, \n               model_name='tf_efficientnet_b3_ns', \n               test_csv='./train_labels.csv', \n               unique_csv='./train_labels.csv',\n               output_dir='../drive/MyDrive/ckpt/grapheme/submission.csv',\n               ckpt='../drive/MyDrive/ckpt/grapheme/20.pth'):\n\n        # initialize attributes\n        self.dataset_path = dataset_path\n        self.batch_size = batch_size\n        self.model_name = model_name\n        self.test_csv = test_csv\n        self.unique_csv = unique_csv\n        self.output_dir = output_dir\n        self.ckpt = ckpt\n        \n        if model_name == 'tf_efficientnet_b0_ns':\n            self.input_size = (224, 224)\n        elif model_name == 'tf_efficientnet_b2_ns':\n            self.input_size = (260, 260)\n        elif model_name == 'tf_efficientnet_b3_ns':\n            self.input_size = (300, 300)\n        elif model_name == 'tf_efficientnet_b4_ns':\n            self.input_size = (380, 380)\n        elif model_name == 'tf_efficientnet_b6_ns':\n            self.input_size = (528, 528)\n        else:\n            raise Exception('non-valid model name')\n        \n        # Compose transforms\n        transform = []\n        transform += [transforms.ToPILImage()]\n        transform += [transforms.Resize(self.input_size)]\n        self.transform = transforms.Compose(transform)\n\n       \n        self.device = torch.device('cuda')\n        self.model_root = create_model(self.model_name, pretrained=False, num_classes=168).to(self.device)\n        self.model_consonant = create_model(self.model_name, pretrained=False, num_classes=8).to(self.device)\n        self.model_vowel = create_model(self.model_name, pretrained=False, num_classes=11).to(self.device)\n\n        ckpt = torch.load(self.ckpt)\n        self.model_root.load_state_dict(ckpt['model_root_state_dict'])\n        self.model_consonant.load_state_dict(ckpt['model_consonant_state_dict'])\n        self.model_vowel.load_state_dict(ckpt['model_vowel_state_dict'])\n\n    def test(self):\n        output_roots = []\n        output_consonants = []\n        output_vowels = []\n        count = 0\n        for ii in range(4):\n            self.test_dataset = BengaliDataset(self.test_csv, self.unique_csv, self.dataset_path, f'/kaggle/input/bengaliai-cv19/test_image_data_{ii}.parquet', self.transform, cache=True)\n            self.names = self.test_dataset.names\n            self.test_dataloader = DataLoader(self.test_dataset, batch_size=self.batch_size, num_workers=0, shuffle=False)\n            \n            pbar = tqdm.tqdm(self.test_dataloader)\n            pbar.set_description('testing process')\n            self.model_root.eval()\n            self.model_consonant.eval()\n            self.model_vowel.eval()\n\n            with torch.no_grad():\n                for it, data in enumerate(pbar):\n                    inputs = data[0].to(self.device)\n                    inputs = inputs.repeat(1, 3, 1, 1)\n                    roots = data[1].to(self.device).long()\n                    consonants = data[2].to(self.device).long()\n                    vowels = data[3].to(self.device).long()\n                    uniques = data[4].to(self.device).long()\n\n                    root_preds = self.model_root(inputs)\n                    self.model_root.zero_grad()\n\n                    consonant_preds = self.model_consonant(inputs)\n                    self.model_consonant.zero_grad()\n\n                    vowel_preds = self.model_vowel(inputs)\n                    self.model_vowel.zero_grad()\n                    # Try setting root EXP to -0.9, vowel EXP to -1.1 and consonant EXP to -0.6.\n                    # 1: -1.2, -0.5, -1.2\n                    # 2: -0.9, -0.6, -1.1\n                    # 3: -0.9, -0.6, -0.9\n                    # 4: -0.6, -0.6, -1.1\n                    root_preds = postprocess(torch.nn.Softmax(1)(root_preds).cpu().numpy(), 168, -0.6)\n                    consonant_preds = postprocess(torch.nn.Softmax(1)(consonant_preds).cpu().numpy(), 8, -0.6)\n                    vowel_preds = postprocess(torch.nn.Softmax(1)(vowel_preds).cpu().numpy(), 11, -1.1)\n\n\n                    \n#                     for index in range(inputs.shape[0]):\n#                         output_roots.append(root_preds.argmax(-1)[index].item())\n#                         output_consonants.append(consonant_preds.argmax(-1)[index].item())\n#                         output_vowels.append(vowel_preds.argmax(-1)[index].item())\n            \n                    \n                    for index in range(inputs.shape[0]):\n                        output_roots.append(root_preds[index].item())\n                        output_consonants.append(consonant_preds[index].item())\n                        output_vowels.append(vowel_preds[index].item())\n            \n            del self.test_dataset.p\n            del self.test_dataset\n            del self.test_dataloader\n\n        row_id, target = [], []\n        for iid, r, c, v in zip(self.names, output_roots, output_consonants, output_vowels):\n            row_id.append(iid + '_grapheme_root')\n            target.append(int(r))\n            row_id.append(iid + '_vowel_diacritic')\n            target.append(int(v))\n            row_id.append(iid + '_consonant_diacritic')\n            target.append(int(c))\n            count += 1\n\n        sub_fn = self.output_dir\n        sub = pd.DataFrame({'row_id': row_id, 'target': target})\n        sub.to_csv(sub_fn, index=False)\n        print(f'Done wrote to {sub_fn}')\n\ntester = Tester(dataset_path='./test_graphemes', \n               batch_size=128, \n               model_name='tf_efficientnet_b2_ns', \n               test_csv='/kaggle/input/bengaliai-cv19/test.csv', \n               unique_csv='/kaggle/input/bengaliai-cv19/train.csv',\n               output_dir='./submission.csv',\n               ckpt='/kaggle/input/graphemesingle/27.pth'\n               )\ntester.test()","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}