A 07-01 vam deixar una xifra sobre la taula — 82-85 % d'exactitud del classificador de categories — i una promesa: batre-la gairebé sense escriure més codi. Aquest projecte final la compleix amb el transfer learning de 05-03: en lloc d'entrenar una CNN des de zero, agafarem MobileNetV2 preentrenada a ImageNet i l'adaptarem al nostre problema en dues fases (extracció de característiques i fine-tuning). En acabar compararàs tots dos enfocaments amb números a la mà, decidiràs quin desplega TecnoMarket i tancaràs el mòdul amb els cinc projectes lliurats.

Contingut

  1. Enunciat: refer 07-01 i batre'l
  2. Fase 1: dades — redimensionament i preprocess_input correcte
  3. Fase 2: el model amb MobileNetV2 congelada
  4. Fase 3: entrenament en dues fases (extracció → fine-tuning)
  5. Fase 4: comparació de corbes entre fases
  6. Fase 5: comparació final honesta contra la CNN de 07-01
  7. Fase 6: quan surt a compte el transfer learning (la taula 2×2, revisada)
  8. Fase 7: empaquetament final i decisió de negoci
  9. Tancament del mòdul: el portfolio de TecnoMarket

Enunciat: refer 07-01 i batre'l

Mateix problema, mateixes dades, mateixa vara de mesurar: CIFAR-10 com a substitut de les categories de producte de TecnoMarket, el mateix conjunt de test congelat de 07-01 i la mateixa partició train/validació. Només canvia l'estratègia: en lloc d'aprendre a veure des de zero amb 45 000 imatges, partim d'una xarxa que ja va aprendre a veure amb 1.4 milions (ImageNet) i li ensenyem únicament les nostres categories. És l'aposta central de 05-03; avui la mesurem contra una alternativa real construïda per nosaltres mateixos — la comparació més honesta possible.

Objectiu quantitatiu: superar clarament el 85 % de 07-01. Resultat típic esperable: 90-93 %.

Fase 1: dades — redimensionament i preprocess_input correcte

MobileNetV2 no accepta 32×32: va ser preentrenada amb imatges grans i la seva cascada de reduccions deixaria mapes buits. Redimensionem a 160×160 (compromís entre fidelitat i cost; 05-03). I el punt que més projectes trenca: cada xarxa preentrenada exigeix el seu propi preprocessament. MobileNetV2 espera píxels en [-1, 1], no el /255 que vam fer servir a 07-01:

import tensorflow as tf
import numpy as np

tf.random.set_seed(42)

