{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"!mkdir -p /tmp/pip/cache\n!cp ../input/piplocal/efficientnet_pytorch-0.7.0.xyz /tmp/pip/cache/efficientnet_pytorch-0.7.0.tar\n!cp ../input/piplocal/torch_optimizer-0.0.1a15-py3-none-any.xyz /tmp/pip/cache/torch_optimizer-0.0.1a15-py3-none-any.whl\n!cp ../input/piplocal/pytorch_ranger-0.1.1-py3-none-any.xyz /tmp/pip/cache/pytorch_ranger-0.1.1-py3-none-any.whl\n!pip install --no-index --find-links /tmp/pip/cache/ efficientnet_pytorch torch_optimizer pytorch_ranger\n\n!mkdir -p /root/.cache/torch/checkpoints\n!cp ../input/pytorchcheckpoints/efficientnet-b0-355c32eb.xyz /root/.cache/torch/checkpoints/efficientnet-b0-355c32eb.pth","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\nfrom efficientnet_pytorch import EfficientNet\nfrom PIL import Image\nimport torch\nfrom torchvision import transforms\nimport torch_optimizer\nimport time\nimport random\nimport os\nimport numpy as np\nimport gc\nfrom sklearn.preprocessing import LabelEncoder","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"BATCH_SIZE = 64\nLOG_STEPS = 10\nMIN_SAMPLES_PER_CLASS = 150","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"gc.enable()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_device():\n    if torch.cuda.is_available():\n        device_type = \"cuda\"\n        print(\"Train on GPU.\")\n    else:\n        device_type = \"cpu\"\n        print(\"Train on CPU.\")\n    device = torch.device(device_type)\n    \n    return device","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def fix_randomness(seed):\n    random.seed(seed)\n    os.environ[\"PYTHONHASHSEED\"] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = True\nfix_randomness(1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"device = get_device()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv(\"../input/landmark-recognition-2020/train.csv\")\n\ncounts = train_df[\"landmark_id\"].value_counts()\nselected = counts[counts >= MIN_SAMPLES_PER_CLASS].index\nprint('classes with at least N samples:', selected.shape[0])\ntrain_df = train_df[train_df[\"landmark_id\"].isin(selected)]\n\nlabel_encoder = LabelEncoder()\nlabel_encoder.fit(train_df[\"landmark_id\"].values)\nassert len(label_encoder.classes_) == selected.shape[0]\n\ntrain_df[\"landmark_id\"] = label_encoder.transform(train_df[\"landmark_id\"])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df = pd.read_csv(\"../input/landmark-recognition-2020/sample_submission.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"image_dir = \"../input/landmark-recognition-2020\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"id_ = train_df[\"id\"].iloc[2]\nprint(f\"ID: {id_}\")\nfilepath = \"{}/train/{}/{}/{}/{}.jpg\".format(image_dir, id_[0], id_[1], id_[2], id_)\nimg = Image.open(filepath)\n\nplt.figure(figsize=(5, 5))\nplt.imshow(img)\nplt.title(\"Landmark: {}\".format(train_df[train_df[\"id\"] == id_][\"landmark_id\"].iloc[0]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class ImageDataset(torch.utils.data.Dataset):\n    def __init__(self, df, image_dir, mode=\"train\"):\n        self.df = df\n        self.mode = mode\n        self.image_dir = image_dir\n        \n        transform_list = [\n            transforms.Resize((64, 64)),\n            transforms.ToTensor(),\n            transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                                std=[0.229, 0.224, 0.225]),\n        ]\n        self.transforms = transforms.Compose(transform_list)\n    \n    def __getitem__(self, index):\n        id_ = self.df[\"id\"].iloc[index]\n        filepath = \"{}/{}/{}/{}/{}/{}.jpg\".format(image_dir, self.mode, id_[0], id_[1], id_[2], id_)\n        img = Image.open(filepath)\n        img = self.transforms(img)\n        \n        if self.mode == \"train\":\n            return {\"image\": img, \"target\": self.df[\"landmark_id\"].iloc[index]}\n        elif self.mode == \"test\":\n            return {\"image\": img}\n\n    def __len__(self):\n        return self.df.shape[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class CustomizedEfficientNet(torch.nn.Module):\n    def __init__(self, num_classes):\n        super(CustomizedEfficientNet, self).__init__()\n        self.base = EfficientNet.from_pretrained(\"efficientnet-b0\")\n        self.avg_pool = torch.nn.AdaptiveAvgPool2d(1)\n        out = self.base._fc.in_features\n        self.fc = torch.nn.Linear(out, num_classes)\n    \n    def forward(self, x):\n        x = self.base.extract_features(x)\n        x = self.avg_pool(x).squeeze(-1).squeeze(-1)\n        x = self.fc(x)\n        return x","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def GAP(predicts, confs, targets):\n    _, indices = torch.sort(confs, descending=True)\n\n    confs = confs.cpu().numpy()\n    predicts = predicts[indices].cpu().numpy()\n    targets = targets[indices].cpu().numpy()\n    \n    correct = 0\n    for i, (p, c, t) in enumerate(zip(predicts, confs, targets)):\n        rel = int(p == t)\n        correct += rel\n        precision = correct * rel / (i+1)\n    \n    return correct / targets.shape[0]   # NEED TO FIX","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"num_classes = train_df[\"landmark_id\"].unique().shape[0]\nprint(num_classes)\n\ntrain_dataset = ImageDataset(train_df, image_dir)\ntrain_loader = torch.utils.data.DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=2, drop_last=True)\ntest_dataset = ImageDataset(test_df, image_dir, mode=\"test\")\ntest_loader = torch.utils.data.DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=2)\n\nmodel = CustomizedEfficientNet(num_classes)\nmodel.to(device)\noptimizer = torch_optimizer.RAdam(model.parameters(), lr=1e-3, betas=(0.9, 0.999), eps=1e-8, weight_decay=0)\nscheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=len(train_loader)*1, eta_min=1e-6)\n\n\nloss_fn = torch.nn.CrossEntropyLoss()\n\nnum_steps = len(train_loader)\n\nmodel.train()\nfor i, data in enumerate(train_loader):\n    start = time.time()\n    \n    optimizer.zero_grad()\n\n    X = data[\"image\"].to(device)\n    y = data[\"target\"].to(device)\n\n    output = model(X)\n    loss = loss_fn(output, y)\n    confs, preds = torch.max(output.detach(), dim=1)\n    gap = GAP(preds, confs, y)\n    \n    loss.backward()\n    optimizer.step()\n    scheduler.step()\n    lr = optimizer.param_groups[0]['lr']\n    \n    elapsed = time.time() - start\n    \n    if i % LOG_STEPS == 0:\n        print(f\"[{i}/{num_steps}]: time {elapsed}, GAP {gap}, lr {lr}\")\n\nall_confs = []\nall_preds = []\nwith torch.no_grad():\n    for i, data in enumerate(test_loader):\n        X = data[\"image\"].to(device)\n        \n        output = model(X)\n        confs, preds = torch.topk(output, 20)\n        all_confs.append(confs)\n        all_preds.append(preds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_confs = torch.cat(all_confs).cpu()\nsubmission_confs = np.array(submission_confs)\n\nsubmission_preds = torch.cat(all_preds).cpu()\nsubmission_preds = [label_encoder.inverse_transform(p) for p in submission_preds]\nsubmission_preds = np.array(submission_preds)\n\nlandmark = []\nfor c, p in zip(submission_confs, submission_preds):\n    c0 = c[0]\n    p0 = p[0]\n    landmark.append(f\"{c0} {p0}\")\n    #landmark.append(\" \".join([f\"{cc} {pp}\" for cc, pp in zip(c, p)]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_df = pd.read_csv(\"../input/landmark-recognition-2020/sample_submission.csv\")\n\nsubmission_df[\"landmarks\"] = landmark\nsubmission_df.set_index(\"id\", inplace=True)\nsubmission_df.to_csv(\"submission.csv\")","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}