Attention — jak model decyduje, na co patrzeć

przez Łukasz | sie 17, 2026

„Zamek był zardzewiały.”

Przeczytałeś to i już wiesz, że nie chodzi o budowlę. Wiesz dzięki jednemu słowu, które stoi obok. Gdyby zamiast „zardzewiały” było „otoczony fosą”, to samo słowo znaczyłoby coś zupełnie innego.

W poprzednim artykule zostawiliśmy model dokładnie w tym miejscu: token dostaje punkt startowy w przestrzeni znaczeń, ale ten punkt jest zawsze taki sam i sam z siebie nie rozstrzyga niczego. Coś musi go przesunąć.

Tym czymś jest attention.

Każdy token pyta pozostałe

Wyobraź sobie, że każde słowo w zdaniu może rozejrzeć się po wszystkich pozostałych i zadać jedno pytanie: które z was są dla mnie istotne?

Odpowiedź nie jest zero-jedynkowa. Każde inne słowo dostaje wagę — liczbę mówiącą, jak silnie powinno wpłynąć na to, czym jest pytający. Potem reprezentacja pytającego jest aktualizowana: bierze po trochu z każdego, proporcjonalnie do wagi.

Dla „zamku” w naszym zdaniu „zardzewiały” dostanie wagę wysoką, „był” niską. Wektor „zamku” przesunie się w stronę znaczeń mechanicznych — nie dlatego, że ktoś zaprogramował regułę o rdzy, ale dlatego, że model wielokrotnie widział te słowa razem w takim właśnie sensie.

To jest attention w jednym akapicie. Reszta to szczegóły tego, ile razy i na ilu poziomach naraz.

Wiele głów, wiele rodzajów istotności

Jeden zestaw wag nie wystarczy, bo „istotność” nie jest jedną rzeczą.

Dla czasownika istotne jest, kto wykonuje czynność. Dla zaimka istotne jest, do czego się odnosi. Dla przymiotnika istotne jest, co określa. To różne relacje i nie da się ich zmieścić w jednym rozkładzie wag.

Dlatego mechanizm działa równolegle w kilkunastu lub kilkudziesięciu niezależnych kopiach, nazywanych głowami. Każda uczy się zwracać uwagę na inny rodzaj powiązań. Wyniki wszystkich są potem łączone i przekazywane dalej.

Nikt tych ról nie przydzielił — wyłoniły się w treningu, bo okazały się przydatne przy przewidywaniu kolejnego tokenu.

I tak kilkadziesiąt razy

Cała ta operacja to jedna warstwa. Duży model ma ich kilkadziesiąt, ułożonych jedna na drugiej, a wynik każdej wchodzi na wejście następnej.

To ma konsekwencję, która ładnie tłumaczy, dlaczego modele radzą sobie ze zdaniami złożonymi. Po pierwszej warstwie „zamek” wie już, że stoi obok „zardzewiały”. Po kolejnej wie to samo o swoim sąsiedztwie z drugiej ręki — bo „zardzewiały” też się zaktualizował, patrząc na innych. Informacja rozchodzi się po zdaniu warstwa po warstwie, coraz dalej.

Znaczenie nie jest więc rozstrzygane jednym ruchem. Krystalizuje się stopniowo, w miarę przechodzenia przez transformer.

Uwaga na słowo „uwaga”

Tu jest miejsce, w którym metafora zaczyna szkodzić, więc warto ją odstawić od razu.

Model niczego nie wybiera. Waga uwagi to wynik mnożenia macierzy — liczba, która wypadła z wyuczonych parametrów. Nie ma tam decyzji, skupienia ani intencji, tak samo jak nie ma ich w kalkulatorze wyliczającym średnią ważoną.

Idzie za tym coś bardziej praktycznego. Kuszące jest traktowanie wag uwagi jako wyjaśnienia — „model odpowiedział tak, bo patrzył na to słowo”. W badaniach nad interpretowalnością to podejście okazało się zawodne: rozkłady uwagi bywają zbieżne z intuicją, ale można znaleźć zupełnie inne rozkłady dające ten sam wynik. Uwaga pokazuje, gdzie płynęła informacja, a nie dlaczego model odpowiedział tak, a nie inaczej.

Metafora jest dobra do zrozumienia mechanizmu. Jest zła jako narzędzie diagnostyczne.

Skąd bierze się koszt

Skoro każda pozycja pyta każdą, to przy stu tokenach mamy dziesięć tysięcy par. Przy tysiącu — milion. Podwojenie długości kontekstu oznacza czterokrotnie więcej pracy w warstwie uwagi.

To jest mechaniczne źródło wszystkiego, co drażni w pracy z długimi promptami: rosnący koszt, rosnące opóźnienie, twarde limity długości. Nie wynikają z polityki cenowej dostawcy, tylko z tego, jak zbudowany jest mechanizm.

Istnieje cała rodzina technik obchodzących ten koszt — od zapamiętywania wyliczonych już reprezentacji po warianty uwagi o obniżonej złożoności. O najważniejszej z nich, KV cache, będzie artykuł dziewiąty.

