Create your own
Lesson illustration

Вычисление и интерпретация энтропии дискретного распределения

Здравствуйте! В прошлом уроке мы вывели собственную информацию отдельного события:

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

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


Энтропия как математическое ожидание surprisal

Пусть дискретная случайная величина принимает значения с вероятностями

Если реализовался исход , его собственная информация равна

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

Это энтропия Шеннона распределения . Индекс подчёркивает основание логарифма; часто его опускают, если единица уже понятна из контекста.

Ключевой смысл формулы — не в механическом выражении , а в том, что каждый исход даёт вклад

Редкий исход имеет большой surprisal, но случается редко. Частый исход приносит мало информации при реализации, зато сильно влияет на среднее, поскольку возникает часто. Энтропия учитывает оба факта одновременно.

1.7. Some Bits of Information Theory — Machine Learning 0 ...

Прочитайте раздел “1.7.1. Entropy” из конспекта Machine Learning 0 Университета Амстердама. Он кратко связывает self-information с энтропией как ожидаемой величиной и разбирает крайние случаи.

В разделе “1.7.1. Entropy” прочитайте материал от определения self-information до примеров равномерного, бинарного и детерминированного распределений; остановитесь перед разделом “1.7.2. Bit Encoding”. После объяснения self-information найдите выбор единиц и определение энтропии. Проследите, почему множитель p_i появляется именно как вес в математическом ожидании.

Полезно держать в голове различие объектов:

ОбъектФормулаЧто характеризует
Surprisal конкретного исходаНасколько неожиданным оказался этот исход
Энтропия распределенияСредняя неожиданность до наблюдения исхода

Так, если модель присвоила правильному классу вероятность , конкретный loss для этого примера велик. Но это ещё не утверждение об энтропии распределения модели: она зависит от вероятностей всех классов, а не только наблюдённой метки.


Вычисление: вероятности, surprisals, вклады

Рассмотрим распределение трёх исходов:

Возьмём логарифм по основанию , то есть будем измерять результат в битах.

ИсходВероятность Surprisal Вклад

Складываем последний столбец:

Заметьте важную деталь. Исход наиболее информативен, если он произошёл: его surprisal составляет бита. Однако его вклад в среднюю неопределённость не максимален: вероятность уменьшает вес этого большого surprisаl. В данном примере крупнейший вклад даёт исход с вероятностью .

Бинарный случай

Если , а

то энтропию удобно записывать как бинарную энтропийную функцию:

Для монеты, где орёл выпадает с вероятностью , получаем:

Это не значит, что каждый бросок «занимает 0.469 физического бита». Это средняя неопределённость одного броска. Её операционную связь с достижимой средней длиной кодирования мы строго разберём в модуле о сжатии.

Бинарная энтропия \(h_2(p)\) в битах в зависимости от вероятности события \(X=1\): она равна нулю при \(p=0\) и \(p=1\), симметрична относительно \(p=0.5\) и достигает \(1\) бита для честной монеты.

График показывает три базовых свойства:

  1. Детерминированность даёт нулевую энтропию. При или исход заранее известен.
  2. Перестановка меток ничего не меняет. Распределения и имеют одну и ту же энтропию.
  3. Равновероятная бинарная переменная имеет максимальную неопределённость. При :

Позднее мы докажем общую теорему: на фиксированном конечном числе исходов энтропия максимальна при равномерном распределении. Здесь пока важна вычислительная и интуитивная сторона этого факта.

Entropy (for data science) Clearly Explained!!!

Посмотрите “Entropy (for data science) Clearly Explained!!!” от StatQuest with Josh Starmer. В этом фрагменте энтропия строится прямо как средний surprisal для смещённой монеты.

В отрывке entropy as average surprise проследите два эквивалентных рассуждения: сначала ожидаемый суммарный surprisal серии бросков, затем деление на число бросков. Сопоставьте веса 0.9 и 0.1 с множителями p_i в формуле математического ожидания.


Нулевые вероятности и крайние распределения

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

Поэтому принимается соглашение

Оно содержательно естественно: исход с вероятностью ноль не происходит в модели распределения и не влияет на средний surprisal.

Например, распределения

имеют одинаковую энтропию:

Формально первое распределение задано на трёх метках, но две из них не принадлежат его фактическому носителю. Энтропия зависит от вероятностной массы, а не от числа записанных в массиве категорий.

Для равномерного распределения на исходах расчёт особенно прозрачен:

Тогда каждый исход имеет одинаковый surprisal:

а среднее той же константы остаётся константой:

В двоичных единицах:

  • : бит;
  • : бита;
  • : бит.

Это объясняет, почему слово «бит» уместно: равномерный выбор из двух вариантов несёт ровно один бит неопределённости. Но не стоит делать обратный неверный вывод, что энтропия всегда равна логарифму мощности алфавита. Это верно только для равномерного распределения. Например, алфавит из токенов с почти всей массой на одном токене может иметь энтропию значительно меньше бит.


Биты и наты: одна величина, разные масштабы

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

При основании :

энтропия измеряется в битах.

При естественном логарифме:

энтропия измеряется в натах.

Связь следует из формулы смены основания:

Следовательно,

Для уже рассмотренного распределения :

В ML наты встречаются особенно часто, потому что log-likelihood, negative log-likelihood и большинство реализаций cross-entropy используют . Биты удобнее для связи с кодированием, compression rate и сравнением с равновероятными двоичными вопросами.

При сравнении чисел всегда проверяйте единицы. Значение не является универсальной «одной единицей неопределённости»:


Надёжное вычисление в PyTorch

На практике энтропия часто считается для вероятностных векторов модели. Важные требования к реализации:

  • вероятности неотрицательны;
  • сумма вероятностей по классовой оси равна единице;
  • нулевые вероятности не должны порождать nan;
  • основание логарифма должно быть явным, если результат выводится пользователю или сопоставляется с другой метрикой.
import math
import torch


def discrete_entropy(
    probs: torch.Tensor,
    dim: int = -1,
    base: float = math.e,
) -> torch.Tensor:
    """Shannon entropy for categorical probability vectors."""
    probs = torch.as_tensor(probs, dtype=torch.float64)

    if not torch.isfinite(probs).all():
        raise ValueError("Probabilities must be finite.")
    if (probs < 0).any():
        raise ValueError("Probabilities must be non-negative.")
    if base <= 0.0 or math.isclose(base, 1.0):
        raise ValueError("Logarithm base must be positive and not equal to 1.")

    total_mass = probs.sum(dim=dim)
    if not torch.allclose(
        total_mass,
        torch.ones_like(total_mass),
        atol=1e-10,
        rtol=1e-10,
    ):
        raise ValueError("Probabilities must sum to 1 along `dim`.")

    # The clamp prevents log(0); torch.where implements 0 log 0 = 0.
    tiny = torch.finfo(probs.dtype).tiny
    safe_probs = probs.clamp_min(tiny)

    terms = torch.where(
        probs > 0,
        probs * safe_probs.log(),
        torch.zeros_like(probs),
    )

    return -terms.sum(dim=dim) / math.log(base)

Проверим распределение из ручного расчёта:

p = torch.tensor([0.7, 0.2, 0.1])

h_bits = discrete_entropy(p, base=2.0)
h_nats = discrete_entropy(p, base=math.e)

print(f"{h_bits.item():.4f} bits")
print(f"{h_nats.item():.4f} nats")
print(torch.allclose(h_nats, h_bits * math.log(2.0)))

Ожидаемый вывод:

1.1568 bits
0.8018 nats
True

Функция работает и для батча распределений. Если тензор имеет форму [batch, num_classes], энтропия по умолчанию вычисляется вдоль последней оси и возвращает один результат на объект:

batch_probs = torch.tensor([
    [0.5, 0.5],
    [0.9, 0.1],
    [1.0, 0.0],
])

print(discrete_entropy(batch_probs, base=2.0))

Результаты соответственно близки к

бит. В дальнейшем такая операция станет основой для анализа предиктивной неопределённости классификаторов, распределений токенов и политик в RL. Но сама по себе высокая или низкая энтропия ещё не означает, что модель хороша, калибрована или полезна: она описывает форму её распределения.


Итог

Энтропия Шеннона — ожидаемая собственная информация:

Главные ориентиры:

  • surprisal относится к реализованному исходу, энтропия — к распределению до наблюдения;
  • каждый вклад имеет вид , поэтому редкость и частота исхода уравновешивают друг друга;
  • используется соглашение ;
  • в битах применяется , в натах — ;
  • перевод единиц задаётся равенством

В следующем уроке мы перейдём от одного распределения к паре случайных величин: научимся вычислять совместную и условную энтропию из совместного распределения.

Can't find a good explanation? Sign up and we'll make it for you

Sign up