24.1 Tanulási görbe és hibadiagnózis

24.1.1 1. Cél, előismeret és induló kérdés

Ebben az alfejezetben a tanítási futás közben keletkező diagnosztikai jelekből lokalizálunk hibát. Nem egyetlen „jó receptet” adunk, hanem olyan gondolkodási keretet, amely minden jelhez több lehetséges okot rendel, és minden okhoz egy diszkrimináló ellenőrzést. A 12.4. III. ellenőrző pont: önállóan tanuló kis háló alfejezetben felépített kis MLP-tanítás, a 21.4. Osztályarány, súlyozás és céleloszlás alfejezetben tárgyalt céleloszlás, a 22.4. Augmentációs kísérlet és domainváltozás alfejezetben bevezetett clean/corrupt elkülönítés és a 23.4. Hibaszeletek és alkalmazási határ alfejezetben tárgyalt hibaszeletek szolgálnak alapul.

Induló kérdés. Egy GlyphLab-futás train loss-a 20 lépés után is 0.6930.693 körül mozog, ahelyett hogy csökkenne. Mely okok jöhetnek szóba, és milyen méréssel lehet őket szétválasztani? A választ a 3. szakasz rendszerezi; előzetes becslésként érdemes már most felsorolni legalább három, egymástól független jelöltet.

24.1.2 2. Diagnosztikai jelek: definíció és jelölés

Legyen a modell paramétervektora θ∈ℝP\theta \in \mathbb R^P, ahol PP a tanítható skalárok száma. A tt-edik lépésben egy BB batchre számolt átlagos veszteség Lt=1|B|∑i∈Bℓ(f(xi;θt),yi)L_t = \frac{1}{|B|}\sum_{i \in B} \ell(f(x_i; \theta_t), y_i). A teljes epoch-veszteség a batchenkénti átlagok súlyozott átlaga: L‾e=1N∑iniL‾i\bar L_e = \frac{1}{N}\sum_i n_i \bar L_i, ahogyan a 12.1. Tanítás, validáció és kiértékelési mód levezette.

Definíció (tanulási görbe). A train loss görbe a t↦Ltt \mapsto L_t sorozat; a val loss görbe ugyanez a modellfrissítéstől független val spliten, rögzített modellállapot mellett számolva.

Definíció (gradiensnorma-jel). gt=∇θLt∈ℝPg_t = \nabla_\theta L_t \in \mathbb R^P, és a jel ∥gt∥2=(∑j=1Pgt,j2)1/2\|g_t\|_2 = \left(\sum_{j=1}^{P} g_{t,j}^2\right)^{1/2}. A teljes gradiensnorma egyetlen összevont szám; rétegenkénti bontásban ∥gt(k)∥\|g_t^{(k)}\| jelöli a kk-adik réteg paramétereire vett normát.

Definíció (paraméterváltozás-jel). Δt=∥θt+1−θt∥2\Delta_t = \|\theta_{t+1} - \theta_t\|_2. Tiszta SGD esetén Δt=η∥gt∥2\Delta_t = \eta \|g_t\|_2; Adam esetén ez nem áll, mert a momentum és a második momentum normalizálja a lépést.

Definíció (tiny overfit). Olyan futtatás, amelyben a train loss csökken, a val loss viszont nő vagy stagnál; tipikus szándékos sanity check a 12.3. Sanity check és kis mintára túlillesztés alfejezetből, hogy a modell egyáltalán képes-e memorizálni egy kis mintát.

A továbbiakban minden diagnosztikai állítás a jel osztályára vonatkozik, nem egyetlen lépés pillanatnyi értékére: például „lapos” alatt |Lt−L0|≤ε|L_t - L_0| \le \varepsilon teljesülését értjük előre megadott ε\varepsilon küszöbbel az első TT lépésben.

24.1.3 3. A jel nem azonos az okkal: diagnosztikai nem-injektivitás

Állítás (diagnosztikai nem-injektivitás). Legyen ℛ\mathcal R a futtatások (modell, adat, optimizer, seed) halmaza, és legyen Φ:ℛ→ℝT×ℝT×ℝT\Phi: \mathcal R \to \mathbb R^T \times \mathbb R^T \times \mathbb R^T a vizsgált jel, Φ(r)=(Lt,∥gt∥2,Δt)t=1T\Phi(r) = (L_t, \|g_t\|_2, \Delta_t)_{t=1}^{T}. A Φ\Phi leképezés értékkészletén értelmezett kvalitatív osztályozás nem határozza meg egyértelműen az okot: ugyanahhoz a jelosztályhoz több, mechanikailag különböző ok tartozhat.