(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data()
x_val, y_val = x_train[45000:], y_train[45000:]      # mateixa partició que 07-01
x_train, y_train = x_train[:45000], y_train[:45000]

MIDA = 160
BATCH = 64
AUTOTUNE = tf.data.AUTOTUNE

augment = tf.keras.Sequential([                       # mateix augment que 07-01 (05-04)
    tf.keras.layers.RandomFlip("horizontal"),
    tf.keras.layers.RandomTranslation(0.1, 0.1),
    tf.keras.layers.RandomZoom(0.1),
])

def preparar(x, y):
    x = tf.image.resize(tf.cast(x, tf.float32), (MIDA, MIDA))
    x = tf.keras.applications.mobilenet_v2.preprocess_input(x)  # -> [-1, 1]
    return x, y

def dataset(x, y, entrenar=False):
    ds = tf.data.Dataset.from_tensor_slices((x, y)).map(preparar, AUTOTUNE)
    if entrenar:
        ds = ds.shuffle(10_000).batch(BATCH).map(
            lambda a, b: (augment(a, training=True), b), AUTOTUNE)
    else:
        ds = ds.batch(BATCH)
    return ds.prefetch(AUTOTUNE)

train_ds = dataset(x_train, y_train, entrenar=True)
val_ds = dataset(x_val, y_val)
test_ds = dataset(x_test, y_test)

Fer servir el preprocess_input de la mateixa família de model no és opcional: amb el /255 de 07-01, MobileNetV2 rebria entrades fora de la distribució amb què es va preentrenar i rendiria uns quants punts per sota sense donar cap error visible.

Fase 2: el model amb MobileNetV2 congelada

La recepta de 05-03: base preentrenada sense cap (include_top=False), congelada, més un cap nou mínim:

from tensorflow.keras import layers, models

base = tf.keras.applications.MobileNetV2(
    input_shape=(MIDA, MIDA, 3),
    include_top=False,           # sense el cap de les 1000 classes d'ImageNet
    weights="imagenet",
)
base.trainable = False           # fase 1: congelada del tot

entrades = layers.Input(shape=(MIDA, MIDA, 3))
x = base(entrades, training=False)   # training=False: BN en mode inferència (05-03)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dropout(0.3)(x)
sortides = layers.Dense(10, activation="softmax")(x)
model = models.Model(entrades, sortides, name="tecnomarket_tl")

model.summary()
# Total: ~2.3 M de parametres; entrenables: ~13 000 (nomes el cap)

Fixa't en la desproporció: la base aporta ~2.26 M de paràmetres ja apresos; nosaltres només n'entrenem ~13 000. El training=False en la crida a la base és el detall subtil de 05-03: manté les BatchNormalization en mode inferència fins i tot durant el fine-tuning posterior, protegint les estadístiques d'ImageNet.

Fase 3: entrenament en dues fases (extracció → fine-tuning)

Fase d'extracció de característiques — només el cap, lr normal:

model.compile(optimizer=tf.keras.optimizers.Adam(1e-3),
              loss="sparse_categorical_crossentropy", metrics=["accuracy"])

callbacks = [
    tf.keras.callbacks.EarlyStopping(monitor="val_accuracy", patience=5,
                                     restore_best_weights=True),
    tf.keras.callbacks.ModelCheckpoint("models/tl_extraccio.keras",
                                       monitor="val_accuracy", save_best_only=True),
    tf.keras.callbacks.TensorBoard(log_dir="logs/tl_fase1"),
]
hist1 = model.fit(train_ds, validation_data=val_ds, epochs=15,
                  callbacks=callbacks)
# Resultat típic: val_accuracy ~86-88 % en 8-12 èpoques

Ja en aquesta fase — entrenant el 0.6 % dels paràmetres — se supera la CNN de 07-01. Les característiques d'ImageNet (vores, textures, formes d'objectes) transfereixen bé a CIFAR-10.

Fase de fine-tuning — descongelar el bloc final, lr baix:

base.trainable = True
for capa in base.layers[:100]:       # MobileNetV2 té 154 capes: alliberem ~1/3 final
    capa.trainable = False

model.compile(optimizer=tf.keras.optimizers.Adam(1e-5),   # lr 100x més baix
              loss="sparse_categorical_crossentropy", metrics=["accuracy"])

callbacks[1] = tf.keras.callbacks.ModelCheckpoint("models/tl_finetuning.keras",
               monitor="val_accuracy", save_best_only=True)
callbacks[2] = tf.keras.callbacks.TensorBoard(log_dir="logs/tl_fase2")

hist2 = model.fit(train_ds, validation_data=val_ds, epochs=15,
                  callbacks=callbacks)
# Resultat típic: val_accuracy ~90-93 %

Les dues regles d'or de 05-03, aplicades: recompilar després de canviar trainable (si no, el canvi no té efecte) i learning rate molt baix (1e-5): les capes descongelades ja contenen coneixement valuós; un lr alt el destruiria a les primeres iteracions (l'anomenat catastrophic forgetting). Descongelem només el bloc final perquè les capes primerenques (vores, colors) són universals i les tardanes són les que convé especialitzar en les nostres categories.

Fase 4: comparació de corbes entre fases

Concatena tots dos historials i pinta l'exactitud de validació amb una línia vertical en el canvi de fase:

import matplotlib.pyplot as plt

acc = hist1.history["val_accuracy"] + hist2.history["val_accuracy"]
plt.plot(acc, label="val_accuracy")
plt.axvline(len(hist1.history["val_accuracy"]) - 1, ls="--", c="gray",
            label="inici fine-tuning")
plt.xlabel("epoca"); plt.legend(); plt.grid(True)

Lectura típica de la corba:

  • Fase 1: pujada ràpida les primeres èpoques i altiplà en ~87 % — el cap espreme tot el que donen unes característiques genèriques congelades.
  • Canvi de fase: un salt visible de 2-4 punts a les primeres èpoques de fine-tuning — les capes finals s'adapten a textures de CIFAR — i un nou altiplà en ~91-92 %.
  • Si a la fase 2 l'exactitud cau de cop, el lr era massa alt: és el símptoma clàssic.

Fase 5: comparació final honesta contra la CNN de 07-01

