{"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":"code","source":"# Импорт библиотек\nimport sys\nsys.path.append('../input/timm-pytorch-image-models/pytorch-image-models-master')\nimport timm","metadata":{"execution":{"iopub.status.busy":"2022-04-02T13:58:30.220909Z","iopub.execute_input":"2022-04-02T13:58:30.22118Z","iopub.status.idle":"2022-04-02T13:58:30.226377Z","shell.execute_reply.started":"2022-04-02T13:58:30.221151Z","shell.execute_reply":"2022-04-02T13:58:30.225671Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport torch\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pytorch_lightning as pl\nfrom pytorch_lightning.plugins import DDPPlugin\nimport warnings\nfrom torch.utils.data import Dataset, DataLoader\nimport pandas as pd\nfrom torchmetrics import Accuracy\nfrom sklearn.model_selection import train_test_split\nimport albumentations as A\nimport cv2\nimport torch.nn as nn\n\n# warnings.filterwarnings(\"ignore\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-04-02T13:58:38.23661Z","iopub.execute_input":"2022-04-02T13:58:38.236925Z","iopub.status.idle":"2022-04-02T13:58:40.648332Z","shell.execute_reply.started":"2022-04-02T13:58:38.236894Z","shell.execute_reply":"2022-04-02T13:58:40.647638Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"config = {\n    'model_name': 'tf_mobilenetv3_small_minimal_100',\n    'train_image_folder': '../input/resized-plant2021/img_sz_256',\n    'test_image_folder': '../input/plant-pathology-2021-fgvc8/test_images',\n    # 'train_dataframe': '../input/sorghum-id-fgvc-9/train_cultivar_mapping.csv',\n    'train_dataframe': '../input/plant-pathology-2021-fgvc8/train.csv',\n    'test_dataframe': '../input/plant-pathology-2021-fgvc8/sample_submission.csv',\n    'lable_column': 'labels',\n    'batch_size': 120,\n    'size': (256, 256),\n    'train': True,\n}","metadata":{"execution":{"iopub.status.busy":"2022-04-02T13:58:40.649434Z","iopub.execute_input":"2022-04-02T13:58:40.649709Z","iopub.status.idle":"2022-04-02T13:58:40.657692Z","shell.execute_reply.started":"2022-04-02T13:58:40.649673Z","shell.execute_reply":"2022-04-02T13:58:40.654683Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Аугментация\ndef get_augmentations(augmentation):\n    \n    w, h = config['size'][0], config['size'][1]\n    if augmentation == 'base':\n        transform = [\n        A.Resize(w, h, p=1),\n        A.Transpose(p=0.5),\n        A.VerticalFlip(p=0.5),\n        A.HorizontalFlip(p=0.5),\n        A.ShiftScaleRotate(p=0.5),\n        A.Cutout(max_h_size=int(h * 0.3), max_w_size=int(w * 0.3), num_holes=1, p=0.5),\n        A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225], max_pixel_value=255.0, p=1.0),  \n        ]      \n    else:\n        transform = [\n        A.Resize(w, h, p=1),\n        A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225], max_pixel_value=255.0, p=1.0),     \n        ] \n    return A.Compose(transform)","metadata":{"execution":{"iopub.status.busy":"2022-04-02T13:58:40.661902Z","iopub.execute_input":"2022-04-02T13:58:40.6625Z","iopub.status.idle":"2022-04-02T13:58:40.692302Z","shell.execute_reply.started":"2022-04-02T13:58:40.662458Z","shell.execute_reply":"2022-04-02T13:58:40.691608Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class SorghumDataset(Dataset):\n    def __init__(self, df, test, augmentations):\n        if test:\n            self.image_paths = df['image'].to_list()\n            self.targets = np.zeros(len(df))\n        else:\n            self.image_paths = df['image'].to_list()\n            self.targets = df['id'].to_list()\n            \n        self.augmentations = get_augmentations(augmentations)\n        \n    def __len__(self):\n        return len(self.image_paths)\n    \n    def __getitem__(self, item):\n        \n        image = cv2.imread(self.image_paths[item])\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        \n        if self.augmentations is not None:\n            augmented = self.augmentations(image=image)\n            image = augmented[\"image\"]\n            \n        image = np.transpose(image, (2, 0, 1)).astype(np.float32)\n        targets = self.targets[item]\n        \n        return torch.tensor(image), torch.tensor(targets)","metadata":{"execution":{"iopub.status.busy":"2022-04-02T13:58:40.693469Z","iopub.execute_input":"2022-04-02T13:58:40.694229Z","iopub.status.idle":"2022-04-02T13:58:40.704086Z","shell.execute_reply.started":"2022-04-02T13:58:40.694192Z","shell.execute_reply":"2022-04-02T13:58:40.703283Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class LoaderGenerator:\n    def __init__(self, config):\n        self.batch_size = config['batch_size']\n        self.train_image_folder = config['train_image_folder']\n        self.test_image_folder = config['test_image_folder']\n        \n        self.train_dataframe = pd.read_csv(config['train_dataframe'])\n        self.test_dataframe = pd.read_csv(config['test_dataframe'])\n        \n        self.lable = config['lable_column']\n        \n        self.train_dataframe = self.label_encoder(self.train_dataframe)\n        self.class_map = dict(sorted(self.train_dataframe[['id', self.lable]].values.tolist()))\n        self.train_dataframe = self.train_dataframe[['image', 'id']]\n        \n        self.train_val_prepare()\n        self.test_prepare()\n        \n    def label_encoder(self, df):\n        from sklearn import preprocessing\n        le = preprocessing.LabelEncoder()\n        le.fit(df[self.lable])\n        df['id'] = le.transform(df[self.lable])        \n        return df\n                \n    def train_val_prepare(self):\n        self.train_dataframe['image'] =  self.train_image_folder + '/' + self.train_dataframe['image']\n        self.train_dataframe, self.val_dataframe = train_test_split(self.train_dataframe, test_size=0.3, stratify=self.train_dataframe['id'], shuffle=True, random_state=107)\n    \n    def test_prepare(self):\n        self.test_dataframe = self.test_dataframe.rename(columns={\"filename\": \"image\"})\n        self.test_dataframe['image'] =  self.test_image_folder + '/' + self.test_dataframe['image']\n        \n    def loader(self, df, test, augmentations, batch_size, drop_last, shuffle):\n        dataset = SorghumDataset(df, test, augmentations)\n        loader = DataLoader(dataset, batch_size=batch_size, num_workers=2, drop_last=drop_last, shuffle=shuffle)\n        return loader\n\n    def get_loaders(self, aug):\n        train_loader = self.loader(df=self.train_dataframe, test=False,\n                                   augmentations=aug, batch_size=self.batch_size, drop_last=False, shuffle=True)\n        val_loader = self.loader(df=self.val_dataframe, test=False,\n                                 augmentations=False, batch_size=self.batch_size, drop_last=False, shuffle=False)\n        test_loader = self.loader(df=self.test_dataframe, test=True,\n                                 augmentations=False, batch_size=self.batch_size, drop_last=False, shuffle=False)\n        return train_loader, val_loader, test_loader, self.class_map","metadata":{"execution":{"iopub.status.busy":"2022-04-02T13:58:40.705466Z","iopub.execute_input":"2022-04-02T13:58:40.7059Z","iopub.status.idle":"2022-04-02T13:58:40.721773Z","shell.execute_reply.started":"2022-04-02T13:58:40.705865Z","shell.execute_reply":"2022-04-02T13:58:40.720986Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_config = {\n    'model_name': 'tf_mobilenetv3_small_minimal_100',\n    'train_image_folder': '../input/resized-plant2021/img_sz_256',\n    'test_image_folder': '../input/plant-pathology-2021-fgvc8/test_images',\n    # 'train_dataframe': '../input/sorghum-id-fgvc-9/train_cultivar_mapping.csv',\n    'train_dataframe': '../input/plant-pathology-2021-fgvc8/train.csv',\n    'test_dataframe': '../input/plant-pathology-2021-fgvc8/sample_submission.csv',\n    'lable_column': 'labels',\n    'batch_size': 1,\n    'size': (256, 256),\n    'train': True,\n}\n\n#Show Augmentation\n%matplotlib inline\nplt.rcParams['figure.figsize'] = (20,20)\n\nloader_generator = LoaderGenerator(show_config)\ntrain_loader, _, _, _ = loader_generator.get_loaders('base')\n  \nfor num, (image, label) in enumerate(train_loader):\n    image = image.cpu()[0]\n    label = label.cpu()[0]\n    plt.subplot(5, 5, num+1)\n    plt.title(f'label: {label}')\n    plt.imshow(image.permute(1,2,0) * np.array([0.229, 0.224, 0.225]) + np.array([0.485, 0.456, 0.406]))\n    if num == 24:\n        break","metadata":{"execution":{"iopub.status.busy":"2022-04-02T13:58:40.723018Z","iopub.execute_input":"2022-04-02T13:58:40.723438Z","iopub.status.idle":"2022-04-02T13:58:45.109487Z","shell.execute_reply.started":"2022-04-02T13:58:40.723402Z","shell.execute_reply":"2022-04-02T13:58:45.108703Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.optim import Adamax\n\ndef get_optimizer(name, parameters, learning_rate):\n    if name == 'Adamax':\n        optimizer = Adamax(parameters, lr=learning_rate)\n    return optimizer","metadata":{"execution":{"iopub.status.busy":"2022-04-02T13:58:45.110686Z","iopub.execute_input":"2022-04-02T13:58:45.110991Z","iopub.status.idle":"2022-04-02T13:58:45.116311Z","shell.execute_reply.started":"2022-04-02T13:58:45.110944Z","shell.execute_reply":"2022-04-02T13:58:45.115755Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.nn import CrossEntropyLoss\n\ndef get_loss(name):\n    if name == 'CrossEntropyLoss':\n        loss = CrossEntropyLoss()\n    return loss","metadata":{"execution":{"iopub.status.busy":"2022-04-02T13:58:45.117579Z","iopub.execute_input":"2022-04-02T13:58:45.118087Z","iopub.status.idle":"2022-04-02T13:58:45.125378Z","shell.execute_reply.started":"2022-04-02T13:58:45.118053Z","shell.execute_reply":"2022-04-02T13:58:45.12483Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CustomModel(nn.Module):\n    def __init__(self, model_name, pretrained=False, num_classes=100):\n        super().__init__()\n        self.model = timm.create_model(model_name, pretrained=pretrained)\n        print('classifier', num_classes)\n        self.model.classifier = nn.Linear(self.model.classifier.in_features, num_classes)\n        # self.model.head = nn.Linear(self.model.head.in_features, feature_num)\n    def forward(self, x):\n        x = self.model(x)\n        return x","metadata":{"execution":{"iopub.status.busy":"2022-04-02T13:58:45.127864Z","iopub.execute_input":"2022-04-02T13:58:45.128358Z","iopub.status.idle":"2022-04-02T13:58:45.137011Z","shell.execute_reply.started":"2022-04-02T13:58:45.128266Z","shell.execute_reply":"2022-04-02T13:58:45.136273Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Model(pl.LightningModule):\n    def __init__(self, config, learning_rate, name_loss, name_optimizer, aug):\n        super(Model, self).__init__()\n        self.aug = aug\n        self.loader_generator = LoaderGenerator(config)\n        self.train_loader, self.val_loader, self.test_loader, self.class_map = self.loader_generator.get_loaders(self.aug)\n        self.model_name = config['model_name']\n        self.name_optimizer = name_optimizer\n        self.name_loss = name_loss\n        self.learning_rate = learning_rate\n        self.n_classes = len(self.class_map)\n        self.load_model()\n        self.loss = get_loss(name_loss)\n        self.metric_train = Accuracy()\n        self.metric_val = Accuracy()\n        self.result = []\n        self.submission = pd.read_csv(config['test_dataframe'])\n\n    def load_model(self):\n        # self.model = timm.create_model(self.model_name, pretrained=True)\n        self.model = CustomModel(self.model_name, pretrained=False, num_classes=self.n_classes)\n        # self.model = torch.load('model.pth', map_location='cuda')\n        \n    def forward(self, x):\n        x = self.model(x)\n        return x\n    \n    def log_scores(self, scores, status, score_name):\n        self.log(f'{status}_{score_name}', scores, on_step=False, on_epoch=True,\n                 prog_bar=True, logger=True, sync_dist=True)\n        \n    def training_step(self, batch, batch_idx):\n        x, y = batch\n        logits = self(x)\n        loss = self.loss(logits, y)\n        self.log('train_loss', loss, on_step=False, on_epoch=True, prog_bar=False, logger=True)\n        preds_class = torch.argmax(logits, 1)\n        self.metric_train.update(preds_class, y)\n        return loss\n\n    def training_epoch_end(self, outputs):\n        acc = self.metric_train.compute()\n        self.log_scores(acc, status='train', score_name='acc')\n\n    def validation_step(self, batch, batch_idx):\n        x, y = batch\n        logits = self(x)\n        loss = self.loss(logits, y)\n        self.log('val_loss', loss, on_step=False, on_epoch=True, prog_bar=False, logger=True, sync_dist=True)\n        preds_class = torch.argmax(logits, 1)\n        self.metric_val.update(preds_class, y)\n        return loss\n\n    def validation_epoch_end(self, outputs):\n        acc = self.metric_val.compute()\n        self.log_scores(acc, status='val', score_name='acc')\n        torch.save(self.model, 'model.pth')\n\n    def test_step(self, batch, batch_idx):\n        x, y = batch\n        logits = self(x)\n        preds_class = torch.argmax(logits, 1)\n        self.result.extend(preds_class.tolist())\n\n    def test_epoch_end(self, outputs):\n        self.submission['cultivar'] = self.result\n        self.submission['cultivar'] = self.submission['cultivar'].map(self.class_map)\n        self.submission.to_csv('submission.csv', index=False)\n\n    def configure_optimizers(self):\n        optimizer = get_optimizer(name=self.name_optimizer, parameters=self.parameters(),\n                            learning_rate=self.learning_rate)\n        lr_scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, factor=0.1, patience=3)\n        scheduler = {'scheduler': lr_scheduler, 'reduce_on_plateau': True,\n                     'monitor': 'val_loss', 'name': 'lr_value'}\n        return [optimizer], [scheduler]\n\n    def train_dataloader(self):\n        return self.train_loader\n\n    def val_dataloader(self):\n        return self.val_loader\n    \n    def test_dataloader(self):\n        return self.test_loader","metadata":{"execution":{"iopub.status.busy":"2022-04-02T13:58:45.138405Z","iopub.execute_input":"2022-04-02T13:58:45.138939Z","iopub.status.idle":"2022-04-02T13:58:45.167296Z","shell.execute_reply.started":"2022-04-02T13:58:45.138904Z","shell.execute_reply":"2022-04-02T13:58:45.16667Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_callbacks():\n    lr_callback = pl.callbacks.LearningRateMonitor(logging_interval='epoch')\n    bar_callback = pl.callbacks.TQDMProgressBar(refresh_rate=1, process_position=0)\n    checkpoint_callback = pl.callbacks.ModelCheckpoint(monitor='val_acc',\n                                                       filename='{epoch:02d}-{val_acc:.3f}',\n                                                       save_top_k=1,\n                                                       mode='max',\n                                                       every_n_epochs=1)\n    callbacks = [lr_callback, bar_callback, checkpoint_callback]\n    return callbacks","metadata":{"execution":{"iopub.status.busy":"2022-04-02T13:58:45.168988Z","iopub.execute_input":"2022-04-02T13:58:45.169441Z","iopub.status.idle":"2022-04-02T13:58:45.180188Z","shell.execute_reply.started":"2022-04-02T13:58:45.169406Z","shell.execute_reply":"2022-04-02T13:58:45.179318Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trainer = pl.Trainer(\n    benchmark=True,\n    sync_batchnorm=True,\n    gpus=-1,\n    num_nodes=1,\n    log_every_n_steps=1,\n    max_epochs=2,\n    num_sanity_val_steps=0,\n    callbacks=get_callbacks(),\n)   \n\nif config['train']:\n    model = Model(config=config, learning_rate=0.001, name_loss='CrossEntropyLoss', name_optimizer='Adamax', aug = 'base')\n    trainer.fit(model)\nelse:\n    model = Model.load_from_checkpoint('../input/sorghum-model/epoch191-step19775.ckpt', config=config, learning_rate=0.001, name_loss='CrossEntropyLoss', name_optimizer='Adamax', aug = 'test')\n    trainer.test(model)","metadata":{"execution":{"iopub.status.busy":"2022-04-02T13:58:45.181695Z","iopub.execute_input":"2022-04-02T13:58:45.182164Z","iopub.status.idle":"2022-04-02T14:00:43.581127Z","shell.execute_reply.started":"2022-04-02T13:58:45.182126Z","shell.execute_reply":"2022-04-02T14:00:43.576574Z"},"trusted":true},"execution_count":null,"outputs":[]}]}