Phase 01 - Lesson 06

Probabilidade e Distribuições

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

Probabilidade é a linguagem que a IA usa para expressar incerteza.

Tipo: Learn Linguagem: Python Pré-requisitos: Fase 1, Lições 01-04 Tempo: ~75 minutos

Objetivos de Aprendizagem

  • Implementar PMFs e PDFs do zero para as distribuições de Bernoulli, categórica, Poisson, uniforme e normal
  • Calcular o valor esperado, a variância e usar o Teorema Central do Limite para explicar por que as Gaussianas dominam
  • Construir as funções softmax e log-softmax com o truque de estabilidade numérica (subtrair o logit máximo)
  • Calcular a perda de entropia cruzada a partir de logits e conectá-la a log-verossimilhança negativa

O Problema

Um classificador retorna [0.03, 0.91, 0.06]. Um modelo de linguagem escolhe a próxima palavra entre 50.000 candidatas. Um modelo de difusão gera imagens amostrando de distribuições aprendidas. Tudo isso é probabilidade em ação.

Toda previsão que um modelo faz é uma distribuição de probabilidade. Toda função de perda mede o quão distante a distribuição prevista está da verdadeira. Todo passo de treinamento ajusta parâmetros para fazer uma distribuição se parecer mais com outra. Sem probabilidade, você não consegue ler um único artigo de ML, depurar um único modelo ou entender por que sua perda de treinamento é NaN.

O Conceito

Eventos, Espaços Amostrais e Probabilidade

O espaço amostral S é o conjunto de todos os resultados possíveis. Um evento é um subconjunto do espaço amostral. A probabilidade mapeia eventos para números entre 0 e 1.

Lancamento de moeda:
  S = {H, T}
  P(H) = 0.5,  P(T) = 0.5

Lancamento de um dado:
  S = {1, 2, 3, 4, 5, 6}
  P(par) = P({2, 4, 6}) = 3/6 = 0.5

Tres axiomas definem toda a probabilidade:

  1. P(A) >= 0 para qualquer evento A
  2. P(S) = 1 (algo sempre acontece)
  3. P(A ou B) = P(A) + P(B) quando A e B não podem ocorrer juntos

Todo o resto (teorema de Bayes, esperancas, distribuições) decorre dessas três regras.

Probabilidade Condicional e Independência

P(A|B) é a probabilidade de A dado que B aconteceu.

P(A|B) = P(A e B) / P(B)

Exemplo: baralho de cartas
  P(Rei | Carta de figura) = P(Rei e Carta de figura) / P(Carta de figura)
                      = (4/52) / (12/52)
                      = 4/12 = 1/3

Dois eventos são independentes quando saber um não diz nada sobre o outro:

Independente:   P(A|B) = P(A)
Equivalente a: P(A e B) = P(A) * P(B)

Lançamentos de moeda são independentes. Tirar cartas sem reposição não é.

Funções de Massa de Probabilidade vs Funções de Densidade de Probabilidade

Variáveis aleatórias discretas têm uma função de massa de probabilidade (PMF). Cada resultado tem uma probabilidade específica que você pode ler diretamente.

PMF: P(X = k)

Dado justo:
  P(X = 1) = 1/6
  P(X = 2) = 1/6
  ...
  P(X = 6) = 1/6

  Soma de todas as probabilidades = 1

Variáveis aleatórias contínuas têm uma função de densidade de probabilidade (PDF). A densidade em um único ponto não é uma probabilidade. A probabilidade vem de integrar a densidade ao longo de um intervalo.

PDF: f(x)

P(a <= X <= b) = integral de f(x) de a ate b

f(x) pode ser maior que 1 (densidade, nao probabilidade)
integral de -inf a +inf de f(x) dx = 1

Essa distincao importa em ML. Saídas de classificação são PMFs (escolhas discretas). Espaços latentes de VAE usam PDFs (contínuos).

Distribuições Comuns

Bernoulli: um ensaio, dois resultados. Modela classificação binária.

P(X = 1) = p
P(X = 0) = 1 - p
Media = p,  Variancia = p(1-p)

Categórica: um ensaio, k resultados. Modela classificação multiclasse (saída softmax).

