Hi ha un enemic que portem esquivant des del mòdul 2: quan vam entrenar la xarxa densa de MNIST a 02-05, les corbes mostraven un sobreajust lleu — la pèrdua d'entrenament continuava baixant mentre la de validació s'estancava i començava a pujar. Llavors ho vam deixar anotat; ara ho resolem. Aquesta lliçó presenta l'arsenal complet de regularització: el conjunt de tècniques que fan que un model generalitzi a dades noves en lloc de memoritzar les d'entrenament. Són transversals — milloren la CNN del catàleg, el classificador de ressenyes, la LSTM de vendes, el transfer learning de la lliçó anterior i fins i tot el discriminador de la GAN — i per això són, probablement, les tècniques que més vegades aplicaràs a la teva vida professional.
Contingut
- El sobreajust a fons: diagnòstic amb corbes
- Bias vs. variance en termes pràctics
- Regularització L1 i L2 (weight decay)
- Dropout
- Batch Normalization
- Early Stopping
- Augment de dades per a imatges
- Taula resum de l'arsenal
- Exemple integrador: el MNIST de 02-05, millorat
- Menció: learning rate schedules
El sobreajust a fons: diagnòstic amb corbes
Sobreajustar és memoritzar en lloc d'aprendre. Un model sobreajustat rendeix molt bé amb les dades d'entrenament i malament amb dades noves: ha après les peculiaritats accidentals del conjunt (el soroll) a més de —o en lloc de— els patrons reals.
L'instrument de diagnòstic ja el coneixes: les corbes train/val que fit() retorna a history. Els tres quadres clínics:
| Quadre | Corba d'entrenament | Corba de validació | Diagnòstic |
|---|---|---|---|
| Subajust (underfitting) | Pèrdua alta, estancada | Alta, enganxada a la de train | El model no dona més de si: falta capacitat o entrenament |
| Ajust sa | Baixa i s'estabilitza | Baixa i s'estabilitza a prop de train | Objectiu aconseguit |
| Sobreajust | Segueix baixant i baixant | S'estanca i comença a pujar | El model memoritza: cal regularitzar |
El senyal inequívoc del sobreajust és la divergència de les corbes: el forat (gap) entre train i val creix amb les èpoques. A 02-05 aquest forat era petit; en el transfer learning de 05-03, amb només 1600 imatges, pot ser un abisme si no es fa res.
Bias vs. variance en termes pràctics
La teoria en diu el compromís biaix-variància (bias-variance). Sense formalismes, la versió de treball:
- Bias alt = el model és massa simple o rígid per al patró real → subajust. Es nota en el fet que ni tan sols l'entrenament va bé.
- Variance alta = el model és tan flexible que canvia dràsticament amb cada mostra concreta de dades: s'ajusta al soroll → sobreajust. Es nota en el forat train/val.
La recepta de decisió pràctica, en ordre:
- La pèrdua d'entrenament és dolenta? → problema de bias: model més gran, entrenar més, millors trets. (La regularització aquí no ajuda; fins i tot empitjora.)
- L'entrenament va bé però la validació divergeix? → problema de variance: regularització (aquesta lliçó), més dades, o model més petit.
- Totes dues van bé? → no toquis res; passa a avaluar en test.
Tot l'arsenal que segueix ataca el cas 2: la variància.
Regularització L1 i L2 (weight decay)
La primera família de tècniques actua sobre la pèrdua: s'hi afegeix una penalització per pesos grans.
- L2 (l'habitual, també anomenada weight decay): afegeix a la pèrdua la suma dels quadrats dels pesos, multiplicada per un factor petit λ.
perdua_total = perdua_dades + λ·Σw² - L1: igual però amb valors absoluts (
λ·Σ|w|); el seu efecte lateral és empènyer molts pesos exactament a zero (produeix xarxes "disperses").
Per què els pesos petits generalitzen millor? La intuïció: un pes enorme significa que la xarxa es recolza moltíssim en un detall concret de l'entrada — el tipus de dependència fràgil que caracteritza la memorització. Amb la penalització, cada pes s'ha de "guanyar el sou": només es manté gran si redueix la pèrdua de dades més del que costa en penalització. El resultat són funcions més suaus, menys capaces de retorçar-se per ajustar punts de soroll individuals. Recorda el "comitè de compres" de 01-04: L2 impedeix que un sol vocal cridi tant que decideixi ell sol.
En Keras s'aplica per capa:
from tensorflow.keras import layers, regularizers
capa = layers.Dense(
128, activation="relu",
kernel_regularizer=regularizers.l2(1e-4), # lambda tipic: 1e-4 a 1e-2
)Valors típics de λ: entre 1e-5 i 1e-2. Massa alt i la xarxa esdevé incapaç d'aprendre (bias); massa baix i no fa res.
Dropout
Dropout és la tècnica de regularització més emblemàtica del deep learning: durant l'entrenament, a cada passada, s'apaga aleatòriament una fracció de les neurones de la capa (per exemple el 30 %, rate=0.3). A cada batch s'apaguen neurones diferents.
Per què funciona una cosa tan aparentment destructiva?
- Impedeix la coadaptació: sense dropout, una neurona es pot especialitzar a corregir els errors d'una altra de concreta, creant dependències fràgils i circuits que memoritzen. Si la teva companya pot desaparèixer en qualsevol moment, no pots construir la teva funció sobre ella: cada neurona ha d'aprendre trets útils per si mateixos.
- Entrena un comitè implícit: cada patró d'apagada defineix una subxarxa diferent; el model final es comporta com la mitjana d'un enorme conjunt de xarxes més petites — i fer la mitjana de models redueix la variància (la mateixa lògica del comitè de compres de 01-04, ara dins de la xarxa).
Detalls operatius:
- Comportament diferent en train i inference: en entrenament apaga neurones; en predicció (
predict/evaluate) no apaga res i compensa les magnituds automàticament. Keras ho gestiona sol — però explica per què la pèrdua d'entrenament que reportafitpot semblar pitjor que la de validació al principi: la de train es mesura amb dropout actiu. - On col·locar-lo: després de les capes denses grans (el lloc clàssic) i després del pooling global en caps de CNN, com vam fer a 05-03. En convolucions intermèdies és menys habitual; en RNN es fan servir variants específiques (els arguments
dropout/recurrent_dropoutde la capa LSTM). - Taxa típica: 0.2–0.5. Comença per 0.2–0.3; 0.5 és agressiu i propi de capes denses molt grans.
model = keras.Sequential([
layers.Dense(256, activation="relu", input_shape=(784,)),
layers.Dropout(0.3), # apaga el 30% de les 256 sortides A CADA BATCH
layers.Dense(128, activation="relu"),
layers.Dropout(0.3),
layers.Dense(10, activation="softmax"),
])Batch Normalization
Batch Normalization (BN) normalitza les activacions d'una capa dins de cada batch: els resta la mitjana del batch i les divideix per la seva desviació, deixant-les centrades i amb escala controlada (i després aplica una escala i un desplaçament aprenibles, per no perdre expressivitat).
Per què ajuda:
- Accelera i estabilitza l'entrenament: sense BN, cada capa rep entrades la distribució de les quals canvia constantment a mesura que les capes anteriors aprenen — és com apuntar a un blanc mòbil. BN manté aquestes distribucions estables, cosa que permet learning rates més grans i fa la xarxa molt menys sensible a la inicialització. També mitiga el vanishing/exploding gradient de 02-03, perquè evita que les activacions se'n vagin a les zones planes de les funcions d'activació (l'"aixeta" que es tanca).
- Efecte regularitzador secundari: com que mitjana i desviació es calculen sobre el batch, cada exemple es normalitza de manera lleugerament diferent segons amb qui comparteixi batch. Aquest petit soroll actua com a regularització suau — un benefici col·lateral, no el seu propòsit principal.
On va: entre la part lineal de la capa i l'activació és la recepta clàssica (Dense/Conv2D → BatchNormalization → Activation), tot i que col·locar-la després de l'activació també és comú i funciona; a la pràctica veuràs totes dues. Ja la vas fer servir sense saber-ho dues vegades: al generador de la DCGAN (05-01) i dins de MobileNetV2 (05-03).
model = keras.Sequential([
layers.Dense(256, use_bias=False, input_shape=(784,)), # BN ja centra:
layers.BatchNormalization(), # el bias sobra
layers.Activation("relu"),
layers.Dense(10, activation="softmax"),
])Igual que Dropout, BN es comporta diferent en inferència: a predict fa servir mitjanes i desviacions acumulades durant l'entrenament (no les del batch actual, que podria ser un sol exemple). D'aquí el training=False que vam passar a la base congelada a 05-03.
Early Stopping
La tècnica més simple i potser la més rendible: deixar d'entrenar quan la validació deixa de millorar. Si el sobreajust apareix a partir de certa època, no entrenis més enllà — el millor model és el d'abans que les corbes divergeixin.
En Keras és un callback:
aturada = keras.callbacks.EarlyStopping(
monitor="val_loss", # quina metrica vigilar
patience=5, # epoques de gracia sense millora abans de parar
restore_best_weights=True, # en parar, RECUPERA els pesos de la millor epoca
)
historial = model.fit(x_train, y_train,
validation_split=0.1,
epochs=100, # un maxim generos: parara abans
callbacks=[aturada])Tres detalls que marquen la diferència:
patience: la validació oscil·la de manera natural; sense paciència, pararies al primer sotrac. 5–10 èpoques és l'habitual.restore_best_weights=True: sense això, et quedes amb els pesos de l'última època (que ja era pitjor), no de la millor. Activa'l sempre.- Amb early stopping pots posar
epochsalt sense por: el nombre d'èpoques deixa de ser un hiperparàmetre crític que calgui endevinar.
Augment de dades per a imatges
Contra la variància, res no funciona millor que més dades. Quan no n'hi ha, es fabriquen variacions plausibles de les existents: és l'augment de dades (data augmentation) que vam prometre a 03-04 en parlar del classificador de fotos de producte.
La idea: una torradora continua sent una torradora si la foto està mirallada, lleugerament girada, amb més zoom o amb una altra il·luminació. Aplicant aquestes transformacions aleatòriament a cada època, la xarxa no veu mai dues vegades exactament la mateixa imatge — memoritzar esdevé impossible i la xarxa aprèn invariàncies reals (l'essència "torradora" que sobreviu als canvis).
En Keras modern, l'augment són capes dins del model, actives només durant l'entrenament:
augment = keras.Sequential([
layers.RandomFlip("horizontal"), # mirall esquerra-dreta
layers.RandomRotation(0.05), # girs de fins a ±5% de volta (±18 graus)
layers.RandomZoom(0.15), # apropar/allunyar fins a un 15%
layers.RandomContrast(0.2), # variar el contrast (il.luminacio)
layers.RandomTranslation(0.1, 0.1), # desplacar fins a un 10%
], name="augment_de_dades")
# S'insereix al principi del model (despres de l'Input, abans de la base):
entrades = keras.Input(shape=(160, 160, 3))
x = augment(entrades) # nomes actua quan training=True
x = keras.applications.mobilenet_v2.preprocess_input(x)
# ... base + cap com a 05-03Regla de seny: les transformacions han de conservar l'etiqueta i ser plausibles en producció. Mirallar una cafetera, bé; mirallar un dígit de MNIST en converteix alguns en brossa (un 2 mirallat no és un 2), i posar una torradora de cap per avall no ajuda si cap foto real no vindrà així.
Taula resum de l'arsenal
| Tècnica | Quan fer-la servir | Cost / contrapartida |
|---|---|---|
| L2 (weight decay) | Sobreajust general en capes denses/conv; gairebé sempre inofensiva en dosis baixes | Un hiperparàmetre més (λ); dosi alta causa subajust |
| L1 | Quan a més interessa dispersar (pesos a zero, selecció de trets) | Menys usada; mateixa precaució amb λ |
| Dropout | Capes denses grans; caps de classificació | Allarga l'entrenament (la xarxa "efectiva" és menor); no barrejar alegrement amb BN a la mateixa capa |
| Batch Normalization | Xarxes profundes: accelera, estabilitza i regularitza de propina | Lleuger cost de còmput; compte amb batches molt petits (estadístiques sorolloses) |
| Early Stopping | Pràcticament sempre | Cap de rellevant; requereix conjunt de validació |
| Augment de dades | Imatges amb datasets petits/mitjans (el cas TecnoMarket) | Entrenament més llarg; exigeix triar transformacions plausibles |
| Més dades reals | Sempre que sigui viable | El més car… i el més efectiu |
Estratègia recomanada: early stopping sempre; augment de dades si treballes amb imatges; després dropout o L2 si el forat train/val persisteix; BN si a més l'entrenament és lent o inestable.
Exemple integrador: el MNIST de 02-05, millorat
Tanquem el deute pendent. Aquesta és la xarxa densa de 02-05 (~97,7 % i sobreajust lleu), reforçada amb BN + Dropout + Early Stopping:
from tensorflow import keras
from tensorflow.keras import layers
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = x_train.reshape(-1, 784).astype("float32") / 255.0
x_test = x_test.reshape(-1, 784).astype("float32") / 255.0
def construir(regularitzada: bool) -> keras.Sequential:
"""La mateixa xarxa de 02-05, amb o sense l'arsenal de regularitzacio."""
capes = [layers.Input(shape=(784,))]
for unitats in (256, 128):
if regularitzada:
capes += [layers.Dense(unitats, use_bias=False),
layers.BatchNormalization(),
layers.Activation("relu"),
layers.Dropout(0.3)]
else:
capes += [layers.Dense(unitats, activation="relu")]
capes.append(layers.Dense(10, activation="softmax"))
return keras.Sequential(capes)
aturada = keras.callbacks.EarlyStopping(monitor="val_loss", patience=5,
restore_best_weights=True)
resultats = {}
for nom, reg in [("original", False), ("regularitzada", True)]:
model = construir(regularitzada=reg)
model.compile(optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"])
hist = model.fit(x_train, y_train, validation_split=0.1,
epochs=50, batch_size=128,
callbacks=[aturada] if reg else [],
verbose=0)
perdua, acc = model.evaluate(x_test, y_test, verbose=0)
resultats[nom] = (hist, acc)
print(f"{nom}: test accuracy = {acc:.4f}, "
f"epoques entrenades = {len(hist.history['loss'])}")I la comparació de corbes, el veredicte visual:
import matplotlib.pyplot as plt
fig, eixos = plt.subplots(1, 2, figsize=(12, 4), sharey=True)
for eix, (nom, (hist, _)) in zip(eixos, resultats.items()):
eix.plot(hist.history["loss"], label="train")
eix.plot(hist.history["val_loss"], label="validacio")
eix.set_title(nom); eix.set_xlabel("epoca"); eix.legend()
eixos[0].set_ylabel("perdua")
plt.show()Què esperar en executar-ho:
- Original: les corbes de 02-05 — train baixa sense parar, val es desenganxa i puja. El forat creix amb les èpoques.
- Regularitzada: les corbes viatgen juntes; la de validació es manté igual o fins i tot per sota de la de train al principi (recorda: la de train es mesura amb dropout actiu). L'entrenament s'atura sol quan deixa de millorar, i
restore_best_weightset retorna el millor punt. - En test, la versió regularitzada sol gratar unes dècimes (cap al ~98 %+) — però el guany important no és aquest: és que ara el rendiment de validació prediu el de test, perquè el model generalitza. En problemes amb menys dades que MNIST (com el catàleg de TecnoMarket), la diferència no són dècimes: són molts punts.
Menció: learning rate schedules
Última peça, només com a menció (els optimitzadors en si ja es van veure a 02-04): en lloc d'un learning rate fix, és habitual reduir-lo durant l'entrenament — passos grans al principi per avançar, petits al final per afinar. Dues formes freqüents en Keras: keras.callbacks.ReduceLROnPlateau (divideix el lr quan la validació s'estanca — combina de meravella amb early stopping) i els schedules predefinits (decaïment exponencial, cosinus). No és regularització en sentit estricte, però és de les "tècniques de millora" més rendibles per línia de codi.
Errors Comuns i Consells
- Regularitzar un model que subajusta. Si la pèrdua d'entrenament ja és dolenta, dropout/L2 l'empitjoraran. Diagnostica primer (bias vs. variance); regularitza només la variància.
- Interpretar malament les corbes amb dropout. Que la pèrdua de validació quedi per sota de la d'entrenament no és un error de Keras: la de train es calcula amb neurones apagades i la de val amb la xarxa completa.
- Augmentar les dades de validació/test. Les capes d'augment han d'actuar només en entrenament (les capes Random* de Keras ja ho fan automàticament); si augmentes la validació, les teves mètriques deixen de ser comparables entre èpoques.
- Apilar-ho tot alhora. Si afegeixes L2 + dropout 0.5 + BN + augment agressiu de cop i la xarxa no aprèn, no sabràs què sobra. Afegeix tècniques d'una en una, mesurant-ne l'efecte a les corbes.
- Triar augments que canvien l'etiqueta. El mirall horitzontal destrossa dígits i text; una rotació de 45° no passa en fotos reals de catàleg. Pensa sempre "podria arribar així una imatge real, i continuaria sent la mateixa classe?".
- Oblidar
restore_best_weights=True. Early stopping sense això atura l'entrenament però et deixa els pesos d'una època ja degradada.
Exercicis
Exercici 1. Per a cada escenari, digues si el problema és de bias o de variance i quines dues mesures de l'arsenal aplicaries primer: (a) el classificador de ressenyes de 04-03 dona 99,5 % en train i 78 % en validació; (b) la LSTM de vendes de 04-04 dona error alt tant en train com en validació; (c) el transfer learning de 05-03 amb base congelada dona corbes train/val enganxades i bones, però després del fine-tuning la de validació empitjora època rere època.
Exercici 2. Dissenya la capa Sequential d'augment de dades per a les fotos de producte de TecnoMarket (fotos de catàleg: producte centrat, fons clar, sempre dret). Justifica cada transformació inclosa i anomena una transformació que no hi inclouries i per què.
Exercici 3. Un company entrena amb EarlyStopping(monitor="val_loss", patience=0) i es queixa que l'entrenament "para gairebé al començar", a l'època 4, tot i que la tendència general de la validació era descendent. Explica què passa i com corregir-ho.
Solucions
Solució 1.
- (a) Forat enorme train/val → variance (sobreajust clar). Primeres mesures: dropout a les capes denses/recurrents del classificador i early stopping; si persisteix, reduir la mida del model o aconseguir més ressenyes etiquetades.
- (b) Malament en totes dues corbes → bias (subajust). La regularització no ajuda aquí: augmentar la capacitat (més unitats/capes), entrenar més èpoques, o millorar les característiques d'entrada (finestres més informatives, variables de calendari com el Black Friday).
- (c) El fine-tuning ha introduït variance: en descongelar, la capacitat efectiva entrenable es va disparar amb les mateixes dades. Mesures: early stopping amb
restore_best_weights(tornar al millor punt) i augment de dades; també val reduir quantes capes es descongelen o abaixar encara més el learning rate.
Solució 2.
augment = keras.Sequential([
layers.RandomFlip("horizontal"), # un producte mirallat continua sent el
# mateix producte i es plausible
layers.RandomZoom(0.15), # l'enquadrament varia entre fotos reals
layers.RandomTranslation(0.1, 0.1),# el producte no sempre esta perfectament centrat
layers.RandomContrast(0.2), # il.luminacio variable entre sessions de foto
layers.RandomRotation(0.02), # inclinacions molt lleus (camera no perfectament recta)
])No hi inclouria rotacions grans (p. ex. RandomRotation(0.25), fins a 90°): les fotos de catàleg mostren sempre el producte dret, així que la xarxa gastaria capacitat en una invariància que mai no necessitarà en producció — i algunes categories es podrien confondre girades. (També seria defensable excloure el flip per a productes amb text visible al frontal, com caixes: el text mirallat no és plausible.)
Solució 3.
Amb patience=0, l'entrenament s'atura tan bon punt la val_loss empitjora una sola època respecte a la millor vista. Però la pèrdua de validació oscil·la de manera natural (batches, dropout, atzar), així que un petit repunt a l'època 4 —encara que la tendència de fons sigui descendent— dispara l'aturada. Correcció: donar marge amb patience=5 (o 10 en entrenaments llargs) i mantenir restore_best_weights=True, de manera que s'explorin diverses èpoques més enllà de cada sotrac i, en parar de veritat, es recuperin els pesos de la millor època.
Conclusió
Has tancat el deute obert a 02-05: ara saps diagnosticar el sobreajust a les corbes (forat train/val creixent), distingir-lo del subajust amb la lent bias/variance, i atacar-lo amb un arsenal ordenat — L2 per a pesos continguts, dropout com a comitè intern, Batch Normalization per entrenar ràpid i estable, early stopping com a xarxa de seguretat universal i augment de dades com a fàbrica d'exemples plausibles. Són tècniques transversals: aplica-les retroactivament a qualsevol model del curs i, molt especialment, als projectes del mòdul 7.
Queda l'última peça del mòdul, i és la més influent de la dècada: a 04-03 vam deixar assenyalat el coll d'ampolla del vector únic en els models seqüència-a-seqüència. La solució —l'atenció— no només va resoldre aquest problema: va reorganitzar el deep learning sencer al voltant d'una nova arquitectura, el Transformer. És la propera lliçó.
Curs de Deep Learning
Mòdul 1: Introducció al Deep Learning
- Què és el Deep Learning?
- Història i evolució del Deep Learning
- Aplicacions del Deep Learning
- Conceptes bàsics de xarxes neuronals
- Preparació de l'entorn de treball
Mòdul 2: Fonaments de Xarxes Neuronals
- Perceptró i Perceptró Multicapa
- Funció d'activació
- Propagació cap endavant i cap enrere
- Optimització i funció de pèrdua
- La teva primera xarxa neuronal completa
Mòdul 3: Xarxes Neuronals Convolucionals (CNN)
- Introducció a les CNN
- Capes convolucionals i de pooling
- Arquitectures populars de CNN
- Aplicacions de CNN en reconeixement d'imatges
Mòdul 4: Xarxes Neuronals Recurrents (RNN)
- Introducció a les RNN
- LSTM i GRU
- Aplicacions de RNN en processament del llenguatge natural
- Seqüències i sèries temporals
Mòdul 5: Tècniques Avançades en Deep Learning
- Xarxes Generatives Adversàries (GAN)
- Autoencoders
- Transfer Learning
- Regularització i tècniques de millora
- Mecanismes d'atenció i Transformers
Mòdul 6: Eines i Frameworks
- Introducció a TensorFlow
- Introducció a PyTorch
- Comparació de frameworks
- Entorns de desenvolupament i recursos addicionals
- Desar, carregar i desplegar models
Mòdul 7: Projectes Pràctics
- Classificació d'imatges amb CNN
- Generació de text amb RNN
- Detecció d'anomalies amb Autoencoders
- Creació d'una GAN per a generació d'imatges
- Fine-tuning d'un model preentrenat
