De onde vem uma função de perda: verossimilhança, não convenção
Três linhas sobre as mesmas 20 medições e três regras de pontuação elegem vencedores diferentes. Erro quadrático é uma escolha.
Nesta página
A lâmina que corta as peças se desgasta. Ao longo de um turno de dez horas, ela perde fio o bastante para que as peças saiam da esteira uma fração de milímetro mais largas do que começaram; quando passam de 23,5 milímetros, a inspeção as rejeita. Ninguém na fábrica sabe quando isso acontece. O que eles têm é um paquímetro, um caderno e vinte leituras da terça-feira passada: as horas desde que a lâmina foi trocada e a largura da peça medida naquele momento.
Alguém traça uma linha pelos pontos. Outra pessoa traça uma ligeiramente diferente. Uma terceira pessoa traça uma terceira. As três parecem razoáveis no papel, e discordam em várias horas sobre quando trocar a lâmina — nesta fábrica, a diferença entre uma semana tranquila e um lote descartado.
Qual linha é melhor?
Do jeito que foi feita, essa pergunta não tem resposta. Não uma resposta difícil — resposta nenhuma. “Melhor” não é uma propriedade de uma linha como sua inclinação é; é uma propriedade de uma linha junto com uma regra para pontuar linhas, e, até alguém escrever a regra, não há nada a calcular. Este capítulo leva essa frase a sério e termina com a descoberta de que a regra mais comum em machine learning não é uma convenção, mas a consequência de uma afirmação sobre o mundo — uma que você pode testar, e uma que às vezes é falsa.
Uma confissão antes da primeira linha de código. Essas vinte leituras não vêm de uma fábrica real: eu as gerei a partir de uma linha que escolhi, , mais ruído aleatório com uma dispersão de cerca de um décimo de milímetro. Isso importa, porque tudo abaixo trata de saber se um método recupera uma verdade, e a única maneira de verificar isso é conhecer a verdade de antemão. Então: 0,30 milímetro por hora é a resposta no fim do livro. Você não pode usá-la, apenas conferir contra ela.
Três regras, três vencedores
Link para a seção: Três regras, três vencedoresAqui estão as leituras e as três linhas, pontuadas de três maneiras: erro quadrático, que é o que todo mundo pega primeiro; erro absoluto, que um estatístico talvez pegasse; e pior erro, que o operador da máquina pegaria, porque o inspetor não se importa com a sua média — ele rejeita a peça individual que está fora da tolerância.
NumPy aparece aqui, um capítulo depois do perceptron em Python puro, por um motivo: até o fim deste capítulo, avaliamos quatrocentas mil linhas candidatas contra vinte leituras cada, e um loop em Python é a ferramenta errada para isso. Também é a notação em que toda fonte citada abaixo está escrita.
import numpy as np
# Hours since the blade was changed, and the width of the part measured then.
SHIFT = np.array([
(0.5, 20.17), (1.0, 20.28), (1.5, 20.53), (2.0, 20.61), (2.5, 20.69),
(3.0, 20.94), (3.5, 21.21), (4.0, 21.31), (4.5, 21.27), (5.0, 21.35),
(5.5, 21.58), (6.0, 21.80), (6.5, 21.67), (7.0, 22.07), (7.5, 22.10),
(8.0, 22.31), (8.5, 22.48), (9.0, 22.66), (9.5, 22.90), (10.0, 23.13),
])
h, y = SHIFT[:, 0], SHIFT[:, 1]
LINES = {"A": (20.10, 0.26), "B": (20.20, 0.28), "C": (20.30, 0.26)}
for name, (a, b) in LINES.items():
r = y - (a + b * h)
print(f"{name} mean square {np.mean(r**2):.5f}"
f" mean absolute {np.mean(np.abs(r)):.5f}"
f" worst {np.max(np.abs(r)):.3f}") A quantidade nas linhas destacadas é o resíduo: o que a linha disse menos o que o paquímetro disse, um número por leitura. Toda regra de pontuação neste capítulo, e toda função de perda nos vinte e oito capítulos seguintes, é alguma forma de espremer uma lista de resíduos até um único número. Elas diferem apenas em como espremem.
A mean square 0.02699 mean absolute 0.12600 worst 0.430
B mean square 0.02524 mean absolute 0.13700 worst 0.350
C mean square 0.03179 mean absolute 0.15000 worst 0.320Leia as colunas, não as linhas. O erro quadrático diz B, o erro absoluto diz A, o pior erro diz C: três regras, três vencedores, nos mesmos vinte pontos.
Escolhi essas três linhas para que elas discordassem, e devo dizer isso claramente. O ponto é como foi fácil — alguns minutos buscando interceptos e inclinações com aparência sensata revelam centenas de trios assim. A classificação é uma propriedade da regra que você escolheu, não um fato sobre as linhas; portanto, a regra não é um detalhe de implementação: ela é a definição do problema. O que levanta a pergunta que este capítulo existe para responder: com base em quê você a escolhe?
Um parâmetro e um vale
Link para a seção: Um parâmetro e um valePrimeiro, uma questão menor, porque não existem três linhas, mas infinitas. Fique com o erro quadrático por enquanto, já que é isso que todo mundo faz, e reduza o problema a um único número usando o truque que poupou o perceptron de onze mil épocas no Capítulo 1: subtraia a média de ambas as colunas. Quando a nuvem de pontos está centrada na origem, a melhor linha sob erro quadrático passa exatamente pela origem — então o intercepto está resolvido e só resta escolher a inclinação.
u, v = h - h.mean(), y - y.mean() # 5.25 hours, 21.553 mm
def mse(theta):
return np.mean((v - theta * u) ** 2)
grid = np.arange(0.0, 0.6001, 0.001)
curve = np.array([mse(t) for t in grid])
print(grid.size, "candidates ->", f"theta={grid[curve.argmin()]:.3f}", f"mse={curve.min():.6f}")601 candidates -> theta=0.293 mse=0.010115Seiscentas e uma inclinações candidatas, uma vencedora: 0,293 milímetro por hora contra uma verdade de 0,300. Vinte leituras ruidosas e um for-loop chegaram a menos de um centésimo de milímetro por hora — dois vírgula três por cento.
A parte interessante não é a vencedora, mas o formato da busca. Imprima a curva inteira, girada para que a perda corra da esquerda para a direita:
ts = np.arange(0.0, 0.6001, 0.04)
ls = np.array([mse(t) for t in ts])
for t, l in zip(ts, ls):
col = round(l / ls.max() * 50)
print(f"theta={t:.2f} |{' ' * col}*{' ' * (50 - col)}| mse={l:7.4f}")theta=0.00 | * | mse= 0.7244
theta=0.04 | * | mse= 0.5428
theta=0.08 | * | mse= 0.3878
theta=0.12 | * | mse= 0.2593
theta=0.16 | * | mse= 0.1575
theta=0.20 | * | mse= 0.0822
theta=0.24 | * | mse= 0.0336
theta=0.28 | * | mse= 0.0116
theta=0.32 | * | mse= 0.0161
theta=0.36 | * | mse= 0.0473
theta=0.40 | * | mse= 0.1050
theta=0.44 | * | mse= 0.1894
theta=0.48 | * | mse= 0.3004
theta=0.52 | * | mse= 0.4379
theta=0.56 | * | mse= 0.6021
theta=0.60 | *| mse= 0.7928Isso é um vale, visto de lado. Ele tem um único fundo, as paredes sobem suavemente dos dois lados e — esta é a parte que a escadaria do Capítulo 1 não podia oferecer — em cada ponto dele há uma direção bem definida de “descida”. Lembre-se desse formato. O Capítulo 3 é inteiramente sobre descer por ele sem visitar todos os seiscentos e um pontos, e sobre o que muda quando um vale tem mais de um fundo.
Então por que quadrático?
Link para a seção: Então por que quadrático?Temos um vale porque elevamos ao quadrado. O erro absoluto teria dado a ele uma quina no fundo; o pior erro teria dado trechos planos em que mover a linha não muda absolutamente nada. Elevar ao quadrado é inegavelmente conveniente — e conveniência é mais ou menos o motivo que a maioria dos cursos dá, fantasiado de quatro maneiras: torna os erros positivos (o valor absoluto também); pune mais erros grandes (por que deveria?); é diferenciável (a quarta potência também é); é o que todo mundo usa (é, e isso não é argumento).
Aqui está a posição honesta. O erro quadrático selecionou a linha B e o erro absoluto selecionou a linha A. Uma dessas está certa para esta fábrica e a outra está errada, e nada dito até agora permite saber qual. Para escolher a regra, você precisa saber algo sobre como as leituras passaram a diferir da linha, e essa é uma pergunta sobre o mundo, não sobre matemática. Respondê-la exige uma pequena peça de maquinaria.
A verossimilhança de uma linha
Link para a seção: A verossimilhança de uma linhaAqui está a afirmação que transforma “qual linha é melhor” em uma pergunta com resposta.
Assuma que a largura de uma peça é a linha mais um erro aleatório, e assuma que esse erro é extraído de uma Gaussiana — a curva em sino — com média zero e desvio padrão :
A densidade da Gaussiana é
Agora faça algo que o perceptron não podia. Para uma inclinação candidata dada , toda leitura tem um resíduo, e a fórmula acima transforma esse resíduo em um número: quão plausível é um erro exatamente desse tamanho, se esta inclinação é a verdade? Uma leitura sobre a linha recebe um número grande; uma leitura meio milímetro distante recebe um pequeno.
As leituras são independentes — o paquímetro não lembra da peça anterior —, então a regra do produto diz que a plausibilidade do caderno inteiro é o produto das densidades individuais. Esse produto é a verossimilhança de .1 Observe a direção, porque é a direção de que a regra de Bayes trata: os dados são fixos e conhecidos, e é o parâmetro que varia. Isso não é “a probabilidade da inclinação”. É a probabilidade que o modelo atribui aos dados que você de fato obteve, lida como função da inclinação.
SIGMA = 0.12
def gaussian(r, sigma):
return np.exp(-r ** 2 / (2 * sigma ** 2)) / (sigma * np.sqrt(2 * np.pi))
def likelihood(theta):
return np.prod(gaussian(v - theta * u, SIGMA))
for t in (0.25, 0.293, 0.35):
print(f"theta={t} likelihood = {likelihood(t):.6g}")theta=0.25 likelihood = 521.952
theta=0.293 likelihood = 2.42028e+07
theta=0.35 likelihood = 0.190312Uma inclinação de 0,293 torna este caderno quarenta e seis mil vezes mais plausível que 0,25, e cento e vinte e sete milhões de vezes mais plausível que 0,35. Máxima verossimilhança é o princípio de escolher o parâmetro que torna aquilo que você de fato observou o menos surpreendente possível. Não é um teorema, mas uma proposta sobre o que “melhor” deveria significar — uma proposta com conteúdo, porque obriga você a declarar sua suposição sobre o ruído antes de poder pontuar qualquer coisa.
O produto quebra
Link para a seção: O produto quebraRode as mesmas três linhas de código em um mês de turnos em vez de um, e o método desmorona.
rng = np.random.default_rng(7)
u_big = rng.uniform(-5.25, 5.25, 2000) # 2000 readings, not 20
v_big = 0.30 * u_big + 0.12 * rng.standard_normal(2000)
print("2000 readings, sigma = 0.12 mm :", np.prod(gaussian(v_big - 0.30 * u_big, 0.12)))
noisy = 0.30 * u_big + 2.0 * rng.standard_normal(2000)
print("2000 readings, sigma = 2.00 mm :", np.prod(gaussian(noisy - 0.30 * u_big, 2.0)))
print("largest float64 :", np.finfo(np.float64).max)RuntimeWarning: overflow encountered in reduce
2000 readings, sigma = 0.12 mm : inf
2000 readings, sigma = 2.00 mm : 0.0
largest float64 : 1.7976931348623157e+308Duas mil multiplicações e a resposta é inf. Mude uma constante — um paquímetro mais descuidado, de modo que as densidades saiam menores que 1 em vez de maiores — e o mesmo código retorna 0.0. Ambas as respostas estão erradas, em direções opostas; nenhuma levanta uma exceção que você possa capturar; e a segunda nem sequer imprime um aviso.
Não há nada errado com a matemática. A verossimilhança nesses ajustes é um número finito perfeitamente bem definido: seu logaritmo natural é 1400,91, então o número em si é cerca de . O problema é que seu computador não tem esse número, e vale entender exatamente quais números ele tem, porque esta não será a última vez que isso decidirá o resultado.
De onde vem o quadrado
Link para a seção: De onde vem o quadradoA correção para o produto explosivo é a usual: tomar logaritmos. O logaritmo transforma produtos em somas, é estritamente crescente, então não pode mover o local do máximo, e uma soma de dois mil números moderados é algo que float64 lida sem reclamar. Por convenção, tomamos a log-verossimilhança negativa, para que melhor signifique menor. Agora substitua a densidade Gaussiana e veja o que acontece.
-
Comece pelo produto. A verossimilhança é , com sendo a densidade Gaussiana acima.
-
Tome menos o log. O produto vira uma soma, e a exponencial na densidade cancela diretamente contra o logaritmo:
- Jogue fora tudo que não contém . O primeiro termo é uma constante. O na frente da soma é uma constante positiva, e escalar uma função por uma constante positiva não pode mover onde seu mínimo está. O que sobra é
que é a soma dos resíduos quadráticos — a coisa com que começamos o capítulo porque foi a primeira coisa em que qualquer pessoa pensaria.
Esse é o resultado que o capítulo existe para mostrar, e ele merece ser declarado sem ressalvas: erro quadrático não é uma convenção. É a log-verossimilhança negativa de uma Gaussiana, com as constantes removidas. Minimizar o erro quadrático é precisamente o mesmo ato que afirmar que seus erros são Gaussianos e perguntar qual parâmetro torna seus dados menos surpreendentes. Você vinha fazendo essa afirmação o tempo todo; só não estavam lhe dizendo.
A equivalência é verificável, então verifique: varra as mesmas seiscentas e uma inclinações com a log-verossimilhança negativa completa, constantes e tudo, e com o erro quadrático simples.
N = v.size
def nll(theta):
r = v - theta * u
return N * np.log(SIGMA * np.sqrt(2 * np.pi)) + np.sum(r ** 2) / (2 * SIGMA ** 2)
nlls = np.array([nll(t) for t in grid])
mses = np.array([mse(t) for t in grid])
print(f"argmin of the negative log-likelihood : theta={grid[nlls.argmin()]:.3f} nll={nlls.min():.6f}")
print(f"argmin of the mean squared error : theta={grid[mses.argmin()]:.3f} mse={mses.min():.6f}")
print("same index:", nlls.argmin() == mses.argmin())argmin of the negative log-likelihood : theta=0.293 nll=-17.001977
argmin of the mean squared error : theta=0.293 mse=0.010115
same index: TrueNúmeros diferentes no eixo vertical, e um deles é negativo, coisa que uma soma de quadrados nunca é: uma log-verossimilhança negativa pode ficar abaixo de zero, porque uma densidade pode exceder 1. O mesmo fundo do mesmo vale, até o último ponto da grade.
Mostrar a dedução completa
Quais descartes são seguros, exatamente? A mesma manobra aparece em todo capítulo que deriva uma perda, e nem sempre é inocente.
Descartar uma constante aditiva é seguro sempre que ela não depende do parâmetro que você está otimizando, e descartar uma constante multiplicativa positiva é seguro porque para qualquer . Ambos falham no momento em que também está sendo ajustado: então não é constante nenhuma; é o termo que impede o modelo de alegar e plausibilidade infinita. Essa é exatamente a próxima seção.
Eles falham de outro jeito no Capítulo 3: uma constante multiplicativa não move o mínimo, mas escala o gradiente, e o gradiente é multiplicado pela taxa de aprendizado. Dividir por para obter o erro quadrático médio em vez da soma é invisível para a resposta e muito visível para a execução do treinamento — com a soma, dobrar o tamanho do seu batch dobra cada passo que você dá.
Sigma também não é grátis
Link para a seção: Sigma também não é grátisFixamos em 0,12 por decreto, e ninguém na fábrica conhece a dispersão do erro do paquímetro. Trate-a como uma segunda incógnita e deixe a máxima verossimilhança decidir isso também. Aqui o termo constante que acabamos de descartar volta, porque ele é a única coisa entre o modelo e uma alegação de precisão perfeita.
r = v - 0.293 * u
sigmas = np.arange(0.01, 1.0001, 0.0001)
nll_sigma = N * np.log(sigmas * np.sqrt(2 * np.pi)) + np.sum(r ** 2) / (2 * sigmas ** 2)
print("best sigma on the grid :", round(float(sigmas[nll_sigma.argmin()]), 4))
print("sqrt(mean squared residual) :", round(float(np.sqrt(np.mean(r ** 2))), 4))best sigma on the grid : 0.1006
sqrt(mean squared residual) : 0.1006Os dois concordam em quatro casas decimais, e não por acidente: diferenciar essa expressão e igualá-la a zero dá exatamente. Portanto, o erro quadrático médio não é apenas parecido com uma variância. Sob este modelo, ele é a estimativa de máxima verossimilhança da variância do ruído — o número que você vinha minimizando o tempo todo era uma estimativa de quão ruidoso é o seu sensor.
Uma sutileza, barata de declarar e cara de redescobrir depois: essa estimativa é enviesada para baixo, porque os resíduos foram medidos contra um ajuste que foi ele próprio escolhido para torná-los pequenos. Simule isso — duzentos mil cadernos de vinte leituras cada, extraídos de uma distribuição cuja variância verdadeira é exatamente 1, com o único parâmetro do ajuste estimado a partir das próprias leituras. Dividir a soma de quadrados por dá uma média de 0,9501; dividir por dá 1,0001; e é 0,95 em cheio. Cada parâmetro que você ajusta custa um grau de liberdade, e esta é a menor instância visível de um problema muito maior: um modelo sempre parece melhor nos dados aos quais foi ajustado. O Capítulo 4 transforma isso na disciplina de separar dados, e o Capítulo 6 dá nome ao efeito.
Uma perda é uma afirmação sobre o ruído
Link para a seção: Uma perda é uma afirmação sobre o ruídoSe o erro quadrático afirma que o ruído é Gaussiano, a próxima pergunta é o que acontece quando a afirmação é falsa. Não ligeiramente falsa — falsa do jeito que medições reais são falsas.
No chão de fábrica, a maioria das leituras do paquímetro é boa até um décimo de milímetro, e uma ou duas vezes por turno uma lasca de cavaco entra sob a mandíbula e a leitura erra por vários milímetros. Erros assim têm caudas pesadas: pequenos na maior parte do tempo, ocasionalmente enormes, e enormes com muito mais frequência do que uma curva em sino permite. A distribuição de Cauchy é o modelo limpo padrão desse comportamento, e sua densidade é tão simples quanto a da Gaussiana:
A diferença está na cauda: a Gaussiana cai como , brutalmente rápido, e a Cauchy como , quase nada. A consequência é mais fácil de ver do que de explicar:
rng = np.random.default_rng(3)
g = 0.12 * rng.standard_normal(10 ** 6) # Gaussian noise
c = 0.12 * rng.standard_cauchy(10 ** 6) # Cauchy noise, same scale
for k in (10 ** 2, 10 ** 3, 10 ** 4, 10 ** 5, 10 ** 6):
print(f"{k:>9,} samples gaussian var {g[:k].var():.4f} cauchy var {c[:k].var():10.2f}") 100 samples gaussian var 0.0164 cauchy var 0.26
1,000 samples gaussian var 0.0146 cauchy var 59.88
10,000 samples gaussian var 0.0145 cauchy var 358.17
100,000 samples gaussian var 0.0144 cauchy var 3097.98
1,000,000 samples gaussian var 0.0144 cauchy var 32886.10A variância amostral da Gaussiana se estabiliza em 0,0144, que é , e fica ali. A da Cauchy sobe, e continua subindo enquanto você amostra, porque não há nada para onde ela convergir: a distribuição de Cauchy não tem variância, nem média. O erro quadrático, cujo trabalho inteiro é minimizar uma média de quadrados, está sendo solicitado a encontrar uma quantidade que não existe.
Então aqui está um turno em que o paquímetro foi enganado. As mesmas vinte horas, a mesma lâmina, a mesma deriva de 0,30 milímetro por hora — só que o ruído agora é Cauchy. Ajuste duas vezes: uma minimizando resíduos quadráticos, outra minimizando a log-verossimilhança negativa do ruído que de fato gerou os dados. O truque de centralização não ajuda aqui — ele fixa o intercepto apenas para o erro quadrático —, então ambos os ajustes são feitos por força bruta sobre uma grade de interceptos e inclinações, já que ainda não temos uma forma de encontrar o fundo de um vale exceto visitando-o.
SWARF = np.array([
(0.5, 20.08), (1.0, 21.95), (1.5, 20.86), (2.0, 27.51), (2.5, 20.64),
(3.0, 20.75), (3.5, 21.01), (4.0, 21.03), (4.5, 21.37), (5.0, 20.60),
(5.5, 22.03), (6.0, 21.95), (6.5, 21.98), (7.0, 22.01), (7.5, 21.73),
(8.0, 22.97), (8.5, 22.60), (9.0, 22.66), (9.5, 22.44), (10.0, 22.78),
])
hs, ys = SWARF[:, 0], SWARF[:, 1]
A = np.arange(18.0, 22.001, 0.005) # 801 intercepts
B = np.arange(-0.20, 0.8001, 0.002) # 501 slopes
R = ys - (A[:, None, None] + B[None, :, None] * hs) # every line against every point
SCALE = 0.12
square = np.sum(R ** 2, axis=2) # least squares
cauchy = np.sum(np.log(1 + (R / SCALE) ** 2), axis=2) # Cauchy likelihood
for name, surface in (("least squares", square), ("Cauchy likelihood", cauchy)):
i, j = np.unravel_index(surface.argmin(), surface.shape)
print(f"{name:>18}: width = {A[i]:.3f} + {B[j]:.4f} * hours"
f" -> 23.5 mm at hour {(23.5 - A[i]) / B[j]:.2f}")
print(f"{'the truth':>18}: width = 20.000 + 0.3000 * hours"
f" -> 23.5 mm at hour {(23.5 - 20.0) / 0.30:.2f}")
print(f"{A.size * B.size:,} candidate lines evaluated")As duas linhas destacadas são toda a diferença entre os ajustes. Tome o log da densidade de Cauchy, descarte as constantes exatamente como antes, e é o que sobra. Mesma receita, afirmação diferente sobre o ruído.
least squares: width = 21.380 + 0.1080 * hours -> 23.5 mm at hour 19.63
Cauchy likelihood: width = 19.935 + 0.3020 * hours -> 23.5 mm at hour 11.80
the truth: width = 20.000 + 0.3000 * hours -> 23.5 mm at hour 11.67
401,301 candidate lines evaluatedMínimos quadrados relata uma deriva de 0,108 milímetro por hora, cerca de um terço da taxa real, e conclui que a lâmina está boa até a hora 19,6. A resposta verdadeira é a hora 11,7. Agindo com base nesse ajuste, a fábrica roda a prensa por oito horas extras fazendo peças fora da tolerância, sob a autoridade da função de perda mais padrão da área. O ajuste de Cauchy, usando as mesmas vinte leituras, a mesma grade e uma diferença de uma linha no código, chega à hora 11,8.
Duas objeções merecem resposta, porque ambas são a primeira coisa que um bom engenheiro diz.
O outlier é óbvio — basta apagá-lo. Você pode, e ajuda, mas não basta. Apagar a pior leitura move a inclinação de mínimos quadrados de 0,108 para 0,239, o que ainda coloca a troca da lâmina na hora 13,1, uma hora e meia tarde; apagar a pior, reajustar e apagar o que for pior agora leva você a 0,286 — e observe que isso já é um procedimento, não uma observação: apague os dois maiores resíduos do ajuste original em vez disso e você chega a 0,223. Mas agora você fez julgamentos que não pode escrever nem defender, e automatizar a regra não a salva: remover-o-maior-resíduo-e-depois-reajustar, rodado em mil turnos simulados, tem erro mediano de inclinação de 0,0177 contra 0,0100 do ajuste por verossimilhança, e fica mais de 0,05 distante em 14,7% dos turnos contra 1,3%. Exclusão é um remendo sobre uma suposição errada. A verossimilhança não precisa de remendo, porque nunca assumiu que o outlier era impossível.
Você escolheu um conjunto de dados sortudo. Essa objeção está exatamente certa, e é por isso que o último experimento simula mil turnos independentes e reajusta dos dois modos em cada um.
A = np.arange(18.0, 22.001, 0.02) # a coarser grid: a thousand fits to do
B = np.arange(-0.20, 0.8001, 0.005)
lines = A[:, None, None] + B[None, :, None] * hs
rng = np.random.default_rng(2026)
err_sq, err_ca = [], []
for _ in range(1000): # 1000 independent shifts
ys = 20.00 + 0.30 * hs + SCALE * rng.standard_cauchy(hs.size)
R = ys - lines
_, j = np.unravel_index(np.sum(R ** 2, axis=2).argmin(), (A.size, B.size))
_, q = np.unravel_index(np.sum(np.log1p((R / SCALE) ** 2), axis=2).argmin(), (A.size, B.size))
err_sq.append(abs(B[j] - 0.30))
err_ca.append(abs(B[q] - 0.30))
err_sq, err_ca = np.array(err_sq), np.array(err_ca)
for name, e in (("least squares", err_sq), ("Cauchy likelihood", err_ca)):
print(f"{name:>18}: median slope error {np.median(e):.4f} mm/h"
f" off by more than 0.05 in {100 * np.mean(e > 0.05):4.1f}% of shifts"
f" worst {e.max():.3f}")
print(f"the likelihood fit is the closer of the two in {100 * np.mean(err_ca < err_sq):.1f}% of shifts") least squares: median slope error 0.0350 mm/h off by more than 0.05 in 40.4% of shifts worst 0.500
Cauchy likelihood: median slope error 0.0100 mm/h off by more than 0.05 in 1.3% of shifts worst 0.090
the likelihood fit is the closer of the two in 75.6% of shiftsMediana, não média, pelo mesmo motivo de todo o resto nesta seção: os erros de mínimos quadrados são conduzidos por uma Cauchy, então sua média não é algo estável a relatar. Mínimos quadrados está muito errado em dois turnos de cinco; o ajuste por verossimilhança está muito errado em um turno de setenta e sete, e sua pior falha em mil turnos é menos de um quinto da pior falha de mínimos quadrados.
Nada disso torna o erro quadrático ruim. Torna-o específico, e a aritmética diz exatamente por quê. Pegue um resíduo de 0,1 mm e outro de 7 mm. Ao quadrado, a leitura ruim contribui 4.900 vezes mais para o total do que a boa, então a linha é arrastada inteira em direção a ela; sob a log-verossimilhança de Cauchy, os mesmos dois resíduos contribuem 0,527 e 8,133, uma razão de 15,4. A leitura ruim ainda conta; ela só não decide. Este é o início da estatística robusta, em que a perda de Huber de 1964 divide a diferença ao se comportar quadraticamente para resíduos pequenos e linearmente para grandes,7 e em que Tukey já havia mostrado como basta pouca contaminação para tornar a variância amostral uma ferramenta pior que o desvio absoluto médio.8
Uma nota histórica, boa demais para deixar de fora. Mínimos quadrados foi publicado primeiro, por Legendre em 1805, como um dispositivo algébrico conveniente sem justificativa além do fato de que funcionava.9 Quatro anos depois, Gauss fez o argumento ao contrário: tomou como dado que a média aritmética é a forma correta de combinar medições repetidas, perguntou qual distribuição de erro torna a média o valor mais provável e mostrou que essencialmente só uma faz isso — a que hoje leva seu nome.10 A derivação neste capítulo é dele, tem mais de dois séculos, e ainda é a parte que a maioria dos cursos deixa de fora.
O que você já pode dizer, e o que ainda não pode fazer
Link para a seção: O que você já pode dizer, e o que ainda não pode fazerConquistado. Uma função de perda é uma regra de pontuação, e a classificação que ela produz é uma propriedade da regra, não dos candidatos. Toda perda neste curso é a log-verossimilhança negativa de alguma suposição sobre o ruído, com as constantes jogadas fora — a Gaussiana dá o erro quadrático aqui, Bernoulli dá cross-entropy no Capítulo 4, e uma distribuição categórica sobre um vocabulário dá a perda de próximo token no Capítulo 8. A receita nunca muda: declare o ruído, escreva a verossimilhança, tome menos o log. E, quando a suposição está errada, o modelo não é apenas impreciso; ele está errado em uma direção que você consegue prever.
Ainda falta. Encontramos o fundo do vale visitando todos os pontos nele. Isso funcionou para um parâmetro e seiscentos candidatos, e sobreviveu a dois parâmetros com 401.301 candidatos em um quinto de segundo. Três parâmetros na mesma resolução são 201.051.801 candidatos e já não cabem em um único array; uma pequena rede no Capítulo 5 tem milhares de parâmetros, e os modelos aos quais o Capítulo 10 atribui preço têm bilhões. Força bruta aqui não é lenta: é aritmeticamente impossível, e nada neste capítulo sugere uma alternativa.
Olhe de novo para o vale, porém. Parado em com uma perda de 0,0822, a direção de “descida” não é mistério — você pode vê-la na página; a curva desce para a direita. Se você pudesse perguntar à função de perda para que lado ela se inclina no ponto em que você está, sem avaliá-la em nenhum outro lugar, poderia dar um passo nessa direção, perguntar de novo e repetir até o chão ficar plano.
Essa pergunta tem nome. A inclinação de uma função em um ponto é sua derivada, e, para uma função de muitos parâmetros, a coleção de inclinações em todas as direções ao mesmo tempo é o gradiente. O Capítulo 1 não podia usar uma, porque o erro do perceptron era uma escadaria sem inclinação sobre a qual perguntar. Este capítulo construiu algo melhor: uma perda suave em todos os lugares e que veio de uma suposição declarada, não de uma preferência.
Então a pergunta para o Capítulo 3 já não é se uma inclinação existe. É como calculá-la, por que mover-se contra ela desce em vez de subir — um sinal que quase todo curso pede que você aceite por fé — e qual deve ser o tamanho do passo antes de perguntar de novo, o que acaba sendo o único número que decide se uma execução de treinamento converge, oscila em torno da resposta para sempre ou dispara para o infinito.
Fontes e método
Link para a seção: Fontes e métodoTambém vale ler junto com este capítulo: Prince, Understanding Deep Learning §5.1–5.2 e Apêndice C, que constrói toda perda do livro a partir de máxima verossimilhança na ordem usada aqui; Goodfellow, Bengio e Courville, Deep Learning §3.1–3.11 e §5.5, cuja seção de máxima verossimilhança também deriva a divergência KL de que o Capítulo 4 precisa; Murphy, Probabilistic Machine Learning: An Introduction capítulo 2 e §4.2, sobre o que a máxima verossimilhança garante e não garante; Deisenroth, Faisal e Ong, Mathematics for Machine Learning §6.1–6.4 para a regra da soma, a regra do produto e a regra de Bayes feitas corretamente; a nota curta da CMU de Tom Mitchell Estimating Probabilities: MLE and MAP (2016); e §22.7 de Dive into Deep Learning, que chega ao mesmo resultado em código executável.
Referências
Link para a seção: Referências-
Fisher, R. A. On the mathematical foundations of theoretical statistics. Philosophical Transactions of the Royal Society A 222, pp. 309–368 (1922). Onde a verossimilhança é apresentada como método geral, junto com “parâmetro”, “estatística”, suficiência e eficiência. A própria nomeação, e a separação em relação à probabilidade, vem um ano antes: Fisher, R. A., On the “probable error” of a coefficient of correlation deduced from a small sample, Metron 1, pp. 3–32 (1921), pp. 24–25. ↩
-
IEEE Standard for Floating-Point Arithmetic, IEEE 754-2019. Define binary32 e binary16, e as regras de arredondamento que fazem o experimento de soma sair como sai. ↩
-
Kalamkar, D. et al. A Study of BFLOAT16 for Deep Learning Training. arXiv:1905.12322 (2019). Os parâmetros do formato e o caso a favor de trocar bits de mantissa por bits de expoente. ↩
-
Micikevicius, P. et al. Mixed Precision Training. ICLR 2018, arXiv:1710.03740. Escalonamento da perda e as magnitudes medidas de gradientes que o tornam necessário em float16. ↩
-
Goldberg, D. What Every Computer Scientist Should Know About Floating-Point Arithmetic. ACM Computing Surveys 23(1), pp. 5–48 (1991). Ainda é a melhor explicação única de por que as duas ordens de soma discordam. ↩
-
Kahan, W. Pracniques: further remarks on reducing truncation errors. Communications of the ACM 8(1), p. 40 (1965). Soma compensada em meia página. ↩
-
Huber, P. J. Robust estimation of a location parameter. The Annals of Mathematical Statistics 35(1), pp. 73–101 (1964). A perda que é quadrática perto de zero e linear nas caudas, derivada em vez de remendada. ↩
-
Tukey, J. W. A survey of sampling from contaminated distributions, em Contributions to Probability and Statistics (Stanford University Press, 1960), pp. 448–485. ↩
-
Legendre, A. M. Nouvelles méthodes pour la détermination des orbites des comètes (Paris, 1805), apêndice Sur la méthode des moindres quarrés. A primeira publicação de mínimos quadrados, como dispositivo computacional. ↩
-
Gauss, C. F. Theoria Motus Corporum Coelestium (Hamburg, 1809), Livro II, §§175–179. O argumento da média aritmética para a lei normal dos erros, e daí para mínimos quadrados. ↩