Sigmoidal
  • Home
  • Pós-Graduação
  • Blog
  • Sobre Mim
  • Contato
Sem Resultado
Ver Todos Resultados
  • English
  • Home
  • Pós-Graduação
  • Blog
  • Sobre Mim
  • Contato
Sem Resultado
Ver Todos Resultados
Sigmoidal
Sem Resultado
Ver Todos Resultados

Binary Cross-Entropy e Regressão Logística do Zero

Carlos Melo por Carlos Melo
junho 1, 2026
em Data Science, Machine Learning, Tutoriais
0
13
VIEWS
Publicar no LinkedInCompartilhar no FacebookCompartilhar no Whatsapp

Existe um único procedimento capaz de gerar toda loss function de Machine Learning. No artigo anterior, nós o aplicamos uma única vez: mostramos que minimizar o MSE equivale a maximizar a verossimilhança sob ruído gaussiano. Hoje vamos aplicá-lo novamente, trocando um único elemento, a distribuição, e ver a binary cross-entropy surgir naturalmente, sem nenhuma escolha arbitrária no caminho.

Este é o terceiro artigo da série Matemática para Machine Learning. No primeiro, construímos a regressão linear f_{w,b}(x) = w x + b; no segundo, derivamos o gradient descent e descobrimos que o MSE é consequência de uma hipótese estatística. Agora atravessamos a fronteira mais importante do curso: sair da regressão, em que y é um número contínuo, e entrar na classificação, em que y é uma resposta binária. A notação segue a convenção padrão da literatura de Machine Learning.

💻

Código do Artigo

Acesse o código-fonte deste artigo gratuitamente.

Informe seu email para acessar o código:

✓ Seu código está pronto!

Abrir no Google Colab →

O procedimento que gera toda loss function

Vale recapitular o final do artigo anterior, porque ele é o motor de tudo o que vem a seguir. Ao assumir que os dados reais são a reta mais um ruído gaussiano, y^{(i)} = f_{w,b}(x^{(i)}) + \varepsilon^{(i)}, a pergunta “qual reta melhor explica os dados?” virou um problema de máxima verossimilhança: encontrar os parâmetros que tornam os dados observados os mais prováveis. Desse raciocínio caiu o MSE, sem que ninguém o escolhesse.

O que fica desse resultado é um procedimento que reutilizaremos integralmente:

  1. Escolher uma distribuição de probabilidade para os dados.
  2. Escrever a verossimilhança como produto sobre os m exemplos.
  3. Aplicar o logaritmo, transformando produto em soma.
  4. Inverter o sinal e chamar o resultado de loss.

Com ruído gaussiano, esse procedimento produz o MSE. A pergunta natural é: o que acontece quando a gaussiana deixa de ser a distribuição certa?

Quando a resposta é sim ou não

Até aqui, y era um número contínuo, como o preço de um imóvel. Mas boa parte dos problemas reais pede outro tipo de resposta. Esse e-mail é spam (y = 1) ou não (y = 0)? Esse tumor é maligno ou benigno? Esse cliente vai cancelar a assinatura ou ficar? Agora y só pode valer 0 ou 1, e não faz sentido um modelo produzir 73{,}4. O que queremos prever é a probabilidade de a resposta ser 1.

A tentação é reaproveitar a regressão linear com um corte: “se wx + b passar de 0{,}5, digo que é classe 1″. Isso falha por duas razões. Primeiro, a reta produz qualquer valor de -\infty a +\infty, e probabilidade precisa viver entre 0 e 1. Segundo, um único ponto muito distante, um outlier, entorta a reta inteira e desloca a fronteira de decisão. Precisamos de algo que comprima a saída linear para dentro do intervalo (0, 1).

No notebook, geramos um dataset sintético com duas features e duas classes parcialmente sobrepostas, o cenário que acompanha todo o artigo:

Dataset sintético de classificação binária com duas nuvens gaussianas parcialmente sobrepostas

O compressor: a função sigmoid

