Фаза 04 · урок 17
Самообучение в компьютерном зрении — SimCLR, DINO, MAE
Цель урока: В ImageNet с обучением с учителем 1,3 млн размеченных изображений; их разметка, по оценкам, обошлась в $10M. Медицинские и промышленные наборы данных меньше, а их разметка ещё дороже. Каждая команда компьютерного зрения задаётся…
Текущий релиз AlexBred.com: первые 100 уроков русскоязычной программы.
Содержание урока
- Цели обучения
- Проблема
- Концепция
- Три семейства методов
- Контрастивное обучение (SimCLR)
- «Учитель—ученик» (DINO)
- Реконструкция по маске (MAE)
- Почему 75 %, а не 15 %
- Оценка линейным зондированием
- Соберите
- Шаг 1: конвейер аугментирования двух представлений
- Шаг 2: функция потерь InfoNCE
- Шаг 3: быстрая проверка InfoNCE
- Шаг 4: маскирование в стиле MAE
- Используйте
- Внедрите
- Упражнения
- Ключевые термины
- Дополнительное чтение
Метки — узкое место обучения компьютерного зрения с учителем. Предобучение с самообучением устраняет эту проблему: обучайте визуальные признаки на 100 млн немаркированных изображений, затем дообучайте модель на 10 тыс. размеченных.
Тип: Изучите + соберите Языки: Python Предварительные требования: Фаза 4, урок 04 (Классификация изображений), фаза 4, урок 14 (ViT) Время: ~75 минут
Цели обучения
- Проследить три основные группы методов самообучения — контрастивные (SimCLR), «учитель—ученик» (DINO), реконструкцию по маске (MAE) — и объяснить, что оптимизирует каждая из них
- Реализовать функцию потерь InfoNCE с нуля и объяснить, почему пакет из 512 примеров работает, а пакет из 32 — нет
- Объяснить, почему коэффициент маскирования MAE в 75 % не произволен и чем он отличается от 15 % у BERT для текста
- Использовать контрольные точки DINOv2 или MAE для ImageNet для линейного зондирования и поиска без обучения на целевой задаче
Проблема
В ImageNet с обучением с учителем 1,3 млн размеченных изображений; их разметка, по оценкам, обошлась в $10M. Медицинские и промышленные наборы данных меньше, а их разметка ещё дороже. Каждая команда компьютерного зрения задаётся вопросом: можно ли предобучаться на дешёвых неразмеченных данных — кадрах YouTube, результатах веб-обходов, записях веб-камер, спутниковых съёмках — а затем дообучать модель на небольшом размеченном наборе?
Ответ — самообучение. Современный ViT с самообучением, обученный на LAION или JFT, после дообучения достигает точности ImageNet с учителем или превосходит её. Он также лучше переносится на последующие задачи (детекцию, сегментацию, оценку глубины), чем предобучение с учителем. DINOv2 (Meta, 2023) и MAE (Meta, 2022) — нынешние производственные стандарты для переносимых признаков компьютерного зрения.
Концептуальный сдвиг состоит в том, что предтекстовая задача — то, чему обучают модель, — не обязана быть последующей задачей. Важно, чтобы она заставляла модель изучать полезные признаки. Предсказывать цвет изображений в оттенках серого, поворачивать изображения и просить модель классифицировать поворот, маскировать патчи и восстанавливать их — всё это работало. Три подхода, которые масштабируются, — контрастивное обучение, дистилляция «учитель—ученик» и реконструкция по маске.
Концепция
Три семейства методов
Контрастивное обучение (SimCLR)
Возьмите одно изображение, примените два случайных аугментирования и получите два представления. Пропустите оба через один и тот же кодировщик с проекционной головой. Минимизируйте функцию потерь, которая утверждает: «эти два эмбеддинга должны быть близки» и «этот эмбеддинг должен быть далёк от эмбеддингов всех остальных изображений в пакете».
Loss for positive pair (z_i, z_j) among 2N views per batch:
L_ij = -log( exp(sim(z_i, z_j) / tau) / sum_k in batch \ {i} exp(sim(z_i, z_k) / tau) )
sim = cosine similarity
tau = temperature (0.1 standard)
Это функция потерь InfoNCE. Ей нужно много отрицательных примеров на каждый положительный, поэтому размер пакета важен: SimCLR нужны 512–8192. MoCo ввёл очередь моментов из прошлых пакетов, чтобы отделить число отрицательных примеров от размера пакета.
«Учитель—ученик» (DINO)
Две сети с одинаковой архитектурой: ученик и учитель. Учитель представляет собой экспоненциальное скользящее среднее (EMA) весов ученика. Обе сети видят аугментированные представления изображения. Выход ученика обучается совпадать с выходом учителя — без явных отрицательных примеров.
loss = CE( student_output(view_1), teacher_output(view_2) )
+ CE( student_output(view_2), teacher_output(view_1) )
teacher_weights = m * teacher_weights + (1 - m) * student_weights (m ≈ 0.996)
Почему метод не схлопывается к «предсказывай константу»: выход учителя центрируется (из каждого измерения вычитается среднее) и заостряется (делится на малую температуру). Центрирование не даёт одному измерению доминировать; заострение не даёт выходу схлопнуться к равномерному распределению.
DINO — это метод, который DINOv2 масштабирует на 142 млн отобранных изображений. Получающиеся признаки являются текущим SOTA для поиска визуальных данных без обучения на целевой задаче и плотного предсказания.
Реконструкция по маске (MAE)
Замаскируйте 75 % патчей входа ViT. Пропустите через кодировщик только видимые 25 %. Небольшой декодер получает выход кодировщика вместе с токенами маски в замаскированных позициях и обучается восстанавливать пиксели замаскированных патчей.
Encoder: visible 25% of patches -> features
Decoder: features + mask tokens at masked positions -> reconstructed pixels
Loss: MSE between reconstructed and original pixels on masked patches only
Ключевые проектные решения, благодаря которым MAE работает:
- Коэффициент маскирования 75 % — высокий. Он заставляет кодировщик изучать семантические признаки; восстанавливать 25 % было бы почти тривиально (соседние пиксели настолько коррелированы, что CNN справилась бы без труда).
- Асимметричные кодировщик и декодер — большой кодировщик ViT видит только видимые патчи; небольшой декодер (8 слоёв, 512 измерений) занимается реконструкцией. Предобучение в 3 раза быстрее, чем у наивного BEiT.
- Цель реконструкции в пространстве пикселей — она проще, чем токенизированная цель BEiT, и лучше работает с ViT.
После предобучения декодер отбрасывают. Кодировщик становится экстрактором признаков.
Почему 75 %, а не 15 %
BERT маскирует 15 % токенов. MAE маскирует 75 %. Разница обусловлена плотностью информации.
- Естественный язык имеет высокую энтропию на токен. Предсказать 15 % токенов всё ещё трудно, потому что у каждой замаскированной позиции много правдоподобных продолжений.
- Патчи изображений имеют низкую энтропию: незамаскированное окружение часто почти точно определяет пиксели замаскированного патча. Чтобы предсказание требовало семантического понимания, нужно маскировать агрессивно.
75 % достаточно много, чтобы простая пространственная экстраполяция не могла решить задачу; кодировщик должен представлять содержимое изображения.
Оценка линейным зондированием
После предобучения с самообучением стандартная оценка — линейный зонд: зафиксируйте кодировщик и обучите поверх него единственный линейный классификатор на метках ImageNet. Сообщается точность top-1.
- SimCLR ResNet-50: ~71 % (2020)
- DINO ViT-S/16: ~77 % (2021)
- MAE ViT-L/16: ~76 % (2022)
- DINOv2 ViT-g/14: ~86 % (2023)
Линейный зонд — чистая мера качества признаков; дообучение обычно добавляет 2–5 пунктов, но также смешивает в оценке эффект переобучения головы.
Соберите
Шаг 1: конвейер аугментирования двух представлений
import torch
import torchvision.transforms as T
two_view_train = lambda: T.Compose([
T.RandomResizedCrop(96, scale=(0.2, 1.0)),
T.RandomHorizontalFlip(),
T.ColorJitter(0.4, 0.4, 0.4, 0.1),
T.RandomGrayscale(p=0.2),
T.ToTensor(),
])
class TwoViewDataset(torch.utils.data.Dataset):
def __init__(self, base):
self.base = base
self.aug = two_view_train()
def __len__(self):
return len(self.base)
def __getitem__(self, i):
img, _ = self.base[i]
v1 = self.aug(img)
v2 = self.aug(img)
return v1, v2
Каждый __getitem__ возвращает два аугментированных представления одного изображения; метки не нужны.
Шаг 2: функция потерь InfoNCE
import torch.nn.functional as F
def info_nce(z1, z2, tau=0.1):
"""
z1, z2: (N, D) L2-normalised embeddings of paired views
"""
N, D = z1.shape
z = torch.cat([z1, z2], dim=0) # (2N, D)
sim = z @ z.T / tau # (2N, 2N)
mask = torch.eye(2 * N, dtype=torch.bool, device=z.device)
sim = sim.masked_fill(mask, float("-inf"))
targets = torch.cat([torch.arange(N, 2 * N), torch.arange(0, N)]).to(z.device)
return F.cross_entropy(sim, targets)
Перед вызовом нормализуйте эмбеддинги по L2. tau=0.1 — значение SimCLR по умолчанию; меньшее значение делает функцию потерь более резкой и требует больше отрицательных примеров.
Шаг 3: быстрая проверка InfoNCE
z1 = F.normalize(torch.randn(16, 32), dim=-1)
z2 = z1.clone()
loss_same = info_nce(z1, z2, tau=0.1).item()
z2_random = F.normalize(torch.randn(16, 32), dim=-1)
loss_random = info_nce(z1, z2_random, tau=0.1).item()
print(f"InfoNCE with identical pairs: {loss_same:.3f}")
print(f"InfoNCE with random pairs: {loss_random:.3f}")
Идентичные пары должны дать малую потерю (близкую к 0 для большого пакета и низкой температуры). Случайные пары должны дать log(2N-1) = ~log(31) = ~3.4 при пакете из 16 пар.
Шаг 4: маскирование в стиле MAE
def random_mask_indices(num_patches, mask_ratio=0.75, seed=0):
g = torch.Generator().manual_seed(seed)
n_keep = int(num_patches * (1 - mask_ratio))
perm = torch.randperm(num_patches, generator=g)
visible = perm[:n_keep]
masked = perm[n_keep:]
return visible.sort().values, masked.sort().values
num_patches = 196
visible, masked = random_mask_indices(num_patches, mask_ratio=0.75)
print(f"visible: {len(visible)} / {num_patches}")
print(f"masked: {len(masked)} / {num_patches}")
Просто, быстро и детерминированно для заданного seed. Реальные реализации MAE выполняют это пакетно и хранят отдельные маски для каждого примера.
Используйте
DINOv2 — производственный стандарт в 2026 году:
import torch
from transformers import AutoImageProcessor, AutoModel
processor = AutoImageProcessor.from_pretrained("facebook/dinov2-base")
model = AutoModel.from_pretrained("facebook/dinov2-base")
model.eval()
# Per-image embeddings for zero-shot retrieval
with torch.no_grad():
inputs = processor(images=[pil_image], return_tensors="pt")
outputs = model(**inputs)
embedding = outputs.last_hidden_state[:, 0] # CLS token
Получающийся 768-мерный эмбеддинг — основа современных конвейеров поиска изображений, плотных соответствий и переноса без обучения на целевой задаче. Для дообучения на последующей задаче редко требуется больше линейной головы.
Для эмбеддингов «изображение—текст» эквивалентом служат SigLIP или OpenCLIP; для дообучения в стиле MAE репозиторий timm предоставляет каждую контрольную точку MAE.
Внедрите
Этот урок создаёт:
outputs/prompt-ssl-pretraining-picker.md— промпт, выбирающий SimCLR / MAE / DINOv2 с учётом размера набора данных, вычислительных ресурсов и последующей задачи.outputs/skill-linear-probe-runner.md— навык, который пишет оценку линейным зондированием для любого зафиксированного кодировщика и размеченного набора данных.
Упражнения
- (Легко) Проверьте, что потеря InfoNCE уменьшается при снижении температуры для хорошо согласованных эмбеддингов и растёт при снижении температуры для случайных эмбеддингов. Постройте график
tau in [0.05, 0.1, 0.2, 0.5]в зависимости от потери. - (Средне) Реализуйте буфер центра в стиле DINO. Покажите, что без центрирования ученик за несколько эпох схлопывается к постоянному вектору.
- (Сложно) Обучите MAE на CIFAR-100, используя TinyUNet из урока 10 как основу. Сообщите точность линейного зонда на 10, 50 и 200 эпохах. Покажите, что линейный зонд с предобучением MAE превосходит линейный зонд с обучением с учителем с нуля на том же подмножестве из 1 000 изображений.
Ключевые термины
| Термин | Что обычно говорят | Что это на самом деле означает |
|---|---|---|
| Самообучение | «Без меток» | Предтекстовая задача, создающая полезные представления из неразмеченных данных |
| Предтекстовая задача | «Искусственная задача» | Цель, используемая во время SSL (восстанавливать патчи, сопоставлять представления); отбрасывается после предобучения |
| Линейный зонд | «Зафиксированный кодировщик + линейная голова» | Стандартная оценка SSL: обучается только линейный классификатор поверх зафиксированных признаков |
| InfoNCE | «Контрастивная функция потерь» | softmax по косинусным сходствам; положительная пара — целевой класс, все остальные — отрицательные примеры |
| Учитель EMA | «Учитель со скользящим средним» | Учитель, чьи веса являются экспоненциальным скользящим средним весов ученика; используется в BYOL, MoCo, DINO |
| Коэффициент маскирования | «% скрытых патчей» | Доля патчей, маскируемых при MAE; 75 % для зрения, 15 % для текста |
| Схлопывание представлений | «Постоянный выход» | Сбой SSL, при котором кодировщик выдаёт постоянный вектор для всех входов; предотвращается центрированием, заострением или отрицательными примерами |
| DINOv2 | «Производственная основа SSL» | Самообучаемый ViT Meta 2023 года; наиболее сильные универсальные признаки изображений в 2026 году |
Дополнительное чтение
- SimCLR (Chen et al., 2020) — справочный материал по контрастивному обучению
- DINO (Caron et al., 2021) — «учитель—ученик» с моментом, центрированием и заострением
- MAE (He et al., 2022) — предобучение маскированного автокодировщика для ViT
- DINOv2 (Oquab et al., 2023) — масштабирование ViT с самообучением до производственных признаков
Источник: Self-Supervised Vision — SimCLR, DINO, MAE 04.16 — Полный конвейер компьютерного зрения: итоговый проект · Фаза 04 — Компьютерное зрение · 04.18 — Зрение с открытым словарём — CLIP · Полный каталог