Bizonyításvázlat (konstrukcióval). Elegendő minden jelosztályra két különböző okot megadni, amelyek ugyanazt a kvalitatív jelet produkálják. Az alábbi táblázat ezt teszi; a lapos loss esetén a konstrukció numerikusan is ellenőrizhető a 4. szakaszban.

Jel Lehetséges ok (nem teljes lista) Diszkrimináló ellenőrzés
Lapos train loss kis tanulási ráta; vanishing gradiens; befagyasztott súly; label bug Δt\Delta_t nagysága; rétegenkénti ∥gt(k)∥\|g_t^{(k)}\|; p.grad is None; target-eloszlás
Train loss csökken, val loss nő tiny overfit; túl nagy kapacitás; train/val eloszláskülönbség train/val loss-gap; modellméret-abláció; split-ellenőrzés
NaN vagy inf loss bemeneti NaN/inf; túl nagy η\eta; log(0)/0/0 a lossban; tanulási ráta divergencia input isfinite; gradnorm; fokozatos η\eta-csökkentés
Eltűnő/robbanó gradiens aktivációk szaturációja; mély szorzat a láncszabályban; inicializálás rétegenkénti aktivációstatisztika; gradnorm rétegenként
A paraméter nem változik requires_grad=False; hiányzik az optimizer paraméterlistájából; η=0\eta=0; BN train/eval mód named_parameters; optimizer.param_groups; Δt\Delta_t

A lapos loss egy numerikus konstrukciója: legyen L(θ)=12(θ−2)2L(\theta)=\frac12(\theta-2)^2, θ0=10\theta_0=10. (a) η=10−6\eta = 10^{-6} mellett a gradiens gt=θt−2=8g_t = \theta_t - 2 = 8, tehát Δt=8⋅10−6\Delta_t = 8\cdot 10^{-6}, és LtL_t az első lépésekben |Lt−L0|≤10−4|L_t - L_0| \le 10^{-4} értékkel gyakorlatilag lapos. (b) Ugyanaz a veszteség, de szándékosan skálázott, eltűnő gradienssel gt=10−8(θt−2)g_t = 10^{-8}(\theta_t-2) és η=0.1\eta = 0.1 mellett Δt=8⋅10−9\Delta_t = 8\cdot 10^{-9}, a veszteség még laposabb. A két ok mechanikailag különböző (optimizer-skála kontra gradiensskála), a jel kvalitatíve azonos. Ez ellenpélda arra a téves következtetésre, hogy „lapos loss = nincs tanulási kapacitás”.

A vanishing/exploding mechanizmus a 9.4. Aktivációk és gradiensáramlás alfejezetben bevezetett láncszabály közvetlen következménye. Ha például h(k+1)=W(k)h(k)h^{(k+1)} = W^{(k)} h^{(k)} lineáris rétegek kompozíciójában a backpropagált jel a ∏kW(k)\prod_k W^{(k)} szorzatokon halad át, akkor ∥W(k)∥<1\|W^{(k)}\| < 1 minden kk-ra a szorzatot exponenciálisan csökkenti, ∥W(k)∥>1\|W^{(k)}\| > 1 pedig növeli. A rétegenkénti gradiensnorma-mérés ezért diszkriminál: ha a korai rétegek normája nagyságrendekkel kisebb a későiekénél, akkor a vanishing-hipotézis erősödik; ha minden rétegben nagy, akkor inkább a learning rate vagy a loss skálázása gyanús.

24.1.4 4. Kézi példa: négy kvalitatív görbe, eltérő okokkal

