Содержание курса 08 / 37

08 / 37 · Распределённые представления

Word2Vec

Задача предсказания на неразмеченном тексте (угадать соседей по центральному слову или центральное слово по соседям) обучает таблицу эмбеддингов; из-за полного softmax по словарю каждый шаг затрагивает десятки миллионов весов, а негативное сэмплирование сокращает это число до нескольких тысяч и при этом по-прежнему выучивает статистику совместной встречаемости.

На этой странице 14

Предыдущая заметка показала, что в таблицах эмбеддингов слов (word embeddings), обученных библиотекой, слова, употребляемые в похожих контекстах, получают похожие векторы, но не объяснила почему. Слова, которые встречаются в одних и тех же контекстах, как правило, близки по смыслу (Harris, 1954; Firth, 1957), и модель, которая должна предсказывать соседей слова через узкое место (bottleneck), вынуждена давать словам с одинаковыми соседями похожие векторы в этом узком месте. Word2Vec (Mikolov et al., 2013a, 2013b) превращает это в две небольшие сети, которые можно обучать на миллиардах токенов благодаря иерархическому softmax (hierarchical softmax) или негативному сэмплированию (negative sampling); в этой заметке мы разбираем негативное сэмплирование — тот приём, который используется на практике.

Обозначения. Корпус — последовательность токенов w1,…,wTw_1, \dots, w_T из словаря VV; dd — размерность эмбеддинга. Для позиции tt центральное слово — это wtw_t, а контекст — окно Ct=(wt+j)j∈JtC_t = (w_{t+j})_{j \in J_t}, где Jt={j:1≤∣j∣≤m, 1≤t+j≤T}J_t = \{j : 1 \le |j| \le m,\ 1 \le t + j \le T\}, — до 2m2m соседей, повторы сохраняются; mm — радиус окна. У каждого слова ww два вектора: входной (центральный) вектор vw∈Rdv_w \in \mathbb R^d, строка матрицы Win∈R∣V∣×dW_{\text{in}} \in \mathbb R^{|V| \times d}, и выходной (контекстный) вектор uw∈Rdu_w \in \mathbb R^d, строка матрицы Wout∈R∣V∣×dW_{\text{out}} \in \mathbb R^{|V| \times d}. WinW_{\text{in}} — это таблица эмбеддингов EE из предыдущей заметки. σ(x)=1/(1+e−x)\sigma(x) = 1/(1 + e^{-x}); kk — число негативных примеров (negative samples), а PnP_n — распределение, из которого их сэмплируют.

Базовый вариант: обучить эмбеддинги на размеченной задаче#

В предыдущей заметке перечислены источники таблицы. Обучение её как слоя классификатора работает (это проверено в заметке о CNN), но таблица узнаёт только о словах из размеченного набора и только то, что помогает предсказать метку. Размеченного текста мало; неразмеченного почти неограниченно много. Что должна предсказывать модель, когда метки нет?

Сеть, первый слой которой — таблица#

Для ключевой идеи достаточно двухслойной линейной сети. Для входного слова cc и целевого слова oo:

  1. берём one-hot-вектор ec∈{0,1}∣V∣e_c \in \{0, 1\}^{|V|} слова cc;
  2. умножаем его на первый слой: h=Win⊤ec=vc∈Rdh = W_{\text{in}}^\top e_c = v_c \in \mathbb R^d — строку слова cc (без смещения и без нелинейности);
  3. сравниваем с hh каждое слово словаря: s=Wout h∈R∣V∣s = W_{\text{out}}\, h \in \mathbb R^{|V|}, так что sw=uw⋅vcs_w = u_w \cdot v_c;
  4. превращаем оценки (scores) в распределение с помощью softmax:
p(o∣c)=exp⁡(uo⋅vc)∑w∈Vexp⁡(uw⋅vc).p(o \mid c) = \frac{\exp(u_o \cdot v_c)}{\sum_{w \in V}\exp(u_w \cdot v_c)}.

Сеть обучается с кросс-энтропией −log⁡p(o∣c)-\log p(o \mid c) на парах (вход, цель), вырезанных из корпуса; затем всё, кроме первого слоя, выбрасывается, и эмбеддинг — это строка vcv_c. В коде произведение на one-hot-вектор — это выборка строки по индексу: батч индексов [B][B] превращается в [B,d][B, d], затем в [B,∣V∣][B, |V|]. У модели 2∣V∣d2|V|d параметров.

Рисунок

Сеть Word2Vec: выбор строки, скалярное произведение с каждым выходным вектором, softmax

Сеть Word2Vec с формами тензоровСлева направо: столбец из восьми ячеек с единственной единицей на позиции coffee; входная матрица W in, восемь строк на три столбца, в которой выделена строка coffee и отмечено, что это сохраняемая таблица эмбеддингов; скрытый вектор h из трёх ячеек, равный этой строке; выходная матрица W out, восемь строк на три столбца, в которой выделена строка drink; столбец из восьми оценок; и горизонтальные столбики вероятностей softmax для восьми слов, самый длинный — у drink. Выходная часть отмечена как используемая только при обучении.ec00010000[|V|]Win[|V|, d]h= vc[d]Wout[|V|, d]s0.161.160.75−0.120.370.680.100.22[|V|]softmaxwedrinkhotcoffeeeverymorningcartaxсохраняется: таблица эмбеддинговнужны только для обучения таблицыСеть Word2Vec с формами тензоровСлева направо: столбец из восьми ячеек с единственной единицей на позиции coffee; входная матрица W in, восемь строк на три столбца, в которой выделена строка coffee и отмечено, что это сохраняемая таблица эмбеддингов; скрытый вектор h из трёх ячеек, равный этой строке; выходная матрица W out, восемь строк на три столбца, в которой выделена строка drink; и горизонтальные столбики вероятностей softmax для восьми слов, самый длинный — у drink. Выходная часть отмечена как используемая только при обучении.ec00010000[|V|]Win[|V|, d]h= vc[d]Wout[|V|, d]softmaxwedrinkhotcoffeeeverymorningcartaxтаблица эмбеддинговтолько для обучения
Игрушечные размеры |V| = 8 и d = 3, центральное слово coffee, наблюдаемое контекстное слово drink. Произведение one-hot-вектора слова coffee на W_in выбирает одну строку, v_coffee; смещения и нелинейности нет, поэтому скрытый вектор h — это и есть эта строка. Каждая строка u_w матрицы W_out скалярно умножается на h, что даёт одну оценку на слово словаря, а softmax превращает 8 оценок в распределение по контекстному слову (оценки и столбики вычислены по игрушечным векторам). Обучение повышает вероятность drink. После обучения сохраняется только W_in — как таблица эмбеддингов; W_out и softmax нужны только для обучающего сигнала. В CBOW на вход подаются 2m контекстных слов, а h — среднее их строк.

Две таблицы нужны потому, что с одной оценка слова в паре с самим собой, ∥vw∥2\|v_w\|^2, была бы большой, хотя слово редко встречается в собственном окне; две таблицы позволяют сделать uw⋅vwu_w \cdot v_w малым (Goldberg and Levy, 2014). Библиотеки возвращают WinW_{\text{in}} (wv в gensim).

Две задачи предсказания: CBOW и skip-gram#

Сеть оставляет открытым вопрос, какие слова служат входами, а какие — целями. Word2Vec определяет два варианта на одних и тех же окнах.

Непрерывный мешок слов (continuous bag of words, CBOW) предсказывает центральное слово по его контексту: среднее входных векторов контекста классифицируется среди ∣V∣|V| возможных центральных слов:

ht=1∣Jt∣∑j∈Jtvwt+j,p(wt∣Ct)=exp⁡(uwt⋅ht)∑w′∈Vexp⁡(uw′⋅ht).h_t = \frac{1}{|J_t|}\sum_{j \in J_t} v_{w_{t+j}}, \qquad p(w_t \mid C_t) = \frac{\exp(u_{w_t} \cdot h_t)}{\sum_{w' \in V}\exp(u_{w'} \cdot h_t)}.

«Мешок» — потому что среднее игнорирует порядок слов; каждая позиция даёт один пример.

Skip-gram меняет направление: центральное слово предсказывает каждое контекстное слово по отдельности с помощью softmax из предыдущего раздела, минимизируя

LSG=−1T∑t=1T∑j∈Jtlog⁡p(wt+j∣wt).\mathcal L_{\text{SG}} = -\frac{1}{T}\sum_{t=1}^T \sum_{j \in J_t} \log p(w_{t+j} \mid w_t).

Каждая позиция даёт до 2m2m пар (центральное слово, контекстное слово).

Рисунок

Одно окно, две задачи предсказания

Пары skip-gram и пример CBOW из одного окнаДве копии предложения we drink hot coffee every morning, в которых слово coffee выделено как центральное, а окно захватывает по два слова с каждой стороны. В верхней копии четыре синие стрелки выходят из coffee и указывают на drink, hot, every и morning, а под ними перечислены четыре пары. В нижней копии четыре красные стрелки выходят из соседей и указывают на coffee, с пометкой, что их векторы усредняются. Последняя строка подсчитывает 18 пар skip-gram и 6 примеров CBOW для всего предложения.Skip-gram: центральное слово предсказывает каждого соседаwedrinkhotcoffeeeverymorning(coffee, drink) (coffee, hot) (coffee, every) (coffee, morning)CBOW: соседи вместе предсказывают центральное словоwedrinkhotcoffeeeverymorningсреднее v(drink), v(hot), v(every), v(morning) → coffeeВсё предложение: 2 + 3 + 4 + 4 + 3 + 2 = 18 пар skip-gram, 6 примеров CBOWПары skip-gram и пример CBOW из одного окнаДве копии предложения we drink hot coffee every morning, в которых слово coffee выделено как центральное, а окно захватывает по два слова с каждой стороны. В верхней копии четыре синие стрелки выходят из coffee и указывают на drink, hot, every и morning, а под ними перечислены четыре пары. В нижней копии четыре красные стрелки выходят из соседей и указывают на coffee, с пометкой, что их векторы усредняются. Последняя строка подсчитывает 18 пар skip-gram и 6 примеров CBOW для всего предложения.Skip-gram: центр → каждый соседwedrinkhotcoffeeeverymorning(coffee, drink) (coffee, hot)(coffee, every) (coffee, morning)CBOW: соседи → центрwedrinkhotcoffeeeverymorningсреднее v(drink), v(hot), v(every),v(morning) → coffeeВсё предложение: 2 + 3 + 4 + 4 + 3 + 2 = 18пар skip-gram, 6 примеров CBOW
Предложение «we drink hot coffee every morning» с радиусом окна m = 2 и центральным словом coffee (янтарное); слово «we» лежит вне окна. Skip-gram (вверху) превращает окно в четыре отдельные обучающие пары, в каждой из которых модель должна предсказать одного соседа по coffee. CBOW (внизу) превращает то же окно в один пример: четыре вектора соседей усредняются, и среднее должно предсказать coffee. Сдвигая центр по всем шести позициям, получаем 2, 3, 4, 4, 3, 2 соседей на позицию (у краёв предложения меньше), то есть 18 обновлений skip-gram против 6 обновлений CBOW.

Разобранный пример: обучающие пары. В предложении we drink hot coffee every morning (T=6T = 6, m=2m = 2) центральное слово coffee даёт четыре пары skip-gram и один пример CBOW, в котором среднее четырёх векторов контекста предсказывает coffee (рисунок выше). У позиции ii есть min⁡(m,i−1)+min⁡(m,T−i)\min(m, i - 1) + \min(m, T - i) соседей, так что предложение даёт 2+3+4+4+3+2=182 + 3 + 4 + 4 + 3 + 2 = 18 пар skip-gram против 6 примеров CBOW.

Нейросетевая языковая модель (Bengio et al., 2003) тоже начинается с таблицы эмбеддингов, но предсказывает следующее слово, как n-граммная модель, через дорогой нелинейный скрытый слой. Word2Vec нужна только таблица, поэтому он отказывается от нелинейности и использует контекст с обеих сторон.

CBOW вычисляет одно выходное распределение на позицию, а skip-gram — до 2m2m, так что CBOW дешевле примерно во столько раз, сколько слов в окне, но в сравнении Mikolov et al. (2013a), §3.1–3.2 и таблица 3 (640-мерные векторы), skip-gram был намного лучше на семантических аналогиях (55% против 24%) и немного хуже на синтаксических (59% против 64%). Также отмечают, что он лучше для редких слов (страница проекта word2vec), векторы которых CBOW обновляет только через среднее с не более чем 2m−12m - 1 другими.

Для каждого центрального слова эффективный радиус выбирается равномерно из {1,…,m}\{1, \dots, m\} (Mikolov et al., 2013a, §3.2), поэтому сосед на расстоянии jj используется с вероятностью (m−j+1)/m(m - j + 1)/m (1,0.8,0.6,0.4,0.21, 0.8, 0.6, 0.4, 0.2 при m=5m = 5): ближние соседи получают больший вес без явного взвешивания.

Почему проблема в softmax#

Запишем функцию потерь skip-gram одной пары (c,o)(c, o) как −log⁡p(o∣c)=−uo⋅vc+log⁡∑w∈Vexp⁡(uw⋅vc)-\log p(o \mid c) = -u_o \cdot v_c + \log \sum_{w \in V} \exp(u_w \cdot v_c). Производная log-sum-exp по vcv_c — это взвешенное по softmax среднее векторов uwu_w, а по одному uwu_w — это p(w∣c) vcp(w \mid c)\, v_c:

∂ (−log⁡p(o∣c))∂vc=−uo+∑w∈Vp(w∣c) uw,∂ (−log⁡p(o∣c))∂uw=(p(w∣c)−1[w=o]) vc.\begin{aligned} \frac{\partial\,(-\log p(o \mid c))}{\partial v_c} &= -u_o + \sum_{w \in V} p(w \mid c)\, u_w, \\ \frac{\partial\,(-\log p(o \mid c))}{\partial u_w} &= \big(p(w \mid c) - \mathbb 1[w = o]\big)\, v_c . \end{aligned}

Первая строка читается как «наблюдаемое минус ожидаемое»: шаг притягивает vcv_c к контекстному слову, которое встретилось, и отталкивает от того, которое ожидает модель. Вторая ненулевая для каждого ww, поэтому одна пара обновляет все ∣V∣|V| строк WoutW_{\text{out}}, а одному лишь нормировочному знаменателю нужны ∣V∣|V| скалярных произведений (Rong, 2014).

При ∣V∣=200 000|V| = 200\,000 и d=300d = 300 у модели 2∣V∣d=1.2×1082|V|d = 1.2 \times 10^8 параметров. Одна пара стоит ∣V∣d=6×107|V| d = 6 \times 10^7 умножений-сложений на оценки и обновляет ∣V∣d+d=60 000 300|V| d + d = 60\,000\,300 параметров, а корпус из 10910^9 токенов при m=5m = 5 даёт до 101010^{10} пар за один проход. Сама модель невелика; обучение невозможно из-за нормировки.

Рисунок

Сколько параметров затрагивает одна обучающая пара при росте словаря

Стоимость одной обучающей пары в зависимости от размера словаряГрафик в логарифмическом масштабе по обеим осям: по горизонтали размер словаря от тысячи до десяти миллионов, по вертикали число параметров, обновляемых на пару, от ста до десяти миллиардов. Линия полного softmax растёт с наклоном один примерно от трёхсот тысяч до трёх миллиардов. Кривая иерархического softmax медленно растёт примерно от трёх тысяч до семи тысяч. Линия негативного сэмплирования горизонтальна на уровне 2100. Вертикальная линия на двухстах тысячах слов отмечает разрыв примерно в 28 600 раз между полным softmax и негативным сэмплированием.10²10⁴10⁶10⁸10¹⁰10³10⁴10⁵10⁶10⁷размер словаря |V|обновляемых параметров на паруполный softmax: (|V| + 1)dиерархический softmax: ≈ d(log₂|V| + 1)негативное сэмплирование, k = 5: (k + 2)d = 2100|V| = 200 000:≈ 28 600× меньшеСтоимость одной обучающей пары в зависимости от размера словаряГрафик в логарифмическом масштабе по обеим осям: по горизонтали размер словаря от тысячи до десяти миллионов, по вертикали число параметров, обновляемых на пару, от ста до десяти миллиардов. Линия полного softmax растёт с наклоном один примерно от трёхсот тысяч до трёх миллиардов. Кривая иерархического softmax медленно растёт примерно от трёх тысяч до семи тысяч. Линия негативного сэмплирования горизонтальна на уровне 2100. Вертикальная линия на двухстах тысячах слов отмечает разрыв примерно в 28 600 раз между полным softmax и негативным сэмплированием.10²10⁴10⁶10⁸10¹⁰10³10⁴10⁵10⁶10⁷размер словаря |V|параметров на паруполный softmaxиерархический softmaxнегативное сэмплирование, k = 5|V| = 200 000:≈ 28 600× меньше
Обе оси логарифмические; d = 300. Полный softmax читает и обновляет каждую выходную строку, поэтому его стоимость растёт пропорционально |V|. Иерархический softmax заменяет нормировку по |V| классам примерно log₂|V| бинарными решениями вдоль дерева. Негативное сэмплирование с k = 5 обновляет центральный вектор, наблюдаемый контекстный вектор и 5 сэмплированных векторов, (k + 2)d = 2100 параметров, каким бы ни был размер словаря. При |V| = 200 000 (вертикальная линия) полный softmax затрагивает 60 000 300 параметров на пару, примерно в 28 600 раз больше.

Иерархический softmax (Morin and Bengio, 2005) размещает словарь в листьях бинарного дерева (дерева Хаффмана, Mikolov et al., 2013b, §2.1), так что предсказание требует около log⁡2∣V∣\log_2 |V| бинарных решений, 18 для 200 000 слов. Негативное сэмплирование отказывается от нормировки; на практике это вариант по умолчанию, и ему посвящена оставшаяся часть заметки.

Негативное сэмплирование#

Рисунок

Softmax и негативное сэмплирование на выходной стороне skip-gram

Softmax и негативное сэмплированиеДве панели. В каждой слева столбец из трёх ячеек — центральный вектор слова coffee, а справа столбец из восьми прямоугольников со словами — словарь. На панели полного softmax каждое слово соединено с центральным вектором сплошной линией. На панели негативного сэмплирования соединены только наблюдаемое слово drink (зелёное, целевое значение 1) и два сэмплированных негативных слова car и tax (красные, целевое значение 0); остальные слова нарисованы бледно.полный softmaxвсе |V| выходных строк читаются и обновляютсяvccoffeewedrinkhotcarmorningtaxcupcoffeeодин softmax по |V| оценкамнегативное сэмплирование, k = 2k + 1 = 3 выходные строки читаются и обновляютсяvccoffeewedrink ← наблюдаемое (1)hotcar ← негативное (0)morningtax ← негативное (0)cupcoffeek + 1 логистическихклассификаторовSoftmax и негативное сэмплированиеДве панели. В каждой слева столбец из трёх ячеек — центральный вектор слова coffee, а справа столбец из восьми прямоугольников со словами — словарь. На панели полного softmax каждое слово соединено с центральным вектором сплошной линией. На панели негативного сэмплирования соединены только наблюдаемое слово drink (зелёное, целевое значение 1) и два сэмплированных негативных слова car и tax (красные, целевое значение 0); остальные слова нарисованы бледно.полный softmaxвсе |V| выходных строк читаются и обновляютсяvccoffeewedrinkhotcarmorningtaxcupcoffeeодин softmax по |V| оценкамнегативное сэмплирование, k = 2k + 1 = 3 выходные строки читаются и обновляютсяvccoffeewedrink ← наблюдаемое (1)hotcar ← негативное (0)morningtax ← негативное (0)cupcoffeek + 1 логистическихклассификаторов
Игрушечные размеры |V| = 8 и d = 3; слова те же, что в разобранном примере ниже: центральное coffee, наблюдаемое контекстное drink, негативные car и tax. В полном softmax (первая панель) вероятность drink нормируется по всем |V| словам, поэтому одна обучающая пара читает и обновляет каждую строку W_out. В негативном сэмплировании (вторая панель) пара (coffee, drink) — положительный пример с целевым значением 1, а k = 2 сэмплированных слова, car и tax, — негативные примеры с целевым значением 0 (целевые значения в скобках); каждый пример — независимый логистический классификатор по своей оценке; читаются и обновляются только эти k + 1 выходные строки и v_coffee. Остальной словарь не затрагивается. При |V| = 200 000, d = 300 и k = 5 это 2100 параметров на пару вместо 60 000 300.

Для наблюдаемой пары (c,o)(c, o) и шумовых слов n1,…,nk∼Pnn_1, \dots, n_k \sim P_n функция потерь skip-gram с негативным сэмплированием (skip-gram negative sampling, SGNS) равна

LNS(c,o)=−log⁡σ(uo⋅vc)−∑i=1klog⁡σ(−uni⋅vc).\mathcal L_{\text{NS}}(c, o) = -\log \sigma(u_o \cdot v_c) - \sum_{i=1}^k \log \sigma(-u_{n_i} \cdot v_c).

σ(uw⋅vc)\sigma(u_w \cdot v_c) — вероятность, которую модель приписывает тому, что пара настоящая, а σ(−x)=1−σ(x)\sigma(-x) = 1 - \sigma(x), так что каждый член суммы — логарифм вероятности того, что шумовая пара будет распознана как подделка. С оценками so=uo⋅vcs_o = u_o \cdot v_c и si=uni⋅vcs_i = u_{n_i} \cdot v_c и с учётом ddxlog⁡σ(x)=1−σ(x)\frac{d}{dx}\log\sigma(x) = 1 - \sigma(x) градиенты равны

∂LNS∂vc=(σ(so)−1) uo+∑i=1kσ(si) uni,∂LNS∂uo=(σ(so)−1) vc,∂LNS∂uni=σ(si) vc.\begin{aligned} \frac{\partial \mathcal L_{\text{NS}}}{\partial v_c} &= \big(\sigma(s_o) - 1\big)\, u_o + \sum_{i=1}^k \sigma(s_i)\, u_{n_i}, \\ \frac{\partial \mathcal L_{\text{NS}}}{\partial u_o} &= \big(\sigma(s_o) - 1\big)\, v_c, \qquad \frac{\partial \mathcal L_{\text{NS}}}{\partial u_{n_i}} = \sigma(s_i)\, v_c . \end{aligned}

Это «наблюдаемое минус ожидаемое», в котором математическое ожидание по ∣V∣|V| словам заменено на kk сэмплированных слов, каждое из которых взвешено тем, насколько правдоподобным его считает модель; у всех остальных строк градиент нулевой.

CBOW использует ту же функцию потерь, в которой вместо центрального вектора стоит среднее контекста hth_t, а положительным примером служит центральное слово:

LCBOW-NS(t)=−log⁡σ(uwt⋅ht)−∑i=1klog⁡σ(−uni⋅ht).\mathcal L_{\text{CBOW-NS}}(t) = -\log \sigma(u_{w_t} \cdot h_t) - \sum_{i=1}^k \log \sigma(-u_{n_i} \cdot h_t).

Её градиенты — те же, что выше, с hth_t вместо vcv_c. Цепное правило через среднее отправило бы каждому вектору контекста 1/∣Jt∣1/|J_t| градиента по hth_t; word2vec.c (страница проекта word2vec) и gensim (cbow_mean=1) добавляют его целиком, что равносильно большему шагу обучения для входной таблицы.

Пара обновляет (k+2)d(k + 2) d параметров, 2 1002\,100 при d=300d = 300 и k=5k = 5. Mikolov et al. (2013b), §2.2, сообщают, что для небольших обучающих наборов подходят kk от 5 до 20, а для больших — от 2 до 5; gensim использует k=5k = 5.

Разобранный пример#

Игрушечные числа: d=2d = 2, k=2k = 2, шаг обучения η=0.5\eta = 0.5 (большой, чтобы движение было заметно), центральное слово coffee, наблюдаемое контекстное слово drink, негативные car и tax.

ВекторЗначениеОценка с vcoffeev_{\text{coffee}}σ(оценка)\sigma(\text{оценка})Член функции потерь
vcoffeev_{\text{coffee}}(1.0,0.5)(1.0, 0.5)
udrinku_{\text{drink}} (наблюдаемое)(0.8,0.6)(0.8, 0.6)1.101.100.7500.750−log⁡σ(1.10)=0.287-\log \sigma(1.10) = 0.287
ucaru_{\text{car}} (негативное)(−0.2,0.9)(-0.2, 0.9)0.250.250.5620.562−log⁡σ(−0.25)=0.826-\log \sigma(-0.25) = 0.826
utaxu_{\text{tax}} (негативное)(0.6,−0.4)(0.6, -0.4)0.400.400.5990.599−log⁡σ(−0.40)=0.913-\log \sigma(-0.40) = 0.913

Функция потерь равна 0.287+0.826+0.913=2.0260.287 + 0.826 + 0.913 = 2.026, а градиенты равны

  • ∂L/∂vcoffee=−0.250 (0.8,0.6)+0.562 (−0.2,0.9)+0.599 (0.6,−0.4)=(0.047,0.117)\partial \mathcal L / \partial v_{\text{coffee}} = -0.250\,(0.8, 0.6) + 0.562\,(-0.2, 0.9) + 0.599\,(0.6, -0.4) = (0.047, 0.117);
  • ∂L/∂udrink=−0.250 (1.0,0.5)=(−0.250,−0.125)\partial \mathcal L / \partial u_{\text{drink}} = -0.250\,(1.0, 0.5) = (-0.250, -0.125);
  • ∂L/∂ucar=0.562 (1.0,0.5)=(0.562,0.281)\partial \mathcal L / \partial u_{\text{car}} = 0.562\,(1.0, 0.5) = (0.562, 0.281) и ∂L/∂utax=0.599 (1.0,0.5)=(0.599,0.299)\partial \mathcal L / \partial u_{\text{tax}} = 0.599\,(1.0, 0.5) = (0.599, 0.299).

Один шаг x←x−η ∂L/∂xx \leftarrow x - \eta\, \partial\mathcal L/\partial x даёт vcoffee=(0.977,0.442)v_{\text{coffee}} = (0.977, 0.442), udrink=(0.925,0.662)u_{\text{drink}} = (0.925, 0.662), ucar=(−0.481,0.759)u_{\text{car}} = (-0.481, 0.759) и utax=(0.301,−0.550)u_{\text{tax}} = (0.301, -0.550); два рисунка ниже показывают, как движутся векторы и оценки, а функция потерь падает с 2.0262.026 до 1.6111.611. Изменились четыре строки; при 200 000 слов остальные 199 997 выходных строк даже не читались.

Рисунок

Один шаг негативного сэмплирования на плоскости

Геометрия одного обновления негативного сэмплированияЧетыре стрелки из начала координат на плоскости, каждая нарисована штриховой линией до обновления и сплошной после него. Синий центральный вектор v coffee почти не движется. Зелёный наблюдаемый контекстный вектор u drink сдвигается наружу вдоль направления v coffee. Два красных негативных вектора u car и u tax отходят от v coffee. Таблица показывает оценки до и после: drink с 1.10 до 1.20, car с 0.25 до −0.13, tax с 0.40 до 0.05.−0.5−0.50.50.51vcoffeeudrinkucarutaxоценка с vcoffeeдопослеdrink (наблюдаемое)1.101.20car (негативное)0.25−0.13tax (негативное)0.400.05Геометрия одного обновления негативного сэмплированияЧетыре стрелки из начала координат на плоскости, каждая нарисована штриховой линией до обновления и сплошной после него. Синий центральный вектор v coffee почти не движется. Зелёный наблюдаемый контекстный вектор u drink сдвигается наружу вдоль направления v coffee. Два красных негативных вектора u car и u tax отходят от v coffee. Таблица показывает оценки до и после: drink с 1.10 до 1.20, car с 0.25 до −0.13, tax с 0.40 до 0.05.−0.5−0.50.50.51vcoffeeudrinkucarutaxоценка с vcoffeeдопослеdrink (наблюдаемое)1.101.20car (негативное)0.25−0.13tax (негативное)0.400.05
Разобранный пример с d = 2, k = 2 негативными примерами и шагом обучения 0.5. Штриховые линии — четыре вектора до шага, сплошные — после него; короткие стрелки показывают, как сдвинулся конец каждого выходного вектора (v_coffee сдвигается слишком мало для стрелки). Центральный вектор v_coffee переходит из (1.000, 0.500) в (0.977, 0.442). Наблюдаемый контекстный вектор u_drink сдвигается вдоль v_coffee, поэтому их скалярное произведение растёт; негативные векторы u_car и u_tax сдвигаются против v_coffee, поэтому их скалярные произведения уменьшаются. Каждый градиент кратен вектору, который уже есть на рисунке: выходная строка движется только вдоль v_coffee, а v_coffee — вдоль взвешенной суммы трёх выходных строк. Никакие другие строки словаря не читаются.
Рисунок

Два члена функции потерь негативного сэмплирования в зависимости от оценки

Члены функции потерь негативного сэмплирования в зависимости от оценкиДве кривые над осью оценок от минус четырёх до четырёх. Зелёная кривая, минус логарифм сигмы от s, падает примерно от четырёх слева почти до нуля справа. Красная кривая, минус логарифм сигмы от минус s, — её зеркальное отражение и поднимается примерно до четырёх справа. Они пересекаются при нулевой оценке на уровне log 2. Три пары точек отмечают разобранный пример: наблюдаемая пара drink на зелёной кривой сдвигается вправо с 1.10 на 1.20; негативные car и tax на красной кривой сдвигаются влево с 0.25 на −0.13 и с 0.40 на 0.05.1234−4−2024оценка s = u · vc0−log σ(s): наблюдаемая пара−log σ(−s): негативная параdrink: оценка 1.10 → 1.20car: оценка 0.25 → −0.13tax: оценка 0.40 → 0.05Члены функции потерь негативного сэмплирования в зависимости от оценкиДве кривые над осью оценок от минус четырёх до четырёх. Зелёная кривая, минус логарифм сигмы от s, падает примерно от четырёх слева почти до нуля справа. Красная кривая, минус логарифм сигмы от минус s, — её зеркальное отражение и поднимается примерно до четырёх справа. Они пересекаются при нулевой оценке на уровне log 2. Три пары точек отмечают разобранный пример: наблюдаемая пара drink на зелёной кривой сдвигается вправо с 1.10 на 1.20; негативные car и tax на красной кривой сдвигаются влево с 0.25 на −0.13 и с 0.40 на 0.05.1234−4−2024оценка s = u · vc0−log σ(s)−log σ(−s)drinkcartax
Зелёная кривая: −log σ(s), функция потерь наблюдаемой пары; её наклон σ(s) − 1 становится пренебрежимо малым, когда оценка велика, так что уже распознанная пара перестаёт двигаться. Красная: −log σ(−s), функция потерь каждой негативной пары; её наклон σ(s) растёт вместе с оценкой, так что негативный пример, который модель ошибочно считает правдоподобным, получает самый сильный толчок. Точки — разобранный пример (d = 2, k = 2, шаг обучения 0.5): полые — до шага, закрашенные — после него. Наблюдаемая пара (coffee, drink) сдвигается с оценки 1.10 на 1.20, негативные car и tax — с 0.25 и 0.40 на −0.13 и 0.05; суммарная функция потерь падает с 2.026 до 1.611.

Для сравнения — полный softmax по игрушечному словарю из шести слов с тем же vcoffeev_{\text{coffee}}: drink (0.8,0.6)(0.8, 0.6), hot (0.7,0.1)(0.7, 0.1), morning (0.3,0.5)(0.3, 0.5), car (−0.2,0.9)(-0.2, 0.9), tax (0.6,−0.4)(0.6, -0.4) и cup (0.9,0.2)(0.9, 0.2). Оценки равны 1.10,0.75,0.55,0.25,0.40,1.001.10, 0.75, 0.55, 0.25, 0.40, 1.00, вероятности — 0.243,0.171,0.140,0.104,0.121,0.2200.243, 0.171, 0.140, 0.104, 0.121, 0.220, а функция потерь — −log⁡0.243=1.414-\log 0.243 = 1.414. Градиенту по vcoffeev_{\text{coffee}}, ∑wp(w∣c) uw−udrink=(−0.193,−0.277)\sum_w p(w \mid c)\, u_w - u_{\text{drink}} = (-0.193, -0.277), нужны все шесть строк, и он понижает cup — правдоподобный контекст, стоящий на втором месте; негативное сэмплирование понижает слово, только когда оно выпало.

Какие слова становятся негативными#

Негативные слова сэмплируются из униграммного распределения (unigram distribution), возведённого в степень 3/43/4 и заново нормированного (Mikolov et al., 2013b, §2.2):

Pn(w)=count⁡(w)3/4∑w′∈Vcount⁡(w′)3/4.P_n(w) = \frac{\operatorname{count}(w)^{3/4}}{\sum_{w' \in V} \operatorname{count}(w')^{3/4}} .

С игрушечными числами вхождений the 600, coffee 30 и espresso 3 сэмплирование пропорционально числу вхождений даёт вероятности 0.948,0.047,0.0050.948, 0.047, 0.005, а степень 3/43/4 — 0.889,0.094,0.0170.889, 0.094, 0.017: вероятность выбрать espresso становится в 3.5 раза выше.

Рисунок

Униграммное распределение в степени 3/4

Шумовое распределение для трёх степеней частотСгруппированная столбчатая диаграмма по рангам слов от одного до десяти. Серые столбики, пропорциональные частоте, убывают от 0.34 на первом ранге до 0.034 на десятом. Синие столбики, частота в степени три четверти, убывают медленнее, от 0.27 до 0.047. Штриховая горизонтальная линия на уровне 0.1 отмечает равномерное сэмплирование.0.10.20.3012345678910ранг слова (1 — самое частое)P(w)α = 1: отношение 10α = 3/4: отношение 5.6α = 0: равномерноеотношение = P(ранг 1) / P(ранг 10)Шумовое распределение для трёх степеней частотСгруппированная столбчатая диаграмма по рангам слов от одного до десяти. Серые столбики, пропорциональные частоте, убывают от 0.34 на первом ранге до 0.034 на десятом. Синие столбики, частота в степени три четверти, убывают медленнее, от 0.27 до 0.047. Штриховая горизонтальная линия на уровне 0.1 отмечает равномерное сэмплирование.0.10.20.3012345678910ранг слова (1 — самое частое)P(w)α = 1: отношение 10α = 3/4: отношение 5.6α = 0: равномерноеотношение = P(ранг 1) / P(ранг 10)
Игрушечный словарь из 10 слов, частоты которых подчиняются закону Ципфа: частота пропорциональна 1/ранг. Серые столбики: негативные примеры выбираются пропорционально частоте (α = 1). Синие: выбор Word2Vec, α = 3/4. Штриховая линия: равномерное сэмплирование (α = 0). Степень 3/4 забирает вероятность у самых частых слов и отдаёт её редким: при α = 1 самое частое слово выбирается в 10 раз чаще самого редкого, при α = 3/4 — в 5.6 раза чаще. Значение 3/4 подобрано эмпирически.

Прореживание частых слов#

Пар с the или a очень много, и они малоинформативны. Перед тем как формировать окна, каждое вхождение слова ww с относительной частотой f(w)f(w) отбрасывается с вероятностью

Pdiscard(w)=1−θ/f(w)P_{\text{discard}}(w) = 1 - \sqrt{\theta / f(w)}

при пороге θ≈10−5\theta \approx 10^{-5} и никогда не отбрасывается при f(w)≤θf(w) \le \theta (Mikolov et al., 2013b, §2.3). Для игрушечных частот 0.050.05, 10−310^{-3} и 10−410^{-4} вероятности отбрасывания равны 0.9860.986, 0.90.9 и 0.680.68. Удаление токена сближает слова вокруг него, поэтому прореживание (subsampling) также расширяет эффективное окно. gensim использует вариант этого правила с порогом sample, по умолчанию 10−310^{-3}.

Что оптимизирует негативное сэмплирование#

Негативное сэмплирование оптимизирует другую целевую функцию, нежели softmax, — упрощённый вариант шумоконтрастного оценивания (noise-contrastive estimation, NCE) (Gutmann and Hyvärinen, 2010; Mnih and Teh, 2012). NCE классифицирует по исправленному логиту uo⋅vc−log⁡(k Pn(o))u_o \cdot v_c - \log\big(k\, P_n(o)\big) и в оптимуме даёт log⁡P(o∣c)\log P(o \mid c). Негативное сэмплирование использует сырую оценку (Mikolov et al., 2013b, §2.2), поэтому его оптимум сдвинут: если dd достаточно велико, чтобы каждую оценку можно было задать независимо, он равен поточечной взаимной информации (pointwise mutual information, PMI), сдвинутой на log⁡k\log k (Levy and Goldberg, 2014, §3.1):

uo⋅vc=PMI⁡(c,o)−log⁡k,PMI⁡(c,o)=log⁡P(c,o)P(c) Pn(o).u_o \cdot v_c = \operatorname{PMI}(c, o) - \log k, \qquad \operatorname{PMI}(c, o) = \log \frac{P(c, o)}{P(c)\, P_n(o)} .

Со степенью 3/43/4 это сглаженная PMI: редкие контекстные слова получают большее Pn(o)P_n(o) и меньшее значение (Levy, Goldberg and Dagan, 2015, «сглаживание распределения контекстов», context distribution smoothing).

Рисунок

Целевая функция негативного сэмплирования для одной пары и её минимум

Целевая функция SGNS для одной пары в зависимости от оценкиТри кривые над осью оценок от минус четырёх до четырёх. Синяя кривая для сильно связанной пары с PMI 3.00 имеет U-образную форму и минимум в 1.39. Янтарная кривая для пары, которая встречается вместе ровно столько, сколько ожидается при независимости, с нулевой PMI, имеет минимум в −1.61. Под осью две стрелки идут от каждого значения PMI к соответствующему минимуму, обе длиной log 5. Точечная серая кривая для пары, которая никогда не встречается вместе, монотонно убывает к нулю слева и минимума не имеет.123−4−20240оценка x = uo · vcPMI 3.00 → минимум 1.39PMI 0.00 → минимум −1.61стрелки: от PMI (полый маркер) к минимуму (закрашенный), сдвиг −log k = −1.61связанная пара: #(c, o) = 200, PMI 3.00несвязанная пара: #(c, o) = 10, PMI 0.00никогда не встречаются вместе: #(c, o) = 0, минимума нетЦелевая функция SGNS для одной пары в зависимости от оценкиТри кривые над осью оценок от минус четырёх до четырёх. Синяя кривая для сильно связанной пары с PMI 3.00 имеет U-образную форму и минимум в 1.39. Янтарная кривая для пары, которая встречается вместе ровно столько, сколько ожидается при независимости, с нулевой PMI, имеет минимум в −1.61. Под осью две стрелки идут от каждого значения PMI к соответствующему минимуму, обе длиной log 5. Точечная серая кривая для пары, которая никогда не встречается вместе, монотонно убывает к нулю слева и минимума не имеет.123−4−20240оценка x = uo · vc3.00 → 1.390.00 → −1.61стрелки: PMI → минимум, −log k = −1.61#(c, o) = 200, PMI 3.00#(c, o) = 10, PMI 0.00#(c, o) = 0, минимума нет
Целевая функция одной пары (c, o) как функция её оценки x = u_o · v_c, делённая на число членов, чтобы кривые помещались на одной оси. Игрушечные значения: центральное слово c встречается в #(c) = 1000 парах, P_n(o) = 0.01 и k = 5, так что o выбирается негативным примером для c в среднем 50 раз. Синяя кривая: o встречается вместе с c 200 раз, PMI = log 20 = 3.00. Янтарная: 10 раз, PMI = 0.00, ровно столько, сколько ожидается при независимости слов. Минимум каждой кривой (закрашенная точка) лежит в точке PMI − log k: 1.39 и −1.61; стрелки под осью показывают сдвиг на log 5 = 1.61 от PMI (полый маркер). Точечная кривая: у пары, которая никогда не встречается вместе, остаётся только негативный член −log σ(−x); он неотрицателен и убывает к своей нижней грани 0 при x → −∞, не достигая её, поэтому конечного минимума нет и оптимальная оценка равна −∞.

Итак, SGNS раскладывает матрицу сдвинутой PMI в произведение WinWout⊤W_{\text{in}} W_{\text{out}}^\top ранга dd, и это сжатие сближает слова с похожими строками PMI. У пар, которые никогда не встречаются вместе, PMI⁡=−∞\operatorname{PMI} = -\infty (точечная кривая), поэтому там разложение остаётся приближённым при любом dd.

Чему учится небольшая модель на вопросах Quora#

Возьмём около полумиллиона вопросов Quora, токенизированных без стоп-слов, но со знаками препинания, такими как ?, и обучим модель с d=32d = 32, радиусом окна 5 и минимальной частотой 5. Всё остальное — значения gensim по умолчанию (таблица ниже), так что это CBOW с негативным сэмплированием, k=5k = 5, и прореживанием.

У вектора слова word 32 координаты от −4.09-4.09 до 4.184.18 (норма 10.7), а его ближайшие соседи по косинусной близости, приведённые в предыдущей заметке, — sentence (0.836), words (0.796) и verb (0.787). Формы единственного и множественного числа стоят рядом (word/words, phrase/phrases), потому что текст не лемматизировался. Соседи тематические не меньше, чем грамматические, потому что без стоп-слов и с прореженным ? окно радиуса 5 покрывает большую часть вопроса, чем пять исходных токенов.

Вторая модель CBOW, 100-мерная, с минимальной частотой 4 и радиусом окна 5, обучается только на обучающих статьях AG News, чтобы слова тестовой выборки не просочились; она даёт входные векторы для следующей заметки.

Гиперпараметры и что они делают#

ПараметрЧто делаетПо умолчанию в gensimМодели Quora и AG News
vector_size ddЁмкость; обычный диапазон 50–30010032 (Quora), 100 (AG News)
window mmРадиус; более широкие окна дают более тематических соседей, более узкие — более синтаксических (Jurafsky and Martin, §5.7)55
min_countОтбрасывает более редкие слова; задаёт ∣V∣\lvert V \rvert55 (Quora), 4 (AG News)
sg0 = CBOW, 1 = skip-gram0по умолчанию
negative kkЧисло негативных примеров на пару; 0 вместе с hs=1 даёт иерархический softmax5по умолчанию
ns_exponentПоказатель степени частот в PnP_n0.75по умолчанию
sampleПорог прореживания частых слов10−310^{-3}по умолчанию
epochs, alphaЧисло проходов по корпусу; начальный шаг обучения5, 0.025по умолчанию

