Kurs: sieci neuronowe od środka · Lekcja 6 z 12 · 14 min
Krok, paczka i optymalizator
W skrócie
Gradient mówi, w którą stronę iść. Jak daleko, na ilu przykładach go liczyć i jak łączyć kolejne kroki, decydują krok uczenia, paczka i optymalizator.
Rozgrzewka Dwa pytania z kursu ML, na których ta lekcja się opiera. Minuta, a lekcji nie blokuje.
Propagacja wsteczna z lekcji 5 daje gradient: dla każdej wagi kierunek, w którym strata rośnie. Zostają trzy decyzje. Krok uczenia η mówi, jak daleko pójść w przeciwną stronę. Paczka mówi, na ilu przykładach liczyć gradient przed jednym krokiem. Optymalizator mówi, jak z gradientów zrobić krok: wprost, z rozpędem albo z osobną skalą dla każdej wagi. Epoka to jedno przejście przez wszystkie przykłady treningowe.
Wybierz odpowiedź i pewność.
Odpowiedz, żeby odblokować lab.
Pokaż odpowiedź
Poprawna odpowiedź: Paczka po 1 przykładzie
Paczka po 1 przykładzie robi 2495 kroków i kończy ze stratą 0,10. Cały zbiór robi 5 kroków i kończy ze stratą 2,29, prawie tam, gdzie zaczął (2,42).
Spróbuj
- Lab startuje z Adamem i krokiem 0,001: po 10 epokach 93,6% cyfr testowych.
- Wybierz SGD i znajdź krok, przy którym trafność przekracza 90%. To cel labu.
- Porównaj SGD z momentem przy kroku 0,01 i zwykły SGD przy 0,1: 93,6% i 94,2%.
- Wybierz Adama i krok 0,5. Zobacz, co się dzieje z krzywą trafności.
Pomysł w prostych słowach
Gradient z jednego przykładu jest tani, ale chwiejny: jedna cyfra ciągnie wagi w swoją stronę. Gradient z całego zbioru jest dokładny, ale drogi, i daje jeden krok na epokę. Paczka jest pośrodku: w labie 32 cyfry, czyli 45 kroków na epokę, 450 kroków w 10 epok. Na karcie graficznej przykłady z jednej paczki liczą się równolegle.
Krok uczenia to długość kroku. Za mały i wagi prawie stoją: zwykły SGD przy kroku 0,01 kończy z 73,8%. Za duży i wagi przeskakują dolinę straty, zamiast do niej zejść.
Moment dodaje rozpęd: krok to suma bieżącego gradientu i 0,9 poprzedniego kroku. Gdy kolejne gradienty wskazują podobnie, krok rośnie. Adam idzie dalej: każdą wagę przesuwa o krok podzielony przez typową wielkość jej gradientu, więc wagi z małym gradientem też się ruszają.
Dlaczego to działa
W przewidywaniu wygrała liczba kroków, nie dokładność gradientu. Przy równych 200 krokach paczka 16 kończy ze stratą 0,72, a cały zbiór 0,71, choć przeliczył ok. 32 razy więcej przykładów. Paczka po 1 przykładzie po 200 krokach ma 0,99, bo widziała tylko 200 cyfr. Mała paczka daje więc dużo tanich kroków, a duża dokładne i drogie.
Moment 0,9 sumuje mniej więcej 10 ostatnich gradientów. Dlatego SGD z momentem przy kroku 0,01 daje prawie to samo co zwykły SGD przy kroku 10 razy większym.
Adam dzieli krok przez wielkość gradientu, więc rusza wagę o ułamek η, prawie niezależnie od skali gradientu. W labie w 1. epoce przy kroku 0,001 waga przesuwała się średnio o 0,42·η na krok, a przy SGD o 0,012·η. Dlatego SGD potrzebuje kroku co najmniej 0,1, a Adam działa już przy 0,001.
Częsty błąd
Prawda czy fałsz: „Adam działa zawsze, więc krok nie ma znaczenia.” Fałsz. W labie Adam przekracza 90% przy krokach 0,001, 0,01 i 0,1, ale przy 0,5 wagi wybijają się z doliny i trafność spada poniżej 25%, blisko zgadywania (10 cyfr, czyli 10%). Na pięciu startach wag Adam przy 0,5 nie przekroczył 25% ani razu. Najlepsze wyniki trzech optymalizatorów różnią się za to najwyżej o 2 pkt proc.: SGD 96,1%, SGD z momentem 98,1%, Adam 96,4%. To trafność przy kroku, który wypadł najlepiej na teście, więc trochę za optymistyczna; uczciwie krok wybiera się na walidacji. Adam nie jest lepszy, tylko wybacza więcej przy wyborze kroku.
Quiz
Trzy pytania na sprawdzenie się. Wybierz odpowiedź albo rozwiń odpowiedź pod pytaniem. Z klawiatury: strzałki wybierają, Enter albo spacja zatwierdza.
Najważniejsze wnioski
- Krok uczenia mówi, jak daleko iść; za mały stoi w miejscu, za duży przeskakuje dolinę.
- Mała paczka daje dużo tanich, chwiejnych kroków; duża mało dokładnych i drogich.
- Moment dodaje rozpęd i działa jak większy krok; Adam skaluje krok osobno dla każdej wagi.
- Adam wybacza więcej, ale też ma za duży krok; najlepsze wyniki optymalizatorów są podobne.
Głębiej: wzór, kod, praktyka
Matematyka
Gradient z paczki B przykładów: g = (1/B) · Σ ∇Lᵢ(w); kroków na epokę ⌈n / B⌉.
- SGD:
w ← w − η·g. - SGD z momentem:
v ← 0,9·v − η·g,w ← w + v. Przy stałym gradiencievdąży do−η·g / (1 − 0,9) = −10·η·g. - Adam:
m ← 0,9·m + 0,1·g,s ← 0,999·s + 0,001·g²,w ← w − η · m̂ / (√ŝ + ε), gdziem̂,ŝtom,sz poprawką na start: podzielone przez1 − 0,9ᵗi1 − 0,999ᵗ. - Zwykły SGD na dolinie o krzywiźnie
λjest stabilny tylko przyη < 2/λ.
W kodzie (Python)
Dwie rzeczy w numpy: ile kroków dają różne paczki w 5 epokach na 499 cyfrach i trzy reguły kroku na wydłużonej dolinie:
import numpy as np
# kroki w 5 epokach na 499 cyfrach: im mniejsza paczka, tym więcej kroków
n = 499
for B in [1, 4, 16, 64, n]:
steps = int(np.ceil(n / B))
print(f"batch {B:3d}: {steps:3d} per epoch, {5 * steps:4d} steps in 5 epochs")
# wydłużona dolina: strata L(w) = (w1^2 + 10 w2^2) / 2, start (3, 1), 50 kroków
grad = lambda w: np.array([w[0], 10 * w[1]])
loss = lambda w: (w[0] ** 2 + 10 * w[1] ** 2) / 2
def run(rule, lr, steps=50):
w, vel, m, v = np.array([3.0, 1.0]), np.zeros(2), np.zeros(2), np.zeros(2)
for t in range(1, steps + 1):
g = grad(w)
if rule == "sgd":
w = w - lr * g
elif rule == "momentum":
vel = 0.9 * vel - lr * g
w = w + vel
else: # adam
m = 0.9 * m + 0.1 * g
v = 0.999 * v + 0.001 * g ** 2
w = w - lr * (m / (1 - 0.9 ** t)) / (np.sqrt(v / (1 - 0.999 ** t)) + 1e-8)
return loss(w)
print("loss after 50 steps (start 9.5)")
for rule in ["sgd", "momentum", "adam"]:
print(f"{rule:8s}", " ".join(f"lr {lr}: {run(rule, lr):9.3g}" for lr in [0.01, 0.1, 0.25]))
Wynik
batch 1: 499 per epoch, 2495 steps in 5 epochs
batch 4: 125 per epoch, 625 steps in 5 epochs
batch 16: 32 per epoch, 160 steps in 5 epochs
batch 64: 8 per epoch, 40 steps in 5 epochs
batch 499: 1 per epoch, 5 steps in 5 epochs
loss after 50 steps (start 9.5)
sgd lr 0.01: 1.65 lr 0.1: 0.00012 lr 0.25: 2.03e+18
momentum lr 0.01: 0.0376 lr 0.1: 0.0323 lr 0.25: 0.0154
adam lr 0.01: 4.59 lr 0.1: 0.0144 lr 0.25: 0.0184
Zwykły SGD przy kroku 0,25 wybucha: krzywizna doliny wzdłuż w₂ to 10, a SGD jest tu stabilny tylko przy kroku poniżej 2/10 = 0,2. Moment przy tym samym kroku zostaje stabilny. Adam przy 0,01 prawie stoi, bo rusza każdą wagę o mniej więcej długość kroku: w 50 krokach przeszedł niecałe 0,5 z drogi 3. Uruchomione w numpy 2.1.3.
Pobierz notebook (.ipynb). Otwórz go w Jupyterze albo wgraj do Google Colab; brakujące dane pobierze sam.
Dla praktyka
- Na start: Adam z krokiem 0,001 i paczka 32. Krok 0,001 to domyślny krok Adama w PyTorch i Keras, a 32 to domyślna paczka w Keras.
- Strata skacze albo rośnie? Zmniejsz krok kilka razy. Strata spada bardzo powoli? Zwiększ go. Krok sprawdzaj w skali logarytmicznej, jak w labie: 0,0001, 0,001, 0,01, 0,1.
- Długi trening zwykle zaczyna większym krokiem i kończy mniejszym. To harmonogram kroku (hasło „Harmonogramy współczynnika uczenia”).
- Porównując optymalizatory, daj każdemu jego najlepszy krok. Porównanie przy jednym, wspólnym kroku mierzy dopasowanie kroku, a nie optymalizator.
Więcej w Atlasie
Hasła encyklopedii o pojęciach z tej lekcji: