{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nfrom tqdm import tqdm\nimport datetime\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.nn.functional as F\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision\n\nimport cv2\nfrom albumentations import Compose, Resize\nfrom albumentations.augmentations.transforms import Normalize\nfrom albumentations.pytorch import ToTensorV2\nimport matplotlib.pyplot as plt\n\nfrom sklearn.model_selection import StratifiedKFold\nfrom IPython.display import display\n\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 1. data exploring"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"train_dataset = pd.read_csv('../input/bengaliai-cv19/train.csv')\nprint(train_dataset.describe())\ndisplay(train_dataset.head())\ndisplay(train_dataset.tail())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"unique = train_dataset.apply(lambda col: col.nunique())\nunique","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_dataset = pd.read_csv('../input/bengaliai-cv19/test.csv')\nprint(test_dataset.describe())\ntest_dataset.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 2.splitting fold with https://www.kaggle.com/haqishen/validation-with-unseen"},{"metadata":{"trusted":true},"cell_type":"code","source":"grapheme2idx = {grapheme: idx for idx, grapheme in enumerate(train_dataset.grapheme.unique())}\ntrain_dataset['grapheme_id'] = train_dataset['grapheme'].map(grapheme2idx)\n\nn_fold = 5\nskf = StratifiedKFold(n_fold)\nfor i_fold, (train_idx, val_idx) in enumerate(skf.split(train_dataset, train_dataset.grapheme)):\n    train_dataset.loc[val_idx, 'fold'] = i_fold\ntrain_dataset['fold'] = train_dataset['fold'].astype(int)\n\ntrain_dataset['unseen'] = 0\ntrain_dataset.loc[train_dataset.grapheme_id >= 1245, 'unseen'] = 1\nprint(train_dataset.unseen.value_counts())\n\n# usage \nfold = 1\ntrain_idx = np.where((train_dataset['fold'] != fold) & (train_dataset['unseen'] == 0))[0]\nvalid_idx = np.where((train_dataset['fold'] == fold) | (train_dataset['unseen'] != 0))[0]\ndisplay(train_dataset.loc[train_idx].reset_index(drop=True).head())\ndisplay(train_dataset.loc[valid_idx].reset_index(drop=True).head())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 3.Dataloader"},{"metadata":{"trusted":true},"cell_type":"code","source":"!mkdir img; ls","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"HEIGHT = 137\nWIDTH = 236\n\ndef make_png(path):\n    df = pd.read_parquet(path)\n    data = 255 - df.iloc[:, 1:].values.reshape(-1, HEIGHT, WIDTH).astype(np.uint8)\n    for idx in tqdm(range(len(df))):\n        name = df.iloc[idx,0]\n        img = (data[idx]).astype(np.uint8)\n        cv2.imwrite(\"/kaggle/working/img/{}.png\".format(name),img)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for path in ['/kaggle/input/bengaliai-cv19/train_image_data_0.parquet',\n            '/kaggle/input/bengaliai-cv19/train_image_data_1.parquet',\n            '/kaggle/input/bengaliai-cv19/train_image_data_2.parquet',\n            '/kaggle/input/bengaliai-cv19/train_image_data_3.parquet']:\n    print(\"now translating: {}\".format(path))\n    make_png(path)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"for dirname, _, filenames in os.walk('/kaggle/working/img'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n        break","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class BengaliImageDataset(Dataset):\n    def __init__(self, data_frame, img_path, labels, transform=None):\n        super().__init__()\n        self.data = data_frame\n        self.data_dummie_labels = pd.get_dummies(\n            self.data[['grapheme_root', 'vowel_diacritic', 'consonant_diacritic']],\n            columns=['grapheme_root', 'vowel_diacritic', 'consonant_diacritic']\n        )\n        self.img_path = img_path\n        self.labels = labels\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, idx):\n        image_name = os.path.join(self.img_path, self.data.loc[idx, 'image_id'] + '.png')\n        img = cv2.imread(image_name)\n\n        if self.transform:\n            transformed = self.transform(image=img)\n            img = transformed['image']\n            \n\n        if self.labels:\n            return {\n                'image': img,\n                'l_graph': torch.tensor(self.data_dummie_labels.iloc[idx, 0:168]),\n                'l_vowel': torch.tensor(self.data_dummie_labels.iloc[idx, 168:179]),\n                'l_conso': torch.tensor(self.data_dummie_labels.iloc[idx, 179:186]),\n            }\n        else:\n            return {'image': img}\n        \nTRAIN_Dataset = BengaliImageDataset(\n    data_frame = train_dataset.loc[train_idx].reset_index(drop=True),\n    img_path = '/kaggle/working/img/',\n    transform = Compose([Resize(HEIGHT,HEIGHT),Normalize(),ToTensorV2()]), labels=True\n)\nprint(len(TRAIN_Dataset))\nprint(next(iter(TRAIN_Dataset)))\nprint(next(iter(TRAIN_Dataset))['image'].size())\nplt.imshow(next(iter(TRAIN_Dataset))['image'].numpy().T)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"VALID_Dataset = BengaliImageDataset(\n    data_frame = train_dataset.loc[valid_idx].reset_index(drop=True),\n    img_path = '/kaggle/working/img/',\n    transform = Compose([Resize(HEIGHT,HEIGHT),Normalize(),ToTensorV2()]), labels=True\n)\n\nbatch_size = 32\nTRAIN_DataLoader = DataLoader(TRAIN_Dataset, batch_size=batch_size, shuffle=True)\nVALID_DataLoader = DataLoader(VALID_Dataset, batch_size=batch_size, shuffle=False)\ndataloaders_dict = {\"train\":TRAIN_DataLoader, \"valid\":VALID_DataLoader}","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 4.NN model"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(torchvision.models.resnet50(pretrained=False, progress=True))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class ResNetFC(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.resnet = torchvision.models.resnet50(pretrained=False, progress=True)\n        self.resnet.load_state_dict(torch.load(\"../input/pretrained-pytorch-models/resnet50-19c8e357.pth\"))\n        in_features = self.resnet.fc.out_features\n        \n        self.fc_graph = torch.nn.Linear(in_features, 168)\n        self.fc_vowel = torch.nn.Linear(in_features, 11)\n        self.fc_conso = torch.nn.Linear(in_features, 7)\n        \n    def forward(self, x):\n        x = self.resnet(x)\n        fc_graph = self.fc_graph(x)\n        fc_vowel = self.fc_vowel(x)\n        fc_conso = self.fc_conso(x)\n        return fc_graph, fc_vowel, fc_conso","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"device = torch.device('cpu' if not torch.cuda.is_available() else 'cuda')\nmodel = ResNetFC().to(device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"update_params_list = ['resnet.fc.weight','resnet.fc.bias',\n                      'fc_graph.weight','fc_graph.bias',\n                      'fc_vowel.weight','fc_vowel.bias',\n                      'fc_conso.weight','fc_conso.bias']\nparams_to_update = []\nfor name, param in model.named_parameters():\n    if name in update_params_list:\n        param.requires_grad = True\n        params_to_update.append(param)\n        print(name)\n    else:\n        param.requires_grad = False","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"criterion = torch.nn.BCEWithLogitsLoss()\noptimizer = optim.Adam(params=params_to_update, lr=1e-4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 5.Training"},{"metadata":{"trusted":true},"cell_type":"code","source":"def train_model(model, dataloaders_dict, criterion, optimizer, num_epochs):\n    train_loss = []\n    valid_loss = []\n    \n    for epoch in range(num_epochs):\n        print('Epoch {}/{}'.format(epoch+1, num_epochs))\n        print('-' * 10)\n        for phase in ['train', 'valid']:\n            if phase == 'train': model.train()\n            else: model.eval()\n                \n            epoch_loss = 0.0\n            iteration = 0\n            length = len(dataloaders_dict[phase].dataset)\n\n            for batch in dataloaders_dict[phase]:\n                iteration += 1\n                optimizer.zero_grad()\n                inputs = batch[\"image\"]\n                l_graph, l_vowel, l_conso = batch[\"l_graph\"], batch[\"l_vowel\"], batch[\"l_conso\"]\n                \n                # send to device\n                inputs = inputs.to(device, dtype=torch.float)\n                l_graph = l_graph.to(device, dtype=torch.float)\n                l_vowel = l_vowel.to(device, dtype=torch.float)\n                l_conso = l_conso.to(device, dtype=torch.float)\n                \n                with torch.set_grad_enabled(phase == 'train'):\n                    # Forward\n                    out_graph, out_vowel, out_conso  = model(inputs)\n                    loss = criterion(out_graph,l_graph) + criterion(out_vowel, l_vowel) + criterion(out_conso, l_conso)\n                    \n                    # Backprop\n                    if phase == 'train':\n                        loss.backward()\n                        optimizer.step()\n                    \n                    batch_loss = loss.item() * inputs.size(0)\n                    epoch_loss += batch_loss\n                if iteration%50 == 1:\n                    print('{} : Minibatch {}/{} finished (Loss: {:.4f})'.format(datetime.datetime.now(),\n                                                            min(batch_size*iteration,length),length, batch_loss/batch_size))\n        \n            epoch_loss = epoch_loss / length\n            if phase == 'train':\n                train_loss.append(epoch_loss)\n            else:\n                valid_loss.append(epoch_loss)\n            print('##### {} Loss: {:.4f} #####'.format(phase, epoch_loss))\n            \n        save_path = '/kaggle/working/weights_epoch{}.pth'.format(epoch+1)\n        #torch.save(model.state_dict(), save_path)\n        \n    return model, train_loss, valid_loss","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"num_epochs = 3\nmodel, train_loss, valid_loss = train_model(model, dataloaders_dict, criterion, optimizer, num_epochs=num_epochs)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 6.Prediction"},{"metadata":{"trusted":true},"cell_type":"code","source":"for path in ['/kaggle/input/bengaliai-cv19/test_image_data_0.parquet',\n            '/kaggle/input/bengaliai-cv19/test_image_data_1.parquet',\n            '/kaggle/input/bengaliai-cv19/test_image_data_2.parquet',\n            '/kaggle/input/bengaliai-cv19/test_image_data_3.parquet']:\n    print(\"now translating: {}\".format(path))\n    make_png(path)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class testDataset(Dataset):\n    def __init__(self, data_frame, img_path, transform=None):\n        super().__init__()\n        self.data = data_frame\n        self.img_path = img_path\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, idx):\n        image_name = os.path.join(self.img_path, self.data.loc[idx, 'image_id'] + '.png')\n        img = cv2.imread(image_name)\n\n        if self.transform:\n            transformed = self.transform(image=img)\n            img = transformed['image']\n\n        return img\n    \ntest_dataset = pd.read_csv('../input/bengaliai-cv19/test.csv')\ntest_dataset = pd.DataFrame(test_dataset['image_id'].unique(),columns=['image_id'])\n\nTEST_Dataset = testDataset(\n    data_frame = test_dataset,\n    img_path = '/kaggle/working/img/',\n    transform = Compose([Resize(HEIGHT,HEIGHT),Normalize(),ToTensorV2()])\n)\nTEST_DataLoader = DataLoader(TEST_Dataset, batch_size=1, shuffle=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def predict(model, dataloader, submission):\n    prediction = []\n    model.to(device)\n    model.eval()\n    for inputs in dataloader:\n        inputs = inputs.to(device, dtype=torch.float)\n        with torch.set_grad_enabled(False):\n            out_graph, out_vowel, out_conso  = model(inputs)\n            _, pred_graph = torch.max(out_graph, 1)\n            _, pred_vowel = torch.max(out_vowel, 1)\n            _, pred_conso = torch.max(out_conso, 1)\n            prediction.append(pred_conso.item())\n            prediction.append(pred_graph.item())\n            prediction.append(pred_vowel.item())\n            \n                \n    print(prediction)\n    for i, pred in enumerate(prediction):\n        submission.loc[i,'target'] = pred\n        \n    return submission\n\nsubmission = pd.read_csv('../input/bengaliai-cv19/test.csv')[['row_id']].assign(target=0)\nsubmission = predict(model, TEST_DataLoader, submission)\ndisplay(submission)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.to_csv(\"/kaggle/working/submission.csv\", index = False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!rm -r img; ls","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}