{"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":7327,"databundleVersionId":861871,"sourceType":"competition"}],"dockerImageVersionId":30646,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport os\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.nn.functional as F\nimport torchvision\nfrom torchvision.transforms import v2\nimport matplotlib.pyplot as plt\nfrom torchvision.io import read_image\nfrom torch.utils.data import Dataset, default_collate\nfrom torchvision.transforms import ToTensor","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:20:26.910598Z","iopub.execute_input":"2024-02-16T00:20:26.911804Z","iopub.status.idle":"2024-02-16T00:20:34.560445Z","shell.execute_reply.started":"2024-02-16T00:20:26.911758Z","shell.execute_reply":"2024-02-16T00:20:34.559586Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:20:34.568694Z","iopub.execute_input":"2024-02-16T00:20:34.568952Z","iopub.status.idle":"2024-02-16T00:20:34.593137Z","shell.execute_reply.started":"2024-02-16T00:20:34.568929Z","shell.execute_reply":"2024-02-16T00:20:34.592101Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BASE_DIR = \"/kaggle/input/dog-breed-identification\"\nTRAIN_DIR = os.path.join(BASE_DIR, \"train\")","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:20:34.594323Z","iopub.execute_input":"2024-02-16T00:20:34.594589Z","iopub.status.idle":"2024-02-16T00:20:34.604205Z","shell.execute_reply.started":"2024-02-16T00:20:34.594567Z","shell.execute_reply":"2024-02-16T00:20:34.603404Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(os.path.join(BASE_DIR, \"labels.csv\"))\ndf[\"id\"] = df[\"id\"].apply(lambda x: os.path.join(TRAIN_DIR, x+\".jpg\"))\n\nlabels = sorted(df[\"breed\"].unique())\nlabel_to_int = {breed:i for i, breed in enumerate(labels)}\nint_to_label = {i:breed for i, breed in enumerate(labels)}","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:20:34.605343Z","iopub.execute_input":"2024-02-16T00:20:34.605607Z","iopub.status.idle":"2024-02-16T00:20:34.675882Z","shell.execute_reply.started":"2024-02-16T00:20:34.605584Z","shell.execute_reply":"2024-02-16T00:20:34.674896Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_size = int(len(df) * 0.1)\nindices = np.random.choice(len(df)-1, replace=False, size=val_size)\ndf_train = df.drop(indices)\ndf_test = df.iloc[indices]\n\nprint(len(df_train), len(df_test))","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:20:34.676998Z","iopub.execute_input":"2024-02-16T00:20:34.677305Z","iopub.status.idle":"2024-02-16T00:20:34.690233Z","shell.execute_reply.started":"2024-02-16T00:20:34.677281Z","shell.execute_reply":"2024-02-16T00:20:34.689228Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DogBreedDataset(Dataset):\n    def __init__(self, dataframe, img_dir, transform=None, target_transform=None):\n        self.img_labels = dataframe\n        self.img_dir = img_dir\n        self.transform = transform\n        self.target_transform = target_transform\n\n    def __len__(self):\n        return len(self.img_labels)\n\n    def __getitem__(self, idx):\n        img_path = self.img_labels.iloc[idx, 0]\n        image = read_image(img_path)\n        label = self.img_labels.iloc[idx, 1]\n        if self.transform:\n            image = self.transform(image)\n        if self.target_transform:\n            label = self.target_transform(label)\n        return image, label","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:20:34.691664Z","iopub.execute_input":"2024-02-16T00:20:34.692028Z","iopub.status.idle":"2024-02-16T00:20:34.699971Z","shell.execute_reply.started":"2024-02-16T00:20:34.691995Z","shell.execute_reply":"2024-02-16T00:20:34.699020Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Cutout(object):\n    def __init__(self, n_holes, length, prob=0.5):\n        self.n_holes = n_holes\n        self.length = length\n        self.prob = prob\n\n    def __call__(self, img):\n        \n        if np.random.rand() > self.prob:\n            return img\n        \n        h = img.size(1)\n        w = img.size(2)\n\n        mask = np.ones((h, w), np.float32)\n\n        for n in range(self.n_holes):\n            y = np.random.randint(h)\n            x = np.random.randint(w)\n\n            y1 = np.clip(y - self.length // 2, 0, h)\n            y2 = np.clip(y + self.length // 2, 0, h)\n            x1 = np.clip(x - self.length // 2, 0, w)\n            x2 = np.clip(x + self.length // 2, 0, w)\n\n            mask[y1: y2, x1: x2] = 0.\n\n        mask = torch.from_numpy(mask)\n        mask = mask.expand_as(img)\n        img = img * mask\n\n        return img","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:20:34.701135Z","iopub.execute_input":"2024-02-16T00:20:34.701479Z","iopub.status.idle":"2024-02-16T00:20:34.711062Z","shell.execute_reply.started":"2024-02-16T00:20:34.701389Z","shell.execute_reply":"2024-02-16T00:20:34.710094Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"transform_train = v2.Compose([\n    v2.Resize((224,224), antialias=True),\n    v2.ToDtype(torch.float32, scale=True),\n    v2.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n    Cutout(1, 56)\n])\n\ntransform_test = v2.Compose([\n    v2.Resize((224,224), antialias=True),\n    v2.ToDtype(torch.float32, scale=True),\n    v2.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\ndataset_train = DogBreedDataset(\n    df_train,\n    TRAIN_DIR,\n    transform_train,\n    lambda x: label_to_int[x]\n)\n\ndataset_test = DogBreedDataset(\n    df_test,\n    TRAIN_DIR,\n    transform_test,\n    lambda x: label_to_int[x]\n)","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:20:34.713930Z","iopub.execute_input":"2024-02-16T00:20:34.714320Z","iopub.status.idle":"2024-02-16T00:20:34.725702Z","shell.execute_reply.started":"2024-02-16T00:20:34.714295Z","shell.execute_reply":"2024-02-16T00:20:34.724789Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=64,\n                                          shuffle=True, num_workers=2)\n\ntest_loader = torch.utils.data.DataLoader(dataset_test, batch_size=64,\n                                          shuffle=False, num_workers=2)","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:20:34.726836Z","iopub.execute_input":"2024-02-16T00:20:34.727145Z","iopub.status.idle":"2024-02-16T00:20:34.735628Z","shell.execute_reply.started":"2024-02-16T00:20:34.727121Z","shell.execute_reply":"2024-02-16T00:20:34.734833Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"figure = plt.figure(figsize=(8, 8))\ncols, rows = 3, 3\nfor i in range(1, cols * rows + 1):\n    sample_idx = torch.randint(len(dataset_train), size=(1,)).item()\n    img, label = dataset_train[sample_idx]\n    figure.add_subplot(rows, cols, i)\n    plt.title(int_to_label[label])\n    plt.axis(\"off\")\n    plt.imshow(torch.permute(img, (1, 2, 0)))\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:20:34.736678Z","iopub.execute_input":"2024-02-16T00:20:34.736952Z","iopub.status.idle":"2024-02-16T00:20:35.866021Z","shell.execute_reply.started":"2024-02-16T00:20:34.736922Z","shell.execute_reply":"2024-02-16T00:20:35.865112Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def accuracy(outputs, labels):\n    with torch.no_grad():\n        _, preds = torch.max(outputs, dim=1)\n        return torch.sum(preds == labels).item() / len(preds)\n    \ndef validate(model, dataset, criterion):\n    correct = 0\n    total = 0\n    running_loss = 0.0\n    \n    with torch.no_grad():\n        for i, data in enumerate(dataset):\n            images, labels = data[0].to(device), data[1].to(device)\n            outputs = model(images)\n            \n            # val loss\n            loss = criterion(outputs, labels)\n            running_loss += loss.item()\n            \n            # val accuracy\n            _, preds = torch.max(outputs.data, 1)\n            total += labels.size(0)\n            correct += (preds == labels).sum().item()\n    \n    return running_loss / (i+1), correct / total","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:20:35.867186Z","iopub.execute_input":"2024-02-16T00:20:35.867463Z","iopub.status.idle":"2024-02-16T00:20:35.876089Z","shell.execute_reply.started":"2024-02-16T00:20:35.867439Z","shell.execute_reply":"2024-02-16T00:20:35.875103Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train(model, optimizer, criterion, train_loader, test_loader, epochs=10, scheduler=None):\n    counter = 0\n    for epoch in range(epochs):\n        \n        if counter > 5:\n            print(\"Early Stopping\")\n            break\n        \n        train_losses, train_accs = list(), list()\n\n        for i, data in enumerate(train_loader, 0):\n            inputs, labels = data[0].to(device), data[1].to(device)\n\n            optimizer.zero_grad()\n\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n            \n            loss.backward()\n            optimizer.step()\n\n            # Train statistics\n            train_losses.append(loss.item())\n            train_accs.append(accuracy(outputs, labels))\n\n            if i % 72 == 71:\n                avg_acc = sum(train_accs)/len(train_accs)\n                avg_loss = sum(train_losses)/len(train_losses)\n                print(f'[{epoch + 1}, {i + 1:5d}] loss: {avg_loss:.3f} acc: {avg_acc:.3f}')\n                train_losses.clear()\n                train_accs.clear()\n\n        # Validation statistics\n        avg_val_loss, avg_val_acc = validate(model, test_loader, criterion)\n        print(f'[{epoch + 1}] val loss: {avg_val_loss:.3f} val acc: {avg_val_acc:.3f}')\n        \n        # Learning Rate Scheduler\n        if scheduler is not None:\n            scheduler.step()\n            print(f\"LR: {optimizer.param_groups[0]['lr']:.7f}\")\n        \n        if (avg_acc - avg_val_acc) > 0.1:\n            counter += 1\n        \n    print('Finished Training')","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:20:35.877161Z","iopub.execute_input":"2024-02-16T00:20:35.877460Z","iopub.status.idle":"2024-02-16T00:20:35.890094Z","shell.execute_reply.started":"2024-02-16T00:20:35.877430Z","shell.execute_reply":"2024-02-16T00:20:35.889226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#(classifier): Linear(in_features=1024, out_features=1000, bias=True)\ndensenet121 = torch.hub.load('pytorch/vision:v0.10.0', 'densenet121', pretrained=True)\ndensenet121.classifier = nn.Linear(1024, len(labels))\ndensenet121.to(device)\ndensenet121.eval()","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:20:35.891304Z","iopub.execute_input":"2024-02-16T00:20:35.891667Z","iopub.status.idle":"2024-02-16T00:20:38.731019Z","shell.execute_reply.started":"2024-02-16T00:20:35.891638Z","shell.execute_reply":"2024-02-16T00:20:38.730107Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"criterion = nn.CrossEntropyLoss()\noptimizer = optim.SGD(densenet121.parameters(), lr=1e-3, weight_decay=4e-5)\nscheduler = optim.lr_scheduler.MultiStepLR(optimizer, [5, 25, 45], gamma = 0.08)\n\ntrain(densenet121, optimizer, criterion,train_loader, test_loader, 100, scheduler)","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:20:38.732166Z","iopub.execute_input":"2024-02-16T00:20:38.732457Z","iopub.status.idle":"2024-02-16T00:34:23.722225Z","shell.execute_reply.started":"2024-02-16T00:20:38.732433Z","shell.execute_reply":"2024-02-16T00:34:23.720981Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.save(densenet121, \"model.pt\")","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:34:23.724302Z","iopub.execute_input":"2024-02-16T00:34:23.724652Z","iopub.status.idle":"2024-02-16T00:34:23.876423Z","shell.execute_reply.started":"2024-02-16T00:34:23.724617Z","shell.execute_reply":"2024-02-16T00:34:23.875598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_true = []\ny_pred = []\n \nwith torch.no_grad():\n    for data in test_loader:\n        images, lbs = data[0].to(device),data[1].to(device)\n\n        y_true.extend(lbs.cpu().numpy())\n\n        outputs = densenet121(images)\n        _, predicted = torch.max(outputs, 1)\n        y_pred.extend(predicted.cpu().numpy())","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:34:23.877798Z","iopub.execute_input":"2024-02-16T00:34:23.878114Z","iopub.status.idle":"2024-02-16T00:34:26.733594Z","shell.execute_reply.started":"2024-02-16T00:34:23.878089Z","shell.execute_reply":"2024-02-16T00:34:26.732538Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import f1_score, accuracy_score\n\nprint(f'F1 Score: {f1_score(y_true, y_pred, average=\"weighted\"):.3f}')\nprint(f'Accuracy: {accuracy_score(y_true, y_pred):.3f}')\n","metadata":{"execution":{"iopub.status.busy":"2024-02-16T00:34:26.735018Z","iopub.execute_input":"2024-02-16T00:34:26.735368Z","iopub.status.idle":"2024-02-16T00:34:27.465154Z","shell.execute_reply.started":"2024-02-16T00:34:26.735337Z","shell.execute_reply":"2024-02-16T00:34:27.464248Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}