12.4 III. ellenőrző pont: egy veszteségfüggvény teljes értelmezése

Ez a III. ellenőrző pont nem vezet be új statisztikai fogalmat. A 9–11. fejezet jelölés-, tömb-, gradiens- és optimalizálási eszköztárát kapcsolja össze a Terület, összeg és numerikus integrál–Várható érték és Monte Carlo közelítés integrál-, sűrűség- és Monte Carlo fogalmaival egyetlen veszteségfüggvényen. Az II. ellenőrző pont: adatból ellenőrzött feature-tábla alfejezetben a feature-táblát kontrollösszeggel és keret-összehasonlítással zártuk; itt ugyanazt a szerződést alkalmazzuk matematikai függvényre: legyen kézi invariáns, numerikus integrál, gradiensellenőrzés és Monte Carlo kontroll.

12.4.1 Cél és konkrét helyzet

A Northstar kezdőprojekt rendelésszintű kérdése: a rendelés pillanatában becsülni a kézbesítési időt a távolságból. Ez az ellenőrző pont egy szándékosan mesterséges, zajmentes sokaságot használ:

Mielőtt bármit futtatnál, adj előzetes becslést: a modellcsalád tartalmazza a 2+3x2+3x egyenest, ezért a minimum várható hiba 00, az optimum pedig w*=(2,3)⊤w^*=(2,3)^\top. A w=(0,0)⊤w=(0,0)^\top paraméternél a veszteség R(0,0)=∫01(2+3x)2dx=4+6+3=13,R(0,0)=\int_0^1(2+3x)^2\,dx = 4+6+3=13, tehát a kézi kontrollérték 1313. Ezt az alábbi kódnak függetlenül vissza kell adnia.

12.4.2 Fogalmi magyarázat: veszteség, sűrűség, gradiens

A korábbi fejezetekből már ismertek a tömbök, az integrál, a derivált és a Monte Carlo átlag. Itt csak a kapcsolatukat írjuk fel egy veszteségfüggvényre.

A predikció vektoros alakban:

ϕ(x)=[1x]∈ℝ2,w=[ab]∈ℝ2,ŷw(x)=w⊤ϕ(x)=a+bx. \phi(x)=\begin{bmatrix}1\\x\end{bmatrix}\in\mathbb R^2,\qquad w=\begin{bmatrix}a\\b\end{bmatrix}\in\mathbb R^2,\qquad \hat y_w(x)=w^\top\phi(x)=a+bx.

Egy megfigyelés hibája y−ŷw(x)y-\hat y_w(x), a vesztesége pedig [y−ŷw(x)]2[y-\hat y_w(x)]^2. A sokasági kockázat a sűrűséggel súlyozott integrál:

R(w)=∫01(2+3x−a−bx)21⏟fX(x)dx. R(w)=\int_0^1(2+3x-a-bx)^2\,\underbrace{1}_{f_X(x)}\,dx.

A négyzetet kifejtve:

R(a,b)=(2−a)2+(2−a)(3−b)+(3−b)23=a2+ab+b23−7a−4b+13. \begin{aligned} R(a,b) &=(2-a)^2+(2-a)(3-b)+\frac{(3-b)^2}{3}\\ &=a^2+ab+\frac{b^2}{3}-7a-4b+13. \end{aligned}

A gradiens a két parciális derivált:

∇R(w)=[∂R∂a∂R∂b]=[2a+b−7a+23b−4]. \nabla R(w)= \begin{bmatrix} \frac{\partial R}{\partial a}\\[2mm] \frac{\partial R}{\partial b} \end{bmatrix} = \begin{bmatrix} 2a+b-7\\ a+\frac{2}{3}b-4 \end{bmatrix}.

Az optimum a stacionárius pont: ∇R(w)=0\nabla R(w)=0 megoldása a=2a=2, b=3b=3, és mivel RR nemnegatív négyzetes kifejezés összege, ez globális minimum.

A shape-szerződés:

Objektum Alak Egység / szerep
ϕ(x)\phi(x) (2,) jellemzővektor
ww (2,) aa nap, bb nap
ŷw(x)\hat y_w(x) skalár előrejelzett nap
egy LiL_i veszteség skalár nap²
R(w)R(w) skalár nap²
∇R(w)\nabla R(w) (2,) nap / paraméterkomponens

A Monte Carlo közelítés x1,…,xNx_1,\dots,x_N független Uniform(0,1)\text{Uniform}(0,1) mintát használ, yi=2+3xiy_i=2+3x_i értékkel:

R̂N(w)=1N∑i=1N(yi−a−bxi)2. \hat R_N(w)=\frac1N\sum_{i=1}^N\left(y_i-a-bx_i\right)^2.

A becslés standard hibája a mintabeli veszteségek sLs_L szórásából:

SE=sLN,sL=1N−1∑i=1N(Li−L‾)2. SE=\frac{s_L}{\sqrt N},\qquad s_L=\sqrt{\frac{1}{N-1}\sum_{i=1}^N(L_i-\bar L)^2}.

A N\sqrt N a Várható érték és Monte Carlo közelítés alfejezetből ismert tulajdonság: a Monte Carlo hiba tipikus nagysága a minta elemszámának négyzetgyökével csökken.

A gradiensellenőrzés a Meredekség és numerikus derivált numerikus deriváltját használja, de most komponensenként és kétoldali differenciával:

∂R∂wj≈R(w+hej)−R(w−hej)2h,h=10−6. \frac{\partial R}{\partial w_j}\approx \frac{R(w+h e_j)-R(w-h e_j)}{2h},\qquad h=10^{-6}.

12.4.3 Teljes minimális munkapélda

A következő szkript a notebooks/s048_risk_checkpoint.py fájl tartalma. A kimeneteket a fenti képletekből számoltuk, ezért az itt látható számok elméletileg várt, nem futtatott értékek. Futtatás után a saját lab környezetedben válik ellenőrzött kimenetté.

"""
s048_risk_checkpoint.py
III. ellenőrző pont: veszteségfüggvény teljes numerikus értelmezése.

A kimeneti kommentek a képletekből számított elméletileg várt értékek;
futtatott jegyzék nélkül nem ellenőrzött mérési eredmények.
"""
import numpy as np
from scipy.integrate import quad
from scipy.optimize import minimize
import matplotlib.pyplot as plt

rng = np.random.default_rng(20261020)

def risk_closed(w):
    a, b = w
    return a*a + a*b + b*b/3.0 - 7.0*a - 4.0*b + 13.0

def risk_quad(w):
    a, b = w
    return quad(lambda x: (2.0 + 3.0*x - a - b*x)**2, 0.0, 1.0)[0]

def grad_closed(w):
    a, b = w
    return np.array([2.0*a + b - 7.0, a + 2.0*b/3.0 - 4.0])

def numerical_gradient(fun, w, h=1e-6):
    g = np.zeros_like(w, dtype=float)
    for j in range(w.size):
        e = np.zeros_like(w, dtype=float)
        e[j] = 1.0
        g[j] = (fun(w + h*e) - fun(w - h*e)) / (2.0*h)
    return g

def monte_carlo_loss(w, rng, n):
    x = rng.uniform(0.0, 1.0, n)        # shape (n,)
    y = 2.0 + 3.0*x                     # shape (n,) nap
    losses = (y - w[0] - w[1]*x)**2     # shape (n,) nap^2
    return losses.mean(), losses.std(ddof=1) / np.sqrt(n)

w00 = np.array([0.0, 0.0])
wopt = np.array([2.0, 3.0])

# Elméletileg várt: 13,    13.0,   [-7. -4.],   [-7.000000 -4.000000]
print("risk_closed(0,0) =", risk_closed(w00))
print("risk_quad(0,0)   =", risk_quad(w00))
print("grad_closed(0,0) =", grad_closed(w00))
print("central grad      =", numerical_gradient(risk_closed, w00))

