{"cells":[{"metadata":{},"cell_type":"markdown","source":"<center><p style=\"font-size: 35px;float:center\">🏃🏽‍♂️ Implementing the RepVGG 🏃🏽‍♀️</p></center>"},{"metadata":{},"cell_type":"markdown","source":"<p style=\"font-size: 20px; margin-right:50px\">Okay, so let's get this right. Recently a paper popped up in <a href=\"paperswithcode.com\">paperswithcode's website</a>.<br> It talked about <a href=\"https://paperswithcode.com/paper/repvgg-making-vgg-style-convnets-great-again\">Making VGG-style ConvNets Great Again</a>.<br><br>\nNo, I am not kidding that is literally the title of that paper.<br>\nI kind of smirked when I read the title. Dude, it's high time we start replacing <b>ConvNets</b> with <b>Pretrained Transformer Models</b> because well they do an equally or sometimes even better of a job when it comes to <b>Image Classification</b>.<br> <br>\nYet here it seems like that Transformers might be met with some sort of competition? Maybe they don't?<br> No one knows let's jump into this.\n<br><br>\nThe Purpose of this Notebook is to help everyone use the RepVGG Model.</p>"},{"metadata":{},"cell_type":"markdown","source":"<p style=\"font-size: 27px; margin-right:50px\">Also, if you already upvoted the Notebook without even going through it: We are automatically Best Friends. 😋</p>"},{"metadata":{},"cell_type":"markdown","source":"# Importing Libraries\n<p style=\"font-size: 20px; margin-right:50px\"> Importing all the necessary libraries.</p>"},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"# Cloning the Github Repo for the Model.\n!git clone https://github.com/DingXiaoH/RepVGG.git","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Some Native Python Tools.\nimport glob\nfrom itertools import chain\nimport os\nimport random\n\n# These ones are for dealing with our Data.\nimport matplotlib.pyplot as plt\nimport pandas as pd\nfrom PIL import Image\nimport numpy as np\n\n# PyTorch is like that one boss who actually does everything he can to help you.\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom torch.optim.lr_scheduler import StepLR\nfrom torch.utils.data import DataLoader, Dataset\nfrom torchvision import datasets, transforms\n\n# Keeping Time in check.\nfrom tqdm.notebook import tqdm\n\n# Tools for Preprocessing and stuff.\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import OrdinalEncoder\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Heading to the directory with model files.\ncd ./RepVGG","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# For Grabbing the RepVGG Model.\nfrom repvgg import repvgg_model_convert, create_RepVGG_B2","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Heading back to where the other data is stored.\ncd ../","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Setting up the Hyperparameters\n\nbatch_size = 64\nepochs = 15\nlr = 3e-4\ngamma= 0.7\nseed = 42","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h1 style=\"font-size: 27px; margin-right:50px\">Seeding Everything</h1>\n<p style=\"font-size: 20px; margin-right:50px\">Seeding makes things reproduceable so let's go!</p>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Definign a function to seed everything.\ndef seed_it(seed):\n    random.seed(seed)\n    os.environ[\"PYTHONSEED\"] = str(seed)\n    np.random.seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.cuda.manual_seed_all(seed)\n    torch.backends.cudnn.deterministic = True\n    \n# Running the Function.\nseed_it(seed)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Moving stuff to the GPU.\ndevice = \"cuda\"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h1 style=\"font-size: 27px; margin-right:50px\">Preprocessing</h1>\n<p style=\"font-size: 20px; margin-right:50px\">Here, we will make a list of all images' paths and put them in a tuple along with thier labels. Also, let's gather all those tuples and put them into a list.</p>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Defining the paths to files.\ntrainimages = \"../input/cassava-leaf-disease-classification/train_images\"\n\ntraindf = pd.read_csv(\"../input/cassava-leaf-disease-classification/train.csv\")\n\ntrain_list = []\n# Converting the Image IDs to their paths.\nfor i in traindf.index:\n    \n    a = traindf[\"image_id\"].loc[i]\n    \n    b = trainimages + \"/\" + a\n    \n    train_list.append((b, traindf['label'].loc[i]))\n\n# Taking a look.\ntrain_list[:3]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Visualizing the Data\n<p style=\"font-size: 20px; margin-right:50px\">Time to take a look at our Data!</p>\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"random_idx = np.random.randint(1, len(train_list), size=16)\nfig, axes = plt.subplots(6,6, figsize=(13,13))\n\nfor idx, ax in enumerate(axes.ravel()):\n    img = Image.open(train_list[idx][0])\n    ax.set_title(train_list[idx][1])\n    ax.imshow(img)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Dataloader\n<p style=\"font-size: 20px; margin-right:50px\">Time to set up a DataLoader with the resources we have.</p>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Splitting the data into training and validation datasets.\ntrain, valid = train_test_split(train_list,\n                                test_size=0.2,\n                                random_state=42)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h1 style=\"font-size: 27px; margin-right:50px\">Transforms</h1>\n<p style=\"font-size: 20px; margin-right:50px\">Producing some transformations for our training and validation datasets.</p>"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_trans = transforms.Compose([\n                transforms.RandomResizedCrop(224),\n                transforms.RandomHorizontalFlip(p=0.3),\n                transforms.ToTensor(),\n                transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                                         std=[0.229, 0.224, 0.225])\n            ])\n\nvalid_trans = transforms.Compose([\n                transforms.ToTensor(),\n                transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                                         std=[0.229, 0.224, 0.225])\n            ])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h1 style=\"font-size: 27px; margin-right:50px\">Dataset Class</h1>\n<p style=\"font-size: 20px; margin-right:50px\">Defining the PyTorch Dataset Class.</p>"},{"metadata":{"trusted":true},"cell_type":"code","source":"class CassavaDataset(Dataset):\n    \n    # Grabbing the transforms presets.\n    def __init__(self, file_list, transform=None):\n        self.file_list = file_list\n        self.transform = transform\n        \n    def __len__(self):\n        self.filelength = len(self.file_list)\n        return self.filelength\n    \n    def __getitem__(self, idx):\n        \n        img_path = self.file_list[idx][0]\n        img = Image.open(img_path).convert(\"RGB\")\n        img_transformed = self.transform(img)\n        \n        # The second item in the tuple is the label.\n        label = self.file_list[idx][1]\n        \n        return img_transformed, label","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<p style=\"font-size: 20px; margin-right:50px\">Finally collecting everthing into a two DataLoaders. One for the training data and another for the valid data.</p>\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_data = CassavaDataset(train, transform = train_trans)\nvalid_data = CassavaDataset(valid, transform = valid_trans)\n\ntrain_loader = DataLoader(dataset = train_data, batch_size = batch_size, shuffle = True)\nvalid_loader = DataLoader(dataset = valid_data, batch_size = batch_size, shuffle = True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model\n<p style=\"font-size: 20px; margin-right:50px\">Grabbing the Model.</p>"},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"model = create_RepVGG_B2(deploy=False).to(device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Defining some presets.\n\ncriterion = nn.CrossEntropyLoss()\n\noptimizer = optim.Adam(model.parameters(), lr = lr)\n\nscheduler = StepLR(optimizer, step_size=1, gamma=gamma)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training the Model\n<p style=\"font-size: 20px; margin-right:50px\">Let's use everything that we have done above to finally train the model for 20 Epochs!</p>"},{"metadata":{"trusted":true},"cell_type":"code","source":"for epoch in range(epochs):\n    epoch_loss = 0.0\n    epoch_accuracy = 0.0\n    \n    for data, label in tqdm(train_loader):\n        data = data.to(device)\n        label = label.to(device)\n        \n        output = model(data)\n        \n        label = torch.nn.functional.one_hot(label, num_classes = 5)\n        label = label.squeeze_()\n        label = torch.argmax(label, axis=1)\n        \n        label = label.type_as(output)\n        \n        loss = criterion(output, label.long())\n        \n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n        \n        acc = (output.argmax(dim=1) == label).float().mean()\n        epoch_accuracy += acc / len(train_loader)\n        epoch_loss += loss / len(train_loader)\n\n        \n    with torch.no_grad():\n        epoch_val_accuracy = 0\n        epoch_val_loss = 0        \n        \n        for data, label in valid_loader:\n            data = data.to(device)\n            \n            label = label.to(device)\n            #label = label.squeeze_()\n            label = label.type_as(output)\n            \n            val_output = model(data)\n            val_loss = criterion(val_output, label.long())\n            \n            accc = (val_output.argmax(dim = 1) == label).float().mean()\n            epoch_val_accuracy += acc / len(valid_loader)\n            epoch_val_loss += val_loss / len(valid_loader)\n\n    print(\n        f\"Epoch: {epoch+1} - loss: {epoch_loss:.4f} - acc : {epoch_accuracy:.4f} - val_loss : {epoch_val_loss:.4f} - val_acc: {epoch_val_accuracy: .4f}\\n\"\n    )","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<img src=\"https://raw.githubusercontent.com/DingXiaoH/RepVGG/main/arch.PNG\" style=\"width:30%;float:right;display:inline-block\">\n<h1 style=\"font-size: 27px; margin-right:50px\">Briefing about this Model</h1>\n\n\n<p style=\"font-size: 20px; margin-right:100px\">A simple but powerful architecture of convolutional neural network, which has a VGG-like inference-time body composed of nothing but a stack of 3x3 convolution and ReLU, while the training-time model has a multi-branch topology. Such decoupling of the training-time and inference-time architecture is realized by a structural re-parameterization technique so that the model is named RepVGG.\n<br><br>\nFor any further reading: <a href=\"https://github.com/DingXiaoH/RepVGG\">Check out the researcher's Repo!</a></p>"}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}