← Назад к вопросам

Что такое receptive field?

2.0 Middle🔥 151 комментариев
#Глубокое обучение

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Receptive Field в нейронных сетях

Receptive Field (рецептивное поле) — это размер области исходного входа (входного изображения или последовательности), которая влияет на выход определённого нейрона в слое нейронной сети. Это ключевой концепт для понимания того, как сверточные нейронные сети (CNN) обрабатывают информацию и какой контекст они видят на каждом уровне.

Как работает receptive field в CNN

Первый сверточный слой

При kernel size = 3x3:

  • Receptive field = 3x3
  • Каждый нейрон видит 9 пикселей входного изображения
import numpy as np
import matplotlib.pyplot as plt

# Пример: входное изображение 5x5, kernel 3x3
input_image = np.random.rand(5, 5)
print(f"Входное изображение (5x5)")
print(input_image)

# Сверка 3x3 фильтром, padding=0, stride=1
# Результат: 3x3 (каждый нейрон видит соответствующий 3x3 блок входа)
output_shape = (5 - 3) // 1 + 1  # 3x3
print(f"Output shape: {output_shape}x{output_shape}")
print(f"Receptive field: 3x3")

Несколько слоёв

Когда стакируешь несколько сверточных слоёв, receptive field растёт экспоненциально:

def calculate_receptive_field(kernel_size, stride=1, padding=0, n_layers=1):
    """
    Вычисляет receptive field после n слоёв
    
    RF_n = 1 + n * (kernel_size - 1) (при stride=1)
    """
    rf = 1
    for i in range(n_layers):
        rf = rf + (kernel_size - 1) * (stride ** i)
    return rf

# Примеры
print("3x3 kernel, stride=1:")
for layers in [1, 2, 3, 4, 5]:
    rf = calculate_receptive_field(kernel_size=3, stride=1, n_layers=layers)
    print(f"  {layers} слоёв -> RF = {rf}x{rf}")

print("\n5x5 kernel, stride=1:")
for layers in [1, 2, 3, 4]:
    rf = calculate_receptive_field(kernel_size=5, stride=1, n_layers=layers)
    print(f"  {layers} слоёв -> RF = {rf}x{rf}")

print("\n3x3 kernel, stride=2 (pooling):")
for layers in [1, 2, 3, 4, 5]:
    rf = calculate_receptive_field(kernel_size=3, stride=2, n_layers=layers)
    print(f"  {layers} слоёв -> RF = {rf}x{rf}")

Результат:

3x3 kernel, stride=1:
  1 слой -> RF = 3x3
  2 слоя -> RF = 5x5
  3 слоя -> RF = 7x7
  4 слоя -> RF = 9x9
  5 слоев -> RF = 11x11

5x5 kernel, stride=1:
  1 слой -> RF = 5x5
  2 слоя -> RF = 9x9
  3 слоя -> RF = 13x13
  4 слоя -> RF = 17x17

3x3 kernel, stride=2 (pooling):
  1 слой -> RF = 3x3
  2 слоя -> RF = 7x7
  3 слоя -> RF = 15x15
  4 слоя -> RF = 31x31
  5 слоев -> RF = 63x63

Формула расчёта receptive field

RF(l) = RF(l-1) + (kernel_size - 1) * stride(l-1)

Где:
  RF(l) — receptive field на слое l
  kernel_size — размер ядра
  stride — шаг свёртки

Пример расчёта VGG-подобной архитектуры

def compute_receptive_field_sequence(layers_config):
    """
    layers_config: список кортежей (kernel_size, stride)
    """
    rf = 1
    cumulative_stride = 1
    
    print(f"{'Слой':<20} {'Kernel':<10} {'Stride':<10} {'RF':<10}")
    print("-" * 50)
    
    for i, (kernel_size, stride) in enumerate(layers_config):
        rf = rf + (kernel_size - 1) * cumulative_stride
        cumulative_stride *= stride
        print(f"Слой {i+1:<13} {kernel_size:<10} {stride:<10} {rf:<10}")
    
    return rf

# VGG-подобная архитектура
config = [
    (3, 1),  # Conv 3x3
    (3, 1),  # Conv 3x3
    (2, 2),  # MaxPool 2x2
    (3, 1),  # Conv 3x3
    (3, 1),  # Conv 3x3
    (2, 2),  # MaxPool 2x2
]

final_rf = compute_receptive_field_sequence(config)
print(f"\nИтоговый receptive field: {final_rf}x{final_rf}")

Практическое значение receptive field

1. Размер входного изображения

# Если входное изображение 224x224 (ImageNet стандарт)
# А receptive field на последнем слое = 450x450
# Это значит модель может видеть больше, чем размер входа
# Это называется "over-complete receptive field"

input_size = 224
final_rf = 450
ratio = final_rf / input_size
print(f"Receptive field покрывает {ratio:.1f}x больше входа")

2. Для семантической сегментации

# Нужен достаточно большой RF для контекста
# Для распознавания объектов нужен RF, охватывающий весь объект

# U-Net для медицинской сегментации
# Обычно RF = 70-150 для 512x512 входа
print("U-Net обычно: RF = 70-150 для входа 512x512")
print("Ratio: 70/512 = 0.14 до 150/512 = 0.29")

3. Для обнаружения объектов (Object Detection)

# YOLO, Faster R-CNN требуют RF, охватывающий целый объект
# Но и должна быть информация о малых масштабах

# ResNet50 backbone
print("ResNet50:")
print("  После layer1: RF ≈ 71x71")
print("  После layer2: RF ≈ 231x231")
print("  После layer3: RF ≈ 471x471")
print("  После layer4: RF ≈ 1023x1023")

Атрусные свёртки (Dilated Convolutions)

Этот паттерн используется для быстрого увеличения RF:

# Обычная свёртка 3x3: RF = 3
# Атрусная свёртка 3x3 с dilation=2: RF = 5
# Атрусная свёртка 3x3 с dilation=4: RF = 7

def receptive_field_dilated(kernel_size, dilation):
    return kernel_size + (kernel_size - 1) * (dilation - 1)

print("3x3 kernel с разными dilation:")
for d in [1, 2, 4, 8]:
    rf = receptive_field_dilated(3, d)
    print(f"  dilation={d}: RF = {rf}x{rf}")

Проверка RF в PyTorch

import torch
from torchvision.models import resnet50
from torch_receptive_field import receptive_field

model = resnet50(pretrained=True)
model.eval()

# Вычисляем RF для выхода последнего слоя
rfs, rf_x, rf_y = receptive_field(model, (3, 224, 224))
print(f"ResNet50 RF: {rfs}x{rfs}")

Важные выводы

  1. Маленький RF — модель видит только локальные детали, может пропустить контекст
  2. Большой RF — модель может видеть глобальный контекст, лучше для понимания
  3. Оптимальный RF зависит от задачи:
    • Классификация: RF должен быть ≥ размеру объекта
    • Сегментация: RF должен быть больше объекта
    • Обнаружение: зависит от диапазона размеров объектов
  4. Stride и pooling экспоненциально растят RF
  5. Атрусные свёртки эффективны для роста RF без потери разрешения

Понимание receptive field критично при проектировании архитектур CNN для конкретных задач компьютерного зрения.