Внимание (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 воедино: посмотрим, как из эмбеддингов, множества слоёв внимания и предсказания токенов получается тот самый чат, который отвечает тебе целыми абзацами. Внимание — это сердце трансформера, и теперь, когда ты понимаешь, как оно выбирает, на что смотреть, остальная картина сложится быстро.

Проверьте себя
1. Что в нейросети делает механизм внимания (attention)?
AХранит для каждого слова один-единственный правильный смысл
BРешает, на какие другие слова смотреть внимательнее при обработке слова
CПереводит текст с одного языка на другой
DСчитает, сколько всего слов в предложении
2. Во фразе «кошка увидела собаку, и она испугалась» на какое слово сильнее всего смотрит «она», если модель решает, что испугалась кошка?
Aсобаку
Bувидела
Cкошка
Dи
3. Чему всегда равна сумма долей внимания одного слова ко всем остальным?
AНулю
BЕдинице (100%)
CКоличеству слов в фразе
DЛюбому числу — это не важно
4. Почему ChatGPT обычно не путает разные значения слова «ключ» (предмет или источник воды)?
AОн заранее запоминает один правильный смысл каждого слова
BОн каждый раз пересобирает смысл слова из контекста через внимание
CОн спрашивает у пользователя, что имелось в виду
DОн использует словарь синонимов
5. Что из перечисленного — правда про внимание?
AВнимание означает, что модель по-настоящему понимает текст как человек
BВнимание считается один раз за всю обработку фразы
CВнимание может ошибиться и собрать неверный смысл, что ведёт к галлюцинациям
DВнимание не способно связать слова, стоящие далеко друг от друга
6. Из каких двух движений состоит работа внимания для одного слова?
AПеревести слово и проверить орфографию
BРаздать доли внимания соседям и собрать их смысл взвешенной суммой
CУдалить лишние слова и добавить новые
DПосчитать длину слова и его частоту