Как правильно реализовать и отладить якоря RPN в ResNet-18 для многократного обнаружения объектов?

Вопрос или проблема

Я работаю над своим первым проектом по обнаружению объектов и мне нужно реализовать обнаружение нескольких объектов, используя ResNet-18 (я ограничен использованием этой архитектуры). Мой набор данных соответствует формату COCO и содержит изображения с одной или несколькими акулами, а также некоторые изображения без акул (но большинство из них содержат одну акулу).

Поскольку ResNet-18 не поддерживает нативное обнаружение нескольких объектов, я понимаю, что мне нужно интегрировать RPN (Сеть Предложений Регионов). Однако, в отличие от ResNet-50, ResNet-18 не имеет встроенной реализации в Torchvision, поэтому я попытался вручную реализовать anchor_generator.

Мне удалось сгенерировать анкерные боксы, но я не уверен, прав ли мой подход.
Ключевые вопросы:

Как можно проверить правильность моей реализации generate_anchors?
Как я могу убедиться, что созданные якоря правильно согласованы с ожиданиями RPN?
Существуют ли рекомендованные методы отладки для проверки, имеют ли смысл предложения якорей до начала обучения?

Ниже я прикрепляю мою реализацию для Dataset, модификацию ResNet-18 с якорями и мою попытку интеграции RPN.

from google.colab import drive
drive.mount('/content/drive')
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import models, transforms
from torch.utils.data import Dataset, DataLoader
from torch.utils.tensorboard import SummaryWriter
import json
from PIL import Image
import os
import torch
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import torch
import torchvision.transforms as T
import matplotlib.pyplot as plt
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from PIL import Image
import json
import os
import torch.optim as optim
from torch.optim.lr_scheduler import StepLR
import albumentations
print(albumentations.__version__)
import torch
from torch.utils.data import Dataset, DataLoader
import albumentations as A
from albumentations.pytorch import ToTensorV2
import json
import os
import numpy as np
from PIL import Image

class SharksDataset(Dataset):
   
    def __init__(self, images_dir, json_file, transform=None):
        with open(json_file, 'r') as f:
            self.coco = json.load(f)
        self.images_dir = images_dir
        self.transform = transform

       
        ann_map = {}
        for ann in self.coco['annotations']:
            img_id = ann['image_id']
            ann_map.setdefault(img_id, []).append(ann)

        self.images = self.coco['images']
        self.annotations = ann_map

    def __len__(self):
        return len(self.images)

    def __getitem__(self, idx):
        img_info = self.images[idx]
        img_id = img_info['id']
        filename = img_info['file_name']
        img_path = os.path.join(self.images_dir, filename)

        image = np.array(Image.open(img_path).convert("RGB"))
        anns = self.annotations.get(img_id, [])

        boxes = []
        labels = []
        for ann in anns:
            x, y, w, h = ann['bbox']
            
            boxes.append([x, y, x + w, y + h])
            
            labels.append(1)

        if self.transform:
            transformed = self.transform(image=image, bboxes=boxes, class_labels=labels)
            image_out = transformed['image']
            boxes_out = transformed['bboxes']
            labels_out = transformed['class_labels']
        else:
            image_out = torch.from_numpy(image).permute(2,0,1).float()
            boxes_out = boxes
            labels_out = labels

        boxes_out = torch.tensor(boxes_out, dtype=torch.float32)
        labels_out = torch.tensor(labels_out, dtype=torch.long)

        return image_out, boxes_out, labels_out, filename

def shark_collate_fn(batch):
    
    images = []
    all_boxes = []
    all_labels = []
    filenames = []
    for (img, b, lbl, fname) in batch:
        images.append(img)
        all_boxes.append(b)
        all_labels.append(lbl)
        filenames.append(fname)

    images = torch.stack(images, dim=0)
    return images, all_boxes, all_labels, filenames
import torch
import torch.nn as nn
import torchvision

class SimpleAnchorResnet18(nn.Module):
    
    def __init__(self, num_anchors=9, num_classes=2):
        super().__init__()
        backbone = torchvision.models.resnet18(weights="IMAGENET1K_V1")
        self.backbone = nn.Sequential(*list(backbone.children())[:-2])
        self.in_channels = 512
        self.num_anchors = num_anchors
        self.num_classes = num_classes

        
        self.cls_head  = nn.Conv2d(self.in_channels, self.num_anchors*self.num_classes, kernel_size=1)
        
        self.bbox_head = nn.Conv2d(self.in_channels, self.num_anchors*4, kernel_size=1)

    def forward(self, x):
        feats = self.backbone(x)        # [B,512,H',W']
        cls_out  = self.cls_head(feats) # [B,2*nAnchors,H',W']
        bbox_out = self.bbox_head(feats)# [B,4*nAnchors,H',W']
        return cls_out, bbox_out
import torchvision
import torch.nn as nn
import torchvision.models as models
from torchvision.models.detection import FasterRCNN
from torchvision.models.detection.rpn import AnchorGenerator


