Pular para o conteúdo
3/30Capítulo 3 de 30

Ladeira abaixo: gradient descent e os dois passos que todo mundo pula

Calcule o teto exato da taxa de aprendizado e veja uma busca bruta em 3.600 direções redescobrir o gradiente sozinha.

Nesta página

O capítulo anterior terminou com um vale.

Não um vale metafórico: uma curva real, a perda plotada contra um único parâmetro, descendo e depois subindo de novo. E a perda por baixo dela não foi escolhida por ser arrumadinha — ela foi derivada a partir de uma afirmação sobre o ruído nas medições, e o erro quadrático apareceu do outro lado como consequência, não como convenção.

Então temos uma paisagem com um fundo, e um motivo para acreditar que o fundo é o lugar certo. O que não temos é uma forma de chegar lá.

Este capítulo constrói uma, e ela é o algoritmo que treina todos os modelos no restante deste curso — todos, sem exceção, até mesmo os que têm centenas de bilhões de parâmetros. Ele cabe em cerca de vinte linhas. As duas partes difíceis não estão nessas vinte linhas, e são as duas coisas que quase toda explicação pula:

  • Por que o sinal de menos. A atualização subtrai o gradiente. Todo tutorial escreve isso; pouquíssimos dizem por que o gradiente é a direção que sobe, que é o único fato que transforma o sinal de menos em algo além de um ato de fé.
  • Qual o tamanho do passo. “Grande demais diverge, pequeno demais é lento” é verdade e não serve para nada. Existe um número exato, ele é computável a partir da perda, e este capítulo o calcula duas vezes — uma para uma parábola de brinquedo e outra para os dados reais.

A configuração, e por que você não pode simplesmente buscar

Link para a seção: A configuração, e por que você não pode simplesmente buscar

Reformulando para que este capítulo se sustente sozinho: as oito peças da esteira do Capítulo 1, mas com uma pergunta diferente. Não aceitar ou rejeitar — isso volta depois —, e sim prever o peso de uma peça a partir da sua largura.

belt.pyPYTHON
import numpy as np

WIDTH  = np.array([18.0, 19.5, 20.2, 21.0, 24.0, 25.5, 23.0, 26.0])
WEIGHT = np.array([47.0, 52.0, 49.0, 55.0, 61.0, 66.0, 70.0, 58.0])

x = WIDTH  - WIDTH.mean()      # 22.15 mm
y = WEIGHT - WEIGHT.mean()     # 57.25 g

As medições estão centralizadas, exatamente como no Capítulo 1 e por um motivo que volta com juros antes do fim deste capítulo. O modelo é uma reta, y^=ax+b\hat{y} = a x + b, e a perda é o erro quadrático médio que o capítulo anterior derivou:

L(a,b)=1ni=1n(axi+byi)2L(a, b) = \frac{1}{n} \sum_{i=1}^{n} \left(a x_i + b - y_i\right)^2

Dois parâmetros. Por que não apenas testar muitos valores? Vamos fazer isso de verdade — uma grade de a=0a = 0 a 55 e de b=5b = -5 a 55, em passos de 0.010.01:

TEXT
grid 501 x 1001 = 501,501 evaluations in 3.67 s
  best found: a = 2.1000, b = -0.0000, L = 24.592450

Meio milhão de avaliações para fixar dois números com duas casas decimais — e esse segundo é tempo de relógio em uma máquina, então uma nova execução pode cair em qualquer lugar entre três e seis; a contagem de avaliações e o mínimo são a parte que se reproduz. Gradient descent, no fim deste capítulo, chega a quatro casas decimais em oito passos e à resposta float64 completa em trinta e seis.

Mas velocidade não é o argumento, e este é o ponto que decide o curso inteiro. Busca em grade custa kPk^P avaliações para PP parâmetros com kk valores cada. Com mil valores por eixo:

modeloparâmetrosavaliações da grade
esta reta210610^{6}
a rede XOR do Capítulo 59102710^{27}
uma pequena rede multicamadas20.0001060,00010^{60{,}000}

A terceira linha não é um número grande, é um número sem sentido — há aproximadamente 108010^{80} átomos no universo observável. A busca não fica mais lenta à medida que os modelos crescem; ela deixa de existir. Tudo o que vem a seguir existe por causa dessa tabela.

Uma derivada é uma medição que você pode fazer

Link para a seção: Uma derivada é uma medição que você pode fazer

Fixe b=0b = 0 por um momento, para que haja um parâmetro e uma curva, que é a figura que o capítulo anterior deixou. Pegue um ponto nela, a=1a = 1, e pergunte: se eu deslocar aa por uma pequena quantidade hh, quanto a perda se move, por unidade desse deslocamento?

L(a+h)L(a)h\frac{L(a + h) - L(a)}{h}

Essa razão é uma variação vertical sobre variação horizontal — a inclinação da reta que passa por dois pontos da curva. À medida que hh encolhe, os dois pontos deslizam um em direção ao outro e a reta vira a tangente. Sua inclinação é a derivada L(a)L'(a): a taxa com que a perda muda por unidade de mudança em aa. Não é uma aproximação de nada, nem uma quantidade infinitamente pequena. É um limite de razões comuns.