# Elméletileg várt: True (1e-12 tolerancia mellett)
print("quad-zart egyezes =", abs(risk_closed(w00) - risk_quad(w00)) < 1e-12)

# Elméletileg várt: True (1e-6 abszolút és relatív tolerancia mellett)
print("gradiens-egyezes  =",
      np.allclose(numerical_gradient(risk_closed, w00),
                  grad_closed(w00), atol=1e-6, rtol=1e-6))

res = minimize(risk_closed, w00, jac=grad_closed, method="BFGS",
               options={"gtol": 1e-10})

# Elméletileg várt: x = [2. 3.], fun = 0.0, success = True
print("BFGS x, fun, success =", res.x, res.fun, res.success)

n = 100_000
mean0, se0 = monte_carlo_loss(w00, rng, n)
# Elméletileg várt: mean0 ≈ 13,  2*se0 ≈ 0.039
print(f"MC at (0,0): {mean0:.4f} +/- {2*se0:.4f} (2 SE), populacios R=13")
meanp, sep = monte_carlo_loss(wopt, rng, n)
# Elméletileg várt: meanp = 0,  sep = 0
print(f"MC at (2,3): {meanp:.4f} +/- {2*sep:.4f}")

# Ábra: R szintvonalai és az optimum
A = np.linspace(-1.0, 5.0, 200)
B = np.linspace(-2.0, 7.0, 200)
A, B = np.meshgrid(A, B)
Z = A*A + A*B + B*B/3.0 - 7.0*A - 4.0*B + 13.0

plt.contourf(A, B, Z, levels=20, cmap="viridis")
plt.colorbar(label="R(a,b)  [nap^2]")
plt.plot([2.0], [3.0], "r*", markersize=12, label="optimum (2,3)")
plt.plot([0.0], [0.0], "wo", label="kézi kontroll (0,0)")
plt.xlabel("a (nap)")
plt.ylabel("b (nap / távolságegység)")
plt.title("III. ellenőrző pont: négyzetes veszteség")
plt.legend()
plt.tight_layout()
plt.savefig("s048_risk_contour.png", dpi=150)

Futtatás a lab projekt gyökeréből:

# Linux/macOS, a könyvtár a lab projekt gyökere:
cd lab
uv run --locked python notebooks/s048_risk_checkpoint.py
# Windows PowerShell, a könyvtár a lab projekt gyökere:
cd lab
uv run --locked python notebooks\s048_risk_checkpoint.py

A --locked kapcsoló a korábbi fejezetben készített uv.lock egyezését ellenőrzi. Ha még nincs feloldott lock, először uv lock, majd uv sync kell.

12.4.4 Eredmény értelmezése

A kézi kontroll egyetlen számpárja: R(0,0)=13R(0,0)=13. A numerikus quad eredménynek 10−1210^{-12} hibahatáron belül egyeznie kell vele, mert a zárt alak egzakt, a quad pedig determinisztikus numerikus közelítés. A gradiens kézi értéke ∇R(0,0)=(−7,−4)⊤\nabla R(0,0)=(-7,-4)^\top; ezt a központi differencia h=10−6h=10^{-6} lépéssel 10−610^{-6} tolerancián belül közelíti.

A BFGS futás ugyanazt a jac gradiensfüggvényt kapja, mint amit ellenőriztünk, ezért az optimum ellenőrzése Optimalizáló választás és konvergenciaellenőrzés szellemében itt kétrétegű: a solver stacionárius pontot talál, és a stacionárius pont a zárt gradiense nulla. A várt eredmény w*=(2,3)⊤w^*=(2,3)^\top, R(w*)=0R(w^*)=0.