Tekintsük az L(θ)=12(θ−2)2L(\theta)=\frac12(\theta-2)^2 veszteséget és a tiszta SGD-lépést. A gradiens gt=θt−2g_t=\theta_t-2.

  1. Egészséges: θ0=10\theta_0=10, η=0.5\eta=0.5. A lépések: θ1=10−0.5⋅8=6,L1=8;θ2=6−0.5⋅4=4,L2=2;\theta_1=10-0.5\cdot 8=6,\quad L_1=8;\qquad \theta_2=6-0.5\cdot 4=4,\quad L_2=2; θ3=4−0.5⋅2=3,L3=0.5;θ4=3−0.5⋅1=2.5,L4=0.125.\theta_3=4-0.5\cdot 2=3,\quad L_3=0.5;\qquad \theta_4=3-0.5\cdot 1=2.5,\quad L_4=0.125. A görbe monoton csökken.

  2. Lapos, kis η\eta: ugyanez η=10−6\eta=10^{-6}-tal; θ1=9.999992\theta_1=9.999992, L1≈31.999936L_1\approx 31.999936, a változás 6.4⋅10−86.4\cdot 10^{-8}.

  3. Oszcilláló: η=2\eta=2. Ekkor θt+1=θt−2(θt−2)=4−θt,\theta_{t+1} = \theta_t - 2(\theta_t-2) = 4 - \theta_t, tehát θt\theta_t a 1010 és −2-2 értékek között ugrál, a hiba |θt−2|=8|\theta_t-2|=8 állandó marad. A loss nem csökken, de nem is divergál.

  4. Divergens: η=2.1\eta=2.1. A hiba-rekurzió et+1=θt+1−2=(1−η)(θt−2)e_{t+1} = \theta_{t+1}-2 = (1-\eta)(\theta_t-2), tehát |et|=|1−η|t|e0|=1.1t⋅8|e_t| = |1-\eta|^t |e_0| = 1.1^t \cdot 8, exponenciálisan nő. A train loss ebben a tiszta kvadratikus esetben véges, de a gradiensnorma exponenciálisan nő; valódi hálóban előbb-utóbb float32 túlcsorduláshoz és NaN-hez vezet.

A 2. és a „vanishing gradiens” eset ugyanazt a lapos jelet adja, ahogyan a 3. szakasz állítja; az egyiket az optimizer léptéke, a másikat a gradiens skálája okozza.

Számított veszteség L_t egészséges SGD esetén - Képletből számolt szemléltetés, nem mérés.

24.1.5 5. Labor: három szándékos traininghiba lokalizálása

A labor három, egymástól függetlenül bekapcsolt hibát vizsgál a GlyphLab adaton, egy kis MLP-vel (576 bemenet a 24×2424\times 24 képből, 32 rejtett egység, 3 logit). Minden futtatás CPU-n, float32-ben, rögzített seeddel fut. A modellválasztás itt nem történik meg: a három futtatás diagnosztikai, és egyiket sem használjuk final modellként.

Az alábbi kimeneti számok előzetes, a képletből és a mechanizmusból várt értékek; a kézirat írásakor a script nincs lefuttatva. A hallgató a script futtatásával kapja a tényleges naplót.

# lab/n093_diagnose.py
# Futtatás a repository gyökeréből: python lab/n093_diagnose.py
import csv
import json
import math
from pathlib import Path

import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import DataLoader, TensorDataset

DATA = Path("lab/data")
DEVICE = "cpu"
DTYPE = torch.float32
SEED = 20261020
torch.manual_seed(SEED)
np.random.seed(SEED)

images = torch.from_numpy(np.load(DATA / "images.npy")).to(device=DEVICE, dtype=DTYPE)
labels = torch.from_numpy(np.load(DATA / "labels.npy")).to(device=DEVICE, dtype=torch.int64)

with open(DATA / "metadata.csv", newline="", encoding="utf-8") as f:
    rows = list(csv.DictReader(f))
train_idx = [int(r["index"]) for r in rows if r["split"] == "train"]
val_idx = [int(r["index"]) for r in rows if r["split"] == "val"]

X_train = images[train_idx].reshape(len(train_idx), -1)
y_train = labels[train_idx]
X_val = images[val_idx].reshape(len(val_idx), -1)
y_val = labels[val_idx]

class TinyMLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(576, 32)
        self.act = nn.ReLU()
        self.fc2 = nn.Linear(32, 3)
    def forward(self, x):
        return self.fc2(self.act(self.fc1(x)))

def run_case(y_train_used, freeze_first=False, lr=0.05, steps=30, bs=64):
    model = TinyMLP().to(DEVICE)
    if freeze_first:
        model.fc1.requires_grad_(False)
    opt = torch.optim.SGD(model.parameters(), lr=lr)
    hist = {"loss": [], "grad_norm": [], "delta": []}
    params_before = [p.detach().clone() for p in model.parameters()]
    for step in range(steps):
        idx = torch.randint(0, X_train.shape[0], (bs,), device=DEVICE)
        xb, yb = X_train[idx], y_train_used[idx]
        opt.zero_grad(set_to_none=True)
        logits = model(xb)
        loss = F.cross_entropy(logits, yb)
        loss.backward()
        gn = 0.0
        for p in model.parameters():
            if p.grad is not None:
                gn += p.grad.detach().pow(2).sum().item()
        gn = math.sqrt(gn)
        opt.step()
        delta = 0.0
        for p, p0 in zip(model.parameters(), params_before):
            delta += (p.detach() - p0).pow(2).sum().item()
        delta = math.sqrt(delta)
        hist["loss"].append(loss.item())
        hist["grad_norm"].append(gn)
        hist["delta"].append(delta)
        params_before = [p.detach().clone() for p in model.parameters()]
    return model, hist