Vale a pena executar, porque os números dizem algo que a definição não diz:

slope.pyPYTHON
def loss1(a):
    return np.mean((a * x - y) ** 2)

for h in [1.0, 1e-2, 1e-4, 1e-6, 1e-8, 1e-10, 1e-12, 1e-14]:
    q = (loss1(1.0 + h) - loss1(1.0)) / h
    print(f"h = {h:<8.0e}   slope estimate = {q:.10f}   error = {abs(q + 16.385):.3e}")
TEXT
h = 1e+00      slope estimate = -8.9400000000    error = 7.445e+00
h = 1e-02      slope estimate = -16.3105500000   error = 7.445e-02
h = 1e-04      slope estimate = -16.3842555001   error = 7.445e-04
h = 1e-06      slope estimate = -16.3849925556   error = 7.444e-06
h = 1e-08      slope estimate = -16.3850003787   error = 3.787e-07
h = 1e-10      slope estimate = -16.3850444324   error = 4.443e-05
h = 1e-12      slope estimate = -16.3851154866   error = 1.155e-04
h = 1e-14      slope estimate = -17.0530256582   error = 6.680e-01

Duas coisas acontecem aqui, e as duas sustentam a estrutura.

O erro não é vagamente proporcional a hh — ele é exatamente 7.445h7.445\,h. Divida hh por cem, e o erro divide por cem, com quatro algarismos significativos todas as vezes. Essa constante não é enfeite: ela é metade da segunda derivada da perda, e é a primeira aparição de uma ideia que volta daqui a duas seções — a de que uma curva perto de um ponto se parece com uma reta mais uma correção proporcional a h2h^2.

E então o padrão quebra. Abaixo de h=108h = 10^{-8}, a estimativa fica pior, e em 101410^{-14} ela erra já no segundo dígito. Nada matemático aconteceu; aconteceu a caixa de ponto flutuante do capítulo anterior. L(a+h)L(a+h) e L(a)L(a) concordam nos primeiros dez dígitos, subtrair um do outro destrói esses dígitos, e dividir os destroços por um número minúsculo amplifica o que sobrou. Existe um melhor hh — aqui em torno de 10810^{-8}, aproximadamente a raiz quadrada do épsilon da máquina —, e ir menor não é ser mais cuidadoso, é ser menos. Lembre disso; uma função no fim deste capítulo depende disso.

A inclinação exata, vinda do cálculo em vez da medição, é 16.385-16.385. Então podemos parar de medir e começar a derivar.

Aqui está a ideia sobre a qual o restante do curso é construído, dita uma vez, claramente.

Compor duas funções é alimentar uma na outra: (fg)(x)=f(g(x))(f \circ g)(x) = f(g(x)). Nada mais.

Uma rede profunda não é como uma composição. Ela é uma. Uma camada é uma função; empilhar camadas é compô-las; “profundidade” é o número de funções na cadeia. Quando o Capítulo 5 constrói uma rede, ele está construindo f4f3f2f1f_4 \circ f_3 \circ f_2 \circ f_1 e nada além disso. O que significa que a regra mais importante do cálculo, para os nossos propósitos, é a que diferencia uma composição:

ddxf(g(x))=f(g(x))g(x)\frac{d}{dx} f(g(x)) = f'(g(x)) \cdot g'(x)

Taxas se multiplicam. Se gg muda três vezes mais rápido que xx, e ff muda duas vezes mais rápido que gg, então ff muda seis vezes mais rápido que xx. Esse é todo o conteúdo, e é por isso que um sinal passando de volta por dez camadas é multiplicado por dez números — que é o motivo pelo qual o Capítulo 6 dedica uma seção ao que acontece quando esses números são todos ligeiramente menores que um.

Use isso na nossa perda. Escreva o resíduo ri=axi+byir_i = a x_i + b - y_i, de modo que L=1nri2L = \frac{1}{n}\sum r_i^2. Cada rir_i depende de aa por meio da função interna axia x_i, cuja derivada é xix_i. Regra da cadeia, termo a termo:

La=1ni2rixi,Lb=1ni2ri1\frac{\partial L}{\partial a} = \frac{1}{n}\sum_i 2 r_i \cdot x_i, \qquad \frac{\partial L}{\partial b} = \frac{1}{n}\sum_i 2 r_i \cdot 1

Esses símbolos \partial curvos marcam uma derivada parcial: diferencie em relação a uma variável e trate todas as outras como constantes. Nada novo acontece — é o mesmo limite de antes, tomado ao longo de um eixo. Reúna as parciais em um vetor e você tem o gradiente:

L=(La, Lb)\nabla L = \left( \frac{\partial L}{\partial a},\ \frac{\partial L}{\partial b} \right)

No ponto (a,b)=(1,4)(a, b) = (1, 4), esse vetor é (16.385, 8.0)(-16.385,\ 8.0). Dois números. A pergunta é o que eles significam, e este é o primeiro passo que todo mundo pula.

O gradiente é um vetor de inclinações ao longo dos eixos. Isso é tudo que provamos. Não é óbvio — nem deveria ser óbvio — que juntá-las em um vetor produza algo que aponte para algum lugar específico.

