JimmyChin1998/Pytorch-Learning-File
0
1{2 "cells": [3 {4 "cell_type": "code",5 "execution_count": 1,6 "id": "d6112ee2-1800-4086-b7c4-cc89ff45a06a",7 "metadata": {},8 "outputs": [9 {10 "name": "stdout",11 "output_type": "stream",12 "text": [13 "data\\pizza_steak_sushi directory exists.\n",14 "Downloading pizza, steak, sushi data...\n",15 "Unzipping pizza, steak, sushi data...\n"16 ]17 }18 ],19 "source": [20 "import os\n",21 "import requests\n",22 "import zipfile\n",23 "from pathlib import Path\n",24 "\n",25 "# Setup path to data folder\n",26 "data_path = Path(\"data/\")\n",27 "image_path = data_path / \"pizza_steak_sushi\"\n",28 "\n",29 "# If the image folder doesn't exist, download it and prepare it... \n",30 "if image_path.is_dir():\n",31 " print(f\"{image_path} directory exists.\")\n",32 "else:\n",33 " print(f\"Did not find {image_path} directory, creating one...\")\n",34 " image_path.mkdir(parents=True, exist_ok=True)\n",35 "\n",36 "# Download pizza, steak, sushi data\n",37 "with open(data_path / \"pizza_steak_sushi.zip\", \"wb\") as f:\n",38 " request = requests.get(\"https://github.com/mrdbourke/pytorch-deep-learning/raw/main/data/pizza_steak_sushi.zip\")\n",39 " print(\"Downloading pizza, steak, sushi data...\")\n",40 " f.write(request.content)\n",41 "\n",42 "# Unzip pizza, steak, sushi data\n",43 "with zipfile.ZipFile(data_path / \"pizza_steak_sushi.zip\", \"r\") as zip_ref:\n",44 " print(\"Unzipping pizza, steak, sushi data...\") \n",45 " zip_ref.extractall(image_path)\n",46 "\n",47 "# Remove zip file\n",48 "os.remove(data_path / \"pizza_steak_sushi.zip\")"49 ]50 },51 {52 "cell_type": "code",53 "execution_count": 2,54 "id": "4ff2a492-fd34-41e9-9a82-ab63ff7d3215",55 "metadata": {},56 "outputs": [57 {58 "name": "stdout",59 "output_type": "stream",60 "text": [61 "Writing going_modular/data_setup.py\n"62 ]63 }64 ],65 "source": [66 "%%writefile going_modular/data_setup.py\n",67 "\"\"\"\n",68 "Contains functionality for creating PyTorch DataLoaders for \n",69 "image classification data.\n",70 "\"\"\"\n",71 "import os\n",72 "\n",73 "from torchvision import datasets, transforms\n",74 "from torch.utils.data import DataLoader\n",75 "\n",76 "NUM_WORKERS = os.cpu_count()\n",77 "\n",78 "def create_dataloaders(\n",79 " train_dir: str, \n",80 " test_dir: str, \n",81 " transform: transforms.Compose, \n",82 " batch_size: int, \n",83 " num_workers: int=NUM_WORKERS\n",84 "):\n",85 " \"\"\"Creates training and testing DataLoaders.\n",86 "\n",87 " Takes in a training directory and testing directory path and turns\n",88 " them into PyTorch Datasets and then into PyTorch DataLoaders.\n",89 "\n",90 " Args:\n",91 " train_dir: Path to training directory.\n",92 " test_dir: Path to testing directory.\n",93 " transform: torchvision transforms to perform on training and testing data.\n",94 " batch_size: Number of samples per batch in each of the DataLoaders.\n",95 " num_workers: An integer for number of workers per DataLoader.\n",96 "\n",97 " Returns:\n",98 " A tuple of (train_dataloader, test_dataloader, class_names).\n",99 " Where class_names is a list of the target classes.\n",100 " Example usage:\n",101 " train_dataloader, test_dataloader, class_names = \\\n",102 " = create_dataloaders(train_dir=path/to/train_dir,\n",103 " test_dir=path/to/test_dir,\n",104 " transform=some_transform,\n",105 " batch_size=32,\n",106 " num_workers=4)\n",107 " \"\"\"\n",108 " # Use ImageFolder to create dataset(s)\n",109 " train_data = datasets.ImageFolder(train_dir, transform=transform)\n",110 " test_data = datasets.ImageFolder(test_dir, transform=transform)\n",111 "\n",112 " # Get class names\n",113 " class_names = train_data.classes\n",114 "\n",115 " # Turn images into data loaders\n",116 " train_dataloader = DataLoader(\n",117 " train_data,\n",118 " batch_size=batch_size,\n",119 " shuffle=True,\n",120 " num_workers=num_workers,\n",121 " pin_memory=True,\n",122 " )\n",123 " test_dataloader = DataLoader(\n",124 " test_data,\n",125 " batch_size=batch_size,\n",126 " shuffle=False, # don't need to shuffle test data\n",127 " num_workers=num_workers,\n",128 " pin_memory=True,\n",129 " )\n",130 "\n",131 " return train_dataloader, test_dataloader, class_names"132 ]133 },134 {135 "cell_type": "code",136 "execution_count": 3,137 "id": "d8a44d9a-b71f-4835-b1f5-44ba1203d875",138 "metadata": {},139 "outputs": [140 {141 "name": "stdout",142 "output_type": "stream",143 "text": [144 "Writing going_modular/model_builder.py\n"145 ]146 }147 ],148 "source": [149 "%%writefile going_modular/model_builder.py\n",150 "\"\"\"\n",151 "Contains PyTorch model code to instantiate a TinyVGG model.\n",152 "\"\"\"\n",153 "import torch\n",154 "from torch import nn \n",155 "\n",156 "class TinyVGG(nn.Module):\n",157 " \"\"\"Creates the TinyVGG architecture.\n",158 "\n",159 " Replicates the TinyVGG architecture from the CNN explainer website in PyTorch.\n",160 " See the original architecture here: https://poloclub.github.io/cnn-explainer/\n",161 "\n",162 " Args:\n",163 " input_shape: An integer indicating number of input channels.\n",164 " hidden_units: An integer indicating number of hidden units between layers.\n",165 " output_shape: An integer indicating number of output units.\n",166 " \"\"\"\n",167 " def __init__(self, input_shape: int, hidden_units: int, output_shape: int) -> None:\n",168 " super().__init__()\n",169 " self.conv_block_1 = nn.Sequential(\n",170 " nn.Conv2d(in_channels=input_shape, \n",171 " out_channels=hidden_units, \n",172 " kernel_size=3, \n",173 " stride=1, \n",174 " padding=0), \n",175 " nn.ReLU(),\n",176 " nn.Conv2d(in_channels=hidden_units, \n",177 " out_channels=hidden_units,\n",178 " kernel_size=3,\n",179 " stride=1,\n",180 " padding=0),\n",181 " nn.ReLU(),\n",182 " nn.MaxPool2d(kernel_size=2,\n",183 " stride=2)\n",184 " )\n",185 " self.conv_block_2 = nn.Sequential(\n",186 " nn.Conv2d(hidden_units, hidden_units, kernel_size=3, padding=0),\n",187 " nn.ReLU(),\n",188 " nn.Conv2d(hidden_units, hidden_units, kernel_size=3, padding=0),\n",189 " nn.ReLU(),\n",190 " nn.MaxPool2d(2)\n",191 " )\n",192 " self.classifier = nn.Sequential(\n",193 " nn.Flatten(),\n",194 " # Where did this in_features shape come from? \n",195 " # It's because each layer of our network compresses and changes the shape of our inputs data.\n",196 " nn.Linear(in_features=hidden_units*13*13,\n",197 " out_features=output_shape)\n",198 " )\n",199 "\n",200 " def forward(self, x: torch.Tensor):\n",201 " x = self.conv_block_1(x)\n",202 " x = self.conv_block_2(x)\n",203 " x = self.classifier(x)\n",204 " return x\n",205 " # return self.classifier(self.conv_block_2(self.conv_block_1(x))) # <- leverage the benefits of operator fusion"206 ]207 },208 {209 "cell_type": "code",210 "execution_count": 4,211 "id": "53d0f879-f508-4484-8d9b-2bcb97484eff",212 "metadata": {},213 "outputs": [214 {215 "name": "stdout",216 "output_type": "stream",217 "text": [218 "Writing going_modular/engine.py\n"219 ]220 }221 ],222 "source": [223 "%%writefile going_modular/engine.py\n",224 "\"\"\"\n",225 "Contains functions for training and testing a PyTorch model.\n",226 "\"\"\"\n",227 "import torch\n",228 "\n",229 "from tqdm.auto import tqdm\n",230 "from typing import Dict, List, Tuple\n",231 "\n",232 "def train_step(model: torch.nn.Module, \n",233 " dataloader: torch.utils.data.DataLoader, \n",234 " loss_fn: torch.nn.Module, \n",235 " optimizer: torch.optim.Optimizer,\n",236 " device: torch.device) -> Tuple[float, float]:\n",237 " \"\"\"Trains a PyTorch model for a single epoch.\n",238 "\n",239 " Turns a target PyTorch model to training mode and then\n",240 " runs through all of the required training steps (forward\n",241 " pass, loss calculation, optimizer step).\n",242 "\n",243 " Args:\n",244 " model: A PyTorch model to be trained.\n",245 " dataloader: A DataLoader instance for the model to be trained on.\n",246 " loss_fn: A PyTorch loss function to minimize.\n",247 " optimizer: A PyTorch optimizer to help minimize the loss function.\n",248 " device: A target device to compute on (e.g. \"cuda\" or \"cpu\").\n",249 "\n",250 " Returns:\n",251 " A tuple of training loss and training accuracy metrics.\n",252 " In the form (train_loss, train_accuracy). For example:\n",253 "\n",254 " (0.1112, 0.8743)\n",255 " \"\"\"\n",256 " # Put model in train mode\n",257 " model.train()\n",258 "\n",259 " # Setup train loss and train accuracy values\n",260 " train_loss, train_acc = 0, 0\n",261 "\n",262 " # Loop through data loader data batches\n",263 " for batch, (X, y) in enumerate(dataloader):\n",264 " # Send data to target device\n",265 " X, y = X.to(device), y.to(device)\n",266 "\n",267 " # 1. Forward pass\n",268 " y_pred = model(X)\n",269 "\n",270 " # 2. Calculate and accumulate loss\n",271 " loss = loss_fn(y_pred, y)\n",272 " train_loss += loss.item() \n",273 "\n",274 " # 3. Optimizer zero grad\n",275 " optimizer.zero_grad()\n",276 "\n",277 " # 4. Loss backward\n",278 " loss.backward()\n",279 "\n",280 " # 5. Optimizer step\n",281 " optimizer.step()\n",282 "\n",283 " # Calculate and accumulate accuracy metric across all batches\n",284 " y_pred_class = torch.argmax(torch.softmax(y_pred, dim=1), dim=1)\n",285 " train_acc += (y_pred_class == y).sum().item()/len(y_pred)\n",286 "\n",287 " # Adjust metrics to get average loss and accuracy per batch \n",288 " train_loss = train_loss / len(dataloader)\n",289 " train_acc = train_acc / len(dataloader)\n",290 " return train_loss, train_acc\n",291 "\n",292 "def test_step(model: torch.nn.Module, \n",293 " dataloader: torch.utils.data.DataLoader, \n",294 " loss_fn: torch.nn.Module,\n",295 " device: torch.device) -> Tuple[float, float]:\n",296 " \"\"\"Tests a PyTorch model for a single epoch.\n",297 "\n",298 " Turns a target PyTorch model to \"eval\" mode and then performs\n",299 " a forward pass on a testing dataset.\n",300 "\n",301 " Args:\n",302 " model: A PyTorch model to be tested.\n",303 " dataloader: A DataLoader instance for the model to be tested on.\n",304 " loss_fn: A PyTorch loss function to calculate loss on the test data.\n",305 " device: A target device to compute on (e.g. \"cuda\" or \"cpu\").\n",306 "\n",307 " Returns:\n",308 " A tuple of testing loss and testing accuracy metrics.\n",309 " In the form (test_loss, test_accuracy). For example:\n",310 "\n",311 " (0.0223, 0.8985)\n",312 " \"\"\"\n",313 " # Put model in eval mode\n",314 " model.eval() \n",315 "\n",316 " # Setup test loss and test accuracy values\n",317 " test_loss, test_acc = 0, 0\n",318 "\n",319 " # Turn on inference context manager\n",320 " with torch.inference_mode():\n",321 " # Loop through DataLoader batches\n",322 " for batch, (X, y) in enumerate(dataloader):\n",323 " # Send data to target device\n",324 " X, y = X.to(device), y.to(device)\n",325 "\n",326 " # 1. Forward pass\n",327 " test_pred_logits = model(X)\n",328 "\n",329 " # 2. Calculate and accumulate loss\n",330 " loss = loss_fn(test_pred_logits, y)\n",331 " test_loss += loss.item()\n",332 "\n",333 " # Calculate and accumulate accuracy\n",334 " test_pred_labels = test_pred_logits.argmax(dim=1)\n",335 " test_acc += ((test_pred_labels == y).sum().item()/len(test_pred_labels))\n",336 "\n",337 " # Adjust metrics to get average loss and accuracy per batch \n",338 " test_loss = test_loss / len(dataloader)\n",339 " test_acc = test_acc / len(dataloader)\n",340 " return test_loss, test_acc\n",341 "\n",342 "def train(model: torch.nn.Module, \n",343 " train_dataloader: torch.utils.data.DataLoader, \n",344 " test_dataloader: torch.utils.data.DataLoader, \n",345 " optimizer: torch.optim.Optimizer,\n",346 " loss_fn: torch.nn.Module,\n",347 " epochs: int,\n",348 " device: torch.device) -> Dict[str, List]:\n",349 " \"\"\"Trains and tests a PyTorch model.\n",350 "\n",351 " Passes a target PyTorch models through train_step() and test_step()\n",352 " functions for a number of epochs, training and testing the model\n",353 " in the same epoch loop.\n",354 "\n",355 " Calculates, prints and stores evaluation metrics throughout.\n",356 "\n",357 " Args:\n",358 " model: A PyTorch model to be trained and tested.\n",359 " train_dataloader: A DataLoader instance for the model to be trained on.\n",360 " test_dataloader: A DataLoader instance for the model to be tested on.\n",361 " optimizer: A PyTorch optimizer to help minimize the loss function.\n",362 " loss_fn: A PyTorch loss function to calculate loss on both datasets.\n",363 " epochs: An integer indicating how many epochs to train for.\n",364 " device: A target device to compute on (e.g. \"cuda\" or \"cpu\").\n",365 "\n",366 " Returns:\n",367 " A dictionary of training and testing loss as well as training and\n",368 " testing accuracy metrics. Each metric has a value in a list for \n",369 " each epoch.\n",370 " In the form: {train_loss: [...],\n",371 " train_acc: [...],\n",372 " test_loss: [...],\n",373 " test_acc: [...]} \n",374 " For example if training for epochs=2: \n",375 " {train_loss: [2.0616, 1.0537],\n",376 " train_acc: [0.3945, 0.3945],\n",377 " test_loss: [1.2641, 1.5706],\n",378 " test_acc: [0.3400, 0.2973]} \n",379 " \"\"\"\n",380 " # Create empty results dictionary\n",381 " results = {\"train_loss\": [],\n",382 " \"train_acc\": [],\n",383 " \"test_loss\": [],\n",384 " \"test_acc\": []\n",385 " }\n",386 "\n",387 " # Loop through training and testing steps for a number of epochs\n",388 " for epoch in tqdm(range(epochs)):\n",389 " train_loss, train_acc = train_step(model=model,\n",390 " dataloader=train_dataloader,\n",391 " loss_fn=loss_fn,\n",392 " optimizer=optimizer,\n",393 " device=device)\n",394 " test_loss, test_acc = test_step(model=model,\n",395 " dataloader=test_dataloader,\n",396 " loss_fn=loss_fn,\n",397 " device=device)\n",398 "\n",399 " # Print out what's happening\n",400 " print(\n",401 " f\"Epoch: {epoch+1} | \"\n",402 " f\"train_loss: {train_loss:.4f} | \"\n",403 " f\"train_acc: {train_acc:.4f} | \"\n",404 " f\"test_loss: {test_loss:.4f} | \"\n",405 " f\"test_acc: {test_acc:.4f}\"\n",406 " )\n",407 "\n",408 " # Update results dictionary\n",409 " results[\"train_loss\"].append(train_loss)\n",410 " results[\"train_acc\"].append(train_acc)\n",411 " results[\"test_loss\"].append(test_loss)\n",412 " results[\"test_acc\"].append(test_acc)\n",413 "\n",414 " # Return the filled results at the end of the epochs\n",415 " return results"416 ]417 },418 {419 "cell_type": "code",420 "execution_count": 5,421 "id": "fceb758b-a949-4bf3-b11f-68d37563f24a",422 "metadata": {},423 "outputs": [424 {425 "name": "stdout",426 "output_type": "stream",427 "text": [428 "Writing going_modular/utils.py\n"429 ]430 }431 ],432 "source": [433 "%%writefile going_modular/utils.py\n",434 "\"\"\"\n",435 "Contains various utility functions for PyTorch model training and saving.\n",436 "\"\"\"\n",437 "import torch\n",438 "from pathlib import Path\n",439 "\n",440 "def save_model(model: torch.nn.Module,\n",441 " target_dir: str,\n",442 " model_name: str):\n",443 " \"\"\"Saves a PyTorch model to a target directory.\n",444 "\n",445 " Args:\n",446 " model: A target PyTorch model to save.\n",447 " target_dir: A directory for saving the model to.\n",448 " model_name: A filename for the saved model. Should include\n",449 " either \".pth\" or \".pt\" as the file extension.\n",450 "\n",451 " Example usage:\n",452 " save_model(model=model_0,\n",453 " target_dir=\"models\",\n",454 " model_name=\"05_going_modular_tingvgg_model.pth\")\n",455 " \"\"\"\n",456 " # Create target directory\n",457 " target_dir_path = Path(target_dir)\n",458 " target_dir_path.mkdir(parents=True,\n",459 " exist_ok=True)\n",460 "\n",461 " # Create model save path\n",462 " assert model_name.endswith(\".pth\") or model_name.endswith(\".pt\"), \"model_name should end with '.pt' or '.pth'\"\n",463 " model_save_path = target_dir_path / model_name\n",464 "\n",465 " # Save the model state_dict()\n",466 " print(f\"[INFO] Saving model to: {model_save_path}\")\n",467 " torch.save(obj=model.state_dict(),\n",468 " f=model_save_path)"469 ]470 },471 {472 "cell_type": "code",473 "execution_count": null,474 "id": "a8b901f4-8847-4308-af41-afb0de9b8cd6",475 "metadata": {},476 "outputs": [],477 "source": [478 "%%writefile going_modular/train.py\n",479 "\"\"\"\n",480 "Trains a PyTorch image classification model using device-agnostic code.\n",481 "\"\"\"\n",482 "\n",483 "import os\n",484 "import torch\n",485 "import data_setup, engine, model_builder, utils\n",486 "\n",487 "from torchvision import transforms\n",488 "\n",489 "# Setup hyperparameters\n",490 "NUM_EPOCHS = 5\n",491 "BATCH_SIZE = 32\n",492 "HIDDEN_UNITS = 10\n",493 "LEARNING_RATE = 0.001\n",494 "\n",495 "# Setup directories\n",496 "train_dir = \"C:/Users/User/Desktop/Pytorch/pytorchPractice/data/pizza_steak_sushi/train\"\n",497 "test_dir = \"C:/Users/User/Desktop/Pytorch/pytorchPractice/data/pizza_steak_sushi/test\"\n",498 "\n",499 "# Setup target device\n",500 "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",501 "\n",502 "# Create transforms\n",503 "data_transform = transforms.Compose([\n",504 " transforms.Resize((64, 64)),\n",505 " transforms.ToTensor()\n",506 "])\n",507 "\n",508 "# Create DataLoaders with help from data_setup.py\n",509 "train_dataloader, test_dataloader, class_names = data_setup.create_dataloaders(\n",510 " train_dir=train_dir,\n",511 " test_dir=test_dir,\n",512 " transform=data_transform,\n",513 " batch_size=BATCH_SIZE\n",514 ")\n",515 "\n",516 "# Create model with help from model_builder.py\n",517 "model = model_builder.TinyVGG(\n",518 " input_shape=3,\n",519 " hidden_units=HIDDEN_UNITS,\n",520 " output_shape=len(class_names)\n",521 ").to(device)\n",522 "\n",523 "# Set loss and optimizer\n",524 "loss_fn = torch.nn.CrossEntropyLoss()\n",525 "optimizer = torch.optim.Adam(model.parameters(),\n",526 " lr=LEARNING_RATE)\n",527 "\n",528 "# Start training with help from engine.py\n",529 "engine.train(model=model,\n",530 " train_dataloader=train_dataloader,\n",531 " test_dataloader=test_dataloader,\n",532 " loss_fn=loss_fn,\n",533 " optimizer=optimizer,\n",534 " epochs=NUM_EPOCHS,\n",535 " device=device)\n",536 "\n",537 "# Save the model with help from utils.py\n",538 "utils.save_model(model=model,\n",539 " target_dir=\"C:/Users/User/Desktop/Pytorch/pytorchPractice/models\",\n",540 " model_name=\"05_going_modular_script_mode_tinyvgg_model.pth\")"541 ]542 },543 {544 "cell_type": "code",545 "execution_count": null,546 "id": "20f6887d-b3b4-484f-9d74-6823a246d7e3",547 "metadata": {},548 "outputs": [],549 "source": []550 }551 ],552 "metadata": {553 "kernelspec": {554 "display_name": "Python 3 (ipykernel)",555 "language": "python",556 "name": "python3"557 },558 "language_info": {559 "codemirror_mode": {560 "name": "ipython",561 "version": 3562 },563 "file_extension": ".py",564 "mimetype": "text/x-python",565 "name": "python",566 "nbconvert_exporter": "python",567 "pygments_lexer": "ipython3",568 "version": "3.12.7"569 }570 },571 "nbformat": 4,572 "nbformat_minor": 5573}574 