{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":20270,"databundleVersionId":1222630,"sourceType":"competition"},{"sourceId":7515484,"sourceType":"datasetVersion","datasetId":4377612},{"sourceId":1253590,"sourceType":"datasetVersion","datasetId":720563}],"dockerImageVersionId":30648,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"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\ninput_directory = '/kaggle/input'\n\nfor dirpath, dirnames, filenames in os.walk(input_directory):\n    for dirname in dirnames:\n        print(dirname)\n# You can write up to 20GB 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","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-01-31T11:01:04.148412Z","iopub.execute_input":"2024-01-31T11:01:04.149129Z","iopub.status.idle":"2024-01-31T11:02:29.794805Z","shell.execute_reply.started":"2024-01-31T11:01:04.149099Z","shell.execute_reply":"2024-01-31T11:02:29.793889Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport matplotlib.pyplot as plt\nimport os\nfrom collections import OrderedDict\nimport torch\nfrom torch import nn\nfrom torch import optim\nimport torch.nn.functional as F\nfrom torchvision import datasets, transforms, models\n\n#import custom_models\n\n#python packages\nfrom PIL import Image\nfrom tqdm import tqdm\n#from tqdm.notebook import tqdm\nimport gc\nimport datetime\nimport copy\nimport matplotlib.pyplot as plt\nimport time\nfrom skimage import io\n#torch\nimport random\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom torch.utils.data import Dataset,DataLoader, Subset, random_split\nfrom sklearn.model_selection import StratifiedKFold\n#torchvision\nimport torchvision\nfrom torchvision import datasets, models, transforms\nprint(\"PyTorch Version: \",torch.__version__)\nprint(\"Torchvision Version: \",torchvision.__version__)\nimport cv2\nimport warnings\nimport seaborn as sns\nimport ssl\nssl._create_default_https_context = ssl._create_unverified_context","metadata":{"execution":{"iopub.status.busy":"2024-01-31T11:02:56.529093Z","iopub.execute_input":"2024-01-31T11:02:56.529671Z","iopub.status.idle":"2024-01-31T11:03:04.885642Z","shell.execute_reply.started":"2024-01-31T11:02:56.529635Z","shell.execute_reply":"2024-01-31T11:03:04.884554Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torchvision.models as models\n\nimport wandb\nwandb.init(project='Skin Melanoma Detection Project', save_code=True,)","metadata":{"execution":{"iopub.status.busy":"2024-01-31T11:03:16.449554Z","iopub.execute_input":"2024-01-31T11:03:16.450527Z","iopub.status.idle":"2024-01-31T11:03:56.78222Z","shell.execute_reply.started":"2024-01-31T11:03:16.450488Z","shell.execute_reply":"2024-01-31T11:03:56.781131Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class AdvancedHairAugmentation:\n    \"\"\"\n    Impose an image of a hair to the target image\n\n    Args:\n        hairs (int): maximum number of hairs to impose\n        hairs_folder (str): path to the folder with hairs images\n    \"\"\"\n\n    def __init__(self, hairs: int = 5, hairs_folder: str = \"\"):\n        self.hairs = hairs\n        self.hairs_folder = hairs_folder\n\n    def __call__(self, img_path):\n        \"\"\"\n        Args:\n            img (PIL Image): Image to draw hairs on.\n\n        Returns:\n            PIL Image: Image with drawn hairs.\n        \"\"\"\n        img = cv2.imread(img_path)\n        n_hairs = random.randint(0, self.hairs)\n\n        if not n_hairs:\n            return img\n\n        height, width, _ = img.shape  # target image width and height\n        hair_images = [im for im in os.listdir(self.hairs_folder) if 'png' in im]\n\n        for _ in range(n_hairs):\n            hair = cv2.imread(os.path.join(self.hairs_folder, random.choice(hair_images)))\n            hair = cv2.flip(hair, random.choice([-1, 0, 1]))\n            hair = cv2.rotate(hair, random.choice([0, 1, 2]))\n\n            h_height, h_width, _ = hair.shape  # hair image width and height\n            roi_ho = random.randint(0, img.shape[0] - hair.shape[0])\n            roi_wo = random.randint(0, img.shape[1] - hair.shape[1])\n            roi = img[roi_ho:roi_ho + h_height, roi_wo:roi_wo + h_width]\n\n            # Creating a mask and inverse mask\n            img2gray = cv2.cvtColor(hair, cv2.COLOR_BGR2GRAY)\n            ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY)\n            mask_inv = cv2.bitwise_not(mask)\n\n            # Now black-out the area of hair in ROI\n            img_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)\n\n            # Take only region of hair from hair image.\n            hair_fg = cv2.bitwise_and(hair, hair, mask=mask)\n\n            # Put hair in ROI and modify the target image\n            dst = cv2.add(img_bg, hair_fg)\n\n            img[roi_ho:roi_ho + h_height, roi_wo:roi_wo + h_width] = dst\n\n        return img\n\n    def __repr__(self):\n        return f'{self.__class__.__name__}(hairs={self.hairs}, hairs_folder=\"{self.hairs_folder}\")'","metadata":{"execution":{"iopub.status.busy":"2024-01-31T11:04:00.522765Z","iopub.execute_input":"2024-01-31T11:04:00.52318Z","iopub.status.idle":"2024-01-31T11:04:01.069205Z","shell.execute_reply.started":"2024-01-31T11:04:00.523147Z","shell.execute_reply":"2024-01-31T11:04:01.067815Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import Dataset, DataLoader, ConcatDataset\nfrom PIL import Image\nimport torchvision\nclass MultimodalDataset(Dataset):\n    \"\"\"\n    Custom dataset definition\n    \"\"\"\n    def __init__(self, csv_path, img_path, mode='train', transform=None):\n        \"\"\"\n        \"\"\"\n        self.df = pd.read_csv(csv_path)\n        self.img_path = img_path\n        self.mode= mode\n        self.transform = transform\n\n\n    def __getitem__(self, index):\n        \"\"\"\n        \"\"\"\n        img_name = self.df.iloc[index][\"image_name\"] + '.jpg'\n        img_path = os.path.join(self.img_path, img_name)\n        image = Image.open(img_path)\n\n        dtype = torch.cuda.FloatTensor if torch.cuda.is_available() else torch.FloatTensor # ???\n\n        if self.mode == 'train':\n            if self.df.iloc[index][\"augmented\"]==1:\n                image = AdvancedHairAugmentation(hairs_folder=\"/kaggle/input/melanoma-hairs\")(img_path)\n                image = Image.fromarray(image, 'RGB')\n            else:\n                image = image.convert(\"RGB\")\n\n            image = np.asarray(image)\n            if self.transform is not None:\n                image = self.transform(image)\n            labels = self.df.iloc[index][\"target\"]\n            return image, labels\n\n        elif self.mode == 'val':\n            image = np.asarray(image)\n            if self.transform is not None:\n                image = self.transform(image)\n            labels = self.df.iloc[index][\"target\"]\n            return image, labels\n\n        else: #when self.mode=='test'\n            image = np.asarray(image)\n            if self.transform is not None:\n                image = self.transform(image)\n            return image, self.df.iloc[index][\"image_name\"]\n\n    def __len__(self):\n        return len(self.df)\n    def get_labels(self):\n            # Assuming you have a method to get the labels from your dataset\n            return [label for label in self.img_path]","metadata":{"execution":{"iopub.status.busy":"2024-01-31T11:04:09.405216Z","iopub.execute_input":"2024-01-31T11:04:09.406274Z","iopub.status.idle":"2024-01-31T11:04:09.924006Z","shell.execute_reply.started":"2024-01-31T11:04:09.406229Z","shell.execute_reply":"2024-01-31T11:04:09.922937Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nfrom torchvision import models\n\nclass CustomVGG19(nn.Module):\n    def __init__(self, num_classes, input_size):\n        super(CustomVGG19, self).__init__()\n        vgg19 = models.vgg19(pretrained=True)\n        \n        # Freeze pre-trained layers\n        for param in vgg19.parameters():\n            param.requires_grad = False\n        \n        # Modify the classifier for the specified number of classes\n        vgg19.classifier[6] = nn.Linear(4096, num_classes)\n        \n        # Adjust the input size for the first layer\n        vgg19.features[0] = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1)\n        \n        self.model = vgg19\n\n    def forward(self, x):\n        return self.model(x)\n\n# Example usage:\n# Specify the number of classes for your task\nnum_classes = 2 # Number of classes in your dataset\ninput_size = 224  # Input size of your images\n\n# Instantiate the CustomVGG19 model\nmodel = CustomVGG19(num_classes=num_classes, input_size=input_size)\n\n# Print the modified VGG19 model\nprint(model)\n\n\n","metadata":{"execution":{"iopub.status.busy":"2024-01-31T11:04:19.205766Z","iopub.execute_input":"2024-01-31T11:04:19.206159Z","iopub.status.idle":"2024-01-31T11:04:25.888505Z","shell.execute_reply.started":"2024-01-31T11:04:19.206128Z","shell.execute_reply":"2024-01-31T11:04:25.887334Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_classes = 2\nmodel = CustomVGG19(num_classes=num_classes, input_size=input_size)\n# Move the model to GPU if available\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel.to(device)\n\n# Create a sample input tensor and move it to the same device as the model\nsample_input = torch.randn((1, 3, input_size, input_size)).to(device)\n\n# Forward pass with the sample input\noutput = model(sample_input)\nprint(output)","metadata":{"execution":{"iopub.status.busy":"2024-01-31T10:01:49.981424Z","iopub.execute_input":"2024-01-31T10:01:49.981811Z","iopub.status.idle":"2024-01-31T10:01:53.208979Z","shell.execute_reply.started":"2024-01-31T10:01:49.981781Z","shell.execute_reply":"2024-01-31T10:01:53.207902Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"'''import torch\nimport torch.nn as nn\nfrom torchvision import models\n\nclass VGG19Custom(nn.Module):\n    def __init__(self, input_size=224, num_classes=2):\n        super(VGG19Custom, self).__init__()\n        vgg19 = models.vgg19(pretrained=True)\n        self.features = vgg19.features\n        self.avgpool = vgg19.avgpool\n\n        # Classifier with dynamic input size\n        self.classifier = nn.Sequential(\n            nn.Linear(512 * (input_size // 32) * (input_size // 32), 4096),\n            nn.ReLU(True),\n            nn.Dropout(),\n            nn.Linear(4096, 4096),\n            nn.ReLU(True),\n            nn.Dropout(),\n            nn.Linear(4096, num_classes),\n            nn.LogSoftmax(dim=1)\n        )\n        self.input_size = input_size\n\n    def forward(self, x):\n        x = self.features(x)\n        x = self.avgpool(x)\n        x = x.view(x.size(0), -1)\n\n        # Print the shapes for debugging\n        print(f\"Shape after view: {x.shape}\")\n        print(f\"Classifier input size: {self.classifier[0].in_features}\")\n\n        # Move x to the same device as the classifier's parameters\n        x = x.to(self.classifier[0].weight.device)\n\n        x = self.classifier(x)\n        return x\n\n# Instantiate the model\ninput_size = 224  # Adjust this if needed\nnum_classes = 2\nmodel = VGG19Custom(input_size=input_size, num_classes=num_classes)\n\n# Move the model to GPU if available\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel.to(device)\n\n# Create a sample input tensor and move it to the same device as the model\nsample_input = torch.randn((1, 3, input_size, input_size)).to(device)\n\n# Forward pass with the sample input\noutput = model(sample_input)\nprint(output)\n\n","metadata":{"execution":{"iopub.status.busy":"2024-01-31T09:55:41.217421Z","iopub.execute_input":"2024-01-31T09:55:41.218248Z","iopub.status.idle":"2024-01-31T09:55:44.332002Z","shell.execute_reply.started":"2024-01-31T09:55:41.218207Z","shell.execute_reply":"2024-01-31T09:55:44.331046Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"'''# Assuming model is an instance of VGG19Custom\nmodel = VGG19Custom(input_size=224, num_classes=2)\n\n# Creating a random input tensor for testing\nbatch_size = 16\nchannels = 3  # Assuming 3 input channels for RGB images\nheight, width = 224, 224  # Assuming input size of 224x224\ninput_tensor = torch.randn((batch_size, channels, height, width))\n\n# Forward pass\noutput = model(input_tensor)","metadata":{"execution":{"iopub.status.busy":"2024-01-31T09:29:34.213911Z","iopub.execute_input":"2024-01-31T09:29:34.214431Z","iopub.status.idle":"2024-01-31T09:29:40.079721Z","shell.execute_reply.started":"2024-01-31T09:29:34.214397Z","shell.execute_reply":"2024-01-31T09:29:40.078654Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_path_dict = {'train': \"../input/siim-isic-melanoma-classification/jpeg/train\",\n                  'val': \"../input/siim-isic-melanoma-classification/jpeg/train\" ,\n                  'test': \"../input/siim-isic-melanoma-classification/jpeg/test\"}","metadata":{"execution":{"iopub.status.busy":"2024-01-31T11:04:52.170722Z","iopub.execute_input":"2024-01-31T11:04:52.171078Z","iopub.status.idle":"2024-01-31T11:04:52.705818Z","shell.execute_reply.started":"2024-01-31T11:04:52.171052Z","shell.execute_reply":"2024-01-31T11:04:52.704642Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#input_size = 224\nbatch_size = 64\nnum_folds = 5","metadata":{"execution":{"iopub.status.busy":"2024-01-31T11:04:56.68373Z","iopub.execute_input":"2024-01-31T11:04:56.684164Z","iopub.status.idle":"2024-01-31T11:04:57.206164Z","shell.execute_reply.started":"2024-01-31T11:04:56.684129Z","shell.execute_reply":"2024-01-31T11:04:57.205063Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_dataloaders(input_size, batch_size, augment=False, shuffle=True):\n    # Set the input size, batch size, and other parameters\n    num_folds = 5\n\n    # Create a StratifiedKFold splitter for the 'train' dataset\n    skf = StratifiedKFold(n_splits=num_folds, shuffle=True, random_state=42)\n\n    data_transforms = {\n        'train': transforms.Compose([\n            transforms.ToPILImage(),\n            transforms.Resize(input_size),\n            transforms.CenterCrop(input_size),\n            # Add extra transformations for data augmentation\n            transforms.RandomApply([\n                transforms.RandomChoice([\n                    transforms.RandomAffine(degrees=20),\n                    transforms.RandomAffine(degrees=0, scale=(0.1, 0.15)),\n                    transforms.RandomAffine(degrees=0, translate=(0.2, 0.2)),\n                    # transforms.RandomAffine(degrees=0, shear=0.15),\n                    transforms.RandomHorizontalFlip(p=1.0)\n                ] if augment else [transforms.RandomAffine(degrees=0)])  # else do nothing\n            ], p=0.5),\n            transforms.ToTensor(),\n            transforms.Normalize([0.5], [0.225])\n        ]),\n        'val': transforms.Compose([\n            transforms.ToPILImage(),\n            transforms.Resize(input_size),\n            transforms.CenterCrop(input_size),\n            transforms.ToTensor(),\n            transforms.Normalize([0.5], [0.225])\n        ]),\n        'test': transforms.Compose([\n            transforms.ToPILImage(),\n            transforms.Resize(input_size),\n            transforms.CenterCrop(input_size),\n            transforms.ToTensor(),\n            transforms.Normalize([0.5], [0.225])\n        ])\n    }\n\n    data_subsets = {x: MultimodalDataset(\n                        csv_path=\"/kaggle/input/melanomacsv/\"+x+\".csv\",\n                        img_path=image_path_dict[x],\n                        mode=x,\n                        transform=data_transforms[x]\n                    ) for x in data_transforms.keys()}\n\n    dataloaders_dict = {}\n   #for fold, (train_index, val_index) in enumerate(skf.split(data_subsets['train'].get_labels(), data_subsets['train'].get_labels())):\n    for fold, (train_index, val_index) in enumerate(skf.split(data_subsets['train'].get_labels(), data_subsets['train'].get_labels())):\n        train_subset = Subset(data_subsets['train'], train_index)\n        val_subset = Subset(data_subsets['train'], val_index)\n\n        train_loader = DataLoader(train_subset, batch_size=batch_size, shuffle=True, num_workers=4)\n        val_loader = DataLoader(val_subset, batch_size=batch_size, shuffle=False, num_workers=4)\n        dataloaders_dict[f'fold_{fold + 1}'] = {'train': train_loader, 'val': val_loader}\n        test_loader = DataLoader(data_subsets['test'], batch_size=batch_size, shuffle=False, num_workers=4)\n        dataloaders_dict['test'] = test_loader\n    return dataloaders_dict\n\n# Set the input size, batch size, and other parameters\ninput_size = 224\nbatch_size = 64\naugment = True  # Set to True if you want data augmentation during training\n\n# Get dataloaders with stratified K-fold cross-validation\ndataloaders_dict = get_dataloaders(input_size, batch_size, augment=augment, shuffle=True)","metadata":{"execution":{"iopub.status.busy":"2024-01-31T11:05:01.064808Z","iopub.execute_input":"2024-01-31T11:05:01.065181Z","iopub.status.idle":"2024-01-31T11:05:01.631615Z","shell.execute_reply.started":"2024-01-31T11:05:01.065154Z","shell.execute_reply":"2024-01-31T11:05:01.630507Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(dataloaders_dict)","metadata":{"execution":{"iopub.status.busy":"2024-01-31T11:08:09.906232Z","iopub.execute_input":"2024-01-31T11:08:09.907137Z","iopub.status.idle":"2024-01-31T11:08:10.455339Z","shell.execute_reply.started":"2024-01-31T11:08:09.907098Z","shell.execute_reply":"2024-01-31T11:08:10.454293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n# Set random seed for reproducibility\ntorch.manual_seed(42)\n\n# Number of splits for Stratified K-Fold\nnum_splits = 5\n\n# Create VGG19 model instance\nmodel = CustomVGG19(num_classes=num_classes, input_size=input_size).to(device)\n\n# Print the modified VGG19 model\nprint(model)\n","metadata":{"execution":{"iopub.status.busy":"2024-01-31T11:09:24.275077Z","iopub.execute_input":"2024-01-31T11:09:24.27593Z","iopub.status.idle":"2024-01-31T11:09:27.215229Z","shell.execute_reply.started":"2024-01-31T11:09:24.275893Z","shell.execute_reply":"2024-01-31T11:09:27.214117Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class EarlyStopping:\n    def __init__(self, patience=7, verbose=False, delta=0, path='checkpoint.pth', trace_func=print):\n        self.patience = patience\n        self.verbose = verbose\n        self.counter = 0\n        self.best_score = None\n        self.early_stop = False\n        self.val_loss_min = np.Inf\n        self.delta = delta\n        self.path = path\n        self.trace_func = trace_func\n\n    def __call__(self, val_loss, model):\n        score = -val_loss\n\n        if self.best_score is None:\n            self.best_score = score\n            self.save_checkpoint(val_loss, model)\n        elif score < self.best_score + self.delta:\n            self.counter += 1\n            self.trace_func(f'EarlyStopping counter: {self.counter} out of {self.patience}')\n            if self.counter >= self.patience:\n                self.early_stop = True\n        else:\n            self.best_score = score\n            self.save_checkpoint(val_loss, model)\n            self.counter = 0\n\n    def save_checkpoint(self, val_loss, model):\n        if self.verbose:\n            self.trace_func(f'Validation loss decreased ({self.val_loss_min:.6f} --> {val_loss:.6f}).  Saving model ...')\n        torch.save(model.state_dict(), self.path)\n        self.val_loss_min = val_loss\n","metadata":{"execution":{"iopub.status.busy":"2024-01-31T11:09:32.76849Z","iopub.execute_input":"2024-01-31T11:09:32.7689Z","iopub.status.idle":"2024-01-31T11:09:33.267685Z","shell.execute_reply.started":"2024-01-31T11:09:32.768866Z","shell.execute_reply":"2024-01-31T11:09:33.266592Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import accuracy_score\n# Log the configuration parameters\nconfig = {\n    \"learning_rate\": 0.001,\n    \"batch_size\": 64,\n    \"architecture\": \"VGG19\",\n    \"num_epochs\": 10,\n}\nwandb.config.update(config)\n\n# Define hyperparameters\nlearning_rate = 0.001\nbatch_size = 64\nnum_epochs = 10\npatience = 3\nnum_folds = 5\ninput_size = 224\naugment = True\n\n# Define loss function\ncriterion = nn.CrossEntropyLoss()\n\n# Define optimizer (using Adam)\noptimizer = optim.Adam(model.parameters(), lr=learning_rate)\n\n# Get dataloaders with stratified K-fold cross-validation\ndataloaders_dict = get_dataloaders(input_size, batch_size, augment=augment, shuffle=True)\n# Initialize WandB\nwandb.init(project='Skin Melanoma Detection Project', name=\"training_run\")\nwandb.watch(model)\n\n# Training loop\ndef train(model, dataloader, criterion, optimizer, device):\n    model.train()\n    total_loss = 0.0\n    all_preds = []\n    all_labels = []\n\n    for inputs, labels in dataloader:\n        inputs, labels = inputs.to(device), labels.to(device)\n\n        optimizer.zero_grad()\n        outputs = model(inputs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n        total_loss += loss.item()\n\n        _, preds = torch.max(outputs, 1)\n        all_preds.extend(preds.cpu().numpy())\n        all_labels.extend(labels.cpu().numpy())\n\n    accuracy = accuracy_score(all_labels, all_preds)\n    wandb.log({\"Train Loss\": total_loss / len(dataloader), \"Train Accuracy\": accuracy})\n\n    return total_loss / len(dataloader), accuracy\n\n# Validation loop\ndef validate(model, dataloader, criterion, device):\n    model.eval()\n    total_loss = 0.0\n    all_preds = []\n    all_labels = []\n\n    with torch.no_grad():\n        for inputs_tuple, labels_tuple in dataloader:\n            # Unpack the tuples\n            inputs, labels = inputs_tuple[0].to(device), labels_tuple[0].to(device)\n\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n\n            total_loss += loss.item()\n\n            _, preds = torch.max(outputs, 1)\n            all_preds.extend(preds.cpu().numpy())\n            all_labels.extend(labels.cpu().numpy())\n\n    accuracy = accuracy_score(all_labels, all_preds)\n    wandb.log({\"Validation Loss\": total_loss / len(dataloader), \"Validation Accuracy\": accuracy})\n\n    return total_loss / len(dataloader), accuracy\n\n# Training pipeline\ndef training_pipeline(model, dataloaders_dict, criterion, optimizer, device, num_epochs, patience, checkpoint_path='checkpoint.pth'):\n    early_stopping = EarlyStopping(patience=patience, verbose=True)\n\n    best_val_loss = float('inf')\n\n    for fold in range(1, num_folds + 1):  # Iterate over available folds\n        print(f'Fold {fold}/{num_folds}')\n\n        # Training phase\n        train_loss, train_accuracy = train(model, dataloaders_dict[f'fold_{fold}']['train'], criterion, optimizer, device)\n        print(f'Training Loss: {train_loss:.4f}, Training Accuracy: {train_accuracy:.4f}')\n\n        # Validation phase\n        val_loss, val_accuracy = validate(model, dataloaders_dict[f'fold_{fold}']['val'], criterion, device)\n        print(f'Validation Loss: {val_loss:.4f}, Validation Accuracy: {val_accuracy:.4f}')\n\n        # Checkpoint if the validation loss improves\n        if val_loss < best_val_loss:\n            best_val_loss = val_loss\n            torch.save(model.state_dict(), checkpoint_path)\n            wandb.run.summary[\"best_val_loss\"] = best_val_loss\n\n        # Check for early stopping\n        early_stopping(val_loss, model)\n\n        if early_stopping.early_stop:\n            print(\"Early stopping.\")\n            break\n\n    # Load the best model weights\n    model.load_state_dict(torch.load(checkpoint_path))\n    os.remove(checkpoint_path)  # Remove the checkpoint file\n\n    # Test phase\n    test_loss, test_accuracy = validate(model, dataloaders_dict['test'], criterion, device)\n    print(f'Test Loss: {test_loss:.4f}, Test Accuracy: {test_accuracy:.4f}')\n\n    wandb.finish()\n\n# Call the training pipeline\ntraining_pipeline(model, dataloaders_dict, criterion, optimizer, device, num_epochs, patience)","metadata":{"execution":{"iopub.status.busy":"2024-01-31T11:09:37.160896Z","iopub.execute_input":"2024-01-31T11:09:37.161924Z","iopub.status.idle":"2024-01-31T11:10:35.361363Z","shell.execute_reply.started":"2024-01-31T11:09:37.161871Z","shell.execute_reply":"2024-01-31T11:10:35.359051Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport wandb\nfrom torch.utils.data import DataLoader\nfrom sklearn.metrics import accuracy_score\n\ndef test(model, dataloader, criterion, device):\n    model.eval()\n    total_loss = 0.0\n    all_preds = []\n    all_labels = []\n\n    with torch.no_grad():\n        for inputs, labels in dataloader:\n            inputs, labels = inputs.to(device), labels.to(device)\n\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n\n            total_loss += loss.item()\n\n            _, preds = torch.max(outputs, 1)\n            all_preds.extend(preds.cpu().numpy())\n            all_labels.extend(labels.cpu().numpy())\n\n    accuracy = accuracy_score(all_labels, all_preds)\n    wandb.log({\"Test Loss\": total_loss / len(dataloader), \"Test Accuracy\": accuracy})\n\n    print(f'Test Loss: {total_loss / len(dataloader):.4f}, Test Accuracy: {accuracy:.4f}')\n\n# Assuming you have already initialized WandB in your training script\nwandb.init(project='Skin Melanoma Detection Project', name=\"testing_run\")\n\n# Set the model to evaluation mode\nmodel.eval()\n\n# Assuming you have a dataloader for the test set\ntest_dataloader = dataloaders_dict['test']\n\n# Call the testing loop\ntest(model, test_dataloader, criterion, device)\n\nwandb.finish()\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport wandb\nfrom torch.utils.data import DataLoader\nfrom sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix\n\ndef test(model, dataloader, criterion, device):\n    model.eval()\n    total_loss = 0.0\n    all_preds = []\n    all_labels = []\n\n    with torch.no_grad():\n        for inputs, labels in dataloader:\n            inputs, labels = inputs.to(device), labels.to(device)\n\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n\n            total_loss += loss.item()\n\n            _, preds = torch.max(outputs, 1)\n            all_preds.extend(preds.cpu().numpy())\n            all_labels.extend(labels.cpu().numpy())\n\n    accuracy = accuracy_score(all_labels, all_preds)\n    precision = precision_score(all_labels, all_preds, average='weighted')\n    recall = recall_score(all_labels, all_preds, average='weighted')\n    f1 = f1_score(all_labels, all_preds, average='weighted')\n    conf_matrix = confusion_matrix(all_labels, all_preds)\n\n    wandb.log({\"Test Loss\": total_loss / len(dataloader), \"Test Accuracy\": accuracy})\n    \n    print(f'Test Loss: {total_loss / len(dataloader):.4f}, Test Accuracy: {accuracy:.4f}')\n    print(f'Precision: {precision:.4f}, Recall: {recall:.4f}, F1 Score: {f1:.4f}')\n    print('Confusion Matrix:')\n    print(conf_matrix)\n\n# Assuming you have already initialized WandB in your training script\nwandb.init(project='Skin Melanoma Detection Project', name=\"testing_run\")\n\n# Set the model to evaluation mode\nmodel.eval()\n\n# Assuming you have a dataloader for the test set\ntest_dataloader = dataloaders_dict['test']\n\n# Call the testing loop\ntest(model, test_dataloader, criterion, device)\n\nwandb.finish()","metadata":{},"execution_count":null,"outputs":[]}]}