Então vamos definir aquilo que realmente queremos. Escolha um vetor unitário u\mathbf{u}, uma direção. A derivada direcional é a taxa com que a perda muda quando você anda nessa direção:

DuL=limh0L(θ+hu)L(θ)hD_{\mathbf{u}} L = \lim_{h \to 0} \frac{L(\boldsymbol{\theta} + h\mathbf{u}) - L(\boldsymbol{\theta})}{h}

A regra da cadeia transforma isso em algo computável. Andar ao longo de u\mathbf{u} muda aa à taxa u1u_1 e bb à taxa u2u_2, e as contribuições se somam:

DuL=Lau1+Lbu2=LuD_{\mathbf{u}} L = \frac{\partial L}{\partial a} u_1 + \frac{\partial L}{\partial b} u_2 = \nabla L \cdot \mathbf{u}

A taxa de mudança em qualquer direção é o produto escalar do gradiente com essa direção. E agora a conclusão, que é uma linha de geometria. Escrevendo o produto escalar com o ângulo ϕ\phi entre os vetores,

Lu=Lucosϕ=Lcosϕ\nabla L \cdot \mathbf{u} = \lVert \nabla L \rVert \, \lVert \mathbf{u} \rVert \cos\phi = \lVert \nabla L \rVert \cos\phi

já que u\mathbf{u} tem comprimento 1. A única coisa que você controla é cosϕ\cos\phi, que é máximo em ϕ=0\phi = 0 e mínimo em meia volta, ϕ=180\phi = 180 graus. Então:

  • A subida mais íngreme é ao longo do próprio L\nabla L, e a inclinação ali é exatamente L\lVert \nabla L \rVert.
  • A descida mais íngreme é ao longo de L-\nabla L, e a inclinação ali é L-\lVert \nabla L \rVert.
  • Perpendicular ao gradiente, a perda não muda nada. É por isso que as linhas de um mapa de contorno cruzam o gradiente em ângulos retos.

Esse é o sinal de menos. Não uma convenção, não uma inversão de sinal que alguém escolheu: a direção de queda mais rápida é o gradiente negativo porque cosϕ\cos\phi é minimizado em meia volta, e por nenhum outro motivo.

Como essa é uma afirmação sobre todas as direções, teste-a contra todas as direções. Amostre 3.600 delas, uma a cada décimo de grau, e meça cada uma deslocando um pouco:

directions.pyPYTHON
theta = np.array([1.0, 4.0])
g = grad(theta)
print("gradient      ", g)
print("its length    ", np.linalg.norm(g))
print("its angle     ", np.degrees(np.arctan2(g[1], g[0])) % 360, "degrees")

best = max(
    ((loss(theta + 1e-6 * u) - loss(theta - 1e-6 * u)) / 2e-6, np.degrees(ang))
    for ang, u in (
        (a, np.array([np.cos(a), np.sin(a)])) for a in np.arange(3600) * 2 * np.pi / 3600
    )
)
print("steepest slope", best[0], "at", best[1], "degrees")
TEXT
gradient       [-16.385   8.   ]
its length     18.23371122399386
its angle      153.97598928042032 degrees
steepest slope 18.233709624837502 at 154.0 degrees

Uma busca que não sabe nada sobre gradientes, em 3.600 direções, encontra sua subida mais íngreme em 154,0 graus — a direção do próprio gradiente, dentro da resolução de 0,1 grau da busca. E a inclinação que ela encontra ali, 18,2337, é o comprimento do gradiente com seis algarismos. O teorema não é uma história sobre o que gradientes significam; é um fato mensurável, e essa é a medição.

Por que um pequeno passo ladeira abaixo realmente ajuda

Link para a seção: Por que um pequeno passo ladeira abaixo realmente ajuda

Agora o segundo passo pulado. Sabemos qual é o caminho para baixo. Disso não se segue que andar nessa direção reduza a perda, porque “para baixo” é uma afirmação sobre um deslocamento infinitesimal, e um passo não é infinitesimal.

A ponte é a linearização. Perto de um ponto, uma função suave é sua tangente mais uma correção:

L(θ+δ)=L(θ)+Lδ+O(δ2)L(\boldsymbol{\theta} + \boldsymbol{\delta}) = L(\boldsymbol{\theta}) + \nabla L \cdot \boldsymbol{\delta} + O(\lVert\boldsymbol{\delta}\rVert^2)

Essa é a expansão de Taylor de primeira ordem. O O(δ2)O(\lVert\boldsymbol{\delta}\rVert^2) descartado é a curvatura — o mesmo termo que fez a estimativa da tabela de inclinações errar exatamente por 7.445h7.445\,h. Coloque nela o passo que pretendemos dar, δ=ηL\boldsymbol{\delta} = -\eta \nabla L:

L(θηL)L(θ)ηL2L(\boldsymbol{\theta} - \eta \nabla L) \approx L(\boldsymbol{\theta}) - \eta \lVert \nabla L \rVert^2

