{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# Prototyping Models" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Let's say you have a novel idea for a model architecture and you want to run ablation study on it with `ablator`. Ablator simplifies the process of prototyping your model, allowing you to swiftly construct and evaluate your innovative concept. Once a prototype runs smoothly, you can switch to parallel ablation study, which trains and runs HPO of different trials, with minimal code change for hyperparameter optimization.\n", "\n", "This chapter covers prototyping a model using Ablator, training the model on the popular **Fashion-mnist** dataset.\n", "\n", "There are 3 main steps to run a prototype experiment in ablator:\n", "\n", "- Configure the prototype experiment.\n", "\n", "- Create model wrapper that defines boiler-plate code for training and evaluating models.\n", "\n", "- Create the trainer and launch the experiment." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Let us first import all necessary dependencies:" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "```python\n", "from ablator import ModelConfig, OptimizerConfig, TrainConfig, RunConfig\n", "from ablator import ModelWrapper, ProtoTrainer, configclass\n", "\n", "import torch\n", "import torch.nn as nn\n", "from torch.utils.data import DataLoader, Dataset\n", "import torchvision\n", "import torchvision.transforms as transforms\n", "\n", "from sklearn.metrics import f1_score, accuracy_score\n", "\n", "import shutil\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Launch the prototype experiment" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Configure the experiment" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "We will follow exactly the same steps as in the previous tutorial on [Configuration Basics](./Configuration-Basics.ipynb) to configure the experiment:\n", "\n", "Here's a summary of how we will configure it:\n", "\n", "- **Model Configuration**: dimensions for the layers of the model.\n", "\n", "- **Optimizer Configuration**: adam (lr = 0.001).\n", "\n", "- **Train Configuration**: `batch_size` = 32, `epochs` = 20, random weights initialization is set as true.\n", "\n", "- **Running Configuration**: CPU as hardware and a random seed for the experiment." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Configure the model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### Model configuration\n", "\n", "For the model configuration, we defines hyperparameters `input_size`, `hidden_size`, and `num_classes` as integer config attributes." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```python\n", "@configclass\n", "class CustomModelConfig(ModelConfig):\n", " input_size :int\n", " hidden_size :int \n", " num_classes :int\n", "\n", "model_config = CustomModelConfig(\n", " input_size = 28*28, \n", " hidden_size = 256, \n", " num_classes = 10\n", " )\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since the hyperparameters are defined using primitive data type integer (aka Stateful), we must provide concrete values when initializing the `model_config` object. " ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "##### Creating Pytorch Model " ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Model Architecture (Simple Neural Network with Linear Layers):\n", "\n", "Linear_1_(28*28, 256) -> ReLU -> Linear_2_(256, 256) -> ReLU -> Linear_3_(256, 10). (where; ReLU is an Activation function) \n", "\n", "Note that here we depart from the Configuration Basics tutorial, we construct our model as a 2-level module:\n", "\n", "- `FashionMNISTModel` defines the model architecture (your novel idea), this is where we use the model config attributes to construct the model.\n", "\n", "- `MyModel` includes the main model architecture as a sub-module, adds a loss function, performs forward computation, and returns the predicted labels and loss during model training and evaluation. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```python\n", "class FashionMNISTModel(nn.Module):\n", " def __init__(self, config: CustomModelConfig):\n", " super(FashionMNISTModel, self).__init__()\n", "\n", " input_size = config.input_size \n", " hidden_size = config.hidden_size\n", " num_classes = config.num_classes\n", "\n", " self.fc1 = nn.Linear(input_size, hidden_size)\n", " self.relu1 = nn.ReLU()\n", " self.fc2 = nn.Linear(hidden_size, hidden_size)\n", " self.relu2 = nn.ReLU()\n", " self.fc3 = nn.Linear(hidden_size, num_classes)\n", " \n", " def forward(self, x):\n", " x = x.view(x.size(0), -1) \n", " x = self.fc1(x)\n", " x = self.relu1(x)\n", " x = self.fc2(x)\n", " x = self.relu2(x)\n", " x = self.fc3(x)\n", " return x\n", "\n", "class MyModel(nn.Module):\n", " def __init__(self, config: CustomModelConfig) -> None:\n", " super().__init__()\n", " \n", " self.model = FashionMNISTModel(config)\n", " self.loss = nn.CrossEntropyLoss()\n", "\n", " def forward(self, x, labels=None):\n", " out = self.model(x)\n", " loss = None\n", "\n", " if labels is not None:\n", " loss = self.loss(out, labels)\n", " labels = labels.reshape(-1, 1)\n", "\n", " out = out.argmax(dim=-1)\n", " out = out.reshape(-1, 1)\n", "\n", " return {\"y_pred\": out, \"y_true\": labels}, loss\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Configure the training process" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "```python\n", "optimizer_config = OptimizerConfig(\n", " name=\"adam\", \n", " arguments={\"lr\": 0.001}\n", ")\n", "\n", "train_config = TrainConfig(\n", " dataset=\"Fashion-mnist\",\n", " batch_size=32,\n", " epochs=20,\n", " optimizer_config=optimizer_config,\n", " scheduler_config=None,\n", " rand_weights_init = True\n", ")\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Configure the running configuration" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```python\n", "@configclass\n", "class CustomRunConfig(RunConfig):\n", " model_config: CustomModelConfig\n", "\n", "run_config = CustomRunConfig(\n", " train_config=train_config,\n", " model_config=model_config,\n", " metrics_n_batches = 800,\n", " experiment_dir = \"/tmp/experiments\",\n", " device=\"cuda\",\n", " amp=False,\n", " random_seed = 42\n", ")\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "