Modifier les poids d'un LLM à la main

J’ai écrit une implémentation from scratch de ROME — modification de modèle de rang 1 — en utilisant uniquement torch et transformers. L’objectif : réécrire un fait unique à l’intérieur de GPT-2 Medium avec une seule addition matricielle, et observer ce qui arrive à tout ce que le modèle sait par ailleurs.

J’ai effectué quatre modifications. Trois étaient chirurgicales. La quatrième a révélé que le caractère « chirurgical » de ROME est extrêmement sensible à des détails d’implémentation auxquels on ne pense pas forcément au départ.

Les quatre modifications

J’ai sélectionné des faits que GPT-2 Medium connaît réellement avec confiance (P > 0,5 sur la bonne réponse) dans quatre domaines différents :

SujetFait originalModifié en
Harvard Universitydans le MassachusettsCalifornie
Googleen CalifornieTexas
Tacosdu MexiqueJapon
Statue of Libertyà New YorkLas Vegas

Les quatre modifications ont atteint leur cible. Après la mise à jour, le modèle prédisait la nouvelle réponse avec une probabilité ≥ 0,98 pour le prompt de modification exact. Donc ROME fonctionne. Ce qui varie, c’est tout le reste.

Les trois modifications propres

Trois des quatre modifications se sont comportées à peu près comme le prédit l’article ROME. Voici ce qui est arrivé aux faits non liés après chaque modification :

Tacos → Japon (norme de mise à jour : 9% de la norme des poids)

ContrôleAprès
Sushi du Japon✓ inchangé
Pizza d’Italie✓ inchangé
Ramen du Japon✓ inchangé
Burritos du Mexique→ Japon

Seuls les Burritos, le voisin le plus proche dans l’espace de la cuisine mexicaine, ont été entraînés.

Harvard → Californie (norme de mise à jour : 13%)

ContrôleAprès
MIT dans le Massachusetts✓ inchangé (toujours flou)
Capitale du Massachusetts = Boston✓ inchangé
Boston dans le Massachusetts✓ inchangé
Yale dans le Connecticut→ Californie

Yale — le voisin le plus proche de Harvard dans l’espace des universités de l’Ivy League — a suivi. Rien d’autre n’a bougé.

Statue of Liberty → Las Vegas (norme de mise à jour : 16%)

ContrôleAprès
Times Square à New York✓ inchangé
New York City à New York✓ inchangé
Empire State Buildingcontesté (New 0,49 vs Las 0,26)
Liberty Bell à Philadelphie→ Las Vegas

Deux monuments ont vacillé. Le Liberty Bell est particulièrement amusant — il n’est pas à NY, mais il partage le mot « Liberty » et GPT-2 les a confondus.

Donc : modifications directes propres, dommages collatéraux limités, magnitudes de mise à jour raisonnables (9–16%).

Le modèle a également fabriqué allègrement des histoires alternatives cohérentes pour correspondre aux modifications. Mon préféré : après avoir déplacé Harvard en Californie, à la question de sa date de fondation, le modèle a répondu « 1776 par le père jésuite français Charles de Montesquieu. » Phrase complète, cohérente en interne, totalement fausse. Ce sont les a priori du modèle (« Harvard est prestigieux, les lieux célèbres ont des fondateurs célèbres ») qui comblent le vide laissé par un fait réel.

La modification chaotique : Google

La modification de Google s’est mal passée. Mon premier essai a rapporté une norme de mise à jour de 117% — la modification de rang 1 était plus grande que la norme de la matrice de poids elle-même — et a fait s’effondrer tout le cluster technologique californien :

J’avais écrit un article de blog avec ça comme découverte principale. Puis j’y ai réfléchi davantage et j’ai réalisé que 117% était suspect. Une modification de rang 1 ne devrait pas être plus grande que ce qu’elle modifie.

Débogage de Google

Deux choses s’avéraient incorrectes.

Problème 1 : ma covariance était sous-estimée

La formule de mise à jour de ROME repose sur C, la covariance des vecteurs intermédiaires (post-GELU) à la couche cible :

u = torch.linalg.solve(C + lambda * I, h_star)
delta_W = (u / (h_star @ u)).unsqueeze(1) @ (v_star - W @ h_star).unsqueeze(0)

La direction C⁻¹ @ h* est ce qui rend la modification sélective — elle est alignée avec h* mais orthogonale aux clés typiques. Si C est mal conditionnée, C⁻¹ @ h* explose dans les directions à faibles valeurs propres, et la mise à jour devient énorme.

