{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":8175639,"sourceType":"datasetVersion","datasetId":4839408}],"dockerImageVersionId":29974,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# RetinaNet in PyTorch - Global Wheat Detection 🌾\n\nIn this notebook, I will show how to train RetinaNet for object detection using PyTorch. You can find more details [here](https://arxiv.org/pdf/1708.02002.pdf).  \n  \nI am using [this](https://github.com/yhenon/pytorch-retinanet) implementation of RetinaNet in PyTorch by [yhenon](https://github.com/yhenon).\n","metadata":{}},{"cell_type":"code","source":"### Cloning Github Repository \n!git clone https://github.com/yhenon/pytorch-retinanet.git","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-05-23T16:03:12.237091Z","iopub.execute_input":"2024-05-23T16:03:12.237469Z","iopub.status.idle":"2024-05-23T16:03:14.183976Z","shell.execute_reply.started":"2024-05-23T16:03:12.237433Z","shell.execute_reply":"2024-05-23T16:03:14.18318Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### Copying RetinaNet Folder to root dir so we can import it easily\n!cp -r /kaggle/working/pytorch-retinanet/retinanet ./","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:03:14.186241Z","iopub.execute_input":"2024-05-23T16:03:14.186543Z","iopub.status.idle":"2024-05-23T16:03:15.14447Z","shell.execute_reply.started":"2024-05-23T16:03:14.186513Z","shell.execute_reply":"2024-05-23T16:03:15.143313Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install pycocotools","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-05-23T16:03:15.146136Z","iopub.execute_input":"2024-05-23T16:03:15.146484Z","iopub.status.idle":"2024-05-23T16:03:23.760263Z","shell.execute_reply.started":"2024-05-23T16:03:15.146444Z","shell.execute_reply":"2024-05-23T16:03:23.759346Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport re\nimport cv2\nimport time\nimport numpy as np\nimport pandas as pd\n\n\nimport torch\nfrom tqdm import tqdm\nimport torch.optim as optim\nimport torchvision.transforms as T\nfrom torchvision.utils import make_grid \nfrom torch.utils.data import DataLoader, Dataset\n\nfrom retinanet import model\nfrom retinanet.dataloader import collater, Resizer, Augmenter, Normalizer, UnNormalizer\n\nimport seaborn as sns\nfrom matplotlib import pyplot as plt\n%matplotlib inline","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:03:23.761891Z","iopub.execute_input":"2024-05-23T16:03:23.762164Z","iopub.status.idle":"2024-05-23T16:03:26.181066Z","shell.execute_reply.started":"2024-05-23T16:03:23.762137Z","shell.execute_reply":"2024-05-23T16:03:26.180336Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Exploring Dataset 📊","metadata":{}},{"cell_type":"code","source":"train_dir = \"/kaggle/input/makerere-ai-lab-dataset/cocoa_new/cocoa_new/train\"\nvalid_dir = \"/kaggle/input/makerere-ai-lab-dataset/cocoa_new/cocoa_new/valid\"\ntest_dir = \"/kaggle/input/makerere-ai-lab-dataset/cocoa_new/cocoa_new/test_new\"","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:03:26.18478Z","iopub.execute_input":"2024-05-23T16:03:26.185085Z","iopub.status.idle":"2024-05-23T16:03:26.188675Z","shell.execute_reply.started":"2024-05-23T16:03:26.185056Z","shell.execute_reply":"2024-05-23T16:03:26.187981Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import xml.etree.ElementTree as ET\n\ndef parse_annotation(file_path):\n    tree = ET.parse(file_path)\n    root = tree.getroot()\n    \n    filename = root.find('filename').text\n    size = root.find('size')\n    image_width = int(size.find('width').text)\n    image_height = int(size.find('height').text)\n    \n    objects = root.findall('object')\n    \n    yolo_bounding_boxes = []\n    names = []\n    for obj in objects:\n        name = obj.find('name').text\n        bbox = obj.find('bndbox')\n        xmin = int(bbox.find('xmin').text)\n        xmax = int(bbox.find('xmax').text)\n        ymin = int(bbox.find('ymin').text)\n        ymax = int(bbox.find('ymax').text)\n        \n        # Calculate YOLO format values\n        x_center = (xmin + xmax) / 2.0 \n        y_center = (ymin + ymax) / 2.0\n        width = (xmax - xmin) \n        height = (ymax - ymin)\n        \n        names.append(name)\n        \n        yolo_bounding_boxes.append([\n            x_center,\n            y_center,\n            width,\n            height\n        ])\n    \n    return {\n        'filename': file_path[:-3] + 'jpg',\n        \"width\" : image_width,\n        \"heigth\" : image_height,\n        'name' : names,\n        'bounding_boxes': yolo_bounding_boxes\n    }","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:03:26.19182Z","iopub.execute_input":"2024-05-23T16:03:26.192108Z","iopub.status.idle":"2024-05-23T16:03:26.206203Z","shell.execute_reply.started":"2024-05-23T16:03:26.192069Z","shell.execute_reply":"2024-05-23T16:03:26.205478Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_data_df(file_dir):\n    files = os.listdir(file_dir)\n    full_df = pd.DataFrame()\n    \n    for i,file in zip(tqdm(range(len(files))), files):\n        if file[-3:] == 'xml':\n            detect_dict = parse_annotation(file_dir + \"/\" + file)\n            df = pd.DataFrame(detect_dict)\n            full_df = pd.concat([df, full_df], axis = 0, ignore_index = True)\n            \n    return full_df","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:03:26.207409Z","iopub.execute_input":"2024-05-23T16:03:26.207706Z","iopub.status.idle":"2024-05-23T16:03:26.217684Z","shell.execute_reply.started":"2024-05-23T16:03:26.207679Z","shell.execute_reply":"2024-05-23T16:03:26.216999Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df = create_data_df(train_dir)\nvalid_df = create_data_df(valid_dir)","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:03:26.21877Z","iopub.execute_input":"2024-05-23T16:03:26.219028Z","iopub.status.idle":"2024-05-23T16:04:02.784762Z","shell.execute_reply.started":"2024-05-23T16:03:26.219002Z","shell.execute_reply":"2024-05-23T16:04:02.783901Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df.head()","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:04:02.7861Z","iopub.execute_input":"2024-05-23T16:04:02.786408Z","iopub.status.idle":"2024-05-23T16:04:02.806004Z","shell.execute_reply.started":"2024-05-23T16:04:02.786377Z","shell.execute_reply":"2024-05-23T16:04:02.804936Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Converting bbox list from original df to some appropriate form","metadata":{}},{"cell_type":"code","source":"df = pd.concat([\n    train_df, valid_df\n], ignore_index = True, axis = 0)","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:04:02.807471Z","iopub.execute_input":"2024-05-23T16:04:02.807807Z","iopub.status.idle":"2024-05-23T16:04:02.81733Z","shell.execute_reply.started":"2024-05-23T16:04:02.807775Z","shell.execute_reply":"2024-05-23T16:04:02.816598Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### Converting bbox list in appropriate form\n\ndf['x'] = -1\ndf['y'] = -1\ndf['w'] = -1\ndf['h'] = -1\n\ndef expand_bbox(x):\n    r = x\n    if len(r) == 0:\n        r = [-1, -1, -1, -1]\n    return r\n\ndf[['x', 'y', 'w', 'h']] = np.stack(df['bounding_boxes'].apply(lambda x: expand_bbox(x)))\ndf.drop(columns=['bounding_boxes'], inplace=True)\ndf['x'] = df['x'].astype(np.float)\ndf['y'] = df['y'].astype(np.float)\ndf['w'] = df['w'].astype(np.float)\ndf['h'] = df['h'].astype(np.float)\n\ndf.head()\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-05-23T16:04:02.818921Z","iopub.execute_input":"2024-05-23T16:04:02.819342Z","iopub.status.idle":"2024-05-23T16:04:02.966651Z","shell.execute_reply.started":"2024-05-23T16:04:02.819301Z","shell.execute_reply":"2024-05-23T16:04:02.965845Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Null Values, Unique Images, etc.","metadata":{}},{"cell_type":"code","source":"### Null Values, Unique Images, etc.\n\nunq_values = df[\"filename\"].unique()\nprint(\"Total Records: \", len(df))\nprint(\"Unique Images: \",len(unq_values))\n\nnull_values = df.isnull().sum(axis = 0)\nprint(\"\\n> Null Values in each column <\")\nprint(null_values)\n\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-05-23T16:04:02.967944Z","iopub.execute_input":"2024-05-23T16:04:02.968275Z","iopub.status.idle":"2024-05-23T16:04:02.984468Z","shell.execute_reply.started":"2024-05-23T16:04:02.968243Z","shell.execute_reply":"2024-05-23T16:04:02.983782Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### Data Sources\n\nsources = df[\"name\"].unique()\nprint(\"Total Sources: \",len(sources))\nprint(\"\\n> Sources <\\n\",sources)","metadata":{"_kg_hide-input":false,"execution":{"iopub.status.busy":"2024-05-23T16:04:02.98569Z","iopub.execute_input":"2024-05-23T16:04:02.985958Z","iopub.status.idle":"2024-05-23T16:04:02.991913Z","shell.execute_reply.started":"2024-05-23T16:04:02.985931Z","shell.execute_reply":"2024-05-23T16:04:02.991049Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### Visualizing Source Distribution\n\nplt.figure(figsize=(14,8))\nplt.title('Name Distribution', fontsize= 20)\nsns.countplot(x = \"name\", data = df)","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:04:02.993696Z","iopub.execute_input":"2024-05-23T16:04:02.99406Z","iopub.status.idle":"2024-05-23T16:04:03.187077Z","shell.execute_reply.started":"2024-05-23T16:04:02.994022Z","shell.execute_reply":"2024-05-23T16:04:03.186216Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### Splitting Train Dataset into train - val (80:20)\n\nimages = df['filename'].unique()\nvalid_imgs = images[-400:]\ntrain_imgs = images[:-400]\n\nvalid_df = df[df['filename'].isin(valid_imgs)]\ntrain_df = df[df['filename'].isin(train_imgs)]\n","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:04:03.188406Z","iopub.execute_input":"2024-05-23T16:04:03.188706Z","iopub.status.idle":"2024-05-23T16:04:03.206646Z","shell.execute_reply.started":"2024-05-23T16:04:03.188677Z","shell.execute_reply":"2024-05-23T16:04:03.205915Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Visualize Random Images with BBox 🕵️‍","metadata":{}},{"cell_type":"code","source":"from PIL import Image","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:04:03.207867Z","iopub.execute_input":"2024-05-23T16:04:03.208141Z","iopub.status.idle":"2024-05-23T16:04:03.212074Z","shell.execute_reply.started":"2024-05-23T16:04:03.208112Z","shell.execute_reply":"2024-05-23T16:04:03.211102Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### Function to plot image\n\ndef plot_img(image_path, df = train_df):\n    \n    fig, ax = plt.subplots(1, 2, figsize = (10, 10))\n    ax = ax.flatten()\n    \n    records = df[df['filename'] == image_path]\n    \n    image = cv2.imread(image_path, cv2.IMREAD_COLOR)\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32)\n    image /= 255.0\n    image2 = image\n    \n    ax[0].set_title('Original Image')\n    ax[0].imshow(image)\n    \n    for idx, row in records.iterrows():\n        box = row[['x', 'y', 'w', 'h']].values\n        xmin = box[0]\n        ymin = box[1]\n        width = box[2]\n        height = box[3]\n        \n        cv2.rectangle(image2, (int(xmin),int(ymin)), (int(xmin + width),int(ymin + height)), (255,0,0), 3)\n    \n    ax[1].set_title('Image with Bondary Box')\n    ax[1].imshow(image2)\n\n    plt.show()\n    ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-05-23T16:04:03.213294Z","iopub.execute_input":"2024-05-23T16:04:03.213576Z","iopub.status.idle":"2024-05-23T16:04:03.226113Z","shell.execute_reply.started":"2024-05-23T16:04:03.213548Z","shell.execute_reply":"2024-05-23T16:04:03.225159Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df['filename'].unique()","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:04:03.227421Z","iopub.execute_input":"2024-05-23T16:04:03.227834Z","iopub.status.idle":"2024-05-23T16:04:03.243968Z","shell.execute_reply.started":"2024-05-23T16:04:03.227805Z","shell.execute_reply":"2024-05-23T16:04:03.242954Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### Pass any image id as parameter\n\nplot_img('/kaggle/input/makerere-ai-lab-dataset/cocoa_new/cocoa_new/train/img_3963_JPG_jpg.rf.5d7f89c90e9104105f6acee0612861be.jpg')\nplot_img('/kaggle/input/makerere-ai-lab-dataset/cocoa_new/cocoa_new/train/img_4156_JPG_jpg.rf.db0a5646c4cd3dbaf1a8c82fcf47d06f.jpg')","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:04:03.24534Z","iopub.execute_input":"2024-05-23T16:04:03.245758Z","iopub.status.idle":"2024-05-23T16:04:04.370389Z","shell.execute_reply.started":"2024-05-23T16:04:03.245719Z","shell.execute_reply":"2024-05-23T16:04:04.369174Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Preparing Dataset for Training 📂","metadata":{"trusted":true}},{"cell_type":"code","source":"### Creating targets for model using Dataset Class\n\nclass CocoaDataset(Dataset):\n\n    def __init__(self, dataframe, mode = \"train\", transforms = None):\n        \n        super().__init__()\n        self.image_ids = dataframe['filename'].unique()\n        self.df = dataframe\n        self.mode = mode\n        self.transforms = transforms\n\n    def __getitem__(self, index: int):\n\n        # Retriving image id and records from df\n        image_file = self.image_ids[index]\n        records = self.df[self.df['filename'] == image_file]\n\n        # Loading Image\n        image = cv2.imread(image_file, cv2.IMREAD_COLOR)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32)\n        image /= 255.0\n\n        # If mode is set to train, then only we create targets\n        if self.mode == \"train\" or self.mode == \"valid\":\n\n            # Converting xmin, ymin, w, h to x1, y1, x2, y2\n            boxes = np.zeros((records.shape[0], 5))\n            boxes[:, 0:4] = records[['x', 'y', 'w', 'h']].values\n            boxes[:, 2] = boxes[:, 0] + boxes[:, 2]\n            boxes[:, 3] = boxes[:, 1] + boxes[:, 3]\n            boxes[:, 4] = 1 # This is for label, as we have only 1 class, it is always 1\n            \n            # Applying Transforms\n            sample = {'img': image, 'annot': boxes}\n                \n            if self.transforms:\n                sample = self.transforms(sample)\n\n            return sample\n        \n        elif self.mode == \"test\":\n            \n            # We just need to apply transoforms and return image\n            if self.transforms:\n                \n                sample = {'img' : image}\n                sample = self.transforms(sample)\n                \n            return sample\n        \n\n    def __len__(self) -> int:\n        return self.image_ids.shape[0]\n    ","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:04:04.372771Z","iopub.execute_input":"2024-05-23T16:04:04.37335Z","iopub.status.idle":"2024-05-23T16:04:04.39337Z","shell.execute_reply.started":"2024-05-23T16:04:04.373307Z","shell.execute_reply":"2024-05-23T16:04:04.392301Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### Preparing Datasets and Dataloaders for Training \n\n# Dataset Object\ntrain_dataset = CocoaDataset(train_df, mode = \"train\", transforms = T.Compose([Augmenter(), Normalizer(), Resizer()]))\nvalid_dataset = CocoaDataset(valid_df, mode = \"valid\", transforms = T.Compose([Normalizer(), Resizer()]))\n\n# DataLoaders\ntrain_data_loader = DataLoader(\n    train_dataset,\n    batch_size = 8,\n    shuffle = True,\n    num_workers = 4,\n    collate_fn = collater\n)\n\nvalid_data_loader = DataLoader(\n    valid_dataset,\n    batch_size = 8,\n    shuffle = True,\n    num_workers = 4,\n    collate_fn = collater\n)\n\n\n# test_data_loader = DataLoader(\n#     valid_dataset,\n#     batch_size = 1,\n#     shuffle = True,\n#     num_workers = 4,\n#     collate_fn = collater\n# )\n","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:04:04.394769Z","iopub.execute_input":"2024-05-23T16:04:04.395286Z","iopub.status.idle":"2024-05-23T16:04:04.415993Z","shell.execute_reply.started":"2024-05-23T16:04:04.395238Z","shell.execute_reply":"2024-05-23T16:04:04.413711Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Create Model - RetinaNet 🔨","metadata":{}},{"cell_type":"code","source":"### Utilize GPU if available\n\ndevice = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')\ntorch.cuda.empty_cache()","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:04:04.417794Z","iopub.execute_input":"2024-05-23T16:04:04.418157Z","iopub.status.idle":"2024-05-23T16:04:04.475915Z","shell.execute_reply.started":"2024-05-23T16:04:04.418118Z","shell.execute_reply":"2024-05-23T16:04:04.474702Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### I am using Pre-trained Resnet50 as backbone\n\nretinanet = model.resnet50(num_classes = 4, pretrained = True)\n\n# Loading Pre-trained model - if you load pre-trained model, comment above line.\n#retinanet = torch.load(\"path_to_.pt_file\")","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:04:04.477295Z","iopub.execute_input":"2024-05-23T16:04:04.477621Z","iopub.status.idle":"2024-05-23T16:04:11.052154Z","shell.execute_reply.started":"2024-05-23T16:04:04.477583Z","shell.execute_reply":"2024-05-23T16:04:11.051389Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### Preparing model for training\n\n# Defininig Optimizer\noptimizer = torch.optim.Adam(retinanet.parameters(), lr = 0.0001)\n\n# Learning Rate Scheduler\n#lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size = 5, gamma=0.5)\n\nretinanet.to(device)\n\n#No of epochs\nepochs = 15\n","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:04:11.053322Z","iopub.execute_input":"2024-05-23T16:04:11.053603Z","iopub.status.idle":"2024-05-23T16:04:11.115944Z","shell.execute_reply.started":"2024-05-23T16:04:11.053567Z","shell.execute_reply":"2024-05-23T16:04:11.115302Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Now comes everbody's favorite part 😋, let's train it!\nI have defined functions to just improve the readability of the code, model and other parameters are defined outside.","metadata":{}},{"cell_type":"code","source":"### One Epoch - Train\n\ndef train_one_epoch(epoch_num, train_data_loader):\n    \n    print(\"Epoch - {} Started\".format(epoch_num))\n    st = time.time()\n    \n    retinanet.train()\n    \n    epoch_loss = []\n\n    for iter_num, data in enumerate(train_data_loader):\n                \n        # Reseting gradients after each iter\n        optimizer.zero_grad()\n            \n        # Forward\n        classification_loss, regression_loss = retinanet([data['img'].cuda().float(), data['annot'].cuda().float()])\n                \n        # Calculating Loss\n        classification_loss = classification_loss.mean()\n        regression_loss = regression_loss.mean()\n\n        loss = classification_loss + regression_loss\n\n        if bool(loss == 0):\n            continue\n                \n        # Calculating Gradients\n        loss.backward()\n\n        # Gradient Clipping\n        torch.nn.utils.clip_grad_norm_(retinanet.parameters(), 0.1)\n                \n        # Updating Weights\n        optimizer.step()\n\n        #Epoch Loss\n        epoch_loss.append(float(loss))\n\n            \n        print(\n            'Epoch: {} | Iteration: {} | Classification loss: {:1.5f} | Regression loss: {:1.5f} | Running loss: {:1.5f}'.format(\n                epoch_num, iter_num, float(classification_loss), float(regression_loss), np.mean(epoch_loss)))\n\n        del classification_loss\n        del regression_loss\n        \n    # Update the learning rate\n    #if lr_scheduler is not None:\n        #lr_scheduler.step()\n        \n    et = time.time()\n    print(\"\\n Total Time - {}\\n\".format(int(et - st)))\n    \n        ","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:04:44.525371Z","iopub.execute_input":"2024-05-23T16:04:44.525776Z","iopub.status.idle":"2024-05-23T16:04:44.538135Z","shell.execute_reply.started":"2024-05-23T16:04:44.525743Z","shell.execute_reply":"2024-05-23T16:04:44.537296Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### One Epoch - Valid\n\ndef valid_one_epoch(epoch_num, valid_data_loader):\n    \n    print(\"Epoch - {} Started\".format(epoch_num))\n    st = time.time()\n    \n    epoch_loss = []\n\n    for iter_num, data in enumerate(valid_data_loader):\n                \n        with torch.no_grad():\n            \n            # Forward\n            classification_loss, regression_loss = retinanet([data['img'].cuda().float(), data['annot'].cuda().float()])\n\n            # Calculating Loss\n            classification_loss = classification_loss.mean()\n            regression_loss = regression_loss.mean()\n            loss = classification_loss + regression_loss\n\n            #Epoch Loss\n            epoch_loss.append(float(loss))\n\n            print(\n                'Epoch: {} | Iteration: {} | Classification loss: {:1.5f} | Regression loss: {:1.5f} | Running loss: {:1.5f}'.format(\n                    epoch_num, iter_num, float(classification_loss), float(regression_loss), np.mean(epoch_loss)))\n\n            del classification_loss\n            del regression_loss\n        \n    et = time.time()\n    print(\"\\n Total Time - {}\\n\".format(int(et - st)))\n    \n    # Save Model after each epoch\n    torch.save(retinanet, \"retinanet_gwd.pt\")\n    \n        ","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:04:50.402802Z","iopub.execute_input":"2024-05-23T16:04:50.403212Z","iopub.status.idle":"2024-05-23T16:04:50.413754Z","shell.execute_reply.started":"2024-05-23T16:04:50.403175Z","shell.execute_reply":"2024-05-23T16:04:50.412748Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### Training Loop\nfor epoch in range(epochs):\n    \n    # Call train function\n    train_one_epoch(epoch, train_data_loader)\n    \n    # Call valid function\n    valid_one_epoch(epoch, valid_data_loader)\n","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-05-23T16:04:54.663654Z","iopub.execute_input":"2024-05-23T16:04:54.664032Z","iopub.status.idle":"2024-05-23T16:10:23.53017Z","shell.execute_reply.started":"2024-05-23T16:04:54.664Z","shell.execute_reply":"2024-05-23T16:10:23.5277Z"},"scrolled":true,"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"### Sample Results\nretinanet.eval()\nunnormalize = UnNormalizer()\n\nfor iter_num, data in enumerate(test_data_loader):\n    \n    # Getting Predictions\n    scores, classification, transformed_anchors = retinanet(data['img'].cuda().float())\n    \n    idxs = np.where(scores.cpu()>0.5)\n    img = np.array(255 * unnormalize(data['img'][0, :, :, :])).copy()\n    \n    img[img<0] = 0\n    img[img>255] = 255\n\n    img = np.transpose(img, (1, 2, 0))\n\n    img = cv2.cvtColor(img.astype(np.uint8), cv2.COLOR_BGR2RGB)\n    \n    fig, ax = plt.subplots(1, 1, figsize=(16, 8))\n    \n    for j in range(idxs[0].shape[0]):\n        bbox = transformed_anchors[idxs[0][j], :]\n        x1 = int(bbox[0])\n        y1 = int(bbox[1])\n        x2 = int(bbox[2])\n        y2 = int(bbox[3])\n\n        cv2.rectangle(img, (x1, y1), (x2, y2), color = (0, 0, 255), thickness = 2)\n        \n    ax.imshow(img)\n    \n    break\n    ","metadata":{"execution":{"iopub.status.busy":"2024-05-23T16:04:14.142774Z","iopub.status.idle":"2024-05-23T16:04:14.143221Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Hope you liked it 😜, comment below your suggestions / feedback. I will upload another notebook for inference soon.","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}