Files
Pavlenko_disser/notes/Взвешенное_управление_Residual_Branch.md
2026-05-05 14:00:36 +03:00

5.2 KiB
Raw Blame History

tags, aliases
tags aliases
диссер
fusion
residual
gate
adaptive
архитектура
Adaptive Alpha
Residual Routing

Взвешенное управление Residual Branch

Постановка задачи

Вывод из экспериментов с Gate+Sum: фиксированный residual пропускает шум при выпадении текстовой модальности, нивелируя работу шлюза.

Решение: заменить фиксированный коэффициент (α=1) на обучаемый per-sample скаляр α, который модель учится предсказывать исходя из состояния модальностей.

fused = gate_output + α · residual

Три варианта реализации

Вариант 1 — Энтропийный сигнал

Считать энтропию признакового вектора на батче и использовать как сигнал:

H(x) = -Σ p_i · log(p_i),  где p_i = softmax(|x|)_i
Высокая H → неопределённость → отсекать residual

Проблема: энтропия плохо коррелирует с информативностью модальности в UAV-задаче. Размытое изображение даёт низкую энтропию (однородный сигнал) — модель ошибочно считает его надёжным.

Статус: отклонён по результатам измерений (Pearson r ≈ 0 между H(img_vec) и g).


Вариант 2 — Learned scalar per-sample ✓ (основной)

self.alpha_net = nn.Linear(proj_dim * 2, 1)

# forward:
cat_vec = torch.cat([img_vec, text_vec], dim=-1)  # (B, 2D)
alpha   = torch.sigmoid(self.alpha_net(cat_vec))  # (B, 1)
fused   = gate_output + alpha * residual

При text_vec = zeros сеть получает другой вход и выучивает alpha → 0.

Инициализация (нейтральный старт, alpha=0.5):

nn.init.zeros_(self.alpha_net.weight)
nn.init.constant_(self.alpha_net.bias, 0.0)  # sigmoid(0) = 0.5

Математическое обобщение:

  • Gate-Fusion (α=0) — один предельный случай
  • Gate+Sum (α=1) — другой предельный случай
  • Adaptive-α — непрерывная интерполяция между ними

Вариант 3 — Явный флаг присутствия модальности (расширение)

self.alpha_net = nn.Linear(proj_dim * 2 + 1, 1)

# forward:
text_present = (text_vec.abs().sum(dim=-1, keepdim=True) > 0).float()  # (B, 1)
alpha_input  = torch.cat([img_vec, text_vec, text_present], dim=-1)    # (B, 2D+1)
alpha        = torch.sigmoid(self.alpha_net(alpha_input))

Модель явно знает что текст отсутствует — не угадывает по нулям.

Примечание: при архитектуре с двумя головами (fused_head + img_head) и text-dropout флаг менее критичен — механизм двух голов создаёт неявный обучающий сигнал для alpha через разницу потерь.


Вариант 4 — Concat residual с projection (полная версия)

self.residual_proj = nn.Linear(proj_dim * 2, proj_dim)
self.alpha_net     = nn.Linear(proj_dim * 2, 1)

# forward:
cat_vec  = torch.cat([img_vec, text_vec], dim=-1)   # (B, 2D)
residual = self.residual_proj(cat_vec)               # (B, D)
alpha    = torch.sigmoid(self.alpha_net(cat_vec))    # (B, 1)
fused    = gate_output + alpha * residual

Residual содержит информацию обеих модальностей через проекцию, а не простую сумму.


Ablation таблица

Метод Residual alpha Параметры
Gate (no residual) 0 baseline
Gate + Sum img + text 1 (fixed) 0 доп.
Adaptive-α v2 img + text learned, 2D→1 минимум
Adaptive-α v3 img + text + flag learned, 2D+1→1 +1 вход
Adaptive-α + proj proj(cat(img,text)) learned, 2D→1 2D→D + 2D→1

Почему LayerNorm не решает проблему масштаба

LayerNorm нормирует по признакам одного сэмпла постфактум — он не различает:

fused = img + text + img*g + text*(1-g)   # текст присутствует
fused = img + 0   + img*g + 0             # текст = zeros

Смысловое содержание разное, но после LN оба вектора имеют одинаковый масштаб. Адаптивный α действует до LN и меняет структуру вектора — формирует осмысленную композицию до нормализации.


Связанные заметки