Что такое RoI Pooling и RoI Align? Для чего они нужны?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое RoI Pooling и RoI Align? Для чего они нужны?
RoI Pooling и RoI Align это два ключевых механизма в архитектуре объектных детекторов, основанных на регионах (R-CNN семейство). Они решают проблему извлечения признаков из произвольно сформированных регионов изображения.
Контекст: почему нужны RoI операции
В детекторах типа Faster R-CNN процесс состоит из двух этапов:
- Region Proposal Network (RPN) генерирует кандидатов регионов (region proposals) произвольного размера и соотношения сторон
- Head network должна классифицировать эти регионы и уточнить их координаты
Проблема: CNN ожидает фиксированные размеры входа. Как обработать регионы разных размеров?
Решение: RoI Pooling и RoI Align.
RoI Pooling (Region of Interest Pooling)
Это старый и простой метод, введённый в Fast R-CNN (2015).
Как работает:
- На выходе CNN есть карта признаков (feature map) размера H x W x C
- Для каждого предложенного региона известны его координаты в исходном изображении
- RoI Pooling преобразует эти координаты в координаты на feature map (с учётом stride CNN)
- Регион на feature map делится на сетку P x Q (фиксированного размера)
- В каждой ячейке сетки применяется max pooling
- Результат: tensor размера P x Q x C (фиксированный!)
import torch
import torch.nn as nn
# Пример использования
feature_map = torch.randn(1, 256, 64, 64) # batch=1, channels=256, H=64, W=64
# RoI с координатами (x1, y1, x2, y2) в пикселях исходного изображения
# Исходное изображение обычно 224x224 или 256x256
rois = torch.tensor([
[0, 10, 20, 100, 200], # batch_index, x1, y1, x2, y2
[0, 50, 50, 150, 150],
])
roi_pool = nn.RoIPool(output_size=(7, 7), spatial_scale=1.0/32.0)
# spatial_scale = 1 / stride CNN
# Если CNN имеет stride 32 (уменьшает размер в 32 раза)
pooled = roi_pool(feature_map, rois)
print(pooled.shape) # (2, 256, 7, 7) фиксированный размер!
Математически:
Для региона [x1, y1, x2, y2]:
1. Преобразуем в координаты feature map: [x1/stride, y1/stride, x2/stride, y2/stride]
2. Делим регион на P x Q ячеек
3. В каждой ячейке берём максимум
Проблемы RoI Pooling:
-
Quantization loss из-за округления координат
- Координаты преобразуются из float в int, что приводит к потере информации
- Регионы смещаются из-за округления
-
Неточное выравнивание (misalignment)
- Регион на исходном изображении не соответствует региону на feature map
# Пример quantization loss
# Регион [10.3, 20.7, 100.5, 200.2] в изображении
# После преобразования на feature map (stride=32):
# [10.3/32, 20.7/32, 100.5/32, 200.2/32] = [0.32, 0.65, 3.14, 6.26]
# После округления: [0, 0, 3, 6] — потеря точности!
RoI Align
Это улучшенная версия, введённая в Mask R-CNN (2017), которая решает проблемы RoI Pooling.
Ключевые отличия:
- Использует биллинейную интерполяцию вместо округления
- Не округляет координаты — работает с float
- Правильное выравнивание (proper alignment)
Как работает:
import torch
import torch.nn as nn
from torchvision.ops import RoIAlign
feature_map = torch.randn(1, 256, 64, 64)
# RoI Align
rois = torch.tensor([
[0, 10.3, 20.7, 100.5, 200.2], # Можем использовать float координаты!
[0, 50.2, 50.8, 150.1, 150.9],
])
roi_align = RoIAlign(output_size=(7, 7), spatial_scale=1.0/32.0, sampling_ratio=2)
# sampling_ratio: количество точек выборки в каждой ячейке
# Если sampling_ratio=-1, берётся адаптивное количество
aligned = roi_align(feature_map, rois)
print(aligned.shape) # (2, 256, 7, 7) фиксированный размер
Математически (RoI Align):
Для каждой ячейки выходной сетки (например 7x7):
1. Вычисляем соответствующие координаты на feature map (используя float)
2. Берём несколько точек выборки (sampling points) в этой ячейке
3. Для каждой точки используем биллинейную интерполяцию для вычисления значения
4. Берём max (или average) от всех выборочных точек
Пример биллинейной интерполяции:
def bilinear_interpolate(feature_map, x, y):
"""
feature_map: (H, W, C)
x, y: координаты (могут быть float)
"""
x1, y1 = int(x), int(y)
x2, y2 = x1 + 1, y1 + 1
# Веса
wx = x - x1
wy = y - y1
# Биллинейная интерполяция
value = (
feature_map[y1, x1] * (1 - wx) * (1 - wy) +
feature_map[y1, x2] * wx * (1 - wy) +
feature_map[y2, x1] * (1 - wx) * wy +
feature_map[y2, x2] * wx * wy
)
return value
Сравнение RoI Pooling vs RoI Align
| Аспект | RoI Pooling | RoI Align |
|---|---|---|
| Округление | Да (int) | Нет (float) |
| Интерполяция | Нет | Биллинейная |
| Квантизационная потеря | Есть | Минимальная |
| Выравнивание | Неточное | Точное |
| Скорость | Быстрее | Медленнее (sampling) |
| Качество | Хуже | Лучше |
| Использование | Fast R-CNN, Faster R-CNN | Mask R-CNN, современные детекторы |
Практическое влияние
На практике RoI Align улучшает результаты на 2-3% mAP (Mean Average Precision) на COCO dataset.
Это особенно заметно для малых объектов, где квантизационная потеря в RoI Pooling была критичной.
Использование в современных фреймворках
PyTorch:
from torchvision.ops import RoIPool, RoIAlign
# RoI Pooling
roi_pool = RoIPool(output_size=(7, 7), spatial_scale=0.0625)
# RoI Align (рекомендуется)
roi_align = RoIAlign(output_size=(7, 7), spatial_scale=0.0625, sampling_ratio=2)
TensorFlow:
from tensorflow.image import crop_and_resize
# crop_and_resize это эквивалент RoI Align
crops = crop_and_resize(
image_tensor,
boxes, # нормализованные координаты
box_indices,
crop_size=(7, 7)
)
Экспертные заметки для собеседования
- RoI Pooling используется в Faster R-CNN, это старый стандарт
- RoI Align используется в Mask R-CNN и современных детекторах (YOLO, EfficientDet и др.)
- Основное улучшение это биллинейная интерполяция и float координаты, а не округление
- sampling_ratio в RoI Align — важный гиперпараметр. Чем больше, тем точнее, но медленнее
- В контексте Mask R-CNN RoI Align было критично для точного маскирования объектов
Если на собеседовании спросят о деталях, упомяни квантизационную потерю и объясни, почему биллинейная интерполяция это решение.