С подобранными окном, прореживанием, числом негативных примеров и показателем степени шума методы, основанные на подсчётах, и SGNS дают гораздо более близкие результаты, чем предполагали исходные сравнения (Levy, Goldberg and Dagan, 2015).

Что изменилось#

Эмбеддинги, обученные на задачеWord2Vec с полным softmaxWord2Vec с негативным сэмплированием
Обучающий сигналМетки одной задачиСам текстСам текст
Доступные данныеТысячи размеченных примеровМиллиарды токеновМиллиарды токенов
Покрытие словаряСлова из размеченного набораСлова корпусаСлова корпуса
Выход на шагеKK классов метокsoftmax по ∣V∣\lvert V \rvert классамk+1k + 1 бинарных классификаторов
Параметров затрагивается на пару (∣V∣=200 000\lvert V \rvert = 200\,000, d=300d = 300)—60 000 3002100 (k=5k = 5)
Что кодируют векторыВсё, что разделяет меткиСтруктуру совместной встречаемостиСдвинутую PMI, сжатую до ранга dd

Результат — таблица, которую может переиспользовать любая модель.

GloVe и FastText#

У двух более поздних статических эмбеддингов есть собственные заметки. GloVe (Pennington, Socher and Manning, 2014), который дал векторы Twitter из предыдущей заметки, подгоняет uw⋅vc+bw+bc≈log⁡Xwcu_w \cdot v_c + b_w + b_c \approx \log X_{wc} к матрице совместной встречаемости XX взвешенным методом наименьших квадратов; как и SGNS, он подгоняет функцию от частот совместной встречаемости скалярными произведениями, поэтому они оказываются близки (заметка о GloVe). FastText (Bojanowski et al., 2017) обучает SGNS, но представляет слово как сумму векторов его символьных n-грамм (where → <wh, whe, her, ere, re>), поэтому у родственных слов есть общие параметры, а незнакомое слово всё равно получает вектор (заметка о FastText).

Ограничения#

  • Статичность. Один вектор на слово словаря: bank — единый компромисс между берегом реки и банком. Это устраняет заметка о BERT.
  • Закрытый словарь. Слова ниже порога min_count или отсутствующие в корпусе не получают вектора; эту проблему решают FastText и токенизация на подслова (subword).
  • Привязка к окну. Вектор формируют только соседи в пределах mm позиций, а CBOW игнорирует их порядок; отрицание и дальние зависимости не учитываются.
  • Сходство означает взаимозаменяемость. good и bad, hot и cold, Monday и Tuesday встречаются в одних и тех же контекстах и оказываются близки — неподходящая геометрия для анализа тональности.
  • Требовательность к данным. Полмиллиона вопросов хватает для частых слов, таких как word, но не для редких; аналогии из предыдущей заметки используют миллиарды токенов.
  • Чувствительность и невоспроизводимость. Предобработка, окно, прореживание и kk меняют соседей, а многопоточные запуски с одним seed дают разные результаты.

Что нужно запомнить#

  • Skip-gram предсказывает контекст по центральному слову, CBOW — центральное слово по контексту. Сеть линейна; её первый слой WinW_{\text{in}} — это таблица эмбеддингов, а выходной слой лишь даёт обучающий сигнал.
  • Полный softmax обновляет все ∣V∣|V| выходных строк на каждую пару; негативное сэмплирование классифицирует настоящую пару против kk пар, сэмплированных из униграммного распределения в степени 3/43/4, и обновляет (k+2)d(k + 2) d параметров.
  • В оптимуме SGNS выставляет uo⋅vc=PMI⁡(c,o)−log⁡ku_o \cdot v_c = \operatorname{PMI}(c, o) - \log k: векторы — низкоранговое сжатие статистики совместной встречаемости.
  • gensim по умолчанию обучает CBOW с k=5k = 5 негативными примерами; для skip-gram нужен sg=1.

Ноутбук#

week01_word_embeddings.ipynb. Ячейки нумеруются с 1, включая текстовые. Приведённые числа взяты из прогона, сохранённого в курсе; у ячеек, изменённых с тех пор под текущие версии библиотек, сохранённого выхода нет.

  • Данные (ячейки 4–31). Ячейка 4 скачивает файл с вопросами Quora, только если его нет (в репозитории он уже лежит); ячейка 6 читает data/quora.txt с диска. Ячейки 13–22 строят data_tok: wordpunct_tokenize, приведение к нижнему регистру (упражнение в ячейке 15, решение уже вписано), удаление стоп-слов NLTK, знаки препинания остаются. Лемматизированные и стеммированные варианты 537 272 вопросов (ячейки 28–31) Word2Vec не использует.
  • Обучение (ячейки 53–58). Текстовые ячейки вводят skip-gram и gensim (Alammar, 2019); ячейка 58 обучает Word2Vec(data_tok, vector_size=32, min_count=5, window=5), что со значениями по умолчанию даёт CBOW с 5 негативными примерами и описанным выше суммирующим обновлением контекста (cbow_mean=1), а не skip-gram.
  • Соседи (ячейки 59–60). Вектор слова word и его ближайшие соседи — единственные сохранённые выходы этой модели: ни кривая функции потерь, ни время обучения, ни размер словаря, ни метрика качества не сохранены. Норма 10.7, приведённая выше, вычислена по напечатанным координатам.
  • Аналогии (ячейки 61–66). Предобученные 100-мерные векторы GloVe Twitter и аналогии, приведённые в предыдущей заметке.

week02_NN_text_classification.ipynb, ячейки 13–15, обучает 100-мерную модель CBOW (min_count=4, window=5) только на обучающих текстах AG News, чтобы слова тестовой выборки не просочились, и превращает каждую статью в последовательность векторов для следующей заметки.

Дальше#

Word2Vec учится по одному окну за раз и никогда не смотрит на корпус целиком. Следующая заметка один раз подсчитывает все пары слов в матрицу совместной встречаемости, подгоняет векторы прямо к логарифмам этих частот и показывает, что оба подхода в итоге раскладывают почти одну и ту же матрицу.

Литература#