P(X = i) = p_i,  onde a soma de p_i = 1
Exemplo: P(gato) = 0.7,  P(cachorro) = 0.2,  P(passaro) = 0.1

Uniforme: todos os resultados igualmente prováveis. Usada para inicialização aleatória.

Discreta: P(X = k) = 1/n para k em {1, ..., n}
Continua: f(x) = 1/(b-a) para x em [a, b]

Normal (Gaussiana): a curva em sino. Parametrizada pela média (mu) e variância (sigma^2).

f(x) = (1 / sqrt(2*pi*sigma^2)) * exp(-(x - mu)^2 / (2*sigma^2))

Normal padrao: mu = 0, sigma = 1
  68% dos dados dentro de 1 sigma
  95% dentro de 2 sigma
  99.7% dentro de 3 sigma

Poisson: contagens de eventos raros em um intervalo fixo. Modela taxas de eventos.

P(X = k) = (lambda^k * e^(-lambda)) / k!
Media = lambda,  Variancia = lambda

Valor Esperado e Variância

O valor esperado é a média ponderada dos resultados.

Discreta:   E[X] = soma de x_i * P(X = x_i)
Continua: E[X] = integral de x * f(x) dx

A variância mede a dispersão em torno da média.

Var(X) = E[(X - E[X])^2] = E[X^2] - (E[X])^2
Desvio padrao = sqrt(Var(X))

Em ML, o valor esperado aparece como a função de perda (perda média sobre a distribuição dos dados). A variância te informa sobre a estabilidade do modelo. Variância alta nos gradientes significa treinamento ruidoso.

Distribuições Conjuntas e Marginais

Uma distribuição conjunta P(X, Y) descreve duas variáveis aleatórias em conjunto.

Exemplo de PMF conjunta (X = clima, Y = guarda-chuva):

Y=0 (sem guarda-chuva) Y=1 (com guarda-chuva) Marginal P(X)
X=0 (sol) 0.40 0.10 P(X=0) = 0.50
X=1 (chuva) 0.05 0.45 P(X=1) = 0.50
Marginal P(Y) P(Y=0) = 0.45 P(Y=1) = 0.55 1.00

A distribuição marginal soma a outra variável:

P(X = x) = soma sobre todo y de P(X = x, Y = y)

Os totais de linha e coluna na tabela acima são as marginais.

Por que a Distribuição Normal Aparece em Todo Lugar

O Teorema Central do Limite: a soma (ou média) de muitas variáveis aleatórias independentes converge para uma distribuição normal, independentemente da distribuição original.

Lance 1 dado:  distribuicao uniforme (plana)
Media de 2 dados:  triangular (com pico)
Media de 30 dados: curva em sino quase perfeita

Isso funciona para QUALQUER distribuicao inicial.

É por isso que:

  • Erros de medição são aproximadamente normais (muitas fontes pequenas e independentes)
  • Inicializações de pesos em redes neurais usam distribuições normais
  • O ruído do gradiente no SGD é aproximadamente normal (soma de muitos gradientes de amostra)
  • A distribuição normal é a distribuição de máxima entropia para uma dada média e variância

Log-Probabilidades

Probabilidades brutas causam problemas numéricos. Multiplicar muitas probabilidades pequenas juntas rapidamente sofre underflow para zero.

P(frase) = P(palavra1) * P(palavra2) * ... * P(palavra_n)
            = 0.01 * 0.003 * 0.02 * ...
            -> 0.0 (underflow apos ~30 termos)

As log-probabilidades resolvem isso. As multiplicacoes viram somas.

log P(frase) = log P(palavra1) + log P(palavra2) + ... + log P(palavra_n)
                = -4.6 + -5.8 + -3.9 + ...
                -> numero finito (sem underflow)

Regras:

  • log(a * b) = log(a) + log(b)
  • log-probabilidades são sempre <= 0 (já que 0 < P <= 1)
  • Mais negativo = menos provável
  • A perda de entropia cruzada é a log-probabilidade negativa da classe correta

Softmax como Distribuição de Probabilidade

Redes neurais retornam scores brutos (logits). O softmax os converte em uma distribuição de probabilidade valida.

softmax(z_i) = exp(z_i) / sum(exp(z_j) para todo j)

