12+
Вектор смысла: новый квадрант

Бесплатный фрагмент - Вектор смысла: новый квадрант

Навигация в пространстве векторного поиска

Объем: 232 бумажных стр.

Формат: epub, fb2, pdfRead, mobi

Подробнее

Предисловие

Эта книга началась с вопроса, который задают все, кто сталкивается с векторным поиском впервые: как это работает? Не в смысле «какой метод вызвать» — это работа документации. А в смысле глубже: почему математика вдруг научилась ловить смысл? Почему «King минус Man плюс Woman» даёт «Queen»? Почему два изображения, не имеющие ни одного общего пикселя, оказываются «похожими»?

Я писал эту книгу для тех, кто хочет понять. Понять — не скопировать код из примера, не настроить по инструкции, не пройти собеседование. Потому что из понимания практика выводится сама. А из практики без понимания — только зависимость от чужих ответов на Stack Overflow, от готовых рецептов, от надежды, что кто-то уже решил твою задачу.

Есть разница между человеком, который знает, какие параметры выставить, и человеком, который понимает, почему именно эти параметры работают для его случая. Первый беспомощен, когда рецепт не срабатывает. Второй может думать сам. Документация молчит, Stack Overflow не знает, языковая модель разводит руками — а понимание остаётся. Вернись к основам. Подумай: что на самом деле происходит? Ответ придёт. Не потому что запомнил — потому что понял.

Разработчик, который слышал про векторные базы данных и хочет разобраться, подходит ли это для его задачи, найдёт здесь фундамент. Инженер, который уже использует Qdrant или Pinecone, но чувствует, что упускает что-то важное в настройках и компромиссах, — заполнит пробелы. Архитектор, которому нужно принять решение о технологии и объяснить его команде, получит язык для этого разговора. А любопытный человек, которому просто интересно, как устроен современный поиск, — добро пожаловать. Любопытство остаётся лучшей причиной читать о технологиях.

Общее у всех этих читателей одно: желание видеть за инструментом принцип. За настройкой — компромисс. За магией — механику. Такой взгляд не обесценивает технологию. Наоборот — делает её по-настоящему своей.

Книга не требует знания линейной алгебры. Не требует опыта работы с нейросетями. Не требует даже глубокого знания программирования — хотя оно поможет оценить некоторые примеры. Единственное, что требуется, — готовность думать. Готовность остановиться на сложном месте, перечитать, связать с тем, что было раньше.

Чего эта книга не даёт? Здесь нет полного описания API, списка всех параметров, примеров на каждый случай — документация справляется с этим лучше и всегда актуальнее. К моменту, когда вы читаете эти строки, какие-то методы уже изменились, какие-то параметры добавились. Синтаксис — ни Python, ни REST, ни gRPC — тоже за пределами этого разговора. Готовых решений для копирования в продакшен не будет. И превращения в эксперта по векторным базам данных — тоже не обещаю.

Зато после прочтения вы будете знать, какие вопросы задавать документации. Куда смотреть, когда что-то не работает. Как думать о проблеме, когда готового ответа нет.

Что она даёт? Понимание. Закончив эту книгу, вы будете знать, почему векторный поиск работает — и где он ломается. Вы поймёте, что стоит за аббревиатурами HNSW, ANN, RAG — не определения из глоссария, а суть идей. Вы увидите компромиссы, которые скрыты за каждой настройкой, и научитесь думать о них осознанно. Быстро, точно, дёшево — выбери два. Не ограничение конкретного продукта — фундаментальный закон. Понимание таких законов меняет способ принимать решения.

Вы перестанете воспринимать технологию как магию и начнёте видеть её как инструмент — со своими возможностями и границами. А инструмент, который понимаешь, служит лучше, чем магия, в которую веришь.

Такое понимание не устареет. Версии API меняются, появляются новые библиотеки, одни продукты вытесняют другие. Принципы остаются. Идея о том, что похожесть — про смысл, а не про байты, не изменится с выходом следующей версии. Знание того, почему приближённый поиск быстрее точного и чем за это приходится платить, останется актуальным и через десять лет.

Книга построена как путешествие. Мы начинаем с простого вопроса — как найти похожее? — и постепенно углубляемся.

Первая часть показывает проблему. Почему наивные подходы не работают? Почему нельзя просто сравнить пиксели или посчитать совпадающие слова? Что вообще значит «похоже» и как математика описывает сходство? Эта часть — фундамент. Она меняет способ думать о поиске.

Вторая часть — история. Откуда взялись эмбеддинги — числовые представления смысла? Как Word2Vec изменил всё в 2013 году? Почему поиск среди миллиардов векторов вообще возможен — ведь сравнить всё со всем нереально? Здесь есть момент красоты: когда «King минус Man плюс Woman» даёт «Queen», математика ловит смысл. Это стоит прочувствовать.

Третья часть — механика. Как устроены векторные базы данных изнутри? Какие решения они принимают за вас, какие оставляют вам? Что означают все эти параметры и почему нет «лучших настроек» — есть только подходящие для конкретной задачи?

Четвёртая часть — практика и границы. Семантический поиск: где он силён, где слаб. RAG: почему это костыль и почему он нужен. Масштабирование: что происходит, когда данных становится много. И наконец — выбор инструмента: когда нужна специализированная база, когда хватит pgvector, а когда векторный поиск вообще не нужен.

Можно читать последовательно — так задумано. Каждая глава опирается на предыдущие, каждая идея готовит следующую. Можно и прыгать. Знаете, что такое эмбеддинги? Вторая часть будет повторением. Интересует только RAG? Начните с десятой главы, хотя я рекомендую хотя бы пролистать девятую.

Одна просьба: не пропускайте первую часть. Даже если вам кажется, что вы всё это знаете. Первые две главы закладывают фундамент — не технический, а концептуальный. Они устанавливают способ думать о похожести, который пронизывает всю книгу. Без этого фундамента остальное рискует остаться набором фактов, а не пониманием.

Несколько слов о Qdrant. Эта книга выросла из работы с Qdrant, и примеры часто используют его терминологию. Она, однако, не реклама продукта и не руководство пользователя. Qdrant здесь — проводник, через которого видна территория. Принципы, о которых мы говорим, универсальны. Они работают в Pinecone, в Milvus, в Weaviate, в pgvector. Меняются детали реализации, но не суть. Работаете с другой базой? Книга всё равно для вас.

Ещё одно. Я старался писать честно. Без маркетингового восторга, без обещаний магии, без «это решит все ваши проблемы». Технология, о которой мы говорим, мощная и красивая. И у неё есть границы. Семантический поиск — поиск по смыслу, не по ключевым словам — не понимает отрицания. RAG, способ давать языковым моделям нужный контекст, ломается на неудачном разбиении текста. Квантизация — сжатие векторов — теряет информацию. HNSW — алгоритм быстрого поиска — иногда промахивается мимо настоящего ближайшего соседа. Не недостатки — свойства. Знать их важнее, чем верить в безграничные возможности.

Здесь показаны и сила подхода, и места, где он ломается. Одно без другого — неполная картина. Восторг без понимания границ — путь к разочарованию. Скептицизм без признания возможностей — упущенные решения. Честность требует и того, и другого.

Иногда я ставлю вопрос и не отвечаю сразу. Иногда оставляю связь неназванной — кто заметит, тот заметит.

Если что-то кажется сложным — это нормально. Остановитесь, перечитайте, свяжите с тем, что было раньше. Понимание не приходит мгновенно. Оно выстраивается. Именно поэтому книга — путешествие, а не справочник.

Последнее. Книга — это разговор. Не лекция, не инструкция, не проповедь. Разговор предполагает, что мы идём вместе. Я знаю эту территорию и покажу её вам. Но я не гуру и не претендую на истину в последней инстанции. Я делаю выборы — что важно, что второстепенно, что опустить — и эти выборы видны. Вы можете с ними не соглашаться.

Если после прочтения вы сможете самостоятельно разобраться в новой векторной базе данных, оценить, подходит ли RAG для вашей задачи, объяснить коллеге, почему «просто сравнить всё со всем» — плохая идея, и принять осознанное решение о том, нужен ли вообще векторный поиск, — книга выполнила свою задачу. Если при этом вы почувствуете красоту момента, когда математика поймала смысл, — тем лучше. Удивление и понимание не мешают друг другу. Они усиливают друг друга.

Добро пожаловать в пространство смыслов.

Часть I: Проблема

Прежде чем решать задачу, нужно её почувствовать. Не прочитать описание — а узнать. Примерить на себя. Понять, почему она вообще существует и почему не решается очевидными способами.

Эта часть — про боль. Про задачу, которая кажется простой, пока не попробуешь её решить. «Найти похожее» — что может быть проще? Оказывается, очень многое. Потому что «похожее» — это не про пиксели и не про буквы. Это про смысл. А смысл измерять куда сложнее, чем кажется на первый взгляд.

Читатель, который пропустит эту часть, потеряет фундамент. Всё остальное в книге — ответы на вопросы, которые здесь задаются. Без вопросов ответы повисают в воздухе.

Глава 1. Поиск похожего

Есть задачи, которые легко сформулировать и трудно решить. «Найти похожее» — одна из них. Мы делаем это постоянно: ищем товар, напоминающий тот, что понравился; документ, связанный с текущим; песню, похожую на любимую. Мозг справляется мгновенно. Компьютер — нет.

Почему? Потому что мозг сравнивает значения, а компьютер видит только данные. Байты. Пиксели. Символы. Между «данными» и «смыслом» — пропасть. Эта глава — о том, как выглядит эта пропасть и почему её нельзя перепрыгнуть наивными методами.

1.1. Миллион фотографий

Представьте: вы строите интернет-магазин. Каталог — миллион товаров. У каждого товара — фотография, название, описание, характеристики. Классический поиск работает: пользователь вводит «красные кроссовки Nike», система находит товары, где в названии или описании есть эти слова. Всё понятно, всё работает. Технология отлажена десятилетиями, инструменты зрелые, задача решена.

А теперь пользователь загружает фотографию. Кроссовки, которые он увидел на улице. Или в соцсети. Или на ком-то в метро. Он не знает бренд, не знает модель, не может описать словами — у него есть только картинка и желание «хочу такие же». Или хотя бы похожие. Что делать?

Можно, конечно, попросить пользователя описать товар текстом. Но попробуйте сами: опишите словами конкретную пару обуви так, чтобы поисковая система нашла именно её среди миллиона других. «Белые кроссовки с синей полосой и толстой подошвой» — сколько результатов вернёт такой запрос? Сотни. Тысячи. И нужный товар может оказаться на двадцатой странице, потому что в его описании написано «спортивная обувь ivory с декоративным элементом navy». Та же пара, другие слова.

Это не экзотический сценарий. Google Lens, Pinterest, Taobao, ASOS — все они решают эту задачу. Загрузи картинку, получи похожие. Для пользователя это выглядит как магия: навёл камеру, нажал кнопку, получил результат. Для инженера — как проблема, у которой нет очевидного решения. Проблема, над которой бились десятилетиями и решили только в последние годы.

Потому что как сравнить две фотографии? Что значит «похожи»?

Одинаковые пиксели? Нет, конечно — тот же товар под другим углом будет иметь совершенно другие пиксели. Сдвиньте камеру на сантиметр, измените освещение, положите товар на другой фон — и попиксельно это будет совершенно другое изображение. Ноль совпадений. При этом для человека — очевидно тот же предмет.

