{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Copy the Pretrained Models to Torch Cache Directory"},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\n\nif not os.path.exists(\"/root/.cache/torch/hub/checkpoints/\"):\n    os.makedirs(\"/root/.cache/torch/hub/checkpoints/\")\n!cp ../input/pretrained-model-weights-pytorch/resnet18-5c106cde.pth /root/.cache/torch/hub/checkpoints/","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Imports"},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport zipfile\nimport shutil\nimport math\nimport time","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Preprocessing"},{"metadata":{"trusted":true},"cell_type":"code","source":"work_dir = \"/kaggle/working\"\ndataset_dir = \"/kaggle/working/data\"\n\n# Delete the residues\n!rm -rf $dataset_dir\n\n# Create the dataset directory\nos.makedirs(dataset_dir)\n\n# Change the working directory\nos.chdir(work_dir)\n\n# Unzip the data to datset_directory\nzip_files = ['test1', 'train']\nfor zip_file in zip_files:\n    with zipfile.ZipFile(f\"../input/dogs-vs-cats/{zip_file}.zip\", \"r\") as z:\n        z.extractall(dataset_dir)\n        print(f\"{zip_file} unzipped\")\n\n# Rearrange the dataset\ndataset_classes = [\"cat\", \"dog\"]\n# Create the required directories\nfor dataset_class in dataset_classes:\n    if not os.path.exists(f\"{dataset_dir}/train/{dataset_class}\"):\n        os.makedirs(f\"{dataset_dir}/train/{dataset_class}\")\n\n# Move the extracted data in the corresponding directories\nfiles = sorted(os.listdir(f\"{dataset_dir}/train\"))\nfor file in files:\n    if os.path.isfile(f\"{dataset_dir}/train/{file}\"):\n        dataset_class = file.split('.')[0]\n        shutil.move(f\"{dataset_dir}/train/{file}\", f\"{dataset_dir}/train/{dataset_class}/{file}\")\n\n# Create the vaidation data out of training data\nval_split = 0.2\nfor dataset_class in dataset_classes:\n    if not os.path.exists(f\"{dataset_dir}/val/{dataset_class}\"):\n        os.makedirs(f\"{dataset_dir}/val/{dataset_class}\")\n\nfor dataset_class in dataset_classes:\n    class_train_dir = f\"{dataset_dir}/train/{dataset_class}\"\n    class_val_dir = f\"{dataset_dir}/val/{dataset_class}\"\n    images = os.listdir(class_train_dir)\n    total_images = len(images)\n    val_images = math.floor(total_images * val_split)\n    slice_factor = math.floor(total_images / val_images)\n    for i in range(0, total_images, slice_factor):\n        shutil.move(f\"{class_train_dir}/{images[i]}\", f\"{class_val_dir}/{images[i]}\")\n\n!echo Train Set\n!ls $dataset_dir/train/cat | wc -l\n!ls $dataset_dir/train/dog | wc -l\n\n!echo Validation Set\n!ls $dataset_dir/val/cat | wc -l\n!ls $dataset_dir/val/dog | wc -l","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Define Dataset and Dataloader Classes"},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport random\nimport cv2\nimport numpy as np\nfrom PIL import Image\n\nimport torch.utils.data\nfrom torchvision import transforms","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class BaseDset(object):\n\n    def __init__(self):\n        self.__base_path = \"\"\n\n        self.__train_set = {}\n        self.__test_set = {}\n        self.__train_keys = []\n        self.__test_keys = []\n\n    def load(self, base_path):\n        self.__base_path = base_path\n        train_dir = os.path.join(self.__base_path, 'train')\n        test_dir = os.path.join(self.__base_path, 'val')\n\n        self.__train_set = {}\n        self.__test_set = {}\n        self.__train_keys = []\n        self.__test_keys = []\n\n        for class_id in os.listdir(train_dir):\n            class_dir = os.path.join(train_dir, class_id)\n            self.__train_set[class_id] = []\n            self.__train_keys.append(class_id)\n            for img_name in os.listdir(class_dir):\n                img_path = os.path.join(class_dir, img_name)\n                self.__train_set[class_id].append(img_path)\n\n        for class_id in os.listdir(test_dir):\n            class_dir = os.path.join(test_dir, class_id)\n            self.__test_set[class_id] = []\n            self.__test_keys.append(class_id)\n            for img_name in os.listdir(class_dir):\n                img_path = os.path.join(class_dir, img_name)\n                self.__test_set[class_id].append(img_path)\n\n        return len(self.__train_keys), len(self.__test_keys)\n\n    def getTriplet(self, split='train'):\n        if split == 'train':\n            dataset = self.__train_set\n            keys = self.__train_keys\n        else:\n            dataset = self.__test_set\n            keys = self.__test_keys\n\n        pos_idx = 0\n        neg_idx = 0\n        pos_anchor_img_idx = 0\n        pos_img_idx = 0\n        neg_img_idx = 0\n\n        pos_idx = random.randint(0, len(keys) - 1)\n        while True:\n            neg_idx = random.randint(0, len(keys) - 1)\n            if pos_idx != neg_idx:\n                break\n\n        pos_anchor_img_idx = random.randint(0, len(dataset[keys[pos_idx]]) - 1)\n        while True:\n            pos_img_idx = random.randint(0, len(dataset[keys[pos_idx]]) - 1)\n            if pos_anchor_img_idx != pos_img_idx:\n                break\n\n        neg_img_idx = random.randint(0, len(dataset[keys[neg_idx]]) - 1)\n\n        pos_anchor_img = dataset[keys[pos_idx]][pos_anchor_img_idx]\n        pos_img = dataset[keys[pos_idx]][pos_img_idx]\n        neg_img = dataset[keys[neg_idx]][neg_img_idx]\n\n        return pos_anchor_img, pos_img, neg_img","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"RESIZE_SIZE = (192, 192)\nNUM_TRAIN_SAMPLES = 10000\nNUM_VAL_SAMPLES = 2500\nBATCH_SIZE = 64\nNUM_WORKERS = 2\n\nmeans = (0.485, 0.456, 0.406)\nstds = (0.229, 0.224, 0.225)\nTRAIN_TRANSFORM = transforms.Compose([transforms.RandomHorizontalFlip(), \n                                     transforms.RandomVerticalFlip(),\n                                     transforms.RandomRotation(90), \n                                     transforms.ToTensor(), \n                                     transforms.Normalize(means, stds)])\nTEST_TRANSFORM = transforms.Compose([\n                    transforms.ToTensor(),\n                    transforms.Normalize(means, stds)\n                    ])\n\nclass BaseLoader(torch.utils.data.Dataset):\n    def __init__(self, triplets, transform=None):\n        self.triplets = triplets\n        self.transform = transform\n\n    def __getitem__(self, index):\n        img1_pth, img2_pth, img3_pth = self.triplets[index]\n        img1 = Image.open(img1_pth)\n        img2 = Image.open(img2_pth)\n        img3 = Image.open(img3_pth)\n\n        try:\n            img1 = img1.resize(RESIZE_SIZE)\n        except Exception as e:\n            img1 = np.zeros(RESIZE_SIZE, dtype=np.uint8)\n\n        try:\n            img2 = img2.resize(RESIZE_SIZE)\n        except Exception as e:\n            img2 = np.zeros(RESIZE_SIZE, dtype=np.uint8)\n\n        try:\n            img3 = img3.resize(RESIZE_SIZE)\n        except Exception as e:\n            img3 = np.zeros(RESIZE_SIZE, dtype=np.uint8)\n\n        if self.transform is not None:\n            img1 = self.transform(img1)\n            img2 = self.transform(img2)\n            img3 = self.transform(img3)\n\n        return img1, img2, img3\n\n    def __len__(self):\n        return len(self.triplets)\n\n\ndef get_loader():\n    train_data_loader = None\n    test_data_loader = None\n\n    train_triplets = []\n    test_triplets = []\n\n    dset_obj = None\n    loader = BaseLoader\n    \n    \n    dset_obj = BaseDset()\n    dset_obj.load(dataset_dir)\n    for i in range(NUM_TRAIN_SAMPLES):\n        pos_anchor_img, pos_img, neg_img = dset_obj.getTriplet()\n        train_triplets.append([pos_anchor_img, pos_img, neg_img])\n    for i in range(NUM_VAL_SAMPLES):\n        pos_anchor_img, pos_img, neg_img = dset_obj.getTriplet(split='test')\n        test_triplets.append([pos_anchor_img, pos_img, neg_img])\n\n    train_data_loader = torch.utils.data.DataLoader(\n        loader(train_triplets, transform=TRAIN_TRANSFORM),\n        batch_size=BATCH_SIZE, shuffle=True, num_workers=NUM_WORKERS, pin_memory=True)\n    test_data_loader = torch.utils.data.DataLoader(\n        loader(test_triplets, transform=TEST_TRANSFORM),\n        batch_size=BATCH_SIZE, shuffle=True, num_workers=NUM_WORKERS, pin_memory=True)\n\n    return train_data_loader, test_data_loader","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Define Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torchvision.models.resnet import resnet18","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class EmbeddingResnet2Blocks(nn.Module):\n    def __init__(self, pretrained):\n        super(EmbeddingResnet2Blocks, self).__init__()\n\n        resnet = resnet18(pretrained=pretrained)\n        self.features = resnet\n#         self.features = nn.Sequential(resnet.conv1, resnet.bn1, resnet.relu, resnet.maxpool, resnet.layer1,\n#                                       resnet.layer2, resnet.avgpool)\n\n    def forward(self, x):\n        features = self.features.forward(x)\n        features = features.view(features.size(0), -1)\n        features = F.normalize(features, p=2, dim=1)\n        return features\n\nclass TripletNet(nn.Module):\n    def __init__(self, embeddingNet):\n        super(TripletNet, self).__init__()\n        self.embeddingNet = embeddingNet\n\n    def forward(self, i1, i2, i3):\n        E1 = self.embeddingNet(i1)\n        E2 = self.embeddingNet(i2)\n        E3 = self.embeddingNet(i3)\n        return E1, E2, E3\n\ndef get_model(checkpoints=None, pretrained=False):\n    embeddingNet = EmbeddingResnet2Blocks(pretrained=pretrained)\n\n    model = TripletNet(embeddingNet)\n    model = nn.DataParallel(model, device_ids=[0])\n    model = model.to(\"cuda\")\n\n    # Load weights if provided\n    if not checkpoints == None:\n        if os.path.isfile(checkpoints):\n            print(\"=> Loading checkpoint '{}'\".format(checkpoints))\n            checkpoint = torch.load(checkpoints)\n            model.load_state_dict(checkpoint['state_dict'])\n            print(\"=> Loaded checkpoint '{}'\".format(checkpoints))\n        else:\n            print(\"=> No checkpoint found at '{}'\".format(checkpoints))\n\n    return model","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Train the Embeddings"},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\n\nfrom torch.autograd import Variable\nimport torch.backends.cudnn as cudnn","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def save_checkpoint(state, file_name):\n    torch.save(state, file_name)\n\ndef train(data, model, criterion, optimizer, epoch, file, device=\"cuda\"):\n    print(\"******** Training ********\")\n    print(\"******** Training ********\", file=file)\n    total_loss = 0\n    model.train()\n    for batch_idx, img_triplet in enumerate(data):\n        anchor_img, pos_img, neg_img = img_triplet\n        anchor_img, pos_img, neg_img = anchor_img.to(device), pos_img.to(device), neg_img.to(device)\n        anchor_img, pos_img, neg_img = Variable(anchor_img), Variable(pos_img), Variable(neg_img)\n        E1, E2, E3 = model(anchor_img, pos_img, neg_img)\n        dist_E1_E2 = F.pairwise_distance(E1, E2, 2)\n        dist_E1_E3 = F.pairwise_distance(E1, E3, 2)\n\n        target = torch.FloatTensor(dist_E1_E2.size()).fill_(-1)\n        target = target.to(device)\n        target = Variable(target)\n        loss = criterion(dist_E1_E2, dist_E1_E3, target)\n        total_loss += loss\n\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        log_step = 10\n        if (batch_idx % log_step == 0) and (batch_idx != 0):\n            print('Train Epoch: {} [{}/{}] \\t Loss: {:.4f}'.format(epoch, batch_idx, len(data), total_loss / log_step))\n            print('Train Epoch: {} [{}/{}] \\t Loss: {:.4f}'.format(epoch, batch_idx, len(data), total_loss / log_step),\n                  file=file)\n            total_loss = 0\n    print(\"****************\")\n    print(\"****************\", file=file)\n\n\ndef test(data, model, criterion, file, device=\"cuda\"):\n    metrics = {}\n    print(\"******** Testing ********\")\n    print(\"******** Testing ********\", file=file)\n    with torch.no_grad():\n        model.eval()\n        accuracies = [0, 0, 0]\n        acc_threshes = [0, 0.2, 0.5]\n        total_loss = 0\n        for batch_idx, img_triplet in enumerate(data):\n            anchor_img, pos_img, neg_img = img_triplet\n            anchor_img, pos_img, neg_img = anchor_img.to(device), pos_img.to(device), neg_img.to(device)\n            anchor_img, pos_img, neg_img = Variable(anchor_img), Variable(pos_img), Variable(neg_img)\n            E1, E2, E3 = model(anchor_img, pos_img, neg_img)\n            dist_E1_E2 = F.pairwise_distance(E1, E2, 2)\n            dist_E1_E3 = F.pairwise_distance(E1, E3, 2)\n\n            target = torch.FloatTensor(dist_E1_E2.size()).fill_(-1)\n            target = target.to(device)\n            target = Variable(target)\n\n            loss = criterion(dist_E1_E2, dist_E1_E3, target)\n            total_loss += loss\n\n            for i in range(len(accuracies)):\n                prediction = (dist_E1_E3 - dist_E1_E2 - 1.0 * acc_threshes[i]).cpu().data\n                prediction = prediction.view(prediction.numel())\n                prediction = (prediction > 0).float()\n                batch_acc = prediction.sum() * 1.0 / prediction.numel()\n                accuracies[i] += batch_acc\n        print('Test Loss: {}'.format(total_loss / len(data)))\n        print('Test Loss: {}'.format(total_loss / len(data)), file=file)\n        metrics['loss'] = total_loss / len(data)\n        for i in range(len(accuracies)):\n            print(\n                'Test Accuracy with diff = {}% of margin: {}'.format(acc_threshes[i] * 100, accuracies[i] / len(data)))\n            print('Test Accuracy with diff = {}% of margin: {}'.format(acc_threshes[i] * 100,\n                                                                       accuracies[i] / len(data)), file=file)\n            metrics[f\"{acc_threshes[i] * 100}\"] = accuracies[i] / len(data)\n    print(\"****************\")\n    print(\"****************\", file=file)\n\n    return metrics","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"torch.manual_seed(1)\ntorch.cuda.manual_seed(1)\ncudnn.benchmark = True\n\nexp_dir = f\"{work_dir}/embedding\"\nif not os.path.exists(exp_dir):\n    os.makedirs(exp_dir)\n\n# Open the file to log the training\nfile = open(f\"{exp_dir}/info.txt\", 'w')\n\nmodel = get_model(pretrained=True)\nparams = []\nfor key, value in dict(model.named_parameters()).items():\n    if value.requires_grad:\n        params += [{'params': [value]}]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"EPOCHS = 50\nCKP_FREQ = 1\nLEARNING_RATE = 0.0001\n\ncriterion = torch.nn.MarginRankingLoss(margin=1.0)\noptimizer = optim.Adam(params, lr=LEARNING_RATE)\nbest_model = {}\nbest_metrics = None\n\n# Train Test Loop\nfor epoch in range(1, EPOCHS + 1):\n    # Init data loaders\n    train_data_loader, test_data_loader = get_loader()\n    # Test train\n    if epoch == 1:\n        metrics = test(test_data_loader, model, criterion, file)\n    train(train_data_loader, model, criterion, optimizer, epoch, file)\n    metrics = test(test_data_loader, model, criterion, file)\n    # Save model\n    model_to_save = {\n        \"epoch\": epoch + 1,\n        \"metrics\": metrics,\n        'state_dict': model.state_dict(),\n    }\n    if best_metrics is not None:\n        best_score = 0\n        for i in metrics.keys():\n            if i == 'loss':\n                if float(metrics[i]) < float(best_metrics[i]):\n                    best_score += 1\n            else:\n                if float(metrics[i]) > float(best_metrics[i]):\n                    best_score += 1\n        if best_score >= 3:\n            print(f\"New Best model at epoch # {epoch}\")\n            print(f\"New Best model at epoch # {epoch}\", file=file)\n            best_model = model_to_save\n            best_metrics = metrics\n    else:\n        best_metrics = metrics\n    if epoch % CKP_FREQ == 0:\n        file_name = os.path.join(exp_dir, \"checkpoint_\" + str(epoch) + \".pth\")\n        save_checkpoint(model_to_save, file_name)\n# Save the best model\nfile_name = os.path.join(exp_dir, \"checkpoint_best\" + \".pth\")\nsave_checkpoint(best_model, file_name)\nfile.close()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training of Classifier"},{"metadata":{},"cell_type":"markdown","source":"## Initialize the Paths"},{"metadata":{"trusted":true},"cell_type":"code","source":"embedding_weights_path = os.path.join(exp_dir, \"checkpoint_best\" + \".pth\")\ntrain_dataset_path = f\"{dataset_dir}/train\"\nval_dataset_path = f\"{dataset_dir}/val\"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Imports"},{"metadata":{"trusted":true},"cell_type":"code","source":"from torch.utils.data import DataLoader\nfrom torchvision import datasets, transforms\nimport cv2\nfrom PIL import Image","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Dataloader"},{"metadata":{"trusted":true},"cell_type":"code","source":"TRANSFORM = transforms.Compose([\n                    transforms.ToTensor(),\n                    transforms.Normalize(means, stds)\n                    ])\nAUGMENTATION = transforms.Compose([transforms.RandomHorizontalFlip(), \n                                   transforms.RandomVerticalFlip(),\n                                   transforms.RandomRotation(90)])\n\ndef image_loader_train(path):\n    image = Image.open(path)\n    image = image.resize(RESIZE_SIZE)\n    image = AUGMENTATION(image)\n    image = TRANSFORM(image)\n    \n    return image\n\ndef image_loader_test(path):\n    image = Image.open(path)\n    image = image.resize(RESIZE_SIZE)\n    image = TRANSFORM(image)\n    \n    return image\n\n\ndef get_dataset_loader(dataset_root_path, batch_size=BATCH_SIZE, shuffle=True, num_workers=2, train=True):\n    if train:\n        image_datset = datasets.ImageFolder(root=dataset_root_path, loader=image_loader_train)\n    else:\n        image_datset = datasets.ImageFolder(root=dataset_root_path, loader=image_loader_test)\n    data_loader = DataLoader(dataset=image_datset, batch_size=batch_size, shuffle=shuffle, num_workers=num_workers)\n\n    print(f\"Dataset Size: {len(image_datset)}\")\n    print(f\"Dataset Classes: {image_datset.classes}\")\n\n    return image_datset, data_loader","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Define Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"class Classifier(nn.Module):\n    def __init__(self, embeddingNet, num_classes=2):\n        super(Classifier, self).__init__()\n        self.embeddingNet = embeddingNet\n        self.fc = nn.Linear(1000, num_classes)\n        self.dropout = nn.Dropout(0.4)\n        self.softmax = nn.Softmax(dim=1)\n\n    def forward(self, x):\n        x = self.embeddingNet(x)\n        x = self.dropout(x)\n        x = self.fc(x)\n        x = self.softmax(x)\n        return x\n\ndef get_classfier_model(embedding_weights_path):\n    embeddingNet = EmbeddingResnet2Blocks(pretrained=True)\n\n    model = Classifier(embeddingNet)\n    model = nn.DataParallel(model, device_ids=[0])\n    model = model.to(\"cuda\")\n\n    # Load the embedding weights\n    if embedding_weights_path:\n        if os.path.isfile(embedding_weights_path):\n            checkpoint = torch.load(embedding_weights_path)\n            model.load_state_dict(checkpoint['state_dict'], strict=False)\n\n    # Freeze the embeddingNet\n    for key, value in dict(model.module.embeddingNet.named_parameters()).items():\n        if value.requires_grad:\n            value.requires_grad = False\n    model.module.embeddingNet.train(False)\n\n    return model","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Train the Classifier"},{"metadata":{"trusted":true},"cell_type":"code","source":"def train(data, model, criterion, optimizer, epoch, dataset_size, device=\"cuda\"):\n    print(\"******** Training ********\")\n    print(\"******** Training ********\", file=file)\n    total_loss = 0\n    total_correct_predictions = 0\n    model.train()\n    for batch_idx, d in enumerate(data):\n        inputs, labels = d\n        inputs = inputs.to(device)\n        labels = labels.to(device)\n        outputs = model(inputs)\n        loss = criterion(outputs, labels)\n        total_loss += loss\n        _, preds = torch.max(outputs, 1)\n        total_correct_predictions += torch.sum(preds == labels.data)\n\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n    \n        log_step = 10\n        if (batch_idx % log_step == 0) and (batch_idx != 0):\n            print('Train Epoch: {} [{}/{}] \\t Loss: {:.4f}'.format(epoch, batch_idx, len(data), total_loss / log_step))\n            print('Train Epoch: {} [{}/{}] \\t Loss: {:.4f}'.format(epoch, batch_idx, len(data), total_loss / log_step),\n                  file=file)\n            total_loss = 0\n    epoch_accuracy = float(total_correct_predictions) / dataset_size\n\n    print(f\"Accuracy: {epoch_accuracy}\")\n    print(f\"Accuracy: {epoch_accuracy}\", file=file)\n    print(\"****************\")\n    print(\"****************\", file=file)\n\n\ndef test(data, model, criterion, dataset_size, device=\"cuda\"):\n    metrics = {}\n    print(\"******** Testing ********\")\n    print(\"******** Testing ********\", file=file)\n    with torch.no_grad():\n        model.eval()\n        total_loss = 0\n        total_correct_predictions = 0\n        for batch_idx, d in enumerate(data):\n            inputs, labels = d\n            inputs = inputs.to(device)\n            labels = labels.to(device)\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n            total_loss += loss\n            _, preds = torch.max(outputs, 1)\n            total_correct_predictions += torch.sum(preds == labels.data)\n\n        epoch_loss = float(total_loss) / len(data)\n        epoch_accuracy = float(total_correct_predictions) / dataset_size\n\n        metrics['loss'] = epoch_loss\n        metrics['accuracy'] = epoch_accuracy\n\n    print(f\"Loss: {epoch_loss}, Accuracy: {epoch_accuracy}\")\n    print(f\"Loss: {epoch_loss}, Accuracy: {epoch_accuracy}\", file=file)\n    print(\"****************\")\n    print(\"****************\", file=file)\n\n    return metrics","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"EPOCHS = 20\nCHK_FREQ = 1\n\ntorch.manual_seed(1)\ntorch.cuda.manual_seed(1)\ncudnn.benchmark = True\n\nexp_dir = f\"{work_dir}/classifier\"\nif not os.path.exists(exp_dir):\n    os.makedirs(exp_dir)\n\n# Open the file to log the training\nfile = open(f\"{exp_dir}/info.txt\", 'w')\n\nmodel = get_classfier_model(embedding_weights_path)\nparams = []\nfor key, value in dict(model.named_parameters()).items():\n    if value.requires_grad:\n        params += [{'params': [value]}]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"criterion = torch.nn.CrossEntropyLoss()\noptimizer = optim.SGD(params, lr=0.001, momentum=0.9)\nbest_model = {}\nbest_metrics = None\n\n# Train Test Loop\nfor epoch in range(1, EPOCHS + 1):\n    # Init data loaders\n    train_dataset, train_data_loader = get_dataset_loader(dataset_root_path=train_dataset_path,\n                                                          batch_size=128)\n    test_dataset, test_data_loader = get_dataset_loader(dataset_root_path=val_dataset_path,\n                                                        batch_size=128, train=False)\n    # Test train\n    if epoch == 1:\n        metrics = test(test_data_loader, model, criterion, len(test_dataset))\n        if best_metrics is None:\n            best_metrics = metrics\n    train(train_data_loader, model, criterion, optimizer, epoch, len(train_dataset))\n    metrics = test(test_data_loader, model, criterion, len(test_dataset))\n    # Save model\n    model_to_save = {\n        \"epoch\": epoch + 1,\n        \"metrics\": metrics,\n        'state_dict': model.state_dict(),\n    }\n    if best_metrics is not None:\n        best_score = 0\n        for i in metrics.keys():\n            if i == 'loss':\n                if float(metrics[i]) < float(best_metrics[i]):\n                    best_score += 1\n            else:\n                if float(metrics[i]) > float(best_metrics[i]):\n                    best_score += 1\n        if best_score >= 2:\n            print(f\"New Best model at epoch # {epoch}\")\n            print(f\"New Best model at epoch # {epoch}\", file=file)\n            best_model = model_to_save\n            best_metrics = metrics\n    else:\n        best_metrics = metrics\n    if epoch % CHK_FREQ == 0:\n        file_name = os.path.join(exp_dir, \"checkpoint_\" + str(epoch) + \".pth\")\n        save_checkpoint(model_to_save, file_name)\n# Save the best model\nfile_name = os.path.join(exp_dir, \"checkpoint_best\" + \".pth\")\nsave_checkpoint(best_model, file_name)\nfile.close()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"# Inference (Preparation of CSV File)"},{"metadata":{},"cell_type":"markdown","source":"> ## Load the Classifier Inference Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"classifier_weights_path = os.path.join(exp_dir, \"checkpoint_best\" + \".pth\")\n\ndef get_classifier_infer_model(pretrained=True):\n    embeddingNet = EmbeddingResnet2Blocks(pretrained=True)\n    \n    model = Classifier(embeddingNet)\n    model = nn.DataParallel(model, device_ids=[0])\n    model = model.to(\"cuda\")\n\n    # Load the trained classifier weights\n    if classifier_weights_path:\n        if os.path.isfile(classifier_weights_path):\n            checkpoint = torch.load(classifier_weights_path)\n            model.load_state_dict(checkpoint['state_dict'], strict=True)\n\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"infer_model = get_classifier_infer_model()\ninfer_model.eval()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Perform Inference on the Test Set"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_data_dir_path = f\"/kaggle/working/data/test1\"\nMODEL_CLASSES = ['cat', 'dog']\nresults = {}\n\nfor i in range(1, len(os.listdir(test_data_dir_path)) + 1):\n    image_path = f\"{test_data_dir_path}/{i}.jpg\"\n    # Preprocess the image\n    image = image_loader(image_path)\n    image = image.to(\"cuda\")\n    image = torch.unsqueeze(image, 0)\n    # Perform inference\n    scores = infer_model(image)\n    # Parse the inference results\n    max_index = torch.argmax(scores)\n    predicted_class = MODEL_CLASSES[max_index]\n    results[i] = predicted_class","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Save the Results in the CSV File"},{"metadata":{"trusted":true},"cell_type":"code","source":"import csv\n\ncsv_contents = {\"dog\": 0, \"cat\": 1}\ncsv_file_path = \"/kaggle/working/Warriors.csv\"\nwith open(csv_file_path, 'w') as f:\n    for key in results.keys():\n        f.write(\"%s,%s\\n\"%(f\"{key}.jpg\", csv_contents[results[key]]))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* ## Delete the Datasets"},{"metadata":{"trusted":true},"cell_type":"code","source":"!rm -rf $dataset_dir","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}