J’estimais C à partir de 200 échantillons WikiText — environ 10 600 tokens. Pour une matrice de covariance 4096×4096, c’est ~2,5 échantillons par dimension. La matrice était sévèrement déficiente en rang. J’avais une régularisation 1e-4 * I, ce qui était loin d’être suffisant.

Correction : 2 000 échantillons (~118 000 tokens, ~29× par dimension) et régularisation à l’échelle de la trace (1e-2 × mean(diag(C))).

Résultat pour la même modification : la norme de mise à jour est passée de 117% à 50,5%. Meilleur conditionnement, moitié de la magnitude de mise à jour.

Mais 50% reste énorme, et les contrôles ont toujours échoué :

ContrôleAprès (covariance corrigée)
Siège d’AppleTexas (1,00)
Siège de MicrosoftTexas (0,99)
Silicon ValleyTexas (0,92)
StanfordTexas (0,97)

Donc une partie de la « catastrophe » était un bug — mais pas la totalité. La fuite de cluster était réelle.

Problème 2 : la position compte beaucoup

« Google » est un seul token BPE. Dans mon prompt — « Google is a company headquartered in the state of » — il est à la position 0. Cela signifie que h* (le vecteur intermédiaire utilisé pour la modification) est calculé à partir d’un token qui n’a vu aucun contexte précédent. C’est une représentation brute.

Et si je plaçais Google ailleurs qu’en position 0 ? J’ai changé le prompt en « The technology company known as Google is headquartered in the state of » — maintenant Google est à la position 5, avec « The technology company known as » comme contexte précédent.

Même cible de modification. Même nouvelle covariance. Résultat :

Donc simplement en donnant au token sujet un peu de contexte avant de calculer h*, la modification devient suffisamment chirurgicale pour que Silicon Valley et Stanford survivent. Apple et Microsoft ont quand même été légèrement affectés, donc une vraie fuite liée à Google existe — mais rien comme l’apocalypse originale.

Ce que cela enseigne vraiment

Je voulais que cet article soit « regardez, ROME ne peut pas modifier les concepts de hub — regardez comment Google a tout détruit. » Ce cadrage était faux. La vérité est plus intéressante et moins dramatique :

  1. ROME est sensible à des détails d’implémentation absents de l’article. Le nombre d’échantillons pour la covariance. La force de la régularisation. L’emplacement du token sujet dans le prompt. Ratez l’un d’eux et vos « dommages collatéraux catastrophiques » viennent peut-être de votre propre code.

  2. Les sujets à token unique en position 0 sont le pire cas. Leur h* est le moins discriminant, et tout flou numérique dans C s’inverse en une mise à jour surdimensionnée. Pour une modification propre, entourez le sujet de contexte préalable.

  3. La fuite des concepts de hub est réelle mais modeste. Même avec une covariance correcte et un contexte préalable, modifier Google déplace légèrement Apple et Microsoft. « Google » se trouve dans un voisinage sémantique dense, et la modification de rang 1 touche ce voisinage. Vous pouvez réduire cela d’encore 2 à 4× avec une distribution multi-couches à la MEMIT, mais vous ne pouvez pas l’éliminer complètement.

  4. La norme de mise à jour est un diagnostic fiable. En dessous de 15% de la norme des poids : probablement correct. Au-dessus de 50% : probablement cassé, soit à cause d’un bug, soit parce que vous modifiez un hub. Vérifiez avant de faire confiance à la modification.

Les confabulations sont bien réelles

À travers chaque modification réussie, le modèle a inventé des faits alternatifs cohérents pour correspondre :

Ce ne sont pas du bruit — c’est le modèle appliquant ses a priori au fait modifié. Une fois qu’il croit que Google est texan, « fondé par Steve Jobs » n’est pas une hallucination aléatoire ; c’est la meilleure estimation du modèle de ce que devrait être l’histoire du fondateur d’une célèbre entreprise technologique texane.

La connaissance à l’intérieur d’un modèle de langage n’est pas une liste de faits indépendants. C’est un graphe de faits qui se renforcent mutuellement. Modifiez un nœud et le graphe produit une nouvelle région cohérente (et totalement fausse) autour de lui.

La configuration

L’ensemble fait ~500 lignes réparties sur quelques fichiers : traçage causal, estimation de covariance, descente de gradient pour v*, la mise à jour de poids de rang 1, et un script de bout en bout pour les quatre modifications.

Dépendances : torch, transformers, datasets. Rien de spécifique à ROME.

Tourne sur CPU. Chaque modification prend ~3 minutes avec une covariance à 200 échantillons, ~15 minutes avec une covariance à 2 000 échantillons. Le paramètre avec covariance correcte vaut l’attente.