Фаза 04 · урок 12

Понимание видео — временное моделирование

Цель урока: 30-секундное видео при 30 fps — это 900 изображений. Наивно классификация видео — это классификация изображений, запущенная 900 раз с последующей агрегацией. Такой подход работает, когда действие видно почти в каждом кадре (спорт,…

Текущий релиз AlexBred.com: первые 100 уроков русскоязычной программы.

Курс
AI Engineering from Scratch
Фаза
Компьютерное зрение
Чтение
11 мин.
Проверено
Содержание урока
  1. Цели обучения
  2. Проблема
  3. Концепция
  4. Три семейства архитектур
  5. 2D + pool
  6. 3D-свёртки
  7. Пространственно-временные трансформеры
  8. Выборка кадров
  9. Оценка
  10. Наборы данных, которые вы встретите
  11. Соберите
  12. Шаг 1: Сэмплер кадров
  13. Шаг 2: Базовое решение 2D+pool
  14. Шаг 3: Раздутая 3D-свёртка в стиле I3D
  15. Шаг 4: Факторизованная свёртка (2+1)D
  16. Используйте
  17. Поставьте
  18. Упражнения
  19. Ключевые термины
  20. Дополнительные материалы

Видео — это последовательность изображений плюс физика, которая их связывает. Каждая модель видео либо рассматривает время как дополнительную ось (3D-свёртка), либо как последовательность для внимания (transformer), либо извлекает признаки один раз и агрегирует их (2D+pool).

Тип: Изучите + соберите Языки: Python Предварительные требования: Фаза 4, урок 03 (CNN), фаза 4, урок 04 (Классификация изображений) Время: ~45 минут

Цели обучения

  • Различать три основных подхода к моделированию видео (2D+pool, 3D-свёртки, пространственно-временные трансформеры) и предсказывать их компромиссы между стоимостью и точностью
  • Реализовать выборку кадров, временной pooling и базовый классификатор 2D+pool в PyTorch
  • Объяснить, почему «раздутые» (inflated) 3D-ядра I3D хорошо переносят веса ImageNet и чем факторизованная свёртка (2+1)D отличается от них
  • Ориентироваться в стандартных наборах данных и метриках распознавания действий: Kinetics-400/600, UCF101, Something-Something V2; точность top-1 на уровне клипа и видео

Проблема

30-секундное видео при 30 fps — это 900 изображений. Наивно классификация видео — это классификация изображений, запущенная 900 раз с последующей агрегацией. Такой подход работает, когда действие видно почти в каждом кадре (спорт, готовка, упражнения), и плохо работает, когда действие определяется самим движением: «толкнуть что-то слева направо» в каждом отдельном кадре выглядит как два неподвижных объекта.

Главный вопрос для каждой видеоархитектуры: когда и как моделируется временная структура? Ответ определяет всё остальное — стоимость вычислений, стратегию предобучения, возможность повторно использовать веса ImageNet и наборы данных, на которых обучается модель.

Этот урок намеренно короче уроков о статических изображениях. Основные механизмы обработки изображений уже есть; понимание видео в основном посвящено временной истории: выборке, моделированию и агрегации.

Концепция

Три семейства архитектур

Диаграмма к уроку «Понимание видео — временное моделирование»

2D + pool

Возьмите 2D CNN (ResNet, EfficientNet, ViT). Запустите её независимо на каждом выбранном кадре. Усредните (или примените max-pool либо attention-pool к) встраиваниям кадров. Передайте агрегированный вектор классификатору.

Преимущества:

  • Предобучение ImageNet переносится напрямую.
  • Самая простая реализация.
  • Дёшево: T кадров * стоимость инференса одного изображения.

Недостатки:

  • Не может моделировать движение. Действие = агрегация внешних признаков.
  • Временной pooling инвариантен к порядку; «открыть дверь» и «закрыть дверь» выглядят одинаково.

Когда использовать: задачи, где важен внешний вид, transfer learning на небольших наборах видео, первоначальные базовые решения.

3D-свёртки

Замените 2D-ядра (H, W) на 3D-ядра (T, H, W). Сеть выполняет свёртку и по пространству, и по времени. Ранние представители семейства: C3D, I3D, SlowFast.

Приём I3D: возьмите предобученную 2D-модель ImageNet и «раздуйте» каждое 2D-ядро, копируя его вдоль новой временной оси. Свёртка 2D 3x3 превращается в свёртку 3D 3x3x3. Так 3D-модель получает сильные предобученные веса вместо обучения с нуля.

Преимущества:

  • Непосредственно моделирует движение.
  • Раздувание I3D даёт бесплатное transfer learning.

Недостатки:

  • В T/8 раз больше FLOPs, чем у 2D-аналога (для временного ядра 3, применённого трижды в стеке).
  • Временные ядра малы; для дальнего движения нужна пирамида или двухпоточный подход.

Когда использовать: распознавание действий, где движение — это сигнал (Something-Something V2, Kinetics с классами, сильно зависящими от движения).

Пространственно-временные трансформеры

Токенизируйте видео в сетку пространственно-временных патчей и выполняйте внимание по всем им. TimeSformer, ViViT, Video Swin, VideoMAE.

Важные паттерны внимания:

  • Совместное (joint) — одно большое внимание по (t, h, w). Квадратичное по T*H*W; дорого.
  • Разделённое (divided) — два внимания на блок: одно по времени, другое по пространству. Почти линейное масштабирование.
  • Факторизованное (factorised) — внимание по времени чередуется с вниманием по пространству между блоками.

Преимущества:

  • SOTA-точность на каждом крупном бенчмарке.
  • Переносится из трансформеров изображений (ViT) через раздувание патчей.
  • Поддерживает видео с длинным контекстом через разреженное внимание.

Недостатки:

  • Требователен к вычислениям.
  • Требует тщательного выбора паттерна внимания, иначе время выполнения резко растёт.

Когда использовать: большие наборы данных, высокоточное понимание видео, мультимодальные задачи видео+текст.

Выборка кадров

10-секундный клип при 30 fps — это 300 кадров; подавать все 300 в любую модель расточительно. Стандартные стратегии:

  • Равномерная выборка (uniform sampling) — выбрать T кадров равномерно по всему клипу. Значение по умолчанию для 2D+pool.
  • Плотная выборка (dense sampling) — случайное непрерывное окно из T кадров. Обычна для 3D-свёрток, поскольку движение требует соседних кадров.
  • Несколько клипов (multi-clip) — выбрать несколько окон из T кадров из одного видео, классифицировать каждое и усреднить предсказания во время тестирования.

T обычно равно 8, 16, 32 или 64. Большее T означает больше временного сигнала за большую цену вычислений.

Оценка

Два уровня:

  • Точность на уровне клипа — модель видит один клип из T кадров и возвращает top-k.
  • Точность на уровне видео — усредняйте предсказания на уровне клипа по нескольким клипам каждого видео; она выше и стабильнее.

Всегда сообщайте обе. Модель с 78% для клипа / 82% для видео сильно полагается на усреднение во время теста; модель с 80% / 81% более устойчива на каждом клипе.

Наборы данных, которые вы встретите

  • Kinetics-400 / 600 / 700 — универсальный набор данных действий. 400 тыс. клипов; URL YouTube (многие уже недоступны).
  • Something-Something V2 — действия, определяемые движением («переместить X слева направо»). Нельзя решить с помощью 2D+pool.
  • UCF-101, HMDB-51 — старые, небольшие, но всё ещё упоминаемые наборы.
  • AVAлокализация действий в пространстве и времени; сложнее классификации.

Соберите

Шаг 1: Сэмплер кадров

Равномерный и плотный сэмплеры, работающие со списком кадров (или тензором видео).

import numpy as np

def sample_uniform(num_frames_total, T):
    if num_frames_total <= T:
        return list(range(num_frames_total)) + [num_frames_total - 1] * (T - num_frames_total)
    step = num_frames_total / T
    return [int(i * step) for i in range(T)]


def sample_dense(num_frames_total, T, rng=None):
    rng = rng or np.random.default_rng()
    if num_frames_total <= T:
        return list(range(num_frames_total)) + [num_frames_total - 1] * (T - num_frames_total)
    start = int(rng.integers(0, num_frames_total - T + 1))
    return list(range(start, start + T))

Оба возвращают T индексов, которые используются для среза тензора видео.

Шаг 2: Базовое решение 2D+pool

Запустите 2D ResNet-18 на каждом кадре, усредните признаки и классифицируйте.

import torch
import torch.nn as nn
from torchvision.models import resnet18, ResNet18_Weights

class FramePool(nn.Module):
    def __init__(self, num_classes=400, pretrained=True):
        super().__init__()
        weights = ResNet18_Weights.IMAGENET1K_V1 if pretrained else None
        backbone = resnet18(weights=weights)
        self.features = nn.Sequential(*(list(backbone.children())[:-1]))  # global avg pool kept
        self.head = nn.Linear(512, num_classes)

    def forward(self, x):
        # x: (N, T, 3, H, W)
        N, T = x.shape[:2]
        x = x.view(N * T, *x.shape[2:])
        feats = self.features(x).view(N, T, -1)
        pooled = feats.mean(dim=1)
        return self.head(pooled)

model = FramePool(num_classes=10)
x = torch.randn(2, 8, 3, 224, 224)
print(f"output: {model(x).shape}")
print(f"params: {sum(p.numel() for p in model.parameters()):,}")

Одиннадцать миллионов параметров, предобучение ImageNet, работа по кадрам, усреднение, классификация. На задачах, где важен внешний вид, это базовое решение часто отстаёт от настоящих 3D-моделей лишь на 5–10 пунктов — а иногда лучше, потому что повторно использует более сильный backbone ImageNet.

Шаг 3: Раздутая 3D-свёртка в стиле I3D

Превратите одну 2D-свёртку в 3D-свёртку, повторив веса вдоль новой временной оси.

def inflate_2d_to_3d(conv2d, time_kernel=3):
    out_c, in_c, kh, kw = conv2d.weight.shape
    weight_3d = conv2d.weight.data.unsqueeze(2)  # (out, in, 1, kh, kw)
    weight_3d = weight_3d.repeat(1, 1, time_kernel, 1, 1) / time_kernel
    conv3d = nn.Conv3d(in_c, out_c, kernel_size=(time_kernel, kh, kw),
                        padding=(time_kernel // 2, conv2d.padding[0], conv2d.padding[1]),
                        stride=(1, conv2d.stride[0], conv2d.stride[1]),
                        bias=False)
    conv3d.weight.data = weight_3d
    return conv3d

conv2d = nn.Conv2d(3, 64, kernel_size=3, padding=1, bias=False)
conv3d = inflate_2d_to_3d(conv2d, time_kernel=3)
print(f"2D weight shape:  {tuple(conv2d.weight.shape)}")
print(f"3D weight shape:  {tuple(conv3d.weight.shape)}")
x = torch.randn(1, 3, 8, 56, 56)
print(f"3D output shape:  {tuple(conv3d(x).shape)}")

Деление на time_kernel сохраняет величины активаций примерно постоянными — это важно, чтобы при первом проходе не нарушить статистики batch norm.

Шаг 4: Факторизованная свёртка (2+1)D

Разделите 3D-свёртку на 2D-свёртку (пространственную) и 1D-свёртку (временную). То же поле восприятия, меньше параметров, на некоторых бенчмарках — лучше точность.

class Conv2Plus1D(nn.Module):
    def __init__(self, in_c, out_c, kernel_size=3):
        super().__init__()
        mid_c = (in_c * out_c * kernel_size * kernel_size * kernel_size) \
                // (in_c * kernel_size * kernel_size + out_c * kernel_size)
        self.spatial = nn.Conv3d(in_c, mid_c, kernel_size=(1, kernel_size, kernel_size),
                                 padding=(0, kernel_size // 2, kernel_size // 2), bias=False)
        self.bn = nn.BatchNorm3d(mid_c)
        self.act = nn.ReLU(inplace=True)
        self.temporal = nn.Conv3d(mid_c, out_c, kernel_size=(kernel_size, 1, 1),
                                  padding=(kernel_size // 2, 0, 0), bias=False)

    def forward(self, x):
        return self.temporal(self.act(self.bn(self.spatial(x))))

c = Conv2Plus1D(3, 64)
x = torch.randn(1, 3, 8, 56, 56)
print(f"(2+1)D output: {tuple(c(x).shape)}")

Полная сеть R(2+1)D устроена так же, как ResNet-18, только каждая свёртка 3x3 заменена на Conv2Plus1D.

Используйте

Две библиотеки покрывают рабочие задачи с видео:

  • torchvision.models.video — R(2+1)D, MViT, Swin3D с предобученными весами Kinetics. Тот же API, что у моделей изображений.
  • pytorchvideo (Meta) — зоопарк моделей, загрузчики данных для Kinetics / SSv2 / AVA, стандартные преобразования.

Для video-language-моделей (создание подписей к видео, video QA) используйте transformers (VideoMAE, VideoLLaMA, InternVideo).

Поставьте

Этот урок создаёт:

  • outputs/prompt-video-architecture-picker.md — промпт, который выбирает 2D+pool / I3D / (2+1)D / transformer по соотношению внешнего вида и движения, размеру набора данных и бюджету вычислений.
  • outputs/skill-frame-sampler-auditor.md — навык, который проверяет сэмплер видеоконвейера и отмечает распространённые ошибки: off-by-one в индексе, неравномерную выборку при num_frames < T, отсутствие кропа с сохранением соотношения сторон и т. д.

Упражнения

  1. (Легко) Вычислите FLOPs (приблизительно) для FramePool с T=8 и для 3D ResNet в стиле I3D с T=8. Объясните, почему 2D+pool в 3–5 раз дешевле.
  2. (Средне) Создайте синтетический набор видео: случайные шарики движутся в случайных направлениях и размечаются направлением движения («слева направо», «справа налево», «по диагонали вверх»). Обучите на нём FramePool. Покажите, что она достигает точности, близкой к случайной, доказывая недостаточность одного лишь внешнего вида для задач движения.
  3. (Сложно) Постройте R(2+1)D-18, заменив каждую Conv2d в ResNet-18 на Conv2Plus1D. Раздуйте веса первой свёртки из предобученной на ImageNet ResNet-18. Обучите на наборе движения из упражнения 2 и превзойдите FramePool.

Ключевые термины

Термин Как обычно говорят Что это на самом деле означает
2D + pool «Покадровый классификатор» Запустить 2D CNN на каждом выбранном кадре, усреднить признаки по времени и классифицировать
3D-свёртка «Пространственно-временное ядро» Ядро выполняет свёртку по (T, H, W); может нативно моделировать движение
Раздувание (inflation) «Поднять 2D-веса до 3D» Инициализировать веса 3D-свёртки повторением весов 2D-свёртки вдоль новой временной оси, затем разделить на kernel_T для сохранения масштаба активаций
(2+1)D «Факторизованная свёртка» Разделить 3D на пространственную 2D и временную 1D; меньше параметров, дополнительная нелинейность между ними
Разделённое внимание «Сначала время, затем пространство» Блок трансформера с двумя механизмами внимания на слой: один по токенам в одном кадре, другой по токенам в одинаковой позиции
Клип «Окно из T кадров» Выбранная подпоследовательность T кадров; единица входа видеомодели
Точность клипа и видео «Два режима оценки» Клип = один образец из видео, видео = среднее по нескольким выбранным клипам
Kinetics «ImageNet для видео» 400–700 классов действий, более 300 тыс. клипов YouTube, стандартный корпус для предобучения видео

Дополнительные материалы


Источник: Video Understanding — Temporal Modeling 04.11 — Stable Diffusion — Architecture & Fine-Tuning · Фаза 04 — Компьютерное зрение · 04.13 — 3D Vision — Point Clouds & NeRFs · Полный каталог