Gated DeltaNet¶
Les 69 couches d'attention linéaire, projection par projection.
Ce que ce chapitre reconstruit¶
config.json donne huit valeurs pour l'attention linéaire :
"linear_num_value_heads": 128,
"linear_num_key_heads": 16,
"linear_key_head_dim": 128,
"linear_value_head_dim": 128,
"linear_conv_kernel_dim": 4,
"output_gate_type": "swish",
"mamba_ssm_dtype": "float32",
"model_type": "qwen3_5_moe_text"
Huit valeurs, et le nom de classe Qwen3_5MoeForCausalLM qui identifie le code
exécuté. De cela découle toute la structure décrite ci-dessous.
Prérequis
Le mécanisme conceptuel — état récurrent, règle delta, portes — est introduit dans Fondations · 03. Ce chapitre en donne la réalisation concrète dans ce modèle précis.
Le chemin dans une couche¶
x (8 192)
│
├──→ in_proj_qkvz ──→ q (2 048) │ k (2 048) │ v (16 384) │ z (16 384)
│ │ │ │ │
├──→ in_proj_ba ──→ β (128) │ a (128) │ │
│ │ │ │ │
│ ┌────┴───────────┴───────────┘ │
│ │ convolution causale, noyau 4 │
│ ▼ │
│ ┌──────────────────────────────┐ │
│ │ récurrence Gated DeltaNet │ │
│ │ S ← S(I − βkkᵀ)·α + βkvᵀ │ │
│ └──────────────┬───────────────┘ │
│ ▼ │
│ o (16 384) ──────→ × swish(z) ←──────┘
│ │
│ ▼
│ out_proj (16 384 → 8 192)
│ │
└────────────────────────── (+) ─────────────────┘
│
▼ vers le bloc MoE
Les projections d'entrée¶
in_proj_qkvz — la grosse¶
Une seule matrice produit quatre tenseurs :
| Tenseur | Rôle | Dimension | Calcul |
|---|---|---|---|
| \(q\) | requêtes | 2 048 | \(16 \times 128\) |
| \(k\) | clés | 2 048 | \(16 \times 128\) |
| \(v\) | valeurs | 16 384 | \(128 \times 128\) |
| \(z\) | porte de sortie | 16 384 | \(128 \times 128\) |
Soit une matrice \(8\,192 \times 36\,864\) :
302 M de paramètres, soit 69 % du coût de la couche.
La dissymétrie 16 / 128 est le point clé
16 têtes de clé, mais 128 têtes de valeur. Huit têtes de valeur partagent chaque tête de clé.
C'est le même principe que GQA dans l'attention classique, appliqué ici à l'espace de la mémoire récurrente : l'état \(S\) est de taille \(d_k \times d_v\), donc réduire \(d_k\) réduit l'état quadratiquement. Avec 16 têtes de clé au lieu de 128, l'état est huit fois plus petit.
in_proj_ba — la petite¶
Produit deux scalaires par tête de valeur :
| Tenseur | Rôle |
|---|---|
| \(\beta\) | taux d'écriture de la règle delta, une valeur par tête |
| \(a\) | facteur de décroissance \(\alpha\), une valeur par tête |
Deux millions de paramètres pour piloter, jeton par jeton et tête par tête, ce qu'on écrit et ce qu'on oublie. C'est peu de paramètres pour beaucoup de contrôle.
La convolution causale¶
"linear_conv_kernel_dim": 4
Avant la récurrence, \(q\), \(k\) et \(v\) passent par une convolution causale de noyau 4 : chaque position est mélangée avec les trois précédentes.
Négligeable en taille, mais pas en fonction.
Pourquoi cette convolution existe
L'état récurrent est une mémoire approximative. La convolution donne au mécanisme une mémoire exacte sur une fenêtre courte — de quoi capter les dépendances locales immédiates (accord grammatical, ouverture et fermeture d'un délimiteur) sans les faire transiter par l'état.
C'est un héritage direct des architectures à espace d'états, Mamba en tête.
Le champ mamba_ssm_dtype dans la configuration trahit d'ailleurs cette
filiation.
La récurrence¶
Le cœur, tête par tête :
| Symbole | Signification | Dimensions ici |
|---|---|---|
| \(S_t\) | état de la tête après le jeton \(t\) | \(128 \times 128\) |
| \(\mathbf{k}_t, \mathbf{q}_t\) | clé et requête | 128 |
| \(\mathbf{v}_t\) | valeur | 128 |
| \(\alpha_t \in\, ]0,1[\) | décroissance globale, issue de \(a\) | scalaire |
| \(\beta_t \in\, ]0,1[\) | taux d'écriture, issu de \(\beta\) | scalaire |
Trois lectures superposées :
- \(\alpha_t\) seul (\(\beta_t = 0\)) : l'état s'estompe uniformément. C'est l'attention linéaire gatée classique.
- \(\beta_t\) seul (\(\alpha_t = 1\)) : l'état remplace l'association liée à \(\mathbf{k}_t\) et ne touche pas au reste. C'est la règle delta pure.
- Les deux : oubli progressif du tout, remplacement précis du concerné. C'est Gated DeltaNet.
L'intuition en une image
Un tableau blanc. \(\alpha_t\) estompe légèrement tout ce qui est écrit. \(\beta_t\) efface une ligne précise et la réécrit.
Un modèle qui ne saurait qu'estomper perdrait tout uniformément ; un modèle qui ne saurait que réécrire finirait par saturer. Il faut les deux.
La porte de sortie¶
"output_gate_type": "swish"
La sortie de la récurrence est multipliée terme à terme par la projection \(z\) passée dans une fonction swish :
où \(\odot\) est le produit terme à terme et \(\sigma\) la sigmoïde.
Rôle : permettre à la couche de supprimer sa propre sortie quand elle n'a rien d'utile à apporter pour ce jeton. Sans porte, chaque couche injecte inconditionnellement quelque chose dans le flux résiduel, ce qui bruite les couches suivantes.
C'est le même principe qui a rendu les LSTM viables il y a trente ans, remis au goût du jour.
Le décompte¶
| Composant | Paramètres |
|---|---|
in_proj_qkvz |
301 989 888 |
in_proj_ba |
2 097 152 |
| convolution causale | 81 920 |
out_proj (\(16\,384 \times 8\,192\)) |
134 217 728 |
| normalisation | 128 |
| Total par couche | 438 386 816 |
| × 69 couches | 30,25 G |
Vérifié par le script joint.
L'état, en mémoire¶
Par couche et par tête : \(128 \times 128 = 16\,384\) nombres. Pour 128 têtes :
En float32 — mamba_ssm_dtype: "float32" — soit 8,4 Mo par couche, et
0,58 Go pour les 69 couches.
Ce chiffre ne bouge jamais
Mille jetons ou un million : l'état pèse 0,58 Go. C'est la propriété qui rend le contexte long abordable, et c'est exactement l'inverse du comportement d'un cache clé-valeur.
Voir Contexte 262 K et 1 M.
Le float32 n'est pas un détail
L'état est une accumulation sur potentiellement un million de mises à jour multiplicatives. En BF16, l'erreur d'arrondi s'accumulerait jusqu'à dégrader le rappel. Qwen impose donc le float32 pour cet état précis, alors que tout le reste du modèle est en BF16.
C'est une contrainte de mise en œuvre à connaître si l'on réimplémente.
À retenir¶
Ce chapitre en cinq points
- Une couche DeltaNet coûte 438 M de paramètres, dont 69 % dans la seule projection d'entrée.
- La dissymétrie 16 têtes de clé / 128 têtes de valeur réduit l'état récurrent d'un facteur 8.
- Une convolution causale de noyau 4 fournit une mémoire locale exacte en complément de l'état approximatif.
- La récurrence combine décroissance \(\alpha\) et règle delta \(\beta\) — oublier globalement, remplacer précisément.
- L'état pèse 0,58 Go au total, indépendamment de la longueur, et est maintenu en float32.
Chapitre suivant : L'attention complète gatée — les 23 couches d'ancrage.