Перейти к содержимому
ПереводыИсследователи и авторы

Крис Ола: глубокое обучение, NLP и представления

Подробный конспект эссе «Deep Learning, NLP, and Representations»: почему универсальность ничего не объясняет, как эмбеддинги слов сами выучивают сходство и аналогии, общие представления для двух языков и для картинок со словами, рекурсивные сети.

  • Теорема об универсальной аппроксимации не объясняет, почему нейросети работают: она лишь говорит, что сеть может быть таблицей поиска. Таблица запоминает, но не обобщает.
  • Настоящее объяснение, по Оле, — представления (representations): сеть сама находит удачный способ записать данные, и в этой записи задача становится простой.
  • Лучший пример — эмбеддингиэмбеддинг, векторное представлениеEN embedding слов. Их учат ради скучной задачи («правильная ли это фраза?»), а побочным эффектом получаются близость синонимов и аналогии вида «женщина − мужчина ≈ королева − король».
  • Представление, выученное на одной задаче, переносится на другие (предобучение, перенос обучения). И наоборот: разные виды данных — два языка, картинки и слова — можно уложить в одно общее пространство.
  • Рекурсивные (древовидные) сети собирают из представлений слов представления фраз и предложений. Обратная задача — восстановить фразу из вектора — в 2014 году только начинала получаться (Cho и др. — будущий seq2seq).

Эссе — идеальное чтение после урока 4.3.1 «Слова как векторы»: вы уже знаете, что такое эмбеддинг и как работают аналогии, а Ола объясняет, почему это важно для всего глубокого обучения. Раздел про универсальность связан с уроком 3.1.1 «Нейрон, слой, MLP», раздел про кодировщик-декодировщик Cho — с уроком 4.1.5, где вы собираете seq2seq сами.

Помните, что эссе написано в 2014 году, до трансформеров. Модели, о которых говорит Ола, давно устарели, но взгляд «глубокое обучение — это обучение представлений» стал общим местом — от BERT до современных LLM.

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

Почему она верна, проще всего увидеть на перцептронах — нейронах, которые выдают 1, если взвешенная сумма входов превышает порог, и 0 иначе. Пусть на входе nn двоичных признаков. Возможных входов конечное число: 2n2^n. Для каждого можно завести в скрытом слое отдельный нейрон, который загорается только на этом входе, а весами от него к выходу задать нужный ответ. Получилась таблица поиска: «увидел вот это — ответь вот так».

flowchart LR
x["вход: 3 бита"] --> h1["нейрон для 000"]
x --> h2["нейрон для 001"]
x --> h3["…"]
x --> h8["нейрон для 111"]
h1 --> y["выход"]
h2 --> y
h3 --> y
h8 --> y
Универсальность «в лоб»: по скрытому нейрону на каждый возможный вход — это просто таблица поиска

Для n=3n = 3 нужно 23=82^3 = 8 нейронов, для n=30n = 30 — уже больше миллиарда. (В сноске Ола уточняет, что на практике всё не так плохо: один нейрон может покрывать сразу группу входов. Для сигмоид универсальность тоже верна, но доказывать её сложнее.)

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

Эмбеддинг слова — это функция W:слова→RnW: \text{слова} \to \mathbb{R}^n, которая сопоставляет слову вектор из нескольких сотен чисел (Ола пишет: «возможно, от 200 до 500»). Технически это просто таблица — матрица θ\theta, где у каждого слова своя строка: Wθ(wn)=θnW_\theta(w_n) = \theta_n. Вначале строки случайные, а осмысленными они становятся в процессе обучения на какой-нибудь задаче.

Задача-предлог. Пример Олы (по работе Леона Ботту, 2011): берём из Википедии фрагменты по пять слов — «cat sat on the mat» — и у половины портим одно слово на случайное: «cat sat song the mat». Сеть должна отличить нормальный фрагмент от испорченного. Устроена она из двух модулей: WW превращает каждое слово в вектор, а модуль RR по пяти векторам выдаёт 1 («нормально») или 0 («испорчено»).

flowchart LR
w1["cat"] --> W1["W"]
w2["sat"] --> W2["W"]
w3["song"] --> W3["W"]
w4["the"] --> W4["W"]
w5["mat"] --> W5["W"]
W1 --> R["R"]
W2 --> R
W3 --> R
W4 --> R
W5 --> R
R --> o["0 — фрагмент испорчен"]
Модульная сеть: общая таблица эмбеддингов W для всех пяти позиций и классификатор R

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

Похожие слова — рядом. Если спроецировать эмбеддинги на плоскость методом t-SNEt-SNE (стохастическое вложение соседей)EN t-distributed stochastic neighbor embedding (t-SNE)Метод визуализации, сохраняющий соседство точек. Размеры кластеров и расстояния между далёкими кластерами на картинке t-SNE почти ничего не значат., получается карта: числа собираются в одном районе, профессии — в другом. Таблица ближайших соседей (из работы Коллобера и др., 2011) показывает то же: соседи у слова почти всегда родственные по смыслу.

Почему сеть к этому приходит? Замена слова синонимом («a few people sing well» → «a couple people sing well») не меняет правильность фразы. Если WW кладёт «few» и «couple» рядом, то для модуля RR вход почти не изменился. Сеть, которая увидела фразу «the wall is blue» и знает, что она правильная, выигрывает, если подтянет «red» поближе к «blue»: тогда и «the wall is red» будет распознана верно.

Это и есть обобщение. Число возможных пятёрок слов астрономическое, а примеров мало. Близость похожих слов позволяет переносить знание с одной фразы на целый класс похожих — и не только заменой синонимов: «the wall is blue» → «the ceiling is red». Ола замечает, что выигрыш растёт экспоненциально с числом заменяемых слов. И формулирует красиво: все слова, которые вы понимаете, вы встречали раньше, но не все предложения, которые вы понимаете, вы встречали раньше. С нейросетями так же.

Аналогии — это разности векторов. Ещё удивительнее (работы Миколова и др., 2013): отношения между словами кодируются постоянным вектором разности:

W(woman)−W(man)≈W(aunt)−W(uncle)≈W(queen)−W(king).W(\text{woman}) - W(\text{man}) \approx W(\text{aunt}) - W(\text{uncle}) \approx W(\text{queen}) - W(\text{king}).

Читается: «сдвиг от „мужчины“ к „женщине“ примерно такой же, как от „дяди“ к „тёте“ и от „короля“ к „королеве“». Для рода это ещё можно объяснить грамматикой: «she is the aunt», но «he is the uncle», и фраза «she is the uncle» скорее испорчена. Но, как показывает таблица Миколова, так же кодируются и куда более сложные отношения — страна → столица, компания → глава компании. Ола пишет, что это кажется «почти чудом».

Посмотрим на механику с игрушечной таблицей, где координаты подобраны вручную:

import numpy as np
# Игрушечная «таблица эмбеддингов»: строка матрицы θ — вектор слова.
# Координаты придуманы вручную: [мужской/женский, королевский, родственник, шум]
words = ["король", "королева", "мужчина", "женщина", "дядя", "тётя", "стол"]
theta = np.array([
[ 1.0, 1.0, 0.0, 0.1], # король
[-1.0, 1.0, 0.0, 0.2], # королева
[ 1.0, 0.0, 0.0, 0.0], # мужчина
[-1.0, 0.0, 0.0, 0.1], # женщина
[ 1.0, 0.0, 1.0, 0.0], # дядя
[-1.0, 0.0, 1.0, 0.1], # тётя
[ 0.0, 0.0, 0.0, 1.0], # стол
])
W = {w: theta[i] for i, w in enumerate(words)} # W(слово) = строка таблицы
def nearest(v, exclude):
# ищем слово с наибольшим косинусным сходством к вектору v
sims = theta @ v / (np.linalg.norm(theta, axis=1) * np.linalg.norm(v))
order = np.argsort(-sims)
return next(words[i] for i in order if words[i] not in exclude)
print(W["женщина"] - W["мужчина"]) # «вектор пола»
print(W["тётя"] - W["дядя"]) # почти тот же вектор
v = W["король"] - W["мужчина"] + W["женщина"]
print(nearest(v, exclude={"король", "мужчина", "женщина"}))
[-2. 0. 0. 0.1]
[-2. 0. 0. 0.1]
королева

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

Можно ли сделать с эмбеддингами что-то полезное, кроме проверки «правильности» пятёрок слов? Да.

Выучив WW на задаче A, можно взять его готовым и обучить поверх новый модуль GG для задачи B. Ола цитирует Луонга и др. (2013): представления слов стали «секретным ингредиентом» многих NLP-систем — для распознавания именованных сущностей, разметки частей речи, синтаксического разбора. Этот приём называют по-разному, в зависимости от деталей: предобучение, перенос обученияперенос обученияEN transfer learningБерём модель, обученную на большой задаче (ImageNet), и дообучаем на своей маленькой. Признаки нижних слоёв (края, текстуры) универсальны и переносятся., многозадачное обучение. Его сила — в том, что представление учится сразу на нескольких видах данных.

flowchart LR
w["слово"] --> W["W (общий)"]
W --> F["F: задача A"]
W --> G["G: задача B"]
W и F учатся решать задачу A; позже G учится решать задачу B поверх того же W

Обратный приём: учить отображать разные виды данных в одно пространство.

Два языка. В работе Сохера и соавторов (Zou, Socher, Cer, Manning, 2013) обучают два эмбеддинга — английский WenW_{en} и китайский WzhW_{zh} — и добавляют условие: слова, про которые известно, что они переводы друг друга, должны оказаться рядом. Конечно, они оказываются рядом — этого и добивались. Интересно другое: рядом оказываются и пары, про которые сеть не знала, что это переводы. Ола объясняет: синонимы тянутся друг к другу, разности вроде «род» кодируются постоянными векторами, и если совместить достаточно много точек, два «облака» слов совпадут по форме. Тогда, если известно, что мужские варианты слов — переводы друг друга, женские тоже встанут на свои места. Это как два одинаковых по форме листа, которые совместили по нескольким булавкам. Для нашего курса пример особенно уместен: речь именно об английском и китайском.

Картинки и слова. Ещё смелее — класть в одно пространство изображения и слова. Классификатор картинок выдаёт не номер класса, а вектор в пространстве эмбеддингов слов: собаки — рядом с вектором «dog», лошади — рядом с «horse».

Самое интересное начинается на классах, которых модель не видела. В работе Сохера и др. (2013) картинки кошек (модель не училась их распознавать) не разбрасываются случайно, а попадают в окрестность вектора «dog» — и при этом близко к вектору «cat». Грузовики оказываются рядом с «truck», который соседствует с «automobile». У стэнфордской группы было всего 8 известных классов и 2 неизвестных. Группа Google сделала большую версию на 1000 классов (DeViSE, Frome и др., 2013), а затем вариант Норузи и др. (2014). Неизвестный класс модели обычно не попадают в точный вектор, но попадают в правильную окрестность — и могут отличить, скажем, эскулапова полоза от броненосца, никогда их не видев. Ола сравнивает это с человеком, который не видел ни того, ни другого, но по словам примерно представляет, как они выглядят. Сегодня это называют zero-shotzero-shot (без примеров)EN zero-shotРешение задачи без обучающих примеров и без дообучения — только по описанию задачи в промпте. С несколькими примерами в промпте — few-shot.-классификацией, а прямой наследник этой идеи — модель CLIP.

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

Модульная сеть R(W(w1),…,W(w5))R(W(w_1), \dots, W(w_5)) из раздела 2 принимает ровно пять слов. Ола обращает внимание, что строить сети из небольших модулей, как из кубиков, в 2014 году было не очень принято, но в NLP это оказалось успешным.

Чтобы снять ограничение на длину, добавим модуль ассоциации AA: он принимает два представления (слов или фраз) и сливает их в одно того же размера. Применяя AA снова и снова, получаем представление фразы и даже целого предложения. Сливать слова подряд слева направо не обязательно: фразу «the cat sat on the mat» естественно разобрать по скобкам «((the cat) (sat (on (the mat))))» и применять AA по этому дереву.

flowchart BT
the1["the"] --> A1["A"]
cat["cat"] --> A1
the2["the"] --> A2["A"]
mat["mat"] --> A2
on["on"] --> A3["A"]
A2 --> A3
sat["sat"] --> A4["A"]
A3 --> A4
A1 --> A5["A: всё предложение"]
A4 --> A5
Модуль A применяется по дереву разбора ((the cat) (sat (on (the mat))))

Такие модели называют рекурсивными (выход модуля снова идёт на вход модуля того же типа) или древовидными нейросетями. Не путайте с рекуррентными (RNN): у рекуррентной сети «дерево» вырождено в цепочку слева направо.

Пример успеха — предсказание тональности предложений по дереву разбора (Сохер и др., 2013): тональность вычисляется в каждом узле, и модель видит, как, например, отрицание переворачивает оценку всей ветки.

Обратимые представления. Большая цель того времени — представление предложения, из которого можно восстановить предложение с тем же смыслом. Для этого нужен модуль «разъединения» DD, обратный к AA. Будь он у нас, можно было бы сделать общее представление предложений двух языков и переводить через него. Ола пишет, что это оказалось «очень, очень трудно». Свежий на тот момент прогресс — модель Cho и др. (2014), которая кодирует английскую фразу в вектор и декодирует её по-французски; на карте t-SNE её представления фраз о времени аккуратно группируются по смыслу. Это та самая архитектура «кодировщик — декодировщик», из которой выросли seq2seq, внимание и в итоге трансформер (уроки 4.1.5 и 4.4.1). Кстати, в той же работе Cho впервые предложен GRU.

Ола честно отмечает, что слышал критику этих результатов от лингвистов и специалистов по NLP — не самих результатов, а выводов из них и сравнения с другими методами. Сформулировать её сам он не берётся и приглашает критиков в комментарии.

Вывод эссе: взгляд на глубокое обучение через представления отвечает на вопрос, почему глубокие сети так эффективны, — потому что из оптимизации многослойных моделей сами собой появляются лучшие способы представлять данные. Ола признаётся, что находит в этом что-то «чрезвычайно красивое». Пост задуман как подготовка к следующему — о связи глубокого обучения с теорией типов и функциональным программированием (позже вышло эссе «Neural Networks, Types, and Functional Programming»).

  1. В уроке 4.3.2 обучите word2vec и проверьте сами: какие слова оказываются ближайшими соседями, работает ли «король − мужчина + женщина».
  2. Повторите идею двуязычного эмбеддинга на игрушечном уровне: возьмите русские и китайские векторы из мультиязычной модели эмбеддингов (урок 4.3.1) для 10 пар «слово — перевод» и проверьте, ближе ли перевод, чем случайное слово.
  3. Подумайте над вопросом Олы: почему таблица поиска (раздел 1) не может обобщать, а эмбеддинг — может? Что общего у похожих слов в таблице θ\theta и чего нет у строк таблицы поиска?
ENRU
universality, universal approximationуниверсальность, универсальная аппроксимация
lookup tableтаблица поиска
representationпредставление
word embeddingэмбеддинг слова, векторное представление слова
t-SNEt-SNE — метод визуализации многомерных данных на плоскости
analogy, difference vectorаналогия, вектор разности
pretraining, transfer learning, multi-task learningпредобучение, перенос обучения, многозадачное обучение
shared representationобщее представление
bilingual word embeddingдвуязычный эмбеддинг слов
zero-shotклассификация классов, которых не было в обучении
recursive (tree-structured) neural networkрекурсивная (древовидная) нейросеть
association / disassociation moduleмодуль ассоциации / разъединения
encoder–decoderкодировщик — декодировщик