A Monte Carlo kontrollnak nem az a célja, hogy „pontosan” eltalálja a 13-at; a 2 SE sáv mutatja a szimulációs bizonytalanságot. A jelen példában R(0,0)=13R(0,0)=13 és a per-sample veszteség szórása 𝔼[(2+3X)4]−132=206,2−169=37,2,\mathbb E[(2+3X)^4]-13^2=206{,}2-169=37{,}2, ezért sL≈6,099s_L\approx6{,}099, és N=100000N=100\,000 mellett SE≈0,019SE\approx0{,}019. Ha a futásod 13,00±0,0413{,}00\pm0{,}04 sávon belül van, az a kontroll szempontjából elfogadható. A w=(2,3)w=(2,3) pontban minden egyes veszteség pontosan 00, ezért ott a MC szórása is 00; ez nem statisztikai „bizonyítás”, hanem a számítás sajátossága.

A veszteségfüggvény optimalizálási sikere és a statisztikai prediktív érvényesség külön állítás. A szintetikus, zajmentes példa analitikus invariánsai a numerikus implementációt ellenőrzik; valós generalizációs következtetést nem igazolnak.

12.4.5 Feladatok

1. feladat — kézi értelmezés. Tekintsük a w=(1,0)⊤w=(1,0)^\top pontot a fenti veszteségfüggvényen.

  1. Add meg a ŷw(x)\hat y_w(x), a hiba és a veszteség kifejezését xx függvényeként.
  2. Számold ki kézzel az R(1,0)R(1,0) integrált, és ellenőrizd a zárt formulával.
  3. Számold ki ∇R(1,0)\nabla R(1,0) mindkét komponensét, és foglald szóba, mit jelent az előjelük.
  4. Miért igaz, hogy R(1,0)>R(2,3)R(1,0)>R(2,3)?

2. feladat — implementálás és gradiensellenőrzés. Készíts függvényeket a fenti példához, majd:

  1. Végezz központi differenciás gradiensellenőrzést a w=(1,2)⊤w=(1,2)^\top pontban h=10−5h=10^{-5} lépéssel. Az analitikus gradiens ∇R(1,2)=(−3,−53)⊤.\nabla R(1,2)=(-3,-\tfrac53)^\top .
  2. Futtasd a BFGS-optimalizálót w0=(0,0)w_0=(0,0) kezdőpontból.
  3. Futtass Monte Carlo becslést N=50000N=50\,000, seed=7 mellett a w=(0,0)w=(0,0) és a w*=(2,3)w^*=(2,3) pontokban. A 2 SE sávot is írd ki.

Milyen toleranciákat adsz meg, és miért?

3. feladat — hibadiagnózis. Egy kolléga az alábbi függvényt használja a Monte Carlo bizonytalanság becslésére:

def monte_carlo_se_bad(w, rng, n):
    x = rng.uniform(0.0, 1.0, n)
    y = 2.0 + 3.0*x
    losses = (y - w[0] - w[1]*x) ** 2
    return losses.mean(), losses.std() / n   # figyelj a nevezőre!

A kolléga N=100000N=100\,000 mintánál a w=(0,0)w=(0,0) pontban ezt kapja: „átlag 13,00013{,}000, 2 SE 0,00010{,}0001”, és ebből arra következtet, hogy a sokasági veszteség pontosan 1313 lett beszorítva egy rendkívül szűk sávba.

  1. Mi a hiba a standard hiba képletében?
  2. Mekkora az elméletileg várt SE a sL≈6,099s_L\approx6{,}099 közelítéssel?
  3. Javítsd a függvényt, és fogalmazd meg, mit állíthatunk a MC átlagról és a 2 SE sávról.

