{"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":"none","dataSources":[{"sourceId":7327,"databundleVersionId":861871,"sourceType":"competition"}],"dockerImageVersionId":30646,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader, Subset\nfrom torchvision import transforms, models\nfrom sklearn.model_selection import StratifiedKFold\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\nfrom skimage import io\nfrom tabulate import tabulate\nimport os\n\nclass DogBreedsDataset(Dataset):\n    def __init__(self, csv_file, root_dir, transform=None, train=True):\n        self.labels_frame = pd.read_csv(csv_file)\n        self.map = dict(zip(self.labels_frame['breed'].unique(), range(0, len(self.labels_frame['breed'].unique()))))\n        self.labels_frame['breed'] = self.labels_frame['breed'].map(self.map)\n        self.root_dir = root_dir\n        self.transform = transform\n        self.train = train\n\n    def getmap(self):\n        return self.map\n\n    def __getclasses__(self):\n        return self.labels_frame['breed'].unique().tolist()\n\n    def __len__(self):\n        return len(self.labels_frame)\n\n    def __getitem__(self, idx):\n        img_name = os.path.join(self.root_dir, self.labels_frame.iloc[idx, 0])\n        img_name = img_name + '.jpg'\n        image = io.imread(img_name)\n        PIL_image = Image.fromarray(image)\n        label = self.labels_frame.iloc[idx, 1:]\n        label = int(label.iloc[0].item())\n        label = np.asarray(label)\n        label = torch.from_numpy(label).long()\n\n        if self.transform:\n            if callable(self.transform):\n                image = self.transform(PIL_image)\n            elif isinstance(self.transform, dict):\n                if self.train:\n                    image = self.transform['train'](PIL_image)\n                else:\n                    image = self.transform['test'](PIL_image)\n\n        return image, label\n\nnew_transform = {\n    'train': transforms.Compose([\n        transforms.RandomResizedCrop(size=256, scale=(0.95, 1.0)),\n        transforms.RandomRotation(degrees=15),\n        transforms.ColorJitter(),\n        transforms.RandomHorizontalFlip(),\n        transforms.CenterCrop(size=224),\n        transforms.ToTensor(),\n        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n    ]),\n    'test': transforms.Compose([\n        transforms.RandomResizedCrop(size=256, scale=(0.95, 1.0)),\n        transforms.CenterCrop(size=224),\n        transforms.ToTensor(),\n        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n    ])\n}\n\ncsv = '/kaggle/input/dog-breed-identification/labels.csv'\nroot = '/kaggle/input/dog-breed-identification/train'\nalldata = DogBreedsDataset(csv_file=csv, root_dir=root, transform=new_transform, train=True)\n\nbatch_size = 32\nall_data_loader = DataLoader(alldata, batch_size=batch_size, shuffle=True)\n\nclass CustomVGG16MultiClass(nn.Module):\n    def __init__(self, num_classes):\n        super(CustomVGG16MultiClass, self).__init__()\n        \n        vgg16 = models.vgg16(pretrained=True)\n        self.features = vgg16.features\n        num_features = self._calculate_num_features(vgg16.features)\n        self.classifier = nn.Sequential(\n            nn.Linear(num_features, 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        )\n        \n    def _calculate_num_features(self, features):\n        x = torch.randn(1, 3, 224, 224)\n        x = features(x)\n        return x.view(x.size(0), -1).size(1)\n\n    def forward(self, x):\n        x = self.features(x)\n        x = x.view(x.size(0), -1)\n        x = self.classifier(x)\n        return x\n\nnum_classes = 120\nmodel = CustomVGG16MultiClass(num_classes)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\n\ndef train_model(model, train_loader, criterion, optimizer, train_on_gpu):\n    model.train()\n    train_loss = 0.0\n    \n    for batch_i, (data, target) in enumerate(train_loader):\n        if train_on_gpu:\n            data, target = data.cuda(), target.cuda()\n        \n        optimizer.zero_grad()\n        output = model(data)\n        loss = criterion(output, target)\n        loss.backward()\n        optimizer.step()\n        train_loss += loss.item()\n        \n        if batch_i % 20 == 19:\n            print('Batch %d loss: %.16f' % (batch_i + 1, train_loss / 20))\n            train_loss = 0.0\n\ndef evaluate_model_table(model, data_loader, criterion, train_on_gpu):\n    model.eval()\n    losses = []\n\n    for batch_i, (data, target) in enumerate(data_loader):\n        if train_on_gpu:\n            data, target = data.cuda(), target.cuda()\n\n        output = model(data)\n        loss = criterion(output, target).item()\n        losses.append(loss)\n\n    # Calculate percentage for each loss\n    total_loss = sum(losses)\n    percentages = [(loss / total_loss) * 100 for loss in losses]\n\n    # Create table\n    table = [[\"Image\", \"Percentage\"]]\n    for i, percentage in enumerate(percentages):\n        table.append([i+1, percentage])\n\n    # Print table\n    print(tabulate(table, headers=\"firstrow\", tablefmt=\"grid\"))\n\ndef evaluate_model(model, data_loader, criterion, train_on_gpu):\n    model.eval()\n    loss = 0.0\n\n    for batch_i, (data, target) in enumerate(data_loader):\n        if train_on_gpu:\n            data, target = data.cuda(), target.cuda()\n\n        output = model(data)\n        loss += criterion(output, target).item()\n\n        if batch_i % 20 == 19:\n            print(f'Batch {batch_i + 1}, Loss: {loss / 20}')\n            loss = 0.0\n\n    return loss / len(data_loader)\n\ntrain_on_gpu = torch.cuda.is_available()\n\nnum_epochs = 15\nfor epoch in range(num_epochs):\n    train_model(model, all_data_loader, criterion, optimizer, train_on_gpu)\n    print(f'Epoch {epoch + 1}, Validation Loss:')\n    evaluate_model_table(model, all_data_loader, criterion, train_on_gpu)\n\nnum_folds = 5\ncv = StratifiedKFold(n_splits=num_folds, shuffle=True, random_state=0)\n\nfor fold, (train_idx, val_idx) in enumerate(cv.split(X=alldata.labels_frame, y=alldata.labels_frame['breed'])):\n    print('****************  FOLD ', fold, '  *********************')\n\n    train_dataset = Subset(alldata, train_idx)\n    val_dataset = Subset(alldata, val_idx)\n\n    train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\n    val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)\n\n    for epoch in range(2):\n        train_model(model, train_loader, criterion, optimizer, train_on_gpu)\n\n    validation_loss = evaluate_model(model, val_loader, criterion, train_on_gpu)\n    print(f'Fold {fold + 1}, Validation Loss: {validation_loss}')\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-02-06T15:44:25.888146Z","iopub.execute_input":"2024-02-06T15:44:25.88864Z","iopub.status.idle":"2024-02-06T15:46:14.175762Z","shell.execute_reply.started":"2024-02-06T15:44:25.888594Z","shell.execute_reply":"2024-02-06T15:46:14.173473Z"},"trusted":true},"execution_count":null,"outputs":[]}]}