{"cells":[{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","collapsed":true,"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":false},"cell_type":"markdown","source":"lets open the file train.csv ,label.csv and describe submission.csv"},{"metadata":{"trusted":true},"cell_type":"code","source":"import json\nimport pandas as pd","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with open('/kaggle/input/imaterialist-fashion-2020-fgvc7/label_descriptions.json', 'r') as file: ## using with to remove works of json\n    label_desc = json.load(file)\nsample_sub_df = pd.read_csv('/kaggle/input/imaterialist-fashion-2020-fgvc7/sample_submission.csv')\ntrain_csv_df = pd.read_csv('/kaggle/input/imaterialist-fashion-2020-fgvc7/train.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"label_desc","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"label_desc.keys()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Details about Classes and Attributes"},{"metadata":{"trusted":true},"cell_type":"code","source":"num_classes = len(label_desc['categories'])\nnum_attributes = len(label_desc['attributes'])\nprint(f'Total # of classes: {num_classes}')\nprint(f'Total # of attributes: {num_attributes}')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"as we can see the categories. it has key id,name,supercategory,level / attributes,\nlets devide categroies and attrubute"},{"metadata":{"trusted":true},"cell_type":"code","source":"categories_df = pd.DataFrame(label_desc.get('categories'))\nattributes_df = pd.DataFrame(label_desc['attributes'])\ncategories_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"attributes_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.set_option('display.max_rows' , 294)\nattributes_df","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"see the distribution"},{"metadata":{"trusted":true},"cell_type":"code","source":"import seaborn as sns\nimport matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig,ax = plt.subplots(1,2,figsize = (20,20))\nsns.countplot('supercategory',data = attributes_df,ax = ax[0])\nsns.countplot('supercategory',data = categories_df,ax = ax[1])\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig,ax = plt.subplots(1,2,figsize = (20,20))\nsns.countplot('level',data = attributes_df,ax = ax[0])\nsns.countplot('level',data = categories_df,ax = ax[1])\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"so attributes based on level 1 , supercategory feature we need to regenerate\ncategories based on level 2, supercateogry feature distributes well\nlets see submission and train datasets"},{"metadata":{"trusted":true},"cell_type":"code","source":"sample_sub_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_csv_df","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"as we can see, the EncodedPixels is complicated\nwhat i understand is first which is spilted is Encoded, second is run-length as string formated: [start0] [length0] [start1] [length1]... in 1d array\nand we can see the difference every single Height and Width\nso pop out the Height and Width, unify them\nand consider category and attribute which are in the label_desc"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_csv = train_csv_df.groupby('ImageId')['Height','Width'].first().hist(bins = 100)\ntrain_csv","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"before define the Height and Width we saw the skeness and lets see the number of mean, max, min\nand then decide between max and min "},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.DataFrame([train_csv_df['Height'].describe(), train_csv_df['Width'].describe()]).T.loc[['min','max','mean']]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"So we got min, max, mean,\nNext consider mask using Encode\nwe need to seperate between Encoded and run_length"},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch\nimport torch.utils","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import collections\nfrom tqdm import tqdm","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def rle_decode(mask_rle, shape):\n    '''\n    mask_rle: run-length as string formated: [start0] [length0] [start1] [length1]... in 1d array\n    shape: (height,width) of array to return\n    Returns numpy array according to the shape, 1 - mask, 0 - background\n    '''\n    shape = (shape[1], shape[0])\n    s = mask_rle.split()\n    # gets starts & lengths 1d arrays\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0::2], s[1::2])]\n    starts -= 1\n    # gets ends 1d array\n    ends = starts + lengths\n    # creates blank mask image 1d array\n    img = np.zeros(shape[0] * shape[1], dtype=np.uint8)\n    # sets mark pixles\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    # reshape as a 2d mask image\n    return img.reshape(shape).T  # Needed to align to RLE direction\n\n\n\nclass FashionDataset(torch.utils.data.Dataset):\n    def __init__(self, image_dir, df_path, height, width, transforms=None):\n        self.transforms = transforms\n        self.image_dir = image_dir\n        self.df = pd.read_csv(df_path, nrows=10000)\n        self.height = height\n        self.width = width\n        self.image_info = collections.defaultdict(dict)\n        self.df['CategoryId'] = self.df.ClassId.apply(lambda x: str(x).split(\"_\")[0])\n        temp_df = self.df.groupby('ImageId')['EncodedPixels', 'CategoryId'].agg(lambda x: list(x)).reset_index()\n        size_df = self.df.groupby('ImageId')['Height', 'Width'].mean().reset_index()\n        temp_df = temp_df.merge(size_df, on='ImageId', how='left')\n        for index, row in tqdm(temp_df.iterrows(), total=len(temp_df)):\n            image_id = row['ImageId']\n            image_path = os.path.join(self.image_dir, image_id)\n            self.image_info[index][\"image_id\"] = image_id\n            self.image_info[index][\"image_path\"] = image_path\n            self.image_info[index][\"width\"] = self.width\n            self.image_info[index][\"height\"] = self.height\n            self.image_info[index][\"labels\"] = row[\"CategoryId\"]\n            self.image_info[index][\"orig_height\"] = row[\"Height\"]\n            self.image_info[index][\"orig_width\"] = row[\"Width\"]\n            self.image_info[index][\"annotations\"] = row[\"EncodedPixels\"]\n\n    def __getitem__(self, idx):\n        # load images ad masks\n        img_path = self.image_info[idx][\"image_path\"]\n        img = Image.open(img_path).convert(\"RGB\")\n        img = img.resize((self.width, self.height), resample=Image.BILINEAR)\n\n        info = self.image_info[idx]\n        mask = np.zeros((len(info['annotations']), self.width, self.height), dtype=np.uint8)\n        labels = []\n        for m, (annotation, label) in enumerate(zip(info['annotations'], info['labels'])):\n            sub_mask = rle_decode(annotation, (info['orig_height'], info['orig_width']))\n            sub_mask = Image.fromarray(sub_mask)\n            sub_mask = sub_mask.resize((self.width, self.height), resample=Image.BILINEAR)\n            mask[m, :, :] = sub_mask\n            labels.append(int(label) + 1)\n\n        num_objs = len(labels)\n        boxes = []\n        new_labels = []\n        new_masks = []\n\n        for i in range(num_objs):\n            try:\n                pos = np.where(mask[i, :, :])\n                xmin = np.min(pos[1])\n                xmax = np.max(pos[1])\n                ymin = np.min(pos[0])\n                ymax = np.max(pos[0])\n                if abs(xmax - xmin) >= 20 and abs(ymax - ymin) >= 20:\n                    boxes.append([xmin, ymin, xmax, ymax])\n                    new_labels.append(labels[i])\n                    new_masks.append(mask[i, :, :])\n            except ValueError:\n                continue\n\n        if len(new_labels) == 0:\n            boxes.append([0, 0, 20, 20])\n            new_labels.append(0)\n            new_masks.append(mask[0, :, :])\n\n        nmx = np.zeros((len(new_masks), self.width, self.height), dtype=np.uint8)\n        for i, n in enumerate(new_masks):\n            nmx[i, :, :] = n\n\n        boxes = torch.as_tensor(boxes, dtype=torch.float32)\n        labels = torch.as_tensor(new_labels, dtype=torch.int64)\n        masks = torch.as_tensor(nmx, dtype=torch.uint8)\n\n        image_id = torch.tensor([idx])\n        area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])\n        iscrowd = torch.zeros((num_objs,), dtype=torch.int64)\n\n        target = {}\n        target[\"boxes\"] = boxes\n        target[\"labels\"] = labels\n        target[\"masks\"] = masks\n        target[\"image_id\"] = image_id\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.image_info)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Preprocessing:\nI applied light augmentatios from the albumentations library to the original image. Then I use multi-scale training: in each iteration, the scale of short edge is randomly sampled\nfrom [600, 1200], and the scale of long edge is fixed as 1900.\n![preprocessing](https://raw.githubusercontent.com/amirassov/kaggle-imaterialist/master/figures/preproc.png)\nthere is based on [2019 1st solution](https://www.kaggle.com/c/imaterialist-fashion-2019-FGVC6/discussion/95247)\nMulti-scale training with flipping and resizing range (512,512) -> (1333,1333)\nthere is based on [16th soulution](https://www.kaggle.com/c/imaterialist-fashion-2019-FGVC6/discussion/95249)"},{"metadata":{"trusted":true},"cell_type":"code","source":"from torchvision import transforms","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"transform = transforms.Compose([transforms.ToTensor(),\n                                transforms.RandomApply([transforms.Resize([1333,1333]),\n                                                      transforms.RandomHorizontalFlip(),\n                                                      transforms.ColorJitter(brightness= 0.3, contrast= 0.3,saturation=0.1, hue=0.1)],\n                                                       p=0.5),\n                                transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n                                      ])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"num_classes = 46 + 1\ndevice = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dataset_train = FashionDataset(\"/kaggle/input/imaterialist-fashion-2020-fgvc7/train/\",\n                               \"/kaggle/input/imaterialist-fashion-2020-fgvc7/train.csv\",\n                               512,\n                               512,\n                               transforms=transform\n                              )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from PIL import Image, ImageFile\nimport torchvision\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor\nfrom torchvision.models.detection.mask_rcnn import MaskRCNNPredictor","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_ft =torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=True)\nin_features = model_ft.roi_heads.box_predictor.cls_score.in_features\nmodel_ft.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)\nin_features_mask = model_ft.roi_heads.mask_predictor.conv5_mask.in_channels\nhidden_layer = 256\nmodel_ft.roi_heads.mask_predictor = MaskRCNNPredictor(in_features_mask, hidden_layer, num_classes)\nmodel_ft.to(device)\nfor param in model_ft.parameters():\n    param.requires_grad = True","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data_loader = torch.utils.data.DataLoader(\n    dataset_train, batch_size=16, shuffle=True, num_workers=8,\n    collate_fn=lambda x: tuple(zip(*x)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install -U pytorch_warmup\nimport pytorch_warmup as warmup","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for param in model_ft.parameters():\n    param.requires_grad = False\nmodel_ft.eval()\noptimizer = torch.optim.SGD(params, lr=0.03, momentum=0.9, weight_decay=0.0001)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def train_one_epoch(model, optimizer, data_loader, device, epoch, print_freq):\n    model.train()\n    metric_logger = MetricLogger(delimiter=\"  \")\n    metric_logger.add_meter('lr', SmoothedValue(window_size=1, fmt='{value:.6f}'))\n    header = 'Epoch: [{}]'.format(epoch)\n\n    lr_scheduler = None\n    if iterations < 500: \n        lr = warmup(warmup_factor = 1. / 3) \n    if epochs == 10: lr = warmup(warmup_factor = 1. / 10) \n    if epochs == 18: lr = warmup(warmup_factor = 1. / 10) \n    if epochs > 20: stop\n    lr_scheduler = warmup_lr_scheduler(optimizer, warmup_iters, step_size=5, gamma=0.1)\n\n    for images, targets in metric_logger.log_every(data_loader, print_freq, header):\n        images = list(image.to(device) for image in images)\n        targets = [{k: v.to(device) for k, v in t.items()} for t in targets]\n\n        loss_dict = model(images, targets)\n\n        losses = sum(loss for loss in loss_dict.values())\n\n        # reduce losses over all GPUs for logging purposes\n        loss_dict_reduced = reduce_dict(loss_dict)\n        losses_reduced = sum(loss for loss in loss_dict_reduced.values())\n\n        optimizer.zero_grad()\n        losses.backward()\n        optimizer.step()\n\n        if lr_scheduler is not None:\n            lr_scheduler.step()\n\n        metric_logger.update(loss=losses_reduced, **loss_dict_reduced)\n        metric_logger.update(lr=optimizer.param_groups[0][\"lr\"])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from __future__ import print_function\n\nfrom collections import defaultdict, deque\nimport datetime\nimport pickle\nimport time\nimport torch.distributed as dist\nimport errno\n\nimport collections\nimport os\nimport numpy as np\nimport torch\nimport torch.utils.data\nfrom PIL import Image, ImageFile\nimport pandas as pd\nfrom tqdm import tqdm\nfrom torchvision import transforms\nimport torchvision\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor\nfrom torchvision.models.detection.mask_rcnn import MaskRCNNPredictor\n\nImageFile.LOAD_TRUNCATED_IMAGES = True","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"num_epochs = 20\nfor epoch in range(num_epochs):\n    train_one_epoch(model_ft, optimizer, data_loader, device, epoch, print_freq=100)\n    lr_scheduler.step()","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}