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

Ladeira abaixo: Gradient Descent e os dois passos que todos saltam

Calcule o limite exato da learning rate e veja uma pesquisa brute-force em 3.600 direções redescobrir o gradiente.

Nesta página

O capítulo anterior terminou com um vale.

Não um vale metafórico: uma curva real, a perda representada contra um único parâmetro, a descer e a voltar a subir. E a perda por baixo dela não foi escolhida por ser arrumada — foi derivada a partir de uma afirmação sobre o ruído nas medições, e o erro quadrático apareceu no fim como consequência, não como convenção.

Temos, portanto, uma paisagem com um fundo e uma razão para acreditar que esse fundo é o sítio certo. O que não temos é uma forma de lá chegar.

Este capítulo constrói uma, e é o algoritmo que treina todos os modelos no resto deste curso — todos, sem exceção, até e incluindo os que têm centenas de milhares de milhões de parâmetros. 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 todas as explicações saltam:

  • Porque existe o sinal menos. A atualização subtrai o gradiente. Todos os tutoriais o escrevem; muito poucos dizem porque é que o gradiente é a direção que vai para cima, que é o único facto que torna o sinal menos algo que não seja um ato de fé.
  • Que tamanho deve ter o passo. "Demasiado grande diverge, demasiado pequeno é lento" é verdade e inútil. Existe um número exato, é calculável a partir da perda, e este capítulo calcula-o duas vezes — uma para uma parábola de brinquedo e outra para os dados reais.

A configuração, e porque não pode simplesmente pesquisar

Ligação para a secção: A configuração, e porque não pode simplesmente pesquisar

Reformulando para que este capítulo se aguente sozinho: as oito peças da passadeira transportadora do Capítulo 1, mas com uma pergunta diferente. Não aceitar ou rejeitar — isso volta mais tarde — mas 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 centradas, exatamente como no Capítulo 1 e por uma razão que regressa com juros antes de este capítulo acabar. 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. Porque não experimentar simplesmente muitos valores? Vamos fazê-lo mesmo — uma grelha de a=0a = 0 até 55 e de b=5b = -5 até 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 a duas casas decimais — e esse segundo é tempo real numa máquina, por isso uma repetição fica em qualquer ponto 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, obtém quatro casas decimais em oito passos e a resposta float64 completa em trinta e seis.

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

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

A terceira linha não é um número grande, é um número sem significado — há cerca de 108010^{80} átomos no universo observável. A pesquisa não fica mais lenta à medida que os modelos crescem; deixa de existir. Tudo o que se segue existe por causa dessa tabela.

Fixe b=0b = 0 por um momento para haver um parâmetro e uma curva, que é a imagem que o último capítulo deixou. Escolha um ponto nela, a=1a = 1, e pergunte: se eu deslocar aa por uma pequena quantidade hh, quanto se move a perda por unidade de deslocamento?

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

Esse quociente é uma subida sobre avanço — o declive da reta que passa por dois pontos na curva. À medida que hh encolhe, os dois pontos deslizam um para o outro e a reta torna-se a tangente. O seu declive é a derivada L(a)L'(a): a taxa a que a perda muda por unidade de mudança em aa. Não é uma aproximação de coisa nenhuma, nem uma quantidade infinitamente pequena. É um limite de quocientes comuns.

Vale a pena executar isto, 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 ambas sustentam a estrutura.

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

E depois o padrão quebra. Abaixo de h=108h = 10^{-8}, a estimativa fica pior, e em 101410^{-14} está errada no segundo dígito. Nada matemático aconteceu; aconteceu a caixa de vírgula flutuante do último capítulo. L(a+h)L(a+h) e L(a)L(a) coincidem nos seus primeiros dez dígitos, subtraí-los destrói esses dígitos, e dividir os destroços por um número minúsculo amplifica o que sobra. Há um melhor hh — aqui por volta de 10810^{-8}, aproximadamente a raiz quadrada do epsilon da máquina — e ir mais pequeno não é ser mais cuidadoso, é ser menos. Lembre-se disso; uma função no fim deste capítulo depende dele.

O declive exato, por cálculo e não por medição, é 16.385-16.385. Portanto, podemos parar de medir e começar a derivar.

Eis a ideia sobre a qual o resto 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. É uma composição. 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, está a construir f4f3f2f1f_4 \circ f_3 \circ f_2 \circ f_1 e nada mais. O que significa que a regra mais importante do cálculo, para os nossos fins, é 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)

As taxas multiplicam-se. Se gg muda três vezes mais depressa do que xx, e ff muda duas vezes mais depressa do que gg, então ff muda seis vezes mais depressa do que xx. Esse é todo o conteúdo, e é por isso que um sinal que passa para trás por dez camadas é multiplicado por dez números — razão pela qual o Capítulo 6 dedica uma secção ao que acontece quando esses números são todos ligeiramente menores do que um.