Avalua sobre el mateix test congelat de 07-01 i posa les xifres cara a cara. Valors típics (els teus variaran una mica; fes servir els que obtinguis de veritat):

test_loss, test_acc = model.evaluate(test_ds)
print(f"Exactitud test transfer learning: {test_acc:.3f}")
Criteri CNN pròpia (07-01) MobileNetV2 + fine-tuning
Exactitud en test ~83 % ~91 %
Paràmetres totals ~1.2 M ~2.3 M
Paràmetres entrenats ~1.2 M (tots) ~13 K + ~0.9 M (fase 2)
Èpoques fins al millor model 40-50 10 + 8
Temps d'entrenament (GPU) ~20 min ~25-35 min*
Mida en disc ~14 MB ~28 MB
Cost d'inferència Menor (entrada 32×32) Major (entrada 160×160)

* Cada època del transfer learning és més cara (imatges 160×160), però en necessita moltes menys.

Conclusions honestes: +8 punts d'exactitud és una millora enorme (els errors baixen de ~17 % a ~9 %: gairebé la meitat); el preu és un model més gran i una inferència més cara. Repeteix també la matriu de confusió de 07-01: veuràs que les parelles conflictives (gat↔gos) continuen sent les pitjors, però amb la meitat de confusions — amb el llindar de 0.80 de 03-04, la cobertura automàtica típica puja del ~70 % al ~85 %.

Fase 6: quan surt a compte el transfer learning (la taula 2×2, revisada)

Reprenem la taula 2×2 de 05-03 i hi situem aquest projecte:

Dades semblants a ImageNet Dades molt diferents
Poques dades Extracció de característiques (només cap) Fine-tuning profund amb compte, o buscar una altra base
Moltes dades Fine-tuning parcial ← el nostre cas Considerar entrenar des de zero

CIFAR-10 cau a «moltes dades (45 K), semblants a ImageNet (objectes naturals)»: la casella del fine-tuning parcial, i els resultats ho confirmen. La CNN des de zero de 07-01 només hauria estat competitiva a la casella inferior dreta — per exemple, imatges mèdiques o espectrogrames amb milions d'exemples. Per a les fotos de producte reals de TecnoMarket (objectes quotidians, desenes de milers de fotos), la recepta d'avui és la correcta gairebé amb tota seguretat.

Fase 7: empaquetament final i decisió de negoci

Decisió: TecnoMarket desplega el model de transfer learning. La millora d'exactitud redueix a la meitat la càrrega de la cua de revisió (03-04), cosa que compensa amb escreix el cost d'inferència més alt. La CNN de 07-01 queda documentada com a baseline al repositori (git, 06-04) — tot model en producció necessita un baseline contra el qual justificar-se.

Empaquetament segons 06-05, amb el preprocessament dins del model:

entrada = tf.keras.layers.Input(shape=(32, 32, 3), dtype=tf.uint8)  # imatge crua
x = tf.cast(entrada, tf.float32)
x = tf.keras.layers.Resizing(MIDA, MIDA)(x)
x = tf.keras.applications.mobilenet_v2.preprocess_input(x)
prob = model(x, training=False)
model_servei = tf.keras.Model(entrada, prob)
model_servei.save("models/classificador_categories_v2.keras")

Redimensionament i preprocess_input viatgen dins del .keras: l'API de FastAPI de 06-05 rep la imatge crua i no es pot equivocar de preprocessament. Abans de substituir la v1, el protocol de 06-05: validar la v2 sobre el conjunt congelat, comparar contra la v1 amb les mateixes imatges, desplegar amb possibilitat de marxa enrere i recalibrar el llindar de confiança sobre validació.

Tancament del mòdul: el portfolio de TecnoMarket

Amb aquest cinquè projecte, l'equip de TecnoMarket (és a dir, tu) lliura el seu portfolio complet:

Projecte Problema de negoci Tècnica principal Estat
07-01 Alta automàtica d'articles CNN pròpia + llindar i cua de revisió Baseline documentat
07-02 Esborranys de descripcions LSTM caràcter a caràcter + temperatura Prototip amb revisió humana
07-03 Detecció de frau Autoencoder + error de reconstrucció En producció amb recalibratge periòdic
07-04 Creativitats generatives DCGAN amb bucle GradientTape Prototip educatiu; producció requereix difusió
07-05 Alta automàtica, v2 Transfer learning MobileNetV2 Desplegat, substitueix 07-01

