← Voltar pra playlist

Da Perda pro Custo: Somando o Erro de Todo Mundo

A perda logística mede o erro de um exemplo. O curso já define essa distinção: perda (loss) é sobre um exemplo só, custo (cost) é a perda somada (com a média) sobre o conjunto de treino inteiro. É o custo que gradiente descendente minimiza.

A função de custo completa

J(w,b)=1m∑i=0m−1[−y(i)log⁡(fw,b(x(i)))−(1−y(i))log⁡(1−fw,b(x(i)))]J(\mathbf{w},b) = \frac{1}{m}\sum_{i=0}^{m-1}\left[-y^{(i)}\log\left(f_{\mathbf{w},b}(\mathbf{x}^{(i)})\right) - (1-y^{(i)})\log\left(1-f_{\mathbf{w},b}(\mathbf{x}^{(i)})\right)\right]

Parece complicada, mas é só a perda de um exemplo, a mesma fórmula de linha única do lab passado, dentro de um somatório dividido por m. Média da perda de todo mundo.

O código, linha a linha

def compute_cost_logistic(X, y, w, b):
    m = X.shape[0]
    cost = 0.0
    for i in range(m):
        z_i = np.dot(X[i],w) + b
        f_wb_i = sigmoid(z_i)
        cost +=  -y[i]*np.log(f_wb_i) - (1-y[i])*np.log(1-f_wb_i)
    cost = cost / m
    return cost
  • m = X.shape[0]: quantos exemplos tem no conjunto.
  • o for percorre cada paciente i.
  • z_i = np.dot(X[i],w) + b: a parte linear, a mesma combinação de sempre, só que agora X[i] pode ter várias variáveis, então é produto escalar em vez de multiplicação simples.
  • f_wb_i = sigmoid(z_i): espreme pra virar probabilidade.
  • a linha do meio soma a perda desse paciente ao acumulador cost, a mesma fórmula de linha única do lab passado.
  • no fim, cost / m faz a média.

Testando com dois valores de b diferentes

Mesmo dataset de sempre, duas fronteiras candidatas: b=-3 e b=-4 (mantendo w=[1,1] fixo nos dois).

print("Custo com b = -3:", compute_cost_logistic(X_train, y_train, np.array([1,1]), -3))
print("Custo com b = -4:", compute_cost_logistic(X_train, y_train, np.array([1,1]), -4))

Saída: Custo com b = -3: 0.3669 · Custo com b = -4: 0.5037

O custo já denuncia qual fronteira é pior, antes de eu precisar olhar gráfico nenhum. Mas o gráfico confirma:

A linha de b=-4 (tracejada) fica deslocada pra cima e pra direita em relação à de b=-3, e nesse deslocamento ela passa a deixar dois pacientes y=1 do lado errado (abaixo da linha, previstos como 0). Faz sentido o custo dela ser maior: custo alto é literalmente o modelo dizendo "essa fronteira explica pior os dados que eu vi".

Fechando

O que eu já sabiaO que essa aula assentou
Perda mede o erro de um exemploCusto é a média da perda sobre todo o conjunto de treino, é isso que se minimiza
A fórmula da perda logística, de linha únicaO mesmo código, dentro de um for com média no fim, vira a função de custo completa
Uma fronteira pior classifica mais gente erradoO custo mede essa piora numericamente, antes mesmo de eu plotar qualquer gráfico

Aplicação Prática

Uso o modelo real de duas variáveis do lab da fronteira de decisão (worst concave points + worst perimeter, ambas normalizadas), com os pesos w=[2.5494, 4.0739] treinados por gradiente descendente, e comparo o custo do b treinado contra um b deliberadamente pior (deslocado em +2):

print("Custo com b treinado:", compute_cost_logistic(X_train_z, y_train, w, b))
print("Custo com b + 2:", compute_cost_logistic(X_train_z, y_train, w, b + 2))

Saída: Custo com b treinado: 0.1461 · Custo com b + 2: 0.2391

O custo mais que soma um terço a mais só por deslocar a fronteira em duas unidades. E a acurácia sente isso na prática: com o b treinado, acurácia de treino é 0.9319; com o b deslocado, cai pra 0.8989. Um b "quase certo" (a direção da fronteira, dada por w, continua a mesma) já perde 3 pontos percentuais de acurácia, e o custo denuncia exatamente essa piora, do jeito que gradiente descendente enxerga: como um número maior, que ele vai tentar diminuir de novo nos próximos passos.