{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Description\nThis kernel performs inference for [Grapheme fast.ai starter](https://www.kaggle.com/iafoss/grapheme-fast-ai-starter) kernel. Check it for more training details. The image preprocessing pipline is provided [here](https://www.kaggle.com/iafoss/image-preprocessing-128x128)."},{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install ../input/pretrainedmodels/pretrainedmodels-0.7.4/pretrainedmodels-0.7.4/ > /dev/null","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"%reload_ext autoreload\n%autoreload 2\n%matplotlib inline\n\nimport cv2\nimport torch\nfrom tqdm import tqdm_notebook as tqdm\nimport fastai\nfrom fastai.vision import *\nimport os\nimport pretrainedmodels\nprint(os.listdir('../input'))\nfrom mish_activation import *\nimport warnings\nwarnings.filterwarnings(\"ignore\")","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"HEIGHT = 137\nWIDTH = 236\nSIZE = 128\nbs = 128\nstats = (0.0692, 0.2051)\narch = pretrainedmodels.__dict__['se_resnext50_32x4d']\nMODEL = '../input/weights/seresnext.pth'\nnworkers = 2\n\nTEST = ['/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\nLABELS = '../input/bengaliai-cv19/train.csv'\n\ndf = pd.read_csv(LABELS)\nnunique = list(df.nunique())[1:-1]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"nunique","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model"},{"metadata":{"_kg_hide-output":false,"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"class Head(nn.Module):\n    def __init__(self, nc, n, ps=0.5):\n        super().__init__()\n        layers = [AdaptiveConcatPool2d(), Mish(), Flatten()] + \\\n            bn_drop_lin(nc*2, 512, True, ps, Mish()) + \\\n            bn_drop_lin(512, n, True, ps)\n        self.fc = nn.Sequential(*layers)\n        self._init_weight()\n        \n    def _init_weight(self):\n        for m in self.modules():\n            if isinstance(m, nn.Conv2d):\n                torch.nn.init.kaiming_normal_(m.weight)\n            elif isinstance(m, nn.BatchNorm2d):\n                m.weight.data.fill_(1.0)\n                m.bias.data.zero_()\n        \n    def forward(self, x):\n        return self.fc(x)\n\n#change the first conv to accept 1 chanel input\nclass Dnet_1ch(nn.Module):\n    def __init__(self, arch=arch, n=nunique, pre=True, ps=0.5):\n        super().__init__()\n        m = arch(pretrained='imagenet') if pre else arch(pretrained=None)\n        \n        conv = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3, bias=False)\n        w = (m.layer0.conv1.weight.sum(1)).unsqueeze(1)\n        conv.weight = nn.Parameter(w)\n        \n        self.layer0 = nn.Sequential(conv, m.layer0.bn1, m.layer0.relu1, m.layer0.pool)\n        self.layer1 = m.layer1\n        self.layer2 = m.layer2\n        self.layer3 = m.layer3\n        self.layer4 = nn.Sequential(m.layer4[0], m.layer4[1], m.layer4[2])\n\n        \n        nc = self.layer4[-1].se_module.fc2.out_channels #changes as per architecture\n        self.head1 = Head(nc,n[0])\n        self.head2 = Head(nc,n[1])\n        self.head3 = Head(nc,n[2])\n        #to_Mish(self.layer0), to_Mish(self.layer1), to_Mish(self.layer2)\n        #to_Mish(self.layer3), to_Mish(self.layer4)\n        \n    def forward(self, x):    \n        x = self.layer0(x)\n        x = self.layer1(x)\n        x = self.layer2(x)\n        x = self.layer3(x)\n        x = self.layer4(x)\n        \n        x1 = self.head1(x)\n        x2 = self.head2(x)\n        x3 = self.head3(x)\n        \n        return x1,x2,x3","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = Dnet_1ch(pre=False).cuda()\nmodel.load_state_dict(torch.load(MODEL, map_location=torch.device('cpu')));\nmodel.eval();","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data"},{"metadata":{"trusted":true},"cell_type":"code","source":"#check https://www.kaggle.com/iafoss/image-preprocessing-128x128\n\ndef bbox(img):\n    rows = np.any(img, axis=1)\n    cols = np.any(img, axis=0)\n    rmin, rmax = np.where(rows)[0][[0, -1]]\n    cmin, cmax = np.where(cols)[0][[0, -1]]\n    return rmin, rmax, cmin, cmax\n\ndef crop_resize(img0, size=SIZE, pad=16):\n    #crop a box around pixels large than the threshold \n    #some images contain line at the sides\n    ymin,ymax,xmin,xmax = bbox(img0[5:-5,5:-5] > 80)\n    #cropping may cut too much, so we need to add it back\n    xmin = xmin - 13 if (xmin > 13) else 0\n    ymin = ymin - 10 if (ymin > 10) else 0\n    xmax = xmax + 13 if (xmax < WIDTH - 13) else WIDTH\n    ymax = ymax + 10 if (ymax < HEIGHT - 10) else HEIGHT\n    img = img0[ymin:ymax,xmin:xmax]\n    #remove lo intensity pixels as noise\n    img[img < 28] = 0\n    lx, ly = xmax-xmin,ymax-ymin\n    l = max(lx,ly) + pad\n    #make sure that the aspect ratio is kept in rescaling\n    img = np.pad(img, [((l-ly)//2,), ((l-lx)//2,)], mode='constant')\n    return cv2.resize(img,(size,size))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class GraphemeDataset(Dataset):\n    def __init__(self, fname):\n        self.df = pd.read_parquet(fname)\n        self.data = 255 - self.df.iloc[:, 1:].values.reshape(-1, HEIGHT, WIDTH).astype(np.uint8)\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, idx):\n        name = self.df.iloc[idx,0]\n        #normalize each image by its max val\n        img = (self.data[idx]*(255.0/self.data[idx].max())).astype(np.uint8)\n        img = crop_resize(img)\n        img = (img.astype(np.float32)/255.0 - stats[0])/stats[1]\n        return img, name","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prediction"},{"metadata":{"trusted":true},"cell_type":"code","source":"EXP = -1.2\nG_logits = []\nV_logits = []\nC_logits = []\nG_preds = []\nV_preds=[]\nC_preds = []","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import scipy","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"row_id,target = [],[]\nfor fname in TEST:\n    ds = GraphemeDataset(fname)\n    dl = DataLoader(ds, batch_size=bs, num_workers=nworkers, shuffle=False)\n    with torch.no_grad():\n        for x,y in tqdm(dl):\n            x = x.unsqueeze(1).cuda()\n            p1,p2,p3 = model(x)\n            p1 = torch.nn.functional.softmax(p1)\n            p2 = torch.nn.functional.softmax(p2)\n            p3 = torch.nn.functional.softmax(p3)\n            G_logits.append(p1.cpu())\n            V_logits.append(p2.cpu())\n            C_logits.append(p3.cpu())\n            p1 = p1.argmax(-1).view(-1).cpu()\n            p2 = p2.argmax(-1).view(-1).cpu()\n            p3 = p3.argmax(-1).view(-1).cpu()\n            G_preds.append(p1)\n            V_preds.append(p2)\n            C_preds.append(p3)\n           \n        \n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"G_preds = np.concatenate(G_preds)\nV_preds = np.concatenate(V_preds)\nC_preds = np.concatenate(C_preds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"s = pd.Series(G_preds)\nvc = s.value_counts().sort_index()\ndf = pd.DataFrame({'a':np.arange(168),'b':np.ones(168)})\ndf.b = df.a.map(vc)\ndf.fillna(df.b.min(),inplace=True)\nmat1 = np.diag(df.b.astype('float32')**EXP)\n\ns = pd.Series(V_preds)\nvc = s.value_counts().sort_index()\ndf = pd.DataFrame({'a':np.arange(11),'b':np.ones(11)})\ndf.b = df.a.map(vc)\ndf.fillna(df.b.min(),inplace=True)\nmat2 = np.diag(df.b.astype('float32')**EXP)\n\ns = pd.Series(C_preds)\nvc = s.value_counts().sort_index()\ndf = pd.DataFrame({'a':np.arange(7),'b':np.ones(7)})\ndf.b = df.a.map(vc)\ndf.fillna(df.b.min(),inplace=True)\nmat3 = np.diag(df.b.astype('float32')**EXP)\n\nG_logits = np.concatenate(G_logits)\nV_logits = np.concatenate(V_logits)\nC_logits = np.concatenate(C_logits)\n\nG_pred = np.argmax( G_logits.dot(mat1), axis=1)\nV_pred = np.argmax( V_logits.dot(mat2), axis=1)\nC_pred = np.argmax( C_logits.dot(mat3), axis=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"all_list = [G_pred, V_pred, C_pred]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"labels = ['grapheme_root', 'vowel_diacritic', 'consonant_diacritic']\n\nsub = pd.DataFrame({'row_id': [f'Test_{i}_{j}' for i in range(len(G_pred)) for j in labels ],'target':[data[i].item() for i in range(len(G_pred)) for data in all_list]} )\nsub.to_csv('submission.csv', index=False)\nsub","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}