{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":3362,"databundleVersionId":31148,"sourceType":"competition"}],"dockerImageVersionId":30761,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"#                                                 Transfer Learning Using Inception V3 (Pytorch)","metadata":{}},{"cell_type":"markdown","source":"Inception V3 is a little bit different Model from others, in a sense that it take the inpit 299 x 299, also it returns its own output type InceptionOutputs. So we need to check during tranining and inference.\n","metadata":{}},{"cell_type":"markdown","source":"## Extrcting files from folders","metadata":{}},{"cell_type":"code","source":"import zipfile\nzip_files = [\"/kaggle/input/dogs-vs-cats/test1.zip\", \"/kaggle/input/dogs-vs-cats/train.zip\"]\n\nfor i in zip_files:\n    with zipfile.ZipFile(i, 'r') as zip_ref:\n        zip_ref.extractall(\"dogs-vs-cats/\")","metadata":{"execution":{"iopub.status.busy":"2024-08-28T23:19:18.172188Z","iopub.execute_input":"2024-08-28T23:19:18.172891Z","iopub.status.idle":"2024-08-28T23:19:31.866963Z","shell.execute_reply.started":"2024-08-28T23:19:18.172848Z","shell.execute_reply":"2024-08-28T23:19:31.866147Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Organize the images folder\nI use two methods to create a dataloader\n","metadata":{}},{"cell_type":"code","source":"import os\nimport shutil\n\n# Define the directory containing your images\nsource_dir = '/kaggle/working/dogs-vs-cats/train'  # Change this to your directory\ncat_dir = 'kaggle/working/dogs-vs-cats/train/cat'  # Change this to your cat folder\ndog_dir = 'kaggle/working/dogs-vs-cats/train/dog'  # Change this to your dog folder\n\n# Create the cat and dog directories if they don't exist\nos.makedirs(cat_dir, exist_ok=True)\nos.makedirs(dog_dir, exist_ok=True)\n\n# Loop through all files in the source directory\nfor filename in os.listdir(source_dir):\n    if 'cat' in filename.lower():\n        shutil.move(os.path.join(source_dir, filename), os.path.join(cat_dir, filename))\n    elif 'dog' in filename.lower():\n        shutil.move(os.path.join(source_dir, filename), os.path.join(dog_dir, filename))\n\nprint(\"Images have been organized into cat and dog folders.\")","metadata":{"execution":{"iopub.status.busy":"2024-08-28T23:19:35.997916Z","iopub.execute_input":"2024-08-28T23:19:35.998282Z","iopub.status.idle":"2024-08-28T23:19:36.866471Z","shell.execute_reply.started":"2024-08-28T23:19:35.998248Z","shell.execute_reply":"2024-08-28T23:19:36.865530Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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\nfor dirname, _, filenames in os.walk('/kaggle/working'):\n    print(dirname)\n#     for filename in filenames:\n#         print(os.path.join(dirname, filename))\n\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-08-28T23:19:40.751979Z","iopub.execute_input":"2024-08-28T23:19:40.752357Z","iopub.status.idle":"2024-08-28T23:19:41.115561Z","shell.execute_reply.started":"2024-08-28T23:19:40.752315Z","shell.execute_reply":"2024-08-28T23:19:41.114590Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%matplotlib inline\n%config InlineBackend.figure_format = 'retina'\n\nimport matplotlib.pyplot as plt\nfrom collections import OrderedDict\nimport torch\nimport time\nfrom torch import nn\nfrom torch import optim\nimport torch.nn.functional as F\nfrom torchvision import datasets, transforms, models\nfrom torch.utils.data import random_split\nfrom torchvision.models.inception import InceptionOutputs\nfrom huggingface_hub import PyTorchModelHubMixin\n","metadata":{"execution":{"iopub.status.busy":"2024-08-28T23:19:44.528704Z","iopub.execute_input":"2024-08-28T23:19:44.529461Z","iopub.status.idle":"2024-08-28T23:19:49.611227Z","shell.execute_reply.started":"2024-08-28T23:19:44.529419Z","shell.execute_reply":"2024-08-28T23:19:49.610263Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_dir = '/kaggle/working/kaggle/working/dogs-vs-cats/'\ntest_dir = '/kaggle/working/dogs-vs-cats/test1'\n\n\ntrain_transforms = transforms.Compose(\n    [\n        transforms.Resize(299),  # Ensure that images are resized to 299x299\n        transforms.CenterCrop(299),  # Center crop to 299x299\n        transforms.RandomRotation(45),\n        transforms.GaussianBlur(3),\n        transforms.RandomHorizontalFlip(),\n        transforms.ToTensor()    \n    ]\n)\n\n\n# Pass transforms in here\ntrain_data = datasets.ImageFolder(data_dir + 'train', transform=train_transforms)\n\n# Define the train-validation split ratio\ntrain_size = int(0.8 * len(train_data))  # 80% for training\nval_size = len(train_data) - train_size   # 20% for validation\n\n# Split the dataset\ntrain_dataset, val_dataset = random_split(train_data, [train_size, val_size])\n\n# Create DataLoaders for train and validation sets\ntrainloader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)\nvalloader = torch.utils.data.DataLoader(val_dataset, batch_size=64)","metadata":{"execution":{"iopub.status.busy":"2024-08-28T23:34:10.628459Z","iopub.execute_input":"2024-08-28T23:34:10.628860Z","iopub.status.idle":"2024-08-28T23:34:10.753054Z","shell.execute_reply.started":"2024-08-28T23:34:10.628826Z","shell.execute_reply":"2024-08-28T23:34:10.752276Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load model\nmodel = models.inception_v3(pretrained=True)\nmodel","metadata":{"execution":{"iopub.status.busy":"2024-08-28T23:34:11.728219Z","iopub.execute_input":"2024-08-28T23:34:11.728906Z","iopub.status.idle":"2024-08-28T23:34:12.026819Z","shell.execute_reply.started":"2024-08-28T23:34:11.728864Z","shell.execute_reply":"2024-08-28T23:34:12.025847Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Freeze parameters so we don't backprop through them\nfor param in model.parameters():\n    param.requires_grad = False\n\n### PyTorchModelHubMixin: To upload the model to huggingface repository. Cool feature to show case your models.\nclass Classifier(\n    nn.Module,\n    PyTorchModelHubMixin,\n    repo_url=\"muneebable\",\n    pipeline_tag=\"image-classification\",\n    license=\"apache-2.0\"\n):\n    def __init__(self):\n        super().__init__()\n        self.fc1 = nn.Linear(2048, 500)\n        self.fc2 = nn.Linear(500, 2)\n        self.dropout = nn.Dropout(p=0.2)\n        self.output =  nn.LogSoftmax(dim=1)\n    \n    def forward(self, x):\n        x = F.relu(self.fc1(x))\n        x = self.dropout(x)\n        x = self.fc2(x)\n        return self.output(x)\n\n\nclassifier = Classifier()\n# Replace the last layer of model with out classifier.\nmodel.fc = classifier","metadata":{"execution":{"iopub.status.busy":"2024-08-28T23:34:12.972718Z","iopub.execute_input":"2024-08-28T23:34:12.973569Z","iopub.status.idle":"2024-08-28T23:34:12.990893Z","shell.execute_reply.started":"2024-08-28T23:34:12.973525Z","shell.execute_reply":"2024-08-28T23:34:12.990110Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model","metadata":{"execution":{"iopub.status.busy":"2024-08-28T23:34:13.481503Z","iopub.execute_input":"2024-08-28T23:34:13.482238Z","iopub.status.idle":"2024-08-28T23:34:13.492577Z","shell.execute_reply.started":"2024-08-28T23:34:13.482199Z","shell.execute_reply":"2024-08-28T23:34:13.491572Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\nprint(device)\n\ncriterion = nn.NLLLoss()\n\n# Only train the classifier parameters, feature parameters are frozen\noptimizer = optim.Adam(model.fc.parameters(), lr=0.003)\n\nmodel.to(device);","metadata":{"execution":{"iopub.status.busy":"2024-08-28T23:36:34.659559Z","iopub.execute_input":"2024-08-28T23:36:34.659933Z","iopub.status.idle":"2024-08-28T23:36:34.673092Z","shell.execute_reply.started":"2024-08-28T23:36:34.659900Z","shell.execute_reply":"2024-08-28T23:36:34.672126Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"criterion = nn.NLLLoss()\nepochs = 1\nsteps = 0\nrunning_loss = 0\nprint_every = 5\nfor epoch in range(epochs):\n    for inputs, labels in trainloader:\n        steps += 1\n        # Move input and label tensors to the default device\n        inputs, labels = inputs.to(device), labels.to(device)\n        \n         # Forward pass\n        model.train()  # Ensure the model is in training mode\n        \n        output = model.forward(inputs)\n        # In training mode, InceptionV3 returns both logits and aux_logits\n        if isinstance(output, InceptionOutputs):\n            logps = output.logits\n        else:\n            logps = output  # Handle the case where the output is already a Tensor\n\n        loss = criterion(logps, labels)\n        \n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item()\n        \n        if steps % print_every == 0:\n            test_loss = 0\n            accuracy = 0\n            model.eval()\n            with torch.no_grad():\n                for inputs, labels in valloader:\n                    inputs, labels = inputs.to(device), labels.to(device)\n                    output = model.forward(inputs)\n                    # In eval mode, InceptionV3 only returns logits\n                    if isinstance(output, InceptionOutputs):\n                        logps = output.logits\n                    else:\n                        logps = output\n        \n                    batch_loss = criterion(logps, labels)\n                    \n                    test_loss += batch_loss.item()\n                    \n                    # Calculate accuracy\n                    ps = torch.exp(logps)\n                    top_p, top_class = ps.topk(1, dim=1)\n                    equals = top_class == labels.view(*top_class.shape)\n                    accuracy += torch.mean(equals.type(torch.FloatTensor)).item()\n                    \n            print(f\"Epoch {epoch+1}/{epochs}.. \"\n                  f\"Train loss: {running_loss/print_every:.3f}.. \"\n                  f\"Test loss: {test_loss/len(valloader):.3f}.. \"\n                  f\"Test accuracy: {accuracy/len(valloader):.3f}\")\n            running_loss = 0\n            model.train()","metadata":{"execution":{"iopub.status.busy":"2024-08-28T23:49:46.102444Z","iopub.execute_input":"2024-08-28T23:49:46.103408Z","iopub.status.idle":"2024-08-29T00:53:44.338336Z","shell.execute_reply.started":"2024-08-28T23:49:46.103342Z","shell.execute_reply":"2024-08-29T00:53:44.337341Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Save the model\nfilename_pth = 'ckpt_inception_v3_catdog.pth'\ntorch.save(model.state_dict(), filename_pth)","metadata":{"execution":{"iopub.status.busy":"2024-08-29T00:55:45.130694Z","iopub.execute_input":"2024-08-29T00:55:45.131083Z","iopub.status.idle":"2024-08-29T00:55:45.317812Z","shell.execute_reply.started":"2024-08-29T00:55:45.131048Z","shell.execute_reply":"2024-08-29T00:55:45.317018Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ## Copied\n# class CatDogDataset(Dataset):\n#     def __init__(self, file_list, dir, mode='train', transform = None):\n#         self.file_list = file_list\n#         self.dir = dir\n#         self.mode= mode\n#         self.transform = transform\n#         if self.mode == 'train':\n#             if 'dog' in self.file_list[0]:\n#                 self.label = 1\n#             else:\n#                 self.label = 0\n            \n#     def __len__(self):\n#         return len(self.file_list)\n    \n#     def __getitem__(self, idx):\n#         img = Image.open(os.path.join(self.dir, self.file_list[idx]))\n#         if self.transform:\n#             img = self.transform(img)\n#         if self.mode == 'train':\n#             img = img.numpy()\n#             return img.astype('float32'), self.label\n#         else:\n#             img = img.numpy()\n#             return img.astype('float32'), self.file_list[idx]\n\n# #Transform the test dataset\n# test_transforms = transforms.Compose(\n#     [\n#         transforms.Resize(255),\n#         transforms.CenterCrop(224),\n#         transforms.ToTensor()    \n#     ]\n# )\n\n# test_dir = '/kaggle/working/dogs-vs-cats/test1'\n# test_files = os.listdir(test_dir)\n# testset = CatDogDataset(test_files, test_dir, mode='test', transform = test_transforms)\n# testloader = torch.utils.data.DataLoader(testset, batch_size = 64, shuffle=False, num_workers=4)\n\n# model.eval()\n# fn_list = []\n# pred_list = []\n# for x, fn in testloader:\n#     with torch.no_grad():\n#         x = x.to(device)\n#         output = model(x)\n#         pred = torch.argmax(output, dim=1)\n#         fn_list += [n[:-4] for n in fn]\n#         pred_list += [p.item() for p in pred]\n\n# submission = pd.DataFrame({\"id\":fn_list, \"label\":pred_list})\n# submission.to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2024-08-29T00:56:27.102772Z","iopub.execute_input":"2024-08-29T00:56:27.103445Z","iopub.status.idle":"2024-08-29T00:56:27.109114Z","shell.execute_reply.started":"2024-08-29T00:56:27.103406Z","shell.execute_reply":"2024-08-29T00:56:27.108059Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from kaggle_secrets import UserSecretsClient\nuser_secrets = UserSecretsClient()\nsecret_value_0 = user_secrets.get_secret(\"hugging_face\")\n\n# model.save_pretrained(\"inception_v3_catdog\")\n# model.push_to_hub(\"muneebable/inception_v3_catdog\",token=secret_value_0)\n\n# Push the model to the Hugging Face Hub (Need to create a Repo)\nfrom huggingface_hub import HfApi\n\napi = HfApi()\napi.upload_file(\n    path_or_fileobj=filename_pth,\n    path_in_repo=filename_pth,\n    repo_id=\"muneebable/inception_v3_catdog\",\n    token=secret_value_0\n)","metadata":{"execution":{"iopub.status.busy":"2024-08-29T00:57:42.804880Z","iopub.execute_input":"2024-08-29T00:57:42.805259Z","iopub.status.idle":"2024-08-29T00:57:49.666628Z","shell.execute_reply.started":"2024-08-29T00:57:42.805223Z","shell.execute_reply":"2024-08-29T00:57:49.665693Z"},"trusted":true},"execution_count":null,"outputs":[]}]}