Дифференциальное и матричное исчисление

Градиент softmax и кросс-энтропии

Вывод, который стоит проделать один раз до конца — ответ оказывается неправдоподобно простым

Шаг 30 из 117 · ~32 мин

Две функции

Softmax превращает произвольные числа (логиты) в распределение:

pi=ezikezkp_i = \frac{e^{z_i}}{\sum_k e^{z_k}}

Кросс-энтропия измеряет, насколько распределение p\mathbf{p} расходится с правильным ответом y\mathbf{y} (обычно one-hot):

L=iyilogpiL = -\sum_i y_i \log p_i

Для one-hot y\mathbf{y} с единицей на позиции cc это просто L=logpcL = -\log p_c. Смысл разберём в блоке 4; здесь нас интересует только производная.

Покрутите логиты, сдвиг и температуру. Сдвиг ничего не меняет — это первое, что понадобится в выводе:

сдвиг всех логитов 0
температура 1
сумма вероятностей
1
наибольшая
60.9%

Инвариантность к сдвигу

ezi+ckezk+c=ecezieckezk=pi\frac{e^{z_i + c}}{\sum_k e^{z_k + c}} = \frac{e^c e^{z_i}}{e^c\sum_k e^{z_k}} = p_i

Множитель ece^c сокращается. Два следствия:

  • у softmax есть лишняя степень свободы: логиты определены с точностью до общего сдвига, поэтому у задачи с KK классами по существу K1K-1 параметров;
  • отсюда берётся стандартный трюк устойчивости: вычесть maxkzk\max_k z_k перед экспонентой. Тогда наибольший показатель равен нулю, exp не переполняется, а ответ не меняется. Ровно это делает logsumexp, и к нему вернёмся в блоке 6.

Якобиан softmax

Дифференцируем pip_i по zjz_j. Случай i=ji = j и случай iji \ne j считаются по правилу частного и объединяются в одну формулу:

pizj=pi(δijpj)\frac{\partial p_i}{\partial z_j} = p_i\bigl(\htmlData{k=delta}{\delta_{ij}} - \htmlData{k=coupling}{p_j}\bigr)

Это матрица, а не вектор: softmax отображает RKRK\R^K \to \R^K. Диагональные элементы pi(1pi)p_i(1-p_i) положительны, внедиагональные pipj-p_ip_j отрицательны. и есть содержательная часть: вероятности связаны условием нормировки, и поднять одну можно только за счёт остальных.

Включите строку якобиана в виджете выше и проверьте знаки.

Сокращение

Теперь соберём градиент лосса по логитам. По правилу цепочки с суммой по путям — через каждую компоненту p\mathbf{p}:

Lzj=iLpipizj\frac{\partial L}{\partial z_j} = \sum_i \frac{\partial L}{\partial p_i}\frac{\partial p_i}{\partial z_j}

Первый множитель: L/pi=yi/pi\partial L/\partial p_i = -y_i/p_i. Подставляем якобиан:

Lzj=i(yipi)pi(δijpj)=iyi(δijpj)\frac{\partial L}{\partial z_j} = \sum_i \left(-\frac{y_i}{p_i}\right)p_i(\delta_{ij} - p_j) = -\sum_i y_i(\delta_{ij} - p_j)

Множитель pip_i сократился — это первое чудо. Раскрываем:

=yj+pjiyi=pjyj= -y_j + p_j\sum_i y_i = p_j - y_j

потому что iyi=1\sum_i y_i = 1 для распределения. Итого:

Lz=py\frac{\partial L}{\partial \mathbf{z}} = \htmlData{k=res}{\mathbf{p} - \mathbf{y}}

Ни экспонент, ни делений, ни матрицы якобиана — просто разность предсказания и правильного ответа. Матрица K×KK \times K сократилась в вектор длины KK.

Почему это важно, а не просто красиво

Численно. В logpc-\log p_c при малом pcp_c и в 1/pi1/p_i теряется точность. В py\mathbf{p} - \mathbf{y} терять нечего. Именно поэтому фреймворки предоставляют cross_entropy(logits, target) одной функцией, а не композицию log(softmax(x)) с NLL: сокращение делается аналитически, до вычислений.

Если вы когда-нибудь получали NaN, написав log(softmax(x)) вручную, — вот объяснение. Это не хрупкость библиотеки, а отказ от готового сокращения.

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

Температура

pi=ezi/Tkezk/Tp_i = \frac{e^{z_i/T}}{\sum_k e^{z_k/T}}

При T0T \to 0 распределение стремится к one-hot на максимуме, при TT \to \infty — к равномерному. Покрутите ползунок температуры: логиты не меняются, а распределение меняется от почти детерминированного до почти равномерного.

Где встречается: сэмплирование из языковых моделей, дистилляция знаний, Gumbel-softmax, энтропийная регуляризация в RL. Везде это один параметр — насколько распределению позволено быть уверенным.

Источники

  • Goodfellow, Bengio, Courville — Deep Learning, гл. 6.2 — Softmax, кросс-энтропия, градиенты выходного слоя
  • Bishop — Pattern Recognition and Machine Learning, гл. 4.3.4 — Многоклассовая логистическая регрессия и её градиент

Проверки

0 из 2
  1. Что даёт сокращение

    Отметьте все верные утверждения про softmax и кросс-энтропию.

  2. Стабильный softmax и градиент

    Реализуйте softmax_ce(logits, target) — верните список [loss, grad_0, grad_1, ...], где loss это кросс-энтропия, а остальное — градиент по логитам.

    target — индекс правильного класса. Значит y\mathbf{y} one-hot, и по уроку

    L=logptarget,Lzj=pjyjL = -\log p_{\text{target}}, \qquad \frac{\partial L}{\partial z_j} = p_j - y_j

    Два требования:

    • softmax считайте устойчиво: вычтите максимум логитов перед exp. Иначе на больших логитах получите inf / inf;
    • градиент считайте по формуле py\mathbf{p} - \mathbf{y}, а не через якобиан.

    Проверьте на последнем случае, что устойчивость действительно нужна: без вычитания максимума exp(1000) даёт бесконечность и весь ответ становится NaN.

    функция softmax_ce

    Загрузка редактора…

    Ctrl/⌘ + Enter