{"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 torch\nimport glob\nimport json\nimport os\nimport cv2\nimport pandas as pd\nfrom PIL import Image\nimport numpy as np\nimport matplotlib\nimport matplotlib.pyplot as plt\nimport torchvision.transforms as tt\nfrom torch.utils.data import Dataset, DataLoader, random_split, Subset\nimport torchvision\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor\n\n%matplotlib inline\nmatplotlib.rcParams['font.size'] = 14\nmatplotlib.rcParams['figure.figsize'] = (25, 25)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-05-26T14:43:04.516202Z","iopub.execute_input":"2021-05-26T14:43:04.516641Z","iopub.status.idle":"2021-05-26T14:43:06.307570Z","shell.execute_reply.started":"2021-05-26T14:43:04.516556Z","shell.execute_reply":"2021-05-26T14:43:06.306393Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = pd.read_csv('../input/global-wheat-detection/train.csv')\nsub_df = pd.read_csv('../input/global-wheat-detection/sample_submission.csv')\n\nbbox = []\nfor i in train_df['bbox']:\n    bbox.append(json.loads(i))\ntrain_df = train_df.drop(['bbox'], axis=1)\ntrain_df['bbox'] = bbox\ntrain_df","metadata":{"execution":{"iopub.status.busy":"2021-05-22T10:59:42.388375Z","iopub.execute_input":"2021-05-22T10:59:42.388782Z","iopub.status.idle":"2021-05-22T10:59:43.287223Z","shell.execute_reply.started":"2021-05-22T10:59:42.388738Z","shell.execute_reply":"2021-05-22T10:59:43.286424Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"'''\nbbox\nimage_id\nlabels\narea\niscrowd\n'''\n\nclass WheatDataset(Dataset):\n    def __init__(self, root, dataframe, transforms=None):\n        self.root = root\n        self.dataframe = dataframe\n        self.transforms = transforms\n        self.images = (root + '/' + dataframe['image_id'] + '.jpg').unique().tolist()\n        \n    def __getitem__(self, index):\n        image_path = self.images[index]\n        img = Image.open(image_path).convert('RGB')\n        \n        image_name = image_path.split('.')[-2].split('/')[-1]\n        related_df = self.dataframe[self.dataframe['image_id'] == image_name]\n        \n        boxes = torch.tensor(related_df['bbox'].values.tolist(), dtype=torch.float32, device=device)\n        boxes[:, 2] = boxes[:, 0] + boxes[:, 2]\n        boxes[:, 3] = boxes[:, 1] + boxes[:, 3]\n        image_id = torch.tensor([index], device=device)\n        labels = torch.ones((len(boxes), ), dtype=torch.int64, device=device)\n        area = (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])\n        iscrowd = torch.zeros((len(boxes), ), dtype=torch.int64, device=device)\n        \n        target = {}\n        target['boxes'] = boxes\n        target['image_id'] = image_id\n        target['labels'] = labels\n        target['area'] = area\n        target['iscrowd'] = iscrowd\n        \n        if self.transforms is not None:\n            img, target = self.transforms(img, target)\n\n        return img, target\n        \n    def __len__(self):\n        return len(self.images)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T10:59:43.288945Z","iopub.execute_input":"2021-05-22T10:59:43.28945Z","iopub.status.idle":"2021-05-22T10:59:43.300988Z","shell.execute_reply.started":"2021-05-22T10:59:43.289411Z","shell.execute_reply":"2021-05-22T10:59:43.300193Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"root = '../input/global-wheat-detection/train'\ndataframe = train_df\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\ndataset = WheatDataset(root, dataframe)\ndataset[90]","metadata":{"execution":{"iopub.status.busy":"2021-05-22T10:59:43.303263Z","iopub.execute_input":"2021-05-22T10:59:43.303559Z","iopub.status.idle":"2021-05-22T10:59:47.419374Z","shell.execute_reply.started":"2021-05-22T10:59:43.303533Z","shell.execute_reply":"2021-05-22T10:59:47.418644Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%cd ../input/myfile\n!pip install pycocotools","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:00:19.286646Z","iopub.execute_input":"2021-05-22T11:00:19.286963Z","iopub.status.idle":"2021-05-22T11:00:32.540176Z","shell.execute_reply.started":"2021-05-22T11:00:19.286933Z","shell.execute_reply":"2021-05-22T11:00:32.539234Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import utils\nimport transforms as T\nfrom engine import train_one_epoch, evaluate\n\ndef get_transform(train):\n    transforms = []\n    transforms.append(T.ToTensor())\n    if train:\n        transforms.append(T.RandomHorizontalFlip(0.5))\n    return T.Compose(transforms)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:01:04.477735Z","iopub.execute_input":"2021-05-22T11:01:04.478072Z","iopub.status.idle":"2021-05-22T11:01:04.483838Z","shell.execute_reply.started":"2021-05-22T11:01:04.47804Z","shell.execute_reply":"2021-05-22T11:01:04.482965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%cd ..\n%cd ..\n%cd working","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:01:05.370639Z","iopub.execute_input":"2021-05-22T11:01:05.370934Z","iopub.status.idle":"2021-05-22T11:01:05.384294Z","shell.execute_reply.started":"2021-05-22T11:01:05.370904Z","shell.execute_reply":"2021-05-22T11:01:05.383461Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_classes = 2\ndef get_model(num_classes):\n    model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=False, pretrained_backbone=False)\n    in_features = model.roi_heads.box_predictor.cls_score.in_features\n    model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)\n    return model\n\nmodel = get_model(num_classes).to(device)\nmodel.load_state_dict(torch.load('../input/fasterrcnn-resnet50-fpn/fasterrcnn_resnet50_fpn.pth'))","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:01:06.529936Z","iopub.execute_input":"2021-05-22T11:01:06.530281Z","iopub.status.idle":"2021-05-22T11:01:10.432751Z","shell.execute_reply.started":"2021-05-22T11:01:06.530251Z","shell.execute_reply":"2021-05-22T11:01:10.432004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.manual_seed(42)\n\ntrain_ds = WheatDataset(root, dataframe, get_transform(train=True))\nvalid_ds = WheatDataset(root, dataframe, get_transform(train=False))\n\nindices = torch.randperm(len(train_ds)).tolist()\ntrain_ds = Subset(train_ds, indices[:-50])\nvalid_ds = Subset(valid_ds, indices[-50:])\n\ntrain_dl = DataLoader(train_ds, batch_size=2, shuffle=True, collate_fn=utils.collate_fn)\nvalid_dl = DataLoader(valid_ds, batch_size=1, shuffle=False, collate_fn=utils.collate_fn)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:01:11.544522Z","iopub.execute_input":"2021-05-22T11:01:11.54484Z","iopub.status.idle":"2021-05-22T11:01:11.664783Z","shell.execute_reply.started":"2021-05-22T11:01:11.544808Z","shell.execute_reply":"2021-05-22T11:01:11.66396Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"params = [p for p in model.parameters() if p.requires_grad]\noptimizer = torch.optim.SGD(params, lr=0.005, momentum=0.9, weight_decay=0.0005)\nlr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=3, gamma=0.1)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:01:15.583194Z","iopub.execute_input":"2021-05-22T11:01:15.583515Z","iopub.status.idle":"2021-05-22T11:01:15.591554Z","shell.execute_reply.started":"2021-05-22T11:01:15.583485Z","shell.execute_reply":"2021-05-22T11:01:15.589364Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# num_epochs = 10\n# for epoch in range(num_epochs):\n#     train_one_epoch(model, optimizer, train_dl, device, epoch, print_freq=10)\n#     lr_scheduler.step()\n#     evaluate(model, valid_dl, device)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:01:17.674612Z","iopub.execute_input":"2021-05-22T11:01:17.67493Z","iopub.status.idle":"2021-05-22T11:01:17.678724Z","shell.execute_reply.started":"2021-05-22T11:01:17.674898Z","shell.execute_reply":"2021-05-22T11:01:17.677754Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Pseudo Labeling and Retraining","metadata":{}},{"cell_type":"code","source":"class WheatTestDataset(Dataset):\n    def __init__(self, root, transform=None):\n        self.root = root\n        self.transform = transform\n        self.images = glob.glob(os.path.join(root, '*'))\n    \n    def __getitem__(self, index):\n        image_path = self.images[index]\n        image_id = image_path.split('.')[-2].split('/')[-1]\n        \n        image = Image.open(image_path).convert('RGB')\n        target = {}\n        \n        if self.transform is not None:\n            image, _ = self.transform(image, target)\n        return image, image_id\n    \n    def __len__(self):\n        return len(self.images)\n\ntest_root = '../input/global-wheat-detection/test'\ntest_ds = WheatTestDataset(test_root, get_transform(train=False))\ntest_dl = DataLoader(test_ds, batch_size=1, shuffle=False, num_workers=4, pin_memory=True, collate_fn=utils.collate_fn)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:01:20.49337Z","iopub.execute_input":"2021-05-22T11:01:20.493693Z","iopub.status.idle":"2021-05-22T11:01:20.510727Z","shell.execute_reply.started":"2021-05-22T11:01:20.49366Z","shell.execute_reply":"2021-05-22T11:01:20.509965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"''''\nboxes\nimage_id\n'''\nfrom torchvision.transforms import functional as F\nthreshold = 0.5\nimage_ids = []\nsources = ['test']\nbbox = []\nplabel_df = pd.DataFrame()\n\nmodel.eval()\nwith torch.no_grad():\n    for image, image_id in test_dl:\n        prediction = model([image[0].to(device)])\n        boxes = prediction[0]['boxes']\n        boxes[:, 2] = boxes[:, 2] - boxes[:, 0]\n        boxes[:, 3] = boxes[:, 3] - boxes[:, 1]\n        \n        scores = prediction[0]['scores']\n        boxes = boxes[scores > threshold]\n    \n        w, h = F._get_image_size(image[0])\n    \n        for box in boxes:\n            temp_df = pd.DataFrame({\n                'image_id': image_id,\n                'width': [w],\n                'height': [h],\n                'source': ['pseudo_label'],\n                'bbox': [[round(b,0) for b in box.tolist()]]\n            })\n            plabel_df = pd.concat([plabel_df, temp_df], axis=0)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:01:33.464083Z","iopub.execute_input":"2021-05-22T11:01:33.46441Z","iopub.status.idle":"2021-05-22T11:01:36.20436Z","shell.execute_reply.started":"2021-05-22T11:01:33.46438Z","shell.execute_reply":"2021-05-22T11:01:36.203398Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"final_plabel_df = pd.concat([train_df, plabel_df], axis=0).reset_index(drop=True)\nfinal_plabel_df","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:01:45.264226Z","iopub.execute_input":"2021-05-22T11:01:45.264693Z","iopub.status.idle":"2021-05-22T11:01:45.323641Z","shell.execute_reply.started":"2021-05-22T11:01:45.264649Z","shell.execute_reply":"2021-05-22T11:01:45.322669Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"'''\nboxes\nimage_id\nlabels\narea\niscrowd\n'''\nclass PLabelDataset(Dataset):\n    def __init__(self, df, transform=None):\n        self.df = df\n        self.transform = transform\n        self.image_names = self.df['image_id'].unique()\n    \n    def __getitem__(self, index):\n        image_name = self.image_names[index]\n        if self.df[self.df['image_id'] == image_name]['source'].values[0] == 'pseudo_label':\n            root = '../input/global-wheat-detection/test'\n        else:\n            root = '../input/global-wheat-detection/train'\n        \n        image_path = os.path.join(root, image_name + '.jpg')\n        image = Image.open(image_path).convert('RGB')\n        \n        boxes = torch.tensor(self.df[self.df['image_id'] == self.image_names[index]]['bbox'].tolist(), device=device, dtype=torch.float)\n        boxes[:, 2] = boxes[:, 0] + boxes[:, 2]\n        boxes[:, 3] = boxes[:, 1] + boxes[:, 3]\n        \n        image_id = torch.tensor([index], device=device, dtype=torch.int64)\n        labels = torch.ones((len(boxes),), device=device, dtype=torch.int64)\n        area = (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])\n        iscrowd = torch.zeros((len(boxes),), device=device, dtype=torch.int64)\n        \n        target = {}\n        target['boxes'] = boxes\n        target['image_id'] = image_id\n        target['labels'] = labels\n        target['area']= area\n        target['iscrowd'] = iscrowd\n        \n        if self.transform is not None:\n            image, target = self.transform(image, target)\n        return image, target\n    \n    def __len__(self):\n        return len(self.image_names)\n    \nds = PLabelDataset(final_plabel_df)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:03:00.380755Z","iopub.execute_input":"2021-05-22T11:03:00.381079Z","iopub.status.idle":"2021-05-22T11:03:00.402042Z","shell.execute_reply.started":"2021-05-22T11:03:00.381047Z","shell.execute_reply":"2021-05-22T11:03:00.401233Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"indices = torch.randperm(len(ds))\n\nplabel_ds = PLabelDataset(final_plabel_df, get_transform(train=True))\ntest_plabel_ds = PLabelDataset(final_plabel_df, get_transform(train=False))\n\ntrain_ds = Subset(plabel_ds, indices=indices[:int(len(indices) * 0.9)])\nvalid_ds = Subset(test_plabel_ds, indices=indices[int(len(indices) * 0.9):])\n\ntrain_dl = DataLoader(train_ds, batch_size=16, shuffle=True, collate_fn=utils.collate_fn)\nvalid_dl = DataLoader(valid_ds, batch_size=8, shuffle=False, collate_fn=utils.collate_fn)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:03:27.139312Z","iopub.execute_input":"2021-05-22T11:03:27.13971Z","iopub.status.idle":"2021-05-22T11:03:27.165458Z","shell.execute_reply.started":"2021-05-22T11:03:27.139668Z","shell.execute_reply":"2021-05-22T11:03:27.164653Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"params = [p for p in model.parameters() if p.requires_grad]\noptimizer = torch.optim.SGD(params, lr=0.01, momentum=0.9, weight_decay=0.0001)\nlr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.5)\n\nnum_epochs = 4\nfor epoch in range(num_epochs):\n    train_one_epoch(model, optimizer, train_dl, device, epoch, print_freq=10)\n    lr_scheduler.step()\n    evaluate(model, valid_dl, device)","metadata":{"execution":{"iopub.status.busy":"2021-05-22T11:03:27.839098Z","iopub.execute_input":"2021-05-22T11:03:27.839406Z","iopub.status.idle":"2021-05-22T12:21:19.071546Z","shell.execute_reply.started":"2021-05-22T11:03:27.839379Z","shell.execute_reply":"2021-05-22T12:21:19.070738Z"},"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_root = '../input/global-wheat-detection/test'\ntest_ds = WheatTestDataset(test_root, get_transform(train=False))\ntest_dl = DataLoader(test_ds, shuffle=False, batch_size=1, collate_fn=utils.collate_fn)\n\nthreshold = 0.5\n\ndef show_result(image: torch.Tensor, boxes):\n    img = Image.fromarray(image.permute(1,2,0).mul(255).byte().numpy()).convert('RGB')\n    img = np.array(img)\n    for box in boxes:\n        cv2.rectangle(img, (box[0], box[1]), (box[2], box[3]), (225, 0, 0), 3)\n    plt.imshow(img)\n    plt.axis(False)\n    \nmodel.eval()\nwith torch.no_grad():\n    for i, (image, image_id) in enumerate(test_dl):\n        prediction = model([image[0].to(device)])\n        \n        boxes = prediction[0]['boxes']\n        scores = prediction[0]['scores']\n        \n        boxes = boxes[scores > threshold]\n        plt.subplot(5, 2, i + 1)\n        show_result(image[0], boxes)\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-05-22T12:37:06.159056Z","iopub.execute_input":"2021-05-22T12:37:06.159381Z","iopub.status.idle":"2021-05-22T12:37:09.348351Z","shell.execute_reply.started":"2021-05-22T12:37:06.159352Z","shell.execute_reply":"2021-05-22T12:37:09.347367Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.save(model.state_dict(), 'fasterrcnn_resnet50_fpn_plabel.pth')","metadata":{"execution":{"iopub.status.busy":"2021-05-22T12:25:16.091593Z","iopub.execute_input":"2021-05-22T12:25:16.091912Z","iopub.status.idle":"2021-05-22T12:25:16.390048Z","shell.execute_reply.started":"2021-05-22T12:25:16.091879Z","shell.execute_reply":"2021-05-22T12:25:16.389174Z"},"trusted":true},"execution_count":null,"outputs":[]}]}