A perda cai em ηL2\eta \lVert \nabla L \rVert^2. Cada parte disso é não negativa, então a promessa é real — para um η\eta pequeno o suficiente, porque o termo negligenciado cresce como η2\eta^2 e, em algum momento, o devora. Essa é a teoria inteira. Aqui está a promessa sendo cumprida e depois quebrada:

TEXT
eta = 0.2       promised    66.49364500   delivered   -16.01619240   ratio -0.240868
eta = 0.1       promised    33.24682250   delivered    12.61936315   ratio  0.379566
eta = 0.01      promised     3.32468225   delivered     3.11840766   ratio  0.937957
eta = 0.001     promised     0.33246822   delivered     0.33040548   ratio  0.993796
eta = 0.0001    promised     0.03324682   delivered     0.03322620   ratio  0.999380
eta = 1e-05     promised     0.00332468   delivered     0.00332448   ratio  0.999938

Leia de baixo para cima. À medida que η\eta encolhe, a queda entregue converge para a prometida — razão 0,99938, depois 0,99994 —, que é o teorema de Taylor fazendo seu trabalho. Leia de cima para baixo e, em η=0.2\eta = 0.2, a “queda” entregue é dezesseis negativa. O passo foi ladeira abaixo e a perda subiu.

Então a regra de atualização é

θθηL(θ)\boldsymbol{\theta} \leftarrow \boldsymbol{\theta} - \eta \nabla L(\boldsymbol{\theta})

e ela vem com uma condição que ninguém declara: η\eta precisa ser pequeno o suficiente. Pequeno o suficiente em comparação com o quê, exatamente, é a próxima seção.

A taxa de aprendizado tem um teto, e ele é computável

Link para a seção: A taxa de aprendizado tem um teto, e ele é computável

Comece pelo vale mais simples que existe, f(x)=x2f(x) = x^2, onde f(x)=2xf'(x) = 2x. Um passo de gradient descent é

xxη2x=x(12η)x \leftarrow x - \eta \cdot 2x = x\,(1 - 2\eta)

A posição é multiplicada por (12η)(1 - 2\eta) a cada passo. Isso é uma sequência geométrica, e sequências geométricas têm exatamente uma regra: elas encolhem quando o multiplicador é menor que 1 em valor absoluto, e crescem caso contrário. Então 12η<1\lvert 1 - 2\eta \rvert < 1, que é 0<η<10 < \eta < 1.

A fronteira está exatamente em η=1\eta = 1. Não “por volta de 1”, não “1 costuma ser grande demais”. Em η=1\eta = 1, o multiplicador é 1-1 e o ponto fica quicando entre xx e x-x para sempre, sem se aproximar nem escapar. Abaixo disso, converge; acima, diverge. O intervalo se divide de novo em η=0.5\eta = 0.5, onde o multiplicador muda de sinal: abaixo disso, a aproximação é monótona; acima, o ponto ultrapassa o alvo e alterna os lados; e exatamente em 0.50.5, o multiplicador é 0 e um único passo cai no mínimo.

Quatro regimes, a partir de quatro linhas de álgebra. Vá cruzar as fronteiras por conta própria:

14 passos, terminando em x = -0.0836.

Ver os dados em tabela
Passoxf(x)
0⁨-1.9000⁩⁨3.6100⁩
1⁨-1.5200⁩⁨2.3104⁩
2⁨-1.2160⁩⁨1.4787⁩
3⁨-0.9728⁩⁨0.9463⁩
4⁨-0.7782⁩⁨0.6057⁩
5⁨-0.6226⁩⁨0.3876⁩
6⁨-0.4981⁩⁨0.2481⁩
7⁨-0.3985⁩⁨0.1588⁩
8⁨-0.3188⁩⁨0.1016⁩
9⁨-0.2550⁩⁨0.0650⁩
10⁨-0.2040⁩⁨0.0416⁩
11⁨-0.1632⁩⁨0.0266⁩
12⁨-0.1306⁩⁨0.0170⁩
13⁨-0.1045⁩⁨0.0109⁩
14⁨-0.0836⁩⁨0.0070⁩
Descida do gradiente, interativa

Quatorze passos a uma taxa de 0,1, a partir de x=1.9x = -1.9, terminando em 0.0836-0.0836. Aumente a taxa para 0,5 e o primeiro passo já cai no fundo. Aumente para 0,9 e ela termina no mesmo 0.0836-0.0836 que 0,1 — mesma distância, estilo oposto, porque 12η\lvert 1 - 2\eta \rvert é 0,8 para ambos —, mas chega lá ziguezagueando pelo vale em vez de descer por um lado.

E agora o caso interessante:

14 passos, terminando em x = -1.9000.

Ver os dados em tabela
Passoxf(x)
0⁨-1.9000⁩⁨3.6100⁩
1⁨1.9000⁩⁨3.6100⁩
2⁨-1.9000⁩⁨3.6100⁩
3⁨1.9000⁩⁨3.6100⁩
4⁨-1.9000⁩⁨3.6100⁩
5⁨1.9000⁩⁨3.6100⁩
6⁨-1.9000⁩⁨3.6100⁩
7⁨1.9000⁩⁨3.6100⁩
8⁨-1.9000⁩⁨3.6100⁩
9⁨1.9000⁩⁨3.6100⁩
10⁨-1.9000⁩⁨3.6100⁩
11⁨1.9000⁩⁨3.6100⁩
12⁨-1.9000⁩⁨3.6100⁩
13⁨1.9000⁩⁨3.6100⁩
14⁨-1.9000⁩⁨3.6100⁩
Descida do gradiente, interativa