A solução é compor a saída linear de sempre, z = w^\top x + b, com uma função que comprime a reta real inteira no intervalo (0, 1). Essa função é a sigmoid:

    \[\sigma(z) = \frac{1}{1 + e^{-z}}\]

O comportamento dela nos extremos e no centro conta a história completa:

def sigmoid(z):
    """Comprime qualquer número real para o intervalo (0, 1)."""
    return 1.0 / (1.0 + np.exp(-z))

for z in [-10, -2, 0, 2, 10]:
    print(f"sigmoid({z:+3d}) = {sigmoid(z):.4f}")
sigmoid(-10) = 0.0000
sigmoid( -2) = 0.1192
sigmoid( +0) = 0.5000
sigmoid( +2) = 0.8808
sigmoid(+10) = 1.0000

A sigmoid funciona como um interruptor suave. Bem à esquerda, ela diz “quase certeza de que é classe 0”; bem à direita, “quase certeza de que é classe 1”; e em z = 0 ela fica exatamente em cima do muro, \sigma(0) = 0{,}5. Esse ponto de indecisão é a fronteira de decisão, e vamos visualizá-la ao final.

Curva da função sigmoid com a fronteira de decisão marcada em z igual a zero

O modelo de classificação fica, então, \hat{p} = \sigma(w^\top x + b) = P(y = 1 \mid x; w, b). A saída deixou de ser um número qualquer e passou a ser a probabilidade de a classe ser 1. E como só existem duas classes, P(y = 0 \mid x; w, b) = 1 - \hat{p}.

Bernoulli: a distribuição certa para sim ou não

Com o modelo pronto, voltamos ao procedimento. O passo um pede uma distribuição para os dados, como as que exploramos em distribuições estatísticas com Python, e uma variável que só assume 0 ou 1 segue uma distribuição de Bernoulli. Ela tem uma forma de escrita elegante, que junta os dois casos em uma fórmula única:

    \[p(y \mid x; w, b) = \hat{p}^{\,y} \, (1 - \hat{p})^{\,1-y}\]

A fórmula parece um artifício engenhoso, mas é apenas um liga-desliga com expoentes. Se y = 1, o segundo fator vira (1-\hat{p})^0 = 1 e sobra \hat{p}, a probabilidade de ser classe 1. Se y = 0, o primeiro fator desliga e sobra 1 - \hat{p}. Uma fórmula única para os dois casos, e é exatamente essa compactação que fará o logaritmo do próximo passo funcionar tão bem.

Aplicando o procedimento: nasce a binary cross-entropy

Agora é execução. A verossimilhança é o produto sobre os exemplos, assumindo independência:

    \[L(w, b) = \prod_{i=1}^{m} \hat{p}^{(i)\, y^{(i)}} \big(1 - \hat{p}^{(i)}\big)^{1 - y^{(i)}}, \qquad \hat{p}^{(i)} = \sigma\big(w^\top x^{(i)} + b\big)\]

O logaritmo transforma o produto em soma e derruba os expoentes, usando \log(ab) = \log a + \log b e \log(a^c) = c \log a:

    \[\log L(w, b) = \sum_{i=1}^{m} \Big[\, y^{(i)} \log \hat{p}^{(i)} + \big(1 - y^{(i)}\big) \log\big(1 - \hat{p}^{(i)}\big) \Big]\]

Por fim, invertemos o sinal, porque maximizar a verossimilhança é minimizar o negativo dela, e dividimos por m para virar uma média:

    \[J(w, b) = -\frac{1}{m} \sum_{i=1}^{m} \Big[\, y^{(i)} \log \hat{p}^{(i)} + \big(1 - y^{(i)}\big) \log\big(1 - \hat{p}^{(i)}\big) \Big]\]

Essa é a famosa binary cross-entropy (em português, entropia cruzada binária). Repare no que acabou de acontecer: ela não caiu do céu nem foi escolhida por conveniência. É o mesmo procedimento que gerou o MSE, com a única diferença de que trocamos “ruído gaussiano” por “distribuição de Bernoulli”. A loss mudou de forma porque a distribuição dos dados mudou. Mais nada.