Use-a 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 através 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 encaracolados \partial assinalam uma derivada parcial: diferencie em relação a uma variável e trate todas as outras como constantes. Nada de novo acontece — é o mesmo limite de antes, tomado ao longo de um eixo. Reúna as parciais num vetor e 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 significam, e este é o primeiro passo que todos saltam.

O gradiente é um vetor de declives ao longo dos eixos. Foi só isso que provámos. Não é óbvio — não deve ser óbvio — que juntá-los num vetor produza algo que aponte para qualquer lado em particular.

Por isso, defina o que realmente queremos. Escolha um vetor unitário u\mathbf{u}, uma direção. A derivada direcional é a taxa a que a perda muda quando caminha 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 isto em algo calculável. Caminhar ao longo de u\mathbf{u} altera aa à taxa u1u_1 e bb à taxa u2u_2, e as contribuições somam-se:

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 o remate, 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

uma vez que u\mathbf{u} tem comprimento 1. A única coisa que controla é cosϕ\cos\phi, que é máximo em ϕ=0\phi = 0 e mínimo a meia volta, ϕ=180\phi = 180 graus. Portanto:

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

Esse é o sinal menos. Não é uma convenção, nem uma inversão de sinal que alguém escolheu: a direção da diminuição mais rápida é o gradiente negativo porque cosϕ\cos\phi é minimizado a meia volta, e por nenhuma outra razão.

Como isto é uma afirmação sobre todas as direções, teste-a contra todas as direções. Amostre 3.600 delas, uma por cada décimo de grau, e meça cada uma com um pequeno deslocamento:

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 pesquisa que nada sabe sobre gradientes, em 3.600 direções, encontra a subida mais íngreme a 154,0 graus — a direção do próprio gradiente, dentro da resolução de 0,1 graus da pesquisa. E o declive que encontra aí, 18,2337, é o comprimento do gradiente a seis algarismos. O teorema não é uma história sobre o que significam os gradientes; é um facto mensurável, e essa é a medição.

Porque é que um pequeno passo ladeira abaixo ajuda mesmo

Ligação para a secção: Porque é que um pequeno passo ladeira abaixo ajuda mesmo

Agora o segundo passo saltado. Sabemos para que lado é baixo. Daí não se segue que caminhar nessa direção baixe a perda, porque "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 é a 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 tornou a estimativa da tabela de declives errada exatamente por 7.445h7.445\,h. Coloque o passo que tencionamos 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 desce ηL2\eta \lVert \nabla L \rVert^2. Todas as partes disso são não negativas, por isso a promessa é real — para um η\eta suficientemente pequeno, porque o termo negligenciado cresce como η2\eta^2 e acaba por o engolir. Essa é toda a teoria. Eis a promessa a ser 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 a estar correto. Leia de cima para baixo e em η=0.2\eta = 0.2 a "queda" entregue é dezasseis negativa. O passo foi ladeira abaixo e a perda subiu.

Portanto, a regra de atualização é

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

e vem com uma condição que ninguém enuncia: que η\eta seja suficientemente pequeno. Suficientemente pequeno em comparação com o quê, exatamente, é a próxima secção.

Comece com o 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) em cada passo. Isso é uma progressão geométrica, e as progressões geométricas têm exatamente uma regra: encolhem quando o multiplicador é menor do que 1 em valor absoluto e crescem caso contrário. Portanto, 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", nem "1 costuma ser demasiado grande". Em η=1\eta = 1, o multiplicador é 1-1 e o ponto salta entre xx e x-x para sempre, sem se aproximar nem fugir. Abaixo disso, converge; acima disso, diverge. O intervalo divide-se novamente em η=0.5\eta = 0.5, onde o multiplicador muda de sinal: abaixo desse ponto, a aproximação é monótona; acima, o ponto passa para lá do mínimo e alterna lados; e exatamente em 0.50.5, o multiplicador é 0 e um único passo aterra no mínimo.

Quatro regimes, a partir de quatro linhas de álgebra. Vá cruzar as fronteiras por si:

Passos: 14; termina 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

Catorze passos a uma taxa de 0,1, a partir de x=1.9x = -1.9, terminando em 0.0836-0.0836. Empurre a taxa para 0,5 e o primeiro passo aterra no fundo. Empurre-a para 0,9 e acaba no mesmo 0.0836-0.0836 em que 0,1 acabou — mesma distância, estilo oposto, porque 12η\lvert 1 - 2\eta \rvert é 0,8 para ambos — mas chega lá em ziguezague através do vale em vez de caminhar por um lado.

E agora o caso interessante:

Passos: 14; termina 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. Catorze passos a uma taxa de 1, e termina em 1.9-1.9: precisamente onde começou, sem fazer nada além de saltar. Um pequeno empurrão acima e os saltos crescem em vez de se manterem; a 1,2 sai do gráfico em quatro passos. Uma taxa demasiado grande não converge devagar. Não converge.

Agora a regra geral, que sai 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 vários parâmetros tem um número destes por direção — os valores próprios da matriz das segundas derivadas. Todas as direções têm de ser estáveis ao mesmo tempo, por isso o teto é definido pelo maior:

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

Para f(x)=x2f(x) = x^2, f=2f'' = 2, teto 1, que é o que acabámos de derivar. Para a nossa passadeira, a matriz das segundas derivadas é 2nAA\frac{2}{n} A^{\top} A, com AA a matriz de entrada de duas colunas, e os seus valores próprios são 2 e 14,89, por isso o teto é 2/14.89=0.134322 / 14.89 = 0.13432. Isto é uma previsão com cinco algarismos significativos. Teste-a:

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 ciclo for.

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

Pior do que o teto é a razão entre os valores próprios. O número de condição mede quão longe de redondo está o vale: uma trincheira longa e estreita força uma taxa pequena o suficiente para as paredes íngremes, e depois o chão da trincheira é percorrido ao mesmo passo rastejante. O nosso passa de 7,44 centrado para 33.452 bruto. Com a melhor taxa que cada versão consegue usar:

featuresnúmero de condiçãomelhor taxapassos até ficar a 1% do ótimo
centradas7,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 aí foi geométrico: os dados flutuavam longe da origem. É a mesma geometria aqui com fato de otimização, e é por isso que a normalização da entrada não é um conselho de higiene, mas aritmética.1

Nada acima precisou de uma biblioteca. Eis o otimizador completo.

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 de mínimos quadrados em forma fechada para estes oito pontos é a=2.100403a = 2.100403, b=0b = 0, com uma perda de 24.59244924.592449. O ciclo encontrou-a a oito algarismos significativos sem saber que existe uma forma fechada — o que importa, porque a partir do Capítulo 5 deixará de haver uma.

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

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 primeiros dois passos, porque o gradiente é maior quando está mais longe do fundo e encolhe à medida que se aproxima. Gradient descent abranda automaticamente perto de um mínimo. Isso é uma funcionalidade 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 a isso "o mínimo". Um ponto com gradiente zero é um ponto crítico, e ser um mínimo é apenas uma das formas de o ser:

  • um mínimo local: a subir em todas as direções, mas possivelmente não o ponto mais baixo desse tipo em todo o lado;
  • um máximo local: a descer em todas as direções;
  • um ponto de sela: a subir em algumas direções e a descer noutras. 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 estes casos, porque só olha para o gradiente, e o gradiente é zero nos três.

A nossa reta tem um ponto crítico e ele é a resposta — uma perda de erro quadrático sobre um modelo linear é convexa, uma taça única, e a descida nela não pode deixar de encontrar o mínimo global. Essa propriedade não sobrevive ao contacto com este curso. A perda de uma rede neuronal não é convexa, e a partir do Capítulo 5 "o mínimo" não é uma coisa que exista: há muitos, de profundidades diferentes, e aquele que obtém depende de onde começou. Isto é uma frase e fica numa frase, porque a teoria é grande e a consequência prática é pequena.

Pode ver a consequência inteira numa curva. Tome 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

Passos: 40; termina 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 de partida um traço para a esquerda, para 0.100.10. Mesma taxa, mesmos quarenta passos, e estabiliza em 1.0461-1.0461 em vez disso, onde a perda é 0,199747 mais baixa. A linha divisória é a lomba em 0.1010310.101031, e toda a diferença entre as duas respostas é o lado em que, por acaso, começou.

Aterrar no vale raso é 56,7% pior em perda, e o algoritmo não tem forma de o saber, porque dentro de um vale todas as direções são a subir. Não há reparação para isto em gradient descent e nenhuma está a caminho. O que há, na prática, é a descoberta de que isto importa muito menos do que a imagem sugere — nas dimensões muito altas de uma rede real, a maioria dos pontos críticos acaba por ser pontos de sela, não armadilhas,2 e o Capítulo 5 mede com que frequência uma pequena rede fica realmente presa.

Uma coisa sobre grad acima deve incomodá-lo: soma todo o conjunto de dados 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-o num pequeno conjunto aleatório — um minibatch — e dê o passo com isso. A estimativa é ruidosa; também é não enviesada, e centenas de passos ruidosos baratos batem 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 de cada vez17.58017.580

