{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<center style=\"\n               padding: 2rem 3rem;\n               border: 3px solid #aae629;\n               border-radius: 20px;\n               \">\n    <h1 style=\"color: #aae629;\">ConvNeXt-tiny</h1>\n    <h2 style=\"color: #aae629;\">⚡️ Pytorch Lightning + timm 📷</h2>\n    <a href=\"https://kaggle.com/shreydan\" style=\"text-decoration:none;\n                                                 padding: 1rem 2rem;\n                                                 color: white;\n                                                 background-color: #aae629;\n                                                 border-radius: 30px;\n                                                 font-size:1.25rem;\n                                                 \" >@shreydan</a>\n</center>","metadata":{}},{"cell_type":"markdown","source":"# **Imports**\n___","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom pathlib import Path\nfrom collections import Counter\nfrom sklearn.model_selection import train_test_split","metadata":{"execution":{"iopub.status.busy":"2022-08-01T10:45:37.217071Z","iopub.execute_input":"2022-08-01T10:45:37.217844Z","iopub.status.idle":"2022-08-01T10:45:38.674197Z","shell.execute_reply.started":"2022-08-01T10:45:37.217751Z","shell.execute_reply":"2022-08-01T10:45:38.672456Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport pytorch_lightning as pl\nfrom pytorch_lightning.callbacks.early_stopping import EarlyStopping\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\nfrom PIL import Image","metadata":{"execution":{"iopub.status.busy":"2022-08-01T11:42:45.044927Z","iopub.execute_input":"2022-08-01T11:42:45.045648Z","iopub.status.idle":"2022-08-01T11:42:45.052424Z","shell.execute_reply.started":"2022-08-01T11:42:45.045616Z","shell.execute_reply":"2022-08-01T11:42:45.051064Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Setting up Timm**\n___","metadata":{}},{"cell_type":"code","source":"import os\nif not os.path.exists('/root/.cache/torch/hub/checkpoints/'):\n    os.makedirs('/root/.cache/torch/hub/checkpoints/')\n!cp '../input/convnext-tiny-1k-224-ema-weights/convnext_tiny_1k_224_ema.pth' '/root/.cache/torch/hub/checkpoints/convnext_tiny_1k_224_ema.pth'","metadata":{"execution":{"iopub.status.busy":"2022-08-01T11:56:55.328176Z","iopub.execute_input":"2022-08-01T11:56:55.328563Z","iopub.status.idle":"2022-08-01T11:56:58.784149Z","shell.execute_reply.started":"2022-08-01T11:56:55.328532Z","shell.execute_reply":"2022-08-01T11:56:58.782367Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import sys\nsys.path.append('../input/timm-pytorch-image-models/pytorch-image-models-master')\nfrom timm import create_model","metadata":{"execution":{"iopub.status.busy":"2022-08-01T11:57:01.612402Z","iopub.execute_input":"2022-08-01T11:57:01.612910Z","iopub.status.idle":"2022-08-01T11:57:01.620235Z","shell.execute_reply.started":"2022-08-01T11:57:01.612864Z","shell.execute_reply":"2022-08-01T11:57:01.618800Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Preparing Datasets**\n___","metadata":{}},{"cell_type":"code","source":"train_images = list(Path('../input/petfinder-pawpularity-score/train').glob(\"*\"))\n\n# just noise\ntest_images = list(Path('../input/petfinder-pawpularity-score/test').glob(\"*\"))\n\nlen(train_images)","metadata":{"execution":{"iopub.status.busy":"2022-08-01T10:45:46.189499Z","iopub.execute_input":"2022-08-01T10:45:46.189865Z","iopub.status.idle":"2022-08-01T10:45:46.593752Z","shell.execute_reply.started":"2022-08-01T10:45:46.189833Z","shell.execute_reply":"2022-08-01T10:45:46.592627Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# checking image types\nCounter([path.suffix for path in train_images])","metadata":{"execution":{"iopub.status.busy":"2022-08-01T10:45:46.596471Z","iopub.execute_input":"2022-08-01T10:45:46.597199Z","iopub.status.idle":"2022-08-01T10:45:46.622358Z","shell.execute_reply.started":"2022-08-01T10:45:46.597148Z","shell.execute_reply":"2022-08-01T10:45:46.621039Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv('../input/petfinder-pawpularity-score/train.csv')\ndf = df.sample(frac=1).reset_index(drop=True) # shuffle","metadata":{"execution":{"iopub.status.busy":"2022-08-01T10:45:46.626322Z","iopub.execute_input":"2022-08-01T10:45:46.627059Z","iopub.status.idle":"2022-08-01T10:45:46.667537Z","shell.execute_reply.started":"2022-08-01T10:45:46.627000Z","shell.execute_reply":"2022-08-01T10:45:46.666353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# since all images have .jpg extension\nbase_path = '../input/petfinder-pawpularity-score/train/'\nget_path = lambda x: base_path + x + '.jpg'\ndf['path'] = df['Id'].apply(get_path)\ndf['norm'] = df['Pawpularity'] / 100.0\ndf.head(1)","metadata":{"execution":{"iopub.status.busy":"2022-08-01T10:45:46.671117Z","iopub.execute_input":"2022-08-01T10:45:46.671476Z","iopub.status.idle":"2022-08-01T10:45:46.707398Z","shell.execute_reply.started":"2022-08-01T10:45:46.671448Z","shell.execute_reply":"2022-08-01T10:45:46.706075Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df = pd.read_csv('../input/petfinder-pawpularity-score/test.csv')\nbase_path = '../input/petfinder-pawpularity-score/test/'\nget_path = lambda x: base_path + x + '.jpg'\ntest_df['path'] = test_df['Id'].apply(get_path)\ntest_df.head(1)","metadata":{"execution":{"iopub.status.busy":"2022-08-01T11:16:17.655889Z","iopub.execute_input":"2022-08-01T11:16:17.656419Z","iopub.status.idle":"2022-08-01T11:16:17.681694Z","shell.execute_reply.started":"2022-08-01T11:16:17.656358Z","shell.execute_reply":"2022-08-01T11:16:17.680425Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df, val_df = train_test_split(df, test_size=0.2, shuffle=True, random_state=1357)\ntrain_df.reset_index(drop=True, inplace=True)\nval_df.reset_index(drop=True, inplace=True)\n\nlen(train_df), len(val_df)","metadata":{"execution":{"iopub.status.busy":"2022-08-01T10:46:02.398899Z","iopub.execute_input":"2022-08-01T10:46:02.399319Z","iopub.status.idle":"2022-08-01T10:46:02.418563Z","shell.execute_reply.started":"2022-08-01T10:46:02.399286Z","shell.execute_reply":"2022-08-01T10:46:02.417102Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Albumentations**\n___","metadata":{}},{"cell_type":"code","source":"train_augs = A.Compose(\n    [\n        A.Resize(height=320, width=320),\n        A.ShiftScaleRotate(shift_limit=0.05, scale_limit=0.05, rotate_limit=15, p=0.5),\n        A.RandomCrop(height=224, width=224),\n        A.Normalize(mean=(0.485, 0.456, 0.406), \n                    std=(0.229, 0.224, 0.225), \n                    always_apply=True\n                   ),\n        ToTensorV2(),\n    ],\n    p=1.0\n)\nval_augs = A.Compose(\n    [\n        A.Resize(height=320, width=320),\n        A.CenterCrop(height=224, width=224),\n        A.Normalize(mean=(0.485, 0.456, 0.406), \n                    std=(0.229, 0.224, 0.225),\n                    always_apply=True\n                   ),\n        ToTensorV2()\n    ],\n    p=1.0\n)","metadata":{"execution":{"iopub.status.busy":"2022-08-01T10:46:04.931233Z","iopub.execute_input":"2022-08-01T10:46:04.931629Z","iopub.status.idle":"2022-08-01T10:46:04.943790Z","shell.execute_reply.started":"2022-08-01T10:46:04.931597Z","shell.execute_reply":"2022-08-01T10:46:04.942427Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Custom Dataset**\n___","metadata":{}},{"cell_type":"code","source":"class PawsDataset:\n    def __init__(self, df, augs, is_test=False):\n        self.paths = df['path'].values\n        self.meta = df.iloc[:,1:13].values\n        self.augs = augs\n        self.is_test = is_test\n        if not self.is_test:\n            self.scores = df['norm'].values\n        \n    def __len__(self):\n        return len(self.paths)\n    \n    def __getitem__(self, idx):\n        sample = self.paths[idx]\n        sample = Image.open(sample).convert(mode='RGB')\n        sample = np.array(sample)\n        sample = self.augs(image=sample)['image']\n        meta = torch.tensor(self.meta[idx,:], dtype=torch.float32)\n        if not self.is_test:\n            score = torch.tensor(self.scores[idx], dtype=torch.float32)\n            return sample, meta, score\n        \n        return sample, meta\n        ","metadata":{"execution":{"iopub.status.busy":"2022-08-01T10:46:08.395347Z","iopub.execute_input":"2022-08-01T10:46:08.395770Z","iopub.status.idle":"2022-08-01T10:46:08.408207Z","shell.execute_reply.started":"2022-08-01T10:46:08.395739Z","shell.execute_reply":"2022-08-01T10:46:08.406721Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_ds = PawsDataset(train_df, augs=train_augs)\nval_ds = PawsDataset(val_df, augs=val_augs)\ntest_ds = PawsDataset(test_df, augs=val_augs, is_test=True)","metadata":{"execution":{"iopub.status.busy":"2022-08-01T11:26:09.059872Z","iopub.execute_input":"2022-08-01T11:26:09.060553Z","iopub.status.idle":"2022-08-01T11:26:09.070637Z","shell.execute_reply.started":"2022-08-01T11:26:09.060508Z","shell.execute_reply":"2022-08-01T11:26:09.069213Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **ConvNeXt-Tiny**\n___\n\n## [Paper: A ConvNet for the 2020s](https://arxiv.org/abs/2201.03545)\n\n## Reason for using this model:\n\nRecently, Professor Jeremy Howard released a notebook: [The best vision models for fine-tuning](https://www.kaggle.com/code/jhoward/the-best-vision-models-for-fine-tuning) in which he says:\n\n>The excellent showing of `convnext_tiny` matches my view that we should think of this as our default baseline for image recognition today. It's fast, accurate, and not too much of a memory hog. \n\nThat's why I wanted to try it. I hadn't tried fast.ai before so chose to go with Pytorch Lightning \n\n","metadata":{}},{"cell_type":"code","source":"m = create_model('convnext_tiny', pretrained=True, num_classes = 1)\nm.head","metadata":{"execution":{"iopub.status.busy":"2022-08-01T11:57:08.747623Z","iopub.execute_input":"2022-08-01T11:57:08.748102Z","iopub.status.idle":"2022-08-01T11:57:09.599736Z","shell.execute_reply.started":"2022-08-01T11:57:08.748068Z","shell.execute_reply":"2022-08-01T11:57:09.598286Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Lightning Model Wrapper**\n___","metadata":{}},{"cell_type":"code","source":"class PawsModel(pl.LightningModule):\n    def __init__(self, model_name='convnext_tiny', dropout=0.1):\n        super(PawsModel, self).__init__()\n        self.model_name = model_name\n        self.backbone = create_model(self.model_name, pretrained=True, num_classes = 0)\n        self.drop = nn.Dropout(dropout)\n        self.fc = nn.LazyLinear(1)\n        self.mse = nn.MSELoss()\n        \n        self.test_preds = []\n        \n    def RMSE(self, preds, y):\n        mse = self.mse(preds.view(-1), y.view(-1))\n        return torch.sqrt(mse)\n        \n    def forward(self, sample):\n        x,m = sample\n        x = self.backbone(x)\n        x = self.drop(x)\n        cat = torch.cat([x,m],dim=1)\n        logit = self.fc(cat)\n        return logit\n    \n    def training_step(self, batch, batch_idx):\n        \n        *sample,y = batch\n        \n        preds = self(sample)\n        \n        loss = self.RMSE(preds, y)\n        self.log('train_loss', loss.item(), on_epoch=True, prog_bar=True)\n        \n        return loss\n    \n    def validation_step(self, batch, batch_idx):\n        \n        *sample,y = batch\n        \n        preds = self(sample)\n        \n        loss = self.RMSE(preds, y)\n        self.log('val_loss', loss.item(), on_epoch=True, prog_bar=True)\n        \n        \n    def configure_optimizers(self):\n        optimizer = torch.optim.Adam(self.parameters(), lr=2e-5)\n        return optimizer\n    \n    def test_step(self, batch, batch_idx):\n        sample = batch\n        preds = 100 * self(sample)\n        self.test_preds.append(preds.detach().cpu())\n        \n    def get_predictions(self):\n        return torch.cat(self.test_preds).numpy()","metadata":{"execution":{"iopub.status.busy":"2022-08-01T11:29:16.278266Z","iopub.execute_input":"2022-08-01T11:29:16.278697Z","iopub.status.idle":"2022-08-01T11:29:16.297578Z","shell.execute_reply.started":"2022-08-01T11:29:16.278631Z","shell.execute_reply":"2022-08-01T11:29:16.296166Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **DataLoaders**\n___","metadata":{}},{"cell_type":"code","source":"train_dl = torch.utils.data.DataLoader(train_ds, batch_size=32, num_workers=2, shuffle=True)\nval_dl = torch.utils.data.DataLoader(val_ds, batch_size=32, num_workers=2, shuffle=False)\ntest_dl = torch.utils.data.DataLoader(test_ds, batch_size=1, num_workers=1, shuffle=False)\nlen(train_dl), len(val_dl), len(test_dl)","metadata":{"execution":{"iopub.status.busy":"2022-08-01T11:30:17.205495Z","iopub.execute_input":"2022-08-01T11:30:17.205894Z","iopub.status.idle":"2022-08-01T11:30:17.219239Z","shell.execute_reply.started":"2022-08-01T11:30:17.205862Z","shell.execute_reply":"2022-08-01T11:30:17.217324Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Training**\n___","metadata":{}},{"cell_type":"code","source":"model=PawsModel()\ntrainer = pl.Trainer(accelerator='gpu', \n                     max_epochs=6, \n                     callbacks=[\n                         EarlyStopping(monitor=\"val_loss\", \n                                       mode=\"min\",\n                                       patience=2,\n                                      )\n                        ]\n                    )\ntrainer.fit(model, train_dl, val_dl)","metadata":{"execution":{"iopub.status.busy":"2022-08-01T11:36:26.744545Z","iopub.execute_input":"2022-08-01T11:36:26.744992Z","iopub.status.idle":"2022-08-01T11:39:51.387608Z","shell.execute_reply.started":"2022-08-01T11:36:26.744955Z","shell.execute_reply":"2022-08-01T11:39:51.386006Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Testing**\n___","metadata":{}},{"cell_type":"code","source":"trainer.test(model,test_dl)","metadata":{"execution":{"iopub.status.busy":"2022-08-01T11:39:51.402975Z","iopub.execute_input":"2022-08-01T11:39:51.403912Z","iopub.status.idle":"2022-08-01T11:39:52.514406Z","shell.execute_reply.started":"2022-08-01T11:39:51.403804Z","shell.execute_reply":"2022-08-01T11:39:52.513103Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"p = model.get_predictions().reshape(-1)\np","metadata":{"execution":{"iopub.status.busy":"2022-08-01T11:49:19.519409Z","iopub.execute_input":"2022-08-01T11:49:19.519819Z","iopub.status.idle":"2022-08-01T11:49:19.531681Z","shell.execute_reply.started":"2022-08-01T11:49:19.519787Z","shell.execute_reply":"2022-08-01T11:49:19.530092Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df = pd.DataFrame({'Id': test_df['Id'].values, 'Pawpularity': p})\nsubmission_df.to_csv('submission.csv',index=False)","metadata":{"execution":{"iopub.status.busy":"2022-08-01T11:47:41.520156Z","iopub.execute_input":"2022-08-01T11:47:41.520856Z","iopub.status.idle":"2022-08-01T11:47:41.534838Z","shell.execute_reply.started":"2022-08-01T11:47:41.520820Z","shell.execute_reply":"2022-08-01T11:47:41.533452Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df","metadata":{"execution":{"iopub.status.busy":"2022-08-01T11:48:18.170993Z","iopub.execute_input":"2022-08-01T11:48:18.171428Z","iopub.status.idle":"2022-08-01T11:48:18.186457Z","shell.execute_reply.started":"2022-08-01T11:48:18.171396Z","shell.execute_reply":"2022-08-01T11:48:18.185130Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Additional Reference Notebooks:\n\n- [Petfinder Pawpularity EDA & fastai starter 🐱🐶](https://www.kaggle.com/code/tanlikesmath/petfinder-pawpularity-eda-fastai-starter/notebook) : gave me reference for learning rate + this was mentioned in Prof. Jeremy Howard's notebook as well\n\n- [[Pytorch + W&B] Pawpularity Training 🔥](https://www.kaggle.com/code/debarshichanda/pytorch-w-b-pawpularity-training) : gave me reference for how to combine feature extractions and meta features, and loss functions\n","metadata":{}},{"cell_type":"markdown","source":"### **✨️ Thank You for taking the time to check out my notebook ✨️**\n\n\n___\n\n<center>\n    <img src=\"https://img.shields.io/badge/Upvote-If%20you%20like%20my%20work-07b3c8?style=for-the-badge&logo=kaggle\"/>\n</center>","metadata":{}}]}