Exatamente na fronteira. Quatorze passos a uma taxa de 1, e ela termina em 1.9-1.9: precisamente onde começou, sem fazer nada além de quicar. Um empurrãozinho acima disso e o quique cresce em vez de se manter; em 1,2, ela sai do gráfico em quatro passos. Uma taxa grande demais não converge lentamente. Ela não converge.

Agora a regra geral, que cai do mesmo argumento. O multiplicador 12η1 - 2\eta era, na verdade, 1ηf1 - \eta f'', e perto de um mínimo uma perda com múltiplos parâmetros tem um número desse tipo por direção — os autovalores da matriz de segundas derivadas. Toda direção precisa ser estável ao mesmo tempo, então o teto é definido pelo maior deles:

η<2λmax\eta < \frac{2}{\lambda_{\max}}

Para f(x)=x2f(x) = x^2, f=2f'' = 2, teto 1, que é o que acabamos de derivar. Para nossa esteira, a matriz de segundas derivadas é 2nAA\frac{2}{n} A^{\top} A com AA sendo a matriz de entradas com duas colunas, e seus autovalores são 2 e 14,89, então o teto é 2/14.89=0.134322 / 14.89 = 0.13432. Essa é uma previsão com cinco algarismos significativos. Teste:

TEXT
lr=0.1343    -> L =      24.5924
lr=0.13431   -> L =      24.5924
lr=0.13432   -> L =       4707.8       BLEW UP
lr=0.13433   -> L =  4.00452e+16       BLEW UP
lr=0.1344    -> L = 1.18229e+107       BLEW UP

Cinco casas decimais de concordância entre uma linha de álgebra linear e cem mil iterações de um loop for.

E aqui é onde o Capítulo 1 volta. Tudo acima usou as medições centralizadas. Execute o código idêntico em milímetros e gramas brutos e os autovalores são 0,0298 e 998,1 em vez de 2 e 14,89. O teto desaba de 0,134 para 0,002004 — com a mesma exatidão, convergindo em lr=0.002003 e explodindo em lr=0.002004.

Pior que o teto é a razão entre os autovalores. O número de condição mede o quanto o vale está longe de ser redondo: uma trincheira longa e fina força uma taxa pequena o bastante para as paredes íngremes, e então o piso da trincheira é percorrido na mesma lentidão. O nosso vai de 7,44 centralizado para 33.452 bruto. Com a melhor taxa que cada versão consegue usar:

atributosnúmero de condiçãomelhor taxapassos até ficar a 1% do ótimo
centralizado7,440,118410
milímetros e gramas brutos33.4520,002003779.513

Mesmos dados, mesmo código, mesma resposta no fim — e oito mil vezes o trabalho, porque ninguém subtraiu uma média. No Capítulo 1, a mesma omissão custou ao perceptron um fator de seis mil em épocas, e o diagnóstico lá era geométrico: os dados flutuavam longe da origem. É a mesma geometria aqui usando uma roupa de otimização, e é por isso que normalização da entrada não é conselho de higiene, mas aritmética.1

Nada acima precisou de uma biblioteca. Aqui está o otimizador inteiro.

descent.pyPYTHON
def loss(theta):
    a, b = theta
    return np.mean((a * x + b - y) ** 2)


def grad(theta):
    a, b = theta
    residual = a * x + b - y
    return np.array([np.mean(2 * residual * x), np.mean(2 * residual)])


def descend(theta, lr, steps):
    theta = np.array(theta, dtype=float)
    for _ in range(steps):
        theta = theta - lr * grad(theta)   
    return theta


theta = descend([0.0, 0.0], lr=0.05, steps=60)
print(theta, loss(theta))
TEXT
[ 2.10040296e+00 -2.76445533e-15] 24.592448791134984

A resposta fechada de mínimos quadrados para esses oito pontos é a=2.100403a = 2.100403, b=0b = 0, com perda de 24.59244924.592449. O loop a encontrou com oito algarismos significativos sem saber que existe uma forma fechada — o que importa, porque do Capítulo 5 em diante não haverá uma.

A trajetória, já que vê-la é o ponto:

TEXT
   0 a=0.000000 b=0.000000 L=57.437500
   1 a=1.563750 b=0.000000 L=26.736582
   2 a=1.963288 b=-0.000000 L=24.732418
   5 a=2.098116 b=-0.000000 L=24.592488
  10 a=2.100400 b=-0.000000 L=24.592449
  60 a=2.100403 b=-0.000000 L=24.592449

A maior parte da distância é coberta nos dois primeiros passos, porque o gradiente é maior quando você está mais longe do fundo e encolhe à medida que você se aproxima. Gradient descent desacelera automaticamente perto de um mínimo. Isso é um recurso e também, no Capítulo 6, um problema.

