Files
caption-test/DIAGNOSTIC_DSS_MoCo_2026-04-25.md
2026-04-27 11:57:29 +03:00

11 KiB
Raw Permalink Blame History

Диагностика: коллапс recall на эпохе 1 — DSS + MoCo queue

Дата: 2026-04-25 Конфиг: conf/gtauav_balanced.gin (gate=0.7, with text) Запуск: python -m src.training.train_gtauav --config conf/gtauav_balanced.gin --filter-meta meta/seg_filter.json


1. Симптомы из лога

Метрики по эпохам

Эпоха Режим сэмплера LR train loss train R@1 val R@1 val AP eval loss
ep0 mutex-only (warmup) 5.00e-05 4.2239 0.0742 0.0758 0.1511 2.0783
ep1 DSS активирован, MoCo queue полная 1.00e-04 4.4218 ↑ 0.0120 ↓6× 0.0107 0.0328 2.0786

Ключевые наблюдения

  • Recall обвалился ровно на эпохе включения DSS (warmup=1, поэтому DSS стартует на ep1)
  • Train loss выросла (4.22 → 4.42), хотя должна падать
  • Eval loss практически стоит (2.0783 → 2.0786) — модель не учится на чистом батч-сигнале
  • Разрыв train/eval loss > 2× — большая часть train loss идёт от MoCo+hard-mining компонент, не от in-batch contrast
  • Gate stable: gate_q=0.70, gate_g=0.70 (текст не вытаскивает дополнительный градиент)
  • tau=0.07 (clamped, learnable, но почти не двигается → loss не учит температуру)

Сбой при сохранении чекпойнта

RuntimeError: [enforce fail at inline_container.cc:668] .
unexpected pos 289048128 vs 289048016

Причина: диск переполнен (ENOSPC). Подтверждено независимо: mkdir в session-env тоже падает с ENOSPC. Это инфраструктурный баг, не алгоритмический — но он не даёт сохранить состояние и продолжить.


2. Почему DSS «не работает» на этом этапе

2.1. Mutex-constraint спасает от false negatives только формально

Mutex исключает дронов с пересекающимися sat_candidates. Но DSS специально пакует визуально похожих дронов — у которых sat-кандидаты могут быть разными tiles, но при этом сцены практически идентичные:

  • один и тот же район Лос-Сантоса
  • та же высота полёта
  • та же time-of-day, та же погода (синтетика GTA-V)

Для холодного энкодера такие «negatives» неотличимы от позитива → softmax пытается развести то, что развести нечем → градиенты шумные и противоречивые.

2.2. Re-embed раз в эпоху — слишком редко в начале обучения

  • На ep1 LR удваивается (5e-5 → 1e-4 после warmup)
  • Encoder за эпоху смещается сильно (MONA-адаптеры учатся быстро)
  • Батчи внутри эпохи собираются по embeddings, посчитанным до этих обновлений
  • То есть «similarity» в DSS — это similarity вчерашнего энкодера
  • Re-embed на ep1 занял 313s, но между двумя re-embed encoder успевает измениться существенно

2.3. Эпохи 0 на mutex-only недостаточно как warmup

  • К моменту запуска DSS R@1=0.074 на полной gallery (~2684 уникальных тайлов)
  • Random baseline ≈ 1/2684 ≈ 0.0004
  • 0.074 — это «модель чуть-чуть оторвалась от случая», но качество embeddings ещё недостаточно
  • DSS усиливает шум, а не сигнал: «визуально похожих» определяет шумный энкодер

3. Почему MoCo queue делает хуже

3.1. Representation drift в queue

  • Queue хранит 4096 embeddings, посчитанных в разные моменты времени разными версиями encoder
  • На ep01, когда MONA-адаптеры учатся быстро, разница между «свежим» и «3 шага назад» embedding'ом — заметная
  • Эти устаревшие негативы дают сигнал в направлении, в котором энкодер уже не находится
  • Без momentum encoder (как в оригинальном MoCo) drift ничем не сглажен

3.2. hard_mining_k=512 амплифицирует ошибку queue

  • Из 4096 берутся 512 «самых трудных»
  • «Трудность» меряется в текущем feature space
  • Сами вектора лежали там в старом feature space
  • На холодном энкодере это эквивалентно «учиться отличать себя-позитива от себя-вчерашнего»
  • Loss растёт, recall падает

