Kurs uczenia maszynowego od zera · Lekcja 3.3 · 16 z 33 gotowych lekcji · 12 min
Krzywe uczenia: więcej danych czy lepszy model?
W skrócie
Krzywe uczenia pokazują wynik na treningu i walidacji, gdy danych przybywa. Z ich kształtu wiesz, czy zbierać dane, czy zmienić model na bogatszy.
Rozgrzewka Dwa pytania z wcześniejszych lekcji. Minuta, a lekcji nie blokuje.
W lekcji 3.1 model był za prosty albo za złożony, a danych było tyle samo. Dziś zmieniasz liczbę danych. To codzienne pytanie praktyka: model działa średnio, więc zbierać więcej przykładów czy zmienić model? Odpowiedź daje krzywa uczenia: wynik na treningu i na walidacji, rysowany dla coraz większego zbioru do nauki.
Wybierz odpowiedź i pewność.
Odpowiedz, żeby odblokować lab.
Eksperyment
Ten interaktywny eksperyment działa w przeglądarce z włączonym JavaScriptem. Tekst wokół opisuje, co w nim widać.
Pokaż odpowiedź
Poprawna odpowiedź: Około 82%, czyli o kilkanaście punktów mniej niż na treningu
Walidacja ma 82,3% (średnia z 5 losowań 50 obrazów), więc luka wynosi 17,7 pkt proc. Na pełnym treningu, 1438 obrazach, walidacja rośnie do 95,8%, a luka maleje do 2,2 pkt proc. Przy małych danych 100% na treningu to w dużej części pamięć.
Spróbuj
- Przy modelu szczegółowym przesuwaj suwak od 50 do 1438 obrazów. Która krzywa się zmienia bardziej: treningu czy walidacji?
- Przełącz na model rozmytych cyfr. Gdzie spotykają się jego krzywe i jak wysoko?
- Porównaj model szczegółowy przy 100 obrazach z modelem rozmytym przy 1438. Który wygrywa?
Gdy już sprawdzisz to w labie, nazwijmy, co widzisz.
Pomysł w prostych słowach
Krzywa uczenia to dwie linie: trafność na danych do nauki i na walidacji, w zależności od liczby przykładów do nauki. Przy kilkudziesięciu obrazach model zapamiętuje każdy z nich: trening ma 100%, a walidacja 82,3%. Im więcej danych, tym trudniej wszystko zapamiętać, więc trening spada (do 98,0%), a walidacja rośnie (do 95,8%). Luka między nimi maleje z 17,7 do 2,2 pkt proc.
Z kształtu tych linii czytasz decyzję:
- Duża luka, walidacja wciąż rośnie (wysoka wariancja): model zna trening dużo lepiej niż nowe dane. Więcej danych pomoże, podobnie jak regularyzacja.
- Mała luka, obie linie nisko (wysokie obciążenie): model jest za prosty. Krzywe się zeszły i więcej danych prawie nic nie da. Pomoże bogatszy model albo lepsze cechy.
Model rozmytych cyfr widzi każdą cyfrę jako obrazek 4 × 4, czyli 16 pikseli zamiast 64. Przy 1438 obrazach ma na treningu 86,9%, na walidacji 85,0%, luka to tylko 1,9 pkt proc. Walidacja zwykle nie wychodzi ponad trening, a ten ma tylko 86,9%. Model szczegółowy przy zaledwie 100 obrazach ma już 87,6%.
Jak to policzono
- Cyfry: Optical Recognition of Handwritten Digits, UCI, licencja CC BY 4.0. 1797 obrazów 8 × 8 pikseli, 10 cyfr.
- Podział 80/20 ze stratyfikacją, taki sam jak w widżecie Atlasu: 1438 obrazów do nauki, 359 do walidacji. Dla każdego rozmiaru średnia z 5 losowań, które obrazy idą do nauki.
- Model: regresja logistyczna (softmax) z karą 0,001 za duże wagi. Model rozmyty widzi średnie bloków 2 × 2 pikseli.
Dlaczego to działa
Na treningu model widzi odpowiedzi, więc przy małych danych może je zapamiętać. Każdy nowy przykład utrudnia zapamiętywanie, a ułatwia znalezienie reguły, która działa też poza treningiem. Dlatego linie idą ku sobie: trening w dół, walidacja w górę. Spotkają się na poziomie, który ten model w ogóle potrafi osiągnąć.
Ten poziom zależy od modelu, nie od danych. Rozmyty obrazek gubi szczegóły, które odróżniają na przykład 3 od 8, i żadna liczba przykładów ich nie odda. W kodzie niżej ten sam eksperyment idzie na 50 różnych podziałach: model rozmyty ma przy pełnych danych 86,4% na treningu i 85,1% na walidacji, a szczegółowy 96,6% na walidacji. Szczegółowy model ze 100 obrazów bije rozmyty z 1437 obrazów w 49 podziałach na 50.
Częsty błąd
Prawda czy fałsz: „więcej danych zawsze pomaga”. Fałsz. Więcej danych pomaga, gdy model jest za mocny jak na ilość danych: wtedy luka jest duża, a walidacja rośnie. Gdy model jest za prosty, krzywe szybko się schodzą i stoją. W labie model rozmyty ma przy 400 obrazach 83,6% na walidacji, a przy prawie czterokrotnie większym zbiorze 85,0%. Model szczegółowy przy tych samych danych ma 95,8%. Zanim zapłacisz za zebranie danych, narysuj krzywą uczenia: jeśli trening sam stoi nisko, dane nie pomogą.
Uwaga: krzywe rysuj na walidacji albo w walidacji krzyżowej, nie na zbiorze testowym. Test zostaje na samą ocenę końcową.
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
- Krzywa uczenia to wynik na treningu i walidacji dla coraz większego zbioru do nauki.
- Duża luka i rosnąca walidacja: model zapamiętuje, więcej danych pomoże.
- Mała luka przy niskim wyniku: model jest za prosty, pomoże bogatszy model albo lepsze cechy, nie więcej danych.
- Narysuj krzywą, zanim zapłacisz za dane; rysuj ją na walidacji, a test zostaw na koniec.
Głębiej: wzór, kod, praktyka
Matematyka
Niech A_tr(n) i A_wal(n) to trafność na n przykładach do nauki i na walidacji. Krzywa uczenia to obie funkcje n. Zwykle A_tr(n) maleje, A_wal(n) rośnie, a obie zbliżają się do tego samego poziomu A*, najlepszej trafności, jaką osiąga ta rodzina modeli.
Luka A_tr(n) − A_wal(n) mierzy wariancję: jak bardzo wynik zależy od tego, które przykłady trafiły do nauki. Odległość 1 − A to obciążenie tej rodziny modeli razem z szumem, którego nie usunie żaden model (cyfry nieczytelne nawet dla człowieka): tego żadne dane nie usuną. Więcej danych zmniejsza lukę, a tylko zmiana modelu podnosi A.
Regresja logistyczna w labie minimalizuje L = średnia strata + (λ / 2) · ‖W‖² z λ = 0,001. W scikit-learn ta sama kara to C = 1 / (λ · n) = 1000 / n.
W kodzie (Python)
Ten sam eksperyment w scikit-learn na 50 różnych podziałach: model na 64 pikselach i na cyfrze rozmytej do 16 pikseli, przy rosnącej liczbie obrazów do nauki.
import numpy as np
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
X, y = load_digits(return_X_y=True)
X = X / 16 # 8 × 8 = 64 piksele od 0 do 1, jak w labie
X16 = X.reshape(-1, 4, 2, 4, 2).mean(axis=(2, 4)).reshape(len(X), -1) # ta sama cyfra rozmyta do 4 × 4 = 16 pikseli
def run(Z, n, seed):
Xtr, Xva, ytr, yva = train_test_split(Z, y, test_size=0.2, stratify=y, random_state=seed)
i = np.random.default_rng(seed).permutation(len(ytr))[:n] # pierwsze n obrazów treningowych po przetasowaniu
m = LogisticRegression(C=1000 / n, max_iter=5000).fit(Xtr[i], ytr[i]) # C = 1000 / n to kara 0,001 z labu
return m.score(Xtr[i], ytr[i]), m.score(Xva, yva)
for name, Z in (("64 pixels", X), ("16 pixels", X16)):
for n in (50, 100, 400, 800, 1437):
tr, va = np.mean([run(Z, n, s) for s in range(50)], axis=0) # średnia z 50 różnych podziałów
print(f"{name}, {n} images: training {tr:.1%}, validation {va:.1%}, gap {(tr - va) * 100:.1f} points")
wins = sum(run(X, 100, s)[1] > run(X16, 1437, s)[1] for s in range(50))
print(f"64 pixels from 100 images beat 16 pixels from 1437 images in {wins} of 50 splits")
Wynik
64 pixels, 50 images: training 100.0%, validation 81.2%, gap 18.8 points
64 pixels, 100 images: training 100.0%, validation 89.5%, gap 10.5 points
64 pixels, 400 images: training 99.7%, validation 94.9%, gap 4.8 points
64 pixels, 800 images: training 99.0%, validation 96.0%, gap 2.9 points
64 pixels, 1437 images: training 98.2%, validation 96.6%, gap 1.6 points
16 pixels, 50 images: training 98.5%, validation 72.6%, gap 25.9 points
16 pixels, 100 images: training 94.1%, validation 79.8%, gap 14.4 points
16 pixels, 400 images: training 87.7%, validation 83.8%, gap 3.8 points
16 pixels, 800 images: training 86.9%, validation 84.6%, gap 2.3 points
16 pixels, 1437 images: training 86.4%, validation 85.1%, gap 1.3 points
64 pixels from 100 images beat 16 pixels from 1437 images in 49 of 50 splits
Lab pokazuje jeden podział i 5 losowań, kod 50 podziałów, więc liczby są trochę inne: przy 50 obrazach walidacja ma w labie 82,3%, a średnio 81,2%. Kształt krzywych i wniosek są te same.
Pobierz notebook (.ipynb). Otwórz go w Jupyterze albo wgraj do Google Colab; brakujące dane pobierze sam.
Dla praktyka
- W scikit-learn krzywe daje
learning_curve(z walidacją krzyżową) iLearningCurveDisplay. Dla klasyfikacji używajStratifiedKFold, żeby każdy rozmiar miał wszystkie klasy. - Oś liczby przykładów rysuj w skali logarytmicznej: postęp przy podwajaniu danych jest wtedy lepiej widoczny.
- Krzywa walidacji (
validation_curve) to coś innego: wynik w zależności od ustawienia modelu, np. siły regularyzacji, przy stałych danych. - Zanim zbierzesz dane, oszacuj, ile da podwojenie: jeśli ostatnie podwojenie dało ułamek punktu, następne da jeszcze mniej.
Czy to było pomocne?
Dzięki! To pomaga nam poprawiać Atlas.
Więcej w Atlasie
Hasła encyklopedii o pojęciach z tej lekcji: