Какие знаешь вариации anchor-free детекторов?
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Вариации Anchor-Free Детекторов объектов
Anchor-free подход к детекции объектов — это парадигма, которая отказывается от предопределённых якорей (anchor boxes) в пользу прямого предсказания параметров объекта. Это упрощает архитектуру, снижает требования к памяти и часто показывает лучшее качество. Вот основные вариации.
1. CornerNet
Использует детекцию углов (corners) объектов:
# Концепция CornerNet:
# - Вместо прямоугольников детектируем верхний-левый и нижний-правый углы
# - Используем стеки hourglass-сетей для обработки особенностей
# - Применяем группировку углов (corner grouping) для связи пар углов
class CornerNetHead(nn.Module):
def __init__(self):
super().__init__()
# Две отдельные ветви для двух типов углов
self.tl_branch = HourglassStack() # Top-left
self.br_branch = HourglassStack() # Bottom-right
# Выходные головы
self.tl_heat = nn.Conv2d(256, 1, kernel_size=1) # Heatmap углов
self.br_heat = nn.Conv2d(256, 1, kernel_size=1)
self.tl_offset = nn.Conv2d(256, 2, kernel_size=1) # Смещения
self.br_offset = nn.Conv2d(256, 2, kernel_size=1)
def forward(self, features):
# Извлекаем особенности для углов
tl_features = self.tl_branch(features)
br_features = self.br_branch(features)
# Heatmaps для локализации углов
tl_heatmap = self.tl_heat(tl_features)
br_heatmap = self.br_heat(br_features)
# Смещения для точной локализации
tl_offsets = self.tl_offset(tl_features)
br_offsets = self.br_offset(br_features)
return {
'tl_heatmap': tl_heatmap,
'br_heatmap': br_heatmap,
'tl_offsets': tl_offsets,
'br_offsets': br_offsets
}
Преимущества:
- Интуитивный подход (углы легко интерпретировать)
- Отсутствие якорей
Недостатки:
- Требует связи углов (corner grouping) — вычислительно сложно
- Может неправильно соединить углы разных объектов
2. CenterNet v1
Детектирует центр и размер объекта:
class CenterNetHead(nn.Module):
"""CenterNet v1: детекция центров + регрессия размеров"""
def __init__(self):
super().__init__()
# Основная сеть признаков (например, ResNet)
self.backbone = ResNet50()
# Выходные головы
# 1. Heatmap центров объектов
self.heatmap = nn.Sequential(
nn.Conv2d(2048, 256, kernel_size=3, padding=1),
nn.ReLU(),
nn.Conv2d(256, 80, kernel_size=1) # 80 классов COCO
)
# 2. Регрессия размера (width, height)
self.size_regression = nn.Sequential(
nn.Conv2d(2048, 256, kernel_size=3, padding=1),
nn.ReLU(),
nn.Conv2d(256, 2, kernel_size=1) # w, h
)
# 3. Смещение центра (для точности)
self.offset = nn.Sequential(
nn.Conv2d(2048, 256, kernel_size=3, padding=1),
nn.ReLU(),
nn.Conv2d(256, 2, kernel_size=1) # dx, dy
)
def forward(self, x):
features = self.backbone(x)
heatmap = self.heatmap(features) # Где центры
size = self.size_regression(features) # Размеры
offset = self.offset(features) # Точные позиции
return {
'heatmap': heatmap,
'size': size,
'offset': offset
}
# Loss функция
def centernet_loss(predictions, targets):
# Focal loss для heatmap (справляется с дисбалансом background/foreground)
heatmap_loss = focal_loss(predictions['heatmap'], targets['heatmap'])
# L1 loss для размеров и смещений
size_loss = F.l1_loss(predictions['size'], targets['size'])
offset_loss = F.l1_loss(predictions['offset'], targets['offset'])
return heatmap_loss + size_loss + offset_loss
Преимущества:
- Простая архитектура
- Быстрая инференция
- Хорошее качество
Недостатки:
- Может перекрываться на объекты (оба центра в одной ячейке)
3. FCOS (Fully Convolutional One-Stage)
Пиксель-ориентированный подход — каждый пиксель предсказывает, является ли он внутри объекта:
class FCOSHead(nn.Module):
"""FCOS: каждый пиксель предсказывает объект"""
def __init__(self, num_classes):
super().__init__()
self.num_classes = num_classes
# Регрессионные ветви (FPN features)
self.cls_convs = nn.Sequential(
nn.Conv2d(256, 256, kernel_size=3, padding=1),
nn.GroupNorm(32, 256),
nn.ReLU(),
nn.Conv2d(256, 256, kernel_size=3, padding=1),
nn.GroupNorm(32, 256),
nn.ReLU()
)
self.bbox_convs = nn.Sequential(
nn.Conv2d(256, 256, kernel_size=3, padding=1),
nn.GroupNorm(32, 256),
nn.ReLU(),
nn.Conv2d(256, 256, kernel_size=3, padding=1),
nn.GroupNorm(32, 256),
nn.ReLU()
)
# Выходы
self.cls_logits = nn.Conv2d(256, num_classes, kernel_size=3, padding=1)
self.bbox_pred = nn.Conv2d(256, 4, kernel_size=3, padding=1) # (l, r, t, b)
self.centeredness = nn.Conv2d(256, 1, kernel_size=3, padding=1) # центрированность
def forward(self, fpn_features):
outputs = []
for level, features in enumerate(fpn_features):
cls_out = self.cls_logits(self.cls_convs(features))
bbox_out = self.bbox_pred(self.bbox_convs(features))
center_out = self.centeredness(self.bbox_convs(features))
# Применяем экспоненту для положительности расстояний
bbox_out = torch.exp(bbox_out)
outputs.append({
'classifications': cls_out,
'bbox': bbox_out,
'centeredness': center_out
})
return outputs
# Ключевая особенность FCOS: каждый пиксель предсказывает расстояния до границ (l, r, t, b)
# Если пиксель внутри объекта, он предсказывает расстояния
# Если снаружи, игнорируется (background)
Преимущества:
- Полностью свёртываемый (FCN) подход
- Нет якорей и группировки
- Высокое качество
- Масштабируемость
Недостатки:
- Может быть медленнее при инференции из-за постобработки
4. KeypointNet / CenterNet v2
Детекция ключевых точек объекта:
class KeypointDetectorHead(nn.Module):
"""Детекция объектов через ключевые точки"""
def __init__(self, num_keypoints=17):
super().__init__()
self.num_keypoints = num_keypoints
# Heatmaps для каждой ключевой точки
self.keypoint_heatmaps = nn.ModuleList([
nn.Conv2d(256, 1, kernel_size=1) for _ in range(num_keypoints)
])
# Смещения для каждой ключевой точки
self.keypoint_offsets = nn.ModuleList([
nn.Conv2d(256, 2, kernel_size=1) for _ in range(num_keypoints)
])
def forward(self, features):
heatmaps = [h(features) for h in self.keypoint_heatmaps]
offsets = [o(features) for o in self.keypoint_offsets]
# Bounding box вычисляется из ключевых точек
# (min/max координат)
keypoints = self._decode_keypoints(heatmaps, offsets)
bbox = self._compute_bbox_from_keypoints(keypoints)
return {
'keypoints': keypoints,
'bbox': bbox
}
def _compute_bbox_from_keypoints(self, keypoints):
"""Вычисляем bounding box из ключевых точек"""
# Берём минимальные и максимальные координаты
x_coords = keypoints[:, :, 0]
y_coords = keypoints[:, :, 1]
x_min, x_max = torch.min(x_coords, dim=1)[0], torch.max(x_coords, dim=1)[0]
y_min, y_max = torch.min(y_coords, dim=1)[0], torch.max(y_coords, dim=1)[0]
return torch.stack([x_min, y_min, x_max, y_max], dim=1)
5. RepPoints
Использует адаптивные точки представления:
class RepPointsHead(nn.Module):
"""RepPoints: объекты представлены адаптивными точками"""
def __init__(self, num_points=9):
super().__init__()
self.num_points = num_points
# Классификация
self.cls_conv = nn.Conv2d(256, 80, kernel_size=3, padding=1)
# Регрессия points (начальные и уточнённые)
# Начальные точки: на сетке регулярной сетки
self.init_points_conv = nn.Conv2d(
256, 2 * num_points, kernel_size=1
)
# Уточнённые точки (через рефайнмент)
self.refine_points_conv = nn.Conv2d(
256, 2 * num_points, kernel_size=1
)
def forward(self, features):
cls_logits = self.cls_conv(features)
init_pts = self.init_points_conv(features) # Начальные точки
refine_pts = self.refine_points_conv(features) # Уточнённые
# Финальные точки = начальные + смещение
final_points = init_pts + refine_pts
return {
'cls_logits': cls_logits,
'points': final_points
}
# Особенность RepPoints: объект представлен облаком точек
# Это более гибко, чем прямоугольник, особенно для объектов с непрямоугольной формой
Преимущества:
- Гибкое представление объектов
- Лучше справляется с необычными формами
- Может использоваться для различных задач (детекция, сегментация)
6. DETR (Detection Transformer)
Трансформер-подход к детекции:
class DETRHead(nn.Module):
"""DETR: Set-based object detection"""
def __init__(self, num_classes, num_queries=100):
super().__init__()
self.num_queries = num_queries
# Обучаемые запросы (queries) — представляют объекты
self.object_queries = nn.Parameter(
torch.randn(num_queries, 256)
)
# Трансформер для обработки запросов
self.transformer = nn.TransformerDecoder(
decoder_layer=nn.TransformerDecoderLayer(
d_model=256,
nhead=8,
dim_feedforward=2048,
dropout=0.1
),
num_layers=6
)
# Выходные головы
self.class_head = nn.Linear(256, num_classes)
self.bbox_head = nn.Sequential(
nn.Linear(256, 256),
nn.ReLU(),
nn.Linear(256, 4) # (cx, cy, w, h) — нормализованные
)
def forward(self, backbone_features, query_pos):
# Трансформер обрабатывает запросы относительно особенностей
decoder_out = self.transformer(
self.object_queries,
backbone_features,
query_pos_embed=query_pos
)
# Получаем классы и bounding boxes
class_logits = self.class_head(decoder_out)
bbox_pred = self.bbox_head(decoder_out)
return {
'class_logits': class_logits,
'bbox': bbox_pred
}
Преимущества:
- Глобальный контекст (внимание трансформера)
- Конец-в-конец обучение
- Естественное многообъектное давление
Недостатки:
- Медленнее традиционных CNN подходов
- Требует больше GPU памяти
Сравнение подходов
| Метод | Парадигма | Скорость | Качество | Применение |
|---|---|---|---|---|
| CornerNet | Углы | Средняя | Хорошее | Научные работы |
| CenterNet | Центры | Быстрая | Хорошее | Практика |
| FCOS | Пиксели | Быстрая | Отличное | Стандарт в индустрии |
| RepPoints | Точки | Средняя | Отличное | Гибкие формы |
| DETR | Трансформер | Медленная | Отличное | Современный подход |
Заключение
Anchor-free подходы революционизировали детекцию объектов, убрав якоря и упростив архитектуры. Каждый вариант имеет свои сильные стороны:
- Для баланса скорости и качества: FCOS или CenterNet
- Для сложных форм: RepPoints
- Для глобального контекста: DETR
- Для научных работ: Экспериментируй со специальными архитектурами
Современные детекторы (YOLOv5+, EfficientDet) часто комбинируют идеи из разных подходов для оптимального баланса.