@torch.inference_mode()
def evaluate(model, X, y):
    model.eval()
    logits = model(X)
    pred = logits.argmax(dim=1)
    return (pred == y).float().mean().item()

summary = {}

# 0. kontroll: ép futtatás
_, hist_ok = run_case(y_train)
acc_ok = evaluate(TinyMLP().to(DEVICE), X_val, y_val)  # kontroll, lásd megjegyzés alább
# Az accuracy-hoz a modellt itt nem tanítottuk; a valódi kontrollt a health run
# modelljén kell mérni: lásd a szövegben jelzett javítást.

# 1. label bug: minden cél 0
y_bad = torch.zeros_like(y_train)
model_bad, hist_bad = run_case(y_bad)
acc_bad = evaluate(model_bad, X_val, y_val)

# 2. frozen first layer
model_fr, hist_fr = run_case(y_train, freeze_first=True)
acc_fr = evaluate(model_fr, X_val, y_val)
frozen_grad_none = model_fr.fc1.weight.grad is None

# 3. large learning rate
model_lr, hist_lr = run_case(y_train, lr=3.0)
acc_lr = evaluate(model_lr, X_val, y_val)

summary = {
    "label_bug_last_loss": hist_bad["loss"][-1],
    "label_bug_val_acc": acc_bad,
    "frozen_first_grad_none": frozen_grad_none,
    "frozen_last_loss": hist_fr["loss"][-1],
    "frozen_val_acc": acc_fr,
    "large_lr_any_nonfinite": not all(math.isfinite(x) for x in hist_lr["loss"]),
    "large_lr_val_acc": acc_lr,
    "seed": SEED,
    "device": DEVICE,
    "dtype": str(DTYPE),
}
out = Path("lab/n093_summary.json")
out.write_text(json.dumps(summary, indent=2), encoding="utf-8")
print(json.dumps(summary, indent=2))

A fenti vázlat 0. esete szándékosan hiányos: a kontroll-accuracyt a tanított model_ok modellen kell mérni, nem egy friss példányon. Ez maga is diagnosztikai gyakorlat (lásd az F4 feladatot). A három vizsgált hiba elvárt jelaláírása:

Az átadandó eredmény a lab/n093_summary.json napló és egy rövid hipotézisnapló, amely mindhárom hibához rögzíti a tesztelt hipotézist, a mért jelet és a diszkrimináló ellenőrzést. A corrupt test itt nem használható: a 22.4. Augmentációs kísérlet és domainváltozás szerint csak a befagyasztott final modellen, egyszer értékelhető.

24.1.6 6. Feladatok

F1 (fogalmi, nehézség 1). Definiáld a gradiensnorma-jelet, és magyarázd el két-három mondatban, miért nem elégséges önmagában a „vanishing gradiens” diagnózis kimondásához. Elvárt átadandó: definíció alakkal, és legalább egy másik ok, amely ugyanazt a kis gradienst produkálja.

F2 (levezetési, nehézség 2). Az L(θ)=a2(θ−b)2L(\theta)=\frac{a}{2}(\theta-b)^2 veszteségen, a>0a>0, tiszta SGD mellett vezesd le a hiba-rekurziót et=θt−be_t=\theta_t-b-re, és bizonyítsd be: η=2/a\eta=2/a esetén |et||e_t| állandó; η>2/a\eta>2/a esetén |et||e_t| exponenciálisan nő. Elvárt átadandó: minden lépés, a rekurzió zárt alakja, a két eset külön.

F3 (implementációs, nehézség 2). Írj classify_run(loss_hist, grad_norm_hist, eps=1e-4) függvényt, amely a következő osztályokat adja vissza: "healthy", "flat", "nan", "diverging". A szabályok: bármely nem véges érték "nan"; a gradiensnorma utolsó értéke több mint 10310^3-szorosa az elsőnek "diverging"; az első és utolsó loss különbsége |LT−1−L0|≤ε|L_{T-1}-L_0|\le \varepsilon "flat"; egyébként "healthy". Teszteld a 4. szakasz három numerikus esetén. Elvárt átadandó: a függvény teljes kódja, a tesztbemenetek és a visszatérési értékek.

