{"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":"## Summary\n* Trained model to identify breeds of dogs and cats\n* Included script to classify between dog and cat\n* Trained ligthgbm to predict Pawpularity\n\nI used several datasets for breed identidication and preprocess them, so that labels do not repeat and trained swin-tiny on this data. Also I included dataset which was collected using API to gather information from [PetFinder.my](PetFinder.my) *../input/cat-breeds-dataset* but it's not clean, so I didn't use it. Dataset is slightly imbalanced, but all the techniques that I tried: weightedSampler, give weights to classes didn't work out. **F1 macro score on validation is ~0.8**. There are a lot of things that can improve score: train larger model, add more augmentations, tune hyperparameters and etc...\n### References\n\n- I used slightly modified code from https://github.com/amitrajitbose/cat-v-dog-classifier-pytorch.git to predict whether animal is a cat or dog.","metadata":{}},{"cell_type":"code","source":"!pip install pytorch-lightning timm python-box -U albumentations wandb > /dev/null","metadata":{"execution":{"iopub.status.busy":"2021-11-08T17:53:27.221757Z","iopub.execute_input":"2021-11-08T17:53:27.222088Z","iopub.status.idle":"2021-11-08T17:53:38.24707Z","shell.execute_reply.started":"2021-11-08T17:53:27.222056Z","shell.execute_reply":"2021-11-08T17:53:38.245792Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Import all needed libraries","metadata":{}},{"cell_type":"code","source":"import sys\nsys.path.append('../input/catvdogclassifier/cat-v-dog-classifier-pytorch')\n\nfrom predict import ModelInference\nfrom lightgbm import LGBMRegressor\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import mean_squared_error\n\nimport pandas as pd\nimport numpy as np\nfrom glob import glob\nfrom pathlib import Path\nfrom tqdm import tqdm\nfrom box import Box\nimport wandb\nimport cv2\nimport os\n\nfrom sklearn.model_selection import StratifiedKFold, train_test_split\nfrom sklearn.preprocessing import LabelEncoder\nfrom torch.utils.data import Dataset, DataLoader, WeightedRandomSampler\nfrom albumentations.pytorch.transforms import ToTensorV2\nfrom torchmetrics import ConfusionMatrix, Accuracy, F1, Precision, Recall\nfrom sklearn.metrics import classification_report\nimport albumentations as A\n\nfrom pytorch_lightning import LightningDataModule, LightningModule\nfrom pytorch_lightning.utilities.seed import seed_everything\nfrom pytorch_lightning.callbacks.early_stopping import EarlyStopping\nfrom pytorch_lightning.loggers import WandbLogger\nfrom pytorch_lightning import callbacks\nimport pytorch_lightning as pl\n\nimport torch\nfrom timm import create_model\nimport torch.nn.functional as F\nimport torch.nn as nn\nimport torch.optim as optim\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\ntqdm.pandas()","metadata":{"execution":{"iopub.status.busy":"2021-11-08T17:57:33.396633Z","iopub.execute_input":"2021-11-08T17:57:33.398737Z","iopub.status.idle":"2021-11-08T17:57:33.420103Z","shell.execute_reply.started":"2021-11-08T17:57:33.398676Z","shell.execute_reply":"2021-11-08T17:57:33.418827Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Preprocess data\nClass **paths** needed to specify all paths to datasets that will be used. You can delete some datasets or add.","metadata":{}},{"cell_type":"code","source":"class paths:\n  #cat_breeds_petfinder = Path('../input/cat-breeds-dataset')\n  cat_breeds_oxford = Path('../input/the-oxfordiiit-pet-dataset')\n  dog_breeds = Path('../input/dog-breeds')\n  dog_breeds_kaggle = Path('../input/dog-breed-identification')\n  petfinder_old = Path('../input/petfinder-adoption-prediction')\n\n#out columns\ncolumns = ['filepath', 'breed', 'data_source']","metadata":{"execution":{"iopub.status.busy":"2021-11-08T16:33:00.829781Z","iopub.execute_input":"2021-11-08T16:33:00.830105Z","iopub.status.idle":"2021-11-08T16:33:00.835948Z","shell.execute_reply.started":"2021-11-08T16:33:00.830056Z","shell.execute_reply":"2021-11-08T16:33:00.834903Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"seed_everything(2021, workers=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Useful class to preprocess all datasets and output final one in the form of pandas DataFrame.","metadata":{}},{"cell_type":"code","source":"class DogsCatsData:\n  def __init__(self, paths, columns):\n    self.paths = paths\n    self.columns = columns\n\n  def get_data(self, min_th = 10, keep_th = 300):\n    \"\"\"\n    min_th: the minimun number of images that breed has\n    keep_th: the maximum number of images that breed has\n    \"\"\"\n    \n    data = []\n    for attr in vars(self.paths):\n      if not attr.startswith('_'):\n        data_function = getattr(self, f'{attr}_data')\n        path = getattr(paths, attr)\n        data.append(data_function(path))\n\n    data = pd.concat([d[self.columns] for d in data])\n    data = self._preprocess_data(data, min_th, keep_th)\n    data = self._label_data(data)\n    return data\n\n  def _preprocess_data(self, data: pd.DataFrame, min_th = 15, keep_th = 300):\n    \"\"\"\n    min_th: the minimun number of images that breed has\n    keep_th: the maximum number of images that breed has\n    \"\"\"\n    \n    data['breed'] = data['breed'].str.lower()\n    data['breed'] = data['breed'].apply(lambda x: x.replace('_', ' '))\n    data = self._class_corections(data)\n\n    breeds_sizes = data.groupby('breed').size()\n    valid_breeds = breeds_sizes[breeds_sizes > min_th].index\n\n    data = (\n        data[data.breed.isin(valid_breeds)]\n        .groupby('breed')\n        .apply(lambda x: x.sample(keep_th, replace = True))\n        .reset_index(drop=True)\n        .drop_duplicates()\n        )\n    return data\n\n  def _label_data(self, data: pd.DataFrame):\n    self.le = LabelEncoder()\n    data['breed_id'] = self.le.fit_transform(data['breed'].values)\n    return data\n\n  def _class_corections(self, data: pd.DataFrame):\n    class_corection = {\n        'afghan': 'afghan hound',\n        'airedale': 'airedale terrier',\n        'blenheim': 'blenheim spaniel',\n        'boston bull': 'boston terrier',\n        'chinese crested dog': 'chinese crested',\n        'chow chow': 'chow',\n        'cocker': 'cocker spaniel',\n        'dalmation': 'dalmatian',\n        'doberman pinscher': 'doberman',\n        'english springer': 'english springer spaniel',\n        'german sheperd': 'german shepherd',\n        'german shepherd dog': 'german shepherd',\n        'german shorthaired': 'german short-haired pointer',\n        'irish spaniel': 'irish water spaniel',\n        'jack russell terrier (parson russell terrier)': 'jack russell terrier',\n        'labrador retriever': 'labrador',\n        'leonberg': 'leonberger',\n        'lhasa': 'lhasa apso',\n        'maltese': 'maltese dog',\n        'mex hairless': 'mexican hairless',\n        'pekinese': 'pekingese',\n        'pit bull': 'pit bull terrier',\n        'rhodesian': 'rhodesian ridgeback',\n        'scottish terrier scottie': 'scottish terrier',\n        'shetland sheepdog sheltie': 'shetland sheepdog',\n        'shih tzu': 'shih-tzu',\n        'sphynx (hairless cat)': 'sphynx',\n        'staffordshire bull terrier': 'staffordshire bullterrier',\n        'west highland white terrier westie': 'west highland white terrier',\n        'wire-haired fox terrier': 'wirehaired terrier',\n        'yorkie': 'yorkshire terrier', \n        'yorkshire terrier yorkie': 'yorkshire terrier',\n        }\n    \n    for breed in data['breed'].unique():\n      if breed not in class_corection.keys():\n        class_corection[breed] = breed\n\n    data['breed'] = data['breed'].map(class_corection)\n    return data\n\n  @staticmethod\n  def get_label_weights(data: pd.DataFrame, device: str):\n    label_count = (\n        data['breed_id']\n        .value_counts()\n        .to_frame()\n        .sort_index()\n        .values\n    )\n    weigths = torch.from_numpy(np.power(label_count, -1.)).float().squeeze()\n    return weigths.to(device)\n\n  @staticmethod\n  def cat_breeds_oxford_data(path: Path):\n    with open(path/'annotations/annotations/list.txt', 'r') as f:\n      for _ in range(6):\n        f.readline()\n      cats_oxford = pd.read_csv(f, sep=\" \", header=None)\n\n      cats_oxford.columns = [\"id\", \"CLASS-ID\", \"SPECIES\", \"BREED-ID\"]\n      cats_oxford['breed'] = cats_oxford['id'].apply(lambda x: ' '.join(x.split('_')[:-1]))\n      cats_oxford['data_source'] = 'cats_oxford'\n      cats_oxford['filepath'] = cats_oxford['id'].apply(lambda x: path/f'images/images/{x}.jpg')\n    return cats_oxford\n\n  @staticmethod\n  def cat_breeds_petfinder_data(path: Path):\n    cats = {'id': [], 'breed': [], 'filepath': []}\n    for path in glob(os.path.join(path, 'images/*/*.jpg')):\n      breed, id = path.split('/')[-2:]\n      id = id.rstrip('.jpg')\n      \n      cats_petfinder['id'].append(id)\n      cats_petfinder['breed'].append(breed)\n      cats_petfinder['filepath'].append(path)\n      \n      cats_petfinder = pd.DataFrame(cats)\n      cats_petfinder['data_source'] = 'cats_petfinder'\n    return cats_petfinder\n\n  @staticmethod\n  def dog_breeds_data(path: Path):\n    dogs = pd.read_csv(path/'dogs.csv')\n    dogs['data_source'] = 'dog_breeds'\n    dogs['filepath'] = dogs['filepaths'].apply(lambda x: path/x)\n    dogs.rename(columns = {'labels': 'breed'}, inplace = True)\n    return dogs\n\n  @staticmethod\n  def dog_breeds_kaggle_data(path: Path):\n    dogs_kaggle = pd.read_csv(path/'labels.csv')\n    dogs_kaggle['filepath'] = dogs_kaggle['id'].apply(lambda x: path/f'train/{x}.jpg')\n    dogs_kaggle['data_source'] = 'dogs_kaggle'\n    return dogs_kaggle\n\n  @staticmethod\n  def petfinder_old_data(path: Path):\n    train_petfinder = pd.read_csv(path/'train/train.csv')\n    mappings = pd.read_csv(path/'breed_labels.csv')\n    mappings = (\n        mappings[['BreedID', 'BreedName']]\n        .set_index('BreedID')\n        .to_dict()['BreedName']\n    )\n\n    train_petfinder['breed'] = train_petfinder['Breed1'].map(mappings)\n    train_petfinder['filepath'] = train_petfinder['PetID'].apply(lambda x: path/f'{x}-1.jpg')\n    train_petfinder['data_source'] = 'petfinder_old'\n\n    most_common = train_petfinder['breed'].value_counts().index[0]\n    train_petfinder['breed'] = train_petfinder['breed'].fillna(most_common)\n    return train_petfinder","metadata":{"execution":{"iopub.status.busy":"2021-11-08T16:37:03.882934Z","iopub.execute_input":"2021-11-08T16:37:03.883249Z","iopub.status.idle":"2021-11-08T16:37:03.918012Z","shell.execute_reply.started":"2021-11-08T16:37:03.883218Z","shell.execute_reply":"2021-11-08T16:37:03.916891Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class BreedDataset(Dataset):\n  def __init__(self, df: pd.DataFrame, img_size = (224, 224), transforms = None):\n    self.df = self._make_dataset(df)\n    self.img_size = img_size\n    self.transforms = self.__transforms(transforms)\n\n  def _make_dataset(self, df):\n    print('dropping wrong images...')\n    for i, row in df.iterrows():\n      img = self.read_img(row.filepath)\n      if not isinstance(img, np.ndarray):\n        df.drop(axis = 0, index = i, inplace = True)\n    return df\n\n  def __transforms(self, transforms):\n    if transforms is None:\n      transforms = A.Compose([\n                       A.Resize(*self.img_size),\n                       A.Normalize(\n                           mean = [0.485, 0.456, 0.406],\n                           std = [0.229, 0.224, 0.225],\n                           always_apply = True\n                           ),\n                       ToTensorV2(),\n                       ])\n    return transforms\n\n  def __len__(self):\n    return len(self.df)\n\n  def __getitem__(self, indx):\n    path = self.df.iloc[indx].filepath\n    label = self.df.iloc[indx].breed_id\n    img = self.prepare_img(path)\n    return img, label\n\n  @staticmethod\n  def read_img(path):\n    if isinstance(path, Path):\n      path = path.as_posix()\n    img = cv2.imread(path)\n    if isinstance(img, np.ndarray): \n      img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    return img\n\n  def prepare_img(self, path):\n    img = self.read_img(path)\n    img = self.transforms(image=img)['image']\n    return img","metadata":{"execution":{"iopub.status.busy":"2021-11-08T16:37:04.425474Z","iopub.execute_input":"2021-11-08T16:37:04.425962Z","iopub.status.idle":"2021-11-08T16:37:04.445013Z","shell.execute_reply.started":"2021-11-08T16:37:04.425917Z","shell.execute_reply":"2021-11-08T16:37:04.443846Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CustomDataModule(LightningDataModule):\n  def __init__(\n      self,\n      data: DogsCatsData,\n      transforms: A.Compose = None,\n      weights = None,\n      test_size = 0.25,\n      img_size = (224, 224),\n      batch_size = 64\n      ):\n    super().__init__()\n    self.train_df, self.val_df = self.split_data(data, test_size)\n    self.batch_size = batch_size\n    self.transforms = transforms\n    self.img_size = img_size\n    self.weights = weights\n\n  @staticmethod\n  def split_data(data, test_size):\n    train_df, val_df = train_test_split(\n        data,\n        test_size = test_size,\n        random_state = 2021,\n        )\n    return train_df, val_df\n\n  def train_dataloader(self):\n    train_split = BreedDataset(\n        self.train_df, \n        self.img_size, \n        self.transforms\n        )\n    return DataLoader(\n        train_split,\n        batch_size=self.batch_size, \n        shuffle=True, \n        num_workers=4,\n        )\n\n  def val_dataloader(self):\n    val_split = BreedDataset(self.val_df, self.img_size)\n    return DataLoader(\n        val_split, \n        batch_size=self.batch_size, \n        shuffle=False,\n        num_workers=4,\n        )","metadata":{"execution":{"iopub.status.busy":"2021-11-08T16:37:04.660364Z","iopub.execute_input":"2021-11-08T16:37:04.660991Z","iopub.status.idle":"2021-11-08T16:37:04.673159Z","shell.execute_reply.started":"2021-11-08T16:37:04.660936Z","shell.execute_reply":"2021-11-08T16:37:04.671942Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CustomModel(LightningModule):\n  def __init__(self, cfg):\n    super().__init__()\n    self.cfg = cfg\n    self.__build_model()\n    self.save_hyperparameters(cfg)\n\n  def __build_model(self):\n    self.backbone = create_model(\n        self.cfg.model_name, \n        drop_rate = self.cfg.dropout_backbone, \n        pretrained=True, \n        num_classes=0, \n        in_chans=3\n        )\n    self.fc = nn.Sequential(\n        nn.Dropout(self.cfg.dropout_fc),\n        nn.LazyLinear(self.cfg.num_classes)\n        )\n    \n  def forward(self, x):\n    f = self.backbone(x)\n    out = self.fc(f)\n    return out\n\n  def configure_optimizers(self):\n    optimizer = eval(self.cfg.optimizer.name)(\n        self.parameters(), \n        **self.cfg.optimizer.params\n        )\n    scheduler = eval(self.cfg.scheduler.name)(\n        optimizer,\n        **self.cfg.scheduler.params\n        )\n    return [optimizer], [scheduler]\n\n  def __share_step(self, batch):\n    img, labels = batch\n    logits = self(img)\n    preds = logits.argmax(dim = -1)\n\n    loss = F.cross_entropy(logits, labels, weight = self.cfg.weights)\n    return loss, labels, preds\n\n  def __share_epoch(self, outputs, stage):\n    def calculate_metrics(preds, labels):\n      accuracy_score = Accuracy(num_classes = self.cfg.num_classes, average = 'macro')\n      f1_score = F1(self.cfg.num_classes, average = 'macro')\n      pr_score = Precision(self.cfg.num_classes, average = 'macro')\n      r_score = Recall(self.cfg.num_classes, average = 'macro')\n\n      accuracy = accuracy_score(preds, labels)\n      f1 = f1_score(preds, labels)\n      precision = pr_score(preds, labels)\n      recall = r_score(preds, labels)\n      return {\n          'accuracy': accuracy, \n          'f1': f1, \n          'precision': precision, \n          'recall': recall\n          }\n\n    preds = torch.cat([out['preds'] for out in outputs]).cpu()\n    labels = torch.cat([out['labels'] for out in outputs]).cpu()\n\n    metrics = calculate_metrics(preds, labels)\n    for k, v in metrics.items():\n      self.log(f'{stage}_{k}', v)\n\n  def training_step(self, batch, batch_idx):\n    loss, labels, preds = self.__share_step(batch)\n    self.log('train_loss', loss)\n    return {'loss': loss, 'preds': preds, 'labels': labels}\n        \n  def validation_step(self, batch, batch_idx):\n    loss, labels, preds = self.__share_step(batch)\n    self.log('val_loss', loss)\n    return {'loss': loss, 'preds': preds, 'labels': labels}\n\n  def training_epoch_end(self, outputs):\n    self.__share_epoch(outputs, 'train')\n\n  def validation_epoch_end(self, outputs):\n    self.__share_epoch(outputs, 'val')\n\n  def predict_step(self, batch, batch_idx, dataloader_idx=0):\n    img, labels = batch\n    return self(img)","metadata":{"execution":{"iopub.status.busy":"2021-11-08T16:37:04.990396Z","iopub.execute_input":"2021-11-08T16:37:04.991146Z","iopub.status.idle":"2021-11-08T16:37:05.014058Z","shell.execute_reply.started":"2021-11-08T16:37:04.991109Z","shell.execute_reply":"2021-11-08T16:37:05.012709Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class ImagePredictionLogger(callbacks.Callback):\n    def __init__(self, val_samples):\n        super().__init__()\n        self.val_imgs, self.val_labels = val_samples\n\n    def on_validation_epoch_end(self, trainer, pl_module):\n        val_imgs = self.val_imgs.to(device=pl_module.device)\n        val_labels = self.val_labels.to(device=pl_module.device)\n        \n        logits = pl_module(val_imgs)\n        preds = torch.argmax(logits, -1)\n\n        trainer.logger.experiment.log({\n            \"examples\":[wandb.Image(x, caption=f\"Pred:{pred}, Label:{y}\") \n                           for x, pred, y in zip(val_imgs, \n                                                 preds, \n                                                 val_labels)]\n            })","metadata":{"execution":{"iopub.status.busy":"2021-11-08T16:37:05.400026Z","iopub.execute_input":"2021-11-08T16:37:05.400648Z","iopub.status.idle":"2021-11-08T16:37:05.409211Z","shell.execute_reply.started":"2021-11-08T16:37:05.400598Z","shell.execute_reply":"2021-11-08T16:37:05.407831Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Main config for the model. You can play with parameters and model name.","metadata":{}},{"cell_type":"code","source":"cfg = {\n    'model_name': 'swin_tiny_patch4_window7_224',\n    'dropout_backbone': 0,\n    'dropout_fc': 0,\n    'epoch': 3,\n    'batch_size': 64,\n    'img_size': (224, 224),\n    'test_size': 0.2,\n    'device': 'cuda:0',\n    'weights': None,\n    'optimizer':{\n        'name': 'optim.AdamW',\n        'params':{\n            'lr': 1e-4,\n            #'weight_decay': 1e-4,\n        },\n    },\n    'scheduler':{\n        'name': 'optim.lr_scheduler.CosineAnnealingWarmRestarts',\n        'params':{\n            'T_0': 10,\n            'eta_min': 1e-6\n        },\n    },\n    'logger': {\n        'save_dir': './',\n        'name': 'swin_tiny_breed',\n        'project': 'Breeds',\n        'log_model': True,\n    },\n    'trainer': {\n        'gpus': 1,\n        'accumulate_grad_batches': 1,\n        'auto_lr_find': False,\n        'progress_bar_refresh_rate': 3,\n        'fast_dev_run': False,\n        'num_sanity_val_steps': 2,\n        'resume_from_checkpoint': None,\n    },\n}\ncfg = Box(cfg)","metadata":{"execution":{"iopub.status.busy":"2021-11-08T16:39:37.057065Z","iopub.execute_input":"2021-11-08T16:39:37.057407Z","iopub.status.idle":"2021-11-08T16:39:37.069156Z","shell.execute_reply.started":"2021-11-08T16:39:37.057375Z","shell.execute_reply":"2021-11-08T16:39:37.067817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_transforms = A.Compose([\n                 A.HorizontalFlip(p = 0.5),\n                 A.VerticalFlip(p = 0.5),\n                 A.RandomBrightnessContrast(p=0.3),\n                 A.ShiftScaleRotate(p=0.3),\n                 A.Resize(height=cfg.img_size[0], width=cfg.img_size[1]),\n                 A.Normalize(\n                     mean = [0.485, 0.456, 0.406],\n                     std = [0.229, 0.224, 0.225],\n                     always_apply = True\n                     ),\n                 ToTensorV2(),                                \n                 ])","metadata":{"execution":{"iopub.status.busy":"2021-11-08T16:39:38.247754Z","iopub.execute_input":"2021-11-08T16:39:38.248484Z","iopub.status.idle":"2021-11-08T16:39:38.26006Z","shell.execute_reply.started":"2021-11-08T16:39:38.248438Z","shell.execute_reply":"2021-11-08T16:39:38.258236Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"I used WandbLogger to log results because it's convenient and easy but you can skip it and don't add.","metadata":{}},{"cell_type":"code","source":"data = DogsCatsData(paths, columns).get_data()\ncfg.num_classes = data['breed'].nunique()\ncfg.train_transforms = train_transforms\n#cfg.weights = DogsCatsData.get_label_weights(data, cfg.device)\n\nmodel = CustomModel(cfg)\ndatamodule = CustomDataModule(\n    data, \n    cfg.train_transforms, \n    cfg.weights,\n    cfg.test_size, \n    cfg.img_size,\n    cfg.batch_size\n    )\n\nval_samples = next(iter(datamodule.val_dataloader()))\nimg_predictions = ImagePredictionLogger(val_samples)\nearystopping = EarlyStopping(monitor=\"val_loss\", patience = 3)\nlr_monitor = callbacks.LearningRateMonitor('step')\n\nloss_checkpoint = callbacks.ModelCheckpoint(\n    dirpath = os.path.join(cfg.logger.save_dir, cfg.logger.name),\n    filename=cfg.logger.name,\n    monitor=\"val_loss\",\n    save_top_k=1,\n    mode=\"min\",\n    save_last=False,\n    )\nwandb_logger = WandbLogger(\n    name = cfg.logger.name,\n    project = cfg.logger.project,\n    log_model = True,\n    )","metadata":{"execution":{"iopub.status.busy":"2021-11-08T16:39:38.947287Z","iopub.execute_input":"2021-11-08T16:39:38.947603Z","iopub.status.idle":"2021-11-08T16:40:29.597668Z","shell.execute_reply.started":"2021-11-08T16:39:38.947565Z","shell.execute_reply":"2021-11-08T16:40:29.596403Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"try:\n    from kaggle_secrets import UserSecretsClient\n    user_secrets = UserSecretsClient()\n    secret_value_0 = user_secrets.get_secret(\"api_key\")\n    wandb.login(key=secret_value_0)\nexcept:\n    raise RuntimeError('If you want to use your W&B account, go to Add-ons -> Secrets and provide your W&B access token. Use the Label name as wandb_api. \\nGet your W&B access token from here: https://wandb.ai/authorize')","metadata":{"execution":{"iopub.status.busy":"2021-11-08T19:10:42.041246Z","iopub.execute_input":"2021-11-08T19:10:42.041605Z","iopub.status.idle":"2021-11-08T19:10:44.6341Z","shell.execute_reply.started":"2021-11-08T19:10:42.041569Z","shell.execute_reply":"2021-11-08T19:10:44.632934Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Training","metadata":{}},{"cell_type":"code","source":"trainer = pl.Trainer(\n      max_epochs=cfg.epoch,\n      logger = wandb_logger,\n      callbacks=[\n            lr_monitor, \n            loss_checkpoint, \n            earystopping,\n            img_predictions,\n            ],\n      deterministic=True,\n      **cfg.trainer,\n      )\ntrainer.fit(model, datamodule=datamodule)\nwandb.finish()","metadata":{"execution":{"iopub.status.busy":"2021-11-08T16:40:29.622091Z","iopub.execute_input":"2021-11-08T16:40:29.622888Z","iopub.status.idle":"2021-11-08T16:55:31.22921Z","shell.execute_reply.started":"2021-11-08T16:40:29.62284Z","shell.execute_reply":"2021-11-08T16:55:31.227852Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Inference","metadata":{}},{"cell_type":"markdown","source":"There are functions to get results from the model. This is a slow implementation, so you can change this code a little bit and add dataloaders in order to do inference with batches.","metadata":{}},{"cell_type":"code","source":"def get_logits(path):  \n    model.eval()\n    model.cuda()\n    \n    with torch.no_grad():\n        img = BreedDataset.read_img(path)\n        img = train_transforms(image = img)['image']\n        logits = model(img.unsqueeze(0).cuda()).cpu()\n        top_pred = logits.argmax(dim = -1)\n        \n    output = torch.cat([logits.squeeze(), top_pred]).numpy()\n    return output\n\ndef get_breeds(path, train_or_test = 'train'):\n    inf_model = ModelInference()\n    df = pd.read_csv(path)\n    \n    df.loc[:, 'path'] = (\n        df['Id']\n        .apply(lambda x: os.path.join(f'../input/petfinder-pawpularity-score/{train_or_test}', f'{x}.jpg'))\n        )\n    df.loc[:, [f'feature_{i}' for i in range(data.breed_id.nunique())] + ['breed_id']] = np.vstack(\n        df['path'].progress_apply(get_logits).values\n    )\n    df.loc[:, ['cat', 'dog']] = np.vstack(\n        df['path'].progress_apply(lambda x: inf_model(x)).values\n    )\n    return df","metadata":{"execution":{"iopub.status.busy":"2021-11-08T18:02:41.132982Z","iopub.execute_input":"2021-11-08T18:02:41.133614Z","iopub.status.idle":"2021-11-08T18:02:41.157522Z","shell.execute_reply.started":"2021-11-08T18:02:41.133513Z","shell.execute_reply":"2021-11-08T18:02:41.156211Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_pawpularity_df = get_breeds('../input/petfinder-pawpularity-score/train.csv', 'train')\ntest_pawpularity_df = get_breeds('../input/petfinder-pawpularity-score/test.csv', 'test')","metadata":{"execution":{"iopub.status.busy":"2021-11-08T18:03:33.107798Z","iopub.execute_input":"2021-11-08T18:03:33.108144Z","iopub.status.idle":"2021-11-08T18:18:58.651997Z","shell.execute_reply.started":"2021-11-08T18:03:33.108104Z","shell.execute_reply":"2021-11-08T18:18:58.650792Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train, X_val, y_train, y_val = train_test_split(\n    train_pawpularity_df.drop(columns = ['Id', 'path', 'Pawpularity']), \n    train_pawpularity_df['Pawpularity'], \n    stratify = train_pawpularity_df['Pawpularity'],\n    test_size = 0.2\n)\n\nlgbm = LGBMRegressor(max_depth=4, n_estimators=100, learning_rate= 0.08)\nlgbm.fit(X_train, y_train)\nprint(np.sqrt(mean_squared_error(y_val, lgbm.predict(X_val))))","metadata":{"execution":{"iopub.status.busy":"2021-11-08T18:19:09.474633Z","iopub.execute_input":"2021-11-08T18:19:09.474927Z","iopub.status.idle":"2021-11-08T18:19:11.102365Z","shell.execute_reply.started":"2021-11-08T18:19:09.474896Z","shell.execute_reply":"2021-11-08T18:19:11.101289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_pawpularity_df['Pawpularity'] = lgbm.predict(test_pawpularity_df.drop(columns = ['Id', 'path']))\ntest_pawpularity_df[['Id', 'Pawpularity']].to_csv('./submission.csv', index = False)","metadata":{"execution":{"iopub.status.busy":"2021-11-08T18:22:04.190861Z","iopub.execute_input":"2021-11-08T18:22:04.191149Z","iopub.status.idle":"2021-11-08T18:22:04.202932Z","shell.execute_reply.started":"2021-11-08T18:22:04.191117Z","shell.execute_reply":"2021-11-08T18:22:04.201859Z"},"trusted":true},"execution_count":null,"outputs":[]}]}