CoolFace
Apppublic

JimmyChin1998/Pytorch-Learning-File

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
PyTorch_Going_Modular.ipynb574 linesDownload Raw Back to root
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