O argumento até aqui tem um buraco. O passo para quando L=0\nabla L = \mathbf{0}, e temos chamado isso de “o mínimo”. Um ponto com gradiente zero é um ponto crítico, e ser um mínimo é apenas uma das formas de ser um:

  • um mínimo local: subida em todas as direções, mas possivelmente não o menor ponto desse tipo em qualquer lugar;
  • um máximo local: descida em todas as direções;
  • um ponto de sela: subida em algumas direções e descida em outras. A superfície f(x,y)=x2y2f(x,y) = x^2 - y^2 tem f=(2x,2y)\nabla f = (2x, -2y), que é zero na origem, onde a função é um mínimo ao longo do eixo xx e um máximo ao longo do eixo yy ao mesmo tempo.

Gradient descent não consegue distinguir esses casos, porque só olha para o gradiente, e o gradiente é zero nos três.

Nossa reta tem um ponto crítico e ele é a resposta — uma perda de erro quadrático sobre um modelo linear é convexa, uma única tigela, e a descida nela não pode deixar de encontrar o mínimo global. Essa propriedade não sobrevive ao contato com este curso. A perda de uma rede neural não é convexa, e do Capítulo 5 em diante “o mínimo” não é algo que existe: há muitos, com profundidades diferentes, e qual deles você obtém depende de onde começou. Essa é uma frase e continuará sendo uma frase, porque a teoria é grande e a consequência prática é pequena.

Você pode ver a consequência inteira em uma curva. Pegue f(x)=x44x22+x10f(x) = \tfrac{x^4}{4} - \tfrac{x^2}{2} + \tfrac{x}{10}, que tem dois vales de profundidades diferentes:

TEXT
   x =  -1.046681   f(x) =  -0.352386   minimum
   x =   0.101031   f(x) =   0.005026   maximum
   x =   0.945649   f(x) =  -0.152639   minimum

40 passos, terminando em x = 0.9456.

Ver os dados em tabela
Passoxf(x)
0⁨0.1100⁩⁨0.0050⁩
1⁨0.1122⁩⁨0.0050⁩
2⁨0.1149⁩⁨0.0049⁩
3⁨0.1182⁩⁨0.0049⁩
4⁨0.1223⁩⁨0.0048⁩
5⁨0.1275⁩⁨0.0047⁩
6⁨0.1338⁩⁨0.0045⁩
7⁨0.1416⁩⁨0.0042⁩
8⁨0.1513⁩⁨0.0038⁩
9⁨0.1633⁩⁨0.0032⁩
10⁨0.1781⁩⁨0.0022⁩
11⁨0.1962⁩⁨0.0007⁩
12⁨0.2183⁩⁨-0.0014⁩
13⁨0.2453⁩⁨-0.0046⁩
14⁨0.2779⁩⁨-0.0093⁩
15⁨0.3170⁩⁨-0.0160⁩
16⁨0.3633⁩⁨-0.0253⁩
17⁨0.4172⁩⁨-0.0377⁩
18⁨0.4783⁩⁨-0.0535⁩
19⁨0.5455⁩⁨-0.0721⁩
20⁨0.6163⁩⁨-0.0922⁩
21⁨0.6869⁩⁨-0.1116⁩
22⁨0.7526⁩⁨-0.1277⁩
23⁨0.8092⁩⁨-0.1393⁩
24⁨0.8540⁩⁨-0.1463⁩
25⁨0.8868⁩⁨-0.1499⁩
26⁨0.9091⁩⁨-0.1516⁩
27⁨0.9236⁩⁨-0.1522⁩
28⁨0.9325⁩⁨-0.1525⁩
29⁨0.9379⁩⁨-0.1526⁩
30⁨0.9411⁩⁨-0.1526⁩
31⁨0.9430⁩⁨-0.1526⁩
32⁨0.9441⁩⁨-0.1526⁩
33⁨0.9448⁩⁨-0.1526⁩
34⁨0.9451⁩⁨-0.1526⁩
35⁨0.9454⁩⁨-0.1526⁩
36⁨0.9455⁩⁨-0.1526⁩
37⁨0.9455⁩⁨-0.1526⁩
38⁨0.9456⁩⁨-0.1526⁩
39⁨0.9456⁩⁨-0.1526⁩
40⁨0.9456⁩⁨-0.1526⁩
Descida do gradiente, interativa

Quarenta passos a partir de x=0.11x = 0.11, estabilizando em 0.94560.9456 — o mais raso dos dois vales. Agora mova o ponto inicial um tique para a esquerda, para 0.100.10. Mesma taxa, mesmos quarenta passos, e ele se estabiliza em 1.0461-1.0461, onde a perda é 0,199747 menor. O divisor de águas é a saliência em 0.1010310.101031, e toda a diferença entre as duas respostas é de que lado dela você por acaso começou.

Cair no vale raso é 56,7% pior em perda, e o algoritmo não tem como saber, porque de dentro de um vale toda direção é subida. Não há conserto para isso em gradient descent, e nenhum está por vir. O que existe, na prática, é a constatação de que isso importa muito menos do que a figura sugere — nas dimensões muito altas de uma rede real, a maioria dos pontos críticos acaba sendo sela, não armadilha,2 e o Capítulo 5 mede com que frequência uma rede pequena realmente fica presa.

Passos mais baratos: estocástico, minibatch, momentum

Link para a seção: Passos mais baratos: estocástico, minibatch, momentum

Uma coisa sobre grad acima deveria incomodar você: ele soma o dataset inteiro em cada passo. Oito peças não são nada. Um milhão significa um milhão de cálculos de gradiente para mover os parâmetros uma vez.

A saída é que o gradiente é uma média, e uma média pode ser estimada a partir de uma amostra. Calcule-a em um punhado aleatório — um minibatch — e dê o passo com isso. A estimativa é ruidosa; ela também é não viesada, e centenas de passos ruidosos baratos vencem um passo exato caro. Em cem mil peças sintéticas, contando gradientes por exemplo em vez de passos:

métodopassos até ficar a 0,1% do ótimogradientes por exemplo
batch completo7700.000
minibatch de 321003.200
um exemplo por vez17.58017.580

Duzentas e dezenove vezes menos aritmética para chegar ao mesmo lugar. E o extremo — um exemplo por vez, a aproximação estocástica original de Robbins e Monro3não é o vencedor: ele é cinco vezes pior que batches de 32, porque 32 exemplos custam quase nada a mais que um em hardware que multiplica matrizes, enquanto o ruído cai com a raiz quadrada do tamanho do batch. Essa troca é o motivo pelo qual todo script de treinamento que você ler terá um batch_size nele.

Momentum é o outro conserto barato, e mira diretamente na trincheira. Em um vale mal condicionado, os passos ziguezagueiam pela direção estreita enquanto rastejam pela longa. Momentum mantém uma média móvel dos gradientes passados, de modo que os componentes oscilantes se cancelam e o componente consistente se acumula:4

vβv+L(θ),θθηv\mathbf{v} \leftarrow \beta \mathbf{v} + \nabla L(\boldsymbol{\theta}), \qquad \boldsymbol{\theta} \leftarrow \boldsymbol{\theta} - \eta \mathbf{v}

Duas linhas extras. Na esteira bruta não centralizada — número de condição 33.452, o pior caso que temos —, na melhor taxa que a descida simples consegue usar:

TEXT
momentum beta=0.0   ->    79,513 steps to 1%
momentum beta=0.9   ->     1,609 steps to 1%
momentum beta=0.99  ->       461 steps to 1%

Um fator de 172 por duas linhas de código. O Capítulo 6 transforma isso em Adam; o mecanismo já está aqui.

A verificação de que você vai precisar no Capítulo 5

Link para a seção: A verificação de que você vai precisar no Capítulo 5

Todo gradiente neste capítulo foi derivado à mão e, portanto, poderia estar errado. O conserto é a tabela de inclinações do começo: meça a derivada numericamente e compare. Use a diferença central, L(θ+h)L(θh)2h\frac{L(\theta+h) - L(\theta-h)}{2h}, que cancela o termo de erro dominante e é muito mais precisa para o mesmo hh.

gradcheck.pyPYTHON
def numeric_grad(f, theta, h=1e-5):
    theta = np.asarray(theta, dtype=float)
    out = np.zeros_like(theta)
    for i in range(theta.size):
        bump = np.zeros_like(theta)
        bump[i] = h
        out[i] = (f(theta + bump) - f(theta - bump)) / (2 * h)     
    return out


def gradcheck(f, df, theta, h=1e-5):
    analytic = np.asarray(df(theta), dtype=float)
    numeric = numeric_grad(f, theta, h)
    return np.max(np.abs(analytic - numeric) / np.maximum(1e-8, np.abs(analytic) + np.abs(numeric)))

A forma relativa da comparação importa: uma diferença absoluta de 10410^{-4} é um desastre em um gradiente de tamanho 10310^{-3} e irrelevante em um de tamanho 10610^{6}.

TEXT
relative error: 1.8929136036763527e-11
with 2 dropped: 0.33333333331650744

A primeira linha é o gradiente derivado à mão acima. A segunda é a mesma função com o fator 2 omitido em um componente — um typo de um único caractere —, e a verificação o captura imediatamente. Qualquer coisa abaixo de cerca de 10710^{-7} é concordância; qualquer coisa acima de 10410^{-4} é bug. Guarde esta função: o Capítulo 5 a usa para depurar um mecanismo de diferenciação automática, e ela é o único motivo pelo qual um gradiente errado pode ser encontrado.

Tudo neste capítulo se apoiou em uma suposição que nunca foi declarada: que você consegue escrever L/θ\partial L / \partial \theta.

Para uma reta com dois parâmetros, isso foi uma linha de álgebra. Quase imediatamente deixa de ser. Peça a um sistema de álgebra simbólica a derivada da perda de uma rede em relação a um único peso da primeira camada, para um único exemplo, e conte a aritmética na resposta:

redeoperações em uma derivada parcial
quatro unidades ocultas, uma camada40
quatro unidades ocultas, duas camadas301
quatro unidades ocultas, três camadas1.717

A terceira linha é uma rede com 57 parâmetros — uma rede tão pequena que seria uma nota de rodapé no Capítulo 6 —, e escrever seu gradiente à mão significa cerca de 97.869 operações para um exemplo de treinamento. Não há notação que salve isso. O que salva é a observação de que a regra da cadeia aplicada a uma composição tem uma estrutura enorme, que as mesmas quantidades intermediárias aparecem repetidas vezes, e que calculá-las na ordem certa fornece todas as derivadas por aproximadamente o preço de uma passada para frente. Esse é o Capítulo 5.

Mas há um problema menor primeiro, e ele está esperando logo ali.

Agora temos uma máquina que rola ladeira abaixo em qualquer perda diferenciável. Aponte-a para a pergunta original da esteira — aceitar ou rejeitar, um alvo que é 1 ou 0 —, coloque uma sigmoide na saída para que ela preveja uma probabilidade, e minimize o erro quadrático. Ela vai rodar. Também vai quase não se mover quando estiver mais errada, e o gradiente mostra por quê:

saída zzprevisãoverdadegradiente com erro quadráticogradiente com entropia cruzada
000.500012.5×1012.5 \times 10^{-1}5.0×1015.0 \times 10^{-1}
2-20.119211.850×1011.850 \times 10^{-1}8.808×1018.808 \times 10^{-1}
6-60.002514.921×1034.921 \times 10^{-3}9.975×1019.975 \times 10^{-1}
10-104.54×1054.54 \times 10^{-5}19.079×1059.079 \times 10^{-5}1.0001.000

Um modelo que está confiante e catastroficamente errado — prevendo 0,0000454 quando a resposta é 1 — produz um gradiente de erro quadrático de 9×1059 \times 10^{-5}. Ele não faz ideia de que está encrencado. A outra coluna, vinda de uma perda que ainda não derivamos, relata 1,0: urgência máxima, exatamente onde ela é merecida.

Isso levanta a pergunta com que o próximo capítulo começa. O último capítulo disse que uma perda é uma suposição sobre o ruído, e erro quadrático supõe ruído gaussiano. Que modelo de ruído uma resposta sim-ou-não tem — e que perda aparece quando você aplica a mesma derivação a ele?


O método é mais antigo que todos esses: Cauchy o descreveu em uma nota à Académie des Sciences em 1847, como uma forma de resolver sistemas de equações andando ladeira abaixo sobre a soma de seus resíduos quadráticos. Também vale ler junto com este capítulo: An overview of gradient descent optimization algorithms, de Sebastian Ruder (arXiv:1609.04747), que cobre de momentum a Adam em quatorze páginas legíveis; o capítulo 3 de Numerical Optimization, de Nocedal e Wright (2ª ed., Springer, 2006), cujo teorema 3.3 dá a taxa de convergência da descida mais íngreme em uma quadrática em termos do número de condição — é a teoria por trás de por que o condicionamento decide a contagem de passos, embora trate de line search em vez do teto 2/λmax2/\lambda_{\max} de passo fixo medido acima —, ou as seções §5.8 e §7.1 de Mathematics for Machine Learning, de Deisenroth, Faisal e Ong, para o mesmo terreno com menos maquinário; §6.1 de Understanding Deep Learning, de Prince, e §4.3 de Deep Learning, de Goodfellow, Bengio e Courville; Dive into Deep Learning §12.1–12.3, que traz a análise de minibatch com mais medições do que cabe aqui; e o capítulo 4 de Hands-On Machine Learning, de Géron (3ª ed.), o tratamento mais prático da taxa de aprendizado como algo que você ajusta em vez de derivar. As notas do MIT 6.390 colocam gradient descent antes da classificação, como este curso faz e pelo mesmo motivo.

  1. LeCun, Y., Bottou, L., Orr, G. B. e Müller, K.-R. Efficient BackProp, em Neural Networks: Tricks of the Trade (Springer, 1998), pp. 9–50. A seção 4.3 dá a recomendação e a seção 5.1 traz o argumento usado na caixa de detalhes acima: centralizar e escalar entradas muda os autovalores da matriz de segundas derivadas e, portanto, o número de passos, não apenas o conforto numérico.

  2. Dauphin, Y. N., Pascanu, R., Gulcehre, C., Cho, K., Ganguli, S. e Bengio, Y. Identifying and attacking the saddle point problem in high-dimensional non-convex optimization, arXiv:1406.2572 (2014). O argumento de que, em altas dimensões, pontos críticos são esmagadoramente selas, e não mínimos locais, já que um mínimo exige que cada uma de milhares de direções se curve para cima ao mesmo tempo.

  3. Robbins, H. e Monro, S. A Stochastic Approximation Method. Annals of Mathematical Statistics 22(3), pp. 400–407 (1951). O artigo que estabeleceu que uma estimativa ruidosa de um gradiente é suficiente, desde que se use um tamanho de passo que encolha da forma correta.

  4. Polyak, B. T. Some methods of speeding up the convergence of iteration methods. USSR Computational Mathematics and Mathematical Physics 4(5), pp. 1–17 (1964). O método da bola pesada, que é a atualização de momentum acima, vinte e dois anos antes de backpropagation chegar a este campo.

Pronto para deixar a LIA escolher por você?

Crie com todos os modelos de IA em um só lugar — comece grátis hoje.