Одинаковые цвета? Ближе, но красная куртка и красный автомобиль — это не «похожие товары». Красный закат и красный перец — тем более.

Одинаковая форма? Уже теплее, но как формализовать «форму»? Как объяснить компьютеру, что кроссовки — это кроссовки, независимо от того, сфотографированы они сбоку, сверху или под углом?

Задача «найти похожее» обманчиво проста в формулировке и удивительно глубока в реализации. Каждый день миллионы людей ищут «что-то похожее на это» — и каждый раз за простым интерфейсом скрывается сложнейшая технологическая задача.

И фотографии — только начало. Та же проблема возникает везде, где нужно искать по смыслу, а не по точному совпадению. Везде, где пользователь знает что хочет, но не может это точно описать. Везде, где «похожее» важнее «точно такого же».

Возьмём документы. Юридическая фирма, архив на сотни тысяч договоров, накопленных за двадцать лет работы. Приходит новый контракт, нужно найти прецеденты — похожие договоры с похожими условиями, чтобы понять типичные формулировки, возможные риски, исторические решения. Поиск по ключевым словам? «Договор аренды» найдёт тысячи результатов, большинство нерелевантных. «Договор аренды нежилого помещения в Москве сроком на 5 лет с правом субаренды» — слишком специфично, можно пропустить релевантные документы, где формулировки чуть другие. «Помещение» в одном договоре, «площадь» в другом, «объект» в третьем — смысл тот же, слова разные. А ведь юристу нужны именно смысловые аналоги, не текстовые совпадения.

Возьмём службу поддержки. База знаний — десятки тысяч статей, инструкций, решений типичных проблем. Годы накопленного опыта, ответы на все возможные вопросы. Клиент пишет: «Приложение вылетает после обновления». Где искать ответ? По слову «вылетает»? Статья может называться «Проблемы совместимости версии 3.2 с iOS 17» — ни одного общего слова с запросом, но это именно то, что нужно. Или клиент напишет «приложение крашится», или «программа закрывается сама», или «не работает после апдейта» — всё это один и тот же вопрос, но для поиска по ключевым словам это четыре разных запроса с разными результатами.

Или рекомендации. Пользователь посмотрел фильм, понравилось. Что предложить дальше? Тот же жанр? Слишком грубо — «комедия» объединяет и лёгкие романтические истории, и чёрный юмор, и абсурдистские эксперименты. Фильм Уэса Андерсона и фильм Адама Сэндлера — оба комедии, но аудитории почти не пересекаются. Того же режиссёра? Может сработать, но ограничивает выбор и не всегда релевантно — режиссёр мог снять очень разные фильмы в разные периоды. С теми же актёрами? Ещё менее надёжно. Что-то с «похожим настроением», с похожей атмосферой, с похожим послевкусием? Отлично, только как измерить настроение? Как объяснить алгоритму, что «Амели» и «Королевство полной луны» — это похожий зрительский опыт, хотя один фильм французский, другой американский, разные жанры, разные годы, разные актёры?

Та же история с музыкой. Spotify и Apple Music каждый день решают эту задачу для сотен миллионов пользователей. Человек слушает песню и хочет «ещё что-нибудь такое». Тот же исполнитель — очевидно, но быстро закончится. Тот же жанр — слишком размыто, «рок» включает в себя тысячи непохожих направлений. Похожий темп, похожие инструменты, похожее настроение — всё это нужно как-то измерить и сравнить.

В науке — аналогично. Исследователь нашёл статью по своей теме и хочет найти связанные работы. Поиск по ключевым словам из заголовка? Пропустит статьи, где та же идея описана другими терминами. Поиск по авторам? Слишком узко. Поиск по цитированию? Ближе, но не учитывает недавние публикации, которые ещё не успели накопить цитаты. Нужен поиск по смыслу — «найди статьи, которые исследуют похожую проблему похожими методами».

Везде одна и та же структура: есть объект, есть коллекция, нужно найти в коллекции что-то «близкое» к объекту. Товар среди миллиона товаров. Документ среди сотен тысяч документов. Песня среди десятков миллионов треков. Статья среди бесконечного потока научных публикаций.

И везде — одна и та же проблема: «близость» определяется смыслом, а не формой. Два изображения похожи не потому, что у них совпадают пиксели, а потому что на них изображено одно и то же. Два документа связаны не потому, что в них одинаковые слова, а потому что они об одном и том же. Две песни воспринимаются как похожие не потому, что совпадают звуковые волны, а потому что они создают похожее ощущение.

Форма — это то, что видит компьютер. Смысл — это то, что видит человек. Между ними — пропасть.

Человек справляется с этим легко. Мы смотрим на две фотографии и мгновенно понимаем: это похожие товары или разные. Мы читаем два документа и чувствуем: об одном они или о разном. Мы слушаем две песни и знаем: это похожая музыка или совершенно разная. Мы не можем объяснить алгоритм — мы не знаем, как именно наш мозг это делает, — но результат выдаём надёжно и быстро.

Компьютер так не может. Компьютер видит массив чисел — яркости пикселей, коды символов, частоты звуковых колебаний. Для него фотография — это таблица из миллионов ячеек, в каждой — три числа от 0 до 255, красный, зелёный, синий. Текст — последовательность кодов Unicode. Музыка — график колебаний давления воздуха. Никакого «смысла», никакого «значения», никакого «похоже на». Только числа.

И вот тут возникает вопрос, который определяет всю дальнейшую историю: можно ли научить машину сравнивать смыслы? Можно ли превратить «это про одно и то же» в вычислимую величину?

Почему очевидные методы не работают — об этом дальше.

1.2. Почему это сложно

Первый рефлекс программиста — попробовать очевидное. Нужно сравнить две картинки? Сравним пиксели. Нужно сравнить два текста? Посчитаем общие слова. Нужно найти дубликаты? Вычислим хэш. Эти методы интуитивно понятны, легко реализуемы, хорошо изучены. Они работают — для других задач. Для поиска по смыслу они бесполезны. И понять почему — значит понять саму природу проблемы.

Начнём с изображений и попиксельного сравнения.

Фотография — это сетка пикселей. Каждый пиксель — три числа: красный, зелёный, синий. Сравнить две фотографии попиксельно — значит взять соответствующие пиксели и посчитать, насколько они различаются. Чем меньше различие — тем более «похожи» картинки. Звучит логично.

На практике это не работает почти никогда.

Возьмите одну и ту же чашку кофе. Сфотографируйте её дважды — один раз чуть левее, другой раз чуть правее. Сдвиг на пять сантиметров. Для человека это очевидно одна и та же чашка, тот же кофе, та же сцена. Для попиксельного сравнения — два совершенно разных изображения. Каждый пиксель сдвинулся, каждый пиксель изменился. Там, где был край чашки, теперь фон. Там, где был фон, теперь чашка. Совпадений почти нет. Алгоритм скажет: это разные картинки, похожесть близка к нулю.

Теперь сфотографируйте ту же чашку при другом освещении. Утром и вечером. При лампе и при свече. Та же чашка, тот же ракурс, та же композиция — но цвета другие. Тени другие. Блики другие. Каждый пиксель изменил свои RGB-значения. Для алгоритма — снова разные картинки.

А теперь сфотографируйте две разные белые чашки на одинаковом белом фоне при одинаковом освещении. Пиксели будут очень похожи — много белого там и тут. Алгоритм скажет: почти одинаковые изображения. Хотя это совершенно разные предметы.

Попиксельное сравнение измеряет не то. Оно отвечает на вопрос «насколько совпадают числа в массивах», а не на вопрос «насколько похоже то, что изображено». Это разные вопросы с разными ответами.

Есть чуть более умные методы. Можно искать не точное совпадение пикселей, а похожие структуры. Можно сравнивать гистограммы цветов — сколько красного, сколько синего, сколько зелёного на картинке в целом. Не попиксельно, а статистически. Можно искать характерные точки — углы, края, контрастные переходы — и сравнивать их расположение. Такие алгоритмы десятилетиями использовались в компьютерном зрении. Они лучше справляются со сдвигами и поворотами. Могут найти тот же объект под другим углом, если угол не слишком отличается.

Но они всё равно сравнивают визуальные свойства, а не смысл. Красное яблоко и красный мяч будут «похожи» по цвету и даже по форме. Фотография кошки анфас и фотография той же кошки в профиль будут «разными» по характерным точкам — точки-то в других местах. А главное — эти методы не понимают, что на картинке. Они видят пиксели, статистику, закономерности. Не видят объекты, не видят сцены, не видят смысл.

Форма — не смысл. Пиксели — не значение. Этот путь никуда не ведёт.

Теперь текст. Кажется, с текстом проще — слова же несут смысл напрямую, в отличие от пикселей. Посчитаем общие слова, и дело в шляпе.

Метод называется «мешок слов» — bag of words. Берём текст, разбиваем на слова, считаем, сколько раз встречается каждое слово. Получаем что-то вроде рецепта: этот документ содержит три слова «договор», два слова «аренда», одно слово «помещение». Другой документ содержит пять слов «договор», одно слово «аренда», три слова «собственность». Сравниваем эти «рецепты» — чем больше совпадений, тем документы «ближе».

Проблема первая: синонимы — разные слова с одинаковым значением. «Автомобиль» и «машина» — одно и то же, но для мешка слов это разные слова. Документ про «автомобили» и документ про «машины» не найдут друг друга, хотя они об одном. «Быстрый», «скорый», «стремительный» — три разных слова, один смысл. «Врач», «доктор», «медик» — то же самое. Язык избыточен, у каждого понятия десятки способов выражения. Мешок слов этого не видит.

Вернёмся к интернет-магазину. Покупатель ищет «красное платье». В каталоге есть «алый сарафан» — именно то, что нужно, идеальное попадание. Но слова не совпадают. «Красное» — не «алый». «Платье» — не «сарафан». Для поиска по ключевым словам это промах. Товар не найден. Покупатель уходит, продажа не состоялась. А ведь достаточно было понять, что «алый» — это оттенок красного, а «сарафан» — это разновидность платья.

Проблема вторая: омонимы — одинаковые слова с разными значениями. «Банк» — это финансовое учреждение или берег реки? «Ключ» — это инструмент, источник воды или разгадка шифра? «Мир» — это планета, отсутствие войны или сообщество людей? «Лук» — овощ или оружие? Одно слово, разные значения. Мешок слов считает слово «банк» и не знает, какой банк имеется в виду. Для него это просто последовательность символов, б-а-н-к, без контекста, без значения. Документ о рыбалке на берегу реки окажется «похож» на документ о финансовых операциях, потому что в обоих есть слово «банк». Документ про стрельбу из лука — на кулинарный рецепт с луком.

Проблема третья: порядок слов. «Собака укусила человека» и «человек укусил собаку» — совершенно разные события, но одинаковые мешки слов. Те же слова, та же частота. Для алгоритма — идентичные документы. Мешок слов теряет структуру, теряет связи между словами, теряет грамматику. Остаётся только набор ингредиентов без рецепта.

Есть улучшенные версии. TF-IDF — метод, который учитывает не просто частоту слов, а их важность: редкое слово весит больше, чем частое. Идея разумная: если слово встречается в каждом документе, оно мало что говорит о конкретном документе. Это помогает: слово «договор» в юридическом архиве встречается в каждом документе и потому почти бесполезно для различения, а слово «субаренда» — редкое и значимое, оно действительно указывает на тему. Но TF-IDF не решает проблемы синонимов и омонимов. Он всё ещё сравнивает слова, а не смыслы. «Субаренда» и «поднаём» для него — разные слова, хотя это одно и то же понятие.

Можно пойти дальше — использовать n-граммы, последовательности из нескольких слов подряд. «Банк реки» и «банк денег» станут разными n-граммами, и омонимы частично разрешатся. Но n-грамм комбинаторно много — каждая пара слов, каждая тройка, каждая четвёрка. Данные становятся разреженными, большинство n-грамм встречаются по одному разу, сравнивать становится сложно. И проблема синонимов всё равно остаётся — «берег реки» и «речной берег» будут разными n-граммами.

Текст — не просто набор слов. Слова — не просто символы. За словами стоит значение, и это значение нельзя вычислить простым подсчётом.

Остаются хэши. Хэш-функция берёт любые данные и превращает их в короткую строку фиксированной длины — «отпечаток пальца» данных. Одинаковые данные дают одинаковый хэш. Разные данные — с очень высокой вероятностью — разные хэши. Сравнить два хэша мгновенно: совпали или нет.

Хэши идеальны для поиска дубликатов. Точных дубликатов. Если нужно найти, есть ли в базе точно такой же файл — хэш справится. Быстро, надёжно, эффективно.

Но «похожее» — это не «точно такое же». Это принципиально другая задача. Измените в документе одну запятую — хэш изменится полностью, станет совершенно другой строкой, будто это другой документ. Измените в фотографии один пиксель — хэш станет другим. Пересохраните JPEG с чуть другим сжатием — хэш изменится, хотя картинка визуально неотличима. Для хэша нет понятия «почти совпадает» или «немного отличается». Есть только «да» и «нет», совпало или не совпало. Бинарно. Абсолютно.

Существуют так называемые locality-sensitive hash — хэши, чувствительные к локальности, к близости объектов. Они устроены хитрее: похожие объекты с некоторой вероятностью получают одинаковые хэши. Это полезно для грубой предварительной фильтрации — быстро отсеять заведомо непохожее. Но это не решение задачи, а вспомогательный инструмент. Степень похожести они не измеряют.

Итак, три наивных подхода — и три тупика.

Попиксельное сравнение измеряет совпадение данных, а не похожесть изображённого. Мешок слов считает слова, а не смыслы. Хэши находят дубликаты, а не похожее.

Все три метода совершают одну и ту же ошибку: они работают с формой, а не с содержанием. С тем, как данные записаны, а не с тем, что они означают. С синтаксисом, а не с семантикой.

Это фундаментальная проблема. Компьютер видит представление — байты, пиксели, символы. Человек видит сквозь представление — объекты, идеи, значения. Наивные методы пытаются сравнивать представления и удивляются, что результаты не совпадают с человеческим восприятием. Они измеряют расстояние между записями, а не между тем, что записано.

Парадокс: чем точнее мы сравниваем данные, тем дальше уходим от сравнения смыслов. Идеальное попиксельное совпадение — это копия, а не похожий объект. Идеальное совпадение слов — это плагиат, а не связанный документ. Точность в неправильном измерении бесполезна.

Чтобы искать по смыслу, нужно как-то добраться до смысла. Нужно превратить «что изображено на картинке» и «о чём этот текст» в нечто, что компьютер может сравнивать. Нужен способ измерить похожесть не данных, а значений. Не формы, а содержания.

Это возможно. Люди научились это делать. Но для этого пришлось переосмыслить само понятие «похоже».

1.3. Что значит «похоже»

Наивные методы провалились не потому, что они плохо реализованы. Они провалились потому, что отвечают на неправильный вопрос. Они спрашивают: «насколько похожи данные?» А нужно спрашивать: «насколько похожи значения?»

Это разные вопросы.

Возьмём две фотографии. На одной — красные кроссовки Nike, вид сбоку, на белом фоне, студийный свет. На другой — те же кроссовки, вид сверху, на деревянном полу, дневной свет из окна. Данные — совершенно разные. Пиксели не совпадают. Гистограммы цветов отличаются. Характерные точки в других местах. С точки зрения данных — два разных изображения.

Но значение — одно. Это один и тот же предмет. Та же модель. Если покупатель ищет именно её, обе фотографии одинаково релевантны. Для задачи поиска — это «похожие» изображения. Не потому что похожи пиксели, а потому что изображено одно и то же.

Теперь возьмём другую пару. На одной фотографии — красные кроссовки Nike. На другой — красный спортивный автомобиль Ferrari. Пиксели? Много красного там и тут, гистограммы похожи. Форма? Обтекаемые линии, динамичный дизайн. С точки зрения визуальных свойств — определённое сходство есть.

Но значение — разное. Совершенно разное. Обувь и автомобиль. Если покупатель ищет обувь, Ferrari не релевантен. Это не «похожие» товары, несмотря на похожие пиксели.

Вот ключевой сдвиг: похожесть — это про смысл, не про байты.

Два объекта «похожи», когда они про одно и то же. Когда они относятся к одной категории, решают одну задачу, вызывают одни ассоциации, отвечают на один вопрос. Неважно, как они записаны — важно, что они означают.

Это не философская абстракция. Это практическое переопределение задачи.

Когда мы говорим «найди похожий товар», мы имеем в виду: найди товар, который выполняет ту же функцию, удовлетворяет ту же потребность, подходит тому же покупателю. Не товар с похожими пикселями на фотографии.

Когда мы говорим «найди связанный документ», мы имеем в виду: найди документ на ту же тему, с той же проблематикой, для той же аудитории. Не документ с теми же словами. Статья о «машинном обучении» и статья об «искусственном интеллекте» могут быть тесно связаны, хотя термины разные. Договор об «аренде» и договор о «найме помещения» — об одном и том же, хотя юридически формулировки различаются. Смысл совпадает, слова — нет.

Когда мы говорим «порекомендуй похожую музыку», мы имеем в виду: найди музыку, которая создаёт похожее настроение, подходит для того же момента, понравится тому же слушателю. Не музыку с похожими частотами звуковых волн.

Смысл. Значение. Содержание. Вот что нужно сравнивать.

Но как? Как превратить «смысл» в нечто измеримое? Как объяснить компьютеру, что кроссовки — это обувь, что обувь — это товар для ношения на ногах, что ношение на ногах — это определённая функция? Как закодировать все эти связи, все эти категории, все эти отношения между понятиями?

Кажется, что задача безнадёжна. Чтобы понимать смысл, нужно понимать мир. Нужно знать, что такое обувь, что такое автомобиль, чем они отличаются и зачем нужны. Нужно иметь модель реальности в голове.

Люди потратили десятилетия, пытаясь построить такие модели вручную. Онтологии, семантические сети, базы знаний, таксономии — всё это способы формально описать, как понятия связаны друг с другом. Эксперты описывали категории, связи, отношения. «Кроссовки — это вид обуви. Обувь — это вид одежды. Одежда носится на теле. Кроссовки предназначены для спорта. Спорт связан с физической активностью.» Кропотливая работа, тысячи правил, годы усилий. Проект Cyc, начатый в 1984 году, пытался описать всё человеческое знание — и продолжается до сих пор, спустя четыре десятилетия.

И это не сработало. Не в полной мере. Мир слишком сложен, слишком изменчив, слишком контекстуален. Всегда есть исключения, всегда есть нюансы, всегда есть случаи, которые не вписываются в схему. Кроссовки можно носить не только для спорта. Некоторая одежда не носится на теле — она вешается в шкаф и ждёт особого случая. Категории размыты, границы подвижны, контекст меняет значение. Ручное описание не масштабируется — мир бесконечен, а эксперты конечны.

Но потом люди нашли другой путь.

Вместо того чтобы описывать смысл явно, можно научить систему улавливать его неявно. Не говорить компьютеру, что «кроссовки похожи на кеды», а показать ему миллионы примеров и позволить самому обнаружить закономерности. Не программировать правила, а обучать на данных.

Это идея, которая изменила всё. Идея, которая кажется очевидной в ретроспективе, но потребовала десятилетий для воплощения.

Если два слова часто встречаются в похожих контекстах — они, вероятно, означают похожие вещи. «Кроссовки» и «кеды» появляются рядом со словами «носить», «бегать», «спорт», «размер», «шнурки». «Автомобиль» и «машина» — рядом со словами «ехать», «дорога», «бензин», «руль», «парковка». Контекст выдаёт значение. Слово определяется своим окружением, своими соседями, своими типичными спутниками. Не нужно объяснять значение слова напрямую — достаточно посмотреть, в каком окружении оно используется, и сравнить с окружением других слов.

Если два изображения распознаются как один и тот же объект — они похожи по смыслу. Если нейросеть, обученная на миллионах картинок, видит на обоих снимках одну и ту же категорию товара — значит, для задачи поиска они релевантны друг другу. Неважно, что пиксели разные. Важно, что система «понимает»: это одна категория.

Понимает в кавычках, потому что никакого настоящего понимания там нет. Нет сознания, нет субъективного переживания в человеческом смысле. Есть статистические закономерности, повторяющиеся структуры в данных, корреляции между признаками. Система не знает, что это такое в человеческом смысле — она не может надеть обувь и побежать. Но для практической задачи этого и не требуется. Система ведёт себя так, будто понимает — и этого хватает, чтобы находить похожее по смыслу. Функция выполняется, задача решается, результат достигается.

Ключевая идея: смысл можно представить как точку в пространстве.

Каждому объекту — тексту, изображению, звуку — сопоставляется набор чисел. Много чисел: сотни, тысячи. Эти числа — координаты точки в многомерном пространстве. Этот набор чисел называют вектором, а процесс превращения объекта в вектор — векторизацией, или созданием эмбеддинга.

Магия в том, что эти числа не произвольны. Они устроены так, что похожие по смыслу объекты оказываются близко друг к другу в этом пространстве. Кроссовки — рядом с кедами, рядом со сникерами, рядом со спортивной обувью. Собаки — рядом с кошками, рядом с домашними питомцами, но далеко от автомобилей и ещё дальше от абстрактных понятий вроде «справедливости». «Врач» — рядом с «доктором» и «медиком», рядом с «больницей» и «лечением», но далеко от «инженера» и «программиста».

Пространство организовано по смыслу. Не по алфавиту, не по длине слова, не по частоте использования — по значению.

Близко в пространстве — значит похоже по смыслу. Далеко — значит разное. Расстояние становится мерой смысловой близости.

Это не метафора. Это буквально так работает. Расстояние между точками в этом пространстве — мера смысловой похожести. Чем меньше расстояние, тем ближе значения.

Задача «найти похожее» превращается в задачу «найти ближайшие точки». Математически точную, вычислимую, решаемую.

Откуда берутся эти волшебные числа? Как научить систему превращать смысл в координаты? Как из миллионов текстов или изображений извлечь структуру, которая отражает человеческое понимание похожести? Это отдельная история, и она удивительна. История о том, как нейросети научились ловить смысл в данных. История о Word2Vec, BERT, CLIP и других прорывах, которые сделали возможным то, что казалось невозможным. Мы расскажем её позже.

А пока важно понять главное: похожесть — это про смысл. И смысл можно представить как положение в пространстве. Это открытие изменило способ поиска информации. Это основа всего, что будет дальше в этой книге.

Мы начали с простого вопроса: как найти похожее? И обнаружили, что вопрос не такой простой. «Похожее» — это не про совпадение данных. Это про близость значений. Про смысл, который прячется за пикселями и буквами, за звуковыми волнами и строками кода.

Наивные методы сравнивают форму и упускают содержание. Они измеряют не то — расстояние между записями вместо расстояния между значениями. Чтобы искать по смыслу, нужно было научиться представлять смысл — превращать его в числа, которые можно сравнивать. Перевести неуловимое «это про одно и то же» на язык математики.

Это удалось. Объект становится точкой в пространстве. Похожие объекты — близкие точки. Поиск похожего — поиск ближайших соседей. Задача, казавшаяся философской, стала вычислительной.

Звучит как магия. Отчасти так и есть — математика поймала смысл, и это по-прежнему удивляет. Но это работающая магия, инженерная магия. За ней стоят алгоритмы, данные, вычисления. И понимание того, как она устроена, даёт власть над ней.

Как именно объект превращается в точку? Что за пространство такое, где смысл становится расстоянием? Что означают все эти сотни чисел? Об этом — следующая глава.

Глава 2. Векторы и пространства

Мы выяснили, что похожесть — это про смысл. Два изображения похожи не потому, что в них совпадают пиксели, а потому, что они про одно и то же. Два текста близки не потому, что в них одинаковые буквы, а потому, что они говорят о схожем. Это философский сдвиг — от сравнения данных к сравнению значений. Но философия не поможет написать код. Нужен способ измерить смысл. Превратить интуитивное «похоже» в число, с которым можно работать.

Звучит как невозможная задача. Смысл — это что-то неуловимое, человеческое, не поддающееся формализации. Как измерить, насколько «кот на диване» похож на «кошку на кресле»? Как сравнить статью о политике со статьёй об экономике? Интуиция подсказывает ответ, но интуицию в код не вставишь.

Здесь на сцену выходит математика — но не та, что пугает формулами и греческими буквами. Математика как способ думать. Как язык, на котором можно говорить о близости и различии. Векторы и пространства — не абстракция из учебника линейной алгебры. Это ментальная модель, которая позволяет увидеть смысл буквально: как точку, у которой есть место. И оказывается, этого достаточно.

2.1. Вектор как адрес

Начнём с простого. Представьте карту города. Чтобы найти любое место, достаточно двух чисел — широты и долготы. Эти два числа однозначно определяют точку на поверхности Земли. Москва — одна пара координат, Токио — другая, кофейня за углом — третья. Каждое место имеет свой адрес, и этот адрес — всего лишь два числа.

Это настолько привычно, что мы не задумываемся о красоте идеи. Вся поверхность планеты — любой пляж, любая вершина, любой перекрёсток — описывается двумя числами. Бесконечное разнообразие мест сжато до пары координат. И этого хватает, чтобы однозначно указать на любое из них.

Вектор — это тот же адрес. Только не на карте, а в пространстве. И не обязательно два числа — может быть три, десять, тысяча. Суть не меняется: набор чисел, который указывает на конкретную точку.

В двух измерениях всё наглядно. Лист бумаги, две оси — горизонтальная и вертикальная. Любая точка на листе описывается парой чисел: сколько вправо, сколько вверх. Точка (3, 5) — это три единицы вправо и пять вверх. Точка (7, 2) — семь вправо, две вверх. Ничего сложного.

Три измерения тоже можно представить. Комната. Длина, ширина, высота. Чтобы указать на лампочку под потолком, нужны три числа: сколько от стены, сколько от другой стены, сколько от пола. Точка (2, 3, 2.5) — и мы знаем, где именно висит лампочка. Три координаты вместо двух, но принцип тот же.

А теперь — прыжок. Что если измерений не три, а триста? Или три тысячи?

Интуиция протестует. Мы живём в трёхмерном мире, мы не можем «увидеть» пространство из тысячи измерений. Четвёртое измерение уже не укладывается в голове, что говорить о тысячном?

Но видеть и не нужно. Достаточно понимать принцип: каждое измерение — это ещё одна координата. Ещё одно число в адресе. Вектор из тысячи чисел — это точка в тысячемерном пространстве. Не более загадочно, чем GPS-координаты, просто чисел больше.

Вот что важно: наша неспособность визуализировать многомерное пространство — ограничение восприятия, не ограничение математики. Компьютеру всё равно, сколько измерений. Для него вектор из трёх чисел и вектор из трёх тысяч — просто массивы разной длины. Операции те же. Принципы те же.

Возьмём что-то осязаемое. Допустим, мы описываем яблоки. В простейшем случае — два параметра: вес в граммах и цена в рублях. Яблоко весом 150 граммов по цене 30 рублей — вектор (150, 30). Другое яблоко, 200 граммов за 45 рублей — вектор (200, 45). Два числа, две координаты, точка на плоскости. Можно нарисовать.

Теперь добавим параметры. Кислотность по шкале от 1 до 10. Содержание сахара в процентах. Диаметр в сантиметрах. Оценка вкуса от покупателей. Срок хранения в днях. Каждый параметр — новое измерение. Яблоко теперь описывается не двумя числами, а семью. Вектор (150, 30, 6, 12, 7.5, 4.2, 14) — это конкретное яблоко в семимерном пространстве яблок. Нарисовать уже нельзя, но вычислять — можно.

Заметьте: мы не потеряли яблоко. Мы его не упростили до неузнаваемости. Мы описали его набором характеристик — и каждая характеристика стала координатой. Чем больше характеристик мы учтём, тем точнее описание, тем больше измерений. Яблоко осталось яблоком, просто теперь у него есть адрес в пространстве всех возможных яблок.

И вот ключевой момент. Когда мы говорим о смысле текста или содержании изображения, происходит то же самое — только измерений гораздо больше, и они не такие очевидные, как вес или цена.

Современные модели превращают текст в вектор из сотен или тысяч чисел. Каждое число что-то «значит» про этот текст — хотя объяснить словами, что именно, часто невозможно. Это не вес и не цена. Это абстрактные характеристики, которые нейросеть научилась выделять сама. Но принцип остаётся: текст становится точкой в пространстве. Адресом. Набором координат.

Можно думать об этом так: у текста есть множество неявных свойств. Насколько он формальный или разговорный. Про технологии или про искусство. Позитивный или негативный. Длинный или короткий. Конкретный или абстрактный. Сотни таких свойств, которые мы чувствуем интуитивно, но не называем явно. Модель превращает эти неявные свойства в числа. Координата номер 47 может отвечать за «техничность» текста. Координата 238 — за эмоциональную окраску. Координата 891 — за что-то, чему и названия нет, но что влияет на смысл.

Изображение — та же история. Модель смотрит на картинку и выдаёт вектор. Пятьсот чисел, тысяча, две тысячи — зависит от модели. Эти числа описывают картинку не попиксельно, а по смыслу. Что на ней изображено, какой стиль, какое настроение, какая композиция — всё закодировано в координатах. Фотография заката и картина заката маслом могут иметь совершенно разные пиксели, но близкие векторы — потому что они про одно и то же.

Слово «эмбеддинг» — от английского embedding, «вложение» — означает именно это: вложить объект в пространство. Дать ему адрес. Превратить текст, картинку, звук или что угодно ещё в вектор, в точку с координатами. Термин звучит технически, но идея проста: мы берём что-то сложное — текст со всеми его нюансами, изображение со всеми его деталями — и сжимаем в компактный набор чисел. Теряем ли мы при этом что-то? Да. Но сохраняем главное: суть. Смысл. То, что делает объект похожим на одни объекты и непохожим на другие.

Почему это работает? Потому что пространство — мощная метафора, которая оказалась не просто метафорой. Когда объекты превращены в точки, с ними можно делать то, что делают с точками: измерять расстояние между ними. А расстояние — это уже кое-что конкретное. Кое-что, что можно вычислить, сравнить, упорядочить.

Но прежде чем перейти к расстояниям, задержимся на секунду. Вектор из тысячи чисел — это не страшно. Это просто длинный адрес. Когда курьер везёт посылку, ему нужен адрес: страна, город, улица, дом, квартира, этаж, код домофона. Семь-восемь «координат», и посылка находит получателя. Вектор из тысячи чисел — то же самое, только координат больше. И каждая координата сужает область поиска, уточняет положение точки в пространстве.

Многомерность пугает, пока думаешь о ней как о чём-то визуальном. Как о комнате с тысячей стен, которую нужно себе представить. Не нужно. Стоит воспринять её как просто длинный список чисел — и страх уходит. Список можно хранить в памяти компьютера. Можно сравнивать два списка. Можно вычислять, насколько они отличаются. Математика работает одинаково что в двух измерениях, что в двух тысячах. Это её сила и это наш инструмент.

Итак, первый шаг сделан. Объекты — тексты, изображения, что угодно — можно превратить в векторы. Точки в пространстве. Адреса. Каждый объект получает своё место, свой набор координат. Откуда берутся эти координаты, как именно модель их вычисляет — вопрос следующих глав. Сейчас важно другое: у нас есть способ поместить смысл в пространство. Дать ему место. Сделать его измеримым.

Но что нам это даёт? Пока — ничего, кроме красивой идеи. Объекты стали точками. Дальше что?

Дальше — расстояние. Если два объекта превратились в две точки, между ними можно измерить расстояние. И вот тут начинается магия: расстояние между точками оказывается мерой похожести между объектами. Близко — значит похоже. Далеко — значит разное. Простая идея с далеко идущими последствиями.

Но как именно измерить это расстояние? И всегда ли «расстояние» означает одно и то же?

2.2. Расстояние между смыслами

У нас есть точки в пространстве. Тексты, изображения, любые объекты — каждый получил свой адрес, свой вектор. Теперь нужно научиться отвечать на вопрос: насколько две точки близки друг к другу?

На первый взгляд, вопрос тривиальный. На второй — оказывается глубже, чем кажется.

В обычном мире это очевидно. Расстояние между двумя городами — сколько километров по прямой. Расстояние между двумя точками на листе бумаги — можно измерить линейкой. Мы делали это в школе: есть две точки, есть формула, получаем число. Чем меньше число — тем ближе точки. Проще некуда.

В многомерном пространстве принцип тот же. Есть два вектора — два набора чисел. Нужно вычислить, насколько они отличаются. Получить одно число, которое скажет: эти объекты почти одинаковые, или они совершенно разные, или где-то посередине. Одно число — вердикт о похожести.

Но тут возникает неожиданный вопрос: а что значит «расстояние»?

В повседневной жизни мы не задумываемся об этом. Расстояние — это расстояние. Метры, километры, шаги. Линейка не врёт. Но математика знает много способов измерить «разницу» между точками. И выбор способа влияет на результат. Иногда — драматически.

Самый интуитивный способ — евклидово расстояние. Названо в честь древнегреческого математика, но идея проще некуда: это расстояние по прямой. Если представить две точки на плоскости и соединить их линией — длина этой линии и есть евклидово расстояние. То, что мы измеряем линейкой. То, что имеем в виду, когда говорим «от Москвы до Петербурга столько-то километров».

В двух измерениях это работает наглядно. Точка А в координатах (2, 3), точка Б в координатах (5, 7). Соединяем прямой, измеряем. Получается 5 — это и есть расстояние между ними. В трёх измерениях принцип тот же, только учитываем ещё и высоту. В тысяче измерений — ничего нового, просто координат больше. Формула усложняется, но суть остаётся: берём разницу по каждой координате, складываем определённым образом, получаем число.

Евклидово расстояние хорошо работает, когда нас интересует буквальная близость. Насколько один вектор отличается от другого по абсолютным значениям. Если координаты — это что-то измеримое, вроде веса или цены, евклидово расстояние имеет прямой смысл. Яблоко весом 150 граммов ближе к яблоку весом 160 граммов, чем к яблоку весом 300. Логично. Понятно. Работает.

