• Introduction
  • Annexe
    • Pourquoi diviser par ?
    • Attention Multi-Têtes
  • Accueil
  • Articles
  • Notes
  • Livres
  • Auteur
🇺🇸 en 🇨🇳 zh 🇮🇳 ml

Nathaniel Thomas

Les Mécanismes de l'Attention Causale

13 novembre 2024

Introduction

L’attention causale est le mécanisme à la base de la plupart des avancées en IA depuis 2017. Dans cet article, je vais détailler le calcul et, espérons-le, acquérir une meilleure intuition de son fonctionnement.

SelfAttention(Q,K,V)=softmax(mask(d​QKT​))V

À un niveau élevé, cette fonction prend une séquence et la transforme en une autre. Une séquence est une liste d’embeddings de tokens, un tenseur de forme L×d, où L est la longueur de la séquence d’entrée et d est la dimension de l’embedding. Chaque ligne de cette matrice correspond à un token d’entrée, représenté comme un vecteur de dimension d.

Alors pourquoi y a-t-il 3 entrées pour SelfAttention ? C’est parce que, dans l’architecture Transformer, la séquence d’entrée est projetée par 3 couches linéaires différentes de taille d×d. Si X est la séquence d’entrée,

Q=XWQ​,K=XWK​,V=XWV​

où WQ​,WK​,WV​ sont de taille d×d. Ainsi, Q,K,V sont simplement des représentations différentes de la même séquence d’entrée.

Calculons SelfAttention étape par étape. D’abord, nous effectuons QKT, qui est un produit scalaire de L×d par d×L, résultant en une sortie de taille L×L. Que fait cette opération ?

QKT=​q1​q2​⋮qL​​​[k1T​​k2T​​⋯​kLT​​]=​q1​k1T​q2​k1T​⋮qL​k1T​​q1​k2T​q2​k2T​⋮qL​k2T​​⋯⋯⋱⋯​q1​kLT​q2​kLT​⋮qL​kLT​​​​

Le résultat de qi​kjT​ est un scalaire ( 1×d produit scalaire d×1), et il représente le produit scalaire entre qi​ et kj​. Si nous nous rappelons de la formule

a⋅b=∥a∥∥b∥cosθ

nous voyons que le produit scalaire est positif lorsque θ, l’angle entre a et b, est proche de 0º et négatif lorsque l’angle est de 180º, ou lorsqu’ils pointent dans des directions opposées. Nous pouvons interpréter le produit scalaire comme une métrique de similarité, où les valeurs positives indiquent des vecteurs similaires, et les valeurs négatives indiquent le contraire.

Ainsi, notre matrice finale L×L est remplie de scores de similarité entre chaque paire de tokens q et k. Le résultat est divisé par d​ pour éviter que la variance n’explose pour de grandes dimensions d’embedding. Voir Annexe pour plus de détails.

L’étape suivante consiste à appliquer la fonction mask, qui définit toutes les valeurs qui ne sont pas dans la section triangulaire inférieure de la matrice d’entrée à −∞.

mask(d​1​QKT)=d​1​​q1​k1T​q2​k1T​q3​k1T​⋮qL​k1T​​−∞q2​k2T​q3​k2T​⋮qL​k2T​​−∞−∞q3​k3T​⋮qL​k3T​​⋯⋯⋯⋱⋯​−∞−∞−∞⋮qL​kLT​​​

À cela, nous appliquons softmax, qui convertit chaque ligne de valeurs de la matrice en une distribution de probabilité. La fonction est définie comme une application de RL→RL, où le ième élément de sortie est donné par

softmax(x)i​=∑j=1L​exj​exi​​pour i=1,2,…,L

Deux choses à noter ici :

  1. La somme de tous les éléments de sortie est 1, comme attendu pour une distribution de probabilité.
  2. Si un élément d’entrée xi​ est −∞, alors softmax(x)i​=0.

Après avoir appliqué la fonction softmax aux scores de similarité masqués, nous obtenons :

S=softmax(mask(d​1​QKT))=​S1,1​S2,1​S3,1​⋮SL,1​​0S2,2​S3,2​⋮SL,2​​00S3,3​⋮SL,3​​⋯⋯⋯⋱⋯​000⋮SL,L​​​

Où les entrées Si,j​ sont définies comme :

Si,j​=∑k=1L​emask(d​QKT​)i,k​emask(d​QKT​)i,j​​

La matrice résultante S a des lignes de distribution de probabilité de longueur L. La dernière étape consiste à mapper notre matrice de valeurs V par ces distributions de probabilité pour obtenir notre nouvelle séquence.

SelfAttention(Q,K,V)​=SV=​S1,1​S2,1​S3,1​⋮SL,1​​0S2,2​S3,2​⋮SL,2​​00S3,3​⋮SL,3​​⋯⋯⋯⋱⋯​000⋮SL,L​​​​V1​V2​V3​⋮VL​​​=​S1,1​V1​S2,1​V1​+S2,2​V2​S3,1​V1​+S3,2​V2​+S3,3​V3​⋮SL,1​V1​+SL,2​V2​+⋯+SL,L​VL​​​​​

Notez que Si,j​ est un scalaire, et Vk​ est un vecteur d’embedding de taille 1×d. Visuellement, nous observons que SelfAttention combine sélectivement les tokens de valeur, pondérés par une distribution de probabilité générée par la manière dont les requêtes et les clés s’attendent mutuellement, c’est-à-dire ont un grand produit scalaire. Nous voyons également que le poids d’un token de sortie à l’indice i ne dépend que des tokens d’entrée avec un indice ≤i, en raison du masque causal que nous avons appliqué précédemment. Cela repose sur l’hypothèse causale, selon laquelle un token de sortie Oi​ ne dépend pas des tokens futurs, ce qui est nécessaire lors de l’entraînement de modèles autoregressifs (c’est-à-dire la prédiction du token suivant).

J’espère que vous avez trouvé cela utile !

Annexe

Pourquoi diviser par d​ ?

Nous faisons cela pour éviter que la variance n’explose lorsque d augmente.

Supposons que qi​,ki​∼N(μ=0,σ2=1) et i.i.d. Calculons la moyenne et la variance de s=q⋅k non divisé.

La moyenne est trivialement nulle :

E[s]=E[i=1∑d​qi​ki​]=i=1∑d​E[qi​ki​]=i=1∑d​E[qi​]E[ki​]=0

Et la variance est :

Var(s)=E[s2]−(E[s])2=E[s2]=d

car

E[s2]=E[i=1∑d​j=1∑d​qi​ki​qj​kj​]=i=1∑d​j=1∑d​E[qi​ki​qj​kj​]

qui est 0 pour i=j (puisque qi​,qj​ et ki​,kj​ sont i.i.d). Pour i=j,

i=1∑d​E[qi2​ki2​]=i=1∑d​E[qi2​]E[ki2​]=i=1∑d​1⋅1=d

puisque E[qi2​]=E[ki2​]=σ2=1.

Ainsi, si nous divisons par 1/d​, notre nouvelle variance est

Var(d​s​)=d1​Var(s)=1

comme souhaité.

Attention Multi-Têtes

La plupart des systèmes modernes utilisent l’attention multi-têtes, qui calcule SelfAttention en parallèle sur plusieurs “têtes”. Nous laissons généralement dk​=dv​=dmodel​/H, où H est le nombre de têtes.

Qh​Kh​Vh​​=XWhQ​=XWhK​=XWhV​​WhQ​∈Rdmodel​×dk​WhK​∈Rdmodel​×dk​WhV​∈Rdmodel​×dv​​​ headh​=SelfAttention(Qh​,Kh​,Vh​)=softmax(mask(dk​​Qh​KhT​​))Vh​ MultiHead(Q,K,V)​=Concat(head1​,head2​,…,headH​)​

←
Un bot expert pour 2048
Approximation Locale
→

back to top