Ansámbly: náhodný les a gradient boosting
Moudrost davu a proč musí být chyby nezávislé, bagging, náhodný les a korelace stromů, odhad chyby z vynechaných vzorků, gradient boosting a rychlost učení — na datech o splácení půjček.
Série Základy AI Díl 54 z 83
- Mapa umělé inteligence: co je co a jak to do sebe zapadá
- Stručná historie umělé inteligence: od Turinga po jazykové modely
- Data, model, trénink, inference: základní pojmy na jednom příkladu
- Jak číst matematický zápis: symboly, indexy, sumy a kvantifikátory
- Množiny a relace: stavebnice, ze které se skládají definice v AI
- Funkce a zobrazení: proč je každý model v AI funkce
- Logika a důkazy: pravidla, podle kterých se v AI uvažuje
- Grafy a stromy: struktura, na které stojí hledání i neuronové sítě
- Lineární algebra pro strojové učení: vektory, matice a proč AI hlavně násobí
- Derivace, gradient a řetízkové pravidlo: jak model zjistí, kterým směrem se učit
- Gradientní sestup: jak se model učí
- Co je pravděpodobnost: od hodu kostkou ke Kolmogorovovým axiomům
- Podmíněná pravděpodobnost a Bayesova věta: jak změnit odhad, když se dozvíte něco nového
- Náhodná veličina a distribuční funkce: jedna funkce, která o rozdělení řekne všechno
- Funkce hustoty a pravděpodobnostní funkce: proč má spojitá veličina v bodě pravděpodobnost nula
- Střední hodnota, rozptyl a kovariance: kde rozdělení leží, jak je široké a co s čím souvisí
- Přehled pravděpodobnostních rozdělení: Bernoulli, binomické, Poisson, rovnoměrné, normální a exponenciální
- Zákon velkých čísel a centrální limitní věta: proč se průměry chovají tak předvídatelně
- Statistika a odhady parametrů: maximální věrohodnost, MAP a intervaly spolehlivosti
- Teorie informace: entropie, křížová entropie a KL divergence — odkud se berou ztrátové funkce
- Prohledávání stavového prostoru: BFS, DFS, UCS a A* s animacemi
- Hry a protivník: minimax, alfa-beta ořezávání a Monte Carlo tree search
- Splňování omezujících podmínek: backtracking, propagace omezení a AC-3 na sudoku a mapě krajů
- Logika a znalostní systémy: dopředné a zpětné řetězení, rezoluce a expertní systémy
- Plánování: STRIPS, svět kostek, heuristiky z relaxace a plánování v AI agentech
- Lokální hledání a simulované žíhání: obchodní cestující přes krajská města
- Genetické algoritmy: populace, křížení, mutace a výběr na batohu na výlet
- Evoluční strategie a genetické programování: od pravidla jedné pětiny po Keplerův zákon
- Optimalizace mravenčí kolonií: jak feromonová stopa najde krátkou cestu
- Optimalizace hejnem částic: setrvačnost, vlastní zkušenost a zkušenost hejna
- Neuroevoluce: evoluce vah i tvaru neuronových sítí a algoritmus NEAT
- Fuzzy množiny a funkce příslušnosti: jak zapsat „trochu teplo“
- Fuzzy logika a pravděpodobnost: proč „trochu teplo“ neznamená „pravděpodobně teplo“
- Fuzzy logika: t-normy, implikace a pravidla KDYŽ–PAK
- Fuzzy řízení: Mamdani a Sugeno od ventilátoru po kyvadlo na vozíku
- Fuzzy shlukování: algoritmus fuzzy c-means a body mezi shluky
- Neuro-fuzzy systémy (ANFIS): fuzzy pravidla, která se učí z dat
- Markovovy řetězce: přechodová matice, stacionární rozdělení a PageRank
- Skryté Markovovy modely: Viterbiho algoritmus a nepoctivé kasino
- Bayesovské sítě: proč je tráva mokrá a co z toho plyne pro postřikovač
- Kalmanův filtr: jak z nepřesných měření odhadnout, kde auto je a jak rychle jede
- Druhy strojového učení: s učitelem, bez učitele, s částečným učitelem a další
- Přeučení a regularizace: proč model, který zná data nazpaměť, selže
- Vyhodnocení modelu: křížová validace, F1 a křivka ROC
- Shlukování a snížení dimenze: k-means, PCA a t-SNE
- Klasifikace a regrese: dvě úlohy učení s učitelem
- Lineární regrese: nejmenší čtverce geometricky i maticově
- Polynomiální a nelineární regrese: jak přímku ohnout
- Logistická regrese: sigmoida, šance a křížová entropie
- Vícetřídní klasifikace a softmax: od dvou tříd k mnoha
- Naivní Bayesův klasifikátor: spamový filtr, který funguje lépe, než by měl
- Ztrátové funkce: co přesně model minimalizuje
- Rozhodovací stromy a k nejbližších sousedů: modely bez vzorců
- Ansámbly: náhodný les a gradient boosting
- SVM a jádrový trik: nejširší hranice a jak ji ohnout
- Signál a vzorkování: proč platí Nyquistův teorém
- Fourierova transformace: rozklad signálu na frekvence
- Filtry a konvoluce: vyhlazení, hrany a odstranění šumu
- Zvuk a řeč: spektrogram, melová škála a MFCC
- Obraz jako signál: pixely, barvy, konvoluce a hrany
- Perceptron a umělý neuron: nejjednodušší neuronová síť a co neumí
- Neuronová síť od nuly: zpětné šíření chyby krok za krokem
- Aktivace, inicializace a normalizace: drobnosti, na kterých hluboká síť stojí
- Konvoluční sítě: jak síť poznává obrázky
- Rekurentní sítě: paměť pro posloupnosti a mizející gradient
- LSTM a GRU: brány, které rozhodují, co si síť zapamatuje
- Autoenkodéry: síť, která se učí data stlačit a zase rozbalit
- Embeddingy a word2vec: jak se slovo stane vektorem
- Mechanismus pozornosti: jak se model naučí, kam se dívat
- Transformery a velké jazykové modely: architektura krok za krokem
- Tokenizace: jak se text rozseká na kousky pro model
- Předtrénování a škálování: proč větší model a víc dat funguje
- Doladění a RLHF: jak se z doplňovače textu stane asistent
- Prompty, kontext a RAG: jak modelu dát správné informace
- Variační autoenkodéry (VAE): nové obrázky ze spojitého latentního prostoru
- Generativní adversariální sítě (GAN): padělatel proti detektivovi
- Difúzní modely: jak se z čistého šumu stane obrázek
- Markovovy rozhodovací procesy: stavy, akce, odměny a Bellmanovy rovnice
- Q-learning a DQN: učení hodnoty akcí od tabulky po neuronovou síť
- Policy gradient a PPO: učení přímo strategie
- Jak funguje AI agent: jazykový model ve smyčce s nástroji
- Programování s AI agenty: zadání, testy a kontrola
- Vyhodnocení a bezpečnost AI systémů: jak měřit a jak hlídat
Celá osnova série 83 z 83 témat hotovo
- Proč hlasování mnoha modelů funguje jen tehdy, když se mýlí nezávisle.
- Jak bagging a náhodný les zkrotí přecitlivělé stromy.
- Jak gradient boosting opravuje chyby krok za krokem a proč hlídat počet kroků.
Co se hodí znát předem: Rozhodovací stromy a k nejbližších sousedů: modely bez vzorců
Roku 1906 nechal statistik Francis Galton na dobytčím trhu 787 lidí hádat váhu vola. Jednotlivé tipy byly všelijaké, ale jejich střed (medián) se od skutečnosti lišil o necelé procento. Na stejném principu stojí jedny z nejúspěšnějších modelů strojového učení: místo jednoho chytrého modelu jich naučit sto hloupějších a nechat je hlasovat. V soutěžích na tabulková data (ceny, pojištění, podvody) takové ansámbly stromů dodnes porážejí i neuronové sítě.
Navazuje na díl Rozhodovací stromy a k nejbližších sousedů; pracujeme se stejnými daty o splácení půjček.
1. Moudrost davu — a její podmínka
Definice — ansámbl
Nechť 𝒳 je množina vstupů, B ≥ 2 a h1, …, hB jsou modely definované na 𝒳 (v klasifikaci s hodnotami v konečné množině tříd 𝒞, v regresi v ℝ). Ansámbl těchto modelů je model F na 𝒳, jehož předpověď vznikne kombinací předpovědí h1(x), …, hB(x), obvykle jedním z těchto předpisů:
- hlasování (klasifikace): F(x) = argmaxc ∈ 𝒞 |{b ∈ {1, …, B} : hb(x) = c}|;
- průměr pravděpodobností (klasifikace, dává-li každý model odhady p̂b(c | x)): F(x) = argmaxc ∈ 𝒞 1/B ∑b=1B p̂b(c | x);
- (vážený) průměr (regrese): F(x) = ∑b=1B wb hb(x) s vahami wb ≥ 0, ∑b wb = 1 (prostý průměr pro wb = 1/B).
Ansámbl je tedy model složený z více modelů, jejichž předpovědi se zkombinují.
Představte si poradce, z nichž každý má pravdu v 60 % případů. Jeden je skoro k ničemu. Když se ale zeptáte jedenácti a uděláte, co řekne většina, máte pravdu v 75,3 % případů; se 101 poradci v 97,9 %. Chyby jednotlivců se navzájem vyruší — pokud jsou nezávislé. Když v 30 % případů všichni opíšou jednoho názorového vůdce, ani 1 001 poradců nepřekročí 88,0 %: dav, který si opisuje, je jen jeden hlas mnohokrát.
Věta — Condorcetova věta o porotě
Nechť n ∈ ℕ je liché, p ∈ (0, 1) a X1, …, Xn jsou nezávislé náhodné veličiny s P(Xi = 1) = p a P(Xi = 0) = 1 − p (Xi = 1 znamená, že i-tý hlasující má pravdu). Označme
Pn = P(X1 + … + Xn > n/2)
pravděpodobnost, že většina má pravdu. Pak Pn je dána vzorcem níže a platí:
- je-li p > 1/2, pak Pn s rostoucím lichým n roste a Pn → 1 pro n → ∞;
- je-li p < 1/2, pak Pn s rostoucím lichým n klesá a Pn → 0.
Proč: počet správných hlasů X1 + … + Xn má binomické rozdělení se střední hodnotou np a směrodatnou odchylkou √np(1 − p). Většina potřebuje víc než n/2; pro p > 1/2 je odstup n(p − 1/2) úměrný n, kdežto typická odchylka od střední hodnoty roste jen jako √n, takže je odstup čím dál bezpečnější. Tvrzení vyslovil markýz de Condorcet roku 1785; dnešní zápis se vzorcem je pozdější formalizace.
Pn = ∑k = n + 1/2n C(n, k) · pk (1 − p)n−k
- Pn
- pravděpodobnost, že většina z n nezávislých hlasujících má pravdu — zelená křivka v obrázku
- k ≥ n + 1/2
- sčítá se jen přes ty počty správných hlasů, které tvoří většinu; u 11 hlasujících je to 6 až 11
- C(n, k)
- kombinační číslo: kolika způsoby lze vybrat, kteří z hlasujících mají pravdu — na tom výsledek nezávisí, ale každý takový výběr je jiná možnost
- pk (1 − p)n−k
- pravděpodobnost jednoho konkrétního výběru: k hlasujících má pravdu a zbylých n − k se mýlí; násobí se, protože jsou nezávislí
Příklad — tři poradci s 60 %
všichni tři mají pravdu (k = 3): C(3, 3) · 0,63 = 1 · 0,216 = 0,216
právě dva (k = 2): C(3, 2) · 0,62 · 0,4 = 3 · 0,36 · 0,4 = 0,432
P3 = 0,216 + 0,432 = 0,648 (z 60 % na 64,8 %); P11 = 0,753, P101 = 0,979
Barvy odpovídají členům vzorce pro Pn výše.
Opisování popisuje náš jednoduchý model závislosti (vlastní zjednodušení pro tento díl): s pravděpodobností ρ všichni zopakují názor jednoho vůdce, jinak hlasují nezávisle.
Pzáv = ρ · p + (1 − ρ) · Pn
- Pzáv
- pravděpodobnost, že má většina pravdu, když se opisuje — jantarová křivka v obrázku
- ρ · p
- všichni opsali vůdce (s pravděpodobností ρ) a ten měl pravdu (p); celý dav je tu jediný hlas a víc hlasujících nepomůže
- 1 − ρ
- pravděpodobnost, že se tentokrát neopisuje
- Pn
- pak platí Condorcetův vzorec pro nezávislé — tato část s rostoucím n jde k 1
Celé umění ansámblů je proto v jediné otázce: jak naučit mnoho modelů, které jsou každý slušný, a přitom se mýlí v různých případech?
2. Bagging: stejný model, jiná data
Definice — bootstrap a bagging
Nechť n ≥ 1 a D = ((x1, y1), …, (xn, yn)) jsou trénovací data. Nechť I1, …, In jsou nezávislé náhodné veličiny s rovnoměrným rozdělením na {1, …, n}, tj. P(Ij = i) = 1/n pro všechna i, j ∈ {1, …, n}. Bootstrapový výběr z D je posloupnost
D* = ((xI1, yI1), …, (xIn, yIn)),
tedy n příkladů vybraných náhodně s vracením: některé se opakují, jiné chybí.
Bagging (bootstrap aggregating; Leo Breiman, 1996) je algoritmus:
- Vstup: trénovací data D, počet modelů B ≥ 1 a učicí algoritmus 𝒜, který z dat vyrobí model (u nás hluboký rozhodovací strom).
- Výstup: ansámbl F.
- Pro b = 1, …, B: vylosuj (nezávisle na ostatních) bootstrapový výběr D*b z D a nauč model hb = 𝒜(D*b).
- Po B modelech skonči a vrať ansámbl: v regresi F(x) = 1/B ∑b=1B hb(x), v klasifikaci hlasování modelů h1, …, hB.
Hluboký strom je přecitlivělý: malá změna dat ho přestaví. Normálně je to vada — tady se z ní stane výhoda. Každý strom dostane trochu jinou verzi dat, vyroste trochu jinak a přeučí se na jiném šumu. Když jich zprůměrujeme dvě stě, náhodné výkyvy se vyruší a zůstane to, na čem se shodnou.
Jeden hluboký strom na našich datech (nechaný růst, dokud nejsou listy čisté) má na 4 000 nových klientech přesnost 86,5 %. Bagging z deseti takových stromů má 88,5 %, z dvou set 89,3 %.
Algoritmus — bagging a náhodný les
def les(D, B, m): # m = 2: bagging, m = 1: náhodný les (u nás)
stromy = []
for b in range(B):
idx = [nahodne_cele(0, n − 1) for _ in range(n)] # s vracením
stromy.append(postav_hluboky([D[i] for i in idx], m))
return stromy
def postav_hluboky(D, m): # CART bez omezení hloubky
if D je čistá: return List(třída)
kandidati = náhodný výběr m příznaků z p # jen v náhodném lese m < p
najdi nejlepší práh jen mezi kandidáty (Giniho nečistota)
return Uzel(…, ano=postav_hluboky(L, m), ne=postav_hluboky(P, m))
def hlas(stromy, x):
return sum(strom(x) for strom in stromy) / len(stromy) # podíl hlasů „splatí“
Předpověď je „splatí“, když hlas ≥ 0,5. Stromy na sobě nezávisí, takže je jde stavět paralelně — na rozdíl od boostingu níže.
3. Náhodný les: ještě víc náhody
Definice — náhodný les
Nechť příklady mají p ≥ 1 příznaků, m ∈ {1, …, p} a B ≥ 1. Náhodný les (random forest; Breiman, 2001) s B stromy je bagging, ve kterém učicí algoritmus 𝒜 je CART (viz díl Rozhodovací stromy) bez omezení hloubky s touto změnou:
- v každém uzlu se nezávisle na ostatních uzlech vylosuje množina příznaků M ⊆ {1, …, p}, |M| = m, rovnoměrně ze všech m-prvkových podmnožin;
- nejlepší dělení (s nejmenší váženou Giniho nečistotou) se hledá jen mezi příznaky j ∈ M.
Typicky se volí m ≈ √p; pro m = p je náhodný les obyčejný bagging stromů.
I na různých bootstrapových výběrech se stromy často ptají na totéž — první otázka bývá skoro vždy „příjem ≤ 40 tisíc?“. Náhodný les jim to zakáže: v každém uzlu smí strom vybírat jen z náhodné části příznaků. U nás jsou příznaky jen dva, takže v každém uzlu dostane strom náhodně buď příjem, nebo věk. Jednotlivé stromy tím trochu zhloupnou, ale přestanou si být podobné.
Měřitelně: korelace chyb dvou náhodně vybraných stromů je u baggingu 0,53, v náhodném lese 0,42. Les z 200 stromů má přesnost 90,2 % (nejvíc 90,5 % s 25 stromy). Strop daný šumem v datech je 91,5 %.
Proč na korelaci tolik záleží, ukazuje vzorec pro rozptyl průměru B stejně rozptýlených předpovědí, z nichž každé dvě mají korelaci ρ (Hastie, Tibshirani, Friedman: The Elements of Statistical Learning, 2. vyd., rovnice 15.1):
Var( 1/B ∑b hb(x) ) = ρ σ2 + (1 − ρ) σ2/B
- ρ σ2
- společná část chyb, kterou mají všechny stromy — průměrování ji neodstraní, ať je stromů kolik chce. Proto náhodný les snižuje ρ
- (1 − ρ) σ2
- vlastní, nesdílená část rozptylu každého stromu — ta, kterou se stromy mezi sebou liší
- B
- počet stromů; vlastní výkyvy se průměrováním vyruší, a proto se nesdílená část dělí B. Od několika desítek stromů je skoro nulová
Příklad — 200 stromů s našimi korelacemi
bagging, ρ = 0,53: 0,53 σ2 + 0,47 σ2/200 = 0,532 σ2
náhodný les, ρ = 0,42: 0,42 σ2 + 0,58 σ2/200 = 0,423 σ2
Barvy odpovídají členům vzorce výše.
Při 200 stromech je druhý člen zanedbatelný a o rozptylu rozhoduje skoro jen ρ. Je to jen přibližná ilustrace: vzorec platí pro průměr čísel, my jsme měřili korelaci chyb (indikátorů „strom se spletl“) a hlasování není prostý průměr. Směr ale sedí — méně korelované stromy dávají stabilnější les.
Obrázek ukazuje i druhý dar ansámblů: místo ostrých obdélníků jednoho stromu je hranice měkká a model ví, kde si není jistý — podíl stromů, které hlasují „splatí“, funguje jako pravděpodobnost. Schody tam pořád jsou, ale jemnější a zprůměrované.
4. Testovací data zadarmo: odhad z vynechaných
Definice — chyba z vynechaných vzorků (OOB)
Nechť D = ((x1, y1), …, (xn, yn)) jsou trénovací data s yi ∈ {0, 1} a h1, …, hB : 𝒳 → {0, 1} stromy baggingu nebo náhodného lesa, kde hb je naučený na bootstrapovém výběru D*b s vylosovanými indexy Ib1, …, Ibn. Pro i ∈ {1, …, n} označme
Oi = {b ∈ {1, …, B} : Ibj ≠ i pro všechna j = 1, …, n}
množinu stromů, které příklad i při učení neviděly, a H = {i : Oi ≠ ∅}. Pro i ∈ H je předpověď z vynechaných vzorků (out-of-bag, OOB) ŷi = 1, právě když 1/|Oi| ∑b ∈ Oi hb(xi) ≥ 1/2, jinak ŷi = 0. OOB přesnost je
|{i ∈ H : ŷi = yi}|/|H|,
a chyba z vynechaných vzorků je 1 minus OOB přesnost. Každý trénovací příklad se tedy předpoví jen hlasováním stromů, které ho při učení neviděly, a výsledek se porovná se skutečností. Bootstrapový výběr přitom vynechá každý příklad s pravděpodobností (1 − 1/n)n ≈ 1/e ≈ 36,8 % (věta níže).
Každý strom třetinu klientů nikdy neviděl, a ti pro něj fungují jako testovací data. Les si tak testovací sadu vyrobí sám, bez obětování dat. V našich lesích chybí v každém výběru průměrně 36,9 % klientů.
Věta — proč chybí zhruba třetina
Nechť n ≥ 1, D* je bootstrapový výběr z n příkladů (s indexy I1, …, In) a i ∈ {1, …, n}. Pak
P(Ij ≠ i pro všechna j) = (1 − 1/n)n a limn → ∞ (1 − 1/n)n = e−1 ≈ 0,368.
Důkaz. Při jednom losování se konkrétní příklad nevybere s pravděpodobností 1 − 1/n. Losování jsou nezávislá a je jich n, takže příklad chybí v celém výběru s pravděpodobností (1 − 1/n)n. Z ln(1 − 1/n) ≈ −1/n − 1/2n2 plyne n · ln(1 − 1/n) → −1, tedy (1 − 1/n)n → e−1. ∎
n = 200: 200 · ln(0,995) = 200 · (−0,0050125) = −1,0025, e−1,0025 = 0,3670
limita: e−1 = 0,3679; ve výběru je tedy v průměru 1 − 0,367 = 63,3 % různých klientů
Naměřených 36,9 % je průměr přes 200 skutečných výběrů — od teoretických 36,7 % se liší náhodou losování.
Algoritmus — odhad z vynechaných vzorků
dobre = hodnoceno = 0
for i, (x_i, y_i) in enumerate(D):
porota = [s for s in stromy if i not in s.vyber] # stromy, které i neviděly
if not porota: continue # (skoro nemožné: 0,633^200 ≈ 10^−40)
hlas = sum(s(x_i) for s in porota) / len(porota)
hodnoceno += 1
dobre += ((hlas >= 0.5) == y_i)
oob_presnost = dobre / hodnoceno
Každý klient je hodnocen „porotou“ asi 0,37 · 200 ≈ 73 stromů, ne celým lesem — i proto je odhad o něco pesimističtější.
OOB odhad dal pro bagging 85,0 % a pro les 86,0 %, na 4 000 nových klientech je skutečnost 89,3 % a 90,2 %. Odhad je tu o tři až čtyři body pesimistický: každý klient je hodnocen jen třetinou lesa, a hlavně je trénovacích klientů jen 200, takže i samotný odhad kolísá zhruba o ±2 procentní body. Při tisících příkladů bývá OOB odhad velmi blízko testovací chybě — a je to oblíbený způsob, jak les ladit bez křížové validace.
5. Boosting: modely, které opravují předchůdce
Bagging staví stromy vedle sebe, nezávisle. Boosting je staví za sebou: každý další se soustředí na to, co předchozí pokazily.
Definice — gradient boosting
Nechť (x1, y1), …, (xn, yn) jsou trénovací data s xi ∈ 𝒳 a yi ∈ {0, 1}, L(y, F) ztráta skóre F ∈ ℝ diferencovatelná podle F (u nás logistická, viz věta níže), M ∈ ℕ počet kroků a η ∈ (0, 1] rychlost učení (shrinkage). Gradient boosting (Jerome Friedman, 2001) je algoritmus:
- Vstup: trénovací data, ztráta L, M, η a maximální hloubka regresních stromů (u nás 2).
- Výstup: skórovací funkce FM : 𝒳 → ℝ; pravděpodobnost třídy 1 je σ(FM(x)).
- Polož F0(x) = c0 pro všechna x, kde c0 minimalizuje ∑i L(yi, c) (u logistické ztráty c0 = ln p̄/1 − p̄, p̄ = podíl jedniček).
- Pro m = 1, …, M:
- spočítej pseudorezidua ri = −∂L(yi, F)/∂F v bodě F = Fm−1(xi), i = 1, …, n (u logistické ztráty ri = yi − pi s pi = σ(Fm−1(xi)));
- nauč malý regresní strom hm : 𝒳 → ℝ na dvojicích (xi, ri);
- polož Fm(x) = Fm−1(x) + η · hm(x).
- Po M krocích skonči a vrať FM.
Model je tedy součet FM = F0 + η(h1 + … + hM), kde každý strom je naučený na záporný gradient ztráty podle F.
První strom udělá hrubý odhad. Druhý se podívá, kde se první spletl, a naučí se opravu. Třetí opravuje opravu — a tak dál. Je to gradientní sestup, jen místo vah posunujeme celou funkci a každý krok je malý strom. Stromy jsou schválně slabé (u nás hloubka 2, tedy čtyři listy) a každá oprava se započítá jen z části η, aby jeden strom nepřestřelil.
Fm(x) = Fm−1(x) + η · hm(x), p = σ(F)
- Fm(x)
- skóre modelu po m krocích (logaritmus šancí); sigmoida z něj udělá pravděpodobnost splacení jako v logistické regresi
- Fm−1(x)
- všechno, co už umí předchozí stromy — zůstává beze změny, nový strom ho jen opravuje
- η
- rychlost učení: oprava se započte jen z části, aby chyba jednoho slabého stromu nepřebila ostatní; menší η chce víc kroků, ale přeučí se pomaleji
- hm(x)
- nový malý strom naučený na rezidua y − p: tam, kde model podceňuje (y = 1, malé p), skóre zvedne, kde přeceňuje, sníží
Věta — rezidua jsou záporný gradient logistické ztráty
Nechť y ∈ {0, 1}, F ∈ ℝ a p = σ(F) = 1/1 + e−F ∈ (0, 1). Nechť
L(y, F) = −[y ln p + (1 − y) ln(1 − p)]
je logistická ztráta (křížová entropie) jednoho příkladu. Pak ∂L/∂F = p − y, tj. záporný gradient je reziduum y − p.
Důkaz: σ′(F) = p(1 − p), takže ∂L/∂F = −y · p(1 − p)/p + (1 − y) · p(1 − p)/1 − p = −y(1 − p) + (1 − y)p = p − y. ∎
Krok proti gradientu je tedy krok ve směru y − p. Gradientní sestup by posunul každé F(xi) zvlášť; boosting místo toho naučí strom, který tento směr přibližuje, a proto funguje i pro klienty, které nikdy neviděl. Hodnota listu je u nás Newtonův krok ∑ ri/∑ pi(1 − pi) přes klienty v listu (druhá derivace ztráty je p(1 − p)) — tak to dělá i Friedmanův algoritmus pro logistickou ztrátu.
Příklad — první krok boostingu na našich datech
start: p̄ = 140/200 = 0,7, F0 = ln 0,7/0,3 = 0,847 pro všechny klienty
rezidua: splácí → 1 − 0,7 = +0,3, nesplácí → 0 − 0,7 = −0,7; p(1 − p) = 0,21
první strom hloubky 2 má stejné otázky jako strom z minulého dílu; list „příjem ≤ 39,5, věk ≤ 47,6“: 47 klientů, splácí 4
hodnota listu h1(x) = 4 · 0,3 − 43 · 0,7/47 · 0,21 = −28,9/9,87 = −2,93
η = 0,1: F1 = 0,847 + 0,1 · (−2,928) = 0,847 − 0,293 = 0,554, p = σ(0,554) = 63,5 % → pořád „splatí“
η = 1: F1 = 0,847 + 1 · (−2,928) = −2,081, p = σ(−2,081) = 11,1 % → „nesplatí“
Barvy v posledních třech řádcích odpovídají členům vzorce Fm = Fm−1 + η · hm výše.
S η = 0,1 zůstanou po prvním kroku všechny čtyři listy nad 50 % (63,5 až 72,9 %), model tedy řekne „splatí“ každému — a přesnost 74,7 % je přesně podíl splácejících mezi novými klienty. S η = 1 je model po prvním kroku totéž co strom hloubky 2 (88,2 %).
Algoritmus — gradient boosting pro dvě třídy
def boosting(D, kroku, eta, hloubka=2):
F0 = log(prumer(y) / (1 − prumer(y)))
F = [F0] * n # skóre každého trénovacího klienta
stromy = []
for m in range(kroku):
p = [sigmoida(F[i]) for i in range(n)]
r = [y[i] − p[i] for i in range(n)] # záporný gradient
h = regresni_strom(D, r, hloubka) # dělení podle r
for list in h.listy: # Newtonův krok v každém listu
list.hodnota = sum(r[i]) / sum(p[i] * (1 − p[i])) # přes klienty v listu
F = [F[i] + eta * h(x[i]) for i in range(n)]
stromy.append(h)
return lambda x: sigmoida(F0 + eta * sum(h(x) for h in stromy))
Každý strom závisí na předchozích (přes p), takže se stromy stavějí za sebou. Počet kroků je hlavní pojistka proti přeučení.
S rychlostí učení 0,1 začíná boosting na 74,7 % (jediný slabý krok), po deseti krocích má 88,2 % a po padesáti 90,3 %. Pak ale pokračuje dál a začne se učit šum: po dvou stech krocích zná trénovací data nazpaměť a na nových klientech klesne na 89,2 %, po tisíci na 88,5 %. Boosting se — na rozdíl od lesa — přeučit umí, a počet kroků se proto volí na validační sadě (předčasné zastavení). S rychlostí učení 1 skočí na 88,2 % hned po prvním stromu, ale lepší než 88,5 % už nebude: velké kroky přeskakují jemné opravy. Malé η a víc kroků bývá skoro vždy lepší, jen pomalejší.
Předchůdcem gradient boostingu byl AdaBoost (Yoav Freund a Robert Schapire, 1995), který místo reziduí zvyšuje váhy špatně zařazených příkladů — a jak ukázal díl o ztrátových funkcích, minimalizuje exponenciální ztrátu. Dnešní knihovny jako XGBoost (2016), LightGBM a CatBoost jsou gradient boosting s mnoha inženýrskými triky.
6. Kdo vyhrál
| Model | přesnost na 4 000 nových klientech |
|---|---|
| jeden hluboký strom | 86,5 % |
| strom hloubky 3 | 89,5 % |
| bagging, 200 stromů | 89,3 % |
| náhodný les, 200 stromů | 90,2 % |
| gradient boosting, 50 kroků, η = 0,1 | 90,3 % |
| k nejbližších sousedů, k = 25 | 91,3 % |
| strop (skutečná hranice) | 91,5 % |
Ansámbly napravily hlavní vadu stromu — přecitlivělost — a z 86,5 % se dostaly přes 90 %, blízko ke stropu. Na našich dvou příznacích se šikmou hranicí je ale kNN stejně dobrý nebo lepší a logistická regrese by stačila taky. Síla ansámblů se ukáže až na skutečných tabulkách: desítky příznaků v různých jednotkách, chybějící hodnoty, kategorie, nelineární interakce. Tam náhodný les funguje skoro bez ladění a gradient boosting po vyladění bývá nejlepší, co existuje.
7. Shrnutí
- Hlasování mnoha slabých modelů funguje, jen když se mýlí nezávisle: 101 nezávislých poradců s 60 % má pravdu v 97,9 %, opisující nepřekročí 88,0 %.
- Bagging učí stejné modely na bootstrapových výběrech a průměruje je; z hlubokého stromu (86,5 %) udělal les s 89,3 %.
- Náhodný les navíc losuje příznaky v každém uzlu; korelace chyb stromů klesla z 0,53 na 0,42 a přesnost stoupla na 90,2 %.
- Každý strom nevidí asi 37 % dat — z nich se dá odhadnout chyba bez testovací sady (OOB).
- Gradient boosting přidává malé stromy, které opravují předchůdce; s η = 0,1 dosáhl 90,3 % po 50 krocích, ale pak se přeučil — počet kroků se musí hlídat.
Chcete si to osahat? Nechte AI agenta naučit náhodný les a gradient boosting na veřejné tabulce — třeba o přeživších Titaniku — a vypsat, které příznaky les považuje za nejdůležitější.
Máte na to jiný názor? Napište na support@coden-app.com.