Фаза 01 · урок 09

Теория информации: энтропия, KL-дивергенция

Цель урока: Вы вызываете CrossEntropyLoss() в каждой обучаемой модели классификации. Видите «перплексию» в каждой статье о языковых моделях. Читаете о KL-дивергенции в VAE, дистилляции и RLHF. Это не разрозненные понятия. Это одна и та же идея в…

Текущий релиз AlexBred.com: первые 100 уроков русскоязычной программы.

Курс
AI Engineering from Scratch
Фаза
Математические основы
Чтение
15 мин.
Проверено
Содержание урока
  1. Цели обучения
  2. Проблема
  3. Концепция
  4. Информационное содержание (неожиданность)
  5. Энтропия (средняя неожиданность)
  6. Кросс-энтропия (функция потерь, которую вы используете каждый день)
  7. KL-дивергенция (расстояние между распределениями)
  8. Взаимная информация
  9. Условная энтропия
  10. Совместная энтропия
  11. Взаимная информация (подробно)
  12. Сглаживание меток и кросс-энтропия
  13. Почему кросс-энтропия — ГЛАВНАЯ функция потерь для классификации
  14. Биты и наты
  15. Перплексия
  16. Соберите сами
  17. Шаг 1: информационное содержание и энтропия
  18. Шаг 2: кросс-энтропия и KL-дивергенция
  19. Шаг 3: кросс-энтропия как функция потерь классификации
  20. Шаг 4: кросс-энтропия равна отрицательному логарифму правдоподобия
  21. Шаг 5: взаимная информация
  22. Примените
  23. Упражнения
  24. Ключевые термины
  25. Дополнительные материалы

Теория информации измеряет неожиданность. На ней строятся функции потерь.

Тип: Изучение Язык: Python Предварительные требования: Фаза 1, урок 06 («Вероятность») Время: ~60 минут

Цели обучения

  • Вычислять с нуля энтропию, кросс-энтропию и KL-дивергенцию и объяснять их связь
  • Вывести, почему минимизация потерь кросс-энтропии эквивалентна максимизации логарифма правдоподобия
  • Вычислять взаимную информацию между признаками и целевой переменной, чтобы ранжировать важность признаков
  • Объяснять перплексию как эффективный размер словаря, из которого выбирает языковая модель

Проблема

Вы вызываете CrossEntropyLoss() в каждой обучаемой модели классификации. Видите «перплексию» в каждой статье о языковых моделях. Читаете о KL-дивергенции в VAE, дистилляции и RLHF. Это не разрозненные понятия. Это одна и та же идея в разных обличьях.

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

Этот урок выводит каждую формулу с нуля, чтобы вы увидели, откуда они берутся и почему работают.

Концепция

Информационное содержание (неожиданность)

Когда происходит что-то маловероятное, это несёт больше информации. Монета выпала орлом? Неудивительно. Выигрыш в лотерею? Очень неожиданно.

Информационное содержание события с вероятностью p равно:

I(x) = -log(p(x))

Логарифм по основанию 2 даёт биты. Натуральный логарифм даёт наты. Идея та же, единицы разные.

Event              Probability    Surprise (bits)
Fair coin heads    0.5            1.0
Rolling a 6        0.167          2.58
1-in-1000 event    0.001          9.97
Certain event      1.0            0.0

Достоверные события несут нулевую информацию. Вы уже знали, что они произойдут.

Энтропия (средняя неожиданность)

Энтропия — это ожидаемая неожиданность по всем возможным исходам распределения.

H(P) = -sum( p(x) * log(p(x)) )  for all x

У честной монеты максимальная энтропия для бинарной переменной: 1 бит. У смещённой монеты (99% орлов) энтропия низкая: 0,08 бита. Вы уже знаете, что произойдёт, поэтому каждый бросок почти ничего не сообщает.

Fair coin:    H = -(0.5 * log2(0.5) + 0.5 * log2(0.5)) = 1.0 bit
Biased coin:  H = -(0.99 * log2(0.99) + 0.01 * log2(0.01)) = 0.08 bits

Энтропия измеряет неустранимую неопределённость распределения. Сжать данные сильнее неё нельзя.

Кросс-энтропия (функция потерь, которую вы используете каждый день)

Кросс-энтропия измеряет среднюю неожиданность, когда вы используете распределение Q для кодирования событий, которые в действительности происходят из распределения P.

H(P, Q) = -sum( p(x) * log(q(x)) )  for all x

P — истинное распределение (метки). Q — предсказания вашей модели. Если Q идеально совпадает с P, кросс-энтропия равна энтропии. Любое расхождение делает её больше.

В классификации P — one-hot-вектор (истинный класс имеет вероятность 1, все остальные — 0). Тогда кросс-энтропия упрощается до:

H(P, Q) = -log(q(true_class))

Это вся формула потерь кросс-энтропии для классификации. Максимизируйте предсказанную вероятность правильного класса.

KL-дивергенция (расстояние между распределениями)

KL-дивергенция измеряет, насколько больше неожиданности вы получаете, используя Q вместо P.

D_KL(P || Q) = sum( p(x) * log(p(x) / q(x)) )  for all x
             = H(P, Q) - H(P)

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

KL-дивергенция несимметрична: D_KL(P || Q) != D_KL(Q || P). Это не настоящая метрика расстояния.

Взаимная информация

Взаимная информация измеряет, сколько знание одной переменной сообщает о другой.

I(X; Y) = H(X) - H(X|Y)
        = H(X) + H(Y) - H(X, Y)

Если X и Y независимы, взаимная информация равна нулю. Знание одной переменной ничего не говорит о другой. Если они идеально коррелированы, взаимная информация равна энтропии любой из них.

При отборе признаков высокая взаимная информация между признаком и целью означает, что признак полезен. Низкая взаимная информация означает шум.

Условная энтропия

H(Y|X) измеряет, сколько неопределённости о Y остаётся после наблюдения X.

H(Y|X) = H(X,Y) - H(X)

Два крайних случая:

  • Если X полностью определяет Y, то H(Y|X) = 0. Знание X устраняет всю неопределённость о Y. Пример: X = температура в градусах Цельсия, Y = температура в градусах Фаренгейта.
  • Если X ничего не сообщает о Y, то H(Y|X) = H(Y). Знание X совсем не уменьшает вашу неопределённость. Пример: X = бросок монеты, Y = погода завтра.

Условная энтропия всегда неотрицательна и никогда не превышает H(Y):

0 <= H(Y|X) <= H(Y)

В машинном обучении условная энтропия встречается в деревьях решений. При каждом разбиении алгоритм выбирает признак X, минимизирующий H(Y|X) — признак, который устраняет наибольшую неопределённость о метке Y.

Совместная энтропия

H(X,Y) — это энтропия совместного распределения X и Y.

H(X,Y) = -sum sum p(x,y) * log(p(x,y))   for all x, y

Ключевое свойство:

H(X,Y) <= H(X) + H(Y)

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

Диаграмма к уроку «Теория информации: энтропия, KL-дивергенция»

Связи:

  • H(X,Y) = H(X) + H(Y|X) = H(Y) + H(X|Y)
  • I(X;Y) = H(X) - H(X|Y) = H(Y) - H(Y|X)
  • H(X,Y) = H(X) + H(Y) - I(X;Y)

Взаимная информация (подробно)

Взаимная информация I(X;Y) количественно определяет, насколько знание одной переменной уменьшает неопределённость о другой.

I(X;Y) = H(X) - H(X|Y)
       = H(Y) - H(Y|X)
       = H(X) + H(Y) - H(X,Y)
       = sum sum p(x,y) * log(p(x,y) / (p(x) * p(y)))

Свойства:

  • I(X;Y) >= 0 всегда. Наблюдая что-либо, вы никогда не теряете информацию.
  • I(X;Y) = 0 тогда и только тогда, когда X и Y независимы.
  • I(X;Y) = I(Y;X). Она симметрична, в отличие от KL-дивергенции.
  • I(X;X) = H(X). Переменная разделяет с собой всю свою информацию.

Взаимная информация для отбора признаков. В ML нужны признаки, информативные о целевой переменной. Взаимная информация даёт принципиальный способ ранжировать признаки:

  1. Для каждого признака X_i вычислите I(X_i; Y), где Y — целевая переменная.
  2. Отранжируйте признаки по оценке MI.
  3. Оставьте top k признаков.

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

Метод Выявляет Вычислительная стоимость Обрабатывает категориальные данные?
Корреляция Пирсона Линейные связи O(n) Нет
Корреляция Спирмена Монотонные связи O(n log n) Нет
Взаимная информация Любая статистическая зависимость O(n log n) с биннингом Да

Сглаживание меток и кросс-энтропия

Стандартная классификация использует жёсткие цели: [0, 0, 1, 0]. Истинному классу присваивается вероятность 1, всем остальным — 0. Сглаживание меток заменяет их мягкими целями:

soft_target = (1 - epsilon) * hard_target + epsilon / num_classes

При epsilon = 0.1 и 4 классах:

  • Жёсткая цель: [0, 0, 1, 0]
  • Мягкая цель: [0.025, 0.025, 0.925, 0.025]

С точки зрения теории информации сглаживание меток увеличивает энтропию целевого распределения. Жёсткие one-hot-цели имеют энтропию 0 — неопределённости нет. Мягкие цели имеют положительную энтропию.

Почему это помогает:

  • Не даёт модели уводить логиты к экстремальным значениям (для идеального совпадения с one-hot-целью при кросс-энтропии потребовались бы бесконечные логиты)
  • Работает как регуляризация: модель не может быть уверена на 100%
  • Улучшает калибровку: предсказанные вероятности лучше отражают истинную неопределённость
  • Сокращает разрыв между поведением при обучении и инференсе

Потери кросс-энтропии при сглаживании меток становятся:

L = (1 - epsilon) * CE(hard_target, prediction) + epsilon * H_uniform(prediction)

Второй член штрафует предсказания, далёкие от равномерного распределения, — это прямая регуляризация уверенности.

Почему кросс-энтропия — ГЛАВНАЯ функция потерь для классификации

Три взгляда, один вывод.

Взгляд теории информации. Кросс-энтропия измеряет, сколько битов вы тратите впустую, используя распределение модели вместо истинного распределения. Минимизация делает модель наиболее эффективным кодировщиком реальности.

Взгляд максимального правдоподобия. Для N обучающих примеров с истинными классами y_i:

Likelihood     = product( q(y_i) )
Log-likelihood = sum( log(q(y_i)) )
Negative log-likelihood = -sum( log(q(y_i)) )

Последняя строка — это потери кросс-энтропии. Минимизация кросс-энтропии = максимизация правдоподобия обучающих данных при вашей модели.

Взгляд градиента. Градиент кросс-энтропии по логитам — это просто (predicted - true). Его легко, стабильно и быстро вычислять. Поэтому она идеально сочетается с softmax.

Биты и наты

Единственное различие — основание логарифма.

log base 2   -> bits      (information theory tradition)
log base e   -> nats      (machine learning convention)
log base 10  -> hartleys  (rarely used)

1 нат = 1/ln(2) бита = 1,4427 бита. PyTorch и TensorFlow по умолчанию используют натуральный логарифм (наты).

Перплексия

Перплексия — это экспонента кросс-энтропии. Она показывает эффективное число равновероятных вариантов, между которыми не уверена модель.

Perplexity = 2^H(P,Q)   (if using bits)
Perplexity = e^H(P,Q)   (if using nats)

Языковая модель с перплексией 50 в среднем настолько же не уверена, как если бы ей приходилось равновероятно выбирать из 50 возможных следующих токенов. Чем ниже, тем лучше.

GPT-2 достигала перплексии ~30 на распространённых бенчмарках. У современных моделей на хорошо представленных доменах значения выражаются однозначными числами.

entropy-kl

Соберите сами

Шаг 1: информационное содержание и энтропия

import math

def information_content(p, base=2):
    if p <= 0 or p > 1:
        return float('inf') if p <= 0 else 0.0
    return -math.log(p) / math.log(base)

def entropy(probs, base=2):
    return sum(
        p * information_content(p, base)
        for p in probs if p > 0
    )

fair_coin = [0.5, 0.5]
biased_coin = [0.99, 0.01]
fair_die = [1/6] * 6

print(f"Fair coin entropy:   {entropy(fair_coin):.4f} bits")
print(f"Biased coin entropy: {entropy(biased_coin):.4f} bits")
print(f"Fair die entropy:    {entropy(fair_die):.4f} bits")

Шаг 2: кросс-энтропия и KL-дивергенция

def cross_entropy(p, q, base=2):
    total = 0.0
    for pi, qi in zip(p, q):
        if pi > 0:
            if qi <= 0:
                return float('inf')
            total += pi * (-math.log(qi) / math.log(base))
    return total

def kl_divergence(p, q, base=2):
    return cross_entropy(p, q, base) - entropy(p, base)

true_dist = [0.7, 0.2, 0.1]
good_model = [0.6, 0.25, 0.15]
bad_model = [0.1, 0.1, 0.8]

print(f"Entropy of true dist:     {entropy(true_dist):.4f} bits")
print(f"CE (good model):          {cross_entropy(true_dist, good_model):.4f} bits")
print(f"CE (bad model):           {cross_entropy(true_dist, bad_model):.4f} bits")
print(f"KL divergence (good):     {kl_divergence(true_dist, good_model):.4f} bits")
print(f"KL divergence (bad):      {kl_divergence(true_dist, bad_model):.4f} bits")

Шаг 3: кросс-энтропия как функция потерь классификации

def softmax(logits):
    max_logit = max(logits)
    exps = [math.exp(z - max_logit) for z in logits]
    total = sum(exps)
    return [e / total for e in exps]

def cross_entropy_loss(true_class, logits):
    probs = softmax(logits)
    return -math.log(probs[true_class])

logits = [2.0, 1.0, 0.1]
true_class = 0

probs = softmax(logits)
loss = cross_entropy_loss(true_class, logits)

print(f"Logits:      {logits}")
print(f"Softmax:     {[f'{p:.4f}' for p in probs]}")
print(f"True class:  {true_class}")
print(f"Loss:        {loss:.4f} nats")
print(f"Perplexity:  {math.exp(loss):.2f}")

Шаг 4: кросс-энтропия равна отрицательному логарифму правдоподобия

import random

random.seed(42)

n_samples = 1000
n_classes = 3
true_labels = [random.randint(0, n_classes - 1) for _ in range(n_samples)]
model_logits = [[random.gauss(0, 1) for _ in range(n_classes)] for _ in range(n_samples)]

ce_loss = sum(
    cross_entropy_loss(label, logits)
    for label, logits in zip(true_labels, model_logits)
) / n_samples

nll = -sum(
    math.log(softmax(logits)[label])
    for label, logits in zip(true_labels, model_logits)
) / n_samples

print(f"Cross-entropy loss:      {ce_loss:.6f}")
print(f"Negative log-likelihood: {nll:.6f}")
print(f"Difference:              {abs(ce_loss - nll):.2e}")

Шаг 5: взаимная информация

def mutual_information(joint_probs, base=2):
    rows = len(joint_probs)
    cols = len(joint_probs[0])

    margin_x = [sum(joint_probs[i][j] for j in range(cols)) for i in range(rows)]
    margin_y = [sum(joint_probs[i][j] for i in range(rows)) for j in range(cols)]

    mi = 0.0
    for i in range(rows):
        for j in range(cols):
            pxy = joint_probs[i][j]
            if pxy > 0:
                mi += pxy * math.log(pxy / (margin_x[i] * margin_y[j])) / math.log(base)
    return mi

independent = [[0.25, 0.25], [0.25, 0.25]]
dependent = [[0.45, 0.05], [0.05, 0.45]]

