Внимание (attention): на что смотрит модель
Чтобы понять слово «он» в длинной фразе, модель должна решить, к кому это «он» относится. Механизм внимания — это и есть способ выбрать, на какие слова смотреть внимательнее.
Главная мысль урока: внимание (attention) — это механизм, который для каждого слова решает, на какие другие слова в тексте смотреть внимательнее, а какие почти игнорировать. Именно благодаря ему модель связывает далёкие друг от друга слова и понимает, что к чему относится.
Зачем модели вообще «смотреть» на разные слова
Представь, что ты читаешь сообщение от друга: «Кошка увидела собаку, и она испугалась». Кто испугался — кошка или собака? Ты понимаешь это почти мгновенно, хотя слово «она» само по себе ничего не говорит. Ты как бы кидаешь взгляд назад по фразе, находишь подходящее слово и связываешь их. Вот этот «взгляд назад» — и есть то, что в нейросети называют вниманием.
В прошлом уроке про трансформер без формул мы выяснили, что трансформер умеет учитывать связи между всеми словами сразу. Но как именно он решает, какие связи важны, а какие нет? Ведь в предложении из двадцати слов связей между всеми парами — сотни. Смотреть на всё одинаково внимательно — всё равно что читать учебник, выделяя маркером каждое слово: толку ноль. Нужно уметь выбирать.
Возьмём наш сквозной текстовый пример — фразу Кошка пьёт ..., по которой мы весь курс учимся предсказывать следующее слово. Чтобы выбрать удачное продолжение (скорее всего «молоко»), модели важно как следует разглядеть слова «кошка» и «пьёт». А вот если фраза была бы длиннее — «Серая кошка, которую мы вчера подобрали на улице, пьёт ...» — то между «кошка» и «пьёт» влезла куча других слов. И всё равно модель должна суметь связать именно их. Внимание — это инструмент, который позволяет дотянуться через всю фразу до нужного слова.
К концу урока ты будешь понимать, почему ChatGPT не путается в длинных предложениях так часто, как можно было бы ожидать, и почему иногда всё-таки путается.
Чтобы было совсем наглядно, представь автодополнение в телефоне. Ты пишешь «еду на», и телефон предлагает «работу», «дачу», «встречу». Откуда он берёт варианты? Он смотрит на предыдущие слова. Но простое автодополнение смотрит буквально на одно-два соседних слова и потому часто промахивается, особенно в длинных фразах. ChatGPT же умеет смотреть на всю фразу сразу и выбирать, какие слова из неё реально важны. Эта способность выбирать и есть внимание — и именно она отличает умное продолжение текста от примитивного.
Метафора: класс на контрольной
Представь, что каждое слово в предложении — это ученик в классе, который решает свою задачку. Но задачка не решается в одиночку: чтобы понять свою часть, ученику надо подсмотреть в тетради к соседям. Вопрос только — к кому именно подсмотреть?
Слово «она» из нашего примера — это ученик, который растерялся: «я местоимение, но я не знаю, кого я заменяю». Он оглядывает класс и решает, чьи тетради ему важнее. В тетрадь к «кошке» он заглядывает долго и внимательно, в тетрадь к «собаке» — мельком, а на слова «увидела» и «и» почти не смотрит. Так он собирает подсказки и достраивает свой смысл.
Внимание устроено именно так: для каждого слова модель раздаёт «доли внимания» всем остальным словам. Сумма всех долей равна единице — как будто у каждого ученика есть ровно 100% взгляда, и он распределяет его между одноклассниками. Кому-то достанется 70%, кому-то 5%, а кому-то и вовсе почти ноль.
| Слово, которое «смотрит» | На кого смотрит сильнее всего | Зачем |
| она | кошка | чтобы понять, кого заменяет местоимение |
| пьёт | кошка | чтобы понять, кто совершает действие |
| молоко (предсказываемое) | пьёт, кошка | чтобы выбрать подходящий продолжающий объект |
Заметь: никто заранее не прописывал правило «местоимение смотрит на существительное». Модель сама выучила это на огромном количестве текстов — мы говорили про обучение и веса в разделах раньше. Доли внимания — это тоже результат подбора чисел-весов во время обучения.
Откуда берутся доли внимания
Не пугайся, матана не будет — только идея. Каждое слово уже превращено в эмбеддинг, то есть в набор координат-точку в пространстве смыслов (про это был отдельный урок). Чтобы понять, насколько слову А интересно слово Б, модель сравнивает их представления: чем «совместимее» два слова, тем больше внимания А отдаёт Б. Потом все эти «интересности» нормируют так, чтобы в сумме получилась единица — и вот готовые доли внимания.
Грубо говоря, внимание — это умная функция «насколько мне сейчас важно вот это слово». И она считается заново для каждого слова и в каждом запросе.
Здесь важно одно отличие от живого чтения. Когда читаешь ты, ты сначала понимаешь смысл, а потом решаешь, на что обратить внимание. У модели всё наоборот: сначала она механически считает, насколько совместимы представления слов, и только из этих чисел складывается то, что со стороны выглядит как «понимание». Никакого внутреннего голоса, который думает «ага, тут речь про кошку», у неё нет — есть лишь числа и веса, выученные на текстах. Помни про это, когда тебе будет казаться, что модель «осознаёт» написанное: она просто очень хорошо считает, кто на кого должен посмотреть.
Разбираем на примерах
Дальше будет немного кода. Он не «настоящий трансформер» — настоящий считает на огромных матрицах, и нам это сейчас не нужно. Мы воспроизведём только идею: раздать доли внимания и собрать из них итог. Этого достаточно, чтобы прочувствовать механику.
Пример 1. Раздаём доли внимания
Сделаем фразу «кошка увидела собаку и она испугалась». Зададим вручную, насколько сильно слово «она» тянется к каждому другому слову (это игрушечные числа, в реальной модели их подбирает обучение), и превратим их в доли, дающие в сумме единицу.
// слова фразы и "сырая тяга" слова "она" к каждому из них
const words = ["кошка", "увидела", "собаку", "и", "она", "испугалась"];
const rawScores = [8.0, 1.0, 3.0, 0.5, 0.0, 1.5];
// превращаем тягу в доли так, чтобы сумма была равна 1
const total = rawScores.reduce((a, b) => a + b, 0);
const shares = rawScores.map(s => s / total);
words.forEach((w, i) => {
const percent = (shares[i] * 100).toFixed(1);
console.log(w + ": " + percent + "%");
});
console.log("Сумма долей: " + shares.reduce((a, b) => a + b, 0).toFixed(2));
Что здесь происходит по шагам. Сначала мы складываем все «тяги» в total. Потом каждую тягу делим на эту сумму — получаем долю от 0 до 1. Сумма всех долей по построению равна единице: мы же просто поделили каждое число на общую сумму. В выводе видно, что почти всё внимание слова «она» уходит на «кошка», и совсем чуть-чуть — на остальных.
Вывод:
кошка: 57.1% увидела: 7.1% собаку: 21.4% и: 3.6% она: 0.0% испугалась: 10.7% Сумма долей: 1.00
Видишь? Модель «решила», что «она» — это про кошку (57%), а не про собаку (21%). Никаких правил грамматики мы не писали — только числа тяги. В настоящей модели эти числа не задаются руками, а вырастают из весов во время обучения.
Пример 2. Собираем смысл из того, на что смотрим
Доли внимания — это полдела. Дальше слово должно собрать из соседей их «смысл», но взвешенно: у кого больше доля, того и вклад больше. Представим смысл каждого слова одним числом-эмбеддингом (в реальности это длинный список чисел, но идея та же) и посмотрим, какой итог соберёт слово «она».
const words = ["кошка", "увидела", "собаку", "и", "она", "испугалась"];
// игрушечный "смысл" каждого слова одним числом
const meaning = [10, 2, 7, 0, 5, 3];
// доли внимания слова "она" (из примера 1, уже в долях)
const shares = [0.571, 0.071, 0.214, 0.036, 0.0, 0.107];
// взвешенная сумма: каждый смысл умножаем на его долю и складываем
let result = 0;
for (let i = 0; i < words.length; i++) {
result += meaning[i] * shares[i];
}
console.log("Собранный смысл для слова 'она': " + result.toFixed(2));
console.log("Смысл слова 'кошка' был: " + meaning[0]);
console.log("Смысл слова 'собаку' был: " + meaning[2]);
Разбор по шагам. Мы идём по всем словам и каждое его число-смысл умножаем на долю внимания, которую ему отдала «она». Слово «кошка» с долей 0.571 и смыслом 10 даёт большой вклад, а «и» с долей 0.036 — почти ничего. Складываем всё — получаем новый смысл слова «она». Обрати внимание: итог (≈7.3) заметно ближе к смыслу «кошки» (10), чем к «собаки» (7) или к исходному смыслу самой «она» (5). Слово «она» как бы пропиталось смыслом кошки.
Вывод:
Собранный смысл для слова 'она': 7.30 Смысл слова 'кошка' был: 10 Смысл слова 'собаку' был: 7
Вот это и есть суть внимания в двух движениях: раздать доли (на кого смотреть) и собрать взвешенный смысл (что из этого взять). После этого слово «она» уже несёт в себе намёк «я про кошку», и следующим слоям сети работать с ним проще.
Пример 3. Неоднозначная фраза и роль контекста
Возьмём слово, у которого несколько значений: «ключ». Во фразе «он повернул ключ в замке» это металлический предмет, а во фразе «родник бил ключом из земли» — источник воды. Само слово одно и то же, а смысл задаётся соседями. Покажем, как разные соседи перетягивают внимание и меняют итог.
// два контекста для одного слова "ключ"
const contextA = { words: ["повернул", "ключ", "в", "замке"], to: [0.5, 0.0, 0.05, 0.45] };
const contextB = { words: ["родник", "бил", "ключом", "из", "земли"], to: [0.55, 0.1, 0.0, 0.05, 0.3] };
function topNeighbour(ctx) {
let best = 0;
for (let i = 1; i < ctx.to.length; i++) {
if (ctx.to[i] > ctx.to[best]) best = i;
}
return ctx.words[best];
}
console.log("Контекст A — сильнее всего смотрит на: " + topNeighbour(contextA));
console.log("Контекст B — сильнее всего смотрит на: " + topNeighbour(contextB));
Тут to — доли внимания слова «ключ» к соседям. Функция topNeighbour просто ищет, кому досталась самая большая доля. В первом контексте это «замке» — и модель поймёт ключ как предмет. Во втором — «родник», и смысл сместится к источнику воды. Слово не менялось; менялось то, на что оно смотрит.
Вывод:
Контекст A — сильнее всего смотрит на: замке Контекст B — сильнее всего смотрит на: родник
Именно поэтому ChatGPT почти не путает значения слов: он не хранит для слова один «правильный» смысл, а каждый раз пересобирает его из контекста через внимание.
Пример 4. А что насчёт нашей кошки и собаки?
Вернёмся к сквозной задаче «отличить кошку от собаки». Раньше в курсе мы делали это по признакам и через нейросеть на картинках. Но привязка значения к контексту работает и для текста про животных. Сравни: «питомец громко мяукал и тёрся о ноги» и «питомец громко лаял и вилял хвостом». Слово «питомец» одно и то же, а вот к кому оно тянется вниманием — к «мяукал» или к «лаял» — и решает, кошка перед нами или собака. Внимание превращает нейтральное слово в «скорее кошку» или «скорее собаку», глядя на глаголы рядом.
Частые ошибки и подводные камни
Когда впервые разбираешься во внимании, легко наступить на пару граблей. Вот самые частые.
- «Внимание — это понимание». Нет. Модель не «понимает» фразу так, как ты. Внимание — это всего лишь способ выбрать, какие числа взять и с каким весом сложить. Получается убедительно, но за этим нет осознания. Это важная честность про ИИ: умное поведение ещё не равно разуму.
- «Доли внимания могут быть любыми числами». Нет, после нормировки они всегда дают в сумме единицу для каждого слова. Если тебе кажется, что слово «отдало» кому-то 200% внимания — где-то ошибка, ты забыл поделить на сумму, как в примере 1.
- «Внимание считается один раз». На самом деле в трансформере таких слоёв внимания много, и они идут друг за другом. На первом слое «она» цепляется за «кошку», на следующем — уже обогащённое «она» смотрит на другие связи. Один проход — это не вся картина.
- «Если слова далеко друг от друга, модель их не свяжет». Как раз наоборот: внимание умеет дотянуться через всю фразу, ему всё равно, рядом слова или за двадцать слов. Но есть предел — у модели ограничено окно (сколько токенов она держит в поле зрения за раз). Если фраза длиннее окна, начало просто выпадает, и связь теряется. Это не про внимание, а про лимит памяти.
- «Раз внимание точное, ошибок не будет». Будет. Если модель отдаст много внимания не тому слову, она соберёт неверный смысл — и может выдать уверенную чушь. Это одна из причин галлюцинаций: уверенно звучащий, но неверный ответ. Внимание помогает, но не гарантирует правды.
Мини-практика: распредели внимание сам
Теперь твоя очередь. Возьми фразу «Серая кошка, которую мы подобрали, пьёт молоко» и подумай, на какие слова должно смотреть слово пьёт, чтобы выбрать удачное продолжение. Ниже заготовка — впиши свои числа тяги (любые неотрицательные) и запусти. Цель — сделать так, чтобы больше всего внимания доставалось слову «кошка», а слову «которую» — почти ничего.
const words = ["Серая", "кошка", "которую", "мы", "подобрали", "пьёт"];
// ЗАДАНИЕ: подбери числа тяги слова "пьёт" к каждому слову.
// Сделай так, чтобы "кошка" получила больше всех, а "которую" — почти 0.
const rawScores = [1.0, 1.0, 1.0, 1.0, 1.0, 0.0]; // <-- меняй эти числа
const total = rawScores.reduce((a, b) => a + b, 0);
const shares = rawScores.map(s => (total === 0 ? 0 : s / total));
words.forEach((w, i) => {
console.log(w + ": " + (shares[i] * 100).toFixed(1) + "%");
});
const topIndex = shares.indexOf(Math.max(...shares));
console.log("Больше всего внимания у слова: " + words[topIndex]);
Если со стартовыми числами «больше всего внимания» достаётся не «кошке», поменяй rawScores: подними число напротив «кошка» (например, до 8) и опусти напротив «которую» (до 0.2). Запусти снова и убедись, что итоговая строка теперь называет «кошка». Так ты руками почувствуешь, как доли внимания управляют тем, что модель считает важным.
Вывод (для стартовых чисел):
Серая: 20.0% кошка: 20.0% которую: 20.0% мы: 20.0% подобрали: 20.0% пьёт: 0.0% Больше всего внимания у слова: Серая
Дополнительное задание со звёздочкой: добавь в код второе слово-«наблюдателя» — например, местоимение «она» где-нибудь во фразе — и задай ему свои доли. Сравни, на кого смотрят «пьёт» и «она»: скорее всего, оба потянутся к «кошке», но по разным причинам.
Итоги
Давай соберём всё вместе.
- Внимание (attention) — это механизм, который для каждого слова решает, на какие другие слова смотреть внимательнее.
- Работает в два движения: раздать доли (в сумме всегда единица) и собрать взвешенный смысл соседей.
- Благодаря вниманию модель связывает далёкие слова, разбирается, к чему относится «она», и понимает разные значения слова «ключ» из контекста.
- Наши сквозные примеры — «Кошка пьёт ...» и «кошка против собаки» — теперь видны изнутри: модель смотрит на нужные глаголы и существительные и собирает из них предсказание.
- Внимание не равно пониманию, считается во много слоёв, ограничено окном и может ошибаться — отсюда галлюцинации.
В следующем уроке мы соберём всё устройство ChatGPT воедино: посмотрим, как из эмбеддингов, множества слоёв внимания и предсказания токенов получается тот самый чат, который отвечает тебе целыми абзацами. Внимание — это сердце трансформера, и теперь, когда ты понимаешь, как оно выбирает, на что смотреть, остальная картина сложится быстро.