--- tags: [диссер, fusion, residual, gate, adaptive, архитектура] aliases: [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 ✓ (основной) ```python 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): ```python 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 — Явный флаг присутствия модальности (расширение) ```python 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 (полная версия) ```python 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 и меняет структуру вектора — формирует осмысленную композицию до нормализации. --- ## Связанные заметки - [[DEQFusion_ProgressiveFusion]] - [[Metadata_Insertion]]