4. feladat — megváltoztatott feltétel. Változtassuk meg a sokasági igaz kapcsolatot Y=1+4XY=1+4X-re, miközben XX továbbra is Uniform(0,1)\text{Uniform}(0,1).

  1. Vezesd le az új zárt veszteséget R(a,b)R(a,b)-re és a ∇R(a,b)\nabla R(a,b) gradienst.
  2. Oldd meg a ∇R=0\nabla R=0 egyenletet; mit kapsz optimumként?
  3. Futtass Monte Carlo kontrollt N=50000N=50\,000, seed=42 mellett a w=(0,0)w=(0,0) és az optimum pontokban. Milyen elméletileg várt értékeket hasonlítasz össze?

12.4.6 Megoldások és indoklás

1. megoldás.

  1. ŷw(x)=1\hat y_w(x)=1; a hiba 2+3x−1=1+3x2+3x-1=1+3x; a veszteség (1+3x)2(1+3x)^2.

  2. R(1,0)=∫01(1+3x)2dx=∫01(1+6x+9x2)dx=1+3+3=7R(1,0)=\int_0^1(1+3x)^2\,dx=\int_0^1(1+6x+9x^2)\,dx=1+3+3=7. A zárt formula a=1,b=0a=1,b=0 mellett 12−7⋅1+13=71^2-7\cdot1+13=7.

  3. ∇R(1,0)=(2⋅1+0−7,1−4)⊤=(−5,−3)⊤\nabla R(1,0)=(2\cdot1+0-7,\ 1-4)^\top=(-5,-3)^\top. Az első komponens azt mondja, hogy aa kicsiny növelése csökkenti a veszteséget; a második hasonlóan csökkentést jelez bb növelésére. Ez konzisztens azzal, hogy a=1<2a=1<2, b=0<3b=0<3, tehát a jelenlegi pont az optimum alatt van.

  4. R(1,0)=7>0=R(2,3)R(1,0)=7>0=R(2,3), mert a w*=(2,3)w^*=(2,3) pontban a predikció minden xx-re megegyezik az igazi 2+3x2+3x értékkel.

2. megoldás.

A gradiensellenőrzés várt kimenete:

w12 = np.array([1.0, 2.0])
ng = numerical_gradient(risk_closed, w12, h=1e-5)
ag = grad_closed(w12)
# ng ≈ [-3.0, -1.6666667]; ag = [-3.0, -1.6666667]

A np.allclose(ng, ag, atol=1e-6, rtol=1e-6) elvártan True. A 10−610^{-6} tolerancia indoklása: a kétoldali differencia hibatagjai O(h2)O(h^2) és kerekítési hiba; h=10−5h=10^{-5}-nél ez a jelen függvényskálán jóval a tolerancia alatt van.

A BFGS futás elvártan a [2,3][2,3] pontot adja vissza, f≈0f\approx0 értékkel. A gtol=1e-10 a gradiensnormára vonatkozó megállási feltétel; a stacionárius pont ellenőrzése tehát a megállási ok, nem a kimeneti egyetlen szám.

A MC seed=7, N=50000N=50\,000 mellett elméletileg várt:

A bemeneteket a feladat mind megadja; a seedelt generátor reprodukálható, de numerikus könyvtárverziótól függő apró eltérés nem sérti a MC sávok stabilitását.

3. megoldás.

  1. A kód losses.std() / n értékkel oszt, nem np.sqrt(n) értékkel. Ezzel a bizonytalanságot N\sqrt N-szeresével alulbecsli.

  2. N=100000N=100\,000, sL≈6,099s_L\approx6{,}099 mellett SE≈6,099/316,2≈0,0193SE\approx6{,}099/316{,}2\approx0{,}0193. A kolléga által kiírt 0,00010{,}0001 hibasáv tehát irreálisan szűk; a valós MC bizonytalanság nagyságrendileg 0,040{,}04 a 2 SE sávban.

  3. Helyes függvény:

def monte_carlo_se_fixed(w, rng, n):
    x = rng.uniform(0.0, 1.0, n)
    y = 2.0 + 3.0*x
    losses = (y - w[0] - w[1]*x) ** 2
    return losses.mean(), losses.std(ddof=1) / np.sqrt(n)

