File size: 1,808 Bytes
6857ec0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
"""Projecteurs multimodaux : alignent image/audio sur l'espace texte (Phases 4-8).

Idée : les encodeurs image/audio produisent des features de dimension propre. Pour
que le décodeur texte puisse les lire, un petit **MLP** projette ces features dans
la dimension du texte (`text_dim`). On insère alors ces vecteurs dans la séquence
de tokens texte, encadrés par des tokens de modalité (`<|image_start|>` …).

Choix d'un MLP (2 couches + GELU) plutôt qu'une projection linéaire : il apprend
une transformation non linéaire, ce qui aide l'alignement, pour un coût modeste.

Justification complète : docs/architecture.md §5.
"""

from __future__ import annotations

import torch
import torch.nn as nn


class MLPProjector(nn.Module):
    """MLP ``in_dim -> hidden -> out_dim`` avec GELU et LayerNorm optionnelle."""

    def __init__(
        self,
        in_dim: int,
        out_dim: int,
        hidden_dim: int | None = None,
        dropout: float = 0.0,
        use_norm: bool = True,
    ):
        super().__init__()
        hidden_dim = hidden_dim or out_dim
        layers: list[nn.Module] = []
        if use_norm:
            layers.append(nn.LayerNorm(in_dim))
        layers += [
            nn.Linear(in_dim, hidden_dim),
            nn.GELU(),
            nn.Linear(hidden_dim, out_dim),
        ]
        if dropout > 0:
            layers.append(nn.Dropout(dropout))
        self.net = nn.Sequential(*layers)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        return self.net(x)


def build_projector(in_dim: int, text_dim: int, hidden_dim: int | None = None,
                    dropout: float = 0.0) -> MLPProjector:
    """Fabrique un projecteur vers l'espace texte (helper)."""
    return MLPProjector(in_dim, text_dim, hidden_dim=hidden_dim, dropout=dropout)