Но для смыслов есть способ лучше.

Возьмём два текста. Один — короткая заметка о кофе. Другой — длинная статья о кофе. Они про одно и то же, но длина разная. Если мы превратим их в векторы, короткий текст может дать «маленький» вектор, длинный — «большой». Евклидово расстояние между ними окажется значительным, хотя тексты очень похожи по смыслу.

Это проблема. Мы хотим измерять близость смыслов, а не близость размеров.

Здесь помогает другой подход — косинусное сходство. Вместо того чтобы измерять расстояние между точками, мы измеряем угол между направлениями.

Представьте себе это так. Вы стоите в начале координат — в точке (0, 0). Смотрите на точку А. Потом смотрите на точку Б. Угол, на который вам нужно повернуть голову, — это и есть мера различия. Если обе точки в одном направлении, угол нулевой — объекты похожи. Если в противоположных направлениях — угол максимальный, объекты совершенно разные. Если под прямым углом — объекты никак не связаны, ортогональны.

Красота этого подхода в том, что он игнорирует «длину» вектора. Короткий текст и длинный текст про одно и то же будут указывать в одном направлении — и косинусное сходство скажет, что они близки. Не важно, что один вектор «короче» другого. Важно, куда они направлены.

Это как компас. Два корабля могут быть на разном расстоянии от порта, но если оба плывут на север — они движутся в одном направлении. Косинусное сходство измеряет именно это: совпадение направлений, а не совпадение положений. Направление — это суть. Расстояние от начала координат — это шум, который мы отбрасываем.

На практике для текстовых эмбеддингов косинусное сходство используется почти всегда. Оно лучше схватывает семантическую близость — похожесть по смыслу, а не по форме. Два документа разной длины, но об одном и том же, окажутся близкими. Два документа одинаковой длины, но о разном, окажутся далёкими. Именно это нам и нужно.

Для изображений ситуация похожа. Фотография высокого разрешения и её уменьшенная копия должны считаться похожими — они про одно и то же. Косинусное сходство справляется с этим лучше, чем евклидово расстояние.

Есть и другие метрики. Манхэттенское расстояние — как если бы вы шли по улицам Нью-Йорка, где нельзя срезать по диагонали, только вдоль кварталов. Скалярное произведение учитывает и направление, и длину — когда важно не только куда смотрит вектор, но и насколько он «сильный». Расстояние Хэмминга считает, в скольких позициях два вектора различаются — удобно для бинарных данных, где координаты только 0 и 1.

Для разных задач — разные метрики. Выбор влияет на результат. Иногда — решающим образом.

Но главное не в формулах. Главное — в идее.

Мы взяли абстрактное понятие «похожесть» и превратили его в число. Два текста — два вектора — одно число, которое говорит, насколько они близки. Два изображения — два вектора — одно число. Любые два объекта, которые можно превратить в векторы, можно сравнить. Универсальный язык для описания сходства.

И это число имеет смысл. Не произвольный, не случайный. Если модель эмбеддингов хорошая, близкие по смыслу объекты получают близкие векторы. Тексты про кофе оказываются рядом друг с другом. Тексты про кофе и тексты про чай — чуть дальше, но всё ещё в одной области, в области напитков. Тексты про кофе и тексты про квантовую физику — далеко друг от друга, в разных концах пространства.

Пространство смыслов обретает структуру. Похожее — рядом. Разное — далеко. Это не метафора. Это буквально так: близкие расстояния в пространстве векторов соответствуют близости смыслов в нашем понимании.

Можно представить это как карту. Только не географическую, а семантическую. На этой карте есть области: область текстов про технологии, область текстов про кулинарию, область текстов про политику. Внутри области технологий — подобласти: машинное обучение, веб-разработка, базы данных. И так далее, вглубь. Похожие тексты собираются в кластеры, разные — расходятся в стороны. Структура возникает сама, из расстояний между векторами. Никто её не программировал. Она проявилась.

Поиск похожего теперь превращается в геометрическую задачу. Есть запрос — текст, изображение, что угодно. Превращаем в вектор — помещаем на карту. Теперь нужно найти в базе векторы, которые ближе всего к этому. Ближайшие соседи. Самые маленькие расстояния. Это уже не философия, это алгоритм. Это код, который можно написать и запустить.

Звучит просто. Есть миллион векторов в базе, есть один запрос. Вычисляем расстояние от запроса до каждого из миллиона, находим минимальные. Сортируем. Берём первые десять. Готово.

Алгоритм прямолинейный, честный, правильный. И совершенно непрактичный на больших масштабах.

На тысяче векторов — мгновенно. На миллионе — терпимо, секунда-другая. На миллиарде — минуты на каждый запрос. Неприемлемо. Но это проблема следующих глав. Там мы узнаем, как люди научились искать быстро, пожертвовав кое-чем другим.

Пока важно другое. Расстояние между векторами — это мера похожести между объектами. Близко — значит похоже. Далеко — значит разное. У нас есть способ измерить смысл. Превратить интуитивное «это похоже на то» в конкретное число. Этого достаточно, чтобы построить поиск.

Однако здесь нужно предупреждение. Всё, что мы обсуждали, прекрасно работает в двух, трёх, даже десяти измерениях. Но эмбеддинги живут в сотнях и тысячах измерений. И там происходят странные вещи.

2.3. Проклятие размерности

Мы привыкли к трёхмерному миру. Верх и низ, лево и право, вперёд и назад — три направления, всё под контролем. Интуиция работает.

А теперь — тысяча измерений. Тысяча независимых направлений. Тысяча осей, перпендикулярных друг другу. Не укладывается в голове? Ни у кого не укладывается. И это не просто ограничение воображения — в высоких измерениях математика ведёт себя иначе. Интуиция, отточенная миллионами лет эволюции, начинает врать.

Вот первая странность. Возьмём куб. В двух измерениях — квадрат. Его площадь равна стороне в квадрате. Сторона 2 — площадь 4. В трёх измерениях — обычный куб. Его объём — сторона в кубе. Сторона 2 — объём 8. В тысяче измерений — гиперкуб, объект, который невозможно представить. Его «объём» — сторона в тысячной степени. Если сторона равна 2, то объём двумерного квадрата — 4, трёхмерного куба — 8, а тысячемерного гиперкуба — 2 в тысячной степени. Число с тремя сотнями нулей. Больше, чем атомов во Вселенной.

Это кажется абстракцией. Игрой с числами. Но следствия — практические и неизбежные.

Теперь возьмём шар внутри этого куба. Шар, который касается всех сторон куба изнутри. В двух измерениях — круг, вписанный в квадрат. Он занимает большую часть площади квадрата, примерно 78 процентов. В трёх измерениях шар, вписанный в куб, занимает уже только 52 процента объёма. Чем больше измерений — тем меньше доля.

В тысяче измерений шар, вписанный в гиперкуб, занимает исчезающе малую долю его объёма. Практически ноль. Число настолько маленькое, что калькулятор покажет просто 0. Весь «объём» гиперкуба сконцентрирован в его углах, далеко от центра. Шар в центре — почти пуст по сравнению с углами. Центр, который в трёхмерном мире кажется главным местом, в тысячемерном — пустыня.

Какое это имеет отношение к поиску похожего?

Прямое. Когда мы ищем ближайших соседей в высокомерном пространстве, мы сталкиваемся с парадоксом: все точки оказываются примерно одинаково далеко друг от друга.

Это называется «проклятие размерности». Термин ввёл математик Ричард Беллман в 1961 году, но проблема никуда не делась. В пространстве высокой размерности расстояния между случайными точками сходятся к одному значению. Разница между «близко» и «далеко» размывается. Ближайший сосед оказывается лишь чуть ближе, чем самый дальний. Само понятие «ближайший» теряет остроту.

Представьте: вы ищете документ, похожий на ваш запрос. В базе миллион документов. В низкоразмерном пространстве — скажем, в двух измерениях — ближайший документ может быть на расстоянии 0.1, а самый дальний — на расстоянии 100. Разница в тысячу раз. Понятно, кто близок, кто далёк. Выбор очевиден.

В тысячемерном пространстве картина другая. Ближайший документ может быть на расстоянии 45.2, а самый дальний — на расстоянии 47.8. Разница — пять процентов. Все примерно одинаково далеко. Как выбрать «похожих», если похожи все одинаково? Или одинаково непохожи?

Это реальная проблема. Не теоретическая, не надуманная. Не пугало из учебника, а ежедневная реальность. Современные модели эмбеддингов выдают векторы в сотнях и тысячах измерений. BERT — одна из таких моделей для текста — даёт 768 измерений. Некоторые модели — 1536 и больше. Проклятие размерности присутствует всегда, в каждой векторной базе, в каждом семантическом поиске.

И всё же — векторный поиск работает. Миллионы систем используют его каждый день. Поисковики, рекомендательные системы, чат-боты — все они опираются на сравнение векторов в высокоразмерном пространстве. Как это возможно, если расстояния теряют смысл? Если проклятие размерности всё портит?

Ответ в том, что настоящие данные — не случайные точки.

Случайные точки, равномерно разбросанные по гиперкубу, действительно схлопываются в облако, где все одинаково далеки друг от друга. Математика неумолима. Но тексты, изображения, объекты из нашего мира — не случайны. Они имеют структуру. Глубокую, многослойную структуру, порождённую реальностью.

Тексты про кофе похожи друг на друга не случайно — они описывают один и тот же феномен, используют похожую лексику, обращаются к похожему опыту. Фотографии котов похожи друг на друга не случайно — на них изображены существа с четырьмя лапами, усами, определёнными пропорциями тела. Эта похожесть — не артефакт алгоритма, а свойство мира. Мир структурирован, и данные о мире наследуют эту структуру.

Хорошие модели эмбеддингов обучены улавливать эту структуру. Они не разбрасывают векторы случайно по всему пространству. Они группируют похожее рядом, раздвигают разное. Данные из реального мира занимают не всё пространство, а некое подмногообразие меньшей размерности. Грубо говоря — поверхность внутри пространства, а не всё пространство целиком. Тонкая плёнка смысла в океане возможных, но бессмысленных комбинаций.

Это можно представить так. Возьмите лист бумаги — двумерный объект. Сверните его в трубочку и поместите в комнату. Технически бумага теперь в трёхмерном пространстве. Любая точка на ней имеет три координаты — x, y, z. Но точки на бумаге по-прежнему живут на двумерной поверхности. Расстояния между ними осмысленны, если измерять вдоль поверхности, а не напрямую сквозь воздух. Муравей, ползущий по бумаге, не знает о третьем измерении — для него мир двумерен, и расстояния в этом мире реальны.

С эмбеддингами похожая история. Да, они живут в пространстве из тысячи измерений. Формально у каждого вектора тысяча координат. Но подлинные данные — тексты, написанные людьми, фотографии настоящих объектов — кластеризуются на поверхностях гораздо меньшей размерности. Они не заполняют всё доступное пространство, они занимают его малую часть. Поэтому расстояния между ними остаются осмысленными. Поэтому поиск работает.

Есть и другие способы борьбы с проклятием. Инструменты, которые разработали исследователи за десятилетия работы.

Нормализация векторов. Если все векторы привести к единичной длине, они окажутся на поверхности гиперсферы. Это уже не весь объём пространства, а только его граница — тонкая оболочка. Косинусное сходство, о котором мы говорили, фактически работает именно так — сравнивает направления, игнорируя длину. На поверхности сферы проклятие размерности проявляется слабее.