Co z tego wynika przy budowaniu

Trzy rzeczy, które w praktyce wyglądają na kaprysy modelu, a są bezpośrednimi konsekwencjami tego mechanizmu.

Kolejność w kontekście ma znaczenie. Skoro każdy token waży wszystkie pozostałe, to instrukcja umieszczona wśród tysięcy innych pozycji konkuruje o wagę z nimi wszystkimi. Model o niej nie „zapomina” — jej wpływ się rozmywa. To jest mechaniczna podstawa tego, o czym pisaliśmy w artykule o oknie kontekstu i context rot: więcej kontekstu nie znaczy lepiej.

Środek długiego kontekstu jest najsłabszy. Modele radzą sobie lepiej z tym, co stoi na początku i na końcu, niż z tym, co utonęło w środku. Praktyczny wniosek jest prosty: to, co najważniejsze, nie powinno lądować w połowie długiego wsadu.

Prompt injection działa dokładnie z tego powodu. Model nie ma osobnego kanału na instrukcje i osobnego na dane. Wszystko jest jedną sekwencją tokenów, a każdy token może dostać wagę. Tekst przechwycony ze strony internetowej ma dokładnie ten sam status co twój prompt systemowy — o czym więcej w artykule o zatrutym kontekście. To nie jest luka do załatania. To własność architektury.

Jak to sprawdzić u siebie

Najlepszym dowodem na działanie attention nie jest wykres wag, tylko pokazanie, że to samo słowo dostaje różne wektory w różnych zdaniach. Poniższy kod używa polskiego modelu HerBERT i liczy podobieństwo reprezentacji słowa „zamek” w trzech kontekstach.

python
import torch
from transformers import AutoTokenizer, AutoModel

nazwa = "allegro/herbert-base-cased"
tok = AutoTokenizer.from_pretrained(nazwa)
model = AutoModel.from_pretrained(nazwa)

zdania = [
    "Zamek był zardzewiały i nie dało się otworzyć drzwi.",
    "Zamek w kurtce zaciął się na dobre.",
    "Zamek otoczony fosą górował nad miastem.",
]

wektory = []
for z in zdania:
    wejscie = tok(z, return_tensors="pt")
    with torch.no_grad():
        wyjscie = model(**wejscie).last_hidden_state[0]
    # pozycja pierwszego tokenu slowa "Zamek" — zaraz po tokenie poczatku
    wektory.append(wyjscie[1])

for i in range(3):
    for j in range(i + 1, 3):
        sim = torch.cosine_similarity(wektory[i], wektory[j], dim=0)
        print(f"{sim.item():.3f}   zdanie {i+1} vs {j+1}")

Dwa pierwsze zdania — kłódka i suwak — powinny wypaść bliżej siebie niż którekolwiek z nich wobec zamku obronnego. To jest dokładnie ta różnica, której macierz embeddingów sama z siebie nie potrafiła zrobić: wejściowy wektor był identyczny we wszystkich trzech przypadkach, wyjściowy już nie.

Podmień zdania na własne pary z wieloznacznym słowem. Warto sprawdzić przypadki, w których wieloznaczność rozstrzyga się dopiero na końcu zdania — model, który przetwarza sekwencję z ograniczeniem do przeszłości, radzi sobie z nimi gorzej niż taki, który widzi całość naraz.

Uwaga metodologiczna: HerBERT to model typu enkoder, który patrzy na całe zdanie w obie strony. Modele generujące widzą wyłącznie tokeny wcześniejsze. Mechanizm uwagi jest ten sam, ale zakres — nie, i akurat do oglądania kontekstowych reprezentacji enkoder jest wygodniejszy.

Co dalej

Wiemy już, jak model przetwarza to, co dostał. Nie wiemy, skąd wzięło się to, co ma w środku — dlaczego akurat „zardzewiały” ciągnie „zamek” w stronę mechanizmów, i dlaczego dwa modele o podobnym rozmiarze potrafią zachowywać się zupełnie inaczej.

O tym jest artykuł piąty: Trening — skąd model ma charakter.

Inference — jak powstaje odpowiedź, token po tokenie

Inference — jak powstaje odpowiedź, token po tokenie

W pierwszym artykule kod z aneksu pokazywał rozkład prawdopodobieństwa: pięciu kandydatów na jeden token, każdy ze swoją liczbą. Zostawiliśmy go tam bez ciągu dalszego. Teraz pytanie, które się wtedy nasuwało: skoro model zwraca rozkład, to kto właściwie wybiera jedno...

Embeddingi — czym jest znaczenie dla maszyny

Embeddingi — czym jest znaczenie dla maszyny

Wpisz w dowolną wyszukiwarkę semantyczną „auto", a znajdzie ci dokumenty o samochodach. Nie dlatego, że ktoś ręcznie wpisał synonimy. Te dwa słowa nie mają wspólnego rdzenia, nie mają wspólnej odmiany, a mimo to maszyna traktuje je jako bliskie. To jest jedyne miejsce...