{"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":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-01-19T09:10:09.943589Z","iopub.execute_input":"2022-01-19T09:10:09.944375Z","iopub.status.idle":"2022-01-19T09:10:09.948444Z","shell.execute_reply.started":"2022-01-19T09:10:09.944334Z","shell.execute_reply":"2022-01-19T09:10:09.947741Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Dataset.py","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nfrom skimage import io\nimport albumentations\nfrom albumentations.pytorch.transforms import ToTensorV2\n\nclass ReefDataset(torch.utils.data.Dataset):\n    def __init__(self,df,transforms=None):\n        self.df = df\n        self.transforms=transforms\n    def __len__(self):\n        return len(self.df)\n    def can_augment(self, boxes):\n        \"\"\" Check if bounding boxes are OK to augment\n        \n        ###### https://www.kaggle.com/julian3833/reef-starter-torch-fasterrcnn-train-lb-0-416\n        For example: image_id 1-490 has a bounding box that is partially outside of the image\n        It breaks albumentation\n        Here we check the margins are within the image to make sure the augmentation can be applied\n        \"\"\"\n        \n        box_outside_image = ((boxes[:, 0] < 0).any() or (boxes[:, 1] < 0).any() \n                             or (boxes[:, 2] > 1280).any() or (boxes[:, 3] > 720).any())\n        return not box_outside_image\n    \n    def __getitem__(self,item):\n        row = self.df.iloc[item]\n        image = io.imread(f'{\"../input/tensorflow-great-barrier-reef/train_images/\"}/{row[\"image_path\"]}')\n        image = np.transpose(image, (2, 0, 1)).astype(np.float32)\n        image /= 255.0\n        \n        boxes = pd.DataFrame(row['annotations'], columns=['x', 'y', 'width', 'height']).astype(float).values\n        # Change from [x_min, y_min, w, h] to [x_min, y_min, x_max, y_max]\n        boxes[:, 2] = boxes[:, 0] + boxes[:, 2]\n        boxes[:, 3] = boxes[:, 1] + boxes[:, 3]\n        \n        n_boxes = boxes.shape[0]  ## I know number of \n        \n        area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])\n        \n        target = {\n            'boxes': torch.tensor(boxes, dtype=torch.float32),\n            'area': torch.tensor(area, dtype=torch.float32),\n            \n            'image_id': torch.tensor([item]),\n            \n            # There is only one class\n            'labels': torch.ones((n_boxes,), dtype=torch.int64),\n            \n            # Suppose all instances are not crowd\n            'iscrowd': torch.zeros((n_boxes,), dtype=torch.int64)            \n        }\n        \n        if self.transforms and self.can_augment(boxes):\n            sample = {\n                'image': image,\n                'bboxes': target['boxes'],\n                'labels': target['labels']\n            }\n            sample = self.transforms(**sample)\n            image = sample['image']\n            \n            if n_boxes > 0:\n                target['boxes'] = torch.stack(tuple(map(torch.tensor, zip(*sample['bboxes'])))).permute(1, 0)\n        else:\n            image = ToTensorV2(p=1.0)(image=image)['image']\n            \n        return {\n            'image': image,\n            'target': target,\n        }","metadata":{"execution":{"iopub.status.busy":"2022-01-19T09:10:09.950617Z","iopub.execute_input":"2022-01-19T09:10:09.951198Z","iopub.status.idle":"2022-01-19T09:10:09.972250Z","shell.execute_reply.started":"2022-01-19T09:10:09.951077Z","shell.execute_reply":"2022-01-19T09:10:09.971571Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Engine.py","metadata":{}},{"cell_type":"code","source":"def train(model, dataloader, optimizer):\n    model.train()\n    for data in dataloader:\n        images = list(image.to('cuda') for image in data['images'])\n        for tsor in range(len(data)):\n            \n            data['targets'][tsor]['boxes'] = data['targets'][tsor]['boxes'].to('cuda')\n            data['targets'][tsor]['area'] = data['targets'][tsor]['area'].to('cuda')\n            data['targets'][tsor]['image_id'] = data['targets'][tsor]['image_id'].to('cuda')\n            data['targets'][tsor]['labels'] = data['targets'][tsor]['labels'].to('cuda')\n            data['targets'][tsor]['iscrowd'] = data['targets'][tsor]['iscrowd'].to('cuda')\n        \n        optimizer.zero_grad()\n        outputs = model(images, data['targets'])\n        losses = sum(loss for loss in outputs.values())\n        losses.backward()\n        optimizer.step()\n        \ndef valid(model, dataloader):\n    model.eval()\n    val_loss_accum = 0\n    with torch.no_grad():\n        for data in dataloader:\n            images = list(image.to('cuda') for image in data['images'])\n            for tsor in range(len(data)):\n            \n                data['targets'][tsor]['boxes'] = data['targets'][tsor]['boxes'].to('cuda')\n                data['targets'][tsor]['area'] = data['targets'][tsor]['area'].to('cuda')\n                data['targets'][tsor]['image_id'] = data['targets'][tsor]['image_id'].to('cuda')\n                data['targets'][tsor]['labels'] = data['targets'][tsor]['labels'].to('cuda')\n                data['targets'][tsor]['iscrowd'] = data['targets'][tsor]['iscrowd'].to('cuda')\n        \n            \n            val_loss_dict = model(images, data['targets'])\n            val_batch_loss = sum(loss for loss in val_loss_dict.values())\n            val_loss_accum += val_batch_loss.item()\n    val_loss = val_loss_accum / len(data)\n    return val_loss\n    ","metadata":{"execution":{"iopub.status.busy":"2022-01-19T09:10:09.973996Z","iopub.execute_input":"2022-01-19T09:10:09.974254Z","iopub.status.idle":"2022-01-19T09:10:09.991088Z","shell.execute_reply.started":"2022-01-19T09:10:09.974221Z","shell.execute_reply":"2022-01-19T09:10:09.990268Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# model.py","metadata":{}},{"cell_type":"code","source":"import torchvision\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor\nfrom torchvision.models.detection import FasterRCNN\n\ndef get_model():\n    # load a model; pre-trained on COCO\n    model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)\n\n    num_classes = 2  # 1 class (starfish) + background\n\n    # get number of input features for the classifier\n    in_features = model.roi_heads.box_predictor.cls_score.in_features\n\n    # replace the pre-trained head with a new one\n    model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)\n\n    model.to('cuda')\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2022-01-19T09:10:09.993173Z","iopub.execute_input":"2022-01-19T09:10:09.993903Z","iopub.status.idle":"2022-01-19T09:10:10.014208Z","shell.execute_reply.started":"2022-01-19T09:10:09.993779Z","shell.execute_reply":"2022-01-19T09:10:10.013449Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# main.py","metadata":{}},{"cell_type":"code","source":"## albumentations Augmentations\n\ndef get_train_transform():\n    return albumentations.Compose([\n        albumentations.Flip(0.5),\n        ToTensorV2(p=1.0)\n    ], bbox_params={'format': 'pascal_voc', 'label_fields': ['labels']})\n\n\ndef get_valid_transform():\n    return albumentations.Compose([\n        ToTensorV2(p=1.0)\n    ], bbox_params={'format': 'pascal_voc', 'label_fields': ['labels']})","metadata":{"execution":{"iopub.status.busy":"2022-01-19T09:10:10.015887Z","iopub.execute_input":"2022-01-19T09:10:10.016704Z","iopub.status.idle":"2022-01-19T09:10:10.027725Z","shell.execute_reply.started":"2022-01-19T09:10:10.016665Z","shell.execute_reply":"2022-01-19T09:10:10.026826Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Collate:\n\n    def __call__(self, batch):\n        output = {}\n        output['images'] = [sample[\"image\"] for sample in batch]\n        output['targets'] = [sample[\"target\"] for sample in batch]\n\n        return output","metadata":{"execution":{"iopub.status.busy":"2022-01-19T09:10:10.029232Z","iopub.execute_input":"2022-01-19T09:10:10.029755Z","iopub.status.idle":"2022-01-19T09:10:10.036955Z","shell.execute_reply.started":"2022-01-19T09:10:10.029716Z","shell.execute_reply":"2022-01-19T09:10:10.036206Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## Loading Files . . . DF-TRAINING and DF-Validation\ndf = pd.read_csv(\"../input/reef-cv-strategy-subsequences-dataframes/train-validation-split/train-0.1.csv\")\n\ndf['annotations'] = df['annotations'].apply(eval)\n\n# Create the image path for the row\n\ndf['image_path'] = \"video_\" + df['video_id'].astype(str) + \"/\" + df['video_frame'].astype(str) + \".jpg\"\n\ndf_train, df_val = df[df['is_train']], df[~df['is_train']]\n\n# https://discuss.pytorch.org/t/fasterrcnn-images-with-no-objects-present-cause-an-error/117974/3\ndf_train = df_train[df_train.annotations.str.len() > 0 ].reset_index(drop=True)\ndf_val = df_val[df_val.annotations.str.len() > 0 ].reset_index(drop=True)\n\n\n# train_dataset = ReefDataset(df_train, get_train_transform())\n# valid_dataset = ReefDataset(df_val, get_train_transform())\n\ntrain_dataset = ReefDataset(df_train,)\nvalid_dataset = ReefDataset(df_val,)\n\n# train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=8, shuffle=False, num_workers=2)\n# valid_loader = torch.utils.data.DataLoader(valid_dataset, batch_size=8, shuffle=False, num_workers=2)\ntrain_loader = torch.utils.data.DataLoader(train_dataset, batch_size=8, shuffle=False, num_workers=2, collate_fn=Collate() )\nvalid_loader = torch.utils.data.DataLoader(valid_dataset, batch_size=8, shuffle=False, num_workers=2, collate_fn=Collate() )\n","metadata":{"execution":{"iopub.status.busy":"2022-01-19T09:10:10.062390Z","iopub.execute_input":"2022-01-19T09:10:10.063235Z","iopub.status.idle":"2022-01-19T09:10:10.434533Z","shell.execute_reply.started":"2022-01-19T09:10:10.063195Z","shell.execute_reply":"2022-01-19T09:10:10.433646Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for data in train_loader:\n    images = list(image.to('cuda') for image in data['images'])\n    print(images['images'][7])\n    break","metadata":{"execution":{"iopub.status.busy":"2022-01-19T09:14:57.917304Z","iopub.execute_input":"2022-01-19T09:14:57.917607Z","iopub.status.idle":"2022-01-19T09:14:58.949419Z","shell.execute_reply.started":"2022-01-19T09:14:57.917572Z","shell.execute_reply":"2022-01-19T09:14:58.948367Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = get_model()\nparams = [p for p in model.parameters() if p.requires_grad]\nEPOCHS = 10\n\noptimizer = torch.optim.SGD(params, lr=0.0025, momentum=0.9, weight_decay=0.0005)\nlr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=3, gamma=0.1)\n\n\nfor epoch in range(EPOCHS):\n    train(model, train_loader, optimizer)\n    val_loss = valid(model, valid_loader)\n    chk_name = f'fasterrcnn_resnet50_fpn-e{epoch}.bin'\n    torch.save(model.state_dict(), chk_name)\n    print(f'validation loss : {val_loss}')\n","metadata":{"execution":{"iopub.status.busy":"2022-01-19T09:10:11.959429Z","iopub.execute_input":"2022-01-19T09:10:11.959763Z","iopub.status.idle":"2022-01-19T09:10:25.609102Z","shell.execute_reply.started":"2022-01-19T09:10:11.959726Z","shell.execute_reply":"2022-01-19T09:10:25.607969Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}