Phase 01 - Lesson 09

Teoria dá Informação

This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.

A teoria dá informação mede surpresa. As funções de perda são construidas sobre ela.

Tipo: Learn Linguagem: Python Pré-requisitos: Fase 1, Lição 06 (Probabilidade) Tempo: ~60 minutos

Objetivos de Aprendizagem

  • Calcular entropia, entropia cruzada e divergência KL do zero e explicar a relação entre elas
  • Derivar por que minimizar a perda de entropia cruzada é equivalente a maximizar a log-verossimilhanca
  • Calcular a informação mutua entre features é um alvo para ranquear a importancia das features
  • Explicar perplexidade como o tamanho efetivo de vocabulário do qual um modelo de linguagem escolhe

O Problema

Você chama CrossEntropyLoss() em todo modelo de classificacao que treina. Você vê "perplexidade" em todo artigo de modelo de linguagem. Você lê sobre divergência KL em VAEs, destilacao e RLHF. Esses não são conceitos desconexos. Eles são todos a mesma ideia usando chapeus diferentes.

A teoria dá informação te dá a linguagem para raciocinar sobre incerteza, compressão e predição. Claude Shannon a inventou em 1948 para resolver problemas de comúnicação. Acontece que treinar uma rede neural é um problema de comúnicação: o modelo está tentando transmitir o rótulo correto atraves de um canal ruidoso de pesos aprendidos.

Está lição constrói cada formula do zero para que você veja de onde elas vêm e por que funcionam.

O Conceito

Conteudo de Informação (Surpresa)

Quando algo improvavel acontece, isso carrega mais informação. Uma moeda caindo cara? Não surpreendente. Ganhar na loteria? Muito surpreendente.

O conteudo de informação de um evento com probabilidade p e:

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

Usar log na base 2 te dá bits. Usar log natural te dá nats. Mesma ideia, unidades diferentes.

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

Eventos certos carregam zero informação. Você já sabia que aconteceriam.

Entropia (Surpresa Média)

Entropia é a surpresa esperada ao longo de todos os resultados possíveis de uma distribuição.

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

Uma moeda justa tem entropia máxima para uma variavel binária: 1 bit. Uma moeda viciada (99% cara) tem baixa entropia: 0,08 bits. Você já sabe o que vai acontecer, então cada lancamento te diz quase nada.

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

Entropia mede a incerteza irredutivel em uma distribuição. Você não consegue comprimir abaixo dela.

Entropia Cruzada (A Função de Perda que Você Usa Todo Dia)

A entropia cruzada mede a surpresa média quando você usa a distribuição Q para codificar eventos que na verdade vêm dá distribuição P.

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

P é a distribuição verdadeira (os rótulos). Q são as predições do seu modelo. Se Q corresponde a P perfeitamente, a entropia cruzada é igual a entropia. Qualquer discrepancia a torna maior.

Na classificacao, P é um vetor one-hot (a classe verdadeira tem probabilidade 1, todo o resto 0). Isso simplifica a entropia cruzada para:

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

Essa é a formula completa dá perda de entropia cruzada para classificacao. Maximize a probabilidade prevista dá classe correta.

Divergência KL (Distância Entre Distribuições)

A divergência KL mede quanta surpresa extra você obtém ao usar Q em vez de P.

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

Entropia cruzada e entropia mais divergência KL. Como a entropia dá distribuição verdadeira é constante durante o treinamento, minimizar a entropia cruzada é o mesmo que minimizar a divergência KL. Você está empurrando a distribuição do seu modelo em direção a distribuição verdadeira.

A divergência KL não é simétrica: D_KL(P || Q) != D_KL(Q || P). Ela não é uma métrica de distância verdadeira.

Informação Mutua

A informação mutua mede quanto conhecer uma variavel te diz sobre outra.

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

Se X e Y são independentes, a informação mutua é zero. Conhecer uma não te diz nada sobre a outra. Se elas são perfeitamente correlacionadas, a informação mutua é igual a entropia de qualquer uma das variaveis.

Na seleção de features, alta informação mutua entre uma feature é o alvo significa que a feature é útil. Baixa informação mutua significa que ela e ruido.

Entropia Condicional

H(Y|X) mede quanta incerteza permanece sobre Y depois que você observa X.

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

Dois extremos:

  • Se X determina completamente Y, então H(Y|X) = 0. Conhecer X elimina toda a incerteza sobre Y. Exemplo: X = temperatura em Celsius, Y = temperatura em Fahrenheit.
  • Se X não te diz nada sobre Y, então H(Y|X) = H(Y). Conhecer X não reduz a sua incerteza de jeito nenhum. Exemplo: X = lancamento de moeda, Y = clima de amanha.

A entropia condicional e sempre não-negativa e nunca excede H(Y):

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

Em machine learning, a entropia condicional aparece em arvores de decisão. Em cada split, o algoritmo escolhe a feature X que minimiza H(Y|X) -- a feature que remove a maior incerteza sobre o rótulo Y.

Entropia Conjunta

H(X,Y) é a entropia dá distribuição conjunta de X e Y juntos.

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

Propriedade chave:

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

A igualdade vale quando X e Y são independentes. Se elas compartilham informação, a entropia conjunta é menor que a soma das entropias individuais. A entropia "faltante" é exatamente a informação mutua.

graph TD
    subgraph "Information Venn Diagram"
        direction LR
        HX["H(X)"]
        HY["H(Y)"]
        MI["I(X;Y)<br/>Mutual<br/>Information"]
        HXgY["H(X|Y)<br/>= H(X) - I(X;Y)"]
        HYgX["H(Y|X)<br/>= H(Y) - I(X;Y)"]
        HXY["H(X,Y) = H(X) + H(Y) - I(X;Y)"]
    end

    HXgY --- MI
    MI --- HYgX
    HX -.- HXgY
    HX -.- MI
    HY -.- MI
    HY -.- HYgX
    HXY -.- HXgY
    HXY -.- MI
    HXY -.- HYgX

As relações:

  • 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)

Informação Mutua (Mergulho Profundo)

A informação mutua I(X;Y) quantifica quanto conhecer uma variavel reduz a incerteza sobre a outra.

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)))

Propriedades:

  • I(X;Y) >= 0 sempre. Você nunca perde informação ao observar algo.
  • I(X;Y) = 0 se e somente se X e Y são independentes.
  • I(X;Y) = I(Y;X). Ela é simétrica, diferente dá divergência KL.
  • I(X;X) = H(X). Uma variavel compartilha toda a sua informação consigo mesma.

Informação mutua para seleção de features. Em ML, você quer features que sejam informativas sobre o alvo. A informação mutua te dá uma forma fundamentada de ranquear features:

  1. Para cada feature X_i, calcule I(X_i; Y) onde Y é a variavel alvo.
  2. Ranqueie as features pelo score de MI.
  3. Mantenha as top k features.

Isso funciona para qualquer relação entre feature e alvo -- linear, não-linear, monotônica ou não. A correlação só captura relações lineares. A MI captura tudo.

Method Detects Computational cost Handles categorical?
Pearson correlation Relações lineares O(n) Não
Spearman correlation Relações monotônicas O(n log n) Não
Mutual information Qualquer dependência estatística O(n log n) com binning Sim

Label Smoothing e Entropia Cruzada

A classificacao padrão usa alvos rigidos: [0, 0, 1, 0]. A classe verdadeira recebe probabilidade 1, todo o resto recebe 0. O label smoothing substitui esses por alvos suaves:

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

Com epsilon = 0.1 e 4 classes:

  • Hard target: [0, 0, 1, 0]
  • Soft target: [0.025, 0.025, 0.925, 0.025]

De uma perspectiva de teoria dá informação, o label smoothing aumenta a entropia dá distribuição alvo. Alvos one-hot rigidos tem entropia 0 -- não ha incerteza. Alvos suaves tem entropia positiva.

Por que isso ajuda:

  • Impede o modelo de levar os logits a valores extremos (logits infinitos seriam necessarios para corresponder perfeitamente a um alvo one-hot sob entropia cruzada)
  • Atua como regularização: o modelo não pode ter 100% de confiança
  • Melhora a calibração: as probabilidades previstas refletem melhor a incerteza verdadeira
  • Reduz a diferença entre o comportamento de treinamento e de inferencia

A perda de entropia cruzada com label smoothing se torna:

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

O segundo termo penaliza predições que estão longe do uniforme -- uma regularização direta sobre a confiança.

Por que a Entropia Cruzada e A Perda de Classificacao

Três perspectivas, a mesma conclusao.

Visao dá teoria dá informação. A entropia cruzada mede quantos bits você desperdica ao usar a distribuição do seu modelo em vez dá distribuição verdadeira. Minimizá-la torna o seu modelo o codificador mais eficiente dá realidade.

Visao de máxima verossimilhanca. Para N amostras de treinamento com classes verdadeiras y_i:

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

Essa ultima linha é a perda de entropia cruzada. Minimizar a entropia cruzada = maximizar a verossimilhanca dos dados de treinamento sob o seu modelo.

Visao do gradiente. O gradiente dá entropia cruzada em relação aos logits e simplesmente (predicted - true). Limpo, estável é rápido de calcular.É por isso que ela combina perfeitamente com softmax.

Bits vs Nats

A única diferença é a base do log.

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

1 nat = 1/ln(2) bits = 1.4427 bits. PyTorch e TensorFlow usam log natural (nats) por padrão.

Perplexidade

A perplexidade é o exponencial dá entropia cruzada. Ela te diz o número efetivo de escolhas igualmente prováveis entre as quais o modelo está incerto.

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

Um modelo de linguagem com perplexidade 50 está, em média, tao confuso quanto se tivesse que escolher uniformemente entre 50 possíveis próximos tokens. Menor é melhor.

O GPT-2 atingiu perplexidade ~30 em benchmarks comuns. Modelos modernos estão na casa dos dígitos únicos para dominios bem representados.

Construa

Passo 1: Conteudo de informação e entropia

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")

Passo 2: Entropia cruzada e divergência 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")

Passo 3: Entropia cruzada como perda de classificacao

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}")

Passo 4: Entropia cruzada é igual a log-verossimilhanca negativa

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}")

Passo 5: Informação mutua

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")

Use

Os mesmos conceitos usando NumPy, do jeito que você vai usá-los na prática:

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")

Você construiu do zero o que torch.nn.CrossEntropyLoss() faz internamente. Agora você sabe por que a perda cai durante o treinamento: a distribuição prevista do seu modelo está ficando mais próxima dá distribuição verdadeira, medida em nats de informação desperdicada.

Exercícios

  1. Calcule a entropia do alfabeto ingles assumindo distribuição uniforme (26 letras). Depois estime-a usando frequências reais de letras. Qual é maior e por que?

  2. Um modelo gera logits [5.0, 2.0, 0.5] para uma amostra com classe verdadeira 1. Calcule a perda de entropia cruzada à mão, depois verifique com a sua função cross_entropy_loss. Quais logits dariam perda zero?

  3. Mostre que a divergência KL não é simétrica. Escolha duas distribuições P e Q e calcule D_KL(P || Q) e D_KL(Q || P). Explique por que elas diferem.

  4. Construa uma função que calcule a perplexidade para uma sequência de predições de tokens. Dada uma lista de pares (true_token_index, predicted_logits), retorne a perplexidade dá sequência.

Termos-Chave

Term What people say What it actually means
Information content "Surpresa" O número de bits (ou nats) necessarios para codificar um evento: -log(p)
Entropy "Aleatoriedade" A surpresa média ao longo de todos os resultados de uma distribuição. Mede a incerteza irredutivel.
Cross-entropy "A função de perda" Surpresa média ao usar a distribuição do modelo Q para codificar eventos dá distribuição verdadeira P.
KL divergence "Distância entre distribuições" Bits extras desperdicados ao usar Q em vez de P. Igual a entropia cruzada menos entropia. Não simétrica.
Mutual information "Quao relacionados são X e Y" Redução na incerteza sobre X ao conhecer Y. Zero significa independente.
Softmax "Transformar logits em probabilidades" Exponencia e normaliza. Mapeia qualquer vetor de valores reais para uma distribuição de probabilidade valida.
Perplexity "Quao confuso o modelo está" Exponencial dá entropia cruzada. O tamanho efetivo de vocabulário do qual o modelo escolhe a cada passo.
Bits "Unidade de Shannon" Informação medida com log na base 2. Um bit resolve um lancamento de moeda justa.
Nats "Unidade do ML" Informação medida com log natural. Usada por PyTorch e TensorFlow por padrão.
Negative log-likelihood "Perda NLL" Identica a perda de entropia cruzada para rótulos one-hot. Minimizá-la maximiza a probabilidade de predições corretas.

Leitura Adicional

0 lifetime access. Curriculum based on AI Engineering from Scratch by Rohit Ghumare (MIT, used under attribution).