Cinc projectes, quatre modalitats (imatges, text, dades tabulars, generació) i un mètode comú: fases clares, particions honestes, mètriques adequades al problema, humans al circuit i lliurament empaquetat.

Errors Comuns i Consells

  • Fer servir /255 en lloc del preprocess_input de la família del model: l'error silenciós més comú del transfer learning; costa uns quants punts d'exactitud sense llançar cap excepció.
  • Oblidar recompilar després de canviar trainable: Keras fixa quines variables s'entrenen en compilar; sense recompilar, el teu «fine-tuning» continua entrenant només el cap.
  • Fine-tuning amb el mateix lr de la fase 1: destrueix els pesos preentrenats en poques iteracions i l'exactitud es desploma. Abaixa el lr dos ordres de magnitud.
  • Descongelar tota la base amb poques dades: més paràmetres lliures dels que les teves dades poden governar; sobreajust gairebé garantit. Descongela per blocs, del final cap enrere.
  • Comparar models amb particions diferents: la comparació de la fase 5 només val perquè el test congelat i la partició train/val són idèntics als de 07-01. Canviar les dades entre comparacions invalida la taula.

Exercicis

  1. Repeteix el projecte entrenant només la fase d'extracció (sense fine-tuning) i compara la taula de la fase 5 amb tres columnes: CNN pròpia, extracció sola, extracció + fine-tuning. Quant aporta cada esglaó?
  2. Prova MIDA = 96 en lloc de 160 i mesura exactitud i temps per època. On queda en la comparació cost/benefici?
  3. Descongela només les últimes 20 capes (en lloc de ~54) i, per separat, la base sencera. Compara l'exactitud final i el comportament de les corbes en els tres escenaris de descongelació.

Solucions

  1. N'hi ha prou de saltar-se la fase 2. Taula típica: CNN pròpia ~83 %, extracció ~87 %, extracció+fine-tuning ~91 %. Lectura: el gruix del salt el dona el preentrenament (característiques d'ImageNet); el fine-tuning hi afegeix el refinament final. Si el pressupost de còmput és mínim, l'extracció sola ja bat el model propi.
  2. Amb 96×96 el temps per època cau aproximadament a la meitat i l'exactitud típica baixa 1-2 punts (~89-90 %): menys resolució, menys detall per a les capes profundes. És un punt intermedi raonable per iterar ràpid i entrenar la versió final a 160.
  3. Amb 20 capes el resultat es queda ~1 punt per sota de l'escenari base (menys capacitat d'adaptació); amb la base sencera i lr=1e-5 pot igualar o millorar dècimes, però les corbes són més fràgils (més risc de sobreajust i de caiguda inicial) i l'entrenament és més lent. El terç final és el compromís robust: prou adaptació sense posar en risc les capes universals.

Conclusió

Projecte final lliurat i promesa complerta: el classificador v2 amb MobileNetV2 bat la CNN pròpia de 07-01 per uns 8 punts, amb una comparació honesta de costos i una decisió de desplegament justificada. Més important que la xifra és el criteri que t'emportes: la taula 2×2 per decidir quan transferir, les dues fases amb els seus dos learning rates, i la disciplina de comparar sempre contra un baseline sobre el mateix test congelat. Amb això es tanca el mòdul 7: cinc projectes de cap a cap al portfolio de TecnoMarket, integrant tot el que has après des de la primera xarxa densa de 02-05 fins al desplegament de 06-05. Però un professional no acaba quan el model funciona: el que hem construït — models que classifiquen productes, generen textos i imatges i assenyalen clients com a sospitosos — té conseqüències sobre persones reals. El mòdul 8 aborda exactament això: l'ètica, l'impacte i el futur del Deep Learning que tot practicant ha de dominar.

Curs de Deep Learning

Mòdul 1: Introducció al Deep Learning

Mòdul 2: Fonaments de Xarxes Neuronals

Mòdul 3: Xarxes Neuronals Convolucionals (CNN)

Mòdul 4: Xarxes Neuronals Recurrents (RNN)

Mòdul 5: Tècniques Avançades en Deep Learning

Mòdul 6: Eines i Frameworks

Mòdul 7: Projectes Pràctics

Mòdul 8: Consideracions Ètiques i Futur del Deep Learning

© Copyright 2026. Tots els drets reservats