Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Multi-scale детекция объектов
Основная идея
Multi-scale детекция — это подход в компьютерном зрении, когда модель детектирует объекты разного размера на разных уровнях абстракции (разных масштабах). Проблема в том, что объекты в изображениях могут быть разного размера: маленькие людиши вдали и большие люди вблизи.
Почему нужна multi-scale детекция?
Проблема: простый CNN с одним выходом плохо работает с объектами разного размера.
Обычный детектор смотрит на изображение один раз:
- Маленькие объекты теряются (не достаточно деталей)
- Большие объекты могут быть фрагментированы (каждая часть предсказывается отдельно)
Способ 1: Пирамида изображений (Image Pyramid)
Построить несколько копий изображения разных масштабов:
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('photo.jpg')
# Пирамида Гаусса
pyramid = [img]
for i in range(3):
pyramid.append(cv2.pyrDown(pyramid[-1]))
# Визуализация
fig, axes = plt.subplots(1, 4)
for i, p in enumerate(pyramid):
axes[i].imshow(p)
axes[i].set_title(f'Scale {i}: {p.shape}')
plt.show()
# Запустить детектор на каждом масштабе
detections = []
for scale_level, scaled_img in enumerate(pyramid):
dets = detector(scaled_img)
# Масштабировать координаты обратно к оригиналу
scale_factor = 2 ** scale_level
dets['boxes'] *= scale_factor
detections.append(dets)
Плюсы:
- Простой и понятный
- Хорошо работает с маленькими объектами
Минусы:
- Медленно (нужно обрабатывать несколько изображений)
- Потребление памяти
- Много дублирующихся вычислений
Способ 2: Пирамида признаков (Feature Pyramid Network, FPN)
Модерный подход — использовать несколько уровней детальности из одного прохода CNN:
import torch
import torch.nn as nn
from torchvision.models.detection.backbone_utils import BackboneWithFPN
from torchvision.ops import FeaturePyramidNetwork
# Стандартный backbone (ResNet)
backbone = torch.hub.load('pytorch/vision:v0.10.0', 'resnet50', pretrained=True)
# Извлечь признаки на разных уровнях
class ResNet50WithFPN(nn.Module):
def __init__(self):
super().__init__()
# Conv1 → Conv5 слои ResNet
self.conv1 = backbone.conv1
self.bn1 = backbone.bn1
self.relu = backbone.relu
self.maxpool = backbone.maxpool
self.layer1 = backbone.layer1 # stride=1, channels=256
self.layer2 = backbone.layer2 # stride=2, channels=512
self.layer3 = backbone.layer3 # stride=4, channels=1024
self.layer4 = backbone.layer4 # stride=8, channels=2048
# Feature Pyramid Network
self.fpn = FeaturePyramidNetwork(
in_channels_list=[256, 512, 1024, 2048],
out_channels=256
)
def forward(self, x):
# Backbone
x = self.relu(self.bn1(self.conv1(x)))
x = self.maxpool(x)
c1 = self.layer1(x) # 1/4 разрешение
c2 = self.layer2(c1) # 1/8 разрешение
c3 = self.layer3(c2) # 1/16 разрешение
c4 = self.layer4(c3) # 1/32 разрешение
# FPN объединяет все уровни
fpn_features = self.fpn({'0': c1, '1': c2, '2': c3, '3': c4})
return fpn_features # Dict с несколькими масштабами
model = ResNet50WithFPN()
x = torch.randn(1, 3, 800, 600) # batch, channels, height, width
fpn_outputs = model(x)
print("FPN выходы на разных масштабах:")
for key, feat in fpn_outputs.items():
print(f"Level {key}: shape {feat.shape}")
Как это работает в Faster R-CNN
1. Входное изображение 800x600
2. ResNet backbone → признаки
3. FPN → несколько уровней признаков:
- P2: 200x150 (маленькие объекты)
- P3: 100x75 (средние объекты)
- P4: 50x37 (большие объекты)
- P5: 25x18 (очень большие объекты)
4. RPN на каждом уровне с разными anchor размерами
5. Классификация и регрессия
Anchor размеры для разных масштабов
# В Faster R-CNN используются разные anchor размеры для разных уровней
anchor_scales = {
'P2': [32], # Маленькие якоря (объекты маленькие)
'P3': [64], # Средние якоря
'P4': [128], # Большие якоря
'P5': [256], # Очень большие якоря
}
anchor_ratios = [0.5, 1, 2] # aspect ratios на всех уровнях
# Каждая позиция может иметь несколько якорей разных размеров
# На P2 (200x150): 200*150*3 = 90,000 якорей
# На P5 (25x18): 25*18*3 = 1,350 якорей
# Всего: много якорей на разных масштабах
Пример: YOLO v3 (один из первых использовал multi-scale)
# YOLO v3 предсказывает на трёх масштабах одновременно
# Масштаб 1: 13x13 (большие объекты)
# Масштаб 2: 26x26 (средние объекты)
# Масштаб 3: 52x52 (маленькие объекты)
from torchvision.models.detection import yolov3
import torch
model = yolov3(pretrained=True)
x = torch.randn(1, 3, 416, 416)
# YOLOv3 выдаёт 3 выхода (один на масштаб)
# output1: (1, 255, 13, 13) → большие объекты
# output2: (1, 255, 26, 26) → средние объекты
# output3: (1, 255, 52, 52) → маленькие объекты
# (255 = 3 якоря * (4 координаты + 1 уверенность + 80 классов))
Сравнение разных архитектур
| Архитектура | Multi-scale подход | Скорость | Маленькие объекты |
|---|---|---|---|
| YOLO v1 | Image pyramid | Медленно | Плохо |
| YOLO v2 | Multi-scale training | Средне | Хорошо |
| YOLO v3 | 3 масштаба выходов | Быстро | Отлично |
| Faster R-CNN | FPN | Средне | Хорошо |
| EfficientDet | BiFPN (улучшенная FPN) | Быстро | Отлично |
| RetinaNet | FPN + Focal Loss | Средне | Хорошо |
BiFPN (Bi-directional Feature Pyramid Network)
Улучшение FPN с двусторонней связью:
# Обычная FPN: только top-down
# C5 → P5
# ↑
# C4 → P4 (использует P5)
# ↑
# C3 → P3 (использует P4)
# ↑
# C2 → P2 (использует P3)
# BiFPN: both направления
# P5 ← P6 ← P7 (down)
# ↓
# P4 ← (из P5 и C4) (up-down)
# ↓
# P3 ← (из P4 и C3) (up-down)
# ↓
# P2 ← (из P3 и C2) (up-down)
Практический пример: детекция в реальной жизни
import cv2
import torch
from torchvision.models.detection import fasterrcnn_resnet50_fpn
model = fasterrcnn_resnet50_fpn(pretrained=True)
model.eval()
img = cv2.imread('photo.jpg')
h, w = img.shape[:2]
# Преобразовать в tensor
img_tensor = torch.from_numpy(img).permute(2, 0, 1).float() / 255
# Детекция (использует FPN для разных масштабов)
with torch.no_grad():
predictions = model([img_tensor])
boxes = predictions[0]['boxes']
scores = predictions[0]['scores']
labels = predictions[0]['labels']
# Визуализировать
for box, score, label in zip(boxes, scores, labels):
if score > 0.5:
x1, y1, x2, y2 = box
cv2.rectangle(img, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
cv2.putText(img, f'{label}: {score:.2f}', (int(x1), int(y1)-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
cv2.imshow('Detections', img)
cv2.waitKey(0)
Заключение
Multi-scale детекция — это критически важный компонент современных детекторов объектов. Методы эволюционировали от простых image pyramids к элегантным FPN и BiFPN, которые одновременно работают эффективно и точно. Без multi-scale подхода трудно детектировать объекты разного размера в одном изображении.