A ±2\pm2 SE sáv közelítőleg az ismételt MC futások 95%-ában tartalmazza a sokasági értéket; ez heurisztikus, a formális indoklást később a normális közelítés és a centrális határeloszlás adja. A sáv nem jelenti azt, hogy a sokasági érték a becsült átlagtól maximálisan ennyire van.

4. megoldás.

  1. Y=1+4XY=1+4X, ezért R=∫01(1+4x−a−bx)2dxR=\int_0^1(1+4x-a-bx)^2\,dx. Kifejtve:

R(a,b)=a2+ab+b23−6a−113b+313. R(a,b)=a^2+ab+\frac{b^2}{3}-6a-\frac{11}{3}b+\frac{31}{3}.

A gradiens:

∇R(a,b)=[2a+b−6a+23b−113]. \nabla R(a,b)= \begin{bmatrix} 2a+b-6\\ a+\frac23b-\frac{11}{3} \end{bmatrix}.

  1. A ∇R=0\nabla R=0 egyenletrendszer megoldása a=1a=1, b=4b=4, tehát w*=(1,4)⊤w^*=(1,4)^\top. Mivel RR nemnegatív négyzetes forma, ez globális minimum, és R(1,4)=0R(1,4)=0.

  2. Elméletileg várt kézi értékek:

A feladat ellenőrző invariantja tehát az RR kézi értéke, a gradiens komponensei és az optimum koordinátái.

12.4.7 Gyakori tévedés és ellenpélda

„Ha egy ponton numerikusan egyezik a gradiens, akkor a gradiensfüggvény mindenütt rendben van.” A numerikus egyezés csak a vizsgált tartományra és toleranciára vonatkozik. A központi differencia pontossága a függvény nagyságától és a véges pontosságtól függ: a kerekítési hibakorlát nagyságrendileg ϵ⋅|R|/h\epsilon\cdot|R|/h, ahol ϵ≈2,2⋅10−16\epsilon\approx2{,}2\cdot10^{-16}.

Ellenpéldaként próbáld ki a w=(1000,1000)⊤w=(1000,1000)^\top pontot, ahol R≈2,3⋅106R\approx2{,}3\cdot10^6, a zárt gradiens

∇R(1000,1000)≈(2993,1627)⊤. \nabla R(1000,1000)\approx(2993,\ 1627)^\top .

Ha valaki itt h=10−12h=10^{-12} lépéssel ellenőriz, a kerekítési hibakorlát nagyobb lehet, mint a gradiens maga, ezért a központi differencia nem egyezik a zárt deriválttal a megszokott 10−610^{-6} tolerancián belül. A javítás nem a gradiensképlet cseréje, hanem a skálázott, stabilabb ellenőrzés vagy az analitikus gradiens használata. Ugyanígy a Monte Carlo kontroll sem igazol „minden ww-re” semmit: egyetlen ponton mért átlag és SE csak azt a pontot és azt a generátorfeltételt ellenőrzi.

12.4.8 Önellenőrzés

12.4.9 Rövid összefoglaló

A III. ellenőrző pont egyetlen veszteségfüggvényen zárta le a matematikai eszköztárat. A négyzetes hiba sűrűséggel súlyozott integrálként írható fel, zárt formulája és gradiense kézzel ellenőrizhető. A scipy.integrate.quad, a központi differencia, a BFGS és a seedelt Monte Carlo ugyanazt az optimumot támasztja alá: (2,3)(2,3), minimum 00. A numerikus egyezés azonban mindig csak a vizsgált pontra, tartományra és toleranciára vonatkozik. A MC bizonytalanságot N\sqrt N-es SE-vel kell becsülni. Következő lépésként a Sokaság, minta és adatfelvételi folyamat a minta és az adatfelvétel fogalmát vezeti be, ahol a sokasági R(w)R(w) helyébe a mintából számolt átlag és annak bizonytalansága lép.