{"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":"!pip install timm\n\nimport os\nimport gc\nimport cv2\nimport math\nimport copy\nimport time\nimport random\n\n# For data manipulation\nimport numpy as np\nimport pandas as pd\n\n# Pytorch Imports\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.nn.functional as F\nfrom torch.optim import lr_scheduler\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.cuda import amp\n\n# Utils\nimport joblib\nfrom tqdm import tqdm\nfrom collections import defaultdict\n\n# For Image Models\nimport timm\nfrom math import cos, pi\n\n# Albumentations for augmentations\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\n\nimport torch.cuda.amp as amp\n\n# For colored terminal text\nfrom colorama import Fore, Back, Style\nb_ = Fore.BLUE\nsr_ = Style.RESET_ALL\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\n# For descriptive error messages\nos.environ['CUDA_LAUNCH_BLOCKING'] = \"1\"","metadata":{"execution":{"iopub.status.busy":"2022-04-05T13:15:26.125209Z","iopub.execute_input":"2022-04-05T13:15:26.126176Z","iopub.status.idle":"2022-04-05T13:15:35.688261Z","shell.execute_reply.started":"2022-04-05T13:15:26.126139Z","shell.execute_reply":"2022-04-05T13:15:35.687155Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Config(object):\n      version = \"v19\"\n      model_name = \"tf_efficientnet_b5\"\n    \n      model = \"train\"\n    \n      learning_rate = 0.001\n    \n      start_fold = 0\n      start_epoch = 24 + 1\n\n      epochs = 30\n      \n      n_accumulate = 2\n    \n    \n      seed = 2022\n      img_size = (512, 512)\n    \n      # warmup\n      warmup_lr_min = 0.00008\n      warmup_epoch = 5\n\n      num_classes = 15587\n      train_batch_size = 10\n      valid_batch_size = 2\n\n      #input\n      TEST_DIR = '../input/backfin-test/test_images/'\n      TRAIN_DIR = '../input/backfin-train/train_images/'\n\n      train_csv = \"../input/train-csv/train_box_clear.csv\" \n      label_path = \"../input/happywhalelabel/label.csv\"   \n      sample_submission = \"../input/happy-whale-and-dolphin/sample_submission.csv\"\n      work_dirs = \"./\"\n\n      n_fold = 5\n      num_workers = 2\n\n      # ArcFace Hyperparametes\n      s = 30.0\n      m = 0.50\n      ls_eps = 0.0\n      easy_margin = False\n    \n      KNN = 100\n        \n      device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n\n\n\n\n    \nCONFIG = Config()\nprint (CONFIG.device)\n\ndef set_seed(seed=42):\n    '''Sets the seed of the entire notebook so results are the same every time we run.\n    This is for REPRODUCIBILITY.'''\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    # When running on the CuDNN backend, two further options must be set\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = False\n    # Set a fixed value for the hash seed","metadata":{"execution":{"iopub.status.busy":"2022-04-05T13:15:35.692747Z","iopub.execute_input":"2022-04-05T13:15:35.692986Z","iopub.status.idle":"2022-04-05T13:15:35.705341Z","shell.execute_reply.started":"2022-04-05T13:15:35.692957Z","shell.execute_reply":"2022-04-05T13:15:35.704283Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_transforms = {\n    \"train\": A.Compose([\n        A.Resize(CONFIG.img_size[1], CONFIG.img_size[0]),\n        A.HueSaturationValue(p=0.5, hue_shift_limit=20, sat_shift_limit=30, val_shift_limit=50),\n        A.HorizontalFlip(),\n        A.GaussianBlur(),\n        A.RandomBrightnessContrast(p=0.5),\n        A.ShiftScaleRotate(),\n        A.Normalize(\n            mean=[0.485, 0.456, 0.406],\n            std=[0.229, 0.224, 0.225],\n            max_pixel_value=255.0,\n            p=1.0\n        ),\n        ToTensorV2()], p=1.),\n\n    \"test\": A.Compose([\n        A.Resize(CONFIG.img_size[1], CONFIG.img_size[0]),\n        A.Normalize(\n            mean=[0.485, 0.456, 0.406],\n            std=[0.229, 0.224, 0.225],\n            max_pixel_value=255.0,\n            p=1.0\n        ),\n        ToTensorV2()], p=1.)\n}","metadata":{"execution":{"iopub.status.busy":"2022-04-05T13:15:35.706912Z","iopub.execute_input":"2022-04-05T13:15:35.707259Z","iopub.status.idle":"2022-04-05T13:15:35.722696Z","shell.execute_reply.started":"2022-04-05T13:15:35.707188Z","shell.execute_reply":"2022-04-05T13:15:35.721498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class HappyWhaleDataset(Dataset):\n    def __init__(self, df, model = \"train\", transforms=None, df_boxes = None):\n        self.model = model\n        if model not in [\"train\", \"triplet_train\", \"test_valid\", \"test\"]:\n            assert False, f\"{model} is not in [train, triplet_train, test_valid, test]\"\n\n        self.file_paths = df['file_path'].values\n        #self.check_image_path()\n\n        if self.model in [\"triplet_train\"]:\n            self.labels = df['individual_id'].values\n\n            self.dict_train = self.balance_train()\n            self.labels = list(self.dict_train.keys())\n\n        if self.model in [\"train\", \"test_valid\"]:\n            self.labels = df['individual_id'].values\n\n        if self.model in [\"test\"]:\n            self.labels = [-1] * len(self.file_paths)\n\n\n        self.transforms = transforms\n        self.df_boxes = None\n\n        if df_boxes is not None:\n            self.df_boxes = df_boxes.set_index('image', drop=False)\n\n    def check_image_path(self):\n        for file in self.file_paths:\n            if not os.path.exists(file):\n                print (file + \" if not exists!\")\n        print (\"check over!\")\n        return\n\n\n    def balance_train(self):\n        dict_train = {}\n        for file_path, label in zip(self.file_paths, self.labels):\n            if not label in dict_train.keys():\n                dict_train[label] = [file_path]\n            else:\n                dict_train[label].append(file_path)\n        return dict_train\n\n    def __len__(self):\n        return len(self.labels)\n\n\n    def get_image(self, img_path):\n        img = \" \"\n\n        img = cv2.imread(img_path)\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        if self.transforms:\n            img = self.transforms(image=img)[\"image\"]\n\n        return img\n\n    def test_getitem(self, index):\n        img_path = self.file_paths[index]\n        label = int(self.labels[index])\n        img_name = img_path.split('/')[-1]\n\n        img_name = img_name.split(\"_\")[-1]\n\n        img = self.get_image(img_path)\n\n        if self.model == \"train\":\n            return img, label,\n        if self.model in [\"test_valid\", \"test\"]:\n\n            return img, label, img_name\n\n    def train_getitem(self, index):\n        label = self.labels[index]\n        file_names = self.dict_train[label]\n        nums = len(file_names)\n        if nums == 1:\n            anchor_path = file_names[0]\n            positive_path = file_names[0]\n        else:\n            anchor_path, positive_path = random.sample(file_names, 2)\n\n        negative_label = random.choice(list(set(self.labels) ^ set([label])))\n        negative_path = random.choice(self.dict_train[negative_label])\n\n        anchor_img = self.get_image(anchor_path)\n        positive_img = self.get_image(positive_path)\n        negative_img = self.get_image(negative_path)\n\n        assert anchor_path != negative_path\n        return [anchor_img, positive_img, negative_img], [label, label, negative_label]\n\n\n    def __getitem__(self, index):\n\n        if self.model in [\"train\", \"test_valid\", \"test\"]:\n            return self.test_getitem(index)\n        if self.model in [\"triplet_train\"]:\n            return self.train_getitem(index)","metadata":{"execution":{"iopub.status.busy":"2022-04-05T13:15:35.727729Z","iopub.execute_input":"2022-04-05T13:15:35.728031Z","iopub.status.idle":"2022-04-05T13:15:35.751582Z","shell.execute_reply.started":"2022-04-05T13:15:35.727985Z","shell.execute_reply":"2022-04-05T13:15:35.750377Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#GeM Pooling\nclass GeM(nn.Module):\n    def __init__(self, p=3, eps=1e-6):\n        super(GeM, self).__init__()\n        self.p = nn.Parameter(torch.ones(1) * p)\n        self.eps = eps\n\n    def forward(self, x):\n        return self.gem(x, p=self.p, eps=self.eps)\n\n    def gem(self, x, p=3, eps=1e-6):\n        return F.avg_pool2d(x.clamp(min=eps).pow(p), (x.size(-2), x.size(-1))).pow(1. / p)\n\n    def __repr__(self):\n        return self.__class__.__name__ + \\\n               '(' + 'p=' + '{:.4f}'.format(self.p.data.tolist()[0]) + \\\n               ', ' + 'eps=' + str(self.eps) + ')'\n","metadata":{"execution":{"iopub.status.busy":"2022-04-05T13:15:35.753789Z","iopub.execute_input":"2022-04-05T13:15:35.754513Z","iopub.status.idle":"2022-04-05T13:15:35.767377Z","shell.execute_reply.started":"2022-04-05T13:15:35.754448Z","shell.execute_reply":"2022-04-05T13:15:35.766244Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def cosine_sim(x1, x2, dim=1, eps=1e-8):\n    ip = torch.mm(x1, x2.t())\n    w1 = torch.norm(x1, 2, dim)\n    w2 = torch.norm(x2, 2, dim)\n    return ip / torch.ger(w1,w2).clamp(min=eps)\n\nclass CosMarginProduct(nn.Module):\n    r\"\"\"Implement of large margin cosine distance: :\n    Args:\n        in_features: size of each input sample\n        out_features: size of each output sample\n        s: norm of input feature\n        m: margin\n    \"\"\"\n\n    def __init__(self, in_features, out_features, s=30.0, m=0.40):\n        super(CosMarginProduct, self).__init__()\n        self.in_features = in_features\n        self.out_features = out_features\n        self.s = s\n        self.m = m\n        self.weight = nn.Parameter(torch.FloatTensor(out_features, in_features))\n        nn.init.xavier_uniform_(self.weight)\n        #stdv = 1. / math.sqrt(self.weight.size(1))\n        #self.weight.data.uniform_(-stdv, stdv)\n\n    def forward(self, input, label):\n        cosine = cosine_sim(input, self.weight)\n        # cosine = F.linear(F.normalize(input), F.normalize(self.weight))\n        # --------------------------- convert label to one-hot ---------------------------\n        # https://discuss.pytorch.org/t/convert-int-into-one-hot-format/507\n        one_hot = torch.zeros_like(cosine)\n        one_hot.scatter_(1, label.view(-1, 1), 1.0)\n        # -------------torch.where(out_i = {x_i if condition_i else y_i) -------------\n        output = self.s * (cosine - one_hot * self.m)\n\n        return output\n    \nclass ArcMarginProduct(nn.Module):\n    r\"\"\"Implement of large margin arc distance: :\n        Args:\n            in_features: size of each input sample\n            out_features: size of each output sample\n            s: norm of input feature\n            m: margin\n            cos(theta + m)\n        \"\"\"\n    def __init__(self, in_features, out_features, s=30.0, \n                 m=0.50, easy_margin=False, ls_eps=0.0):\n        super(ArcMarginProduct, self).__init__()\n        self.in_features = in_features\n        self.out_features = out_features\n        self.s = s\n        self.m = m\n        self.ls_eps = ls_eps  # label smoothing\n        self.weight = nn.Parameter(torch.FloatTensor(out_features, in_features))\n        nn.init.xavier_uniform_(self.weight)\n\n        self.easy_margin = easy_margin\n        self.cos_m = math.cos(m)\n        self.sin_m = math.sin(m)\n        self.th = math.cos(math.pi - m)\n        self.mm = math.sin(math.pi - m) * m\n    def forward(self, input, label):\n        # --------------------------- cos(theta) & phi(theta) ---------------------\n        cosine = F.linear(F.normalize(input), F.normalize(self.weight))\n        sine = torch.sqrt(1.0 - torch.pow(cosine, 2))\n        phi = cosine * self.cos_m - sine * self.sin_m\n        if self.easy_margin:\n            phi = torch.where(cosine > 0, phi, cosine)\n        else:\n            phi = torch.where(cosine.to(dtype=phi.dtype)  > self.th, phi, cosine.to(dtype=phi.dtype)  - self.mm)\n        # --------------------------- convert label to one-hot ---------------------\n        # one_hot = torch.zeros(cosine.size(), requires_grad=True, device='cuda')\n        one_hot = torch.zeros(cosine.size(), device=CONFIG.device)\n        one_hot.scatter_(1, label.view(-1, 1).long(), 1)\n        if self.ls_eps > 0:\n            one_hot = (1 - self.ls_eps) * one_hot + self.ls_eps / self.out_features\n        # -------------torch.where(out_i = {x_i if condition_i else y_i) ------------\n        output = (one_hot * phi) + ((1.0 - one_hot) * cosine)\n        output *= self.s\n\n        return output","metadata":{"execution":{"iopub.status.busy":"2022-04-05T13:15:35.771205Z","iopub.execute_input":"2022-04-05T13:15:35.771540Z","iopub.status.idle":"2022-04-05T13:15:35.796609Z","shell.execute_reply.started":"2022-04-05T13:15:35.771457Z","shell.execute_reply":"2022-04-05T13:15:35.795297Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\ndef l2_norm(input,axis=1):\n    norm = torch.norm(input,2,axis,True)\n    output = torch.div(input, norm)\n    return output\n\nclass BinaryHead(nn.Module):\n\n    def __init__(self, emb_size = 2048, num_class=10008,  s = 16.0):\n        super(BinaryHead,self).__init__()\n        self.s = s\n        self.fc = nn.Sequential(nn.Linear(emb_size, num_class))\n\n    def forward(self, fea):\n        fea = l2_norm(fea)\n        logit = self.fc(fea)*self.s\n        return logit\n\n\nclass ArcMarginHead(nn.Module):\n    def __init__(self, embedding_size, num_classes):\n        super(ArcMarginHead, self).__init__()\n        self.arc = ArcMarginProduct(embedding_size, num_classes)\n\n    def forward(self, fea, label):\n        logit = self.arc(fea, label)\n        return logit\n\n\nclass CosMarginHead(nn.Module):\n    def __init__(self, embedding_size, num_classes):\n        super(CosMarginHead, self).__init__()\n        self.cos = CosMarginProduct(embedding_size, num_classes)\n\n    def forward(self, fea, label):\n        logit = self.cos(fea, label)\n        return logit\n    \n#attention\nclass ChannelAttention(nn.Module):\n    def __init__(self, channel, reduction=16):\n        super().__init__()\n        self.maxpool = nn.AdaptiveMaxPool2d(1)\n        self.avgpool = nn.AdaptiveAvgPool2d(1)\n        self.se = nn.Sequential(\n            nn.Conv2d(channel, channel // reduction, 1, bias=False),\n            nn.ReLU(),\n            nn.Conv2d(channel // reduction, channel, 1, bias=False)\n        )\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        max_result = self.maxpool(x)\n        avg_result = self.avgpool(x)\n        max_out = self.se(max_result)\n        avg_out = self.se(avg_result)\n        output = self.sigmoid(max_out + avg_out)\n        return output\n    \nclass SpatialAttention(nn.Module):\n    def __init__(self, kernel_size=7):\n        super().__init__()\n        self.conv = nn.Conv2d(2, 1, kernel_size=kernel_size, padding=(kernel_size -1) // 2)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        max_result, _ = torch.max(x, dim=1, keepdim=True)\n        avg_result = torch.mean(x, dim=1, keepdim=True)\n        result = torch.cat([max_result, avg_result], 1)\n        output = self.conv(result)\n        output = self.sigmoid(output)\n        return output\n\n    \nclass CBAMBlock(nn.Module):\n\n    def __init__(self, channel=512, reduction=16):\n        super().__init__()\n        self.ca = ChannelAttention(channel=channel, reduction=reduction)\n        self.sa = SpatialAttention()\n\n    def init_weights(self):\n        for m in self.modules():\n            if isinstance(m, nn.Conv2d):\n                init.kaiming_normal_(m.weight, mode='fan_out')\n                if m.bias is not None:\n                    init.constant_(m.bias, 0)\n            elif isinstance(m, nn.BatchNorm2d):\n                init.constant_(m.weight, 1)\n                init.constant_(m.bias, 0)\n            elif isinstance(m, nn.Linear):\n                init.normal_(m.weight, std=0.001)\n                if m.bias is not None:\n                    init.constant_(m.bias, 0)\n    def forward(self, x):\n        b, c, _, _ = x.size()\n        residual = x\n        out = x * self.ca(x)\n        out = out * self.sa(out)\n        return out + residual ","metadata":{"execution":{"iopub.status.busy":"2022-04-05T13:15:35.798353Z","iopub.execute_input":"2022-04-05T13:15:35.800860Z","iopub.status.idle":"2022-04-05T13:15:35.828746Z","shell.execute_reply.started":"2022-04-05T13:15:35.800813Z","shell.execute_reply":"2022-04-05T13:15:35.827527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class FocalLoss(nn.Module):\n\n    def __init__(self, gamma=0, eps=1e-7):\n        super(FocalLoss, self).__init__()\n        self.gamma = gamma\n        self.eps = eps\n        self.ce = torch.nn.CrossEntropyLoss()\n\n    def forward(self, input, target):\n        logp = self.ce(input, target)\n        p = torch.exp(-logp)\n        loss = (1 - p) ** self.gamma * logp\n        return loss.mean()\n   \n\ndef focal_loss(outputs, labels):\n    return FocalLoss(gamma=2).to(CONFIG.device)(outputs, labels)\n\nclass BinaryHead(nn.Module):\n\n    def __init__(self, emb_size = 2048, num_class=10008,  s = 16.0):\n        super(BinaryHead,self).__init__()\n        self.s = s\n        self.fc = nn.Sequential(nn.Linear(emb_size, num_class))\n\n    def forward(self, fea):\n        fea = l2_norm(fea)\n        logit = self.fc(fea)*self.s\n        return logit\n","metadata":{"execution":{"iopub.status.busy":"2022-04-05T13:15:35.832396Z","iopub.execute_input":"2022-04-05T13:15:35.833097Z","iopub.status.idle":"2022-04-05T13:15:35.846088Z","shell.execute_reply.started":"2022-04-05T13:15:35.833049Z","shell.execute_reply":"2022-04-05T13:15:35.844982Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class HappyWhaleModel(nn.Module):\n    def __init__(self, model_name, pretrained=True):\n        super(HappyWhaleModel, self).__init__()\n        self.model = timm.create_model(model_name, pretrained=pretrained)\n\n        in_features = self.model.classifier.in_features\n        self.model.classifier = nn.Identity()\n        self.model.global_pool = nn.Identity()\n\n        self.pooling = GeM()\n        \n        #self.attention = CBAMBlock(channel=in_features, reduction=16)\n\n        embedding_size = in_features\n        self.neck1 = nn.Sequential(\n            nn.Dropout(p=0.2, inplace=False),\n            nn.Linear(in_features, embedding_size , bias = True),\n            nn.BatchNorm1d(embedding_size),\n            nn.PReLU(),\n        )\n\n        self.neck2 = nn.Sequential(\n            nn.Dropout(p=0.2, inplace=False),\n            nn.Linear(in_features, embedding_size, bias=True),\n            nn.BatchNorm1d(embedding_size),\n            nn.PReLU()\n        )\n\n\n        self.neck3 = nn.Sequential(\n            nn.Dropout(p=0.2, inplace=False),\n            nn.Linear(in_features, embedding_size, bias=True),\n            nn.BatchNorm1d(embedding_size),\n            nn.PReLU()\n        )\n\n        self.arc= ArcMarginHead(embedding_size, CONFIG.num_classes)\n        self.cos = CosMarginHead(embedding_size, CONFIG.num_classes)\n        self.binary = BinaryHead(embedding_size, CONFIG.num_classes)\n\n\n\n    def forward(self, images, labels):\n\n        features = self.model(images)\n        #features = self.attention(features)\n        \n        gem_fea = self.pooling(features).flatten(1)\n\n        embedding1 = self.neck1(gem_fea)\n        binary_outputs1 = self.binary(embedding1)\n\n        embedding2 = self.neck2(gem_fea)\n        arc_outputs2 = self.arc(embedding2, labels)\n\n        embedding3 = self.neck3(gem_fea)\n        cos_outputs3 = self.cos(embedding3, labels)\n\n        return binary_outputs1, arc_outputs2, cos_outputs3\n\n    def get_loss(self, binary_outputs1, arc_outputs2, cos_outputs3, labels):\n        binary_loss1 = focal_loss(binary_outputs1, labels)\n        arc_loss2 = focal_loss(arc_outputs2, labels)\n        cos_loss3 = focal_loss(cos_outputs3, labels)\n        return binary_loss1, arc_loss2, cos_loss3\n\n\n\n    def inference(self, images):\n        features = self.model(images)\n        \n        #features = self.attention(features)\n        gem_fea = self.pooling(features).flatten(1)\n\n        embedding1 = self.neck1(gem_fea)\n        embedding2 = self.neck2(gem_fea)\n        embedding3 = self.neck3(gem_fea)\n        embedding = torch.cat((embedding1, embedding2, embedding3), dim = 1)\n        return embedding\n\n\n    def freeze(self):\n        for param in self.model.parameters():\n            param.requires_grad = False\n\n    def unfreeze(self):\n        for param in self.model.parameters():\n            param.requires_grad = True\n\n    def train(self, mode=True):\n        \"\"\"\n        Override the default train() to freeze the BN parameters\n        \"\"\"\n\n        super(HappyWhaleModel, self).train(mode)\n\n        if mode:\n            freeze_bn = True\n            freeze_bn_affine = False\n\n            if freeze_bn:\n                print(\"Freezing Mean/Var of BatchNorm2D.\")\n                for m in self.model.modules():\n                    if isinstance(m, nn.BatchNorm2d):\n                        m.eval()\n                        if freeze_bn_affine:\n                            print(\"Freezing Weight/Bias of BatchNorm2D.\")\n                            m.weight.requires_grad = False\n                            m.bias.requires_grad = False\n","metadata":{"execution":{"iopub.status.busy":"2022-04-05T13:15:35.850498Z","iopub.execute_input":"2022-04-05T13:15:35.850796Z","iopub.status.idle":"2022-04-05T13:15:35.875673Z","shell.execute_reply.started":"2022-04-05T13:15:35.850759Z","shell.execute_reply":"2022-04-05T13:15:35.874619Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_list = ['938b7e931166', '5bf17305f073', '7593d2aee842', '7362d7a01d00','956562ff2888']\nfrom sklearn.neighbors import NearestNeighbors\n\nclass EmbedFeatureCom():\n    def __init__(self, weights, resuled_csv_path):\n\n        target_df = pd.read_csv(CONFIG.label_path)\n\n        self.resuled_csv_path = resuled_csv_path\n\n        self.inverse_encodings = target_df.set_index([\"id\"])[\"individual_name\"].to_dict()\n        self.encodings = target_df.set_index([\"individual_name\"])[\"id\"].to_dict()\n\n        self.train_df = pd.read_csv(CONFIG.train_csv)\n        self.train_df['file_path'] = \"_\" + self.train_df['image']\n        self.train_df['file_path'] = self.train_df['individual_id'].astype(\"str\") + self.train_df['file_path']\n        self.train_df['file_path'] = CONFIG.TRAIN_DIR + self.train_df['file_path']\n \n\n\n        self.test_df = pd.read_csv(CONFIG.sample_submission)\n        self.test_df['file_path'] = CONFIG.TEST_DIR + self.test_df['image']\n        self.test_df[\"predictions\"] = ''\n        \n        #self.train_df = self.train_df.iloc[:100]\n        #self.test_df = self.test_df.iloc[:10]\n        \n        \n\n\n        self.models = []\n        for weight in weights:\n            model = HappyWhaleModel(CONFIG.model_name)\n            model.load_state_dict(torch.load(weight))\n            model.to(CONFIG.device)\n            model.eval()\n            self.models.append(model)\n\n\n\n\n    def map_per_image(self, label, predictions):\n\n        try:\n            return 1 / (predictions[:5].index(label) + 1)\n        except ValueError:\n            return 0.0\n\n    def get_loaders(self, df, mode):\n\n        dataset = HappyWhaleDataset(df, mode, transforms=data_transforms[\"test\"])\n        loader = DataLoader(dataset, batch_size=CONFIG.valid_batch_size,\n                            num_workers=CONFIG.num_workers, shuffle=False, pin_memory=True)\n\n        return loader\n\n\n    def get_embeddings(self, data_loader):\n        targets_container  = []\n        embeddings_container  = []\n        names_container = []\n        with torch.no_grad():\n            for i, (images, targets, image_names) in tqdm(enumerate(data_loader), total=len(data_loader)):\n\n                images = images.to(CONFIG.device, dtype=torch.float)\n                embeddings = []\n                for model in self.models:\n                    embedding = model.inference(images)\n                    embeddings.append(embedding.cpu().numpy())\n\n                embedding = np.mean(np.stack(embeddings), axis=0)\n                embeddings_container.append(embedding)\n\n\n                targets_container.append(np.array(targets))\n                names_container.append(np.array(image_names))\n\n            embeddings_container = np.concatenate(embeddings_container)\n            labels_container = np.concatenate(targets_container)\n            names_container = np.concatenate(names_container)\n\n        return embeddings_container, labels_container, names_container\n\n\n\n    def get_Neighbors_dis(self, neigh, embeddings, names, train_targets, train_species):\n        test_nn_distances, test_nn_idxs = neigh.kneighbors(embeddings, CONFIG.KNN, return_distance=True)\n\n        test_df = []\n        for i in tqdm(range(len(names))):\n            id_ = names[i]\n            labels = train_targets[test_nn_idxs[i]]\n            distances = test_nn_distances[i]\n\n            species = train_species[test_nn_idxs[i]]\n            subset_preds = pd.DataFrame(np.stack([labels, distances, species], axis=1), columns=['target', 'distances', 'species'])\n\n            subset_preds['target'] = subset_preds['target'].astype('int')\n            subset_preds['distances'] = subset_preds['distances'].astype('float')\n            subset_preds['image'] = id_\n            test_df.append(subset_preds)\n\n        test_df = pd.concat(test_df).reset_index(drop=True)\n        test_df['confidence'] = 1 - test_df['distances']\n\n        return test_df\n\n\n\n\n    def get_test_Neighbors(self):\n\n        train_loader = self.get_loaders(self.train_df, mode=\"test_valid\")\n        train_embeddings, train_targets, train_names = self.get_embeddings(train_loader)\n\n        train_species = []\n        train_df = self.train_df.set_index(\"image\")\n        for train_name in train_names:\n            species = train_df.loc[train_name].species\n            train_species.append(species)\n\n        train_species = np.array(train_species)\n        neigh = NearestNeighbors(n_neighbors=CONFIG.KNN, metric='cosine')\n        neigh.fit(train_embeddings)\n\n\n        test_loader = self.get_loaders(self.test_df, mode=\"test\")\n        test_embeddings, _, test_names = self.get_embeddings(test_loader)\n\n\n        test_df = self.get_Neighbors_dis(neigh, test_embeddings, test_names, train_targets, train_species)\n\n        test_df.to_csv(CONFIG.version + \"_test_df_submission.csv\", index=False)\n      \n        test_df = test_df.groupby(\n            ['image', 'target']).confidence.max().reset_index()\n\n        test_df = test_df.sort_values('confidence', ascending=False).reset_index(drop=True)\n\n        test_df['target'] = test_df['target'].map(self.inverse_encodings)\n\n        test_df.image.value_counts().value_counts()\n\n        best_threshold_adjusted = 0.6\n\n        predictions = self.get_predictions(test_df, threshold=best_threshold_adjusted)\n\n        for x in predictions:\n            predictions[x] = ' '.join(predictions[x])\n\n        predictions = pd.Series(predictions).reset_index()\n        predictions.columns = ['image', 'predictions']\n        predictions.to_csv(self.resuled_csv_path, index=False)\n        predictions.head()\n\n\n\n\n    def get_predictions(self, dis_df, threshold=0.2):\n        predictions = {}\n\n        for i, row in dis_df.iterrows():\n\n            if row.image in predictions:\n                if len(predictions[row.image]) == 5:\n                    continue\n                predictions[row.image].append(row.target)\n            elif row.confidence > threshold:\n                predictions[row.image] = [row.target, 'new_individual']\n            else:\n                predictions[row.image] = ['new_individual', row.target]\n\n        for x in predictions:\n            if len(predictions[x]) < 5:\n                remaining = [y for y in sample_list if y not in predictions]\n                predictions[x] = predictions[x] + remaining\n                predictions[x] = predictions[x][:5]\n\n        return predictions\n\n\n    def get_Neighbors_score(self, fold):\n\n        '''\n\n        df_train = self.train_df[self.train_df.kfold != fold].reset_index(drop=True)\n        df_valid = self.train_df[self.train_df.kfold == fold].reset_index(drop=True)\n        '''\n\n        valid_proportion = 0.1\n\n        df_valid = self.train_df.sample(frac=valid_proportion, replace=False, random_state=1).copy()\n        df_train = self.train_df[~self.train_df['image'].isin(df_valid['image'])].copy()\n\n\n        train_targets = np.array(df_train.individual_id)\n        valid_names = np.array(df_valid.image)\n        valid_targets = np.array(df_valid.individual_id)\n\n\n        train_loader = self.get_loaders(df_train, mode=\"test_valid\")\n        valid_loader = self.get_loaders(df_valid, mode=\"test_valid\")\n\n        train_embeddings, train_targets, train_names = self.get_embeddings(train_loader)\n\n        train_species = []\n        train_df = self.train_df.set_index(\"image\")\n        for train_name in train_names:\n            species = train_df.loc[train_name].species\n            train_species.append(species)\n\n        train_species = np.array(train_species)\n\n\n        neigh = NearestNeighbors(n_neighbors=CONFIG.KNN, metric='cosine')\n        neigh.fit(train_embeddings)\n\n        valid_embeddings, valid_targets, valid_names = self.get_embeddings(valid_loader)\n\n        df_valid1 =df_valid[[\"image\", \"species\"]]\n        df_valid1 = df_valid1.rename(columns=lambda x: x.replace('species', 'test_species'))\n        df_valid1 = df_valid1.reset_index(drop=True)\n        test_df = self.get_Neighbors_dis(neigh, valid_embeddings, valid_names, train_targets, train_species)\n\n        test_df = pd.merge(test_df, df_valid1, how='left', on='image')\n        test_df.to_csv(CONFIG.version + \"_test_df_scores.csv\", index=False)\n\n\n        #test_df = pd.read_csv(\"test_df_scores.csv\")\n\n        test_df = test_df.groupby(['image', 'target', 'species', 'test_species']).confidence.max().reset_index()\n\n        test_df = test_df.sort_values('confidence', ascending=False).reset_index(drop=True)\n        test_df['target'] = test_df['target'].map(self.inverse_encodings)\n\n        allowed_targets = set([self.inverse_encodings[x] for x in np.unique(train_targets)])\n        val_targets_df = pd.DataFrame(np.stack([valid_names, valid_targets], axis=1), columns=['image', 'target'])\n        val_targets_df['target'] = val_targets_df['target'].astype(int).map(self.inverse_encodings)\n\n\n        val_targets_df.loc[~val_targets_df.target.isin(allowed_targets), 'target'] = 'new_individual'\n        val_targets_df.target.value_counts()\n\n        ## Compute CV\n        best_cv = 0\n        for th in [0.1 * x for x in range(11)]:\n            all_preds = self.get_predictions(test_df, threshold=th)\n            for i, row in val_targets_df.iterrows():\n                target = row.target\n                preds = all_preds[row.image]\n                val_targets_df.loc[i, th] = self.map_per_image(target, preds)\n            cv = val_targets_df[th].mean()\n            print(f\"CV at threshold {round(th, 2)}: {cv}\")\n            if cv > best_cv:\n                best_th = th\n                best_cv = cv\n                \nweight1 = \"../input/weights/best_v25_fold0_Loss3.1968_epoch_29.bin\"\n\nweights = [weight1]\nname = (weight1.split('/')[-1])[:-4]\nresuled_csv_path = \"./{}_{}.csv\".format(CONFIG.version, name)\n\ncomper = EmbedFeatureCom(weights, resuled_csv_path)\n#comper.get_Neighbors_score(fold = 0)\ncomper.get_test_Neighbors()","metadata":{"execution":{"iopub.status.busy":"2022-04-05T13:15:35.880240Z","iopub.execute_input":"2022-04-05T13:15:35.880525Z","iopub.status.idle":"2022-04-05T13:15:45.728093Z","shell.execute_reply.started":"2022-04-05T13:15:35.880452Z","shell.execute_reply":"2022-04-05T13:15:45.727050Z"},"trusted":true},"execution_count":null,"outputs":[]}]}