Propriedades:
  - Todas as saidas estao em (0, 1)
  - Todas as saidas somam 1
  - Preserva a ordenacao relativa das entradas
  - exp() amplifica diferencas entre logits

O truque do softmax: subtraia o logit máximo antes de exponenciar para evitar overflow.

z = [100, 101, 102]
exp(102) = overflow

z_shifted = z - max(z) = [-2, -1, 0]
exp(0) = 1  (seguro)

Mesmo resultado, sem overflow.

O log-softmax combina softmax e log para estabilidade numérica. O PyTorch usa isso internamente para a perda de entropia cruzada.

Amostragem

Amostragem significa tirar valores aleatórios de uma distribuição. Em ML:

  • O dropout amostra aleatoriamente quais neurônios zerar
  • A aumentacao de dados amostra transformações aleatórias
  • Modelos de linguagem amostram o próximo token da distribuição prevista
  • Modelos de difusão amostram ruído e o removem progressivamente

Amostrar de distribuições arbitrárias requer técnicas como amostragem por transformada inversa, amostragem por rejeição ou o truque de reparametrização (usado em VAEs).

Construa

Passo 1: Fundamentos de probabilidade

import math
import random

def factorial(n):
    result = 1
    for i in range(2, n + 1):
        result *= i
    return result

def combinations(n, k):
    return factorial(n) // (factorial(k) * factorial(n - k))

def conditional_probability(p_a_and_b, p_b):
    return p_a_and_b / p_b

p_king_given_face = conditional_probability(4/52, 12/52)
print(f"P(King | Face card) = {p_king_given_face:.4f}")

Passo 2: PMF e PDF do zero

def bernoulli_pmf(k, p):
    return p if k == 1 else (1 - p)

def categorical_pmf(k, probs):
    return probs[k]

def poisson_pmf(k, lam):
    return (lam ** k) * math.exp(-lam) / factorial(k)

def uniform_pdf(x, a, b):
    if a <= x <= b:
        return 1.0 / (b - a)
    return 0.0

def normal_pdf(x, mu, sigma):
    coeff = 1.0 / (sigma * math.sqrt(2 * math.pi))
    exponent = -0.5 * ((x - mu) / sigma) ** 2
    return coeff * math.exp(exponent)

Passo 3: Valor esperado e variância

def expected_value(values, probabilities):
    return sum(v * p for v, p in zip(values, probabilities))

def variance(values, probabilities):
    mu = expected_value(values, probabilities)
    return sum(p * (v - mu) ** 2 for v, p in zip(values, probabilities))

die_values = [1, 2, 3, 4, 5, 6]
die_probs = [1/6] * 6
mu = expected_value(die_values, die_probs)
var = variance(die_values, die_probs)
print(f"Die: E[X] = {mu:.4f}, Var(X) = {var:.4f}, SD = {var**0.5:.4f}")

Passo 4: Amostragem de distribuições

def sample_bernoulli(p, n=1):
    return [1 if random.random() < p else 0 for _ in range(n)]

def sample_categorical(probs, n=1):
    cumulative = []
    total = 0
    for p in probs:
        total += p
        cumulative.append(total)
    samples = []
    for _ in range(n):
        r = random.random()
        for i, c in enumerate(cumulative):
            if r <= c:
                samples.append(i)
                break
    return samples

def sample_normal_box_muller(mu, sigma, n=1):
    samples = []
    for _ in range(n):
        u1 = random.random()
        u2 = random.random()
        z = math.sqrt(-2 * math.log(u1)) * math.cos(2 * math.pi * u2)
        samples.append(mu + sigma * z)
    return samples

Passo 5: Softmax e log-probabilidades

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

def log_softmax(logits):
    max_logit = max(logits)
    shifted = [z - max_logit for z in logits]
    log_sum_exp = max_logit + math.log(sum(math.exp(z) for z in shifted))
    return [z - log_sum_exp for z in logits]

def cross_entropy_loss(logits, target_index):
    log_probs = log_softmax(logits)
    return -log_probs[target_index]

Passo 6: Demonstração do Teorema Central do Limite

def demonstrate_clt(dist_fn, n_samples, n_averages):
    averages = []
    for _ in range(n_averages):
        samples = [dist_fn() for _ in range(n_samples)]
        averages.append(sum(samples) / len(samples))
    return averages

Passo 7: Visualização

import matplotlib.pyplot as plt

xs = [mu + sigma * (i - 500) / 100 for i in range(1001)]
ys = [normal_pdf(x, mu, sigma) for x, mu, sigma in ...]
plt.plot(xs, ys)

As implementações completas com todas as visualizações estão em code/probability.py.

Use

Com NumPy e SciPy, tudo acima vira uma linha só:

import numpy as np
from scipy import stats

normal = stats.norm(loc=0, scale=1)
samples = normal.rvs(size=10000)
print(f"Mean: {np.mean(samples):.4f}, Std: {np.std(samples):.4f}")
print(f"P(X < 1.96) = {normal.cdf(1.96):.4f}")

logits = np.array([2.0, 1.0, 0.1])
from scipy.special import softmax, log_softmax
probs = softmax(logits)
log_probs = log_softmax(logits)
print(f"Softmax: {probs}")
print(f"Log-softmax: {log_probs}")

Você construiu tudo isso do zero. Agora você sabe o que as chamadas da biblioteca estão fazendo.

Exercícios

  1. Implemente a amostragem por transformada inversa para a distribuição exponencial. Verifique amostrando 10.000 valores e comparando o histograma com a PDF verdadeira.

  2. Construa uma tabela de distribuição conjunta para dois dados viciados. Calcule as distribuições marginais e verifique se os dados são independentes.

  3. Calcule a perda de entropia cruzada para um classificador de 5 classes que retorna os logits [2.0, 0.5, -1.0, 3.0, 0.1] quando a classe correta é o índice 3. Depois verifique sua resposta com o nn.CrossEntropyLoss do PyTorch.

  4. Escreva uma função que recebe uma lista de log-probabilidades e retorna a sequência mais provável, a log-probabilidade total e a probabilidade bruta equivalente. Teste-a com uma frase de 50 palavras onde cada palavra tem probabilidade 0.01.

Termos-Chave

Termo O que as pessoas dizem O que realmente significa
Espaço amostral "Todas as possibilidades" O conjunto S de todo resultado possível de um experimento
PMF "A função de probabilidade" Uma função que dá a probabilidade exata de cada resultado discreto, somando 1
PDF "A curva de probabilidade" Uma função de densidade para variáveis contínuas. Integre-a sobre um intervalo para obter a probabilidade
Probabilidade condicional "Probabilidade dado algo" P(A|B) = P(A e B) / P(B). A base do raciocínio bayesiano e do teorema de Bayes
Independência "Não se afetam mutuamente" P(A e B) = P(A) * P(B). Saber um evento não diz nada sobre o outro
Valor esperado "A média" A soma ponderada por probabilidade de todos os resultados. A função de perda é um valor esperado
Variância "O quão disperso" O desvio quadrático esperado em relação à média. Variância alta = estimativas ruidosas e instáveis
Distribuição normal "A curva em sino" f(x) = (1/sqrt(2pisigma^2)) * exp(-(x-mu)^2/(2*sigma^2)). Aparece em todo lugar por causa do TCL
Teorema Central do Limite "Médias viram normais" A média de muitas amostras independentes converge para uma distribuição normal independentemente da fonte
Distribuição conjunta "Duas variáveis juntas" P(X, Y) descreve a probabilidade de cada combinação de resultados de X e Y
Distribuição marginal "Some a outra variável" P(X) = soma_y P(X, Y). Recupera a distribuição de uma variável a partir da conjunta
Log-probabilidade "Log dá a probabilidade" log P(x). Transforma produtos em somas, evitando o underflow numérico em sequências longas
Softmax "Transforma scores em probabilidades" softmax(z_i) = exp(z_i) / sum(exp(z_j)). Mapeia logits de valor real para uma distribuição de probabilidade valida
Entropia cruzada "A função de perda" -sum(p_true * log(p_predicted)). Mede o quão diferentes são duas distribuições. Menor e melhor
Logits "Saídas brutas do modelo" Scores não normalizados antes do softmax. Nomeado em referência a função logística
Amostragem "Tirar valores aleatórios" Gerar valores conformé uma distribuição de probabilidade. Como os modelos geram saída

Leitura Adicional

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