Снижение размерности. Иногда тысяча измерений — избыточно. Многие координаты коррелируют друг с другом, несут дублирующую информацию. Можно спроецировать векторы в пространство меньшей размерности, сохранив структуру расстояний. Методы вроде PCA находят главные направления в данных и отбрасывают остальное — как если бы вы смотрели на статую и рисовали её силуэт на стене. Объём теряется, но форма узнаваема. UMAP идёт дальше, сохраняя локальные соседства. Теряется часть информации, но основные отношения между точками остаются.

Умные алгоритмы поиска. Вместо того чтобы сравнивать запрос со всеми точками подряд, можно построить структуру данных, которая позволяет быстро находить кандидатов. HNSW, о котором речь пойдёт позже, — один из таких алгоритмов. Он не страдает от проклятия размерности так сильно, потому что использует локальную структуру графа, а не глобальные расстояния. Ищет не везде, а там, где вероятнее всего найти.

Важно понимать: проклятие размерности — это не приговор. Это предупреждение. Оно говорит: не верь интуиции слепо. Не думай, что высокоразмерное пространство ведёт себя как трёхмерное. Не экстраполируй опыт трёхмерного мира на тысячу измерений. Но при правильном подходе — с хорошими данными, с правильной метрикой, с умными алгоритмами — работать можно. И нужно.

И люди научились работать. Десятилетия исследований, проб и ошибок привели к инструментам, которые справляются. Не идеально — идеального решения нет и быть не может. Но достаточно хорошо для практических задач. Достаточно хорошо, чтобы искать среди миллиардов векторов за миллисекунды. Достаточно хорошо, чтобы находить похожее там, где наивный подход захлебнулся бы.

Векторный поиск — это искусство компромиссов. Между точностью и скоростью. Между размерностью и вычислительной стоимостью. Между теоретическими ограничениями и практическими потребностями. Проклятие размерности — одно из таких ограничений. Оно не исчезает. Но его можно обойти, если знать, что делаешь. Если понимать, с чем имеешь дело.

Итак, у нас есть ментальная модель. Объекты — тексты, изображения, любые данные — превращаются в векторы. Точки в многомерном пространстве. Адреса в мире смыслов. Расстояние между точками измеряет похожесть между объектами. Близко — значит похоже, далеко — значит разное. Простая идея с мощными следствиями.

Мы узнали, что высокая размерность создаёт проблемы. Проклятие размерности — реальное явление, не выдумка теоретиков. Но мы также узнали, что эти проблемы не непреодолимы. Подлинные данные имеют структуру, и эта структура спасает. Умные алгоритмы и правильные метрики делают своё дело.

Теперь у нас есть язык для разговора о похожести. Есть способ измерить смысл — пусть не идеально, но достаточно хорошо. Есть понимание, почему это работает и где может сломаться.

Осталось понять одно. Мы говорили о векторах как о данности. Текст становится вектором. Изображение становится вектором. Но как именно это происходит? Кто или что превращает слова и пиксели в набор чисел? Откуда берутся эти координаты, которые так точно отражают смысл?

Это история следующих глав. История о том, как люди научились векторизовать мир. От первых попыток — примитивных, неуклюжих, теряющих смысл на каждом шагу — до современных моделей, которые понимают язык и изображения так, будто действительно их понимают. История поворотных моментов и неожиданных открытий. История о том, как математика поймала смысл — и что из этого вышло.

Часть II: Эволюция

Откуда это взялось? Векторные базы данных не возникли из ниоткуда. За ними — десятилетия исследований, ошибок, озарений и снова ошибок. История идей, не хронология продуктов.

Мы привыкли к тому, что технологии появляются готовыми. Открываешь документацию, копируешь код, получаешь результат. Но за каждой строкой API — годы работы людей, которые искали способ превратить смысл в числа. Они ошибались, начинали заново, спорили о направлениях. Иногда целые исследовательские программы заходили в тупик. Иногда случайная идея оказывалась поворотной. И в какой-то момент что-то сработало — так хорошо, что изменило всю область.

Эта часть — о том, как люди научились делать то, что казалось невозможным: измерять похожесть смыслов. Не похожесть букв, не совпадение слов — похожесть того, что стоит за ними. Путь оказался неочевидным. Первые попытки выглядели разумно, но упирались в стену. Прорыв пришёл оттуда, откуда не ждали — не от лингвистов и не от философов, а от инженера, который заставил нейронную сеть предсказывать соседние слова. А потом — цепная реакция: от поиска к генерации, от текста к изображениям и звуку.

Глава 3. Как научились векторизовать

Векторы не падают с неба. Кто-то должен превратить текст, изображение, звук в набор чисел — так, чтобы похожие объекты оказались рядом в пространстве. Это не тривиальная задача. Это центральная задача всей области.

Предыдущая глава дала нам инструмент: если есть векторы, можно измерить расстояние между ними. Близко — значит похоже. Но откуда взять эти векторы? Как превратить фотографию кота в тысячу чисел так, чтобы фотография другого кота оказалась рядом, а фотография собаки — дальше?

Эта глава — история о том, как люди научились это делать. От первых наивных попыток, которые работали, но теряли главное, до момента, когда математика поймала смысл. Путь занял десятилетия. Препятствия казались непреодолимыми. А потом — одна идея перевернула правила игры.

3.1. Тупик ключевых слов

Первая идея была простой и казалась разумной. Текст состоит из слов. Значит, чтобы сравнить два текста, нужно сравнить их слова. Посчитать, какие слова встречаются в обоих, — и вот тебе мера похожести.

Этот подход получил название «мешок слов» — Bag of Words. Название точное: текст буквально превращается в мешок, куда ссыпаны все его слова. Порядок не важен. «Собака укусила человека» и «человек укусил собаку» — один и тот же мешок. Структура предложения исчезает. Контекст исчезает. Остаётся только набор.

Технически это работало так: составляется словарь всех слов, которые встречаются в коллекции документов. Каждому слову присваивается номер — позиция в словаре. Документ превращается в вектор, где на каждой позиции стоит число — сколько раз соответствующее слово встретилось в тексте. Если словарь содержит десять тысяч слов, каждый документ становится вектором из десяти тысяч чисел. Большинство из них — нули, потому что в конкретном тексте используется лишь малая часть всех возможных слов. Такие разреженные векторы легко хранить и быстро сравнивать.

Два документа можно сравнить, сравнив их векторы. Чем больше общих ненулевых позиций, тем больше общих слов, тем документы «похожее». Математика простая, вычисления быстрые, результат понятный. Вектор становится числовым отпечатком документа.

Для некоторых задач этого хватало. Если нужно понять, о чём документ в целом — о медицине, о спорте, о политике, — мешок слов справлялся. Слова «диагноз», «пациент», «лечение» достаточно надёжно указывают на медицинскую тематику, даже если мы не знаем, в каком порядке они стоят.

Но для поиска похожего этот подход быстро упёрся в стену.

Представим интернет-магазин. Пользователь загружает фотографию платья и хочет найти похожие. Но у нас нет фотографий — только текстовые описания товаров. Пользователь не знает точных слов, которые использовал копирайтер. «Элегантное вечернее платье в пол» или «длинный нарядный наряд для торжеств» — как угадать?

Или служба поддержки. Клиент пишет: «Не могу зайти в личный кабинет». В базе знаний есть статья «Проблемы с авторизацией в персональном разделе». Смысл тот же, слова разные. Мешок слов не найдёт.

Первая проблема — синонимы. Пользователь ищет «автомобиль», а в документе написано «машина». Мешок слов не видит связи. Для него это разные слова, разные элементы, нулевое пересечение. Документ о машинах не найдётся по запросу об автомобилях — хотя речь об одном и том же.

Это не редкий случай. Язык избыточен по своей природе. «Дом» и «жилище», «идти» и «шагать», «большой» и «крупный» — пары множатся бесконечно. Профессиональные тексты используют одну терминологию, разговорные — другую. Научная статья о «кардиологических патологиях» не найдётся по запросу «болезни сердца», хотя говорит о том же самом.

Можно попробовать решить это словарём синонимов. Но словарь нужно составлять вручную. Он никогда не будет полным. И он не учитывает контекст: «крутая тачка» и «крутой поворот» используют слово «крутой» в совершенно разных значениях. «Тяжёлый чемодан» и «тяжёлый характер» — разные «тяжёлые».

Вторая проблема — омонимы. «Банк» может означать финансовую организацию или берег реки. «Ключ» — инструмент, источник воды или музыкальный знак. «Лук» — оружие, овощ или модный образ. «Мир» — вселенная, отсутствие войны или община. Мешок слов не различает эти значения. Для него «ключ от квартиры» и «ключ бьёт из-под земли» — одинаково релевантны запросу «ключ».

Появилась идея улучшить подход. Не просто считать слова, а взвешивать их. Так в семидесятых годах родился TF-IDF — Term Frequency–Inverse Document Frequency. Идея элегантная: слово важно, если оно часто встречается в данном документе, но редко — в остальных. «Диагноз» в медицинской статье важнее, чем «и» или «в». Редкие термины получают больший вес, частые служебные слова — почти нулевой.

Формула выглядела изящно. Частота слова в документе умножается на логарифм от общего числа документов, делённого на число документов с этим словом. Чем реже слово в коллекции и чем чаще в конкретном тексте — тем выше его вес. Служебные слова вроде «и», «в», «на» встречаются везде и получают почти нулевой вес — они не помогают различать документы. Специфические термины, характерные именно для данного документа, получают высокий вес — они и есть его «подпись».

TF-IDF работал лучше. Поиск стал точнее. На нём построены классические поисковые системы — те, что индексировали интернет в девяностые и двухтысячные. Он до сих пор используется там, где нужна простота и скорость: в поиске по документации, в фильтрации спама, в начальном ранжировании результатов. Библиотеки для работы с TF-IDF есть в любом языке программирования, их можно поднять за час.

Для своего времени это был шаг вперёд. Пользователь вводил запрос, система находила документы с редкими ключевыми словами из запроса, ранжировала их по весам — и результат был приемлемым. Не идеальным, но работающим. Достаточно хорошим, чтобы построить на этом индустрию.

Но фундаментальные проблемы никуда не делись.

Синонимы по-прежнему невидимы. TF-IDF не знает, что «врач» и «доктор» — одно и то же. Что «быстрый» и «скорый» близки по смыслу. Что «недорогой» и «бюджетный» описывают похожее свойство. Каждое слово существует в изоляции, как будто язык — это просто список несвязанных ярлыков.

Омонимы по-прежнему неразличимы. Алгоритм не понимает, что «лист бумаги» и «лист дерева» — разные вещи. Что «операция на сердце» и «военная операция» не имеют ничего общего, кроме случайного совпадения букв.

И самое главное — смысл по-прежнему теряется. «Мне грустно» и «я в печали» — идентичны по значению, но не имеют ни одного общего слова. TF-IDF покажет нулевое сходство. «Счастлив» и «несчастлив» — противоположны по смыслу, но очень похожи по написанию. Алгоритм решит, что они близки.

Отрицание вообще невидимо для мешка слов. «Этот ресторан хороший» и «этот ресторан нехороший» — почти идентичные мешки. Одно маленькое «не» меняет смысл на противоположный, но статистически это шум. «Фильм понравился» и «фильм не понравился» будут считаться похожими документами.

Порядок слов, который несёт в себе половину смысла, отбрасывается полностью. «Человек кусает собаку» — новость. «Собака кусает человека» — рутина. Для мешка слов это одно и то же. «Я должен тебе сто рублей» и «ты должен мне сто рублей» — идентичные мешки, противоположные ситуации.

Проблема была глубже, чем казалось. Дело не в том, что алгоритмы плохие. Дело в том, что слова — это не смысл. Слова — это ярлыки, которые люди навешивают на смыслы. Один смысл может иметь много ярлыков. Один ярлык может указывать на разные смыслы. Пока мы работаем с ярлыками, мы работаем с поверхностью, не с глубиной.

Исследователи понимали это. В конце восьмидесятых появился латентно-семантический анализ — LSA. Идея была интересной: если слова «врач» и «доктор» встречаются в похожих документах, значит, они как-то связаны. Можно попробовать найти эти скрытые связи математически, разложив огромную матрицу «слова × документы» на компоненты. Под поверхностью буквальных совпадений должна скрываться латентная — скрытая — семантика.

LSA действительно находил некоторые связи. Синонимы иногда оказывались ближе друг к другу. Тематически связанные слова группировались. Результаты были обнадёживающими — казалось, ещё чуть-чуть, и проблема будет решена.

Но метод был громоздким, требовал огромных вычислений, а результаты оставались нестабильными и трудно интерпретируемыми. Главное — он по-прежнему не понимал смысл. Он находил статистические корреляции, но не значения. «Хороший» и «плохой» часто встречаются в одних и тех же контекстах — обзорах, оценках, отзывах — и LSA мог посчитать их близкими. Хотя они противоположны по значению.

Нужен был другой подход. Не сравнивать слова — сравнивать то, что за ними стоит. Но как измерить то, что стоит за словом? Как превратить значение в число?

Десятилетиями это казалось философским вопросом, а не инженерной задачей. Смысл — категория человеческая, субъективная, неуловимая. Лингвисты спорили о природе значения. Философы писали трактаты о референции и денотации. А инженерам нужно было что-то, что можно посчитать.

Можно ли формализовать смысл? Можно ли научить машину понимать, что «король» ближе к «королеве», чем к «карандашу»? Что «бежать» и «мчаться» — почти одно и то же, а «бежать» и «лежать» — нет, несмотря на рифму? Что «не люблю» — противоположность «люблю», хотя отличается всего на два символа?

Интуитивно казалось, что нельзя. Смысл — это то, что понимает человек. Машина оперирует символами, не значениями. Она может сравнить строки, посчитать совпадения, применить статистику — но понять? Это из другой области.

Оказалось — можно. Но решение пришло не из лингвистики и не из философии. Оно пришло из наблюдения за тем, как слова ведут себя в тексте. Из простой идеи, оказавшейся ключом: слово определяется своим окружением.

Лингвист Джон Фёрс сформулировал это ещё в пятидесятых: «Ты узнаешь слово по компании, которую оно водит». Слово «кофе» появляется рядом с «чашка», «утро», «аромат», «бодрость». Слово «чай» — рядом с похожими словами. Значит, «кофе» и «чай» в чём-то близки, хотя сами по себе не похожи. Контекст определяет значение.

Идея красивая. Но от красивой фразы до работающего алгоритма — пропасть. Преодолеть её удалось только через полвека, когда появились нейронные сети, большие данные и достаточно мощные компьютеры. И человек, который соединил всё это вместе.

3.2. Word2Vec

Две тысячи тринадцатый год. Томас Миколов, исследователь из Google, публикует статью с неброским названием. Никаких громких обещаний, никакого маркетинга. Просто описание метода, который он назвал Word2Vec — «слово в вектор».

Идея выглядела почти наивно. Берём огромный массив текстов — всю Википедию, миллионы книг, весь доступный интернет. Строим простую нейронную сеть с одной задачей: по слову предсказать его соседей. Или наоборот — по соседям угадать пропущенное слово. Сеть ошибается, корректирует свои веса, снова ошибается, снова корректирует. Миллиарды раз.

Сама по себе задача предсказания соседних слов не очень интересна. Интересно другое. В процессе обучения сеть вынуждена как-то представлять слова внутри себя. Каждое слово получает внутреннее представление — набор чисел, которые сеть использует для своих вычислений. Эти числа и есть вектор слова.

Миколов обнаружил, что эти векторы — не просто технический артефакт. Они несут смысл.

Слова с похожим значением получали близкие векторы. «Король» оказывался рядом с «королевой», «принцем», «монархом». «Бежать» — рядом с «мчаться», «нестись», «спешить». «Париж» — рядом с «Лондоном», «Берлином», «Римом». Сеть никто не учил, что это столицы. Она сама обнаружила это, наблюдая за контекстами.

Но главное открытие было другим.

Миколов взял вектор слова «король». Вычел из него вектор слова «мужчина». Прибавил вектор слова «женщина». И получил вектор, ближайшим соседом которого оказалась «королева».

King — Man + Woman = Queen.

Стоит остановиться и подумать, что здесь произошло.

Это не метафора. Это буквальная арифметика над векторами. Вычитание и сложение чисел — сотен чисел, но всё равно просто чисел. И результат имеет смысл. Человеческий, интуитивно понятный смысл.

Никто не программировал это правило. Никто не говорил системе, что королева — это женский эквивалент короля. Никто не вводил понятия пола, статуса, власти. Сеть сама извлекла эти абстракции из текстов, наблюдая только за тем, какие слова стоят рядом.

Что это значит? Это значит, что разница между «королём» и «мужчиной» — это что-то вроде «королевскости», статуса, власти. Направление в пространстве, которое можно отделить от конкретных слов. Если добавить этот «королевский» компонент к «женщине», получится «королева». Математика поймала абстрактное понятие, которое, казалось, существует только в человеческом сознании.

Это работало не только для королей. «Париж» минус «Франция» плюс «Италия» давало «Рим». Столица минус страна плюс другая страна — столица той страны. «Москва» минус «Россия» плюс «Япония» — «Токио». Географические отношения закодированы в направлениях пространства.

«Плавать» минус «плавание» плюс «бег» давало «бежать». Инфинитив минус существительное плюс другое существительное — соответствующий инфинитив. Грамматические отношения тоже закодированы. Превращение глагола в существительное — это направление, которое можно применить к другим глаголам.

Сравнительная степень тоже оказалась направлением: «больше» минус «большой» плюс «хороший» давало «лучше». Применив то же направление к «маленький», получали «меньше».

Исследователи находили всё новые примеры. Антонимы оказывались связаны предсказуемым образом. Множественное число отличалось от единственного на один и тот же вектор для разных слов. Прошедшее время — на другой. Языковая структура проявлялась как геометрия пространства.

Векторы выучили грамматику. Выучили географию. Выучили семейные отношения: «отец» минус «мужчина» плюс «женщина» давало «мать». Выучили профессиональные: «доктор» и «медсестра» связаны так же, как «король» и «королева». Никто их этому не учил напрямую — они извлекли эти закономерности из того, как слова встречаются рядом друг с другом в текстах.

Момент стоит осознать. Десятилетиями лингвисты строили сложные теории значения. Философы спорили о природе смысла. А тут — простая нейросеть, обученная угадывать соседние слова, вдруг демонстрирует понимание абстрактных отношений между понятиями. Не идеальное понимание, не человеческое — но работающее. Измеримое. Вычислимое.

Почему это сработало? Потому что Фёрс был прав: слово определяется своим окружением. «Король» появляется в контекстах о власти, тронах, коронах, указах. «Королева» — в очень похожих контекстах. Нейросеть, пытаясь предсказать контекст, вынуждена поместить эти слова близко друг к другу во внутреннем пространстве. Иначе она не сможет делать правильные предсказания.

А «мужчина» и «женщина» появляются в контекстах, которые отличаются предсказуемым образом. Там, где про мужчину скажут «он», про женщину скажут «она». Где у мужчины «жена», у женщины «муж». Эта систематическая разница кодируется как направление в пространстве — вектор, который можно прибавить или вычесть.

Технически Word2Vec устроен просто — проще, чем можно было бы ожидать от такого открытия. Есть два варианта архитектуры. Первый — CBOW, Continuous Bag of Words: сеть получает на вход несколько слов вокруг пропуска и пытается угадать пропущенное слово. Контекст предсказывает центр. Второй — Skip-gram: сеть получает одно слово и пытается предсказать его окружение. Центр предсказывает контекст. Skip-gram работает лучше для редких слов и больших корпусов, CBOW быстрее обучается на небольших данных. Оба дают похожие результаты.

Сама нейросеть — всего два слоя. Входной слой, скрытый слой, выходной слой. Никаких глубоких архитектур, никаких десятков слоёв. Простота была осознанным выбором: Миколов хотел, чтобы модель можно было обучить на огромных данных за разумное время. Глубокие сети учатся медленно. Простая сеть на миллиарде слов побеждает сложную на миллионе.

Размерность векторов — параметр. Можно взять сто измерений, можно триста, можно тысячу. Больше измерений — больше нюансов можно уловить, но и больше данных нужно для обучения. На практике часто используют от ста до пятисот измерений. Каждое измерение — не какое-то конкретное свойство вроде «одушевлённость» или «размер». Это абстрактные оси, которые сеть создаёт сама. Человеку они не интерпретируемы напрямую, но в совокупности они кодируют смысл.

Обучение требует много данных — миллионы и миллиарды слов. Но само по себе обучение быстрое, потому что архитектура простая. На одном компьютере можно обучить модель за часы или дни. По меркам современных нейросетей — мгновенно.

Результат — таблица. Каждому слову из словаря соответствует строка чисел — его вектор. Словарь может содержать сотни тысяч слов. Эту таблицу можно сохранить, распространить, использовать где угодно. Обучение делается один раз, использование — бесконечно.

После публикации Миколова начался бум. Исследователи по всему миру воспроизводили эксперименты, находили новые примеры векторной арифметики, применяли Word2Vec к своим задачам. Статья набрала тысячи цитирований за первый год — редкость для академической работы.

Качество машинного перевода выросло. Раньше системы перевода работали с отдельными словами и фразами, не понимая связей между ними. Теперь переводчик мог использовать то, что «большой» и «огромный» близки, даже если точного перевода в словаре нет.

Поиск стал умнее. Запрос «как починить автомобиль» стал находить статьи про ремонт машин. Не потому что кто-то вручную добавил синоним — потому что векторы этих слов близки.

Системы рекомендаций научились понимать, что пользователю, который читал про «автомобили», может быть интересно и про «машины», и про «транспорт», и про «двигатели». Не потому что это прописано в правилах — потому что эти слова образуют кластер в пространстве смыслов.

Чат-боты стали чуть менее тупыми. Анализ тональности текстов стал точнее. Классификация документов улучшилась. Везде, где раньше приходилось вручную создавать словари и правила, теперь можно было использовать готовые векторы.

Но Word2Vec имел ограничения, и их важно понимать. Не для того чтобы принизить достижение — для того чтобы видеть, куда двигаться дальше.

Первое: один вектор на слово. «Банк» — финансовая организация или берег реки? У Word2Vec один вектор на слово «банк», усреднённый по всем контекстам. В нём смешаны оба значения. Это как средняя температура по больнице — формально верно, практически бессмысленно.

Для редких значений это особенно болезненно. Слово «мир» чаще означает вселенную или отсутствие войны, чем крестьянскую общину. Вектор сдвинут к частым значениям. Редкое значение почти невидимо.

Второе: вектор слова не зависит от контекста. «Холодный приём» и «холодный чай» используют слово «холодный» в разных значениях — метафорическом и буквальном. Но вектор у него один и тот же. «Тяжёлый рок» и «тяжёлый камень» — один вектор «тяжёлый». Word2Vec знает типичные контексты слова, но не адаптируется к конкретному употреблению.

Это фундаментальное ограничение. Смысл слова проявляется в контексте. Без контекста он неопределён. А Word2Vec игнорирует контекст при использовании — только при обучении.

Третье: только слова. Word2Vec работает с отдельными словами, не с фразами, не с предложениями, не с документами. Чтобы получить вектор предложения, нужно как-то скомбинировать векторы слов — усреднить, сложить, взять взвешенную сумму. Это работает, но грубо.

«Не люблю» — это не сумма «не» и «люблю». Отрицание меняет смысл полностью, а не складывается с ним. «Собака укусила человека» и «человек укусил собаку» состоят из одних слов, но означают разное. Порядок важен, а Word2Vec его теряет при переходе к фразам.

Четвёртое: статичность. Обученные векторы фиксированы. Если появилось новое слово или у старого слова появилось новое значение — нужно переобучать всю модель. «Ковид» в 2019 году не существовал. «Твитнуть» в 2005 году не существовало. Язык живёт и меняется, а векторы застывают в моменте обучения.

Эти ограничения будут преодолены позже — в следующих поколениях моделей. Но даже с ними Word2Vec изменил ландшафт. Он показал, что смысл можно вычислять. Что похожесть слов можно измерять расстоянием. Что математика способна ловить абстрактные отношения между понятиями.

Это был концептуальный сдвиг. До Word2Vec компьютеры работали с символами — последовательностями букв, которые нужно было точно сопоставлять. После Word2Vec компьютеры стали работать со смыслами — точками в пространстве, между которыми можно измерять расстояние.

До Word2Vec эмбеддинги были экзотикой — интересной идеей без практического воплощения. После Word2Vec они стали инструментом. Каждый мог скачать готовые векторы, обученные на миллиардах слов, и использовать их в своих приложениях. Барьер входа упал почти до нуля.

Google выложил предобученные векторы в открытый доступ. Три миллиона слов и фраз, трёхсотмерные векторы, обученные на корпусе Google News — сто миллиардов слов. Скачать, загрузить, использовать. Строчка кода — и у тебя есть вектор любого английского слова.

И что ещё важнее — Word2Vec показал направление. Если нейросеть может выучить смысл слов, предсказывая контекст, то почему бы не применить тот же принцип к чему-то ещё? К предложениям. К документам. К изображениям. К звукам. К видео. К чему угодно.

Принцип работал. Оставалось его обобщить.

3.3. От слов к чему угодно

Word2Vec открыл дверь. За ней оказался целый мир.

Почти сразу после публикации Миколова появились вариации. В Стэнфорде создали GloVe — Global Vectors. Другой подход к той же идее: вместо нейросети, предсказывающей контекст, матричное разложение статистики совместной встречаемости слов. Математика другая, результат похожий. Векторы GloVe тоже демонстрировали арифметику смыслов, тоже группировали синонимы, тоже работали в приложениях.

Facebook выпустил FastText. Главная инновация — работа с частями слов, не только с целыми словами. Слово «бесполезный» разбивается на части: «бес», «полез», «ный». Каждая часть имеет свой вектор. Вектор слова — сумма векторов частей. Это решало проблему редких и новых слов. Никогда не видел слово «суперполезный»? Не страшно — его можно собрать из знакомых частей.

Но настоящий прорыв случился в 2018 году.

BERT — Bidirectional Encoder Representations from Transformers. Название громоздкое, идея революционная. Вместо одного вектора на слово — разные векторы в зависимости от контекста. «Банк» в предложении о деньгах и «банк» в предложении о реке получают разные векторы. Наконец-то.

Ключевое слово — bidirectional, двунаправленный. Word2Vec тоже видит контекст с обеих сторон — но создаёт один вектор на слово, усреднённый по всем употреблениям в корпусе. BERT работает иначе: он смотрит на конкретное предложение и создаёт вектор слова именно для этого употребления. Когда он вычисляет вектор слова в середине предложения, он уже «видел» и начало, и конец. Контекст полный, не частичный.

BERT использует архитектуру трансформера — механизм внимания, который позволяет каждому слову «смотреть» на все остальные слова в предложении и решать, какие из них важны для понимания текущего слова. Когда модель вычисляет вектор слова «банк», она видит соседние слова: «деньги», «кредит», «счёт» — и понимает, какое значение имеется в виду. Или видит «река», «берег», «вода» — и выбирает другое значение. Внимание распределяется динамически, по-разному для разных предложений.

Это не просто улучшение — это качественный скачок. Word2Vec знал про слово всё, что можно знать в среднем. BERT знает про слово в конкретном употреблении. Разница как между словарной статьёй и живым разговором.

BERT обучался на двух задачах. Первая — угадать замаскированное слово в предложении. Случайные слова закрываются маской, модель пытается их восстановить по контексту. Это как Word2Vec, но сложнее: нужно учитывать всё предложение, не только ближайших соседей. Вторая задача — определить, следует ли одно предложение за другим в оригинальном тексте. Это учит модель понимать связи между предложениями, логику повествования.

После BERT появились десятки вариаций. RoBERTa — тот же BERT, но обученный тщательнее, на большем количестве данных. ALBERT — облегчённая версия для случаев, когда важна скорость. DistilBERT — ещё легче, с минимальной потерей качества. XLNet, ELECTRA, DeBERTa — каждая модель пробовала новые трюки, выжимала ещё немного качества.

Для русского языка появился RuBERT, обученный на русских текстах. Для медицинских текстов — BioBERT. Для юридических — LegalBERT. Для научных статей — SciBERT. Специализированные модели для специализированных задач.

Но BERT работал только с текстом. А что если нужно векторизовать изображение?

Ещё до BERT свёрточные нейросети научились распознавать объекты на фотографиях. ImageNet, AlexNet, VGG, ResNet — каскад архитектур, каждая точнее предыдущей. Эти сети обучались классифицировать картинки: кошка или собака, автомобиль или велосипед. Но внутри них формировались представления — векторы, которые сеть использовала для классификации.

Исследователи обнаружили, что эти внутренние представления полезны сами по себе. Если взять предпоследний слой сети, обученной на ImageNet, — получится вектор изображения. Похожие изображения дают близкие векторы. Сеть, обученная отличать кошек от собак, попутно научилась понимать, что две фотографии кошек похожи друг на друга больше, чем кошка и собака.

Это работало, но с ограничением. Сети классификации понимали объекты, но не понимали связи между изображениями и текстом. Фотография кошки давала вектор, но этот вектор жил в своём пространстве, отдельном от пространства слов. Нельзя было найти изображение по текстовому запросу, потому что текст и картинки существовали в разных мирах.

В 2021 году OpenAI представил CLIP — Contrastive Language-Image Pre-training. Идея элегантная: обучить модель так, чтобы изображение и его текстовое описание получали близкие векторы. Фотография кошки и фраза «рыжий кот на подоконнике» должны оказаться рядом в едином пространстве. Разные модальности — один язык векторов.

CLIP обучался на четырёхстах миллионах пар «картинка + подпись», собранных из интернета. Подписи к фотографиям, описания товаров, альтернативный текст для изображений — всё, что люди написали рядом с картинками. Данные шумные, не всегда точные, но их много. А в глубоком обучении количество часто важнее качества.

Две сети работают параллельно: одна — визуальный энкодер — превращает изображение в вектор, другая — текстовый энкодер — превращает текст в вектор той же размерности. Задача при обучении — сделать так, чтобы вектор картинки был близок к вектору её подписи и далёк от векторов чужих подписей. Контрастивное обучение: притягивать правильные пары, отталкивать неправильные.

После обучения происходит магия. Можно взять любое изображение, получить его вектор. Взять любой текст, получить его вектор. Сравнить. Если близки — изображение соответствует описанию. Поиск картинок по тексту. Поиск текста по картинке. Единое пространство смыслов для разных модальностей.

«Закат над морем» — и система находит фотографии закатов. Не потому что кто-то разметил их словом «закат». Потому что вектор фразы близок к векторам соответствующих изображений. Модель никогда не видела конкретно эту фотографию с этим описанием — она обобщила принцип.

CLIP показал, что эмбеддинги не обязаны быть мономодальными. Текст и изображения могут жить в одном пространстве. Это открыло совершенно новые возможности.

Позже появились модели, которые добавили туда же аудио. Речь и её транскрипция получают близкие векторы. Музыка и её описание — тоже. Потом видео: клип и его текстовое описание оказываются рядом в пространстве. Теперь можно искать видеоролик по текстовому описанию, находить музыку, похожую на картину, или подбирать звуковое сопровождение к фотографии.

Мультимодальные модели размыли границы между типами данных. Раньше для каждого типа нужна была своя система: текстовый поиск отдельно, поиск по картинкам отдельно, аудиопоиск отдельно. Теперь всё можно свести к единому пространству. Запрос — вектор. База — векторы. Поиск — измерение расстояний. Неважно, текст это, картинка или звук.

Изменился масштаб. Word2Vec учился на миллиардах слов — тогда это казалось огромным. Современные модели учатся на триллионах токенов. Word2Vec занимал мегабайты памяти. Современные модели — гигабайты и терабайты. Word2Vec обучался на одном компьютере за часы. Современные модели требуют кластеров из тысяч GPU и недель непрерывных вычислений. Стоимость обучения одной большой модели измеряется миллионами долларов.

Изменилось качество. Word2Vec ловил базовые семантические отношения — синонимы, аналогии, тематическую близость. Современные модели понимают нюансы, иронию, контекст, культурные отсылки. Word2Vec не различал омонимы — у него один вектор на слово. BERT различает: разные векторы для разных употреблений. Word2Vec не связывал текст и картинки — они жили в разных пространствах. CLIP связывает: единое пространство для всех модальностей.

Сегодня можно взять любой объект — текст, картинку, аудио, видео, молекулу, последовательность ДНК — и превратить его в вектор. Для большинства задач не нужно обучать свою модель: существуют готовые, предобученные на огромных данных. Загружаешь библиотеку, вызываешь функцию, получаешь вектор. Десять лет назад это было исследовательским фронтиром. Сегодня — несколько строк кода.

Для текста на английском есть десятки моделей на любой вкус: быстрые и лёгкие, медленные и точные, специализированные для конкретных областей. Для русского языка — меньше, но достаточно. Для изображений — модели от OpenAI, Google, Meta, десятков стартапов. Для аудио. Для кода — да, программный код тоже можно векторизовать, и похожие функции окажутся рядом.

Выбор модели — отдельная задача, и мы вернёмся к ней позже. Пока важно понять: проблема векторизации в целом решена. Не идеально, не для всех случаев, но решена. Мы умеем превращать смысл в числа.

Эволюция заняла десятилетие. От мешка слов, который терял смысл, до моделей, которые его ловят. От одного вектора на слово до контекстуальных эмбеддингов, которые адаптируются к употреблению. От только текста до любых модальностей в едином пространстве. Каждый шаг казался революцией, пока не приходил следующий. А базовый принцип оставался неизменным: нейросеть учится предсказывать что-то по контексту — и попутно создаёт осмысленные представления. Похожее оказывается рядом. Математика ловит смысл.

Бесплатный фрагмент закончился.

Купите книгу, чтобы продолжить чтение.