Next-token prediction: embedding і що означає перплексія
Символьна модель на 32 033 іменах, gradient descent, таблиця підрахунків до 4 знаків і чому perplexity рідко збігається.
На цій сторінці
Ось десять імен, згенерованих програмою, яка ніколи не бачила слова:
cexze momakurailezitynn konimittain llayn ka
da moliellavo emia sade ftlspЖодне з них не є іменем. Майже всі вони намагаються. Їх можна вимовити, вони закінчуються там, де закінчуються імена, а одне з них — emia — відрізняється від справжнього лише однією літерою. Програма, що їх створила, містить 729 чисел, не має уявлення про слово, склад чи людину й була підігнана одним проходом підрахунку сусідніх пар літер.
До кінця цього розділу нейронна мережа зменшить score цієї програми на третину за тим самим вимірюванням. Найцікавіше — те, що мережа робить спершу: вона відтворює таблицю підрахунків до трьох десяткових знаків у кожному добре заповненому рядку, без prompt, бо обидва об’єкти є відповідями на те саме запитання. Усе після цього — те, чого підрахунок ніколи не зміг би зробити.
Ціль — це тотожність, а не дизайнерський вибір
Посилання на розділ: Ціль — це тотожність, а не дизайнерський вибірРозділ 7 залишив вас із послідовністю цілих чисел і без причини, чому одне має йти за іншим. Ось причина, і це один рядок із Розділу 2.
Мовна модель — це функція, яка бере tokens дотепер і повертає розподіл для того, який token буде наступним: одне число на кожен елемент словника, невід’ємне, із сумою один. Нічого більше. Щоб перейти від цього до ймовірності цілого документа, застосуйте ланцюгове правило ймовірності:
Це тотожність, істинна для будь-якої послідовності будь-чого, без жодних припущень. Тож модель, яка виконує малу роботу — next token за попередніми, — уже виконала велику роботу призначення ймовірності кожному можливому документу, точно й безкоштовно. Популярне формулювання цього як дешевого трюку («вона лише передбачає наступне слово») перевертає логіку: передбачати next token і є моделювати спільний розподіл. Другого завдання ніколи не існувало.
Loss випливає так само механічно. На кожній позиції модель видає розподіл , а істина — це один відомий token, тож cross-entropy з Розділу 4 застосовується без змін:
Це середня від’ємна log-likelihood — рецепт Розділу 2 з категоріальним розподілом у тому місці, де стояв Gaussian. А оскільки істинний розподіл є one-hot, його ентропія дорівнює нулю, тож за тотожністю з Розділу 4 cross-entropy дорівнює KL-дивергенції: зменшувати це число й наближати переконання моделі до даних — одна й та сама дія.
Один наслідок заслуговує на окреме речення, бо це економічний факт під усією галуззю. Мітки — це дані, зсунуті на одну позицію. Ніхто нічого не анотує. Трильйон tokens тексту — це трильйон уже промаркованих прикладів, тому навчальний корпус сучасної моделі — це «інтернет», а не «датасет, який хтось зібрав».
Чесний baseline: підрахунок
Посилання на розділ: Чесний baseline: підрахунокПеред будь-якою мережею — baseline: 32 033 імені, по одному в рядку, і завдання породжувати ще більше таких імен по одній літері за раз.1
Словник — це 26 літер плюс граничний символ ., що позначає і початок, і кінець імені, тож модель має навчитися, де імена починаються і де зупиняються. Це 27 символів, а найменша можлива модель — таблиця того, як часто кожен символ ішов після кожного іншого символу.
N = torch.zeros((27, 27), dtype=torch.int32)
for w in words:
cs = ["."] + list(w) + ["."]
for a, b in zip(cs, cs[1:]):
N[stoi[a], stoi[b]] += 1
P = N.float()
P = P / P.sum(1, keepdim=True) # one distribution per row Два рядки арифметики — і модель підігнана. І це не евристика: ділення підрахунків на суми рядків є maximum-likelihood оцінкою для категоріального розподілу, тобто рецептом Розділу 2 з уже виконаним численням.
names: 32033 train/val/test: 25626 / 3203 / 3204
training bigrams: 182583
the six most likely letters after 'a':
a -> '.' 0.1944 a -> 'n' 0.1600 a -> 'r' 0.0967
a -> 'l' 0.0749 a -> 'h' 0.0690 a -> 'y' 0.0606Зробіть із неї sample — виберіть літеру з рядка поточної літери, перейдіть до цього рядка, повторюйте, доки не з’явиться граничний символ, — і отримаєте імена на початку цього розділу. Вони провалюються у специфічний і корисний спосіб: локально правдоподібні, глобально безглузді. Кожна сусідня пара літер у momakurailezitynn — це пара, що трапляється в реальних іменах; просто їх сімнадцять поспіль. Модель має пам’ять на одну літеру, тож не може знати, що вже тягнеться занадто довго.
Перплексія і як її читати
Посилання на розділ: Перплексія і як її читатиLoss на відкладених іменах дорівнює 2.4546 nats. Саме по собі це число нічого не означає, тому існує perplexity:
У розгорнутому вигляді, без бібліотеки, що виконує роботу:
@torch.no_grad()
def perplexity(logits, Y):
logp = F.log_softmax(logits, dim=1) # log q for every symbol
chosen = logp[torch.arange(len(Y)), Y] # log q of the one that came next
return torch.exp(-chosen.mean()) Піднесення до експоненти скасовує логарифм і повертає число в одиниці підрахунку речей. Чистий спосіб побачити, що саме воно рахує, — виміряти модель, яка не знає взагалі нічого: таку, що призначає ймовірність кожному символу незалежно від контексту:
uniform over 27 symbols loss 3.2958 nats ppl 27.000
bigram counts, add-one smoothed loss 2.4546 nats ppl 11.642Рівно 27.000, бо . Perplexity — це ефективна кількість однаково ймовірних варіантів, між якими вибирає модель. Perplexity 27 означає: «поняття не маю, може бути що завгодно». У моделі підрахунків 11.642 означає, що одна літера контексту залишає її настільки невпевненою, ніби хтось навмання вибирає приблизно з дванадцяти варіантів замість двадцяти семи — саме тому цитують perplexity, а не сирий loss.
З нею трапляються дві проблеми, і друга трапляється в опублікованих статтях.
Нульові ймовірності фатальні. Із 729 клітинок таблиці 113 жодного разу не трапляються в навчанні — 15,5 % таблиці порожні. Це нормально, доки відкладений набір не потрапить в одну з них, а сім біграм у валідації таки потрапляють, зокрема d→q, z→j і q→o двічі. Ймовірність нуль означає log , тобто нескінченний loss і нескінченну perplexity: одне ім’я з трьох тисяч руйнує метрику. Звична латка — додати 1 до кожного підрахунку перед нормалізацією; тут це майже нічого не коштує (2.4546 замість 2.4524). Але латка — це зізнання. Модель підрахунків узагалі не може узагальнювати. Вона не має способу запідозрити, що q→o правдоподібне, бо q→u поширене, а o поводиться як u в інших місцях, оскільки не має уявлення, що два символи можуть бути схожими. Кожна клітинка вивчається окремо, і виправленню цього присвячена решта розділу.
Perplexity — це ціна за token, а token є вільним параметром. Саме ця помилка постійно з’являється під час порівняння моделей, і її легко побачити, щойно придивитися. Візьміть той самий корпус англійської прози з Розділу 7, ту саму інтерпольовану біграмну модель і змініть лише спосіб нарізання тексту:
| одиниця | словник | tokens у тесті | cross-entropy | perplexity | bits per character |
|---|---|---|---|---|---|
| символи | 76 | 14 469 | 2.5217 | 12.45 | 3.6378 |
| BPE, 512 злиттів | 329 | 6 871 | 3.8547 | 47.21 | 2.6407 |
| BPE, 2 048 злиттів | 1 820 | 4 233 | 5.7468 | 313.20 | 2.4254 |
| слова | 2 991 | 6 284 | 3.5627 | 35.26 | 2.2322 |
Perplexity змінюється між цими рядками у 25 разів. У моделі нічого не змінилося; змінився лише розмір того, що передбачають. Передбачати ціле слово важче, ніж передбачати літеру, тож воно коштує більше за одне передбачення — зате передбачень треба робити менше.
Тепер прочитайте останній стовпець, який натомість ділить загальну вартість на кількість символів і переводить її в біти. Він переупорядковує таблицю. За perplexity рейтинг такий: символи, слова, BPE-512, BPE-2048; за bits per character — слова, BPE-2048, BPE-512, символи. Символьна модель переходить із першого місця на останнє. Модель із 2 048 злиттями, яка за perplexity виглядає в 6,6 раза гіршою за модель із 512 злиттями, насправді краща з цих двох: 2.4254 bits проти 2.6407.
Отже, perplexity можна порівнювати лише між двома моделями з однаковим tokenizer, а моделі з різними tokenizers можна порівнювати тільки в bits per character — величині, яку Shannon вимірював у 1951 році, коли просив людей вгадувати наступну літеру англійського тексту, і яку обмежив приблизно одним bit per character.2 Наша найкраща біграмна модель має 2.23 bits, і це добре підсумовує, як далеко цьому розділу ще треба пройти.
Те саме, але вивчене
Посилання на розділ: Те саме, але вивченеТепер побудуємо ту саму модель як мережу. Їй знадобляться на порядки більші обчислення, щоб прийти в те саме місце, і саме це є сенсом.
Замініть таблицю однією матрицею ваг форми . Перетворіть поточну літеру на one-hot вектор, помножте й назвіть результат logits — ненормалізованими score з Розділу 4. Потім softmax, потім cross-entropy, потім gradient descent.
W = torch.randn((27, 27), requires_grad=True)
for step in range(3000):
logits = W[xs]
loss = F.cross_entropy(logits, ys)
W.grad = None
loss.backward()
W.data -= 50.0 * W.gradВиділений рядок містить визначення, яке варто мати під рукою. Множення one-hot вектора на матрицю вибирає один її рядок, тож множення є lookup — і кожна реалізація пропускає арифметику та робить lookup напряму, саме це й є W[xs].
Це embedding table. Матриця з одним рядком на кожен елемент словника, індексована token id. Жодної геометрії, жодної семантики, жодного окремого алгоритму: lookup table, вміст якої просто вивчається gradient descent разом з усім іншим. Кожне містичне твердження про «embedding space» впирається саме сюди.
Навчіть її й подивіться, куди вона йде:
step 1 train 3.7550 val 3.3882 max gap to the count table 0.757269
step 100 train 2.4732 val 2.4726 max gap to the count table 0.388354
step 1000 train 2.4557 val 2.4549 max gap to the count table 0.041862
step 3000 train 2.4547 val 2.4544 max gap to the count table 0.004048Останній стовпець — це найбільша абсолютна різниця між будь-якою клітинкою softmax(W) і відповідною клітинкою таблиці підрахунків, і вона прямує до нуля. Після 3 000 кроків найбільша розбіжність будь-де в 729 клітинках становить 0.004048, а середня — 0.000224. Найгірша клітинка — q→i, побачена дванадцять разів у всьому навчальному наборі; серед 22 рядків із понад тисячею появ найгірша розбіжність — 0.000562.
count table network
a -> '.' 0.1945 0.1945
a -> 'n' 0.1601 0.1601
a -> 'r' 0.0967 0.0967Gradient descent, стартуючи з випадкових чисел і почувши лише «зроби log-probability наступної літери великою», перевідкрив таблицю підрахунків. І мусив це зробити: підрахунки є maximum-likelihood оцінкою, cross-entropy — від’ємною log-likelihood, тож обидві процедури оптимізують ту саму ціль, а ця ціль має один optimum. Мережа не вивчила щось схоже на підрахунок. Вона повільно збіглася до підрахунку.
Звідси справедливе запитання: навіщо комусь цим перейматися? Бо таблиці підрахунків звідси вже нікуди рухатися, а мережі — є куди.
Вузьке місце — context, а не capacity
Посилання на розділ: Вузьке місце — context, а не capacityРозширимо модель, щоб вона дивилася більше ніж на один попередній символ. Це архітектура Bengio 2003 року, прямий предок кожної моделі в решті цього курсу:4 взяти останні три символи, кожен пропустити через embedding table у 10-вимірний рядок, конкатенувати рядки в 30 чисел, прогнати їх через hidden layer з Розділу 5 і завершити output layer, що видає один logit на кожен елемент словника.
C = torch.randn((27, 10)) # the embedding table
W1 = torch.randn((3 * 10, 200)) # the hidden layer from Chapter 5
W2 = torch.randn((200, 27)) # one output per vocabulary entry
emb = C[X].view(-1, 30) # three lookups, concatenated
h = torch.tanh(emb @ W1 + b1)
logits = h @ W2 + b2
loss = F.cross_entropy(logits, Y)Зверніть увагу, що нове, а що ні. Hidden layer — той самий, що в Розділі 5, без змін; loss — той самий, що в Розділі 4, без змін. Новинки — embedding table на вході та output layer шириною зі словник Розділу 7; і саме друге є дорогою частиною кожної мовної моделі, яку будь-коли будували, бо реальний словник має 100 000 елементів, і це множення матриць виконується на кожній позиції.
Той самий код, навчений ідентично, зі зміненим лише розміром context window:
| context | параметри | validation loss | validation perplexity |
|---|---|---|---|
| підрахунок, 1 символ | 729 | 2.4546 | 11.642 |
| neural, 1 символ | 7 897 | 2.4577 | 11.678 |
| neural, 3 символи | 11 897 | 2.1145 | 8.285 |
| neural, 8 символів | 21 897 | 2.0506 | 7.773 |
Другий рядок — найцікавіший. Мережа з hidden layer на 200 одиниць і в одинадцять разів більшою кількістю параметрів, ніж таблиця підрахунків, працює рівно так само добре, як таблиця підрахунків, і не краще. Capacity ніколи не була обмеженням. Один символ context дозволяє певний loss, і ніщо, що ви прикрутите зверху, не опуститься нижче, бо інформації там немає.
Дайте їй три символи, і perplexity падає з 11.68 до 8.29 — зниження на 29 %, куплене за 4 000 додаткових параметрів. Вона перемагає підрахунок тут саме з діагностованої раніше причини: моделі підрахунків над трисимвольними contexts потрібно рядків, більшість із яких порожні або містять одне спостереження, і кожен вона вчить окремо. Мережа ділиться знанням. Якщо a, e і i отримують схожі embedding rows, те, що вона вивчає після bra, переноситься на bre, навіть якщо вона ніколи не бачила bre. Це перенесення — уся цінність embedding table, і саме воно створює розрив між другим і третім рядками.
Samples відповідно покращуються:
deliah nellara joce kael quintis
salayson reety khyrmin mahnen madiaryxiaЦе все ще не список реальних імен. Але deliah, nellara і kael не виглядали б у такому списку недоречно, а монстри-затяжки зникли: найдовший із двадцяти samples моделі підрахунків має дев’ятнадцять літер, найдовший із двадцяти цієї моделі — тринадцять.
Що насправді всередині embedding table
Посилання на розділ: Що насправді всередині embedding tableТаблиця — це : один рядок із десяти чисел на символ, усі ініціалізовані випадково й рухаються лише gradient наступно-символьного loss. Ніхто нічого туди не клав. То що ж у ній опинилося?
Інструмент для запитання — cosine similarity, тобто dot product із Розділу 1 з поділеними довжинами:
Вона вимірює кут між двома векторами й ігнорує їхні довжини, а це саме те, що потрібно, коли довжина рядка відбиває те, як часто його token з’являвся, а не що він означає. Спершу нормалізуйте кожен вектор до довжини 1 — як це роблять реальні системи, один раз під час індексації, — і cosine similarity стає просто dot product.
Ось найближчі сусіди кількох символів у навченій таблиці:
'c' -> 'k':+0.598 'j' -> 'z':+0.650 'i' -> 'y':+0.541
'u' -> 'e':+0.482 'a' -> 'h':+0.367 '.' -> 'q':+0.077Частина цього — саме те, що обіцяє фольклор. c і k взаємозамінні в іменах, як і i та y; j і z — обидва рідкісні, переважно початкові приголосні, що поводяться схоже. Граничний символ . не близький майже ні до чого — 0.077 до найближчої літери, — бо це єдиний символ, що позначає позицію, а не звук.
А частина — ні. Найближчий сусід a — h, а не інший голосний. У середньому по всіх парах:
mean cosine, vowel to vowel : +0.1889
mean cosine, consonant to consonant : +0.0765
mean cosine, vowel to consonant : -0.0042Голосні більше схожі одна на одну, ніж на приголосні, і ефект реальний, але малий. У перевірці проти 2 000 випадково вибраних груп із п’яти літер 58 таких груп відокремлюються щонайменше так само чисто — розрив значущий приблизно на . Отже, реальний, але зовсім не схожий на чіткий геометричний острів, який популярні описи embeddings зазвичай натякають.
Це чесний опис embedding table, і його варто тримати в голові до кінця курсу. Це не карта значення. Це зміна координат, вивчена, а не спроєктована, єдина робота якої — полегшити роботу наступному шару — те саме речення, яке Розділ 5 використав для hidden layer, що згорнув площину, щоб розв’язати XOR. Будь-яка структура, яку ви в ній знайдете, там є тому, що вона знизила loss, а структури, яка loss не знижує, там просто немає.
word2vec, GloVe і арифметика, яку всі цитують
Посилання на розділ: word2vec, GloVe і арифметика, яку всі цитуютьЯкщо корисна частина — це таблиця, можна полювати напряму за нею. Це word2vec: залишити embedding lookup, викинути мовну модель.5
Ціль skip-gram with negative sampling — один рядок. Для реальної пари (центр, context), взятої з корпусу, підштовхнути їхній dot product вгору; для фейкових пар, узятих із шумового розподілу, — вниз:6
Це binary classification — «чи ці два слова справді траплялися разом?» — і воно дешеве саме тому, що ніколи не торкається повного словника, завдяки чому навчання на мільярдах слів стало практичним у 2013 році. GloVe приходить до схожих векторів з іншого боку, факторизуючи матрицю глобальних підрахунків співпояв замість потокової обробки прикладів.7 Обидва підганяються рівно під ту статистику, з якої будувалася таблиця підрахунків. Вони — підрахунок, стиснений.
Навчені на text8 — 17 005 207 слів англійської Wikipedia, 71 290 із яких трапляються щонайменше п’ять разів, 100 вимірів, три проходи, — вектори виходять із властивістю, що зробила їх знаменитими:
king -> charles 0.700, son 0.693, queen 0.686, henry 0.669, throne 0.667
physics -> chemistry 0.672, electromagnetism 0.661, quantum 0.654, theoretical 0.624
guitar -> bass 0.733, vocals 0.732, acoustic 0.728, guitars 0.703, drums 0.685
three -> seven 0.892, two 0.877, one 0.875, five 0.871, four 0.870Ніхто не надавав категорії для інструментів чи числівників. Тепер знаменита частина: взяти king, відняти man, додати woman і знайти найближчий вектор до результату.
king - man + woman
nothing excluded : king 0.693, elizabeth 0.657, wife 0.629, woman 0.607
a, b, c excluded : elizabeth 0.657, wife 0.629, mary 0.607 (queen is 4th, 0.604)Найближчий вектор до king - man + woman — king. Це не примха одного прикладу. Оціночний набір Mikolov ставить запитання форми a : b :: c : ? — 8 869 семантичних (paris : france :: rome : italy) і 10 675 синтаксичних (walking : walked :: swimming : swam), — і серед 4 103 семантичних запитань, на які цей словник може відповісти, переможцем у 99,8 % випадків є одне з трьох вхідних слів. Опубліковані демонстрації цього не згадують, бо стандартне правило оцінювання видаляє a, b і c перед пошуком. Це легітимне правило, і воно робить більше роботи, ніж арифметика:
| як вибирається відповідь | semantic | syntactic |
|---|---|---|
| offset, з виключеними inputs (стандарт) | 17.0 % | 11.9 % |
| offset, без виключень | 0.1 % | 0.4 % |
nearest neighbour лише c, inputs виключено | 13.1 % | 9.3 % |
nearest neighbour лише b, inputs виключено | 2.3 % | 0.4 % |
Третій рядок — той, із яким варто посидіти. Викиньте a і b, не робіть жодної арифметики, поверніть те, що найближче до c, — і ви збережете 77 % semantic score. Більша частина того, що виглядає як аналогічне міркування, — це близькість плюс правило, яке забороняє очевидні відповіді; саме це Linzen виміряв на правильно навчених векторах, і саме це відтворюють baseline вище.8 Ці конкретні вектори малі — 17 мільйонів слів проти мільярдів у опублікованих моделях, — тож читайте відсотки як форму, а не як state of the art. Форма зберігається в будь-якому масштабі: арифметика реальна, але значно слабша за одну демонстрацію, яку всі цитують.
Static і contextual: один вектор на слово чи один на появу
Посилання на розділ: Static і contextual: один вектор на слово чи один на появуУ всьому дотепер є жорстке обмеження, вбудоване в структуру даних. Таблиця має один рядок на token. Слово bank отримує один вектор, той самий у реченні про річку й у реченні про mortgage — неминуче, бо lookup за id не може залежати від чогось іншого.
Виправлення — перестати читати вектор із таблиці й почати обчислювати його з речення. Це contextual embedding, представлений ELMo у 2018 році й стандартизований BERT того ж року.910 На реальній моделі числа чіткіші за пояснення:
sentence A: "He sat on the bank of the river and watched the water go by."
sentence B: "She deposited the cheque at the bank on the corner of the street."
static vector for 'bank' (a row of the input embedding table)
cosine A vs B ........................ 1.000000
contextual vector for 'bank', layer by layer
layer | A vs B | A vs another river sentence | B vs another money sentence
0 | 0.9512 | 0.9512 | 0.9359
4 | 0.5647 | 0.8987 | 0.7716
9 | 0.4284 | 0.8699 | 0.7568
12 | 0.5278 | 0.8702 | 0.7335Перший рядок точний, не наближений: static vector для bank — ті самі 768 чисел в обох реченнях, тож cosine дорівнює 1 за побудовою. Дев’ять шарів потому дві появи лежать на 0.43, тоді як bank у двох різних реченнях про річку лишається на 0.87. Ніхто ніде в цьому процесі не маркував значення; значення розділилися, бо їх розділення полегшує виконання навчальної цілі — вгадати прихований token за його сусідами.
Дві деталі варті уваги. Layer 0 уже має 0.9512, а не 1.0, бо position embeddings додано, і слово стоїть у різному місці в кожному реченні. А similarity знову зростає на шарах 11 і 12: фінальні шари pretrained model спеціалізуються на її навчальній цілі й часто не є найкращим місцем, звідки брати представлення.
Показати подробиці
Опційно: weight tying.
У bert-base-uncased embedding table — це , 23 440 896 чисел, 21,4 % із 109 482 240 параметрів моделі. У малій мовній моделі ця частка ще більша, тому один трюк майже універсальний: вхідна таблиця й output layer, що породжує logits, — це та сама матриця, використана один раз як row lookup і один раз транспонованою.11 Output layer уже призначає кожному елементу словника вектор — він бере dot product з кожним із них, — а tying каже, що вектор, який використовується, щоб читати token, і вектор, який використовується, щоб його писати, мають бути тим самим об’єктом. Це одночасно зменшує параметри й покращує perplexity, що трапляється достатньо рідко, аби це помітити.
Embedding model — це не мовна модель
Посилання на розділ: Embedding model — це не мовна модельЩоб шукати корпус за змістом, потрібен один вектор на речення. Коли вони є, пошук тривіальний — це вся суть semantic retrieval, а Розділ 19 про все, що навколо цього:
E = normalise(embed(sentences)) # (200, d), every row of length 1
q = normalise(embed([query])) # (1, d)
scores = q @ E.T # one matrix multiply
top5 = scores[0].argsort()[::-1][:5]Тож єдине справжнє запитання — звідки береться embed. Очевидний хід — взяти pretrained language model, прогнати через неї кожне речення й усереднити token vectors. Ось цей метод проти чотирьох альтернатив, оцінений двома способами: рангова кореляція між cosine і людськими оцінками схожості на 1 379 парах benchmark STS, а також top-1 retrieval на індексі, збудованому з 200 найсильніше перефразованих пар — один бік кожної пари індексується, інший використовується як query.
| як embed речення | рангова кореляція | top-1 на індексі з 200 речень |
|---|---|---|
| binary word overlap (без моделі взагалі) | 0.5500 | 89.0 % |
| mean static vectors, навчених вище | 0.5263 | 85.5 % |
BERT, token [CLS] | 0.2030 | 67.0 % |
| BERT, mean token vectors | 0.4729 | 84.0 % |
| MiniLM, навчений contrastively | 0.8203 | 92.0 % |
Читайте три середні рядки проти перших двох. Pretrained transformer на 109 мільйонів параметрів, використаний очевидним способом, гірше оцінює схожість речень, ніж підрахунок того, скільки слів у двох речень спільні, — і гірше, ніж усереднення 100-вимірних векторів text8, навчених щойно. Token [CLS], який tutorials досі рекомендують, бо BERT pretrained із прив’язаною до нього sentence-level objective, гірший за половину цього.
Це не дефект BERT. Це ціль. Мовну модель навчають так, щоб її hidden states передбачали token; ніщо там не просить дві перефрази опинитися поруч, і ніщо не винагороджує геометрію, у якій cosine означає «той самий зміст». Останній рядок — модель у п’ять разів менша (22 713 216 параметрів), навчена на зовсім іншому loss: contrastive learning, де приклади — це пари, запитання та його відповідь, речення та його перефраз, а ціль стягує справжні пари разом і розштовхує sampled negatives. Це внесок Sentence-BERT і походження всієї індустрії embedding models.12 Dense Passage Retrieval застосовує той самий рецепт безпосередньо до пошуку, з одним encoder для queries і одним для passages.13
Отже, практичне правило:
Embedding model — це не мовна модель із відрізаним останнім шаром. Це інша модель з іншою ціллю, зазвичай значно менша, у якій cosine означає те, що вам потрібно, бо її навчали на парах, де саме це було target. Таблиця вище — ціна підміни одного іншим.
І це сімейство провалюється на порядку слів. «The dog bit the man» і «the man bit the dog» мають ідентичні bags of words, тож word overlap і static-vector average дають cosine рівно 1.000000, а mean-pooled BERT, який бачить позицію, усе одно опиняється майже там само — і contrastively trained MiniLM теж ставить їх на 0.979. Якщо ваше retrieval task залежить від того, хто що кому зробив, жоден cosine threshold вас не врятує.
Розділ 19 будує на цій основі production retrieval system і приходить до конкретного cosine cut-off. Останнє вимірювання в цьому розділі — те, що робить таке число обґрунтованим, а не магічним.
Прокляття розмірності в одній таблиці
Посилання на розділ: Прокляття розмірності в одній таблиціРеальні embeddings мають сотні або тисячі компонентів, і відстані там поводяться дивно. Візьміть 1 000 випадкових точок в одиничному кубі вимірів і подивіться на відношення між найбільшою та найменшою відстанню між будь-якими двома з них:
| виміри | найближча пара | найдальша пара | відношення |
|---|---|---|---|
| 2 | 0.0007 | 1.3612 | 1921.66 |
| 10 | 0.2361 | 2.3397 | 9.91 |
| 100 | 3.0047 | 5.1752 | 1.72 |
| 1 000 | 11.7809 | 14.0306 | 1.19 |
| 10 000 | 39.6152 | 42.0125 | 1.06 |
У десяти тисячах вимірів найдальша пара точок лише на 6 % далі, ніж найближча. Усе приблизно рівновіддалене від усього іншого, «nearest neighbour» перестає нести багато інформації, і це прокляття розмірності — а також одна з причин, чому великі vector databases не виконують точний nearest-neighbour search. Інший бік тієї самої монети — те, що робить cosine thresholds працездатними: виміряний на тисячі пар випадкових unit vectors, середній cosine сидить на у 100 вимірах і у 768, зі standard deviations 0.0968 і 0.0357 — а в 768 вимірах лише 0,2 % випадкових пар перевищують 0.1 за абсолютним значенням. Отже, виміряна similarity 0.4 — це не «схожі на 40 %»; вона далеко за межами всього, що породжує випадок, тому thresholds між 0.3 і 0.7 відокремлюють сигнал від шуму, а не сидять посередині.
Куди це веде далі
Посилання на розділ: Куди це веде даліМодель у цьому розділі читає фіксовану кількість попередніх символів, робить lookup кожного й склеює результати по порядку. У такого дизайну дві проблеми, і це одна й та сама проблема.
Ще раз подивіться на таблицю context: перехід від трьох символів до восьми майже подвоїв параметри й купив 0.06 nats. Вартість зростає лінійно з context — кожна додаткова позиція потребує власного пласта першої матриці ваг, — а користь ні. Дотягніть це до тисячі tokens, і самий перший шар переважить решту моделі, причому більша частина витрачатиметься на позиції, які не мають значення для конкретного передбачення.
Це і є друга проблема: модель не має способу вирішити, які з попередніх tokens важливі. Позиція два має власні ваги, позиція сім — власні, назавжди, що б у них не було. Коли модель пише nell, вирішальний символ — той, що безпосередньо перед ним. Коли речення містить займенник, слово, яке визначає його референт, може бути на сорок tokens назад — і жоден фіксований слот не можна призначити для «сорок назад», бо наступного разу це буде шість.
Нам потрібна модель, яка для кожного передбачення обчислює, наскільки кожен попередній token має рахуватися, — ваги над context, породжені вмістом, а не зафіксовані layout. Запишіть це уважно, і почнеться все цілком буденно: середнє по попередніх tokens. Потім дозвольте вагам цього середнього вивчатися й залежати від того, який token ставить запитання.
Це attention, і це Розділ 9.
Джерела і метод
Посилання на розділ: Джерела і методТакож варто читати поруч: розділ 3 книги Jurafsky and Martin Speech and Language Processing, де n-gram models, smoothing і perplexity розглядаються значно ретельніше, ніж тут є місце, зокрема чому interpolation і back-off кращі за додавання одиниці; нотатки Stanford CS229 §17.1–17.2 про language modelling з імовірнісного боку; і статтю Linzen вище, яка коротка й варта повного прочитання.
Примітки
Посилання на розділ: Примітки-
Приклад генерації імен, датасет і перехід від таблиці підрахунків до мережі в стилі Bengio йдуть за серією Andrej Karpathy building makemore, перші дві частини якої — найкращий супровід до цього розділу. ↩
-
Shannon, C. E. Prediction and Entropy of Printed English. Bell System Technical Journal 30(1), pp. 50–64 (1951). Люди вгадують наступну літеру англійського тексту, і початкове вимірювання bits-per-character. ↩
-
Shannon, C. E. A Mathematical Theory of Communication. Bell System Technical Journal 27 (1948). Теорема кодування джерела та ототожнення передбачення зі стисненням. ↩
-
Bengio, Y., Ducharme, R., Vincent, P. and Jauvin, C. A Neural Probabilistic Language Model. Journal of Machine Learning Research 3, pp. 1137–1155 (2003). Архітектура, використана вище: embedding на слово, конкатенований у фіксованому вікні, через hidden layer до softmax над словником. ↩
-
Mikolov, T., Chen, K., Corrado, G. and Dean, J. Efficient Estimation of Word Representations in Vector Space. arXiv:1301.3781 (2013). CBOW і skip-gram, а також набір аналогій, використаний вище. ↩
-
Mikolov, T., Sutskever, I., Chen, K., Corrado, G. and Dean, J. Distributed Representations of Words and Phrases and their Compositionality. arXiv:1310.4546 (2013). Negative sampling, subsampling частих слів і шумовий розподіл у степені 3/4, використані вище. ↩
-
Pennington, J., Socher, R. and Manning, C. GloVe: Global Vectors for Word Representation. EMNLP 2014. Word vectors з факторизації глобальної матриці співпояв замість потокових локальних вікон. ↩
-
Linzen, T. Issues in evaluating semantic spaces using word analogies. RepEval 2016, arXiv:1606.07736. Джерело offset-free baselines, відтворених вище. ↩
-
Peters, M. et al. Deep contextualized word representations. arXiv:1802.05365 (2018). ELMo: один вектор на появу, обчислений bidirectional language model. ↩
-
Devlin, J., Chang, M.-W., Lee, K. and Toutanova, K. BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. arXiv:1810.04805 (2018). Модель, виміряна в експерименті з bank. ↩
-
Press, O. and Wolf, L. Using the Output Embedding to Improve Language Models. arXiv:1608.05859 (2016), and Inan, H., Khosravi, K. and Socher, R. Tying Word Vectors and Word Classifiers. arXiv:1611.01462 (2016). Два незалежні аргументи на користь того самого трюку. ↩
-
Reimers, N. and Gurevych, I. Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks. arXiv:1908.10084 (2019). Його початкове вимірювання — mean-pooled BERT поступається averaged static vectors у sentence similarity — це те, що відтворює таблиця вище. ↩
-
Karpukhin, V. et al. Dense Passage Retrieval for Open-Domain Question Answering. arXiv:2004.04906 (2020). Contrastive training двоенкодерного retriever; прямий предок retrieval stack із Розділу 19. ↩