{"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":"!pip install -q efficientnet_pytorch","metadata":{"execution":{"iopub.status.busy":"2022-11-04T11:49:17.278198Z","iopub.execute_input":"2022-11-04T11:49:17.279659Z","iopub.status.idle":"2022-11-04T11:49:26.495687Z","shell.execute_reply.started":"2022-11-04T11:49:17.279614Z","shell.execute_reply":"2022-11-04T11:49:26.494530Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport time\n\nimport numpy as np \nimport pandas as pd\nimport cv2\nimport matplotlib.pyplot as plt\nimport albumentations as A\nfrom albumentations import pytorch as ATorch\nimport torch\nfrom torch import nn\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision.io import read_image\nfrom efficientnet_pytorch import EfficientNet\nfrom sklearn.model_selection import train_test_split","metadata":{"execution":{"iopub.status.busy":"2022-07-01T11:51:23.176572Z","iopub.execute_input":"2022-07-01T11:51:23.176918Z","iopub.status.idle":"2022-07-01T11:51:24.532718Z","shell.execute_reply.started":"2022-07-01T11:51:23.176876Z","shell.execute_reply":"2022-07-01T11:51:24.531881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# TODO: add configs\n\nCFG = {\n    \"seed\": 42,\n    \"batch_size\": 16,\n    \"test_size\" : 0.2,\n    \"learning_rate\" : 0.001,\n    \"batch_size\" : 16,\n    \"epochs\" : 25,\n    \n}","metadata":{"execution":{"iopub.status.busy":"2022-07-01T11:51:24.533942Z","iopub.execute_input":"2022-07-01T11:51:24.535094Z","iopub.status.idle":"2022-07-01T11:51:24.539989Z","shell.execute_reply.started":"2022-07-01T11:51:24.535054Z","shell.execute_reply":"2022-07-01T11:51:24.539261Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMG_DIR = \"../input/cassava-leaf-disease-classification/train_images/\"\nANNOTATIONS_FILE = pd.read_csv(\"../input/cassava-leaf-disease-classification/train.csv\")\nMODEL_SAVE_PATH = \"best_model.torch\"","metadata":{"execution":{"iopub.status.busy":"2022-07-01T11:51:24.542279Z","iopub.execute_input":"2022-07-01T11:51:24.542972Z","iopub.status.idle":"2022-07-01T11:51:24.568195Z","shell.execute_reply.started":"2022-07-01T11:51:24.542936Z","shell.execute_reply":"2022-07-01T11:51:24.567527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# TODO: Remove preprocess\n\nclass CassavaImageDataset(Dataset):\n    def __init__(self, annotations_file, img_dir, transform=None):\n        self.img_labels = annotations_file\n        self.img_dir = img_dir\n        self.transform = transform\n       \n    def __len__(self):\n        return len(self.img_labels)\n\n    def __getitem__(self, idx):\n        img_path = os.path.join(self.img_dir, self.img_labels.iloc[idx, 0])\n        image = cv2.imread(img_path)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        label = self.img_labels.iloc[idx, 1]\n        if self.transform:\n            image = self.transform(image=image)['image']\n        \n        return image, label","metadata":{"execution":{"iopub.status.busy":"2022-07-01T11:51:24.569811Z","iopub.execute_input":"2022-07-01T11:51:24.570386Z","iopub.status.idle":"2022-07-01T11:51:24.577825Z","shell.execute_reply.started":"2022-07-01T11:51:24.570351Z","shell.execute_reply":"2022-07-01T11:51:24.576972Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# TODO: Change to effnet\nclass EfficientNetModel(nn.Module):\n    def __init__(self, n_classes=5):\n        super().__init__()\n        self.net = EfficientNet.from_pretrained('efficientnet-b0')\n        self.net._fc = nn.Linear(1280, n_classes)\n\n    def forward(self, x):\n        return self.net(x)","metadata":{"execution":{"iopub.status.busy":"2022-07-01T11:51:24.579635Z","iopub.execute_input":"2022-07-01T11:51:24.580242Z","iopub.status.idle":"2022-07-01T11:51:24.588245Z","shell.execute_reply.started":"2022-07-01T11:51:24.580207Z","shell.execute_reply":"2022-07-01T11:51:24.587472Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Trainer:\n    def __init__(self, model, device, score, loss, optimizer = None):\n        self.model = model\n        self.device = device\n        self.score = score\n        self.loss = loss\n        self.optimizer = optimizer\n        \n    def run(self, train_dataloader, val_dataloader, epochs, save_path):\n        best_score = 0\n        \n        for epoch in range(epochs):\n            train_loss, train_score, train_time = self.train_epoch(train_dataloader)\n            val_loss, val_score, valid_time = self.val_epoch(val_dataloader)\n            \n            print(\n                f\"Epoch {epoch+1}\",\n                f\"Train Loss: {train_loss:.3f}, Train Accuracy: {train_score:.3f}, Time: {train_time} sec.\",\n                f\"Validation Loss: {val_loss:.3f}, Validation Accuracy: {val_score:.3f}, Time: {valid_time} sec.\",\n                f\"------------------------------\",\n                sep=\"\\n\",\n            )\n            \n            if best_score < val_score:\n                best_score = val_score\n                self.save_model(save_path)\n                \n        \n    def train_epoch(self, dataloader):\n        self.model.train()\n        t = time.time()\n        train_loss, train_accuracy = 0, 0\n        \n        for batch, (X, y) in enumerate(dataloader):\n            X, y = X.to(self.device), y.to(self.device)\n            pred = self.model(X)\n            loss = self.loss(pred, y)\n            accuracy = self.score(pred.detach().cpu().numpy(), y.detach().cpu().numpy())\n            train_accuracy, train_loss = update_metrics(train_accuracy, accuracy, train_loss, loss, batch)\n\n            self.optimizer.zero_grad()\n            loss.backward()\n            self.optimizer.step()\n            \n        return train_loss, train_accuracy, int(time.time() - t)\n\n        \n    def val_epoch(self, dataloader):\n        self.model.eval()\n        t = time.time()\n        val_loss, val_accuracy = 0, 0\n\n        with torch.no_grad():\n            for batch, (X, y) in enumerate(dataloader):\n                X, y = X.to(self.device), y.to(self.device)\n                pred = self.model(X)\n                loss = self.loss(pred, y)\n                accuracy = self.score(pred, y)\n                val_accuracy, val_loss = update_metrics(val_accuracy, accuracy, val_loss, loss, batch)\n                \n        return val_loss, val_accuracy, int(time.time() - t)\n\n    \n    def save_model(self, save_path):\n        torch.save(\n            {\n                \"model_state_dict\": self.model.state_dict(),\n            },\n            save_path,\n        )\n        \n        \n        ","metadata":{"execution":{"iopub.status.busy":"2022-07-01T11:51:24.591114Z","iopub.execute_input":"2022-07-01T11:51:24.591420Z","iopub.status.idle":"2022-07-01T11:51:24.608647Z","shell.execute_reply.started":"2022-07-01T11:51:24.591393Z","shell.execute_reply":"2022-07-01T11:51:24.607912Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# TODO: change to albumentations\n# Use only A library\n# TODO: get_train_transforms, get_valid_transforms\n\ndef get_train_transforms():\n    return A.Compose(\n        [\n            A.Resize(224, 224),            \n            A.Rotate(limit=30, border_mode=cv2.BORDER_REPLICATE, p=0.5),\n            A.HorizontalFlip(p=0.5),\n            A.RandomBrightnessContrast(p=0.2),\n            A.Blur(p=0.25),\n            A.Normalize(\n                mean=[0.485, 0.456, 0.406], \n                std=[0.229, 0.224, 0.225], \n                p=1.0\n            ),\n            ATorch.transforms.ToTensorV2(p=1.0),\n        ],\n        p=1.0\n    )\n\ndef get_valid_transforms():\n    return A.Compose(\n        [\n            A.Resize(224, 224),\n            A.Normalize(\n                mean=[0.485, 0.456, 0.406], \n                std=[0.229, 0.224, 0.225], \n                p=1.0\n            ),\n            ATorch.transforms.ToTensorV2(p=1.0),\n        ],\n        p=1.0\n    )","metadata":{"execution":{"iopub.status.busy":"2022-07-01T11:51:24.609853Z","iopub.execute_input":"2022-07-01T11:51:24.610192Z","iopub.status.idle":"2022-07-01T11:51:24.620869Z","shell.execute_reply.started":"2022-07-01T11:51:24.610160Z","shell.execute_reply":"2022-07-01T11:51:24.620021Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def accuracy_fn(y_pred, y):\n    return (y_pred.argmax(1) == y).sum().item() / y.shape[0]","metadata":{"execution":{"iopub.status.busy":"2022-07-01T11:51:24.622224Z","iopub.execute_input":"2022-07-01T11:51:24.622571Z","iopub.status.idle":"2022-07-01T11:51:24.630656Z","shell.execute_reply.started":"2022-07-01T11:51:24.622537Z","shell.execute_reply":"2022-07-01T11:51:24.629862Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def update_metrics(mean_score, score, mean_loss, loss, step):\n    mean_score = (mean_score * step + score)/(step+1)\n    mean_loss = (mean_loss * step + loss.detach().cpu().item())/(step+1)\n    return mean_score, mean_loss","metadata":{"execution":{"iopub.status.busy":"2022-07-01T11:51:24.633473Z","iopub.execute_input":"2022-07-01T11:51:24.633726Z","iopub.status.idle":"2022-07-01T11:51:24.640845Z","shell.execute_reply.started":"2022-07-01T11:51:24.633704Z","shell.execute_reply":"2022-07-01T11:51:24.640087Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train, val = train_test_split(ANNOTATIONS_FILE, test_size=CFG[\"test_size\"], random_state=CFG[\"seed\"], shuffle=True)","metadata":{"execution":{"iopub.status.busy":"2022-07-01T11:51:24.642432Z","iopub.execute_input":"2022-07-01T11:51:24.642933Z","iopub.status.idle":"2022-07-01T11:51:24.653353Z","shell.execute_reply.started":"2022-07-01T11:51:24.642882Z","shell.execute_reply":"2022-07-01T11:51:24.652574Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset = CassavaImageDataset(train, IMG_DIR, transform=get_train_transforms())\nval_dataset = CassavaImageDataset(val, IMG_DIR, transform=get_valid_transforms())","metadata":{"execution":{"iopub.status.busy":"2022-07-01T11:51:24.654682Z","iopub.execute_input":"2022-07-01T11:51:24.655196Z","iopub.status.idle":"2022-07-01T11:51:24.661285Z","shell.execute_reply.started":"2022-07-01T11:51:24.655160Z","shell.execute_reply":"2022-07-01T11:51:24.660497Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataloader = DataLoader(train_dataset, batch_size=CFG[\"batch_size\"], shuffle=True)\nval_dataloader = DataLoader(val_dataset, batch_size=CFG[\"batch_size\"])","metadata":{"execution":{"iopub.status.busy":"2022-07-01T11:51:24.666028Z","iopub.execute_input":"2022-07-01T11:51:24.666504Z","iopub.status.idle":"2022-07-01T11:51:24.673802Z","shell.execute_reply.started":"2022-07-01T11:51:24.666469Z","shell.execute_reply":"2022-07-01T11:51:24.672766Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\nmodel = EfficientNetModel().to(device)\n\nloss_fn  = nn.CrossEntropyLoss()\noptimizer =  torch.optim.SGD(model.parameters(), lr=CFG[\"learning_rate\"])","metadata":{"execution":{"iopub.status.busy":"2022-07-01T11:51:24.675141Z","iopub.execute_input":"2022-07-01T11:51:24.675547Z","iopub.status.idle":"2022-07-01T11:51:26.494984Z","shell.execute_reply.started":"2022-07-01T11:51:24.675511Z","shell.execute_reply":"2022-07-01T11:51:26.494042Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trainer = Trainer(model, device, accuracy_fn, loss_fn, optimizer)\ntrainer.run(train_dataloader, val_dataloader, CFG[\"epochs\"], MODEL_SAVE_PATH)","metadata":{"execution":{"iopub.status.busy":"2022-07-01T11:51:26.496456Z","iopub.execute_input":"2022-07-01T11:51:26.496832Z","iopub.status.idle":"2022-07-01T13:41:42.401053Z","shell.execute_reply.started":"2022-07-01T11:51:26.496795Z","shell.execute_reply":"2022-07-01T13:41:42.399991Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}