Duzentas e dezanove vezes menos aritmética para chegar ao mesmo sítio. E o extremo — um exemplo de cada vez, a aproximação estocástica original de Robbins e Monro3não é o vencedor: é cinco vezes pior do que batches de 32, porque 32 exemplos custam quase nada mais do que um em hardware que multiplica matrizes, enquanto o ruído cai com a raiz quadrada do tamanho do batch. Esse compromisso é a razão por que todos os scripts de treino que alguma vez ler terá um batch_size.

Momentum é a outra correção barata, e mira diretamente a trincheira. Num vale mal condicionado, os passos fazem ziguezague através da direção estreita enquanto rastejam ao longo da comprida. 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 extra. Na passadeira bruta não centrada — número de condição 33.452, o pior caso que temos — à 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 isto em Adam; o mecanismo já está aqui.

Todos os gradientes neste capítulo foram derivados à mão e, portanto, podiam estar errados. A correção é a tabela de declives do início: medir a derivada numericamente e comparar. 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 num gradiente de tamanho 10310^{-3} e irrelevante num 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 numa componente — um erro tipográfico de um único caráter — e a verificação apanha-o imediatamente. Qualquer coisa abaixo de cerca de 10710^{-7} é concordância; qualquer coisa acima de 10410^{-4} é um bug. Guarde esta função: o Capítulo 5 usa-a para depurar um motor de diferenciação automática, e é a única razão pela qual um gradiente errado é sequer encontrável.

Tudo neste capítulo assentou numa suposição que nunca foi enunciada: que consegue escrever L/θ\partial L / \partial \theta.

Para uma reta com dois parâmetros, isso foi uma linha de álgebra. Deixa de o ser quase imediatamente. 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 numa 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 o seu gradiente à mão significa cerca de 97.869 operações para um exemplo de treino. Não há notação que salve isto. O que o salva é a observação de que a regra da cadeia aplicada a uma composição tem uma estrutura enorme, que as mesmas quantidades intermédias aparecem repetidamente, e que calculá-las pela ordem certa dá todas as derivadas por aproximadamente o preço de uma passagem para a frente. Esse é o Capítulo 5.

Mas há primeiro um problema mais pequeno, e está à espera já a seguir.

Temos agora uma máquina que descerá encosta abaixo em qualquer perda diferenciável. Aponte-a à pergunta original da passadeira — aceitar ou rejeitar, um alvo que é 1 ou 0 — ponha uma sigmoide na saída para prever uma probabilidade, e minimize o erro quadrático. Vai correr. Também quase não se moverá quando estiver mais errada, e o gradiente diz porquê:

output 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 — a prever 0,0000454 quando a resposta é 1 — produz um gradiente de erro quadrático de 9×1059 \times 10^{-5}. Não faz ideia de que está em apuros. A outra coluna, de uma perda que ainda não derivámos, reporta 1,0: urgência máxima, exatamente onde é merecida.

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


O método é mais antigo do que todos estes: Cauchy descreveu-o numa nota à Académie des Sciences em 1847, como forma de resolver sistemas de equações caminhando ladeira abaixo sobre a soma dos seus resíduos quadráticos. Também vale a pena ler juntamente com este capítulo: An overview of gradient descent optimization algorithms, de Sebastian Ruder (arXiv:1609.04747), que cobre momentum até Adam em catorze 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 numa quadrática em termos do número de condição — é a teoria por trás de porque o condicionamento decide a contagem de passos, embora trate pesquisa em linha em vez do teto de 2/λmax2/\lambda_{\max} com passo fixo medido acima; ou §5.8 e §7.1 de Mathematics for Machine Learning, de Deisenroth, Faisal e Ong, para o mesmo terreno com menos maquinaria; §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 tem a análise de minibatch com mais medições do que há espaço para incluir aqui; e o capítulo 4 de Hands-On Machine Learning, de Géron (3.ª ed.), o tratamento mais prático da learning rate como algo que se afina em vez de se derivar. As notas do MIT 6.390 colocam gradient descent antes da classificação, como este curso faz e pela mesma razão.

  1. LeCun, Y., Bottou, L., Orr, G. B. and Müller, K.-R. Efficient BackProp, in Neural Networks: Tricks of the Trade (Springer, 1998), pp. 9–50. A secção 4.3 dá a recomendação e a secção 5.1 o argumento usado na caixa de detalhe acima: centrar e escalar entradas altera os valores próprios da matriz das 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. and 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, os pontos críticos são esmagadoramente pontos de sela e não mínimos locais, já que um mínimo exige que cada uma de milhares de direções curve para cima ao mesmo tempo.

  3. Robbins, H. and 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, dado um tamanho de passo que encolhe da forma certa.

  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 heavy-ball, que é a atualização com momentum acima, vinte e dois anos antes de backpropagation chegar a este campo.

Pronto para deixar a LIA escolher?

Construa com todos os modelos de IA num só sítio — comece grátis hoje.