{"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":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":30776,"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\nfor dirname, _, filenames in os.walk('/kaggle/input'):\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-09-25T11:31:51.060373Z","iopub.execute_input":"2024-09-25T11:31:51.061481Z","iopub.status.idle":"2024-09-25T11:31:51.440925Z","shell.execute_reply.started":"2024-09-25T11:31:51.061402Z","shell.execute_reply":"2024-09-25T11:31:51.439857Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport os\nimport random\nfrom PIL import Image\nimport time\nimport torch\nfrom torch import nn\nimport torchvision\nfrom torchvision import datasets\nfrom torchvision import transforms\nfrom torch.utils.data import Dataset, DataLoader\nfrom tqdm.auto import tqdm\nimport zipfile\nimport glob\nfrom sklearn.model_selection import train_test_split\nimport shutil # to move data from dir to another","metadata":{"execution":{"iopub.status.busy":"2024-09-25T11:31:51.629967Z","iopub.execute_input":"2024-09-25T11:31:51.630986Z","iopub.status.idle":"2024-09-25T11:31:56.660147Z","shell.execute_reply.started":"2024-09-25T11:31:51.630930Z","shell.execute_reply":"2024-09-25T11:31:56.659338Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 0- i will make some changes in directories which contains data to make it more flexible\n### 1- create data_transform\n### 2- load data into Image folder dataset\n### 3- load data into dataloader\n### 4- build model\n### 5- create train, test functions and make functions combines them togrther\n### 6- start training\n### 7- plot loss and accuracy\n### 8- test on custom image","metadata":{}},{"cell_type":"markdown","source":"i want to make the Directory hierarchy for Dataset","metadata":{}},{"cell_type":"code","source":"os.listdir('../input/dogs-vs-cats-redux-kernels-edition')","metadata":{"execution":{"iopub.status.busy":"2024-09-25T11:32:01.130779Z","iopub.execute_input":"2024-09-25T11:32:01.131267Z","iopub.status.idle":"2024-09-25T11:32:01.140433Z","shell.execute_reply.started":"2024-09-25T11:32:01.131230Z","shell.execute_reply":"2024-09-25T11:32:01.139526Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.makedirs('../data', exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2024-09-25T11:32:01.557778Z","iopub.execute_input":"2024-09-25T11:32:01.558141Z","iopub.status.idle":"2024-09-25T11:32:01.562795Z","shell.execute_reply.started":"2024-09-25T11:32:01.558103Z","shell.execute_reply":"2024-09-25T11:32:01.561774Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"base_dir = '../input/dogs-vs-cats-redux-kernels-edition'\ntrain_dir = '../data/train'\ntest_dir = '../data/test'","metadata":{"execution":{"iopub.status.busy":"2024-09-25T11:32:02.359975Z","iopub.execute_input":"2024-09-25T11:32:02.360706Z","iopub.status.idle":"2024-09-25T11:32:02.364816Z","shell.execute_reply.started":"2024-09-25T11:32:02.360662Z","shell.execute_reply":"2024-09-25T11:32:02.363877Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = 'cuda' if torch.cuda.is_available() else 'cpu'\n\ntorch.manual_seed(42)\nif device =='cuda':\n    torch.cuda.manual_seed_all(42)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-25T11:32:03.653527Z","iopub.execute_input":"2024-09-25T11:32:03.653909Z","iopub.status.idle":"2024-09-25T11:32:03.697646Z","shell.execute_reply.started":"2024-09-25T11:32:03.653871Z","shell.execute_reply":"2024-09-25T11:32:03.696777Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with zipfile.ZipFile(os.path.join(base_dir, 'train.zip')) as train_zip:\n    train_zip.extractall('../data')\n    \nwith zipfile.ZipFile(os.path.join(base_dir, 'test.zip')) as test_zip:\n    test_zip.extractall('../data')","metadata":{"execution":{"iopub.status.busy":"2024-09-25T11:32:05.831745Z","iopub.execute_input":"2024-09-25T11:32:05.832134Z","iopub.status.idle":"2024-09-25T11:32:24.722560Z","shell.execute_reply.started":"2024-09-25T11:32:05.832095Z","shell.execute_reply":"2024-09-25T11:32:24.721715Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_list = glob.glob(os.path.join(train_dir,'*.jpg'))\ntest_list = glob.glob(os.path.join(test_dir, '*.jpg'))","metadata":{"execution":{"iopub.status.busy":"2024-09-25T11:32:24.724066Z","iopub.execute_input":"2024-09-25T11:32:24.724375Z","iopub.status.idle":"2024-09-25T11:32:24.865725Z","shell.execute_reply.started":"2024-09-25T11:32:24.724340Z","shell.execute_reply":"2024-09-25T11:32:24.864781Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# visualize image from train data\nfrom pathlib import Path\nrandom.seed(42)\nrandom_img =random.choice(train_list)\nrandom_img_class = Path(random_img).parent.stem\nimg = Image.open(random_img)\nprint(f\"Random image path: {random_img} \\n Image class: {random_img_class}\")\nprint(f\"Image height: {img.height}\")\nprint(f\"Image width: {img.width}\")\nimg","metadata":{"execution":{"iopub.status.busy":"2024-09-25T11:33:46.058813Z","iopub.execute_input":"2024-09-25T11:33:46.059239Z","iopub.status.idle":"2024-09-25T11:33:46.086985Z","shell.execute_reply.started":"2024-09-25T11:33:46.059201Z","shell.execute_reply":"2024-09-25T11:33:46.086091Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train, val = train_test_split(train_list, test_size=0.2)","metadata":{"execution":{"iopub.status.busy":"2024-09-25T11:33:50.431762Z","iopub.execute_input":"2024-09-25T11:33:50.432494Z","iopub.status.idle":"2024-09-25T11:33:50.445090Z","shell.execute_reply.started":"2024-09-25T11:33:50.432431Z","shell.execute_reply":"2024-09-25T11:33:50.444277Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# Define paths for train and validation directories\nbase_dir = 'data'\ntrain_dir = os.path.join(base_dir, 'train')\nval_dir = os.path.join(base_dir, 'val')\n\n# Create the directory structure\nos.makedirs(os.path.join(train_dir, 'dogs'), exist_ok=True)\nos.makedirs(os.path.join(train_dir, 'cats'), exist_ok=True)\nos.makedirs(os.path.join(val_dir, 'dogs'), exist_ok=True)\nos.makedirs(os.path.join(val_dir, 'cats'), exist_ok=True)\n\n# Move training images\nfor img_path in train:\n    if 'cat' in img_path:\n        dst_path = os.path.join(train_dir, 'cats', os.path.basename(img_path))\n    else:\n        dst_path = os.path.join(train_dir, 'dogs', os.path.basename(img_path))\n    \n    shutil.copy(img_path, dst_path)  # Use copy to avoid moving if needed\n\n# Move validation images\nfor img_path in val:\n    if 'cat' in img_path:\n        dst_path = os.path.join(val_dir, 'cats', os.path.basename(img_path))\n    else:\n        dst_path = os.path.join(val_dir, 'dogs', os.path.basename(img_path))\n\n    shutil.copy(img_path, dst_path)  # Use copy to avoid moving if needed\n\n# Now you can use ImageFolder\nfrom torchvision import datasets, transforms\n\n","metadata":{"execution":{"iopub.status.busy":"2024-09-25T12:09:56.234567Z","iopub.execute_input":"2024-09-25T12:09:56.234959Z","iopub.status.idle":"2024-09-25T12:09:56.240159Z","shell.execute_reply.started":"2024-09-25T12:09:56.234920Z","shell.execute_reply":"2024-09-25T12:09:56.239197Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 1- Data Transform","metadata":{}},{"cell_type":"code","source":"#Transformation using augmantation and without augmantation\ndata_transform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize((0.5,), (0.5,))\n])\n\ntrain_data = datasets.ImageFolder(root=train_dir, transform=data_transform)\nval_data = datasets.ImageFolder(root=val_dir, transform=data_transform)\n\nprint(\"Data is ready for use with ImageFolder.\")","metadata":{"execution":{"iopub.status.busy":"2024-09-25T12:10:02.468917Z","iopub.execute_input":"2024-09-25T12:10:02.469680Z","iopub.status.idle":"2024-09-25T12:10:02.589756Z","shell.execute_reply.started":"2024-09-25T12:10:02.469635Z","shell.execute_reply":"2024-09-25T12:10:02.588787Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2- Loading dataset into dataloader","metadata":{}},{"cell_type":"code","source":"NUM_WORKERS = os.cpu_count() # number of cpus in the system\nBATCH_SIZE = 32\ntrain_dataloader = DataLoader(dataset=train_data, \n                              batch_size=BATCH_SIZE, \n                              shuffle=True, \n                              num_workers=NUM_WORKERS)\n\ntest_dataloader = DataLoader(dataset=val_data, \n                            batch_size=BATCH_SIZE,\n                            num_workers=NUM_WORKERS)","metadata":{"execution":{"iopub.status.busy":"2024-09-25T11:34:38.031559Z","iopub.execute_input":"2024-09-25T11:34:38.032279Z","iopub.status.idle":"2024-09-25T11:34:38.037754Z","shell.execute_reply.started":"2024-09-25T11:34:38.032241Z","shell.execute_reply":"2024-09-25T11:34:38.036645Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(train_dataloader), len(test_dataloader)","metadata":{"execution":{"iopub.status.busy":"2024-09-25T11:34:38.930073Z","iopub.execute_input":"2024-09-25T11:34:38.930423Z","iopub.status.idle":"2024-09-25T11:34:38.936716Z","shell.execute_reply.started":"2024-09-25T11:34:38.930390Z","shell.execute_reply":"2024-09-25T11:34:38.935745Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3- Build Model","metadata":{}},{"cell_type":"code","source":"class TinyVGG(nn.Module):\n    def __init__(self, input_shape, hidden_units, output_shape):\n        super().__init__()\n        self.conv_block_1 = nn.Sequential(\n            nn.Conv2d(in_channels=input_shape,\n                      out_channels=hidden_units,\n                      kernel_size=3,\n                      stride=1,\n                      padding=1),\n            nn.ReLU(),\n            nn.Conv2d(in_channels=hidden_units,\n                      out_channels=hidden_units,\n                      kernel_size=3,\n                      stride=1,\n                      padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2)\n        )\n        self.conv_block_2 = nn.Sequential(\n            nn.Conv2d(in_channels=hidden_units,\n                      out_channels=hidden_units,\n                      kernel_size=3,\n                      stride=1,\n                      padding=1),\n            nn.ReLU(),\n            nn.Conv2d(in_channels=hidden_units,\n                      out_channels=hidden_units,\n                      kernel_size=3,\n                      stride=1,\n                      padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2)\n        )\n        self.classifier = nn.Sequential(\n            nn.Flatten(),\n            nn.Linear(in_features=hidden_units*56*56,\n                      out_features=output_shape))\n        \n    def forward(self, x):\n#         x = self.conv_block_1(x)\n#         print(f\"Layer 1 shape: {x.shape}\")\n#         x = self.conv_block_2(x)\n#         print(f\"Layer 2 shape: {x.shape}\")\n#         x = self.classifier(x)\n#         print(f\"Layer 3 shape: {x.shape}\")\n        return self.classifier(self.conv_block_2(self.conv_block_1(x))) # it's better for fast computaation","metadata":{"execution":{"iopub.status.busy":"2024-09-25T12:31:41.572908Z","iopub.execute_input":"2024-09-25T12:31:41.573301Z","iopub.status.idle":"2024-09-25T12:31:41.591023Z","shell.execute_reply.started":"2024-09-25T12:31:41.573263Z","shell.execute_reply":"2024-09-25T12:31:41.590062Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data.class_to_idx, train_data.classes","metadata":{"execution":{"iopub.status.busy":"2024-09-25T12:31:44.884090Z","iopub.execute_input":"2024-09-25T12:31:44.884495Z","iopub.status.idle":"2024-09-25T12:31:44.890876Z","shell.execute_reply.started":"2024-09-25T12:31:44.884442Z","shell.execute_reply":"2024-09-25T12:31:44.889910Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_names = train_data.classes\nclass_idx = train_data.class_to_idx","metadata":{"execution":{"iopub.status.busy":"2024-09-25T12:31:45.222515Z","iopub.execute_input":"2024-09-25T12:31:45.222829Z","iopub.status.idle":"2024-09-25T12:31:45.227034Z","shell.execute_reply.started":"2024-09-25T12:31:45.222796Z","shell.execute_reply":"2024-09-25T12:31:45.226116Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_0 = TinyVGG(input_shape=3, hidden_units=20, output_shape=len(class_names))","metadata":{"execution":{"iopub.status.busy":"2024-09-25T12:31:45.566943Z","iopub.execute_input":"2024-09-25T12:31:45.567733Z","iopub.status.idle":"2024-09-25T12:31:45.575347Z","shell.execute_reply.started":"2024-09-25T12:31:45.567687Z","shell.execute_reply":"2024-09-25T12:31:45.574485Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_0.to(device) # set our model into device agnostic code","metadata":{"execution":{"iopub.status.busy":"2024-09-25T12:31:45.940074Z","iopub.execute_input":"2024-09-25T12:31:45.940792Z","iopub.status.idle":"2024-09-25T12:31:45.948512Z","shell.execute_reply.started":"2024-09-25T12:31:45.940749Z","shell.execute_reply":"2024-09-25T12:31:45.947449Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dummy_x = torch.rand(size= [1,3,224,224])\nmodel_0(dummy_x.to(device))","metadata":{"execution":{"iopub.status.busy":"2024-09-25T12:31:46.278527Z","iopub.execute_input":"2024-09-25T12:31:46.279240Z","iopub.status.idle":"2024-09-25T12:31:46.289418Z","shell.execute_reply.started":"2024-09-25T12:31:46.279202Z","shell.execute_reply":"2024-09-25T12:31:46.288541Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 4- train, test steps","metadata":{}},{"cell_type":"code","source":"def train_step(model, dataloader, loss_fn, optimizer):\n    model.train()\n    train_loss, train_acc = 0, 0\n    total_samples = 0\n\n    for batch, (X, y) in enumerate(dataloader):\n        X, y = X.to(device), y.to(device)\n        \n        y_pred = model(X)  # Get raw logits\n\n        # Calculate loss\n        loss = loss_fn(y_pred, y)  # No need to squeeze for CrossEntropyLoss\n        train_loss += loss.item()\n        optimizer.zero_grad()  # Zero gradients at the start of the batch        \n        loss.backward()  # Backpropagation\n        optimizer.step()  # Update weights\n        \n        # Calculate accuracy\n        _, y_pred_class = torch.max(y_pred, 1)  # Get predicted classes\n        train_acc += (y_pred_class == y).sum().item()\n        total_samples += y.size(0)\n\n    train_loss /= len(dataloader)\n    train_acc /= total_samples  # Calculate accuracy as a fraction of total samples\n    return train_loss, train_acc\n","metadata":{"execution":{"iopub.status.busy":"2024-09-25T12:31:46.672137Z","iopub.execute_input":"2024-09-25T12:31:46.672536Z","iopub.status.idle":"2024-09-25T12:31:46.680548Z","shell.execute_reply.started":"2024-09-25T12:31:46.672494Z","shell.execute_reply":"2024-09-25T12:31:46.679636Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def test_step(model, dataloader, loss_fn):\n    model.eval()\n    \n    test_loss, test_acc = 0, 0\n    total_samples = 0\n    \n    with torch.inference_mode():\n        for batch, (X, y) in enumerate(dataloader):\n            X, y = X.to(device), y.to(device)\n\n            test_pred_logits = model(X)\n            loss = loss_fn(test_pred_logits, y)  # Pass directly without squeezing\n            test_loss += loss.item()\n            \n            # Use torch.max for predicted labels\n            _, test_pred_labels = torch.max(test_pred_logits, 1)  # Get predicted classes\n            test_acc += (test_pred_labels == y).sum().item()\n            total_samples += y.size(0)\n\n        test_loss /= len(dataloader)\n        test_acc /= total_samples  # Calculate accuracy as a fraction of total samples\n        return test_loss, test_acc\n","metadata":{"execution":{"iopub.status.busy":"2024-09-25T12:31:47.149442Z","iopub.execute_input":"2024-09-25T12:31:47.149806Z","iopub.status.idle":"2024-09-25T12:31:47.156866Z","shell.execute_reply.started":"2024-09-25T12:31:47.149769Z","shell.execute_reply":"2024-09-25T12:31:47.155951Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train(model, \n          train_dataloader, \n          test_dataloader, \n          optimizer, \n          loss_fn, \n          epochs):\n    \n    \"\"\"Take in various of parameters\n    which required for training and testing steps\n    \"\"\"\n    results= {\"train_loss\": [],\n             \"train_acc\": [],\n             \"test_loss\": [],\n             \"test_acc\": []}\n    \n    for epoch in tqdm(range(epochs)):\n        train_loss, train_acc= train_step(model, \n                                          dataloader=train_dataloader, \n                                          loss_fn=loss_fn, \n                                          optimizer=optimizer)\n        test_loss, test_acc = test_step(model=model, \n                                       dataloader=test_dataloader,\n                                       loss_fn=loss_fn)\n        \n        print(\n            f\"Epoch: {epoch+1} | \"\n            f\"train_loss: {train_loss:.4f} | \"\n            f\"train_acc: {train_acc:.4f} | \"\n            f\"test_loss: {test_loss:.4f} | \"\n            f\"test_acc: {test_acc:.4f}\"\n        )\n        # Ensure all data is moved to CPU and converted to float for storage\n        results[\"train_loss\"].append(train_loss.item() if isinstance(train_loss, torch.Tensor) else train_loss)\n        results[\"train_acc\"].append(train_acc.item() if isinstance(train_acc, torch.Tensor) else train_acc)\n        results[\"test_loss\"].append(test_loss.item() if isinstance(test_loss, torch.Tensor) else test_loss)\n        results[\"test_acc\"].append(test_acc.item() if isinstance(test_acc, torch.Tensor) else test_acc)\n\n    # 6. Return the filled results at the end of the epochs\n    return results","metadata":{"execution":{"iopub.status.busy":"2024-09-25T12:31:47.687009Z","iopub.execute_input":"2024-09-25T12:31:47.687389Z","iopub.status.idle":"2024-09-25T12:31:47.696781Z","shell.execute_reply.started":"2024-09-25T12:31:47.687349Z","shell.execute_reply":"2024-09-25T12:31:47.695844Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# set loss and optimizer\nloss_fn = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(params=model_0.parameters(), lr=0.001)","metadata":{"execution":{"iopub.status.busy":"2024-09-25T12:38:22.664998Z","iopub.execute_input":"2024-09-25T12:38:22.665463Z","iopub.status.idle":"2024-09-25T12:38:22.670723Z","shell.execute_reply.started":"2024-09-25T12:38:22.665402Z","shell.execute_reply":"2024-09-25T12:38:22.669787Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 5- Firing our model.....","metadata":{}},{"cell_type":"code","source":"from timeit import default_timer as timer\nstart_time = timer()\ntorch.manual_seed(42)\nmodel_0_results = train(model=model_0, \n                        train_dataloader= train_dataloader, \n                        test_dataloader=test_dataloader, \n                        optimizer=optimizer,\n                       loss_fn=loss_fn, \n                       epochs=10)\nend_time =timer()\nprint(f\"Total training time: {end_time-start_time:.3f} seconds\")\n","metadata":{"execution":{"iopub.status.busy":"2024-09-25T12:31:57.380544Z","iopub.execute_input":"2024-09-25T12:31:57.381303Z","iopub.status.idle":"2024-09-25T12:37:08.166824Z","shell.execute_reply.started":"2024-09-25T12:31:57.381264Z","shell.execute_reply":"2024-09-25T12:37:08.165368Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 6- plot loss and accuracy to see what's happening","metadata":{}},{"cell_type":"code","source":"def plot_loss_curves(results):\n    \"\"\"Plots training curves of a results dictionary.\n\n    Args:\n        results (dict): dictionary containing list of values, e.g.\n            {\"train_loss\": [...],\n             \"train_acc\": [...],\n             \"test_loss\": [...],\n             \"test_acc\": [...]}\n    \"\"\"\n    \n    # Get the loss values of the results dictionary (training and test)\n    loss = results['train_loss']\n    test_loss = results['test_loss']\n\n    # Get the accuracy values of the results dictionary (training and test)\n    accuracy = results['train_acc']\n    test_accuracy = results['test_acc']\n\n    # Figure out how many epochs there were\n    epochs = range(len(results['train_loss']))\n\n    # Setup a plot \n    plt.figure(figsize=(15, 7))\n\n    # Plot loss\n    plt.subplot(1, 2, 1)\n    plt.plot(epochs, loss, label='train_loss')\n    plt.plot(epochs, test_loss, label='test_loss')\n    plt.title('Loss')\n    plt.xlabel('Epochs')\n    plt.legend()\n\n    # Plot accuracy\n    plt.subplot(1, 2, 2)\n    plt.plot(epochs, accuracy, label='train_accuracy')\n    plt.plot(epochs, test_accuracy, label='test_accuracy')\n    plt.title('Accuracy')\n    plt.xlabel('Epochs')\n    plt.legend();","metadata":{"execution":{"iopub.status.busy":"2024-09-25T11:50:48.607226Z","iopub.execute_input":"2024-09-25T11:50:48.607658Z","iopub.status.idle":"2024-09-25T11:50:48.617666Z","shell.execute_reply.started":"2024-09-25T11:50:48.607615Z","shell.execute_reply":"2024-09-25T11:50:48.616505Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_loss_curves(model_0_results)","metadata":{"execution":{"iopub.status.busy":"2024-09-25T11:50:48.619010Z","iopub.execute_input":"2024-09-25T11:50:48.619347Z","iopub.status.idle":"2024-09-25T11:50:49.238323Z","shell.execute_reply.started":"2024-09-25T11:50:48.619304Z","shell.execute_reply":"2024-09-25T11:50:49.237387Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 7- Chosse random custom image and make some predictions","metadata":{}},{"cell_type":"code","source":"aacustom_image_path = test_list[2]\ncustom_image = torchvision.io.read_image(str(custom_image_path)).type(torch.float32)\n\n# Divide the image pixel values by 255 to get them between [0, 1]\ncustom_image = custom_image / 255. \n\n# Print out image data\nprint(f\"Custom image tensor:\\n{custom_image}\\n\")\nprint(f\"Custom image shape: {custom_image.shape}\\n\")\nprint(f\"Custom image dtype: {custom_image.dtype}\")","metadata":{"execution":{"iopub.status.busy":"2024-09-25T13:19:37.008581Z","iopub.execute_input":"2024-09-25T13:19:37.008971Z","iopub.status.idle":"2024-09-25T13:19:37.025256Z","shell.execute_reply.started":"2024-09-25T13:19:37.008933Z","shell.execute_reply":"2024-09-25T13:19:37.024406Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"custom_image_transform = transforms.Compose([\n    transforms.Resize(size=(224,224)),\n])\n\n# Transform target image\ncustom_image_transformed = custom_image_transform(custom_image)\n\n# Print out original shape and new shape\nprint(f\"Original shape: {custom_image.shape}\")\nprint(f\"New shape: {custom_image_transformed.shape}\")","metadata":{"execution":{"iopub.status.busy":"2024-09-24T22:01:50.902240Z","iopub.execute_input":"2024-09-24T22:01:50.902631Z","iopub.status.idle":"2024-09-24T22:01:50.911406Z","shell.execute_reply.started":"2024-09-24T22:01:50.902593Z","shell.execute_reply":"2024-09-24T22:01:50.910442Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_0.eval()\nwith torch.inference_mode():\n    # Add an extra dimension to image\n    custom_image_transformed_with_batch_size = custom_image_transformed.unsqueeze(dim=0)\n    \n    # Print out different shapes\n    print(f\"Custom image transformed shape: {custom_image_transformed.shape}\")\n    print(f\"Unsqueezed custom image shape: {custom_image_transformed_with_batch_size.shape}\")\n    \n    # Make a prediction on image with an extra dimension\n    custom_image_pred = model_0(custom_image_transformed.unsqueeze(dim=0).to(device))","metadata":{"execution":{"iopub.status.busy":"2024-09-24T22:01:51.264510Z","iopub.execute_input":"2024-09-24T22:01:51.264921Z","iopub.status.idle":"2024-09-24T22:01:51.272900Z","shell.execute_reply.started":"2024-09-24T22:01:51.264885Z","shell.execute_reply":"2024-09-24T22:01:51.271889Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"custom_image_pred","metadata":{"execution":{"iopub.status.busy":"2024-09-24T22:01:51.582123Z","iopub.execute_input":"2024-09-24T22:01:51.582927Z","iopub.status.idle":"2024-09-24T22:01:51.590798Z","shell.execute_reply.started":"2024-09-24T22:01:51.582880Z","shell.execute_reply":"2024-09-24T22:01:51.589840Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# Print out prediction logits\nprint(f\"Prediction logits: {custom_image_pred}\")\n\n# Convert logits -> prediction probabilities (using torch.softmax() for multi-class classification)\ncustom_image_pred_probs = torch.softmax(custom_image_pred, dim=1)\nprint(f\"Prediction probabilities: {custom_image_pred_probs}\")\n\n# Convert prediction probabilities -> prediction labels\ncustom_image_pred_label = torch.argmax(custom_image_pred_probs, dim=1)\nprint(f\"Prediction label: {custom_image_pred_label}\")","metadata":{"execution":{"iopub.status.busy":"2024-09-24T22:01:51.887966Z","iopub.execute_input":"2024-09-24T22:01:51.888280Z","iopub.status.idle":"2024-09-24T22:01:51.896885Z","shell.execute_reply.started":"2024-09-24T22:01:51.888249Z","shell.execute_reply":"2024-09-24T22:01:51.895984Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"custom_image_pred_class = class_names[custom_image_pred_label.cpu()] # put pred label to CPU, otherwise will error\nplt.imshow(custom_image.permute(1, 2, 0)) # need to permute image dimensions from CHW -> HWC otherwise matplotlib will error\nplt.title(f\"Image label: {custom_image_pred_class}\")\nplt.axis(False);","metadata":{"execution":{"iopub.status.busy":"2024-09-24T22:01:52.188056Z","iopub.execute_input":"2024-09-24T22:01:52.189078Z","iopub.status.idle":"2024-09-24T22:01:52.493504Z","shell.execute_reply.started":"2024-09-24T22:01:52.189039Z","shell.execute_reply":"2024-09-24T22:01:52.492596Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# first model did very bad in fitting our data, so i will make some changes and use pre trained model and run again and see how it works","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torchvision.transforms as transforms\nimport torchvision.models as models\nfrom torchvision import datasets\nfrom torch.utils.data import DataLoader\n\nclass TransferLearningModel(nn.Module):\n    def __init__(self, output_shape):\n        super().__init__()\n        # Load a pre-trained ResNet model\n        self.model = models.resnet18(pretrained=True)\n        # Freeze the convolutional base\n        for param in self.model.parameters():\n            param.requires_grad = False\n        \n        # Replace the final layer\n        num_features = self.model.fc.in_features\n        self.model.fc = nn.Sequential(\n            nn.Linear(num_features, output_shape)\n        )\n    \n    def forward(self, x):\n        return self.model(x)\n\n# Data Augmentation and Data Loaders\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),  # Resize images to 224x224 for ResNet\n    transforms.RandomHorizontalFlip(),  # Data augmentation\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),  # Normalize\n])\n\ntrain_dataset = datasets.ImageFolder(train_dir, transform=transform)\ntrain_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)\n\nvalid_dataset = datasets.ImageFolder(val_dir, transform=transform)\nvalid_loader = DataLoader(valid_dataset, batch_size=32, shuffle=False)\n\n# Model, Loss Function, Optimizer\nmodel = TransferLearningModel(output_shape=2)\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n\n# Training Loop (simplified)\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nmodel.to(device)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-25T12:51:46.309826Z","iopub.execute_input":"2024-09-25T12:51:46.310249Z","iopub.status.idle":"2024-09-25T12:51:47.079240Z","shell.execute_reply.started":"2024-09-25T12:51:46.310209Z","shell.execute_reply":"2024-09-25T12:51:47.078250Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from timeit import default_timer as timer\nstart_time = timer()\ntorch.manual_seed(42)\nmodel_0_results = train(model=model, \n                        train_dataloader= train_loader, \n                        test_dataloader=valid_loader, \n                        optimizer=optimizer,\n                       loss_fn=criterion, \n                       epochs=10)\nend_time =timer()\nprint(f\"Total training time: {end_time-start_time:.3f} seconds\")\n","metadata":{"execution":{"iopub.status.busy":"2024-09-25T13:01:25.977971Z","iopub.execute_input":"2024-09-25T13:01:25.978377Z","iopub.status.idle":"2024-09-25T13:17:26.082387Z","shell.execute_reply.started":"2024-09-25T13:01:25.978335Z","shell.execute_reply":"2024-09-25T13:17:26.081300Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# iam going to repeat steps above ","metadata":{}},{"cell_type":"code","source":"custom_image_path = test_list[2]\ncustom_image = torchvision.io.read_image(str(custom_image_path)).type(torch.float32)\n\n# Divide the image pixel values by 255 to get them between [0, 1]\ncustom_image = custom_image / 255. \n\n# Print out image data\nprint(f\"Custom image tensor:\\n{custom_image}\\n\")\nprint(f\"Custom image shape: {custom_image.shape}\\n\")\nprint(f\"Custom image dtype: {custom_image.dtype}\")","metadata":{"execution":{"iopub.status.busy":"2024-09-25T13:21:12.344687Z","iopub.execute_input":"2024-09-25T13:21:12.345593Z","iopub.status.idle":"2024-09-25T13:21:12.358448Z","shell.execute_reply.started":"2024-09-25T13:21:12.345528Z","shell.execute_reply":"2024-09-25T13:21:12.357312Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"custom_image_transform = transforms.Compose([\n    transforms.Resize(size=(224,224)),\n])\n\n# Transform target image\ncustom_image_transformed = custom_image_transform(custom_image)\n\n# Print out original shape and new shape\nprint(f\"Original shape: {custom_image.shape}\")\nprint(f\"New shape: {custom_image_transformed.shape}\")","metadata":{"execution":{"iopub.status.busy":"2024-09-25T13:22:48.298695Z","iopub.execute_input":"2024-09-25T13:22:48.299389Z","iopub.status.idle":"2024-09-25T13:22:48.315042Z","shell.execute_reply.started":"2024-09-25T13:22:48.299342Z","shell.execute_reply":"2024-09-25T13:22:48.314095Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.eval()\nwith torch.inference_mode():\n    # Add an extra dimension to image\n    custom_image_transformed_with_batch_size = custom_image_transformed.unsqueeze(dim=0)\n    \n    # Print out different shapes\n    print(f\"Custom image transformed shape: {custom_image_transformed.shape}\")\n    print(f\"Unsqueezed custom image shape: {custom_image_transformed_with_batch_size.shape}\")\n    \n    # Make a prediction on image with an extra dimension\n    custom_image_pred = model(custom_image_transformed.unsqueeze(dim=0).to(device))","metadata":{"execution":{"iopub.status.busy":"2024-09-25T13:23:18.635021Z","iopub.execute_input":"2024-09-25T13:23:18.635667Z","iopub.status.idle":"2024-09-25T13:23:18.670022Z","shell.execute_reply.started":"2024-09-25T13:23:18.635624Z","shell.execute_reply":"2024-09-25T13:23:18.669076Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# Print out prediction logits\nprint(f\"Prediction logits: {custom_image_pred}\")\n\n# Convert logits -> prediction probabilities (using torch.softmax() for multi-class classification)\ncustom_image_pred_probs = torch.softmax(custom_image_pred, dim=1)\nprint(f\"Prediction probabilities: {custom_image_pred_probs}\")\n\n# Convert prediction probabilities -> prediction labels\ncustom_image_pred_label = torch.argmax(custom_image_pred_probs, dim=1)\nprint(f\"Prediction label: {custom_image_pred_label}\")","metadata":{"execution":{"iopub.status.busy":"2024-09-25T13:23:40.767430Z","iopub.execute_input":"2024-09-25T13:23:40.768329Z","iopub.status.idle":"2024-09-25T13:23:40.787530Z","shell.execute_reply.started":"2024-09-25T13:23:40.768275Z","shell.execute_reply":"2024-09-25T13:23:40.786690Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"custom_image_pred_class = class_names[custom_image_pred_label.cpu()] # put pred label to CPU, otherwise will error\nplt.imshow(custom_image.permute(1, 2, 0)) # need to permute image dimensions from CHW -> HWC otherwise matplotlib will error\nplt.title(f\"Image label: {custom_image_pred_class}\")\nplt.axis(False);","metadata":{"execution":{"iopub.status.busy":"2024-09-25T13:23:52.409420Z","iopub.execute_input":"2024-09-25T13:23:52.409848Z","iopub.status.idle":"2024-09-25T13:23:52.730360Z","shell.execute_reply.started":"2024-09-25T13:23:52.409808Z","shell.execute_reply":"2024-09-25T13:23:52.729406Z"},"trusted":true},"execution_count":null,"outputs":[]}]}