De onde vem uma função de perda: verosimilhança, não convenção
Três retas traçadas à vista sobre as mesmas vinte medições, e três regras de pontuação que elegem vencedores diferentes.
Nesta página
A lâmina que corta as peças vai-se gastando. Ao longo de um turno de dez horas, perde fio suficiente para que as peças saiam da passadeira uma fração de milímetro mais largas do que no início; quando passam os 23,5 milímetros, a inspeção rejeita-as. Ninguém na fábrica sabe quando isso acontece. O que 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 nesse momento.
Alguém traça uma reta pelos pontos. Outra pessoa traça uma ligeiramente diferente. Uma terceira traça uma terceira. As três parecem razoáveis no papel e discordam, por várias horas, sobre quando trocar a lâmina — nesta fábrica, a diferença entre uma semana tranquila e um lote para sucata.
Qual reta é melhor?
Tal como está formulada, essa pergunta não tem resposta. Não é uma resposta difícil — é nenhuma resposta. «Melhor» não é uma propriedade de uma reta como o declive é; é uma propriedade de uma reta juntamente com uma regra para pontuar retas, e até alguém escrever a regra não há nada para 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 pode testar, e que por vezes é falsa.
Uma confissão antes da primeira linha de código. Estas vinte leituras não vêm de uma fábrica real: gerei-as a partir de uma reta 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 é sobre saber se um método recupera uma verdade, e a única forma de verificar isso é conhecer a verdade à partida. Portanto: 0,30 milímetros por hora é a resposta no fim do livro. Não pode usá-la, só comparar com ela.
Três regras, três vencedores
Ligação para a secção: Três regras, três vencedoresAqui estão as leituras e as três retas, pontuadas de três formas: erro quadrático, ao qual todos recorrem; erro absoluto, ao qual talvez recorresse um estatístico; e pior erro, ao qual recorreria o maquinista, porque o inspetor não quer saber da sua média — rejeita a peça individual que está fora da tolerância.
O NumPy chega aqui, um capítulo depois do perceptron em Python puro, por uma razão: até ao fim deste capítulo vamos avaliar quatrocentas mil retas candidatas contra vinte leituras cada, e um ciclo Python é a ferramenta errada para isso. É também a notação em que todas as fontes citadas abaixo estão escritas.
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 reta disse menos o que o paquímetro disse, um número por leitura. Todas as regras de pontuação deste capítulo, e todas as loss function dos vinte e oito capítulos depois dele, são uma forma de comprimir uma lista de resíduos num único número. Diferem apenas na forma como comprimem.
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 escolhe B, o erro absoluto escolhe A, o pior erro escolhe C: três regras, três vencedores, nos mesmos vinte pontos.
Escolhi estas três retas para que discordassem, e devo dizê-lo claramente. O ponto é quão fácil foi — alguns minutos a procurar entre interceções e declives de aspeto sensato produzem centenas de trios assim. A ordenação é uma propriedade da regra que escolheu, não um facto sobre as retas; por isso, 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 que fundamento a escolhe?
Um parâmetro, e um vale
Ligação para a secção: Um parâmetro, e um valePrimeiro, uma questão menor, porque não há três retas, mas infinitas. Tome por agora o erro quadrático, já que é o que toda a gente toma, e reduza o problema a um único número usando o truque que poupou onze mil épocas ao perceptron no Capítulo 1: subtraia a média às duas colunas. Assim que a nuvem de pontos fica centrada na origem, a melhor reta segundo o erro quadrático passa exatamente pela origem — portanto a interceção fica resolvida e só resta escolher o declive.
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.010115Seiscentos e um declives candidatos, um vencedor: 0,293 milímetros 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 é o vencedor, mas a forma da procura. Imprima a curva inteira, rodada 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.7928Isto é um vale, visto de lado. Tem um único fundo, as paredes sobem suavemente dos dois lados e — esta é a parte que a escadaria do Capítulo 1 não conseguia oferecer — em todos os pontos há uma direção bem definida de «descida». Lembre-se desta forma. O Capítulo 3 é inteiramente sobre descê-lo sem visitar todos os seiscentos e um pontos, e sobre o que muda quando um vale tem mais do que um fundo.
Então porquê ao quadrado?
Ligação para a secção: Então porquê ao quadrado?Temos um vale porque elevámos ao quadrado. O erro absoluto ter-lhe-ia dado um vinco no fundo; o pior erro ter-lhe-ia dado troços planos onde mover a reta não muda absolutamente nada. Elevar ao quadrado é inegavelmente conveniente — e a conveniência é, grosso modo, a razão que a maioria dos cursos dá, vestida de quatro maneiras: torna os erros positivos (o valor absoluto também); penaliza mais os erros grandes (porquê?); é diferenciável (a quarta potência também); é o que toda a gente usa (é, e isso não é um argumento).
A posição honesta é esta. O erro quadrático selecionou a reta B e o erro absoluto selecionou a reta A. Uma delas está certa para esta fábrica e a outra está errada, e nada do que foi dito até agora lhe permite saber qual. Para escolher a regra, precisa de saber algo sobre como as leituras passaram a diferir da reta, e isso é uma pergunta sobre o mundo, não sobre matemática. Respondê-la exige uma pequena peça de maquinaria.
A verosimilhança de uma reta
Ligação para a secção: A verosimilhança de uma retaEis a afirmação que transforma «qual reta é melhor» numa pergunta com resposta.
Assuma que a largura de uma peça é a reta mais um erro aleatório, e assuma que esse erro é retirado 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 conseguia. Para um declive candidato dado , cada leitura tem um resíduo, e a fórmula acima transforma esse resíduo num número: quão plausível é um erro exatamente desse tamanho, se este declive for a verdade? Uma leitura em cima da reta recebe um número grande; uma leitura meio milímetro ao lado recebe um pequeno.
As leituras são independentes — o paquímetro não se lembra da peça anterior —, por isso a regra do produto diz que a plausibilidade do caderno inteiro é o produto das densidades individuais. Esse produto é a verosimilhança de .1 Repare na direção, porque é a direção de que trata a regra de Bayes: os dados são fixos e conhecidos, e é o parâmetro que varia. Isto não é «a probabilidade do declive». É a probabilidade que o modelo atribui aos dados que obteve, lida como função do declive.
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.190312Um declive de 0,293 torna este caderno quarenta e seis mil vezes mais plausível do que 0,25, e cento e vinte e sete milhões de vezes mais plausível do que 0,35. Máxima verosimilhança é o princípio segundo o qual escolhe o parâmetro que torna aquilo que realmente observou tão pouco surpreendente quanto possível. Não é um teorema, mas uma proposta sobre o que «melhor» deve significar — uma proposta com conteúdo, porque o obriga a declarar a sua suposição sobre o ruído antes de poder pontuar seja o que for.
O produto parte-se
Ligação para a secção: O produto parte-seExecute as mesmas três linhas de código num mês de turnos em vez de um, e o método colapsa.
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 impreciso, para que as densidades saiam menores que 1 em vez de maiores — e o mesmo código devolve 0.0. Ambas as respostas estão erradas, em direções opostas, nenhuma lança uma exceção que possa apanhar, e a segunda nem sequer imprime um aviso.
Não há nada de errado com a matemática. A verosimilhança nessas configurações é um número finito perfeitamente bem definido: o seu logaritmo natural é 1400,91, portanto o próprio número é cerca de . O problema é que o seu computador não tem esse número, e vale a pena perceber exatamente que números tem, porque esta não será a última vez que isso decidirá o resultado.
De onde vem o quadrado
Ligação para a secção: De onde vem o quadradoA correção para o produto explosivo é a habitual: tomar logaritmos. O logaritmo transforma produtos em somas, é estritamente crescente e por isso não pode deslocar a localização do máximo, e uma soma de dois mil números moderados é algo que float64 trata sem queixa. Por convenção, tomamos a log-verosimilhança negativa, para que melhor signifique menor. Agora substitua a densidade Gaussiana e veja o que acontece.
-
Comece pelo produto. A verosimilhança é , com a densidade Gaussiana acima.
-
Tome menos o logaritmo. O produto torna-se uma soma, e a exponencial na densidade cancela diretamente com o logaritmo:
- Deite fora tudo o que não contém . O primeiro termo é uma constante. O à frente da soma é uma constante positiva, e escalar uma função por uma constante positiva não pode alterar o sítio do seu mínimo. O que sobra é
que é a soma dos resíduos ao quadrado — aquilo com que começámos o capítulo porque era a primeira coisa em que toda a gente pensa.
Esse é o resultado para o qual o capítulo existe, e merece ser afirmado sem reservas: o erro quadrático não é uma convenção. É a log-verosimilhança negativa de uma Gaussiana, sem as constantes. Minimizar o erro quadrático é precisamente o mesmo ato que afirmar que os seus erros são Gaussianos e perguntar que parâmetro torna os seus dados menos surpreendentes. Esteve a fazer essa afirmação o tempo todo; simplesmente ninguém lho disse.
A equivalência é verificável, por isso verifique-a: percorra os mesmos seiscentos e um declives com a log-verosimilhança negativa completa, constantes incluídas, 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-verosimilhança negativa pode ficar abaixo de zero, porque uma densidade pode exceder 1. O mesmo fundo do mesmo vale, até ao último ponto da grelha.
Mostrar a dedução completa
Que descartes são exatamente seguros? A mesma manobra aparece em todos os capítulos que derivam uma perda, e nem sempre é inocente.
Eliminar uma constante aditiva é seguro sempre que ela não dependa do parâmetro que está a otimizar, e eliminar uma constante multiplicativa positiva é seguro porque para qualquer . Ambos falham no momento em que também está a ser ajustado: então já não é uma constante, é o termo que impede o modelo de declarar e plausibilidade infinita. É exatamente a próxima secção.
Falham de outra forma no Capítulo 3: uma constante multiplicativa não desloca o mínimo, mas escala o gradiente, e o gradiente é multiplicado pela taxa de aprendizagem. 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 corrida de treino — com a soma, duplicar o tamanho do seu lote duplica cada passo que dá.
Sigma também não é grátis
Ligação para a secção: Sigma também não é grátisFixámos em 0,12 por decreto, e ninguém na fábrica conhece a dispersão do erro do seu paquímetro. Trate-a como uma segunda incógnita e deixe a máxima verosimilhança decidi-la também. Aqui, o termo constante que acabámos de descartar regressa, porque é a única coisa entre o modelo e uma afirmaçã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 a 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 verosimilhança da variância do ruído — o número que esteve a minimizar o tempo todo era uma estimativa de quão ruidoso é o seu sensor.
Uma nuance, barata de enunciar e cara de redescobrir mais tarde: essa estimativa é enviesada para baixo, porque os resíduos foram medidos contra um ajuste que foi ele próprio escolhido para os tornar pequenos. Simule: duzentos mil cadernos de vinte leituras cada, retirados 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 dos quadrados por dá uma média de 0,9501; dividir por dá 1,0001; e é 0,95 em cheio. Cada parâmetro que ajusta custa um grau de liberdade, e esta é a menor instância visível de um problema muito maior: um modelo parece sempre melhor nos dados aos quais foi ajustado. O Capítulo 4 transforma isso na disciplina de reservar dados, e o Capítulo 6 dá nome ao efeito.
Uma perda é uma afirmação sobre o ruído
Ligação para a secção: Uma perda é uma afirmação sobre o ruídoSe o erro quadrático afirma que o ruído é Gaussiano, a pergunta seguinte é o que acontece quando a afirmação é falsa. Não ligeiramente falsa — falsa da forma como as 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 aparas de limalha fica debaixo da garra e a leitura fica desviada por vários milímetros. Erros assim têm caudas pesadas: pequenos na maior parte do tempo, ocasionalmente enormes, e enormes muito mais vezes do que uma curva em sino permite. A distribuição de Cauchy é o modelo limpo padrão desse comportamento, e a sua densidade é tão simples como a da Gaussiana:
A diferença está na cauda: a Gaussiana cai como , brutalmente depressa, e a Cauchy como , quase nada. A consequência é mais fácil de ver do que de dizer:
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 estabiliza em 0,0144, que é , e fica aí. A da Cauchy sobe, e continua a subir enquanto amostrar, porque não há nada para onde convergir: a distribuição de Cauchy não tem variância, nem média. O erro quadrático, cuja função inteira é minimizar uma média de quadrados, está a ser pedido para uma quantidade que não existe.
Eis então um turno em que o paquímetro foi enganado. As mesmas vinte horas, a mesma lâmina, a mesma deriva de 0,30 milímetros por hora — só que o ruído é agora Cauchy. Ajuste-o duas vezes: uma minimizando resíduos quadráticos, outra minimizando a log-verosimilhança negativa do ruído que realmente gerou os dados. O truque de centrar não ajuda aqui — só fixa a interceção para o erro quadrático —, por isso ambos os ajustes são feitos por força bruta numa grelha de interceções e declives, já que continuamos sem forma de encontrar o fundo de um vale a não ser 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 logaritmo da densidade de Cauchy, elimine 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 evaluatedOs mínimos quadrados reportam uma deriva de 0,108 milímetros por hora, cerca de um terço da taxa real, e concluem que a lâmina está boa até à hora 19,6. A resposta verdadeira é a hora 11,7. Agindo com base nesse ajuste, a fábrica deixa a prensa a funcionar mais oito horas, a produzir peças fora da tolerância, com a autoridade da loss function mais padrão da área. O ajuste de Cauchy, usando as mesmas vinte leituras, a mesma grelha 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. Pode fazê-lo, e ajuda, mas não chega. Apagar a pior leitura move o declive dos mínimos quadrados de 0,108 para 0,239, o que ainda põe a troca da lâmina na hora 13,1, uma hora e meia tarde; apagar a pior, reajustar e apagar a que agora for pior leva-o a 0,286 — e repare que isto já é um procedimento, não uma observação: apague antes os dois maiores resíduos do ajuste original e chega a 0,223. Mas agora fez juízos de valor que não consegue escrever nem defender, e automatizar a regra não a salva: «remover-o-maior-resíduo-e-reajustar», executado em mil turnos simulados, tem um erro mediano do declive de 0,0177 contra 0,0100 do ajuste por verosimilhança, e fica desviado por mais de 0,05 em 14,7% dos turnos contra 1,3%. A eliminação é um remendo em cima de uma suposição errada. A verosimilhança não precisa de remendo, porque nunca supôs que o outlier fosse impossível.
Escolheu um conjunto de dados com sorte. Essa objeção está exatamente certa, e é por isso que a última experiência simula mil turnos independentes e reajusta das duas formas 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, pela mesma razão que tudo o resto nesta secção: os erros dos mínimos quadrados são conduzidos por uma Cauchy, por isso a sua média não é uma coisa estável para reportar. Os mínimos quadrados erram feio em dois turnos em cinco; o ajuste por verosimilhança erra feio em um turno em setenta e sete, e a sua pior falha em mil turnos é menos de um quinto da pior dos mínimos quadrados.
Nada disto torna o erro quadrático mau. Torna-o específico, e a aritmética diz exatamente porquê. Pegue num resíduo de 0,1 mm e noutro de 7 mm. Ao quadrado, a má leitura contribui 4.900 vezes mais para o total do que a boa, por isso a reta é arrastada em bloco na sua direção; sob a log-verosimilhança de Cauchy, os mesmos dois resíduos contribuem 0,527 e 8,133, uma razão de 15,4. A má leitura continua a contar, simplesmente não pode decidir. Isto é o começo da estatística robusta, onde a perda de Huber de 1964 divide a diferença ao comportar-se quadraticamente para resíduos pequenos e linearmente para grandes,7 e onde Tukey já tinha mostrado quão pouca contaminação é necessária para tornar a variância amostral uma ferramenta pior do que o desvio absoluto médio.8
Uma nota histórica, demasiado boa para deixar de fora. Os mínimos quadrados foram publicados primeiro por Legendre em 1805, como um dispositivo algébrico conveniente sem outra justificação além de funcionar.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 que distribuição de erro torna a média o valor mais provável, e mostrou que essencialmente só uma o faz — a que hoje tem o seu nome.10 A derivação deste capítulo é a dele, tem mais de dois séculos, e continua a ser a parte que a maioria dos cursos omite.
O que pode agora dizer, e o que ainda não consegue fazer
Ligação para a secção: O que pode agora dizer, e o que ainda não consegue fazerConquistado. Uma loss function é uma regra de pontuação, e a ordenação que produz é uma propriedade da regra, não dos candidatos. Todas as perdas deste curso são a log-verosimilhança negativa de alguma suposição sobre o ruído, com as constantes deitadas fora — a Gaussiana dá aqui o erro quadrático, a Bernoulli dá cross-entropy no Capítulo 4, e uma distribuição categórica sobre um vocabulário dá a perda do próximo token no Capítulo 8. A receita nunca muda: declare o ruído, escreva a verosimilhança, tome menos o logaritmo. E, quando a suposição está errada, o modelo não é apenas impreciso; está errado numa direção que consegue prever.
Ainda em falta. Encontrámos o fundo do vale visitando todos os pontos. 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 à mesma resolução são 201.051.801 candidatos e já não cabem num array; uma pequena rede no Capítulo 5 tem milhares de parâmetros, e os modelos a que o Capítulo 10 põe preço têm milhares de milhões. A força bruta aqui não é lenta; é aritmeticamente impossível, e nada neste capítulo sugere uma alternativa.
Olhe outra vez para o vale, contudo. Em pé em com uma perda de 0,0822, a direção de «descida» não é nenhum mistério — consegue vê-la na página, a curva desce para a direita. Se pudesse perguntar à loss function para que lado inclina no ponto onde está, sem a avaliar em mais nenhum sítio, poderia dar um passo nessa direção, perguntar de novo, e repetir até o chão ficar plano.
Essa pergunta tem nome. O declive de uma função num ponto é a sua derivada, e para uma função de muitos parâmetros a coleção de declives em todas as direções ao mesmo tempo é o gradiente. O Capítulo 1 não podia usar um, porque o erro do perceptron era uma escadaria sem declive para perguntar. Este capítulo construiu algo melhor: uma perda que é suave em todo o lado e que veio de uma suposição declarada, não de uma preferência.
Portanto, a pergunta para o Capítulo 3 já não é se existe declive. É como calculá-lo, porque é que mover-se contra ele desce em vez de subir — um sinal que quase todos os cursos lhe pedem para aceitar por fé — e que distância percorrer antes de perguntar de novo, que acaba por ser o único número que decide se uma corrida de treino converge, oscila para sempre à volta da resposta ou dispara para o infinito.
Fontes e método
Ligação para a secção: Fontes e métodoTambém vale a pena ler juntamente com este capítulo: Prince, Understanding Deep Learning §5.1–5.2 e Apêndice C, que constrói todas as perdas do livro a partir da máxima verosimilhança pela ordem usada aqui; Goodfellow, Bengio e Courville, Deep Learning §3.1–3.11 e §5.5, cuja secção sobre máxima verosimilhanç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 verosimilhanç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
Ligação para a secçã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 verosimilhança é apresentada como método geral, juntamente com «parâmetro», «estatística», suficiência e eficiência. A própria nomeação, e a separação da probabilidade, é de 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 a experiência 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 argumento a favor de trocar bits de mantissa por bits de expoente. ↩
-
Micikevicius, P. et al. Mixed Precision Training. ICLR 2018, arXiv:1710.03740. Loss scaling, e as magnitudes de gradiente medidas 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). Continua a ser a melhor explicação única de porque é 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 dos 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 do erro, e daí para os mínimos quadrados. ↩