{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\n# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# %%\n# randomly show imgs\nfrom sklearn.model_selection import train_test_split\nimport random\nimport os\nimport cv2\nimport numpy as np\nimport pandas as pd\nfrom matplotlib import patches\nfrom matplotlib import pyplot as plt\nfrom PIL import Image\nimport copy\n\n\nclass dataPreprocess(object):\n    \"\"\"Convert train.csv into Train and Validation parts.\n\n    read csv file â†’ convert bbox â†’ drop columns â†’ train and val image ids\n\n    Attributes:\n        train_csv_path: train.csv dir\n\n    \"\"\"\n\n    def __init__(self, data_path):\n        \"\"\"Read data root path.\n\n        Args:\n            data_path: data which contains images and train.csv.\n        \"\"\"\n        self.data_path = data_path\n        self.data_csv_path = os.path.join(data_path, 'train.csv')\n        self.data_df = pd.read_csv(self.data_csv_path)\n\n        # conver bbox from string into xmin, ymin, w, h, (top left point, w, h)\n        bboxs = np.stack(self.data_df.bbox.apply(\n            lambda x: np.fromstring(x[1:-1], sep=',')))\n        for i, column in enumerate(['x', 'y', 'w', 'h']):\n            self.data_df[column] = bboxs[:, i]\n        self.data_df.drop(columns=['bbox', 'width', 'height'], inplace=True)\n        self.img_ids = self.data_df.image_id.unique()\n\n    def random_split_dataset(self, frac=0.999):\n        \"\"\"Random split dataset into train and validation based on frac.\n\n        Args:\n            frac: frac as train dataset, (1-frac) as validation set.\n\n        Returns:\n            return list(train_ids), list(val_ids)\n        \"\"\"\n        # In case you need the original img_ids, we copy the imgs and shuffle.\n        img_ids = copy.deepcopy(self.img_ids)\n        random.shuffle(img_ids)\n        train_index = int(frac * len(img_ids))\n        train_ids = img_ids[:train_index]\n        val_ids = img_ids[train_index:]\n        return train_ids, val_ids\n\n    def __str__(self):\n        return self.data_df.describe().__str__() + self.data_df.info().__str__()\n\n\ndef draw_rectangle(img_path, x, y, w, h):\n    img = Image.open(img_path)\n    cv2.rectangle(img, (x, y), (x + w, y + h), 255, 3)\n    return img\n\n\ndef draw_multirectangles(boxes, imgpath):\n    img = plt.imread(imgpath)\n    for x1, y1, x2, y2 in boxes:\n        cv2.rectangle(img, (x1, y1), (x2, y2), 255, 3)\n    return img","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import glob\nimport os\nimport random\n\nimport cv2\nimport numpy as np\nimport pandas as pd\nimport PIL\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nimport torchvision\nfrom matplotlib import pyplot as plt\nfrom PIL import Image\nfrom torchvision import transforms\n\n\nclass WheatDataset(torch.utils.data.Dataset):\n    \"\"\"Global wheat dataset for dataloader.\n\n    Attributes:\n        image_ids: list of file names, ['fe133ccb4', ...]\n        image_dir: data path, data/train/ or data/test/\n        transforms: preprocessing for images from torchvision.\n        target_transforms: transform target\n\n    Returns:\n        image: PIL RGB format.\n        bboxes: [N, 4] x1, y1, x2, y2\n        labels: [N, ] [1, ..., 1]\n        areas: [N, ] areas float\n    \"\"\"\n\n    def __init__(self, image_ids, image_dir, transforms=None, target_transforms=None):\n        super(WheatDataset, self).__init__()\n        self.image_ids = image_ids\n        self.transforms = transforms\n        self.target_transforms = target_transforms\n        self.img_dir = image_dir\n        meta_data = dataPreprocess(image_dir).data_df\n        meta_data['x2'] = meta_data.x + meta_data.w\n        meta_data['y2'] = meta_data.y + meta_data.h\n        meta_data['area'] = meta_data.w * meta_data.h\n        self.dataframe = meta_data.groupby('image_id')\n\n    def __getitem__(self, index):\n        image_id = self.image_ids[index]\n        data = self.dataframe.get_group(\n            image_id).loc[:, ['x', 'y', 'x2', 'y2', 'source', 'area']].values\n        bboxes, labels, areas = data[:, :4], data[:, -2], data[:, -1]\n\n        bboxes = torch.from_numpy(bboxes.astype(np.float32))\n        labels = torch.ones(labels.shape, dtype=torch.int64)\n\n        # image\n        img_path = os.path.join(self.img_dir, 'train', image_id + '.jpg')\n        image = Image.open(img_path).convert('RGB')\n        # The image is in HWC, we need to convert to CHW.\n        if self.transforms:\n            image = self.transforms(image)\n        if self.target_transforms:\n            labels = self.target_transforms(labels)\n        return image, bboxes, labels, image_id\n\n    def __len__(self):\n        return len(self.image_ids)\n\n\nclass WheatDatasetTest(torch.utils.data.Dataset):\n    \"\"\"Some Information about WheatDatasetTest  \"\"\"\n\n    def __init__(self, test_dir):\n        super(WheatDatasetTest, self).__init__()\n        # glob all the test data\n        self.image_ids = glob.glob(os.path.join(test_dir, \"*.jpg\"))\n\n    def __getitem__(self, index):\n        img = PIL.Image.open(self.image_ids[index]).convert('RGB')\n        img = torchvision.transforms.ToTensor()(img)\n        return img, self.image_ids[index]\n\n    def __len__(self):\n        return len(self.image_ids)\n\n\ndef collate_fn(batch):\n    images, bboxes, labels, imageid = tuple(zip(*batch))\n    targets = []\n    for box, label in zip(bboxes, labels):\n        targets.append({'boxes': box, 'labels': label})\n    return torch.stack(images), targets, imageid","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport random\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nimport torchvision\nfrom torchvision import transforms\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor\nfrom matplotlib import pyplot as plt\n\nDATA_DIR = '/kaggle/input/global-wheat-detection/'\n# torch.backends.cudnn.benchmark = True\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n# DataPrerpocessing\ndata = dataPreprocess(DATA_DIR)\ntrain_ids, val_ids = data.random_split_dataset(1.0)\n\n############## hyperparameters\nlearning_rate = 1e-3\nepochs = 4\n\n# Dataset\ntsfm = transforms.Compose([\n    transforms.RandomHorizontalFlip(),\n    transforms.ToTensor()\n])\n\ndataset = WheatDataset(train_ids, DATA_DIR, transforms=tsfm)\n\n\ndataloader = torch.utils.data.DataLoader(\n    dataset, batch_size=16, num_workers=8, collate_fn=collate_fn)\n\nmodel = torchvision.models.detection.fasterrcnn_resnet50_fpn(\n    pretrained=True, progress=True, pretrained_backbone=False)\nin_features = model.roi_heads.box_predictor.cls_score.in_features\nmodel.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes=2)\n# model = nn.DataParallel(model)\nmodel.to(device=device)\n\nparams = [p for p in model.parameters() if p.requires_grad]\noptimizer = torch.optim.SGD(params, lr=learning_rate)\n\n# loop over the dataset multiple times\n\n# For saving best model\nbest_loss = float('inf')\n\n# For early stop\nsteps = 3\nprevious_loss = []\n\nfor epoch in range(epochs):\n    for iteration, data in enumerate(dataloader, 0):\n        images, targets, image_ids = data\n        images = images.to(device)\n        targets = [{'boxes': i['boxes'].to(\n            device), 'labels':i['labels'].to(device)} for i in targets]\n        # zero the parameter gradients\n        optimizer.zero_grad()\n\n        # forward + backward + optimize\n        loss_dict = model(images, targets)\n        loss = sum(loss for loss in loss_dict.values())\n        loss.backward()\n        optimizer.step()\n        if iteration % 50 == 0:\n            print(f\"Iteration {iteration} Loss: {loss.mean().item()}\")\ntorch.save(model, '/kaggle/working/final.pth')\n\nprint('Finished Training')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def eval_dataset(model_path, test_path='test'):\n    \"\"\"Evaluate Model. plot images\n\n    Args:\n        model_path: 'final.pth'.\n\n    Returns:\n        return result\n    \"\"\"\n    device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\n    model = torch.load(model_path)\n    model.to(device)\n    model.eval()\n    eval_dataset = WheatDatasetTest(test_path)\n    # Use batch_size == 1 for evaluation, DON't CHANGE\n    eval_dataloader = torch.utils.data.DataLoader(eval_dataset, batch_size=10)\n    results = []\n    submmision = open('submission.csv', 'w')\n    lines = []\n    for images, image_ids in eval_dataloader:\n        images = images.to(device)\n        outputs = model(images)\n        image_ids = list(map(lambda x: x.split(\n            '/')[-1].strip('.jpg'), image_ids))\n        for image_id, output_dict in zip(image_ids, outputs):\n            boxes = output_dict['boxes'].cpu().detach().numpy()\n            scores = output_dict['scores'].cpu().detach().numpy()\n            one_line = []\n            for score, box in zip(scores, boxes):\n                one_line.extend([str(score)] + [str(num) for num in box])\n            one_line = image_id + ',' + \" \".join(one_line)\n            submmision.writelines(one_line+'\\n')\n            lines.append(one_line)\n    # submmision.writelines(lines)\n    submmision.close()\n    # visualize to verify\n    # plt.figure(figsize=(20, 20))\n    # for i, res in enumerate(results):\n    #     out_dict, img_id = res\n    #     img = draw_multirectangles(out_dict['boxes'], img_id)\n    #     plt.subplot(2, 5, i+1)\n    #     plt.imshow(img)\n    # # Generate CSV submmision file.\n    # # Format: image_id, score x1, y1, x2, y2\n    return results","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!ls","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!ls /kaggle/input/global-wheat-detection/test","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"eval_dataset('final.pth', '/kaggle/input/global-wheat-detection/test')","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}