{"cells":[{"metadata":{},"cell_type":"markdown","source":"## Thanks to [@Abhishek Thakur](https://www.kaggle.com/abhishek) youtube channel for this wonderful video and kernal.\n\n### [Bengali.AI: Handwritten Grapheme Classification Using PyTorch (Part-1)](https://www.youtube.com/watch?v=8J5Q4mEzRtY) \n\n### [Bengali.AI: Handwritten Grapheme Classification Using PyTorch (Part-2)](https://www.youtube.com/watch?v=uZalt-weQMM&t=3478s)\n\n![image.png](attachment:image.png)\n\n### Used model\n* ResNet34 \n","attachments":{"image.png":{"image/png":"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"}}},{"metadata":{"trusted":true},"cell_type":"code","source":"%%writefile create_folds.py\n\nimport pandas as pd\nfrom iterstrat.ml_stratifiers import MultilabelStratifiedKFold\n\nif __name__ == \"__main__\":\n    df = pd.read_csv(\"../input/train.csv\")\n    print(df.head())\n    df.loc[:, 'kfold'] = -1\n\n    df = df.sample(frac=1).reset_index(drop=True)\n\n    X = df.image_id.values\n    y = df[['grapheme_root', 'vowel_diacritic', 'consonant_diacritic']].values\n\n    mskf = MultilabelStratifiedKFold(n_splits=5)\n\n    for fold, (trn_, val_) in enumerate(mskf.split(X, y)):\n        print(\"TRAIN: \", trn_, \"VAL: \", val_)\n        df.loc[val_, \"kfold\"] = fold\n\n    print(df.kfold.value_counts())\n    df.to_csv(\"../input/train_folds.csv\", index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%writefile create_image_pickles.py\n\nimport pandas as pd\nimport joblib\nimport glob\nfrom tqdm import tqdm\n\nif __name__ == \"__main__\":\n    files = glob.glob(\"../input/train_*.parquet\")\n    for f in files:\n        df = pd.read_parquet(f, engine='fastparquet')\n        image_ids = df.image_id.values\n        df = df.drop(\"image_id\", axis=1)\n        image_array = df.values\n        for j, image_id in tqdm(enumerate(image_ids), total=len(image_ids)):\n            joblib.dump(image_array[j, :], f\"../input/image_pickles/{image_id}.pkl\")\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%writefile dataset.py\n\nimport pandas as pd\nimport albumentations\nimport joblib\nimport numpy as np\nimport torch\n\nfrom PIL import Image\n\nclass BengaliDatasetTrain:\n    def __init__(self, folds, img_height, img_width, mean, std):\n        df = pd.read_csv(\"../input/train_folds.csv\")\n        df = df[[\"image_id\", \"grapheme_root\", \"vowel_diacritic\", \"consonant_diacritic\", \"kfold\"]]\n\n        df = df[df.kfold.isin(folds)].reset_index(drop=True)\n        \n        self.image_ids = df.image_id.values\n        self.grapheme_root = df.grapheme_root.values\n        self.vowel_diacritic = df.vowel_diacritic.values\n        self.consonant_diacritic = df.consonant_diacritic.values\n\n        if len(folds) == 1:\n            self.aug = albumentations.Compose([\n                albumentations.Resize(img_height, img_width, always_apply=True),\n                albumentations.Normalize(mean, std, always_apply=True)\n            ])\n        else:\n            self.aug = albumentations.Compose([\n                albumentations.Resize(img_height, img_width, always_apply=True),\n                #albumentations.ShiftScaleRotate(shift_limit=0.0625,\n                #                                scale_limit=0.1, \n                #                                rotate_limit=5,\n                #                                p=0.9),\n                albumentations.Normalize(mean, std, always_apply=True)\n            ])\n\n\n    def __len__(self):\n        return len(self.image_ids)\n    \n    def __getitem__(self, item):\n        image = joblib.load(f\"../input/image_pickles/{self.image_ids[item]}.pkl\")\n        image = image.reshape(137, 236).astype(float)\n        image = Image.fromarray(image).convert(\"RGB\")\n        image = self.aug(image=np.array(image))[\"image\"]\n        image = np.transpose(image, (2, 0, 1)).astype(np.float32)\n\n        return {\n            \"image\": torch.tensor(image, dtype=torch.float),\n            \"grapheme_root\": torch.tensor(self.grapheme_root[item], dtype=torch.long),\n            \"vowel_diacritic\": torch.tensor(self.vowel_diacritic[item], dtype=torch.long),\n            \"consonant_diacritic\": torch.tensor(self.consonant_diacritic[item], dtype=torch.long)\n        }\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%writefile models.py\n\nimport pretrainedmodels\nimport torch.nn as nn\nfrom torch.nn import functional as F\n\nclass ResNet34(nn.Module):\n    def __init__(self, pretrained):\n        super(ResNet34, self).__init__()\n        if pretrained is True:\n            self.model = pretrainedmodels.__dict__[\"resnet34\"](pretrained=\"imagenet\")\n        else:\n            self.model = pretrainedmodels.__dict__[\"resnet34\"](pretrained=None)\n        \n        self.l0 = nn.Linear(512, 168)\n        self.l1 = nn.Linear(512, 11)\n        self.l2 = nn.Linear(512, 7)\n\n    def forward(self, x):\n        bs, _, _, _ = x.shape\n        x = self.model.features(x)\n        x = F.adaptive_avg_pool2d(x, 1).reshape(bs, -1)\n        l0 = self.l0(x)\n        l1 = self.l1(x)\n        l2 = self.l2(x)\n        return l0, l1, l2\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%writefile model_dispatcher.py\n\nimport models\n\nMODEL_DISPATCHER = {\n    \"resnet34\": models.ResNet34\n}  ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%writefile train.py\n\nimport os\nimport ast\nimport torch\nimport torch.nn as nn\nimport numpy as np\nimport sklearn.metrics\n\nfrom model_dispatcher import MODEL_DISPATCHER\nfrom dataset import BengaliDatasetTrain\nfrom tqdm import tqdm\nfrom pytorchtools import EarlyStopping\n\n\nDEVICE = \"cuda\"\nTRAINING_FOLDS_CSV = os.environ.get(\"TRAINING_FOLDS_CSV\")\n\nIMG_HEIGHT = int(os.environ.get(\"IMG_HEIGHT\"))\nIMG_WIDTH = int(os.environ.get(\"IMG_WIDTH\"))\nEPOCHS = int(os.environ.get(\"EPOCHS\"))\n\nTRAIN_BATCH_SIZE = int(os.environ.get(\"TRAIN_BATCH_SIZE\"))\nTEST_BATCH_SIZE = int(os.environ.get(\"TEST_BATCH_SIZE\"))\n\nMODEL_MEAN = ast.literal_eval(os.environ.get(\"MODEL_MEAN\"))\nMODEL_STD = ast.literal_eval(os.environ.get(\"MODEL_STD\"))\n\nTRAINING_FOLDS = ast.literal_eval(os.environ.get(\"TRAINING_FOLDS\"))\nVALIDATION_FOLDS = ast.literal_eval(os.environ.get(\"VALIDATION_FOLDS\"))\nBASE_MODEL = os.environ.get(\"BASE_MODEL\")\n\n\n\ndef macro_recall(pred_y, y, n_grapheme=168, n_vowel=11, n_consonant=7):\n    \n    pred_y = torch.split(pred_y, [n_grapheme, n_vowel, n_consonant], dim=1)\n    pred_labels = [torch.argmax(py, dim=1).cpu().numpy() for py in pred_y]\n\n    y = y.cpu().numpy()\n\n    recall_grapheme = sklearn.metrics.recall_score(pred_labels[0], y[:, 0], average='macro')\n    recall_vowel = sklearn.metrics.recall_score(pred_labels[1], y[:, 1], average='macro')\n    recall_consonant = sklearn.metrics.recall_score(pred_labels[2], y[:, 2], average='macro')\n    scores = [recall_grapheme, recall_vowel, recall_consonant]\n    final_score = np.average(scores, weights=[2, 1, 1])\n    print(f'recall: grapheme {recall_grapheme}, vowel {recall_vowel}, consonant {recall_consonant}, 'f'total {final_score}, y {y.shape}')\n    \n    return final_score\n\n\ndef loss_fn(outputs, targets):\n    o1, o2, o3 = outputs\n    t1, t2, t3 = targets\n    l1 = nn.CrossEntropyLoss()(o1, t1)\n    l2 = nn.CrossEntropyLoss()(o2, t2)\n    l3 = nn.CrossEntropyLoss()(o3, t3)\n    return (l1 + l2 + l3) / 3\n\n\n\ndef train(dataset, data_loader, model, optimizer):\n    model.train()\n    final_loss = 0\n    counter = 0\n    final_outputs = []\n    final_targets = []\n\n    for bi, d in tqdm(enumerate(data_loader), total=int(len(dataset)/data_loader.batch_size)):\n        counter = counter + 1\n        image = d[\"image\"]\n        grapheme_root = d[\"grapheme_root\"]\n        vowel_diacritic = d[\"vowel_diacritic\"]\n        consonant_diacritic = d[\"consonant_diacritic\"]\n\n        image = image.to(DEVICE, dtype=torch.float)\n        grapheme_root = grapheme_root.to(DEVICE, dtype=torch.long)\n        vowel_diacritic = vowel_diacritic.to(DEVICE, dtype=torch.long)\n        consonant_diacritic = consonant_diacritic.to(DEVICE, dtype=torch.long)\n        \n        print(image.shape)\n\n        optimizer.zero_grad()\n        outputs = model(image)\n        targets = (grapheme_root, vowel_diacritic, consonant_diacritic)\n        loss = loss_fn(outputs, targets)\n\n        loss.backward()\n        optimizer.step()\n\n        final_loss += loss\n\n        o1, o2, o3 = outputs\n        t1, t2, t3 = targets\n        final_outputs.append(torch.cat((o1,o2,o3), dim=1))\n        final_targets.append(torch.stack((t1,t2,t3), dim=1))\n\n        #if bi % 10 == 0:\n        #    break\n    final_outputs = torch.cat(final_outputs)\n    final_targets = torch.cat(final_targets)\n\n    print(\"=================Train=================\")\n    macro_recall_score = macro_recall(final_outputs, final_targets)\n    \n    return final_loss/counter , macro_recall_score\n\n\n\ndef evaluate(dataset, data_loader, model):\n    with torch.no_grad():\n        model.eval()\n        final_loss = 0\n        counter = 0\n        final_outputs = []\n        final_targets = []\n        for bi, d in tqdm(enumerate(data_loader), total=int(len(dataset)/data_loader.batch_size)):\n            counter = counter + 1\n            image = d[\"image\"]\n            grapheme_root = d[\"grapheme_root\"]\n            vowel_diacritic = d[\"vowel_diacritic\"]\n            consonant_diacritic = d[\"consonant_diacritic\"]\n\n            image = image.to(DEVICE, dtype=torch.float)\n            grapheme_root = grapheme_root.to(DEVICE, dtype=torch.long)\n            vowel_diacritic = vowel_diacritic.to(DEVICE, dtype=torch.long)\n            consonant_diacritic = consonant_diacritic.to(DEVICE, dtype=torch.long)\n\n            outputs = model(image)\n            targets = (grapheme_root, vowel_diacritic, consonant_diacritic)\n            loss = loss_fn(outputs, targets)\n            final_loss += loss\n\n            o1, o2, o3 = outputs\n            t1, t2, t3 = targets\n            #print(t1.shape)\n            final_outputs.append(torch.cat((o1,o2,o3), dim=1))\n            final_targets.append(torch.stack((t1,t2,t3), dim=1))\n        \n        final_outputs = torch.cat(final_outputs)\n        final_targets = torch.cat(final_targets)\n\n        print(\"=================Train=================\")\n        macro_recall_score = macro_recall(final_outputs, final_targets)\n\n    return final_loss/counter , macro_recall_score\n\n\n\ndef main():\n    model = MODEL_DISPATCHER[BASE_MODEL](pretrained=True)\n    model.to(DEVICE)\n\n    train_dataset = BengaliDatasetTrain(\n        folds=TRAINING_FOLDS,\n        img_height = IMG_HEIGHT,\n        img_width = IMG_WIDTH,\n        mean = MODEL_MEAN,\n        std = MODEL_STD\n    )\n\n    train_loader = torch.utils.data.DataLoader(\n        dataset=train_dataset,\n        batch_size= TRAIN_BATCH_SIZE,\n        shuffle=True,\n        num_workers=4\n    )\n\n    valid_dataset = BengaliDatasetTrain(\n        folds=VALIDATION_FOLDS,\n        img_height = IMG_HEIGHT,\n        img_width = IMG_WIDTH,\n        mean = MODEL_MEAN,\n        std = MODEL_STD\n    )\n\n    valid_loader = torch.utils.data.DataLoader(\n        dataset=valid_dataset,\n        batch_size= TEST_BATCH_SIZE,\n        shuffle=True,\n        num_workers=4\n    )\n\n    optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)\n    scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, \n                                                            mode=\"min\", \n                                                            patience=5, \n                                                            factor=0.3,verbose=True)\n\n    early_stopping = EarlyStopping(patience=5, verbose=True)\n\n    #if torch.cuda.device_count() > 1:\n    #    model = nn.DataParallel(model)\n\n    best_score = -1\n\n    print(\"FOLD : \", VALIDATION_FOLDS[0] )\n    \n    for epoch in range(1, EPOCHS+1):\n\n        train_loss, train_score = train(train_dataset,train_loader, model, optimizer)\n        val_loss, val_score = evaluate(valid_dataset, valid_loader, model)\n\n        scheduler.step(val_loss)\n\n        \n\n        if val_score > best_score:\n            best_score = val_score\n            torch.save(model.state_dict(), f\"{BASE_MODEL}_fold{VALIDATION_FOLDS[0]}.pth\")\n\n        epoch_len = len(str(EPOCHS))\n        print_msg = (f'[{epoch:>{epoch_len}}/{EPOCHS:>{epoch_len}}] ' +\n                     f'train_loss: {train_loss:.5f} ' +\n                     f'train_score: {train_score:.5f} ' +\n                     f'valid_loss: {val_loss:.5f} ' +\n                     f'valid_score: {val_score:.5f}'\n                    )\n        \n        print(print_msg)\n\n        early_stopping(val_score, model)\n        if early_stopping.early_stop:\n            print(\"Early stopping\")\n            break\n\n\nif __name__ == \"__main__\":\n    main()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%writefile run.sh\n\nexport IMG_HEIGHT=137\nexport IMG_WIDTH=236\nexport EPOCHS=50\nexport TRAIN_BATCH_SIZE=64\nexport TEST_BATCH_SIZE=64\nexport MODEL_MEAN=\"(0.485, 0.456, 0.406)\"\nexport MODEL_STD=\"(0.229, 0.224, 0.225)\"\nexport BASE_MODEL=\"resnet34\"\nexport TRAINING_FOLDS_CSV=\"../input/train_folds.csv\"\n\n\nexport TRAINING_FOLDS=\"(0,1,2,3)\"\nexport VALIDATION_FOLDS=\"(4,)\"\npython3 train.py\n\nexport TRAINING_FOLDS=\"(0,1,2,4)\"\nexport VALIDATION_FOLDS=\"(3,)\"\npython3 train.py\n\nexport TRAINING_FOLDS=\"(0,1,3,4)\"\nexport VALIDATION_FOLDS=\"(2,)\"\npython3 train.py\n\nexport TRAINING_FOLDS=\"(0,2,3,4)\"\nexport VALIDATION_FOLDS=\"(1,)\"\npython3 train.py\n\nexport TRAINING_FOLDS=\"(1,2,3,4)\"\nexport VALIDATION_FOLDS=\"(0,)\"\npython3 train.py\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Inference"},{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","trusted":true},"cell_type":"code","source":"import sys\npt_models = \"../input/pretrained-models/pretrained-models.pytorch-master/\"\nsys.path.insert(0, pt_models)\nimport pretrainedmodels","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#when internet is off\n# %%capture\n# !pip install /kaggle/input/output/albumentations-0.4.3/albumentations-0.4.3\n# !pip install /kaggle/input/output/imgaug-0.2.6/imgaug-0.2.6\n# !pip install /kaggle/input/output/opencv_python-4.2.0.32-cp36-cp36m-manylinux1_x86_64.whl\n\n#for internet when on\n#!pip install albumentations","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"import glob\nimport torch\nimport albumentations\nimport pandas as pd\nimport numpy as np\n\nfrom tqdm import tqdm\nfrom PIL import Image\nimport joblib\nimport torch.nn as nn\nfrom torch.nn import functional as F","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nMODEL_MEAN = (0.485, 0.456, 0.406)\nMODEL_STD = (0.229, 0.224, 0.225)\nIMG_HEIGHT = 137\nIMG_WIDTH = 236\nDEVICE=\"cuda\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class ResNet34(nn.Module):\n    def __init__(self, pretrained):\n        super(ResNet34, self).__init__()\n        if pretrained is True:\n            self.model = pretrainedmodels.__dict__[\"resnet34\"](pretrained=\"imagenet\")\n        else:\n            self.model = pretrainedmodels.__dict__[\"resnet34\"](pretrained=None)\n        \n        self.l0 = nn.Linear(512, 168)\n        self.l1 = nn.Linear(512, 11)\n        self.l2 = nn.Linear(512, 7)\n\n    def forward(self, x):\n        bs, _, _, _ = x.shape\n        x = self.model.features(x)\n        x = F.adaptive_avg_pool2d(x, 1).reshape(bs, -1)\n        l0 = self.l0(x)\n        l1 = self.l1(x)\n        l2 = self.l2(x)\n        return l0, l1, l2\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class BengaliDatasetTest:\n    def __init__(self, df, img_height, img_width, mean, std):\n        \n        self.image_ids = df.image_id.values\n        self.img_arr = df.iloc[:, 1:].values\n\n        self.aug = albumentations.Compose([\n            albumentations.Resize(img_height, img_width, always_apply=True),\n            albumentations.Normalize(mean, std, always_apply=True)\n        ])\n\n\n    def __len__(self):\n        return len(self.image_ids)\n    \n    def __getitem__(self, item):\n        image = self.img_arr[item, :]\n        img_id = self.image_ids[item]\n        \n        image = image.reshape(137, 236).astype(float)\n        image = Image.fromarray(image).convert(\"RGB\")\n        image = self.aug(image=np.array(image))[\"image\"]\n        image = np.transpose(image, (2, 0, 1)).astype(np.float32)\n        \n\n        return {\n            \"image\": torch.tensor(image, dtype=torch.float),\n            \"image_id\": img_id\n        }","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def model_predict():\n    g_pred, v_pred, c_pred = [], [], []\n    img_ids_list = [] \n    \n    for file_idx in range(4):\n        df = pd.read_parquet(f\"../input/bengaliai-cv19/test_image_data_{file_idx}.parquet\")\n\n        dataset = BengaliDatasetTest(df=df,\n                                    img_height=IMG_HEIGHT,\n                                    img_width=IMG_WIDTH,\n                                    mean=MODEL_MEAN,\n                                    std=MODEL_STD)\n\n        data_loader = torch.utils.data.DataLoader(\n            dataset=dataset,\n            batch_size= TEST_BATCH_SIZE,\n            shuffle=False,\n            num_workers=4\n        )\n\n        for bi, d in enumerate(data_loader):\n            image = d[\"image\"]\n            img_id = d[\"image_id\"]\n            image = image.to(DEVICE, dtype=torch.float)\n\n            g, v, c = model(image)\n            #g = np.argmax(g.cpu().detach().numpy(), axis=1)\n            #v = np.argmax(v.cpu().detach().numpy(), axis=1)\n            #c = np.argmax(c.cpu().detach().numpy(), axis=1)\n\n            for ii, imid in enumerate(img_id):\n                g_pred.append(g[ii].cpu().detach().numpy())\n                v_pred.append(v[ii].cpu().detach().numpy())\n                c_pred.append(c[ii].cpu().detach().numpy())\n                img_ids_list.append(imid)\n        \n    return g_pred, v_pred, c_pred, img_ids_list","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = ResNet34(pretrained=False)\nTEST_BATCH_SIZE = 32\n\nfinal_g_pred = []\nfinal_v_pred = []\nfinal_c_pred = []\nfinal_img_ids = []\n\nfor i in range(5):\n    model.load_state_dict(torch.load(f\"../input/resnet34weights/resnet34_fold{i}.pth\"))\n    model.to(DEVICE)\n    model.eval()\n    g_pred, v_pred, c_pred, img_ids_list = model_predict()\n    \n    final_g_pred.append(g_pred)\n    final_v_pred.append(v_pred)\n    final_c_pred.append(c_pred)\n    if i == 0:\n        final_img_ids.extend(img_ids_list)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img_ids_list","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"final_g = np.argmax(np.mean(np.array(final_g_pred), axis=0), axis=1)\nfinal_v = np.argmax(np.mean(np.array(final_v_pred), axis=0), axis=1)\nfinal_c = np.argmax(np.mean(np.array(final_c_pred), axis=0), axis=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"final_img_ids","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predictions = []\nfor ii, imid in enumerate(final_img_ids):\n    predictions.append((f\"{imid}_grapheme_root\", final_g[ii]))\n    predictions.append((f\"{imid}_vowel_diacritic\", final_v[ii]))\n    predictions.append((f\"{imid}_consonant_diacritic\", final_c[ii]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub = pd.DataFrame(predictions, columns=[\"row_id\", \"target\"])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub.to_csv(\"submission.csv\", index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.6.6"}},"nbformat":4,"nbformat_minor":4}