backbone = models.resnet18(weights="IMAGENET1K_V1")  
backbone = nn.Sequential(*list(backbone.children())[:-2])  


backbone.out_channels = 512


anchor_generator = AnchorGenerator(
    sizes=((32, 64, 128, 256, 512),),  
    aspect_ratios=((0.5, 1.0, 2.0),) * 5 

roi_pooler = torchvision.ops.MultiScaleRoIAlign(
    featmap_names=["0"], output_size=7, sampling_ratio=2
)


model = FasterRCNN(
    backbone,
    num_classes=2,  
    rpn_anchor_generator=anchor_generator,
    box_roi_pool=roi_pooler
)

print(model)

Ответ или решение

Введение работы с объектным детектированием требует понимания множества аспектов архитектур глубокого обучения, и использование ResNet-18 с RPN для многообъектного детектирования — одна из таких задач. Вы начали с попытки реализовать генерацию анкор-боксов, что является жизненно важной частью в процедуре обучения, поскольку anchors определяют область поиска объектов в изображениях. Давайте разберем, как правильно реализовать и отладить anchors в этой архитектуре, опираясь на ваш код и описанную задачу.

Теория (Theory)

Region Proposal Network (RPN) — это важная часть алгоритмов объектного детектирования. Он генерирует потенциальные bounding-боксы, которые могли бы содержать объекты, и эти боксы последовательно используются для классификации.

Anchors — это фиксированные bounding-боксы с предопределенными размерами и соотношениями сторон, которые RPN использует для поиска объектов. Во время процесса обучения, RPN обучается изменять anchors таким образом, чтобы они соответствовали объектам на изображениях.

Ключевыми характеристиками для определения правильности генерации anchors являются их размер, количество и соотношение сторон. Правильная реализация подразумевает, что:

  1. Генерированные anchors эффективно покрывают область изображения.
  2. Соотношения сторон и размеры anchors соответствуют характеру изображений в вашем наборе данных.

Пример (Example)

В вашем примере использования ResNet-18 в сочетании с Faster R-CNN, вы уже начали интеграцию AnchorGenerator, который добавляет важные параметры, такие как размеры (sizes) и соотношения (aspect ratios) anchors. Пример вашей реализации выглядит следующим образом:

anchor_generator = AnchorGenerator(
    sizes=((32, 64, 128, 256, 512),),  
    aspect_ratios=((0.5, 1.0, 2.0),) * 5
)

Этот код показывает, что вы выбрали пять разных размеров anchors и три соотношения сторон. Эта конфигурация должна обеспечивать достаточную вариативность дляохвата большинства объектов в ваших изображениях.

Применение (Application)

Теперь нам следует перейти к стратегическим шагам валидации и отладки процесса:

  1. Визуализация Anchors: Перед началом обучения вы можете визуализировать ваши anchors на изображениях, чтобы убедиться, что они покрывают области, соответствующие потенциальным позициям объектов. Это можно сделать с использованием matplotlib для наложения anchors поверх изображений.
import matplotlib.pyplot as plt
import matplotlib.patches as patches

def visualize_anchors(image, anchors):
    fig, ax = plt.subplots(1)
    ax.imshow(image)
    for anchor in anchors:
        rect = patches.Rectangle(
            (anchor[0], anchor[1]), anchor[2] - anchor[0], anchor[3] - anchor[1], 
            linewidth=1, edgecolor='r', facecolor='none')
        ax.add_patch(rect)
    plt.show()
  1. Проверка корреляции Anchors с данными: Проверьте, насколько ваши anchors коррелируют с реальными bounding-боксами. Это можно сделать путем вычисления таких метрик, как Intersection-over-Union (IoU) между anchors и боксами labeled объектов. Настроив метрики, вы сможете количественно оценить, соответствуют ли ваши anchors вашим данным.

  2. Тестирование гиперпараметров Anchor Generator: В зависимости от вашего набора данных может потребоваться адаптация размеров и соотношений anchors. Например, если обнаружится, что большинство объектов имеют схожие размеры, имеет смысл сосредоточиться на соответсвующих размерах anchors.

  3. Отладка Проведения Тренировки: Когда вы начинаете обучение сети с использованием ваших anchors, внимательно следите за потерями, особенно за тем, как сходится ваша модель. Если потери не снижаются должным образом, это может быть сигналом к необходимости настройки anchors или гиперпараметров обучения.

  4. Использование TensorBoard для мониторинга: Инструменты, такие как TensorBoard, могут быть полезны для отслеживания метрик обучения, визуализации потерь и других параметров в динамике. Это может помочь отследить, как изменение anchors влияет на общее обучение модели.

Заключая, корректная реализация и отладка anchors в контексте object detection представляет собой критический шаг для достижения точных результатов. Посредством визуализации, тестирования и тщательной проверки гиперпараметров, вы сможете достичь более высокой эффективности вашей модели на основе ResNet-18.

Оцените материал
Добавить комментарий

Капча загружается...