F4 (hibakeresési, nehézség 2). Az alábbi részlet két független hibát tartalmaz. Azonosítsd mindkettőt, add meg a következményüket, és javítsd ki a kódot.

loss = F.cross_entropy(F.softmax(logits, dim=1), labels)
# ...
logits = model(images.reshape(images.shape[0], 1, -1))  # images: (N,1,H,W)
# labels_valtozo valójában y_train.clone() volt egy korábbi blokkban
labels = labels_transposed  # valahol labels_transposed = labels.T

Elvárt átadandó: a két hiba megnevezése, a várható tünet, a javított sor.

F5 (kísérlettervezési, nehézség 3). Tervezz kísérletet annak eldöntésére, hogy egy val loss plató oka kapacitáskorlát vagy label noise. Adj protokollt: kérdés, hipotézisek, megfigyelési egység, split, baseline, változó tényező, metrika, erőforrás-korlát, érvényességi határ. Elvárt átadandó: legalább két modellméret, a train/val split rögzítése, a label noise injektálásának módja, és annak indoklása, miért nem használható a test a döntéshez.

24.1.7 7. Megoldások és indoklás

F1 megoldás. A gradiensnorma-jel ∥gt∥2=(∑j(∇θjLt)2)1/2\|g_t\|_2 = \left(\sum_j (\nabla_{\theta_j} L_t)^2\right)^{1/2}. A vanishing gradiens diagnózisához rétegenkénti bontás kell: ha a korai rétegek normája nagyságrendekkel kisebb, mint a későieké, akkor a láncszabály-szorzat csökkenése a valószínű ok. Ha viszont minden rétegben kicsi a gradiens, az lehet kis tanulási ráta, a loss konstans tagja, befagyasztott súlyok vagy label bug is — a jel önmagában nem különbözteti meg ezeket.

F2 megoldás. gt=∇θL=a(θt−b)=aetg_t=\nabla_\theta L=a(\theta_t-b)=a e_t, így θt+1=θt−ηaet.\theta_{t+1}=\theta_t-\eta a e_t. Kivonva bb-t: et+1=(1−ηa)et.e_{t+1}=(1-\eta a)e_t. Indukcióval et=(1−ηa)te0e_t=(1-\eta a)^t e_0. Ha η=2/a\eta=2/a, akkor 1−ηa=−11-\eta a=-1, tehát |et|=|e0||e_t|=|e_0| állandó (ugrálás a két oldal között). Ha η>2/a\eta>2/a, akkor |1−ηa|>1|1-\eta a|>1, tehát |et|=|1−ηa|t|e0||e_t|=|1-\eta a|^t |e_0| exponenciálisan nő. Alakellenőrzés: ete_t skalár, a rekurzió dimenzióhelyes; a szélsőeset η=0\eta=0 ad et=e0e_t=e_0 állandót, ami konzisztens az „egyáltalán nem lépünk” esettel.

F3 megoldás. A függvény:

import math

def classify_run(loss_hist, grad_norm_hist, eps=1e-4):
    if any(not math.isfinite(x) for x in loss_hist + grad_norm_hist):
        return "nan"
    if grad_norm_hist[-1] > 1e3 * grad_norm_hist[0]:
        return "diverging"
    if abs(loss_hist[-1] - loss_hist[0]) <= eps:
        return "flat"
    return "healthy"

Teszt: a 4. szakasz egészséges görbéje ([32,8,2,0.5,0.125], [8,4,2,1,0.5]) "healthy"; a lapos eset ([32,31.999936], [8,7.999992]) "flat"; a divergens rekurzió 10 lépése "diverging"; egy [float("nan"), 1.0] input "nan". Tűrés: az eps=1e-4 küszöb a float32 kerekítés fölött van, de problémafüggő; a hallgatónak a saját loss-skálájához kell igazítania.