Por que essa loss faz sentido

A fórmula intimida à primeira vista, mas o comportamento dela é muito intuitivo. Por causa do liga-desliga da Bernoulli, para cada exemplo sobra apenas um dos dois termos. Quando a resposta certa é y = 1, sobra -\log \hat{p}: se o modelo acertou com confiança (\hat{p} \to 1), a loss vai a zero; se errou gravemente (\hat{p} \to 0), a loss dispara para o infinito. Quando y = 0, sobra -\log(1 - \hat{p}), com o comportamento espelhado. A implementação é uma tradução direta da fórmula, com um detalhe numérico: o clip impede o \log(0), que explodiria para infinito.

def bce(y, p_hat, eps=1e-12):
    """Binary cross-entropy média (a cost da classificação)."""
    p_hat = np.clip(p_hat, eps, 1 - eps)
    return -np.mean(y * np.log(p_hat) + (1 - y) * np.log(1 - p_hat))

print(f"acertou com confiança (y=1, p=0.99): loss = {bce(np.array([1.0]), np.array([0.99])):.4f}")
print(f"em cima do muro     (y=1, p=0.50): loss = {bce(np.array([1.0]), np.array([0.50])):.4f}")
print(f"errou com confiança (y=0, p=0.99): loss = {bce(np.array([0.0]), np.array([0.99])):.4f}")
acertou com confiança (y=1, p=0.99): loss = 0.0101
em cima do muro     (y=1, p=0.50): loss = 0.6931
errou com confiança (y=0, p=0.99): loss = 4.6052

O acerto confiante custa quase nada. A previsão neutra de 50\% custa 0{,}6931, que é exatamente \log 2. E o erro confiante custa 4{,}6, quase sete vezes o valor do muro. A cross-entropy pune confiança errada de forma brutal: se o modelo diz “tenho 99% de certeza de que é classe 1” e a resposta era 0, a loss explode. É a função de custo dizendo que errar com convicção é imperdoável, enquanto o erro tímido é punido de leve. Isso leva o modelo a só ficar confiante quando há motivo.

Curvas de menos log da probabilidade mostrando a punição crescente da cross-entropy

Treinando e enxergando a fronteira de decisão

Falta treinar. O gradiente da BCE em relação aos parâmetros tem uma propriedade notável: apesar de a fórmula da loss ser completamente diferente da do MSE, a regra de atualização sai com exatamente a mesma forma da regressão linear, erro vezes entrada:

    \[\frac{\partial J}{\partial w} = \frac{1}{m} \sum_{i=1}^{m} \big(\hat{p}^{(i)} - y^{(i)}\big)\, x^{(i)}, \qquad \frac{\partial J}{\partial b} = \frac{1}{m} \sum_{i=1}^{m} \big(\hat{p}^{(i)} - y^{(i)}\big)\]

A derivação passo a passo dessas fórmulas, que envolve uma simplificação elegante da derivada da sigmoid, fica para o próximo artigo da série. Por ora, vamos usá-las com o mesmo gradient descent de sempre. O modelo é a sigmoid da saída linear, o gradiente traduz as fórmulas acima, e o laço de treinamento é idêntico ao da regressão linear:

def modelo(X, w, b):
    """Probabilidade prevista para a classe 1: sigmoid da saída linear."""
    return sigmoid(X @ w + b)

def gradiente(X, y, w, b):
    """Derivadas parciais da BCE: a forma 'erro vezes entrada'."""
    erro = modelo(X, w, b) - y
    dw = X.T @ erro / len(y)
    db = np.mean(erro)
    return dw, db

def gradient_descent(X, y, w, b, alpha, n_iter):
    """Treina a regressão logística, retornando parâmetros e histórico da cost."""
    historico = []
    for _ in range(n_iter):
        dw, db = gradiente(X, y, w, b)
        w = w - alpha * dw      # atualização simultânea
        b = b - alpha * db
        historico.append(bce(y, modelo(X, w, b)))
    return w, b, historico

w, b, historico = gradient_descent(X, y, w=np.zeros(2), b=0.0, alpha=0.1, n_iter=3000)
BCE em w=0, b=0 (previsão neutra de 50%): 0.6931
w treinado = [1.610, 1.167]
b treinado = -7.924
BCE final = 0.0941
acurácia    = 0.965

Repare no ponto de partida. Com w = 0 e b = 0, a saída linear é zero para todo exemplo, a sigmoid devolve 0{,}5 para todos, e a cost é exatamente o \log 2 = 0{,}6931 do “em cima do muro” que medimos há pouco: o modelo não treinado é uma previsão neutra de 50\%. O gradient descent derrubou essa cost para 0{,}0941, e o modelo passou a classificar corretamente 96{,}5\% dos exemplos. O modelo prevê classe 1 quando \hat{p} \geq 0{,}5, o que acontece exatamente quando w^\top x + b \geq 0. A fronteira de decisão é, portanto, a reta w^\top x + b = 0, e podemos enxergá-la junto com a probabilidade prevista em cada região do plano:

Fronteira de decisão da regressão logística com o mapa de probabilidades previsto em cada região

A linha preta é o “em cima do muro” da sigmoid, os pontos em que o modelo atribui 50\% para cada classe. Longe dela, nas regiões de azul ou vermelho intensos, o modelo está confiante, e a cross-entropy garantiu durante o treinamento que essa confiança só aparecesse onde os dados a sustentam. Esse modelo tem nome: regressão logística, criado há mais de meio século e até hoje o primeiro classificador a ser treinado em qualquer problema sério.

A lição que vale para o resto do curso é a mesma do artigo anterior, agora confirmada duas vezes: toda loss function é uma escolha de distribuição de probabilidade disfarçada. Sempre que você encontrar uma loss nova, a pergunta certa é “que distribuição essa loss assume sobre os dados?”. Existe uma resposta. Sempre há uma.

Takeaways

  • Um único procedimento gera toda loss function: escolher a distribuição dos dados, escrever a verossimilhança, aplicar o logaritmo e inverter o sinal. Gaussiana gera o MSE; Bernoulli gera a cross-entropy.
  • A sigmoid transforma a saída linear em probabilidade, comprimindo (-\infty, +\infty) no intervalo (0, 1), com a fronteira de decisão exatamente em \sigma(0) = 0{,}5.
  • A cross-entropy pune a confiança errada de forma brutal: no experimento, o erro confiante custou 4{,}6052, contra 0{,}0101 do acerto confiante, empurrando o modelo a calibrar a própria certeza.
  • O gradiente mantém a forma “erro vezes entrada” da regressão linear, e com ele a regressão logística atingiu 96{,}5\% de acurácia, desenhando uma fronteira de decisão linear no plano.
CompartilharCompartilharEnviar
Post Anterior

Gradient Descent e Loss Function: a Origem do MSE

Próximo Post

Pipelines no Scikit-Learn: Transformações sem Data Leakage

Carlos Melo

Carlos Melo

Engenheiro de Visão Computacional graduado em Ciências Aeronáuticas pela Academia da Força Aérea (AFA) e Mestre em Engenharia Aeroespacial pelo Instituto Tecnológico de Aeronáutica (ITA).

Relacionado Artigos

Machine Learning

Pipelines no Scikit-Learn: Transformações sem Data Leakage

por Carlos Melo
julho 6, 2026
Gradient Descent e Loss Function: a Origem do MSE
Data Science

Gradient Descent e Loss Function: a Origem do MSE

por Carlos Melo
maio 27, 2026
Regressão Linear e Aprendizado Supervisionado
Data Science

Regressão Linear e Aprendizado Supervisionado

por Carlos Melo
maio 26, 2026
Introdução ao Pandas: capa do guia prático para análise de dados com Python
Data Science

Introdução ao Pandas: Guia Prático para Análise de Dados

por Carlos Melo
abril 27, 2026
Carreira

Como Aprender Matemática para Machine Learning

por Carlos Melo
abril 23, 2026
Próximo Post

