{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Fastai2 starter\nI decided to start working with fastai2, after a few hours of searching the notebooks and documentation I finnaly got to this point. I figured this may be helpfull to other people wanting to learn about the new fastai version so I'm sharing this notebook. Let me know if you find anything that can be improved, I'm just getting started with fastai2!\n\nSome references:\n* https://www.kaggle.com/yiheng/iterative-stratification\n* https://www.kaggle.com/iafoss/image-preprocessing-128x128\n* https://www.kaggle.com/iafoss/grapheme-fast-ai-starter-lb-0-964\n* https://github.com/fastai/fastai2\n* http://dev.fast.ai/"},{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","trusted":true},"cell_type":"code","source":"!pip install git+https://github.com/fastai/fastai2 \n!pip install git+https://github.com/fastai/fastcore","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import fastai2\nfrom fastai2.vision.all import *\nfrom sklearn.metrics import recall_score\nprint(fastai2.__version__)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Configs\nsz = 128\nbs = 128\nnfolds = 5\nfold = 0\ntrain_path = Path('/kaggle/input/grapheme-imgs-128x128')\ncsv_file = Path('/kaggle/input/iterative-stratification/train_with_fold.csv')\narch = xresnet50","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Load dataframe\ndf = pd.read_csv(csv_file)\ndf.drop(columns=['id'], inplace=True)\ndf.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dblock = DataBlock(\n  blocks=(ImageBlock(cls=PILImageBW), *(3*[CategoryBlock])),      # one image input and three categorical outputs\n  getters=[ColReader('image_id', pref=train_path, suff='.png'),   # image input\n           ColReader('grapheme_root'),                            # label 1\n           ColReader('vowel_diacritic'),                          # label 2\n           ColReader('consonant_diacritic')],                     # label 3\n  splitter=IndexSplitter(df.loc[df.fold==fold].index),            # train/validation split\n  batch_tfms=[Normalize.from_stats([0.0692], [0.2051]),           # Normalize the images with the specified mean and standard deviation\n              *aug_transforms(do_flip=False, size=sz)])           # Add default transformations except for horizontal flip      \ndls = dblock.dataloaders(df, bs=bs)                               # Create the dataloaders\ndls.n_inp = 1                                                     # Set the number of inputs","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Show an example\ndls.show_batch()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Model \nclass Head(Module):\n    def __init__(self, nc, n, ps=0.5):\n        self.fc = nn.Sequential(*[AdaptiveConcatPool2d(), nn.ReLU(inplace=True), Flatten(),\n             LinBnDrop(nc*2, 512, True, ps, nn.ReLU(inplace=True)),\n             LinBnDrop(512, n, True, ps)])\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\nclass BengaliModel(Module):\n    def __init__(self, arch=arch, n=dls.c, pre=True):\n        m = arch(pre)\n        m = nn.Sequential(*children_and_parameters(m)[:-4])\n        conv = nn.Conv2d(3, 32, kernel_size=3, stride=2, padding=1, bias=False)\n        w = (m[0][0].weight.sum(1)).unsqueeze(1)\n        conv.weight = nn.Parameter(w)\n        m[0][0] = conv\n        nc = m(torch.zeros(2, 1, sz, sz)).detach().shape[1]\n        self.body = m\n        self.heads = nn.ModuleList([Head(nc, c) for c in n])\n        \n    def forward(self, x):    \n        x = self.body(x)\n        return [f(x) for f in self.heads]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Loss function\nclass Loss_combine(Module):\n    def __init__(self, func=F.cross_entropy, weights=[2, 1, 1]):\n        self.func, self.w = func, weights\n\n    def forward(self, xs, *ys):\n        for i, w, x, y in zip(range(len(xs)), self.w, xs, ys):\n            if i == 0: loss = w*self.func(x, y) \n            else: loss += w*self.func(x, y) \n        return loss","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Metrics\nclass RecallPartial(Metric):\n    # based on AccumMetric\n    \"Stores predictions and targets on CPU in accumulate to perform final calculations with `func`.\"\n    def __init__(self, a=0, **kwargs):\n        self.func = partial(recall_score, average='macro', zero_division=0)\n        self.a = a\n\n    def reset(self): self.targs,self.preds = [],[]\n\n    def accumulate(self, learn):\n        pred = learn.pred[self.a].argmax(dim=-1)\n        targ = learn.y[self.a]\n        pred,targ = to_detach(pred),to_detach(targ)\n        pred,targ = flatten_check(pred,targ)\n        self.preds.append(pred)\n        self.targs.append(targ)\n\n    @property\n    def value(self):\n        if len(self.preds) == 0: return\n        preds,targs = torch.cat(self.preds),torch.cat(self.targs)\n        return self.func(targs, preds)\n\n    @property\n    def name(self): return df.columns[self.a+1]\n    \nclass RecallCombine(Metric):\n    def accumulate(self, learn):\n        scores = [learn.metrics[i].value for i in range(3)]\n        self.combine = np.average(scores, weights=[2,1,1])\n\n    @property\n    def value(self):\n        return self.combine","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create learner\nlearn = Learner(dls, BengaliModel(), loss_func=Loss_combine(), cbs=CSVLogger(),\n                metrics=[RecallPartial(a=i) for i in range(len(dls.c))] + [RecallCombine()],\n                splitter=lambda m: [list(m.body.parameters()), list(m.heads.parameters())])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"learn.fit_one_cycle(12, lr_max=slice(1e-3, 1e-2))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"learn.recorder.plot_loss()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"learn.save('model') ","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"},"widgets":{"application/vnd.jupyter.widget-state+json":{"state":{"020f1ffb30e5428daef12be0d113e548":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"1437bc55973e4eaaaf0d4be79cac3bd1":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":"initial"}},"4b69a4bb39164d96aa61a4d1d3b4cd86":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"4dbb0e36b12c4ed5981334800fd2b0ff":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"100%","description_tooltip":null,"layout":"IPY_MODEL_c0d7bf525f5f4612bd5d59e72a681822","max":256198016,"min":0,"orientation":"horizontal","style":"IPY_MODEL_1437bc55973e4eaaaf0d4be79cac3bd1","value":256198016}},"62f83043dc7b426cbf0b4b99b8e539eb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_f0bd0fc4284f474c91e1d3a779d00e27","placeholder":"​","style":"IPY_MODEL_4b69a4bb39164d96aa61a4d1d3b4cd86","value":" 244M/244M [00:02&lt;00:00, 99.2MB/s]"}},"7d5db37ad0e64787a733200727258e6a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_4dbb0e36b12c4ed5981334800fd2b0ff","IPY_MODEL_62f83043dc7b426cbf0b4b99b8e539eb"],"layout":"IPY_MODEL_020f1ffb30e5428daef12be0d113e548"}},"c0d7bf525f5f4612bd5d59e72a681822":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f0bd0fc4284f474c91e1d3a779d00e27":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}}},"version_major":2,"version_minor":0}}},"nbformat":4,"nbformat_minor":4}