Ja saps construir capes Conv2D i MaxPooling2D, predir les seves formes de sortida i comptar-ne els paràmetres. La pregunta natural següent és: com es combinen aquestes peces en xarxes que funcionen de debò? La bona notícia és que no cal inventar-ho des de zero: entre 1998 i avui, una sèrie d'arquitectures cèlebres va anar resolent, una a una, les dificultats d'entrenar CNN cada vegada més profundes, i els seus patrons de disseny s'han convertit en el vocabulari estàndard del camp. En aquesta lliçó recorrerem aquesta evolució —LeNet-5, AlexNet, VGG, GoogLeNet/Inception, ResNet i les famílies eficients per a mòbil— entenent la idea clau de cadascuna, i l'aterrarem implementant a Keras una mini-VGG i un bloc residual. Conèixer aquestes arquitectures no és cultura general: són exactament els models que TecnoMarket (i tu) reutilitzareu a la pràctica.
Contingut
- LeNet-5: la pionera (1998)
- AlexNet: el despertar (2012)
- VGG: l'elegància de la profunditat (2014)
- GoogLeNet/Inception: mòduls en paral·lel (2014)
- ResNet: connexions residuals (2015)
- Eficiència per a mòbil i edge: MobileNet i EfficientNet
- Taula comparativa
- Mans a l'obra: una mini-VGG i un bloc residual a Keras
LeNet-5: la pionera (1998)
Molt abans del boom del deep learning, Yann LeCun va dissenyar LeNet-5 per llegir dígits manuscrits en xecs bancaris — el mateix problema MNIST que vas resoldre a 02-05, però quinze anys abans i amb maquinari dels 90. La seva estructura et resultarà familiar perquè és exactament l'anatomia que vam veure a 03-01:
Entrada 32×32×1 → Conv 5×5 (6 filtres) → Pooling → Conv 5×5 (16 filtres) → Pooling → Densa 120 → Densa 84 → Sortida 10
- Uns 60 000 paràmetres en total: menys que la nostra xarxa densa de 02-05 (~110 000), i tanmateix més precisa en dígits, perquè respecta l'estructura espacial.
- Va establir el patró canònic conv → pool → conv → pool → denses que continuem fent servir.
- La seva limitació no era conceptual sinó d'època: sense GPUs, sense grans datasets i amb activacions sigmoide/tanh (amb el seu vanishing gradient, com vas veure a 02-03), no es podia escalar.
AlexNet: el despertar (2012)
A 01-02 vam explicar que AlexNet va guanyar ImageNet 2012 reduint l'error de manera tan brutal que va reactivar tot el camp. Ara pots entendre què era AlexNet: en essència, una LeNet a l'engròs més tres ingredients nous.
- Estructura: 5 capes convolucionals + 3 denses, ~60 milions de paràmetres, entrada 224×224×3 (la imatge del nostre càlcul d'explosió de paràmetres a 03-01!).
- Ingredient 1: ReLU en comptes de sigmoide/tanh — entrenament molt més ràpid i menys vanishing (02-02).
- Ingredient 2: GPUs — es va entrenar en dues GPUs domèstiques durant ~una setmana.
- Ingredient 3: dades massives (1.2 milions d'imatges d'ImageNet) i trucs contra el sobreajust com dropout i augment de dades (els sistematitzarem a 05-04).
- Resultat: 15.3 % d'error top-5 a ImageNet davant del 26.2 % del segon classificat. L'era moderna del deep learning comença aquí.
La seva lliçó de disseny: escala (més dades, més còmput, més capes) + ReLU. Però AlexNet era artesanal: filtres d'11×11, 5×5 i 3×3 barrejats sense cap criteri clar. L'arquitectura següent hi va posar ordre.
VGG: l'elegància de la profunditat (2014)
VGG (Universitat d'Oxford, 2014) es construeix sobre una única regla de disseny radicalment simple:
Fes servir sempre filtres 3×3 amb padding
same, apila'ls en blocs, i després de cada bloc fes max pooling 2×2 duplicant el nombre de filtres.
VGG-16 (16 capes amb pesos) queda així: blocs de 64, 128, 256, 512 i 512 filtres, i la imatge es redueix 224 → 112 → 56 → 28 → 14 → 7.
Per què filtres 3×3 i no més grans? Dos filtres 3×3 apilats "veuen" una zona de 5×5 (el segon mira una finestra de resultats que al seu torn van mirar finestres), i tres d'apilats veuen 7×7. Però comparem paràmetres per a C canals d'entrada i sortida:
| Opció | Camp receptiu | Paràmetres (sense biaixos) |
|---|---|---|
| 1 conv de 7×7 | 7×7 | 49 C² |
| 3 convs de 3×3 | 7×7 | 3 × 9 C² = 27 C² |
Les tres capes 3×3 veuen el mateix amb gairebé la meitat de paràmetres i, a més, intercalen tres ReLU en comptes d'una: més no-linealitat, més capacitat de representació. Aquesta observació va consagrar el 3×3 com a estàndard (per això el fem servir per defecte a 03-02).
El preu: VGG-16 té 138 milions de paràmetres, dels quals ~102 milions són a la primera capa densa després del Flatten (7×7×512 = 25 088 entrades × 4096 neurones) — la patologia que ja vam diagnosticar en llegir el summary() a 03-02, portada a l'extrem.
GoogLeNet/Inception: mòduls en paral·lel (2014)
El mateix any, Google va atacar la pregunta "quina mida de filtre faig servir a cada capa?" amb una resposta lateral: no triïs — fes-ne servir diversos alhora. El mòdul Inception aplica en paral·lel, sobre la mateixa entrada, convolucions 1×1, 3×3, 5×5 i un max pooling, i concatena tots els mapes resultants per l'eix de canals: la xarxa decideix durant l'entrenament a quina branca donar pes.
flowchart TB
E["Entrada del modul"] --> A["Conv 1x1"]
E --> B["Conv 1x1 -> Conv 3x3"]
E --> C["Conv 1x1 -> Conv 5x5"]
E --> D["MaxPool 3x3 -> Conv 1x1"]
A --> F["Concatenar canals"]
B --> F
C --> F
D --> F
Dues idees d'aquest disseny es van convertir en patrimoni comú:
- La convolució 1×1 ("bottleneck"): un filtre 1×1×C no mira veïns espacials, però barreja i comprimeix canals (p. ex. de 256 canals a 64) abans de les convolucions cares. És una capa densa aplicada píxel a píxel sobre el vector de canals, i abarateix dràsticament el mòdul.
- Global average pooling al final: en comptes de Flatten + denses gegants, es fa la mitjana de cada mapa de característiques complet a un sol número. GoogLeNet va aconseguir així 22 capes amb només ~7 milions de paràmetres — 20 vegades menys que VGG amb millor error.
ResNet: connexions residuals (2015)
Amb ReLU, GPUs i bons dissenys, seria d'esperar que apilar més capes sempre millorés. Però els experiments mostraven el contrari: a partir d'una certa profunditat (~20 capes), afegir capes empitjorava fins i tot l'error d'entrenament. No era sobreajust (això empitjoraria només la validació): era un problema d'optimització — la degradació. El gradient, després de travessar desenes de capes multiplicant derivades (la regla de la cadena i el "repartiment de la culpa" de 02-03), arribava a les primeres capes esvaït, i la xarxa profunda ni tan sols aconseguia aprendre el que la superficial ja sabia.
ResNet (Microsoft Research, 2015) ho va resoldre amb un canvi mínim i genial: la connexió residual (skip connection). En comptes de demanar a un bloc de capes que aprengui una transformació completa H(x), se li demana que aprengui només la correcció F(x) sobre la identitat, i l'entrada se suma directament a la sortida:
flowchart LR
X["x"] --> C1["Conv 3x3 + ReLU"]
C1 --> C2["Conv 3x3"]
C2 --> S(("+"))
X -->|"drecera (identitat)"| S
S --> R["ReLU"] --> Y["sortida"]
Per què funciona, en dues lectures:
- Lectura d'aprenentatge: si un bloc no aporta res d'útil, en té prou d'aprendre
F(x) = 0(pesos a zero, fàcil) i el bloc es converteix en la identitat: la xarxa de 50 capes mai no pot ser pitjor que la de 20, perquè les capes sobrants poden "apartar-se". Aprendre una correcció petita és més fàcil que aprendre una transformació sencera. - Lectura del gradient: en derivar
F(x) + x, la branca+ xté derivada 1, així que en la retropropagació el gradient disposa d'una autopista directa cap a les capes primerenques, sense travessar (i sense ser encongit per) totes les multiplicacions intermèdies. És la solució arquitectònica al vanishing gradient que vam analitzar a 02-03.
Amb això, la profunditat es va desbloquejar: ResNet-152 (152 capes) va guanyar ImageNet 2015 amb un error top-5 del 3.6 %, per sota de l'humà de referència (~5 %), i ResNet-50 continua sent avui un dels cavalls de batalla de la visió per computador. Les connexions residuals apareixen des de llavors gairebé a tot arreu, inclosos els transformers (05-05).
Eficiència per a mòbil i edge: MobileNet i EfficientNet
Menció breu, perquè te'ls creuaràs constantment: no tot és guanyar ImageNet. Si TecnoMarket volgués que la seva app mòbil classifiqués la foto al telèfon del venedor (sense pujar-la a un servidor), necessitaria xarxes petites i ràpides:
- MobileNet (2017): substitueix la convolució estàndard per la convolució separable en profunditat (primer un filtre espacial per canal, després una conv 1×1 que barreja canals), reduint el còmput ~8-9 vegades amb poca pèrdua de precisió. Ideal per a mòbil i dispositius edge.
- EfficientNet (2019): parteix d'una base eficient i defineix una regla d'escalat compost (augmentar alhora profunditat, amplada i resolució d'entrada en proporcions equilibrades), generant una família B0...B7 que cobreix des de mòbil fins a servidor amb precisió capdavantera per a cada nivell de còmput.
Taula comparativa
| Arquitectura | Any | Capes (amb pesos) | Paràmetres | Idea clau | Error top-5 ImageNet |
|---|---|---|---|---|---|
| LeNet-5 | 1998 | 7 | ~60 K | Patró conv→pool→denses | — (dígits, no ImageNet) |
| AlexNet | 2012 | 8 | ~60 M | Escala + ReLU + GPU | 15.3 % |
| VGG-16 | 2014 | 16 | ~138 M | Profunditat amb només filtres 3×3 | 7.3 % |
| GoogLeNet | 2014 | 22 | ~7 M | Mòduls Inception en paral·lel, convs 1×1 | 6.7 % |
| ResNet-152 | 2015 | 152 | ~60 M | Connexions residuals | 3.6 % |
| MobileNetV2 | 2018 | ~53 | ~3.5 M | Convs separables (mòbil/edge) | ~9 % (top-5, model petit) |
| EfficientNet-B7 | 2019 | ~200+ | ~66 M | Escalat compost | ~1.9 % |
La tendència que explica la taula: l'error cau del 15 % a menys del 2 % en set anys, i no a base d'inflar paràmetres (GoogLeNet i MobileNet els redueixen), sinó a base de millors idees d'arquitectura.
Mans a l'obra: una mini-VGG i un bloc residual a Keras
No implementarem VGG-16 ni ResNet-50 senceres (no tindria sentit entrenar-les des de zero aquí, i de seguida veurem per què tampoc no cal). Implementarem els patrons a escala reduïda, que és el que de debò es transfereix.
Mini-VGG per a fotos de producte
El patró VGG en miniatura per a imatges 64×64×3 de TecnoMarket, amb la regla "dues convs 3×3 same + pooling, duplicant filtres" i tancament modern amb global average pooling en lloc del Flatten golafre:
from tensorflow import keras
from tensorflow.keras import layers
def bloc_vgg(x, filtres):
"""Dues convs 3x3 'same' + ReLU, i un max pooling que redueix a la meitat."""
x = layers.Conv2D(filtres, (3, 3), padding="same", activation="relu")(x)
x = layers.Conv2D(filtres, (3, 3), padding="same", activation="relu")(x)
return layers.MaxPooling2D((2, 2))(x)
entrada = keras.Input(shape=(64, 64, 3))
x = bloc_vgg(entrada, 32) # 64x64 -> 32x32, 32 canals
x = bloc_vgg(x, 64) # 32x32 -> 16x16, 64 canals
x = bloc_vgg(x, 128) # 16x16 -> 8x8, 128 canals
x = layers.GlobalAveragePooling2D()(x) # 8x8x128 -> vector de 128 (mitjana de cada mapa)
sortida = layers.Dense(4, activation="softmax")(x) # 4 categories de producte
mini_vgg = keras.Model(entrada, sortida, name="mini_vgg")
mini_vgg.summary()Detalls que convé notar:
- Fem servir l'API funcional de Keras (
keras.Input, capes aplicades com a funcions,keras.Model) en comptes delSequentialde 02-05 i 03-02. Per a VGG tant se valdria, però és imprescindible per al bloc residual de sota, perquèSequentialnomés sap encadenar capes en línia recta i una drecera no és una línia recta. - Cada
bloc_vggapila dues convs abans del pooling: camp receptiu 5×5 amb paràmetres de 3×3+3×3 i dues ReLU — l'argument de VGG. GlobalAveragePooling2Dconverteix els 128 mapes de 8×8 en un vector de 128 mitjanes: la sortida densa només necessita 128×4+4 = 516 paràmetres. El model sencer queda en ~300 K paràmetres, sense la densa monstruosa que a 03-02 concentrava el 85 % del total.
Un bloc residual
El patró ResNet mínim — dues convs i la suma de la drecera:
def bloc_residual(x, filtres):
"""Bloc residual basic: sortida = ReLU( F(x) + x )."""
drecera = x # guardem l'entrada
y = layers.Conv2D(filtres, (3, 3), padding="same", activation="relu")(x)
y = layers.Conv2D(filtres, (3, 3), padding="same")(y) # sense activacio encara
y = layers.Add()([y, drecera]) # F(x) + x
return layers.Activation("relu")(y) # ReLU despres de la suma
entrada = keras.Input(shape=(16, 16, 64))
sortida = bloc_residual(entrada, 64)
bloc = keras.Model(entrada, sortida)
bloc.summary()Lectura del codi, línia a línia:
drecera = x: la connexió de salt no és cap capa, és simplement conservar la referència a l'entrada per fer-la servir després.- La segona conv va sense activació: primer se suma la drecera i després s'aplica la ReLU. Si activéssim abans de sumar,
F(x)només podria afegir valors positius i la correcció perdria la meitat del seu rang. layers.Add()([y, drecera])exigeix que tots dos tensors tinguin la mateixa forma — per això fem servir paddingsamei els mateixos 64 filtres que porta l'entrada. Quan un bloc canvia el nombre de canals o redueix la mida (stride 2), la drecera s'adapta amb una conv 1×1 (el truc bottleneck d'Inception reutilitzat); les ResNet reals alternen tots dos tipus de bloc.- Apilar
bloc_residualdesenes de vegades és, literalment, com es construeix una ResNet: cada bloc afegeix la seva petita correcció i el gradient sempre té la seva autopista de tornada.
Errors Comuns i Consells
- Intentar entrenar VGG-16 o ResNet-50 des de zero amb poques dades. Aquestes xarxes es van entrenar amb 1.2 milions d'imatges; amb les desenes de milers de fotos de TecnoMarket (o menys) sobreajustarien massivament. La solució és reutilitzar-les preentrenades (vegeu la conclusió).
- Confondre degradació amb sobreajust. El sobreajust empitjora la validació però millora l'entrenament; la degradació que va motivar ResNet empitjorava també l'entrenament. Són mals diferents amb remeis diferents (05-04 per al primer, skip connections per al segon).
- Oblidar que
Addsuma, no concatena.layers.Add()suma element a element (formes idèntiques, patró ResNet);layers.Concatenate()apila canals (patró Inception). Triar l'equivocat canvia el disseny per complet. - Posar la ReLU abans de la suma residual. L'ordre canònic és conv → conv → sumar drecera → ReLU. Activa-ho abans i estaràs restringint la correcció
F(x)a valors no negatius. - Memoritzar arquitectures en comptes d'idees. D'aquí a tres anys hi haurà una altra arquitectura de moda; el que perdura és el repertori: 3×3 apilats, convs 1×1 per comprimir canals, global average pooling, connexions residuals. Aprèn el vocabulari, no l'enciclopèdia.
Exercicis
Exercici 1: ordenar la història
Sense mirar la taula, assigna cada idea a la seva arquitectura i ordena-les cronològicament: (a) mòduls amb diverses convolucions en paral·lel, (b) dreceres que sumen l'entrada a la sortida, (c) només filtres 3×3 apilats en blocs, (d) primer gran èxit amb ReLU + GPU a ImageNet, (e) patró original conv→pool→denses per a dígits.
Exercici 2: l'argument de VGG amb números
Una capa rep i produeix 128 canals. Compara els paràmetres (ignora biaixos) de (a) una sola conv 7×7 davant de (b) tres convs 3×3 apilades. Quin avantatge addicional a la reducció de paràmetres aporten les tres capes?
Exercici 3: depurar un bloc residual
Aquest bloc llança un error en construir-se. Explica per què i proposa dos arranjaments diferents:
def bloc_erroni(x): # x arriba amb forma (8, 8, 64)
drecera = x
y = layers.Conv2D(128, (3, 3), padding="same", activation="relu")(x)
y = layers.Conv2D(128, (3, 3), padding="same")(y)
return layers.Activation("relu")(layers.Add()([y, drecera]))Solucions
Exercici 1: (e) LeNet-5, 1998 → (d) AlexNet, 2012 → (c) VGG, 2014 → (a) GoogLeNet/Inception, 2014 → (b) ResNet, 2015.
Exercici 2:
- (a) Una conv 7×7: 7 × 7 × 128 × 128 = 802 816 paràmetres.
- (b) Tres convs 3×3: 3 × (3 × 3 × 128 × 128) = 442 368 paràmetres — un 45 % menys amb el mateix camp receptiu de 7×7.
- Avantatge addicional: les tres capes intercalen tres ReLU en comptes d'una, així que la transformació és més no lineal i expressiva (i el raonament de 02-02 explica per què això importa).
Exercici 3: L'entrada x té 64 canals però F(x) en produeix 128; layers.Add() exigeix formes idèntiques i falla amb (8, 8, 64) davant de (8, 8, 128). Arranjaments: (1) fer servir 64 filtres a les dues convs del bloc, de manera que F(x) conservi la forma de l'entrada; (2) adaptar la drecera amb una conv 1×1 de 128 filtres — drecera = layers.Conv2D(128, (1, 1), padding="same")(x) — que projecta els 64 canals a 128 abans de la suma (és el que fan les ResNet reals en canviar d'etapa).
Conclusió
Has recorregut vint anys d'evolució en una lliçó: LeNet va fixar el patró conv→pool→denses; AlexNet va demostrar que escala + ReLU + GPU canviaven les regles; VGG va destil·lar el disseny a blocs de filtres 3×3; Inception va introduir les branques paral·leles, les convs 1×1 i el global average pooling; ResNet va desbloquejar la profunditat arbitrària amb connexions residuals que donen al gradient una autopista contra el vanishing de 02-03; i MobileNet/EfficientNet optimitzen el cost per arribar al telèfon del venedor. A més, has implementat els dos patrons més reutilitzats —el bloc VGG i el bloc residual— amb l'API funcional de Keras.
Queda una observació amb conseqüències pràctiques enormes: totes aquestes arquitectures estan disponibles ja entrenades sobre ImageNet (a Keras, a una línia de distància: keras.applications.ResNet50(...)). Les seves primeres capes van aprendre detectors de vores, textures i formes que serveixen per a qualsevol imatge — també per a les fotos de productes de TecnoMarket. Reutilitzar aquest coneixement en comptes d'entrenar des de zero es diu transfer learning, i és la tècnica que estudiarem a 05-03 (i aplicarem amb fine-tuning a 07-05). Abans d'arribar-hi, a la propera lliçó aixecarem la vista de la classificació pura: veurem tot el que les CNN saben fer amb imatges — localitzar, detectar, segmentar, llegir i buscar per similitud — i com encaixa cada tasca en l'operativa de TecnoMarket.
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