Pipelines no Scikit-Learn: Transformações sem Data Leakage

Deixe um comentário Cancelar resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Pós em Visão Computacional Pós em Visão Computacional Pós em Visão Computacional

Mais Populares

  • Cientista de Dados: Salário em 2026 (Júnior, Pleno e Sênior)

    89 compartilhamentos
    Compartilhar 36 Tweet 22
  • ORB-SLAM 3: Tutorial Completo para Mapeamento 3D e Localização em Tempo Real

    479 compartilhamentos
    Compartilhar 192 Tweet 120
  • Geometria da Formação de Imagens: Matrizes, Transformações e Sistemas de Coordenadas

    437 compartilhamentos
    Compartilhar 175 Tweet 109
  • 6 Livros de Visão Computacional e Deep Learning

    25 compartilhamentos
    Compartilhar 10 Tweet 6
  • Introdução ao MediaPipe e Pose Estimation

    569 compartilhamentos
    Compartilhar 228 Tweet 142
  • Em Alta
  • Comentários
  • Mais Recente
Como Tratar Dados Ausentes com Pandas

Como Tratar Dados Ausentes com Pandas

agosto 13, 2019
Introdução ao MediaPipe e Pose Estimation

Introdução ao MediaPipe e Pose Estimation

julho 15, 2023
Como usar o DALL-E 2 para gerar imagens a partir de textos

Como usar o DALL-E 2 para gerar imagens a partir de textos

dezembro 25, 2022

ORB-SLAM 3: Tutorial Completo para Mapeamento 3D e Localização em Tempo Real

abril 10, 2023
Como Analisar Ações da Bolsa com Python

Como Analisar Ações da Bolsa com Python

15
Setembro Amarelo: Análise do Suicídio no Brasil, com Data Science

Setembro Amarelo: Análise do Suicídio no Brasil, com Data Science

13
Como Aprender Data Science?

Como Aprender Data Science?

9
Qual o Cenário de Data Science no Brasil hoje?

Qual o Cenário de Data Science no Brasil hoje?

8

Pipelines no Scikit-Learn: Transformações sem Data Leakage

julho 6, 2026

Binary Cross-Entropy e Regressão Logística do Zero

junho 1, 2026
Gradient Descent e Loss Function: a Origem do MSE

Gradient Descent e Loss Function: a Origem do MSE

maio 27, 2026
Regressão Linear e Aprendizado Supervisionado

Regressão Linear e Aprendizado Supervisionado

maio 26, 2026
Instagram Youtube LinkedIn Twitter
Sigmoidal

O melhor conteúdo técnico de Data Science, com projetos práticos e exemplos do mundo real.

Seguir no Instagram

Categorias

  • Aeroespacial
  • Artigos
  • Blog
  • Carreira
  • Cursos
  • Data Science
  • Deep Learning
  • Destaques
  • Entrevistas
  • IA Generativa
  • Livros
  • Machine Learning
  • Notícias
  • Python
  • Teoria
  • Tutoriais
  • Visão Computacional
  • Youtube

Navegar por Tags

algebra-linear camera calibration carreira chatgpt cientista de dados cnn computer vision Cursos dados desbalanceados data science data science na prática decision tree deep learning deploy gpt-3 gradient descent IA generativa inteligência artificial jupyter kaggle keras livros machine learning matplotlib nft openai opencv pandas profissão python pytorch reconstrução 3d redes neurais redes neurais convolucionais regressão linear regressão logística salário scikit-learn sklearn tensorflow tutorial visão computacional vídeo youtube árvore de decisão

© 2024 Sigmoidal - Aprenda Data Science, Visão Computacional e Python na prática.

Welcome Back!

Login to your account below

Forgotten Password?

Retrieve your password

Please enter your username or email address to reset your password.

Log In

Add New Playlist

Sem Resultado
Ver Todos Resultados
  • Home
  • Pós-Graduação
  • Blog
  • Sobre Mim
  • Contato
  • English

© 2024 Sigmoidal - Aprenda Data Science, Visão Computacional e Python na prática.