Демо: похожие слова рядом
В прошлый раз мы договорились, что слова можно представить точками в пространстве смыслов. Сейчас ты сам запустишь код, который посчитает расстояние между этими точками и докажет: похожие слова и правда лежат рядом.
Главная мысль урока: если выдать каждому слову координаты-эмбеддинг, то «похоже по смыслу» превращается в «близко по расстоянию». А расстояние между точками — это уже не философия, а пара строк кода, которые ты сейчас запустишь.
Зачем тебе это нужно
Представь поиск по музыке. Ты вбиваешь «грустный медленный трек на вечер», а сервис достаёт песни, в названии которых нет ни одного из этих слов — но по настроению они подходят идеально. Или рекомендации в соцсети: ты лайкнул пару мемов про котов, и лента тут же подсовывает ещё десяток похожих, хотя картинки разные. Как машина понимает, что одно «похоже» на другое?
Секрет в том, что внутри у каждого такого сервиса слова и объекты живут не как буквы, а как точки с координатами. И «похожи» для компьютера буквально означает «лежат близко друг к другу». В прошлом уроке про эмбеддинги — слова как точки мы разобрали эту идею на пальцах. Сегодня доведём её до конца: ты запустишь код, который возьмёт координаты слов и сам посчитает, кто кому ближе.
Вот результат, к которому мы придём за этот урок:
кошка ↔ собака: 0.15 кошка ↔ дом: 1.08 Кто ближе к кошке? собака
Два числа и один вывод — но за ними стоит ровно та идея, на которой работает поиск, рекомендации и сам ChatGPT. Разберём, откуда они берутся.
Эмбеддинг — представление слова или объекта в виде точки в многомерном пространстве, где похожие смыслы лежат рядом.
Метафора: слова как точки на карте
Вспомни карту в телефоне. Каждое место на ней — это пара чисел: широта и долгота. Твоя школа и ближайший магазин имеют близкие координаты, потому что они рядом. А школа и другой город — далёкие координаты, потому что между ними сотни километров. Зная только цифры координат, ты можешь посчитать расстояние, ни разу не выходя из дома.
Эмбеддинги — это такая же карта, только не для городов, а для смыслов. Каждому слову выдаётся набор чисел-координат. И главная хитрость: слова раскладывают так, чтобы близкие по смыслу оказались на карте рядом. «Кошка» и «котёнок» — соседние дворы. «Кошка» и «собака» — соседние улицы (оба животные, оба домашние). А «кошка» и «дом» — разные районы города.
На настоящей карте координат всего две — широта и долгота. У эмбеддингов их сотни: смыслов слишком много, чтобы уложить их на плоский лист. Но идея не меняется от количества чисел. Поэтому в нашем демо мы возьмём всего три координаты на слово — этого хватит, чтобы прочувствовать механику, и при этом числа останутся понятными глазу.
| На карте городов | В пространстве смыслов |
| Место = широта, долгота | Слово = набор координат (эмбеддинг) |
| Рядом = близко географически | Рядом = похоже по смыслу |
| Расстояние считаем по формуле | Расстояние считаем точно так же |
Откуда эта карта берётся? Её никто не рисует вручную. Модель строит координаты сама, пока читает гигантские объёмы текста, и пользуется простым наблюдением: слова, которые встречаются в похожих местах, скорее всего похожи по смыслу. «Кошка» и «собака» постоянно стоят рядом с «гладить», «корм», «питомец», «лапы» — вот их и тянет в один угол карты. А «дом» окружают совсем другие слова, поэтому он оседает в другом районе. Подробно этот механизм мы трогали в прошлом уроке; сейчас нам важно лишь, что готовая карта уже есть, и мы можем с ней работать как с обычными числами.
И ещё одна важная мелочь. Координаты эмбеддингов — это не «настоящие» числа из реального мира, как рост или вес. Это удобная выдумка, которую модель подобрала так, чтобы расстояния отражали смысловую близость. Поэтому бессмысленно спрашивать «а почему у кошки именно 0.9, а не 0.91» — конкретное значение не важно само по себе, важно лишь, насколько оно близко к значениям других слов. Карта работает как система относительных расстояний, а не как линейка с абсолютным нулём.
Как меряют расстояние между точками
Между двумя точками расстояние считают так же, как ты, возможно, делал на уроке геометрии. Берём разницу по каждой координате, возводим в квадрат, складываем и извлекаем корень. На плоскости это знаменитая теорема Пифагора. В пространстве с тремя (или тремя сотнями) координат — всё то же самое, просто слагаемых больше.
Звучит как матан, но в коде это буквально цикл: пробежался по координатам, накопил сумму квадратов разностей, взял корень. Сейчас увидишь — это короче, чем кажется.
Демо 1: кто ближе к кошке — собака или дом
Заведём игрушечную карту смыслов на пять слов. Каждому слову — три координаты. Числа я подобрал руками, по-честному, как если бы их выучила модель: первое число грубо отвечает за «животное ли это», второе — за «съедобное/питьевое», третье — за «живое/домашнее существо». Не вчитывайся в точные значения, важна только их близость.
// Игрушечные эмбеддинги: каждому слову — 3 координаты.
// Похожие по смыслу слова имеют похожие числа.
const emb = {
"кошка": [0.9, 0.1, 0.8],
"котёнок": [0.85, 0.15, 0.75],
"собака": [0.8, 0.2, 0.85],
"молоко": [0.2, 0.9, 0.3],
"дом": [0.1, 0.3, 0.1]
};
// Расстояние между двумя точками (теорема Пифагора).
function dist(a, b) {
let s = 0;
for (let i = 0; i < a.length; i++) {
const d = a[i] - b[i];
s += d * d; // копим квадраты разностей
}
return Math.sqrt(s); // и берём корень
}
const d1 = dist(emb["кошка"], emb["собака"]);
const d2 = dist(emb["кошка"], emb["дом"]);
console.log("кошка ↔ собака:", d1.toFixed(2));
console.log("кошка ↔ дом: ", d2.toFixed(2));
console.log("Кто ближе к кошке?", d1 < d2 ? "собака" : "дом");Вывод:
кошка ↔ собака: 0.15 кошка ↔ дом: 1.08 Кто ближе к кошке? собака
Разберём по шагам, что произошло.
- Завели карту. Объект
emb— это наш мини-словарь: ключ — слово, значение — три его координаты. Это и есть эмбеддинги в самом наглядном виде. - Написали линейку. Функция
distбежит по координатам двух точек, на каждом шаге берёт разницу, возводит в квадрат и копит сумму вs. В конце —Math.sqrt, корень. Это та самая формула расстояния, без всякой магии. - Замерили две пары. «Кошка ↔ собака» дали
0.15— точки почти слиплись. «Кошка ↔ дом» дали1.08— в семь раз дальше. - Сделали вывод. Простое сравнение
d1 < d2— и код сам говорит: собака ближе.
Заметь: код нигде не «знает», что кошка и собака — животные. Он не понимает смысла слов вообще. Он просто сложил и сравнил числа. Вся «понятливость» спрятана в том, как заранее подобрали координаты. Это и есть фокус эмбеддингов: смысл превращается в числа, а дальше работает обычная арифметика.
Полезно остановиться на секунду и оценить, насколько это удобно. Раньше, чтобы научить программу понятию «похоже», пришлось бы вручную прописывать тысячи правил: «кошка похожа на собаку, потому что обе домашние, четвероногие, мяукают или лают...». Это бесконечная и хрупкая работа — на каждое исключение придётся новое правило. Эмбеддинги убирают всю эту возню: вместо правил у нас просто координаты, а вместо «похоже» — одно число-расстояние. Любые два слова можно сравнить одной и той же функцией dist, не придумывая для них ничего особенного. Именно поэтому подход с эмбеддингами оказался таким сильным и лёг в основу почти всего современного ИИ, который работает с текстом.
Демо 2: выстроим всех соседей кошки по близости
Сравнивать по две точки скучно. Давай сделаем то, что делает настоящий поиск: возьмём слово «кошка» и отсортируем все остальные слова по близости к нему — от самого похожего к самому далёкому.
const emb = {
"кошка": [0.9, 0.1, 0.8],
"котёнок": [0.85, 0.15, 0.75],
"собака": [0.8, 0.2, 0.85],
"молоко": [0.2, 0.9, 0.3],
"дом": [0.1, 0.3, 0.1]
};
function dist(a, b) {
let s = 0;
for (let i = 0; i < a.length; i++) {
const d = a[i] - b[i];
s += d * d;
}
return Math.sqrt(s);
}
const target = "кошка";
// все слова, кроме самой кошки
const others = Object.keys(emb).filter(w => w !== target);
// посчитать расстояние до каждого и отсортировать
const ranked = others
.map(w => ({ word: w, d: dist(emb[target], emb[w]) }))
.sort((a, b) => a.d - b.d);
console.log("Слова по близости к «" + target + "»:");
for (const r of ranked) {
console.log(" " + r.word + " → " + r.d.toFixed(2));
}
console.log("Самое близкое:", ranked[0].word);Вывод:
Слова по близости к «кошка»: котёнок → 0.09 собака → 0.15 дом → 1.08 молоко → 1.17 Самое близкое: котёнок
Что мы сделали:
others— все слова, кроме самой кошки (сравнивать слово с собой бессмысленно — расстояние было бы ноль)..map(...)превращает каждое слово в пару «слово + расстояние до кошки»..sort(...)выстраивает эти пары от меньшего расстояния к большему.
И смотри, какой получился порядок: котёнок (это почти кошка), потом собака (другое, но тоже животное), и только потом далёкие дом и молоко. Ровно так интуитивно расставил бы их и ты. Только мы не вкладывали в код никакого здравого смысла — он сам выстроился из чисел. Вот так же, по сути, работает «похожие треки» в музыке и «похожие товары» в магазине: у всего есть координаты, а сервис просто ищет ближайшие точки.
Демо 3: возвращаемся к «Кошка пьёт ...»
Пора вернуть второй сквозной пример курса — фразу, которую модель должна продолжить: «Кошка пьёт ...». В уроке про токены мы видели, что модель подбирает следующий токен. Теперь покажем это через близость точек, чтобы связать обе наши сквозные истории.
Идея такая: у фразы «Кошка пьёт ...» есть свой смысл — «дальше должно идти что-то жидкое, что пьют». Представим этот смысл тоже точкой в нашем пространстве — назовём её context. А дальше поступим как в демо 2: найдём слово-кандидата, чья точка ближе всего к этому смыслу.
// Кандидаты на продолжение фразы и их координаты
const emb = {
"молоко": [0.2, 0.9, 0.3],
"воду": [0.25, 0.85, 0.35],
"сок": [0.3, 0.8, 0.4],
"камень": [0.1, 0.2, 0.9]
};
// Смысл фразы «Кошка пьёт ...»: что-то жидкое и питьевое.
// Это тоже точка в нашем пространстве.
const context = [0.22, 0.88, 0.32];
function dist(a, b) {
let s = 0;
for (let i = 0; i < a.length; i++) {
const d = a[i] - b[i];
s += d * d;
}
return Math.sqrt(s);
}
const ranked = Object.keys(emb)
.map(w => ({ word: w, d: dist(context, emb[w]) }))
.sort((a, b) => a.d - b.d);
console.log("Кошка пьёт ... — кандидаты:");
for (const r of ranked) {
console.log(" " + r.word + " → " + r.d.toFixed(2));
}
console.log("Модель допишет:", ranked[0].word);Вывод:
Кошка пьёт ... — кандидаты: молоко → 0.03 воду → 0.05 сок → 0.14 камень → 0.90 Модель допишет: молоко
Смотри, что вышло. Питьё — молоко, вода, сок — столпилось рядом с точкой смысла фразы, расстояния крошечные. А «камень» — то, что не пьют — улетел далеко. Код выбрал ближайшее: «молоко». Получилось то же самое продолжение «Кошка пьёт молоко», что и в уроке про токены, но теперь ты видишь механику: предсказание следующего слова — это во многом поиск ближайшей точки в пространстве смыслов.
Конечно, у настоящего ChatGPT точку context не задают руками — её вычисляет нейросеть, разглядывая всю фразу целиком. Как именно она это делает, мы разберём дальше в курсе, когда дойдём до трансформера и внимания. Но фундамент ты уже потрогал руками: смысл — это точка, а «подходит» — это «близко».
Частые ошибки и подводные камни
На этом демо новички спотыкаются предсказуемо. Разберём, чтобы ты не попался.
1. Думать, что меньшее расстояние — это «хуже»
Тут всё наоборот, чем с оценками в школе. Чем меньше расстояние, тем больше похожи слова. Ноль означал бы «это одна и та же точка». Поэтому в сортировке мы ставим ближайших первыми: a.d - b.d выстраивает от маленьких чисел к большим, то есть от самых похожих к самым далёким.
2. Искать смысл в самих числах координат
В нашем демо я подписал, за что «отвечает» каждая из трёх координат, чтобы было нагляднее. У настоящих моделей так нельзя: там сотни координат, и ни одна не значит понятную человеку вещь вроде «животное ли это». Смысл живёт не в отдельном числе, а в том, как все координаты вместе располагают точки друг относительно друга. Не пытайся прочитать одну координату как ярлык.
3. Путать эмбеддинг с номером токена
Из прошлых уроков легко всё смешать. Напомню разницу: номер токена — это просто адрес кусочка в словаре, как номер дома, в нём нет смысла. Эмбеддинг — это координаты точки, и вот в них смысл уже зашит: близкие точки — близкие смыслы. Сначала текст превращают в номера токенов, и только потом каждому номеру сопоставляют его эмбеддинг.
4. Забывать, что код не понимает слов
Очень соблазнительно сказать «программа поняла, что кошка похожа на собаку». Нет. Программа сложила квадраты разностей и взяла корень — чистая арифметика. Вся «понятливость» заранее упакована в координаты. Эмбеддинги не делают компьютер умным; они переводят смысл на язык чисел, с которым он умеет работать.
5. Сравнивать точки разной длины
Если у одного слова три координаты, а у другого вдруг две, формула расстояния сломается или даст бессмыслицу — цикл пробежит только по общим координатам. В настоящих моделях у всех слов одинаковое число координат, иначе их нельзя было бы сравнивать. В нашем демо это тоже строго соблюдено: ровно три числа у каждого.
Мини-практика: построй свою карту смыслов
Теперь твоя очередь. Возьми за основу код из демо 2 и поэкспериментируй:
- Добавь в
embсловощенокс координатами[0.78, 0.22, 0.82](это «маленькая собака»). Прогони сортировку по близости к кошке. На каком месте оказался щенок и почему именно там? - Поменяй
targetс"кошка"на"молоко". Кто теперь окажется самым близким соседом? Совпало с твоей интуицией? - Придумай и добавь своё слово из мира игр или музыки — например
тигрилигитара— и сам прикинь ему три координаты по той же логике (животное? съедобное? живое?). Проверь, встало ли оно на ожидаемое место. - В демо 3 поменяй
contextна[0.15, 0.25, 0.85](смысл сместился к «твёрдому, неживому»). Какое слово модель допишет теперь? Объясни, почему изменился ответ.
Лучший способ почувствовать эмбеддинги — не прочитать про них, а самому подвигать координаты и увидеть, как меняется порядок соседей.
Итоги
Сегодня ты не просто прочитал про эмбеддинги — ты запустил код, который превратил смысл в числа и посчитал близость.
- Эмбеддинг — это координаты слова в пространстве смыслов. Похожие по смыслу слова имеют похожие координаты и лежат на карте рядом.
- «Похоже» для компьютера = «близко». Близость считают обычной формулой расстояния (та самая теорема Пифагора), и в коде это короткий цикл с корнем в конце.
- Чем меньше расстояние, тем больше сходство. Поиск похожего — это поиск ближайших точек, как «похожие треки» в музыке.
- Наши сквозные примеры сошлись: «собака» оказалась ближе к «кошке», чем «дом», а фраза «Кошка пьёт ...» дописалась до «молоко» — потому что точка «молоко» ближе всего к смыслу фразы.
- Код не понимает слов — он считает числа. Вся «понятливость» спрятана в том, как заранее подобраны координаты.
Теперь у тебя есть мощная картинка: смысл — это точка, сходство — это расстояние, а предсказание слова — поиск ближайшей точки. Но мы пока сами, руками, задавали точку смысла фразы context. Как настоящая нейросеть сама вычисляет её, глядя на все слова сразу и решая, на какие из них смотреть внимательнее? Это и есть главный секрет ChatGPT — механизм внимания внутри трансформера. К нему мы и направимся в следующих разделах курса.