print(f"MI (independent): {mutual_information(independent):.4f} bits")
print(f"MI (dependent):   {mutual_information(dependent):.4f} bits")

Примените

Те же понятия с использованием NumPy — так, как вы будете применять их на практике:

import numpy as np

def np_entropy(p):
    p = np.asarray(p, dtype=float)
    mask = p > 0
    result = np.zeros_like(p)
    result[mask] = p[mask] * np.log(p[mask])
    return -result.sum()

def np_cross_entropy(p, q):
    p, q = np.asarray(p, dtype=float), np.asarray(q, dtype=float)
    mask = p > 0
    return -(p[mask] * np.log(q[mask])).sum()

def np_kl_divergence(p, q):
    return np_cross_entropy(p, q) - np_entropy(p)

true = np.array([0.7, 0.2, 0.1])
pred = np.array([0.6, 0.25, 0.15])
print(f"Entropy:    {np_entropy(true):.4f} nats")
print(f"Cross-ent:  {np_cross_entropy(true, pred):.4f} nats")
print(f"KL div:     {np_kl_divergence(true, pred):.4f} nats")

Вы собрали с нуля то, что torch.nn.CrossEntropyLoss() делает внутри. Теперь вы знаете, почему потери снижаются во время обучения: предсказанное распределение вашей модели приближается к истинному распределению, измеренному в натах потраченной впустую информации.

Упражнения

  1. Вычислите энтропию английского алфавита, предполагая равномерное распределение (26 букв). Затем оцените её, используя фактические частоты букв. Какая величина выше и почему?

  2. Модель выдаёт логиты [5.0, 2.0, 0.5] для примера с истинным классом 1. Вычислите потери кросс-энтропии вручную, затем проверьте их своей функцией cross_entropy_loss. Какие логиты дали бы нулевые потери?

  3. Покажите, что KL-дивергенция несимметрична. Выберите два распределения P и Q и вычислите D_KL(P || Q) и D_KL(Q || P). Объясните, почему они различаются.

  4. Создайте функцию, вычисляющую перплексию для последовательности предсказаний токенов. Получив список пар (true_token_index, predicted_logits), верните перплексию последовательности.

Ключевые термины

Термин Как обычно говорят Что это на самом деле означает
Информационное содержание «Неожиданность» Число битов (или натов), необходимое для кодирования события: -log(p)
Энтропия «Случайность» Средняя неожиданность по всем исходам распределения. Измеряет неустранимую неопределённость.
Кросс-энтропия «Функция потерь» Средняя неожиданность при использовании распределения модели Q для кодирования событий из истинного распределения P.
KL-дивергенция «Расстояние между распределениями» Дополнительные биты, потраченные впустую при использовании Q вместо P. Равна кросс-энтропии минус энтропия. Несимметрична.
Взаимная информация «Насколько связаны X и Y» Уменьшение неопределённости о X благодаря знанию Y. Ноль означает независимость.
Softmax «Превращает логиты в вероятности» Возводит в экспоненту и нормализует. Отображает любой вещественный вектор в корректное распределение вероятностей.
Перплексия «Насколько модель запутана» Экспонента кросс-энтропии. Эффективный размер словаря, из которого модель выбирает на каждом шаге.
Биты «Единица Шеннона» Информация, измеренная логарифмом по основанию 2. Один бит разрешает один честный бросок монеты.
Наты «Единица ML» Информация, измеренная натуральным логарифмом. По умолчанию используется PyTorch и TensorFlow.
Отрицательный логарифм правдоподобия «Потери NLL» Идентичен потерям кросс-энтропии для one-hot-меток. Его минимизация максимизирует вероятность правильных предсказаний.

Дополнительные материалы


Источник: Information Theory — оригинал Навигация: назад: 01.08 — Оптимизация: семейство градиентного спуска · Фаза 1 — Математические основы · Полный каталог · следующая статья: 01.10 — Понижение размерности: PCA, t-SNE, UMAP.