Faza 04 · lecția 04
Clasificarea imaginilor
Scopul lecției: Un clasificator este o funcție de la pixeli la o distribuție de probabilitate peste clase. Tot restul este infrastructură.
Versiunea curentă AlexBred.com: primele 100 de lecții ale programului în limba română.
Cuprinsul lecției
- Obiective de învățare
- Problema
- Conceptul
- Fluxul de clasificare
- Entropia încrucișată, logiturile și softmax
- De ce funcționează augmentarea
- Mixup și CutMix
- Netezirea etichetelor
- Evaluarea dincolo de acuratețe
- Construiți-l
- Pasul 1: un set de date sintetic determinist
- Pasul 2: normalizare și augmentare
- Pasul 3: mixup
- Pasul 4: bucla de antrenare
- Pasul 5: reuniți componentele
- Pasul 6: citiți matricea de confuzie
- Utilizați-l
- Livrați-l
- Exerciții
- Termeni-cheie
- Lecturi suplimentare
Un clasificator este o funcție de la pixeli la o distribuție de probabilitate peste clase. Tot restul este infrastructură.
Tip: Construcție Limbaje: Python Cerințe preliminare: Faza 2, Lecția 09 (Evaluarea modelului), Faza 3, Lecția 10 (Mini framework), Faza 4, Lecția 03 (CNN-uri) Timp: ~75 de minute
Obiective de învățare
- Construiți un flux complet de clasificare a imaginilor pe CIFAR-10: set de date, augmentare, model, buclă de antrenare, evaluare
- Explicați rolul fiecărei componente (încărcător de date, pierdere, optimizator, planificator, augmentare) și anticipați cum se manifestă în curba pierderii defectarea oricăreia dintre ele
- Implementați de la zero mixup, cutout și netezirea etichetelor și justificați când merită adăugată fiecare
- Citiți o matrice de confuzie și un tabel de precizie/recall pe clasă pentru a diagnostica eșecurile setului de date și ale modelului dincolo de acuratețea agregată
Problema
Orice sarcină de viziune care ajunge în producție se reduce, la un anumit nivel, la clasificarea imaginilor. Detecția clasifică regiuni. Segmentarea clasifică pixeli. Regăsirea ordonează după similaritatea cu centroizii claselor. Stăpânirea clasificării — bucla setului de date, politica de augmentare, pierderea, evaluarea — este competența care se transferă la orice altă sarcină din fază.
Majoritatea erorilor de clasificare nu sunt în model. Ele se află în fluxul de procesare: o normalizare defectă, un set de antrenare neamestecat, o augmentare care deformează etichetele, o împărțire de validare contaminată cu date de antrenare, o rată de învățare care diverge în tăcere după epoca 30. Un CNN care ar atinge 93% pe CIFAR-10 cu o configurare corectă obține frecvent 70–75% cu una defectă, iar curba pierderii pare plauzibilă tot timpul.
Această lecție leagă manual întregul flux, astfel încât fiecare parte să poată fi inspectată. Nu veți utiliza nimic din torchvision.datasets care ar putea ascunde o eroare.
Conceptul
Fluxul de clasificare
Fiecare linie din această buclă poate ascunde o eroare. Entropia încrucișată primește logituri brute, nu ieșiri softmax, astfel încât orice apel model(x).softmax() înainte de pierdere calculează în tăcere gradientul greșit. Augmentările se aplică numai intrărilor, nu etichetelor — cu excepția mixup, care le amestecă pe amândouă. optimizer.zero_grad() trebuie apelat o dată la fiecare pas; omiterea lui acumulează gradienți și seamănă cu o rată de învățare extrem de instabilă. Fiecare dintre aceste erori aplatizează curba de învățare fără a arunca o excepție.
Entropia încrucișată, logiturile și softmax
Un clasificator produce C numere pentru fiecare imagine, numite logituri. Aplicarea softmax le transformă într-o distribuție de probabilitate:
softmax(z)_i = exp(z_i) / sum_j exp(z_j)
Entropia încrucișată măsoară logaritmul negativ al probabilității clasei corecte:
CE(z, y) = -log( softmax(z)_y )
= -z_y + log( sum_j exp(z_j) )
Forma din dreapta este cea stabilă numeric (log-sum-exp). nn.CrossEntropyLoss din PyTorch combină softmax + NLL într-o singură operație și primește direct logituri brute. Aplicarea manuală a softmax înaintea ei este aproape întotdeauna o eroare — ajungeți să calculați log(softmax(softmax(z))), o cantitate lipsită de semnificație pentru obiectivul dorit.
Notă tehnică a traducerii: Formula din dreapta este echivalentă algebric cu entropia încrucișată, dar evaluarea ei naivă poate totuși suferi overflow în
exp. O implementare stabilă folosește operația log-sum-exp;CrossEntropyLossprimește logituri și combină internLogSoftmaxcuNLLLoss. Consultați PyTorch.
De ce funcționează augmentarea
Un CNN are bias inductiv pentru translație (din partajarea ponderilor), dar nu are invarianță încorporată la decupări, oglindiri, variații de culoare sau ocluzii. Singura modalitate de a-l învăța aceste invarianțe este să îi arătați pixeli care le pun în practică. Fiecare transformare aleatorie în timpul antrenării spune: „aceste două imagini au aceeași etichetă; învățați caracteristicile care ignoră diferența”.
Notă tehnică a traducerii: Partajarea ponderilor convoluției oferă, în condiții discrete, echivarianță la deplasări, nu invarianță exactă. Pooling-ul, arhitectura și augmentarea pot apropia invarianța, fără să o garanteze. Consultați McGreivy și Hakim.
Decupare originală: "câine orientat spre stânga"
Oglindire: "câine orientat spre dreapta" <- aceeași etichetă, pixeli diferiți
Rotire(+15): "câine, ușor înclinat"
Variație de culoare:"câine în lumină mai caldă"
RandomErasing: "câine cu o zonă lipsă"
Regula: augmentarea trebuie să păstreze eticheta. Cutout-ul și rotația aplicate unei cifre pot transforma „6” în „9”; pentru acel set de date utilizați intervale de rotație mai mici și alegeți augmentări care respectă invarianțele specifice cifrelor.
Notă tehnică a traducerii: Cutout maschează regiuni pătrate ale intrării; el nu poate roti sau transforma singur un „6” în „9”. Rotațiile mari pot modifica eticheta unei cifre, iar ocluzia Cutout poate doar ascunde informația. Vedeți DeVries și Taylor.
Mixup și CutMix
Augmentarea obișnuită transformă pixelii, dar păstrează etichetele one-hot. Mixup și CutMix schimbă acest lucru prin interpolarea ambelor.
Mixup:
lambda ~ Beta(a, a)
x = lambda * x_i + (1 - lambda) * x_j
y = lambda * y_i + (1 - lambda) * y_j
CutMix:
lipește un dreptunghi aleatoriu din x_j în x_i
y = amestec al lui y_i și y_j ponderat după arie
De ce ajută: modelul nu mai memorează ținte one-hot abrupte și învață să interpoleze între clase. Pierderea de antrenare crește, acuratețea de test crește. Este cea mai ieftină îmbunătățire a robusteții pentru orice clasificator.
Notă tehnică a traducerii: Mixup este o regularizare empiric eficientă, nu o îmbunătățire garantată sau universal cea mai ieftină. Lucrarea originală raportează generalizare și robustețe mai bune în experimentele sale, iar efectul concret depinde de date, model și protocol. Vedeți Zhang și colaboratorii.
Netezirea etichetelor
O rudă a mixup. În loc să antrenați față de [0, 0, 1, 0, 0], antrenați față de [eps/C, eps/C, 1-eps, eps/C, eps/C] pentru un eps mic, cum ar fi 0.1. Împiedică modelul să producă logituri arbitrar de ascuțite și îmbunătățește calibrarea aproape fără cost. Este integrată în nn.CrossEntropyLoss(label_smoothing=0.1) începând cu PyTorch 1.10.
Notă tehnică a traducerii: Vectorul afișat în original nu este normalizat: dacă masa
eps/Cse alocă tuturor claselor, inclusiv celei corecte, componenta corectă trebuie să fie1-eps+eps/C. Alternativ, forma cu masa totalăepspe clasele greșite este[eps/(C-1), eps/(C-1), 1-eps, ...].CrossEntropyLossdocumentează netezirea ca amestec între ținta originală și distribuția uniformă: PyTorch.
Evaluarea dincolo de acuratețe
Acuratețea agregată ascunde dezechilibrul. Un clasificator binar 90–10 care prezice întotdeauna clasa majoritară obține 90%. Instrumentele care arată ce se întâmplă cu adevărat:
- Acuratețe pe clasă — un număr pentru fiecare clasă; scoate imediat la iveală categoriile cu performanță slabă.
- Matrice de confuzie — grilă C x C în care rândul i și coloana j = numărul exemplelor din clasa reală i prezise drept clasa j; diagonala este corectă, iar în afara diagonalei se află comportamentul modelului.
- Top-1 / Top-5 — dacă clasa corectă se află printre primele 1 sau 5 predicții; Top-5 contează pentru ImageNet deoarece clase precum „Norwich terrier” și „Norfolk terrier” sunt cu adevărat ambigue.
- Calibrare (ECE) — o predicție cu încredere 0,8 este corectă în 80% dintre cazuri? Rețelele moderne sunt sistematic prea încrezătoare; corectați cu scalarea temperaturii sau cu netezirea etichetelor.
receptive-field
Construiți-l
Pasul 1: un set de date sintetic determinist
CIFAR-10 se află pe disc. Pentru ca lecția să fie reproductibilă și rapidă, construim un set de date sintetic care seamănă cu CIFAR — imagini RGB 32x32 cu structură specifică fiecărei clase, pe care modelul trebuie să o învețe. Exact același flux funcționează neschimbat pe CIFAR-10 real.
import numpy as np
import torch
from torch.utils.data import Dataset
def synthetic_cifar(num_per_class=1000, num_classes=10, seed=0):
rng = np.random.default_rng(seed)
X = []
Y = []
for c in range(num_classes):
centre = rng.uniform(0, 1, (3,))
freq = 2 + c
for _ in range(num_per_class):
yy, xx = np.meshgrid(np.linspace(0, 1, 32), np.linspace(0, 1, 32), indexing="ij")
r = np.sin(xx * freq) * 0.5 + centre[0]
g = np.cos(yy * freq) * 0.5 + centre[1]
b = (xx + yy) * 0.5 * centre[2]
img = np.stack([r, g, b], axis=-1)
img += rng.normal(0, 0.08, img.shape)
img = np.clip(img, 0, 1)
X.append(img.astype(np.float32))
Y.append(c)
X = np.stack(X)
Y = np.array(Y)
idx = rng.permutation(len(X))
return X[idx], Y[idx]
class ArrayDataset(Dataset):
def __init__(self, X, Y, transform=None):
self.X = X
self.Y = Y
self.transform = transform
def __len__(self):
return len(self.X)
def __getitem__(self, i):
img = self.X[i]
if self.transform is not None:
img = self.transform(img)
img = torch.from_numpy(img).permute(2, 0, 1)
return img, int(self.Y[i])
Fiecare clasă primește propria paletă de culori și propriul tipar de frecvență, plus zgomot gaussian pentru a forța modelul să învețe semnalul, în loc să memoreze pixelii. Zece clase, o mie de imagini pentru fiecare, permutate.
Pasul 2: normalizare și augmentare
Cele două transformări prezente în orice flux de viziune.
def standardize(mean, std):
mean = np.array(mean, dtype=np.float32)
std = np.array(std, dtype=np.float32)
def _fn(img):
return (img - mean) / std
return _fn
def random_hflip(p=0.5):
def _fn(img):
if np.random.random() < p:
return img[:, ::-1, :].copy()
return img
return _fn
def random_crop(pad=4):
def _fn(img):
h, w = img.shape[:2]
padded = np.pad(img, ((pad, pad), (pad, pad), (0, 0)), mode="reflect")
y = np.random.randint(0, 2 * pad)
x = np.random.randint(0, 2 * pad)
return padded[y:y + h, x:x + w, :]
return _fn
def compose(*fns):
def _fn(img):
for fn in fns:
img = fn(img)
return img
return _fn
Aplicați padding prin reflectare înaintea decupării, nu padding cu zerouri, deoarece marginile negre ar fi un semnal pe care modelul ar învăța să îl ignore într-un mod nefolositor.
Notă tehnică a traducerii: În
np.random.randint, limita superioară este exclusivă; cupad=4, codul selectează doar pozițiile 0–7 și omite poziția 8. Pentru toate cele2 * pad + 1poziții de decupare, limita superioară trebuie să fie2 * pad + 1. Consultați documentația NumPy.
Pasul 3: mixup
Amestecă două imagini și două etichete în interiorul pasului de antrenare. Este implementat ca transformare a lotului, deci se află lângă propagarea înainte, nu în interiorul setului de date.
def mixup_batch(x, y, num_classes, alpha=0.2):
if alpha <= 0:
return x, torch.nn.functional.one_hot(y, num_classes).float()
lam = float(np.random.beta(alpha, alpha))
idx = torch.randperm(x.size(0), device=x.device)
x_mixed = lam * x + (1 - lam) * x[idx]
y_onehot = torch.nn.functional.one_hot(y, num_classes).float()
y_mixed = lam * y_onehot + (1 - lam) * y_onehot[idx]
return x_mixed, y_mixed
def soft_cross_entropy(logits, soft_targets):
log_probs = torch.log_softmax(logits, dim=-1)
return -(soft_targets * log_probs).sum(dim=-1).mean()
soft_cross_entropy este entropie încrucișată față de o distribuție de etichete soft. Se reduce la cazul one-hot obișnuit când ținta este exact one-hot.
Pasul 4: bucla de antrenare
Rețeta completă: o trecere prin date, gradienți o dată pentru fiecare lot, planificatorul avansat o dată pe epocă.
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from torch.optim import SGD
from torch.optim.lr_scheduler import CosineAnnealingLR
def train_one_epoch(model, loader, optimizer, device, num_classes, use_mixup=True):
model.train()
total, correct, loss_sum = 0, 0, 0.0
for x, y in loader:
x, y = x.to(device), y.to(device)
if use_mixup:
x_m, y_soft = mixup_batch(x, y, num_classes)
logits = model(x_m)
loss = soft_cross_entropy(logits, y_soft)
else:
logits = model(x)
loss = nn.functional.cross_entropy(logits, y, label_smoothing=0.1)
optimizer.zero_grad()
loss.backward()
optimizer.step()
loss_sum += loss.item() * x.size(0)
total += x.size(0)
# Training accuracy vs the un-mixed labels `y` is only an approximation
# when mixup is on (the model saw soft targets, not y). Treat it as a
# rough progress signal; rely on val accuracy for real performance.
with torch.no_grad():
pred = logits.argmax(dim=-1)
correct += (pred == y).sum().item()
return loss_sum / total, correct / total
@torch.no_grad()
def evaluate(model, loader, device, num_classes):
model.eval()
total, correct = 0, 0
loss_sum = 0.0
cm = torch.zeros(num_classes, num_classes, dtype=torch.long)
for x, y in loader:
x, y = x.to(device), y.to(device)
logits = model(x)
loss = nn.functional.cross_entropy(logits, y)
pred = logits.argmax(dim=-1)
for t, p in zip(y.cpu(), pred.cpu()):
cm[t, p] += 1
loss_sum += loss.item() * x.size(0)
total += x.size(0)
correct += (pred == y).sum().item()
return loss_sum / total, correct / total, cm
Cinci invariante pe care le verificați de fiecare dată când scrieți o buclă de antrenare:
model.train()înainte de antrenare,model.eval()înainte de evaluare — comută comportamentul dropout și batchnorm..zero_grad()înainte de.backward()..item()când acumulați metrici, astfel încât nimic să nu mențină graful de calcul în viață.@torch.no_grad()în timpul evaluării — economisește memorie și timp, previne accidente subtile.- Argmax pe logituri brute, nu după softmax — același rezultat, o operație mai puțin.
Pasul 5: reuniți componentele
Utilizați TinyResNet din lecția anterioară, antrenați câteva epoci, evaluați.
from main import synthetic_cifar, ArrayDataset
from main import standardize, random_hflip, random_crop, compose
from main import mixup_batch, soft_cross_entropy
from main import train_one_epoch, evaluate
# TinyResNet comes from the previous lesson (03-cnns-lenet-to-resnet).
# Adjust the import path to wherever you stored the previous lesson's code.
from cnns_lenet_to_resnet import TinyResNet # example placeholder
X, Y = synthetic_cifar(num_per_class=500)
split = int(0.9 * len(X))
X_train, Y_train = X[:split], Y[:split]
X_val, Y_val = X[split:], Y[split:]
mean = [0.5, 0.5, 0.5]
std = [0.25, 0.25, 0.25]
train_tf = compose(random_hflip(), random_crop(pad=4), standardize(mean, std))
eval_tf = standardize(mean, std)
train_ds = ArrayDataset(X_train, Y_train, transform=train_tf)
val_ds = ArrayDataset(X_val, Y_val, transform=eval_tf)
train_loader = DataLoader(train_ds, batch_size=128, shuffle=True, num_workers=0)
val_loader = DataLoader(val_ds, batch_size=256, shuffle=False, num_workers=0)
device = "cuda" if torch.cuda.is_available() else "cpu"
model = TinyResNet(num_classes=10).to(device)
optimizer = SGD(model.parameters(), lr=0.1, momentum=0.9, weight_decay=5e-4, nesterov=True)
scheduler = CosineAnnealingLR(optimizer, T_max=10)
for epoch in range(10):
tr_loss, tr_acc = train_one_epoch(model, train_loader, optimizer, device, 10, use_mixup=True)
va_loss, va_acc, _ = evaluate(model, val_loader, device, 10)
scheduler.step()
print(f"epoch {epoch:2d} lr {scheduler.get_last_lr()[0]:.4f} "
f"train {tr_loss:.3f}/{tr_acc:.3f} val {va_loss:.3f}/{va_acc:.3f}")
Pe setul de date sintetic, acesta ajunge la o acuratețe de validare aproape perfectă în cinci epoci; acesta este ideea: fluxul este corect, iar modelul poate învăța ceea ce poate fi învățat. Înlocuiți setul de date cu CIFAR-10 real și aceeași buclă ajunge la ~90% fără modificări.
Notă tehnică a traducerii: Aceste rezultate sunt ilustrative, nu niveluri de performanță garantate. Acuratețea depinde de arhitectură, implementarea exactă, numărul de epoci, optimizator, augmentare, semințe și protocolul de evaluare. Comparațiile controlate ale trucurilor de antrenare pentru clasificare sunt discutate de He și colaboratorii.
Pasul 6: citiți matricea de confuzie
Doar acuratețea nu vă spune niciodată unde eșuează modelul. Matricea de confuzie o face.
def print_confusion(cm, labels=None):
c = cm.shape[0]
labels = labels or [str(i) for i in range(c)]
print(f"{'':>6}" + "".join(f"{l:>5}" for l in labels))
for i in range(c):
row = cm[i].tolist()
print(f"{labels[i]:>6}" + "".join(f"{v:>5}" for v in row))
print()
tp = cm.diag().float()
fp = cm.sum(dim=0).float() - tp
fn = cm.sum(dim=1).float() - tp
prec = tp / (tp + fp).clamp_min(1)
rec = tp / (tp + fn).clamp_min(1)
f1 = 2 * prec * rec / (prec + rec).clamp_min(1e-9)
for i in range(c):
print(f"{labels[i]:>6} prec {prec[i]:.3f} rec {rec[i]:.3f} f1 {f1[i]:.3f}")
_, _, cm = evaluate(model, val_loader, device, 10)
print_confusion(cm)
Rândurile sunt clasele reale, coloanele sunt predicțiile. Un grup de valori în afara diagonalei între clasele 3 și 5 înseamnă că modelul le confundă și vă oferă un punct de pornire pentru colectarea țintită de date sau pentru o augmentare specifică clasei.
Utilizați-l
torchvision împachetează toate cele de mai sus în componente idiomatice. Pentru CIFAR-10 real, fluxul complet înseamnă patru linii plus o buclă de antrenare.
from torchvision.datasets import CIFAR10
from torchvision.transforms import Compose, RandomCrop, RandomHorizontalFlip, ToTensor, Normalize
mean = (0.4914, 0.4822, 0.4465)
std = (0.2470, 0.2435, 0.2616)
train_tf = Compose([
RandomCrop(32, padding=4, padding_mode="reflect"),
RandomHorizontalFlip(),
ToTensor(),
Normalize(mean, std),
])
eval_tf = Compose([ToTensor(), Normalize(mean, std)])
train_ds = CIFAR10(root="./data", train=True, download=True, transform=train_tf)
val_ds = CIFAR10(root="./data", train=False, download=True, transform=eval_tf)
Notă tehnică a traducerii: În
torchvision.datasets.CIFAR10,train=Falseselectează setul oficial de test, nu o validare extrasă din setul de antrenare. Nu ajustați hiperparametri pe acestval_ds; împărțiți setul de antrenare pentru validare și păstrați setul de test pentru raportarea finală. Consultați API-ul CIFAR10 și ghidul scikit-learn despre scurgeri de date.
Două lucruri de remarcat: media/abaterea standard sunt specifice setului de date — calculate pe setul de antrenare CIFAR-10, nu pe ImageNet — iar padding-ul prin reflectare este politica de decupare implicită a comunității. Copierea statisticilor ImageNet aici produce o pierdere de ~1% la acuratețe pe care nimeni nu o observă până când cineva profilează modelul.
Notă tehnică a traducerii: Nu există o pierdere universală de „~1%” pentru folosirea statisticilor ImageNet pe CIFAR-10. Efectul depinde de model, de normalizarea reală a datelor și de restul protocolului de antrenare; măsurați-l printr-o ablație pe propriul set de validare. Rezultatele transferului în funcție de alegerile de antrenare sunt, de asemenea, dependente de sarcina-țintă: He, Girshick și Dollár.
Livrați-l
Această lecție produce:
outputs/prompt-classifier-pipeline-auditor.md— un prompt care auditează un script de antrenare pentru cele cinci invariante de mai sus și evidențiază prima încălcare.outputs/skill-classification-diagnostics.md— o abilitate care, primind o matrice de confuzie și o listă de nume de clase, rezumă eșecurile pe clasă și propune corecția cu cel mai mare impact.
Exerciții
- (Ușor) Antrenați același model cu și fără mixup timp de cinci epoci pe setul de date sintetic. Reprezentați pierderea de antrenare și de validare pentru ambele. Explicați de ce pierderea de antrenare cu mixup este mai mare, dar acuratețea de validare este similară sau mai bună.
- (Mediu) Implementați Cutout — anulați un pătrat aleatoriu de 8x8 din fiecare imagine de antrenare — și executați o ablație față de lipsa augmentării, hflip+crop, hflip+crop+cutout, hflip+crop+mixup. Raportați acuratețea de validare pentru fiecare.
- (Dificil) Construiți un flux CIFAR-100 (100 de clase, aceeași dimensiune de intrare) și reproduceți o rulare de antrenare ResNet-34 la o acuratețe aflată la cel mult un punct procentual de acuratețea publicată. Suplimentar: explorați trei rate de învățare și două valori de weight decay, înregistrați într-un CSV local, produceți tabelul final cu cele mai mari confuzii din matricea de confuzie.
Termeni-cheie
| Termen | Ce spun oamenii | Ce înseamnă de fapt |
|---|---|---|
| Logituri | „Ieșiri brute” | Vectorul pre-softmax cu C numere pentru fiecare imagine; entropia încrucișată îl așteaptă pe acesta, nu valori după softmax |
| Entropie încrucișată | „Pierderea” | Logaritmul negativ al probabilității clasei corecte; combină log-softmax și NLL într-o singură operație stabilă |
| DataLoader | „Generatorul de loturi” | Împachetează un set de date cu amestecare, grupare în loturi și încărcare opțională cu mai mulți workeri; este învinovățit pentru jumătate dintre erorile de antrenare |
| Augmentare | „Transformări aleatorii” | Orice transformare la nivel de pixel, aplicată în timpul antrenării, care păstrează eticheta; învață invarianțe pe care CNN-ul nu le are nativ |
| Mixup / CutMix | „Amestecați două imagini” | Combinați intrările și etichetele, astfel încât clasificatorul să învețe interpolări netede în locul limitelor rigide |
| Netezirea etichetelor | „Ținte mai blânde” | Înlocuiți one-hot cu (1-eps, eps/(C-1), …); îmbunătățește calibrarea și crește ușor acuratețea |
| Acuratețe Top-k | „Top-5” | Clasa corectă se află printre cele k predicții cu probabilitatea cea mai mare; utilizată pe seturi de date cu clase cu adevărat ambigue |
| Matrice de confuzie | „Unde se află erorile” | Tabel C x C în care intrarea (i, j) numără imaginile din clasa reală i prezise ca j; diagonala este corectă, iar în afara diagonalei se vede ce trebuie corectat |
Lecturi suplimentare
- CS231n: Training Neural Networks — încă cel mai clar tur al fluxului de antrenare într-o singură pagină
- Bag of Tricks for Image Classification (He et al., 2019) — fiecare mic truc care, împreună, adaugă 3–4% la acuratețea ResNet pe ImageNet
- mixup: Beyond Empirical Risk Minimization (Zhang et al., 2017) — lucrarea originală mixup; trei pagini de teorie plus experimente convingătoare
- Why temperature scaling matters (Guo et al., 2017) — lucrarea care a demonstrat că rețelele moderne sunt necalibrate și a corectat problema cu un singur parametru scalar
Sursă: Originalul în limba engleză
Navigare: ← Lecția 04.03 — CNN-uri — de la LeNet la ResNet · Lecția 04.05 — Învățare prin transfer și ajustare fină → · Faza 4 — Viziune computerizată · Catalog complet