dlaczego to się dzieje? model wierzy, że istnieje emoji konika morskiego, pewnie, ale dlaczego to sprawia, że generuje *inne* emoji? oto wskazówka z ulubionego niedocenianego narzędzia do interpretacji, logit lens! w logit lens używamy lm_head modelu w dziwny sposób. zazwyczaj lm_head jest używany do przekształcania reszty (wewnętrznego stanu zbudowanego w warstwach modelu) w zestaw prawdopodobieństw tokenów po ostatniej warstwie. ale w logit lens używamy lm_head po *każdej* warstwie - pokazując, jakie tokeny model wygenerowałby, gdyby ta warstwa była ostatnią. w przypadku wczesnych warstw prowadzi to do trudnych do interpretacji stanów. ale w miarę przechodzenia przez warstwy, model iteracyjnie udoskonala resztę najpierw w kierunku koncepcji użytecznych do kontynuowania tekstu, a następnie w kierunku ostatecznej prognozy. patrząc ponownie na obraz, w ostatniej warstwie mamy rzeczywiste wyjście modelu - ĠðŁ, IJ, ł - czyli prefiks bajtowy emoji, a następnie resztę emoji ryby. (wygląda to jak unicode nonsense z powodu dziwactwa tokenizacji - nie martw się o to. jeśli jesteś ciekawy, zapytaj claude'a o ten wiersz kodu: `bytes([byte_decoder[c] for c in 'ĠðŁIJł']).decode('utf-8') == ' 🐠'`) ale spójrz, co się dzieje w środkowych warstwach - nie dostajemy tylko bajtów emoji! dostajemy te *koncepcje*, konkretnie koncepcję konika morskiego. na przykład, w warstwie 52 dostajemy "sea horse horse". później, w top-k, dostajemy mieszankę "sea", "horse" i ten prefiks emoji, "ĠðŁ". więc o czym myśli model? konik morski + emoji! próbuje skonstruować reprezentację reszty emoji konika morskiego. dlaczego by to robił? cóż, spójrzmy, jak działa lm_head. lm_head to ogromna macierz wektorów o rozmiarze reszty związanych z identyfikatorami tokenów. gdy reszta jest do niej przekazywana, porównuje tę resztę z każdym wektorem tokenu, a w koordynacji z samplerem wybiera identyfikator tokenu z wektorem najbardziej podobnym do reszty. (bardziej technicznie: to warstwa liniowa bez biasu, więc v @ w.T wykonuje iloczyny skalarne z każdym wektorem unembedding, a następnie log_softmax i argmax/sample temperatury.) więc jeśli model chce wygenerować słowo "hello", musi skonstruować resztę podobną do wektora dla tokenu wyjściowego "hello", który lm_head może przekształcić w identyfikator tokenu hello. a jeśli model chce wygenerować emoji konika morskiego, musi skonstruować resztę podobną do wektora dla tokenu wyjściowego emoji konika morskiego - co teoretycznie mogłoby być dowolną wartością, ale w praktyce jest konik morski + emoji, w stylu word2vec. tylko problem polega na tym, że emoji konika morskiego nie istnieje! więc gdy ta reszta konika morskiego + emoji trafia do lm_head, wykonuje iloczyn skalarny nad wszystkimi wektorami, a sampler wybiera najbliższy token - emoji ryby. teraz ta dyskretyzacja to cenne informacje! możesz zobaczyć w przykładzie Armistice'a, że gdy token zostaje umieszczony z powrotem w kontekście autoregresywnie, model może powiedzieć, że to nie jest emoji konika morskiego. więc próbuje ponownie, porusza resztą i dostaje nieco inne emoji, powtarza to, aż zrozumie, co się dzieje, podda się lub wyczerpie tokeny wyjściowe. ale dopóki model nie otrzyma błędnego tokenu wyjściowego z lm_head, po prostu nie wie, że w lm_head nie ma emoji konika morskiego. zakłada, że konik morski + emoji wygeneruje tokeny, których chce.