diff --git a/Makefile b/Makefile index dee7067210..0f9035b0fa 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,7 @@ NOTEBOOKS_TO_RUN += src/super_gradients/examples/model_export/models_export_pose NOTEBOOKS_TO_RUN += notebooks/what_are_recipes_and_how_to_use.ipynb NOTEBOOKS_TO_RUN += notebooks/transfer_learning_classification.ipynb NOTEBOOKS_TO_RUN += notebooks/how_to_use_knowledge_distillation_for_classification.ipynb +NOTEBOOKS_TO_RUN += notebooks/detection_how_to_connect_custom_dataset.ipynb NOTEBOOKS_TO_RUN += notebooks/PTQ_and_QAT_for_classification.ipynb NOTEBOOKS_TO_RUN += notebooks/quickstart_segmentation.ipynb NOTEBOOKS_TO_RUN += notebooks/segmentation_connect_custom_dataset.ipynb diff --git a/README.md b/README.md index 7deab15cbe..b1270cf3b9 100644 --- a/README.md +++ b/README.md @@ -224,7 +224,7 @@ model = models.get("model-name", pretrained_weights="pretrained-model-name") ### Object Detection * [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://bit.ly/3SkMohx) [Object Detection Transfer Learning](https://bit.ly/3SkMohx) -* [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://bit.ly/3dqDlg3) [How to Connect Custom Dataset](https://bit.ly/3SkMohx) +* [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Deci-AI/super-gradients/blob/master/notebooks/detection_how_to_connect_custom_dataset.ipynb) [How to Connect Custom Dataset](https://colab.research.google.com/github/Deci-AI/super-gradients/blob/master/notebooks/detection_how_to_connect_custom_dataset.ipynb) ### How to Predict Using Pre-trained Model diff --git a/notebooks/detection_how_to_connect_custom_dataset.ipynb b/notebooks/detection_how_to_connect_custom_dataset.ipynb new file mode 100644 index 0000000000..f95fedf165 --- /dev/null +++ b/notebooks/detection_how_to_connect_custom_dataset.ipynb @@ -0,0 +1,1461 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + }, + "accelerator": "GPU" + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "![SG - Horizontal.png](data:image/png;base64,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)" + ], + "metadata": { + "id": "sh6t_y7KzqBH", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "# SuperGradients Object Detection How to Connect Custom Dataset\n", + "\n", + "In this tutorial we will explore how you can connect your custom object detection dataset to SG.\n", + "\n", + "Since SG trainer is fully compatible with PyTorch data loaders, we will demonstrate how to build one and use it.\n", + "\n", + "The notebook is divided into 5 sections:\n", + "1. Experiment setup\n", + "2. Dataset definition: create a proxy dataset and create a dataloader\n", + "3. Architecture definition: pre-trained YoloX on COCO\n", + "4. Training setup\n", + "5. Training and Evaluation\n" + ], + "metadata": { + "id": "5aISf1B-AGDQ", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "#Install SG" + ], + "metadata": { + "id": "-1nPOPmc1lGp", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "The cell below will install **super_gradients** which will automatically get all its dependencies. Let's import all the installed libraries to make sure they installed succesfully." + ], + "metadata": { + "id": "VAssbjJw7Yt1", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JKce1SM6voVH", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "98939239-1891-4714-efad-4dd90df9766a", + "pycharm": { + "name": "#%%\n", + "is_executing": true + } + }, + "outputs": [], + "source": [ + "! pip install -q super_gradients==3.4.1" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# 1. Experiment setup" + ], + "metadata": { + "id": "njthhNJR1pJm", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "metadata": { + "id": "YPym4wvpOcOJ", + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "We will first initialize our **trainer** which will be in charge of everything, like training, evaluation, saving checkpoints, plotting etc.\n", + "\n", + "The **experiment name** argument is important as every checkpoints, logs and tensorboards to be saved in a directory with the same name. This directory will be created as a sub-directory of **ckpt_root_dir** as follow:\n", + "\n", + "```\n", + "ckpt_root_dir\n", + "|─── experiment_name_1\n", + "│ ckpt_best.pth # Model checkpoint on best epoch\n", + "│ ckpt_latest.pth # Model checkpoint on last epoch\n", + "│ average_model.pth # Model checkpoint averaged over epochs\n", + "│ events.out.tfevents.1659878383... # Tensorflow artifacts of a specific run\n", + "│ log_Aug07_11_52_48.txt # Trainer logs of a specific run\n", + "└─── experiment_name_2\n", + " ...\n", + "```\n", + "In this notebook multi-gpu training is set as `OFF`, for Distributed training multi_gpu can be set as\n", + " `MultiGPUMode.DISTRIBUTED_DATA_PARALLEL` or `MultiGPUMode.DATA_PARALLEL`.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Let's define **ckpt_root_dir** inside the Colab, later we can use it to start TensorBoard and monitor the run." + ], + "metadata": { + "id": "A2PlnTWpimnH", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "source": [ + "from super_gradients.training import Trainer\n", + "\n", + "\n", + "CHECKPOINT_DIR = '/home/notebook_ckpts/'\n", + "trainer = Trainer(experiment_name='transfer_learning_object_detection_yolox', ckpt_root_dir=CHECKPOINT_DIR)" + ], + "metadata": { + "id": "_v1N3kXs3wo1", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 3, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# 2. Dataset definition\n" + ], + "metadata": { + "id": "J9ZaMulSvwhr", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "## 2.A Generate Proxy Dataset" + ], + "metadata": { + "id": "_1TXuJKkKzFJ", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "A proxy dataset generation is available merely to demonstrate an end-to-end training pipeline in this notebook.\n", + "\n", + "The expected data is in COCO format where the labels are class_id X_center Y_center H W .\n" + ], + "metadata": { + "id": "Y7us7VHRig7M", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "source": [ + "from super_gradients.training.utils.ssd_utils import SSDPostPredictCallback, DefaultBoxes\n", + "from super_gradients.training.metrics import DetectionMetrics\n", + "from PIL import Image\n", + "import os\n", + "import numpy as np\n", + "import torch\n", + "\n", + "\n", + "# Anchors\n", + "def dboxes():\n", + " figsize = 96\n", + " feat_size = [6, 3, 2, 1]\n", + " scales = [9, 36, 64, 91, 96]\n", + " aspect_ratios = [[2], [2], [2], [2]]\n", + " return DefaultBoxes(figsize, feat_size, scales, aspect_ratios)\n", + "\n", + "def base_detection_collate_fn(batch):\n", + " \"\"\"\n", + " Simple aggregation function to batched the data\n", + " \"\"\"\n", + "\n", + " images_batch, labels_batch = list(zip(*batch))\n", + " for i, labels in enumerate(labels_batch):\n", + " # ADD TARGET IMAGE INDEX\n", + " labels[:, 0] = i\n", + "\n", + " return torch.stack(images_batch, 0), torch.cat(labels_batch, 0)\n", + "\n", + "# creation of proxy dataset to demonstrate usage\n", + "def generate_proxy_dataset( write_path):\n", + " # Create training files and text\n", + " os.makedirs(os.path.join(write_path, 'images', 'train'), exist_ok=True)\n", + " os.makedirs(os.path.join(write_path, 'images', 'val'), exist_ok=True)\n", + " os.makedirs(os.path.join(write_path, 'labels', 'train'), exist_ok=True)\n", + " os.makedirs(os.path.join(write_path, 'labels', 'val'), exist_ok=True)\n", + " train_fp = open(os.path.join(write_path, 'train.txt'), 'w')\n", + " val_fp = open(os.path.join(write_path, 'val.txt'), 'w')\n", + "\n", + " for n in range(10):\n", + " a = np.random.rand(96, 96, 3) * 255\n", + " im_out = Image.fromarray(a.astype('uint8')).convert('RGB')\n", + " im_string = '%000d.jpg' % n\n", + " im_out.save(os.path.join(write_path, 'images', 'train', im_string))\n", + " im_out.save(os.path.join(write_path, 'images', 'val', im_string))\n", + " train_fp.write((os.path.join(write_path,'images', 'train', im_string)) + '\\n')\n", + " val_fp.write((os.path.join(write_path, 'images', 'val', im_string)) + '\\n')\n", + "\n", + " # Create label files\n", + " train_label_fp = open(os.path.join(write_path, 'labels', 'train', im_string.replace('.jpg','.txt')), 'w')\n", + " val_label_fp = open(os.path.join(write_path, 'labels', 'val', im_string.replace('.jpg','.txt')), 'w')\n", + " for b in range(5):\n", + " cls = np.random.randint(0, 7)\n", + " loc = np.random.uniform(0.25, 0.5)\n", + " train_label_fp.write(f'{cls} {loc - 0.1} {loc + 0.1} {loc - 0.2} {loc + 0.2}' + '\\n')\n", + " val_label_fp.write(f'{cls} {loc - 0.1} {loc + 0.1} {loc - 0.2} {loc + 0.2}' + '\\n')\n" + ], + "metadata": { + "id": "wbdVYnIyjgv-", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 4, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "generate_proxy_dataset('/content/example_data')" + ], + "metadata": { + "id": "DXu4yfuZoiv0", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 5, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## 2.B Create Torch Dataset" + ], + "metadata": { + "id": "MDksFYrIqClt", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "source": [ + "import torch\n", + "from torch.utils.data import Dataset\n", + "import json\n", + "import os\n", + "from PIL import Image\n", + "from torchvision import transforms, utils\n", + "import numpy as np\n", + "\n", + "\n", + "class CustomDataset(Dataset):\n", + " \"\"\"\n", + " A PyTorch Dataset class to be used in a PyTorch DataLoader to create batches.\n", + " \"\"\"\n", + "\n", + " def __init__(self, data_folder, split, keep_difficult=False):\n", + " \"\"\"\n", + " :param data_folder: folder where data files are stored\n", + " :param split: split, one of 'TRAIN' or 'TEST'\n", + " :param keep_difficult: keep or discard objects that are considered difficult to detect?\n", + " \"\"\"\n", + " self.split = split.lower()\n", + "\n", + " assert self.split in {'train', 'val'}\n", + "\n", + " self.data_folder = data_folder\n", + " self.keep_difficult = keep_difficult\n", + "\n", + " # Read data files\n", + " with open(os.path.join(data_folder, self.split + '.txt'), 'r') as j:\n", + " self.images = j.readlines()\n", + "\n", + " def __getitem__(self, i):\n", + " # Read image and label\n", + " image = Image.open(self.images[i].replace(\"\\n\",\"\"), mode='r').resize((320, 320))\n", + " image_tensor = torch.tensor(np.array(image)).permute(2, 0, 1).float()\n", + " labels = np.loadtxt(self.images[i].replace(\"jpg\\n\",\"txt\").replace(\"images\", \"labels\"))\n", + " return image_tensor, labels\n", + "\n", + "\n", + " def __len__(self):\n", + " return len(self.images)\n" + ], + "metadata": { + "id": "AGziBKSIqaUu", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 6, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "train_dataset = CustomDataset(\"/content/example_data\", split=\"train\")\n", + "val_dataset = CustomDataset(\"/content/example_data\", split=\"val\")" + ], + "metadata": { + "id": "2B0hlas_1Rh-", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 7, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's have a look at the first image:" + ], + "metadata": { + "id": "eIG5tsiuor9E", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "source": [ + "train_dataset[1][0]" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ZsHqcq1jpN0F", + "outputId": "e9ac3efa-75a9-4ea6-e46c-277ab418a66f", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 8, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "tensor([[[135., 136., 135., ..., 1., 0., 0.],\n", + " [130., 131., 132., ..., 10., 0., 0.],\n", + " [117., 119., 123., ..., 31., 20., 19.],\n", + " ...,\n", + " [189., 185., 179., ..., 172., 176., 178.],\n", + " [215., 209., 196., ..., 174., 171., 169.],\n", + " [226., 218., 203., ..., 176., 169., 167.]],\n", + "\n", + " [[ 80., 82., 85., ..., 58., 45., 38.],\n", + " [ 76., 78., 83., ..., 65., 53., 47.],\n", + " [ 64., 67., 75., ..., 85., 73., 68.],\n", + " ...,\n", + " [ 96., 95., 91., ..., 194., 203., 208.],\n", + " [122., 118., 107., ..., 198., 200., 202.],\n", + " [132., 127., 113., ..., 200., 200., 200.]],\n", + "\n", + " [[195., 193., 190., ..., 47., 30., 21.],\n", + " [189., 188., 185., ..., 56., 39., 30.],\n", + " [173., 173., 174., ..., 77., 61., 54.],\n", + " ...,\n", + " [132., 130., 124., ..., 97., 96., 97.],\n", + " [156., 150., 137., ..., 95., 86., 84.],\n", + " [165., 158., 143., ..., 94., 82., 79.]]])" + ] + }, + "metadata": {}, + "execution_count": 8 + } + ] + }, + { + "cell_type": "code", + "source": [ + "train_dataset[1][0].shape" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "SWhwpP0H5_3z", + "outputId": "5b12d11d-dc76-421c-e635-37c9d5fce8ed", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 9, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "torch.Size([3, 320, 320])" + ] + }, + "metadata": {}, + "execution_count": 9 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Let's have a look at the first label" + ], + "metadata": { + "id": "8y2rKSxTo4HR", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "source": [ + "train_dataset[1][1]" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "X4qdL8KGpIZJ", + "outputId": "c3b8c530-9f6b-40dc-eca7-72e310750fb3", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 10, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "array([[0. , 0.18314663, 0.38314663, 0.08314663, 0.48314663],\n", + " [4. , 0.2662562 , 0.4662562 , 0.1662562 , 0.5662562 ],\n", + " [0. , 0.24051457, 0.44051457, 0.14051457, 0.54051457],\n", + " [6. , 0.30498596, 0.50498596, 0.20498596, 0.60498596],\n", + " [2. , 0.2363268 , 0.4363268 , 0.1363268 , 0.5363268 ]])" + ] + }, + "metadata": {}, + "execution_count": 10 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "This target has 5 boxes, each from a different class.\n", + "\n", + "Each label include the following [img_id, class, X_center, Y_center, H, W ]\n" + ], + "metadata": { + "id": "6BC44LrJpSpM", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "source": [ + "train_dataset[1][1].shape" + ], + "metadata": { + "id": "MEE-VNBdrl96", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "433f8150-dd5b-4771-ce98-38869de9205a", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 11, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "(5, 5)" + ] + }, + "metadata": {}, + "execution_count": 11 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## 2.C Create Torch Dataloader" + ], + "metadata": { + "id": "aWfFrYLzo9j8", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "As each target may include a diffrent number of boxes we define Dataloader.collate_fn to be DetectionCollateFN. More information regarding this function can be found [here](https://https://github.com/Deci-AI/super-gradients/blob/a47fa1d9b6689df9228df0e56fe73600565d2a32/src/super_gradients/training/utils/detection_utils.py)" + ], + "metadata": { + "id": "D3ThxDIopDDB", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "source": [ + "from torch.utils.data import Dataset, DataLoader\n", + "from super_gradients.training.utils.collate_fn.detection_collate_fn import DetectionCollateFN\n", + "\n", + "train_dataloader = DataLoader(train_dataset, batch_size=4, shuffle=True, num_workers=2, collate_fn=DetectionCollateFN())\n", + "val_dataloader = DataLoader(val_dataset, batch_size=4, shuffle=False, num_workers=2, collate_fn=DetectionCollateFN())" + ], + "metadata": { + "id": "XrWjWfjXnw_r", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 12, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Lets' have a look at the first batch:\n", + "\n", + "We have 4 images in each batch, each include 5 labels.\n", + "\n", + "Each label include the following [img_id, class, X_center, Y_center, H, W ]\n" + ], + "metadata": { + "id": "vB1sGPO8qwZJ", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "source": [ + "next(iter(train_dataloader))[1]" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "O-KuZQ3XBduM", + "outputId": "44cdcf3b-4a2a-49db-ae7f-cd1ffac07c27", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 13, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.10/dist-packages/super_gradients/training/utils/collate_fn/detection_collate_fn.py:29: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n", + " images_batch = [torch.tensor(img) for img in images_batch]\n", + "/usr/local/lib/python3.10/dist-packages/super_gradients/training/utils/collate_fn/detection_collate_fn.py:29: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n", + " images_batch = [torch.tensor(img) for img in images_batch]\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "tensor([[0.0000, 6.0000, 0.2528, 0.4528, 0.1528, 0.5528],\n", + " [0.0000, 6.0000, 0.2613, 0.4613, 0.1613, 0.5613],\n", + " [0.0000, 3.0000, 0.3278, 0.5278, 0.2278, 0.6278],\n", + " [0.0000, 4.0000, 0.3212, 0.5212, 0.2212, 0.6212],\n", + " [0.0000, 0.0000, 0.3695, 0.5695, 0.2695, 0.6695],\n", + " [1.0000, 5.0000, 0.2007, 0.4007, 0.1007, 0.5007],\n", + " [1.0000, 2.0000, 0.1661, 0.3661, 0.0661, 0.4661],\n", + " [1.0000, 5.0000, 0.2157, 0.4157, 0.1157, 0.5157],\n", + " [1.0000, 4.0000, 0.2274, 0.4274, 0.1274, 0.5274],\n", + " [1.0000, 6.0000, 0.3697, 0.5697, 0.2697, 0.6697],\n", + " [2.0000, 1.0000, 0.1861, 0.3861, 0.0861, 0.4861],\n", + " [2.0000, 5.0000, 0.1755, 0.3755, 0.0755, 0.4755],\n", + " [2.0000, 6.0000, 0.3389, 0.5389, 0.2389, 0.6389],\n", + " [2.0000, 1.0000, 0.2743, 0.4743, 0.1743, 0.5743],\n", + " [2.0000, 2.0000, 0.2375, 0.4375, 0.1375, 0.5375],\n", + " [3.0000, 4.0000, 0.2116, 0.4116, 0.1116, 0.5116],\n", + " [3.0000, 4.0000, 0.2414, 0.4414, 0.1414, 0.5414],\n", + " [3.0000, 5.0000, 0.2835, 0.4835, 0.1835, 0.5835],\n", + " [3.0000, 6.0000, 0.2687, 0.4687, 0.1687, 0.5687],\n", + " [3.0000, 3.0000, 0.2546, 0.4546, 0.1546, 0.5546]], dtype=torch.float64)" + ] + }, + "metadata": {}, + "execution_count": 13 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "# 3. Architecture definition" + ], + "metadata": { + "id": "fFfvyMHU32QF", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "SG includes implementations of many different architectures for object detection tasks that can be found [here](https://github.com/Deci-AI/super-gradients#implemented-model-architectures)." + ], + "metadata": { + "id": "EpqgjQjl4awr", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "As mentioned earlier, the architecture that we'll use is based on [YOLOX: Exceeding YOLO Series in 2021](https://arxiv.org/pdf/2107.08430.pdf) and its performance can be view [here](https://github.com/Deci-AI/super-gradients#implemented-model-architectures).\n", + "This architecture was pretrained on COCO2017 datasets.\n", + "\n", + "There are 80 categories in COCO detection, but we want only 8 for our proxy dataset, which means that the predicting layers of the pre-trained model don't work for us. There is a bit of magic for this use case behind the scenes that SuperGradients does for you: you can specify **num_classes** during model construction and it'll automatically replace model's head to a suitable one. As for the pre-trained weights, they will be used for all layers except of those that are replaced." + ], + "metadata": { + "id": "GNM64JAa4sbF", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "source": [ + "from super_gradients.training import models\n", + "\n", + "\n", + "model = models.get(\"yolox_n\", pretrained_weights=\"coco\", num_classes=8)\n", + "model.num_classes" + ], + "metadata": { + "id": "YDK4btf04Gbu", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "5191cbb9-e010-4875-c0d7-fde22f30b44a", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 14, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "Downloading: \"https://sghub.deci.ai/models/yolox_n_coco.pth\" to /root/.cache/torch/hub/checkpoints/yolox_n_coco.pth\n", + "100%|██████████| 11.1M/11.1M [00:00<00:00, 15.6MB/s]\n", + "[2023-10-30 15:09:51] INFO - checkpoint_utils.py - Successfully loaded pretrained weights for architecture yolox_n\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "8" + ] + }, + "metadata": {}, + "execution_count": 14 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "That being said, SG allows you to use one of SG implemented architectures or your custom architecture, as long as it inherits torch.nn.Module." + ], + "metadata": { + "id": "40UcYJ3u5JyF", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "# 4. Training setup\n" + ], + "metadata": { + "id": "LYPVR-XM4GsZ", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "With a model and data in hand we have almost everything to start training, only the recipe is yet to be defined. For this use case we can start with the training recipe that was used for pre-training our model. Let's load it and take a look at the training parameters it gives us." + ], + "metadata": { + "id": "6K_56lDV8azX", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "source": [ + "from super_gradients.training import training_hyperparams\n", + "\n", + "train_params = training_hyperparams.get('coco2017_yolox')\n", + "train_params" + ], + "metadata": { + "id": "3eRe0hBz4G1n", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "87f9bbf1-157b-4f2d-a3cd-410377d60f10", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 21, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "{'resume': None,\n", + " 'run_id': None,\n", + " 'resume_path': None,\n", + " 'resume_from_remote_sg_logger': False,\n", + " 'ckpt_name': 'ckpt_latest.pth',\n", + " 'lr_mode': 'CosineLRScheduler',\n", + " 'lr_schedule_function': None,\n", + " 'lr_warmup_epochs': 5,\n", + " 'lr_warmup_steps': 0,\n", + " 'lr_cooldown_epochs': 15,\n", + " 'warmup_initial_lr': None,\n", + " 'step_lr_update_freq': None,\n", + " 'cosine_final_lr_ratio': 0.05,\n", + " 'warmup_mode': 'LinearEpochLRWarmup',\n", + " 'lr_updates': [],\n", + " 'pre_prediction_callback': None,\n", + " 'optimizer': 'SGD',\n", + " 'optimizer_params': {'momentum': 0.9, 'weight_decay': 0.0005, 'nesterov': True},\n", + " 'load_opt_params': True,\n", + " 'zero_weight_decay_on_bias_and_bn': True,\n", + " 'loss': 'YoloXDetectionLoss',\n", + " 'criterion_params': {'strides': [8, 16, 32], 'num_classes': 80},\n", + " 'ema': True,\n", + " 'ema_params': {'decay': 0.9999, 'decay_type': 'exp', 'beta': 15},\n", + " 'train_metrics_list': [],\n", + " 'valid_metrics_list': [{'DetectionMetrics': {'normalize_targets': True, 'post_prediction_callback': YoloXPostPredictionCallback(), 'num_cls': 80}}],\n", + " 'metric_to_watch': 'mAP@0.50:0.95',\n", + " 'greater_metric_to_watch_is_better': True,\n", + " 'launch_tensorboard': False,\n", + " 'tensorboard_port': None,\n", + " 'tb_files_user_prompt': False,\n", + " 'save_tensorboard_to_s3': False,\n", + " 'precise_bn': False,\n", + " 'precise_bn_batch_size': None,\n", + " 'sync_bn': False,\n", + " 'silent_mode': False,\n", + " 'mixed_precision': True,\n", + " 'save_ckpt_epoch_list': [285],\n", + " 'average_best_models': True,\n", + " 'dataset_statistics': False,\n", + " 'batch_accumulate': 1,\n", + " 'run_validation_freq': 1,\n", + " 'run_test_freq': 1,\n", + " 'save_model': True,\n", + " 'seed': 42,\n", + " 'phase_callbacks': [{'YoloXTrainingStageSwitchCallback': {'next_stage_start_epoch': 285}}],\n", + " 'log_installed_packages': True,\n", + " 'clip_grad_norm': None,\n", + " 'ckpt_best_name': 'ckpt_best.pth',\n", + " 'max_train_batches': None,\n", + " 'max_valid_batches': None,\n", + " 'sg_logger': 'base_sg_logger',\n", + " 'sg_logger_params': {'tb_files_user_prompt': False, 'launch_tensorboard': False, 'tensorboard_port': None, 'save_checkpoints_remote': False, 'save_tensorboard_remote': False, 'save_logs_remote': False, 'monitor_system': True},\n", + " 'torch_compile': False,\n", + " 'torch_compile_loss': False,\n", + " 'torch_compile_options': {'mode': 'reduce-overhead', 'fullgraph': False, 'dynamic': False, 'backend': 'inductor', 'options': None, 'disable': False},\n", + " '_convert_': 'all',\n", + " 'max_epochs': 300,\n", + " 'initial_lr': 0.02}" + ] + }, + "metadata": {}, + "execution_count": 21 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "If it looks like a daunting numbers of parameters, remember that they define everything necessary for SG to know how to train your model: metrics, an optimizer with its parameters, a loss, EMA parameters, various callbacks, etc. If you wish, take a moment to go over them and get aquainted, for the most part, the structure is shared between all the recipes in SuperGradients.\n", + "\n", + "For the sake of this tutorial, we'll change a few parameters above to values that make more sense for a quick transer learning. We'll set a small number of epochs, disable warmup and cooldown, pass a correct number of classes into the loss (criterion) and set a much smaller learning rate not to alter the models weights too much too fast. Mixed precision is also disabled because it is not supported for the CPU training of Colab." + ], + "metadata": { + "id": "65MTR4hd5Fp1", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "source": [ + "train_params['max_epochs'] = 5\n", + "train_params['lr_warmup_epochs'] = 0\n", + "train_params['lr_cooldown_epochs'] = 0\n", + "train_params['criterion_params']['num_classes'] = 8\n", + "train_params['average_best_models'] = False\n", + "train_params['initial_lr'] = 0.0005\n", + "train_params['cosine_final_lr_ratio'] = 0.9\n", + "train_params['mixed_precision'] = False" + ], + "metadata": { + "id": "HRZhFnEk8XzL", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 16, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# 5. Training and evaluation\n" + ], + "metadata": { + "id": "D3tVVUhy4OqP", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "## 5.A. Connect tensor board" + ], + "metadata": { + "id": "T0k_F-7C8-j6", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "You can instantiate a tensorboard to be able to monitor the run live.\n", + "\n", + "This was commented out because it cannot be saved in the notebook, just uncomment the following code if you want to start in a tensorboard" + ], + "metadata": { + "id": "se-cC5sK9Cfz", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "source": [ + "# %load_ext tensorboard\n", + "# %tensorboard --logdir $CHECKPOINT_DIR --bind_all" + ], + "metadata": { + "id": "ExGJWUHE4O1c", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 17, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## 5.B. Start Training" + ], + "metadata": { + "id": "hqk9fUXt9Ift", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "The logs and the checkpoint for the latest epoch will be kept in your experiment folder.\n", + "\n", + "To start training we'll call train(...) and provide it with the objects we construted above: the model, the training parameters and the data loaders.\n", + "\n", + "**Note:** While training, don't forget to refresh the tensorboard with the arrow on the top right." + ], + "metadata": { + "id": "8tKUuxbe9NlQ", + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "source": [ + "trainer.train(model=model, training_params=train_params, train_loader=train_dataloader, valid_loader=val_dataloader)" + ], + "metadata": { + "id": "-Ojnc1bk9L3s", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "6d9b0e33-98c2-4377-9913-cc402c9732c0", + "pycharm": { + "name": "#%%\n" + } + }, + "execution_count": 18, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "[2023-10-30 15:09:51] WARNING - sg_trainer.py - Train dataset size % batch_size != 0 and drop_last=False, this might result in smaller last batch.\n", + "[2023-10-30 15:09:51] INFO - sg_trainer.py - Starting a new run with `run_id=RUN_20231030_150951_846432`\n", + "[2023-10-30 15:09:51] INFO - sg_trainer.py - Checkpoints directory: /home/notebook_ckpts/transfer_learning_object_detection_yolox/RUN_20231030_150951_846432\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Training parameters:\n", + "{\n", + " \"resume\" : null,\n", + " \"run_id\" : null,\n", + " \"resume_path\" : null,\n", + " \"resume_from_remote_sg_logger\" : false,\n", + " \"ckpt_name\" : \"ckpt_latest.pth\",\n", + " \"lr_mode\" : \"CosineLRScheduler\",\n", + " \"lr_schedule_function\" : null,\n", + " \"lr_warmup_epochs\" : 5,\n", + " \"lr_warmup_steps\" : 0,\n", + " \"lr_cooldown_epochs\": 15,\n", + " \"warmup_initial_lr\" : null,\n", + " \"step_lr_update_freq\" : null,\n", + " \"cosine_final_lr_ratio\" : 0.05,\n", + " \"warmup_mode\" : \"LinearEpochLRWarmup\",\n", + " \"lr_updates\": [],\n", + " \"pre_prediction_callback\" : null,\n", + " \"optimizer\" : \"SGD\",\n", + " \"optimizer_params\" : {\"momentum\": 0.9, \"weight_decay\": 0.0005, \"nesterov\": true},\n", + " \"load_opt_params\" : true,\n", + " \"zero_weight_decay_on_bias_and_bn\" : true,\n", + " \"loss\" : \"YoloXDetectionLoss\",\n", + " \"criterion_params\" : {\"strides\": [8, 16, 32], \"num_classes\": 80},\n", + " \"ema\" : true,\n", + " \"ema_params\": {\"decay\": 0.9999, \"decay_type\": \"exp\", \"beta\": 15},\n", + " \"train_metrics_list\": [],\n", + " \"valid_metrics_list\":\n", + " [\n", + " {\n", + " \"DetectionMetrics\":\n", + " {\"normalize_targets\": true, \"post_prediction_callback\": YoloXPostPredictionCallback(), \"num_cls\": 80}\n", + " }\n", + " ],\n", + " \"metric_to_watch\" : \"mAP@0.50:0.95\",\n", + " \"greater_metric_to_watch_is_better\" : true,\n", + " \"launch_tensorboard\": false,\n", + " \"tensorboard_port\" : null,\n", + " \"tb_files_user_prompt\" : false,\n", + " \"save_tensorboard_to_s3\": false,\n", + " \"precise_bn\": false,\n", + " \"precise_bn_batch_size\" : null,\n", + " \"sync_bn\" : false,\n", + " \"silent_mode\" : false,\n", + " \"mixed_precision\" : true,\n", + " \"save_ckpt_epoch_list\" : [285],\n", + " \"average_best_models\" : true,\n", + " \"dataset_statistics\": false,\n", + " \"batch_accumulate\" : 1,\n", + " \"run_validation_freq\" : 1,\n", + " \"run_test_freq\" : 1,\n", + " \"save_model\": true,\n", + " \"seed\" : 42,\n", + " \"phase_callbacks\" : [{\"YoloXTrainingStageSwitchCallback\": {\"next_stage_start_epoch\": 285}}],\n", + " \"log_installed_packages\": true,\n", + " \"clip_grad_norm\" : null,\n", + " \"ckpt_best_name\" : \"ckpt_best.pth\",\n", + " \"max_train_batches\" : null,\n", + " \"max_valid_batches\" : null,\n", + " \"sg_logger\" : \"base_sg_logger\",\n", + " \"sg_logger_params\":\n", + " {\n", + " \"tb_files_user_prompt\" : false,\n", + " \"launch_tensorboard\": false,\n", + " \"tensorboard_port\" : null,\n", + " \"save_checkpoints_remote\" : false,\n", + " \"save_tensorboard_remote\" : false,\n", + " \"save_logs_remote\" : false,\n", + " \"monitor_system\" : true\n", + " },\n", + " \"torch_compile\" : false,\n", + " \"torch_compile_loss\": false,\n", + " \"torch_compile_options\":\n", + " {\n", + " \"mode\" : \"reduce-overhead\",\n", + " \"fullgraph\" : false,\n", + " \"dynamic\" : false,\n", + " \"backend\" : \"inductor\",\n", + " \"options\" : null,\n", + " \"disable\" : false\n", + " },\n", + " \"_convert_\" : \"all\",\n", + " \"max_epochs\": 300,\n", + " \"initial_lr\": 0.02\n", + "}\n", + "The console stream is now moved to /home/notebook_ckpts/transfer_learning_object_detection_yolox/RUN_20231030_150951_846432/console_Oct30_15_09_51.txt\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "[2023-10-30 15:09:51] INFO - sg_trainer.py - Using EMA with params {'decay': 0.9999, 'decay_type': 'exp', 'beta': 15}\n", + "[2023-10-30 15:09:51] INFO - sg_trainer.py - Using EMA with params {'decay': 0.9999, 'decay_type': 'exp', 'beta': 15}\n", + "/usr/local/lib/python3.10/dist-packages/super_gradients/training/utils/collate_fn/detection_collate_fn.py:29: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n", + " images_batch = [torch.tensor(img) for img in images_batch]\n", + "[2023-10-30 15:09:51] INFO - sg_trainer.py - Using EMA with params {'decay': 0.9999, 'decay_type': 'exp', 'beta': 15}\n", + "/usr/local/lib/python3.10/dist-packages/super_gradients/training/utils/collate_fn/detection_collate_fn.py:29: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n", + " images_batch = [torch.tensor(img) for img in images_batch]\n", + "[2023-10-30 15:09:52] INFO - sg_trainer_utils.py - TRAINING PARAMETERS:\n", + " - Mode: Single GPU\n", + " - Number of GPUs: 0 (0 available on the machine)\n", + " - Full dataset size: 10 (len(train_set))\n", + " - Batch size per GPU: 4 (batch_size)\n", + " - Batch Accumulate: 1 (batch_accumulate)\n", + " - Total batch size: 4 (num_gpus * batch_size)\n", + " - Effective Batch size: 4 (num_gpus * batch_size * batch_accumulate)\n", + " - Iterations per epoch: 3 (len(train_loader))\n", + " - Gradient updates per epoch: 3 (len(train_loader) / batch_accumulate)\n", + "\n", + "[2023-10-30 15:09:52] INFO - sg_trainer.py - Started training for 5 epochs (0/4)\n", + "\n", + "Train epoch 0: 0%| | 0/3 [00:00