F4 megoldás. Az első hiba: F.cross_entropy már tartalmazza a log-softmaxot, ezért a F.softmax dupla normalizálás, logitok helyett valószínűségi bemenet; ez torz gradienst és numerikus instabilitást okoz. Javítás: loss = F.cross_entropy(logits, labels). A második hiba: labels_transposed nem megfelelő alakú/vagy rossz sorrendű; a címkének (N,) int64 alakúnak kell lennie, osztályindexekkel, nem transzponált mátrixnak. Tünet: shape-mismatch hiba vagy, ha a transzponálás véletlenül átmegy, a loss csökken ugyan, de a val accuracy a véletlen szinten marad. Javítás: labels = y_train az eredeti, indexelt tenzorból, és assert labels.ndim == 1 ellenőrzés.

F5 megoldásvázlat. Kérdés: a val plató oka kapacitás vagy label noise? Megfigyelési egység: scene_id, mert a két nézet függő. Split: a GlyphLab rögzített train/val/test felosztása, a test a teljes elemzés végéig érintetlen. Baseline: a 12.4. III. ellenőrző pont: önállóan tanuló kis háló alfejezetbeli 32 egységes MLP. Változó tényező: modellméret (például 8, 32, 128 rejtett egység), és címkeminőség (tiszta, p=0.1p=0.1 véletlen címkecsere). Metrika: val loss és val accuracy. Ha a plató a legkisebb modellen eltűnik a nagyobb mérettel, akkor a kapacitás-hipotézis erősödik; ha a tiszta címkével a legnagyobb modell is platón marad, akkor más ok (adat vagy optimalizálás) gyanús. Az érvényességi határ: a toy adat nem általánosít; a tesztet csak a protokoll végén, a rögzített modellen lehet használni, különben kiválasztási torzítás lép fel.

24.1.8 8. Gyakori tévedés ellenpéldával

Tévedés: „A lapos veszteséggörbe azt jelenti, hogy a modell elérte a veszteségfelület lokális minimumát.” Ellenpélda: a 4. szakasz η=10−6\eta=10^{-6} esetében a veszteség L(θ)L(\theta) szigorúan konvex, egyetlen minimuma van θ=2\theta=2-nél, de a görbe a 10-es pontban lapos, mert a lépések túl kicsik; a modell nincs a minimum közelében. A gradiens itt 88, tehát nem nulla. A helyes következtetés az, hogy a laposság numerikus, adat- vagy optimalizálási okból is eredhet; a gradiensnorma- és paraméterváltozás-mérés különbözteti meg az eseteket.

24.1.9 9. Önellenőrzés és visszahívás

Ellenőrizd, hogy (a) minden jelhez legalább két lehetséges ok szerepel-e a diagnózisnaplódban; (b) a lapos loss esetén rögzítetted-e az ε\varepsilon küszöböt és a lépésszámot; (c) a labor futtatása nem használta-e a test splitet modellválasztásra. Visszahívás: a 12.1. Tanítás, validáció és kiértékelési mód alfejezetben levezetett súlyozott epoch-loss itt azért fontos, mert a diagnosztikai görbét batch-átlagokból építed; a 23.1. Confusion matrix és aggregálási konvenció alfejezetben tárgyalt aggregálás pedig arra figyelmeztet, hogy a train accuracy önmagában nem helyettesíti a val loss-t és a csoportszintű hibát.

24.1.10 10. Rövid összefoglaló

A tanulási görbe három jelet kapcsol össze: veszteség, gradiensnorma és paraméterváltozás. Ugyanahhoz a jelhez több mechanikailag különböző ok tartozhat, ezért a diagnózis nem a görbe „ránézéséből”, hanem diszkrimináló ellenőrzésekből áll. A lapos loss oka lehet kis tanulási ráta, eltűnő gradiens, befagyasztott súly vagy label bug; a NaN eredhet adathibából, túl nagy tanulási rátából vagy rossz loss-kompozícióból. A vanishing/exploding jelenség a láncszabály-szorzat skálázódásának következménye. A labor három szándékos hibát kapcsol be, és hipotézisenként egy mért jelet és egy ellenőrzést naplóz. A korrekt diagnosztikai gyakorlat a hibás futtatást tanulságként kezeli, nem a test split engedélyeként.

24.1.11 11. Következő alkalmazás és felhasznált források

A 24.2. CPU/GPU profiling és helyes időmérés a tényleges futásidőt és erőforráshasználatot méri. Ott a D14/D16/D17 hivatalos dokumentációs URL-ek ([D14] Automatic Mixed Precision, [D16] torch.utils.benchmark, [D17] torch.profiler) tartalma még ellenőrzésre vár; a jelen egység nem állít GPU/AMP-viselkedést. A 24.1. Tanulási görbe és hibadiagnózis alfejezethez felhasznált forrás: