- BrainTools - https://www.braintools.ru -

И так, разбираем нейросети по винтикам. Мы уже разобрали градиентный спуск и обратное распространение ошибки [1]. Сегодня погружаемся в самую сердцевину языковых моделей- векторные представления слов.
Представьте, что вы объясняете ребёнку, что такое «яблоко». Вы покажете картинку, дадите попробовать, расскажете, что оно круглое, сладкое, растёт на дереве, а теперь попробуйте объяснить это нейросети. Она не видит, не пробует, но она понимает только числа.
Как же тогда заставить машину понять, что «яблоко» ближе к «груше», чем к «трактору»? Ответ на самом деле кроется в элегантном приёме, который произвёл революцию в NLP- векторных представлениях слов, или эмбеддингах.
Проблема «слепого» кодирования: почему one-hot не работает
Самый наивный подход- это пронумеровать все слова в словаре и закодировать каждое вектором из нулей и одной единицы:
яблоко → [0, 0, 1, 0, 0, ..., 0] (10 000 элементов)
груша → [0, 1, 0, 0, 0, ..., 0]
трактор→ [1, 0, 0, 0, 0, ..., 0]
Это one-hot encoding– надёжный, но семантически мёртвый формат. Для нейросети векторы «яблоко» и «груша» так же различны, как «яблоко» и «трактор»: их скалярное произведение равно нулю, векторы перпендикулярны. Смысл утерян.
Один философский момент: машина не «думает», она оперирует геометрией, чтобы передать смысл- нужно построить пространство, где близость векторов = близость значений.
Вместо разреженного вектора длиной 10 000 мы используем плотный вектор из 50–512 чисел (обычно 300). Каждое число- это координата в многомерном пространстве:
яблоко → [0.24, -1.31, 0.87, ..., 0.05] (300 чисел)
груша → [0.22, -1.29, 0.91, ..., 0.07]
трактор→ [-0.78, 2.14, -1.03, ..., -0.92]
Что происходит? Слова с похожим контекстом использования («яблоко» и «груша» часто встречаются рядом со словами «фрукт», «сладкий», «сад») сдвигаются ближе друг к другу в этом пространстве, а слова из разных семантических полей- расходятся.
Важно то, что признаки в эмбеддингах не интерпретируемы напрямую. Нейросеть сама выявляет абстрактные измерения: не «съедобность», а некая комбинация признаков, которая косвенно отражает её.
Самый знаменитый эксперимент с эмбеддингами- это операции над смыслом:
вектор("король") − вектор("мужчина") + вектор("женщина") ≈ вектор("королева")
Как это работает? Вектор «мужчина» задаёт направление гендерного признака. Вычитая его из «короля», мы получаем «абстрактного правителя». Добавляя «женщину», мы возвращаем гендер, но в ином полюсе. Результат попадает в окрестность слова «королева».
Это следствие того, что эмбеддинги улавливают регулярные паттерны в языке. Аналогичные операции работают для:
Париж − Франция + Германия ≈ Берлин
Москва − Россия + Италия ≈ Рим
В 300-мерном пространстве евклидово расстояние («линейка») обманчиво: векторы могут быть длинными, но направлены в разные стороны. Поэтому в NLP используют косинусное сходство:
1.0– векторы совпадают по направлению («яблоко» vs «фрукт»)
0.0– перпендикулярны («яблоко» vs «трактор»)
-1.0– противоположны («хороший» vs «плохой»)
Именно косинусное сходство лежит в основе поиска по смыслу, кластеризации текстов и работы рекомендательных систем.
Эмбеддинги это обучаемые параметры нейросети. Рассмотрим упрощённую схему Word2Vec (архитектура Skip-gram):
На вход подаётся слово в one-hot кодировке.
Оно умножается на матрицу весов размером (словарь × 300) – это и есть таблица эмбеддингов.
Полученный вектор проходит через нейросеть, которая предсказывает слова из контекста.
При ошибке градиент распространяется назад- и обновляются строки матрицы, соответствующие словам.
В результате слова, часто встречающиеся в похожих контекстах («кот» и «собака» → «пушистый», «лапы», «мяу/гав»), сближаются в векторном пространстве.
Оптимизация на практике: современные фреймворки (PyTorch, TensorFlow) не умножают one-hot вектор на матрицу, тк это неэффективно. Вместо этого используется индекс слова для прямого извлечения строки из матрицы эмбеддингов- операция O(1).
# PyTorch: как это выглядит в коде
import torch
import torch.nn as nn
vocab_size = 10000
embedding_dim = 300
embeddings = nn.Embedding(vocab_size, embedding_dim)
word_index = torch.tensor([42]) # индекс слова "яблоко"
vector = embeddings(word_index) # сразу получаем 300-мерный вектор
print(vector.shape) # torch.Size([1, 300])
Эмбеддинги- это не исторический курьёз. Они- фундамент всего современного NLP:
В трансформерах (BERT, GPT) эмбеддинги слов дополняются позиционными и сегментными.
В мультимодальных моделях (CLIP) текстовые и визуальные эмбеддинги проецируются в единое пространство, поэтому поиск «красная собака» находит нужные картинки.
Даже в рекомендательных системах поведение [3] пользователя кодируется в вектор, близкий к векторам «похожих» пользователей.
Эмбеддинги решают задачу «как подать слово в сеть», но как обрабатывать последовательности? Как учесть порядок слов и долгосрочные зависимости? Ответ на самом деле в архитектурах, которые оперируют этими векторами: рекуррентных сетях, механизме внимания [4] и, конечно, трансформерах.
Автор: Nikta3
Источник [5]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/25210
URLs in this post:
[1] ошибки: http://www.braintools.ru/article/4192
[2] Image: https://sourcecraft.dev/
[3] поведение: http://www.braintools.ru/article/9372
[4] внимания: http://www.braintools.ru/article/7595
[5] Источник: https://habr.com/ru/articles/992928/?utm_campaign=992928&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.