3.3. Тройная hard-negative композиция → collapse-режим

Все три механизма независимо подсовывают «трудные» негативы:

Механизм Источник трудности
DSS визуально близкие в батче
Mutex sampler in-batch contrast после фильтра
hard_mining_k=512 top-K из MoCo queue

На warm encoder это polish; на cold encoder это too-hard negatives problem (известная failure mode у contrastive learning, Robinson et al., 2021):

  • Модель не получает «лёгких» примеров, на которых формируется базовое embedding-пространство
  • Градиенты толкают её в произвольных направлениях
  • Embedding space коллапсирует или размывается

4. Подтверждения из истории коммитов

8f8cbb1 Diagnostic baseline v2: also disable MoCo queue
c25bd64 Diagnostic baseline: disable DSS + hard mining, fresh output dir
9a7fbff Fix plot_combined: fallback from 'total' to 'train_loss'
70f1617 Fix autograd in-place error: move memory-bank enqueue after backward
8197ab2 Fix training loop: only pass positive_weights to WeightedInfoNCELoss

Подозрение на DSS+MoCo уже было — текущие числа подтверждают его эмпирически.


5. Рекомендации

5.1. Cold-start curriculum (приоритет)

  1. Несколько эпох mutex-only без MoCo и без hard_mining до R@1 хотя бы ~0.2 на train.
    • Конкретно: sampler_type="mutex", loss.use_memory_bank=False, loss.hard_mining_k=0.
  2. Затем включить MoCo queue с warm-up: либо momentum encoder, либо queue pre-fill 1 эпоху со stop_grad на queue updates.
  3. DSS включать только после того, как embeddings стали discriminative (R@1 на train > 0.2). Иначе «similar» = «random».
  4. hard_mining_k стартует с 0 и поднимается curriculum-схемой (например, 0 → 64 → 256 → 512 по эпохам).

5.2. Изменения по DSS

  • Сократить интервал re-embed (раз в N шагов, не раз в эпоху) — минимум первые 2-3 эпохи
  • Или временно фиксировать кеш embeddings из чистого baseline (без DSS) и использовать его как «референсный» для сэмплинга

5.3. Изменения по MoCo

  • Добавить momentum encoder (EMA на ключи, как в оригинальном MoCo) — это решает drift
  • Либо очищать queue на каждой эпохе (теряем эффект, но избегаем drift)
  • Размер queue 4096 при batch 64 → 64 батча в очереди = слишком долгая история для холодного энкодера

5.4. Инфраструктура

  • Освободить диск (ENOSPC блокирует чекпойнты и часть утилит)
  • Возможно, перенести out/gtauav/ на другой диск или почистить старые runs
  • Добавить pre-flight disk check перед torch.save

6. План эксперимента для подтверждения

Run Sampler MoCo queue hard_mining_k Цель
A (clean baseline) mutex off 0 Подтвердить, что без DSS/MoCo recall растёт нормально
B (only MoCo) mutex on 0 Изолировать вклад queue
C (only hard_mining) mutex on 512 Изолировать вклад top-K mining
D (only DSS) dss off 0 Изолировать вклад DSS
E (full, current) dss on 512 Reproduce coллапс

Decision rule:

  • Если A учится нормально (R@1 растёт монотонно), а E коллапсирует — это decisive ablation
  • Если B/C/D по отдельности тоже коллапсируют — проблема в каждом компоненте
  • Если только E коллапсирует — проблема в композиции

7. Альтернативная гипотеза (менее вероятная)

LR=1e-4 на проекциях после warmup может быть слишком большим для shared DINOv3 + MONA с малым trainable %. Симптомы похожи (резкий обвал на эпохе с полным LR), но не объясняют, почему mutex-only baseline (commit c25bd64) учится нормально без изменения LR. Так что это вторичный фактор.


8. Резюме

Главный диагноз: связка DSS + MoCo queue + hard_mining_k=512 создаёт too-hard negatives problem на холодном энкодере. Каждый компонент по отдельности рассчитан на warm encoder; их композиция на ep1 (когда R@1 ещё ~0.07) делает задачу нерешаемой и приводит к коллапсу embedding space.

Решение: curriculum — сначала mutex+CE без queue/mining до R@1≈0.2, потом постепенно включать остальные механизмы.

Блокер: диск переполнен (ENOSPC), без освобождения места дальнейшее обучение и сохранение чекпойнтов невозможно.