A la lliçó anterior vam veure que el generador d'una GAN mapa un espai latent a imatges, però aquest espai es construeix "a cegues", empès per un adversari. L'autoencoder pren el camí directe: és una xarxa que aprèn a comprimir les seves entrades i a reconstruir-les, i en el procés construeix un espai latent explícit sense necessitar ni etiquetes ni adversaris. Aquesta idea aparentment modesta —copiar l'entrada a la sortida passant per un embut— és una de les més fecundes del deep learning: dona lloc a reducció de dimensionalitat, neteja de soroll i, sobretot per a TecnoMarket, detecció d'anomalies i frau, que és l'aplicació que deixarem plantejada aquí i desenvoluparem com a projecte a 07-03.
Contingut
- Aprenentatge no supervisat de representacions
- Anatomia: encoder, coll d'ampolla, decoder
- Què aprèn l'espai latent
- Un autoencoder dens sobre MNIST en Keras
- Interpretació de l'error de reconstrucció
- Aplicacions: reducció de dimensionalitat i denoising
- Detecció d'anomalies: per què funciona
- L'autoencoder variacional (VAE): pont cap a la generació
Aprenentatge no supervisat de representacions
Tots els models que has entrenat fins ara eren supervisats: cada exemple portava la seva etiqueta (el dígit correcte, el sentiment de la ressenya, les vendes de l'endemà). Però etiquetar és car. TecnoMarket té milions de transaccions, fotos i registres sense etiquetar, i aquí és on entra l'aprenentatge no supervisat: extreure estructura de les dades sense que ningú digui què és cada cosa.
El truc de l'autoencoder és convertir un problema sense etiquetes en un de supervisat amb un gir elegant: l'etiqueta de cada exemple és el mateix exemple. La xarxa rep una imatge i ha de produir... aquesta mateixa imatge. Sembla trivial (n'hi hauria prou de copiar), però li posem un obstacle: al mig de la xarxa hi ha un coll d'ampolla, una capa molt més petita que l'entrada. Per travessar-lo, la xarxa es veu obligada a decidir quina informació és essencial i quina és prescindible. Això —decidir què importa— és aprendre una representació.
Anatomia: encoder, coll d'ampolla, decoder
Un autoencoder té tres parts:
flowchart LR
X[Entrada<br/>784 valors] --> E1[Dense 128]
E1 --> E2[Dense 64]
E2 --> Z[Coll d'ampolla<br/>32 valors]
Z --> D1[Dense 64]
D1 --> D2[Dense 128]
D2 --> XR[Reconstruccio<br/>784 valors]
subgraph Encoder
E1
E2
end
subgraph Decoder
D1
D2
end
- Encoder: comprimeix progressivament l'entrada fins al coll d'ampolla. És com el camí d'una CNN cap al seu embedding (03-04), però aquí sense etiquetes que guiïn.
- Coll d'ampolla (codi o vector latent
z): la representació comprimida. La seva mida és una decisió de disseny: massa gran i la xarxa "copia" sense aprendre res; massa petit i perd informació essencial. - Decoder: reconstrueix l'entrada a partir del codi. Et sona? És estructuralment el mateix que el generador de la GAN de 05-01: un mapa de vector latent → dada. La diferència és com s'entrena.
La pèrdua de reconstrucció mesura com s'assembla la sortida a l'entrada. Per a imatges normalitzades sol fer-se servir l'MSE que vas conèixer a 02-04 (o BCE per píxel):
perdua = MSE(x, x_reconstruida) = mitjana de (x_i - x̂_i)²
No hi ha adversari, no hi ha joc minimax: és una optimització normal amb Adam i backpropagation, tan estable com les del mòdul 2.
Què aprèn l'espai latent
Comprimir 784 píxels en 32 números obliga a una compressió amb pèrdua, i aquesta pèrdua és selectiva: la xarxa conserva allò que ajuda a reconstruir molts exemples i descarta el soroll idiosincràtic. L'analogia útil és el resum: si resumeixes una ressenya de 500 paraules en 20, conserves "client insatisfet, la bateria dura poc, demana devolució" i descartes els girs d'estil. El coll d'ampolla fa el mateix amb les dades.
El resultat és un espai latent amb les propietats que ja coneixes dels embeddings (03-04, 04-03) i de l'espai latent de les GAN (05-01):
- Entrades semblants → codis propers (mesurables amb similitud cosinus o distància euclidiana).
- Els eixos latents capturen factors de variació (inclinació del traç, gruix, forma, en el cas de MNIST).
- Es pot fer servir el codi com a "empremta" compacta de la dada per a cerques o clustering.
Hi ha una diferència important amb la GAN: l'espai latent d'un autoencoder clàssic no està pensat per generar: si dones al decoder un z inventat a l'atzar, el més probable és que en surti una taca borrosa, perquè la xarxa només ha après a reconstruir codis que provenen de dades reals. Hi tornarem al final amb el VAE.
Un autoencoder dens sobre MNIST en Keras
Seguint la metodologia del curs —primer el dataset públic, després TecnoMarket—, construïm l'autoencoder del diagrama sobre MNIST:
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers
# 1. Dades: nomes necessitem les imatges, NO les etiquetes (no supervisat)
(x_train, _), (x_test, _) = keras.datasets.mnist.load_data()
x_train = x_train.astype("float32") / 255.0 # normalitzem a [0, 1]
x_test = x_test.astype("float32") / 255.0
x_train = x_train.reshape(-1, 784) # aplanem 28x28 -> 784
x_test = x_test.reshape(-1, 784)
DIM_LATENT = 32 # el coll d'ampolla: 784 -> 32 (compressio ~24:1)
# 2. Encoder: embut descendent
encoder = keras.Sequential([
layers.Dense(128, activation="relu", input_shape=(784,)),
layers.Dense(64, activation="relu"),
layers.Dense(DIM_LATENT, activation="relu"), # el codi z
], name="encoder")
# 3. Decoder: embut ascendent, mirall de l'encoder
decoder = keras.Sequential([
layers.Dense(64, activation="relu", input_shape=(DIM_LATENT,)),
layers.Dense(128, activation="relu"),
# sigmoide final perque els pixels estan a [0, 1]
layers.Dense(784, activation="sigmoid"),
], name="decoder")
# 4. Autoencoder = encoder + decoder encadenats
autoencoder = keras.Sequential([encoder, decoder], name="autoencoder")
# 5. L'"etiqueta" es la mateixa entrada: fit(x_train, x_train)
autoencoder.compile(optimizer="adam", loss="mse")
historial = autoencoder.fit(
x_train, x_train, # <- entrada i objectiu son el mateix
epochs=20,
batch_size=256,
validation_data=(x_test, x_test),
)Els detalls que importen:
fit(x_train, x_train): aquí hi ha tota la idea de l'autoencoder condensada en una línia. L'objectiu és la mateixa entrada.- Sigmoide a l'última capa perquè els píxels normalitzats viuen a [0, 1]; recorda de 02-02 que l'activació de sortida ha de casar amb el rang de l'objectiu.
- Simetria encoder/decoder: no és obligatòria, però és el disseny habitual i facilita raonar sobre la xarxa.
I ara, el més instructiu: mirar les reconstruccions.
import matplotlib.pyplot as plt
reconstruides = autoencoder.predict(x_test[:10])
fig, eixos = plt.subplots(2, 10, figsize=(14, 3))
for i in range(10):
eixos[0, i].imshow(x_test[i].reshape(28, 28), cmap="gray")
eixos[0, i].set_title("original", fontsize=8)
eixos[0, i].axis("off")
eixos[1, i].imshow(reconstruides[i].reshape(28, 28), cmap="gray")
eixos[1, i].set_title("reconstruida", fontsize=8)
eixos[1, i].axis("off")
plt.show()Veuràs dígits recognoscibles però lleugerament suavitzats: els traços fins es difuminen i les rareses cal·ligràfiques desapareixen. Aquesta suavitat és la compressió amb pèrdua en acció — la xarxa reconstrueix el dígit "típic" que resumeix el teu.
Interpretació de l'error de reconstrucció
A més de mirar les imatges, podem mesurar l'error de cada exemple:
errors = np.mean((x_test - autoencoder.predict(x_test)) ** 2, axis=1)
print(f"Error mitja: {errors.mean():.4f}")
print(f"Pitjor exemple: {errors.max():.4f} | Millor: {errors.min():.4f}")Aquest número per exemple és la clau de gairebé totes les aplicacions pràctiques:
- Error baix → l'exemple s'assembla al que la xarxa va veure en entrenament: és "normal".
- Error alt → l'exemple té alguna cosa que el resum après no sap expressar: és rar, sorollós... o anòmal.
Ordena els exemples de test per error descendent i mira els primers: hi trobaràs els dígits més estranys del dataset (traços il·legibles, estils atípics). L'autoencoder acaba de fer, sense que li ho demanéssim, un detector de rareses.
Aplicacions
Reducció de dimensionalitat (vs. PCA)
L'encoder tot sol (encoder.predict(x)) és un reductor de dimensionalitat: 784 → 32. La tècnica clàssica per a això és PCA (anàlisi de components principals); comparem-los:
| Aspecte | PCA | Autoencoder |
|---|---|---|
| Tipus de transformació | Lineal (projecció) | No lineal (tan flexible com la xarxa) |
| Capacitat | Limitada a estructura lineal | Captura relacions corbes i complexes |
| Cost d'entrenament | Molt baix (àlgebra directa) | Entrenament per gradient |
| Interpretabilitat | Alta (components ordenades per variància) | Baixa (el codi no té ordre natural) |
| Quan triar-lo | Baseline ràpid, dades ~lineals | Dades complexes (imatges, senyals) |
La regla pràctica és la mateixa que amb els baselines de 04-04: comença per PCA (barat i honest) i passa a l'autoencoder si l'estructura de les teves dades ho justifica. De fet, un autoencoder amb activacions lineals i MSE aprèn essencialment el mateix subespai que PCA — el guany ve de les no linealitats.
Denoising autoencoder
Variant amb un canvi mínim i gran utilitat: entrenar amb entrada sorollosa i objectiu net.
# Afegim soroll gaussia a les entrades
factor_soroll = 0.4
x_train_soroll = x_train + factor_soroll * np.random.normal(size=x_train.shape)
x_test_soroll = x_test + factor_soroll * np.random.normal(size=x_test.shape)
x_train_soroll = np.clip(x_train_soroll, 0.0, 1.0) # mantenim [0, 1]
x_test_soroll = np.clip(x_test_soroll, 0.0, 1.0)
# Mateixa arquitectura; canvia NOMES el parell (entrada, objectiu):
# entrada sorollosa -> objectiu net
autoencoder.fit(x_train_soroll, x_train,
epochs=20, batch_size=256,
validation_data=(x_test_soroll, x_test))Com que la xarxa no pot memoritzar el soroll (és aleatori i diferent cada vegada), es veu forçada a aprendre l'estructura subjacent del dígit i a descartar-lo. Per a TecnoMarket, la mateixa recepta neteja fotos de producte pujades per venedors amb mala il·luminació o compressió agressiva abans de passar-les al classificador de 03-04.
Detecció d'anomalies: per què funciona
Aquesta és l'aplicació estrella per a TecnoMarket, i el raonament mereix enunciar-se amb precisió:
- Entrenes l'autoencoder només amb dades normals (p. ex., centenars de milers de transaccions legítimes).
- La xarxa aprèn a resumir i reconstruir bé allò normal: les seves regularitats caben al coll d'ampolla.
- Arriba un exemple anòmal (una transacció fraudulenta amb una combinació insòlita d'import, hora, dispositiu i adreça d'enviament). El resum après no té vocabulari per a aquesta raresa: en comprimir-la, la deforma cap a allò normal, i la reconstrucció surt malament.
- Error de reconstrucció alt → candidata a anomalia. Fixant un llindar sobre l'error (una altra vegada el patró de llindar + cua de revisió humana de 03-04), les transaccions sospitoses van a revisió.
L'elegància de l'enfocament: no necessites exemples de frau per entrenar — només normalitat abundant, que és just el que sobra. Això importa perquè el frau és rar, canviant i car d'etiquetar. A 07-03 construirem aquest sistema complet sobre dades fictícies de transaccions de TecnoMarket: generació del dataset, elecció del llindar, mètriques adequades per a classes desequilibrades i posada en marxa. Aquí n'hi ha prou que la lògica t'hagi quedat clara.
L'autoencoder variacional (VAE)
Tanquem el cercle amb la GAN de 05-01. Vam dir que el decoder d'un autoencoder clàssic no serveix per generar: el seu espai latent té "forats" — regions sense dades on la reconstrucció és brossa. L'autoencoder variacional (VAE) arregla exactament això, amb dos canvis conceptuals (t'estalviem la matemàtica pesada):
- L'encoder no produeix un punt
z, sinó un petit núvol de probabilitat (una mitjana i una variància) del qual es mostrejaz. Cada exemple ocupa una regió, no un punt. - S'afegeix a la pèrdua un terme que empeny tots aquests núvols cap a una distribució normal estàndard, obligant-los a solapar-se i a omplir l'espai sense forats.
El resultat és un espai latent continu i navegable: mostreja qualsevol z de la normal, passa'l pel decoder i obtindràs una dada nova plausible. És a dir, un VAE és un autoencoder que sí que genera:
| Autoencoder clàssic | VAE | GAN | |
|---|---|---|---|
| Entrena amb | Reconstrucció | Reconstrucció + regularització del latent | Joc adversarial |
| Estabilitat | Alta | Alta | Baixa (05-01) |
| Genera mostres noves? | No (forats al latent) | Sí (una mica borroses) | Sí (nítides) |
| Ús típic | Compressió, anomalies | Generació controlada, interpolació | Generació d'alta fidelitat |
El VAE és el pont conceptual entre les dues lliçons: reconstruir (autoencoder) i crear (GAN) són dues cares del mateix espai latent.
Errors Comuns i Consells
- Fer el coll d'ampolla massa gran. Amb
DIM_LATENT=784la xarxa pot aprendre la identitat i l'error serà baixíssim sense haver après res d'útil. Si les teves reconstruccions són perfectes, sospita: redueix el codi fins que la compressió "faci una mica de mal". - Entrenar el detector d'anomalies amb dades contaminades. Si el conjunt d'entrenament inclou fraus sense saber-ho, la xarxa també aprendrà a reconstruir-los i deixaran de destacar. Cura el dataset d'entrenament tan bé com puguis.
- Oblidar que l'error de reconstrucció no és una probabilitat. És una distància sense escala universal: el llindar d'anomalia s'ha de calibrar sobre un conjunt de validació, no fixar-se "a ull" (ho farem amb rigor a 07-03).
- Fer servir el mateix soroll fix en el denoising. Si generes el soroll una sola vegada, la xarxa el pot memoritzar. Idealment el soroll es regenera a cada època (amb un generador de dades), o si més no s'accepta la versió simple sabent-ne la limitació.
- Comparar l'autoencoder contra res. Com amb les sèries de 04-04: tingues un baseline (PCA per a reducció, distància a la mitjana per a anomalies) i exigeix que l'autoencoder el superi.
Exercicis
Exercici 1. Explica amb l'analogia del resum per què un autoencoder entrenat amb transaccions legítimes de TecnoMarket reconstrueix malament una transacció fraudulenta, i per què això és un avantatge davant d'entrenar un classificador supervisat frau/no-frau.
Exercici 2. Modifica l'autoencoder de MNIST perquè el coll d'ampolla sigui de 2 dimensions, entrena, i escriu el codi per pintar un scatter plot d'encoder.predict(x_test) acolorit pel dígit real (les etiquetes, que no fem servir per entrenar, sí que podem fer-les servir per visualitzar). Què esperes veure-hi?
Exercici 3. Vertader o fals, justificant-ho: (a) un autoencoder necessita etiquetes per entrenar-se; (b) mostrejar un z aleatori i passar-lo pel decoder d'un autoencoder clàssic produeix exemples nous de qualitat; (c) el denoising autoencoder fa servir com a objectiu l'entrada sorollosa; (d) un VAE afegeix a la reconstrucció un terme que organitza l'espai latent.
Solucions
Solució 1.
L'autoencoder aprèn un "resum" d'allò normal: les combinacions habituals d'import, horari, dispositiu i destí caben al coll d'ampolla perquè es repeteixen en centenars de milers d'exemples. Una transacció fraudulenta conté combinacions que el resum no sap expressar (p. ex., import alt + compte acabat de crear + enviament a una adreça mai vista); en comprimir-la, la xarxa la "normalitza" i la reconstrucció difereix molt de l'original → error alt → alarma. L'avantatge davant del classificador supervisat és doble: (1) no calen exemples etiquetats de frau, que són escassos i cars; (2) detecta fraus de tipus nous, mentre que un classificador només reconeix patrons semblants als fraus que va veure entrenant.
Solució 2.
DIM_LATENT = 2 # i reentrenar encoder/decoder/autoencoder com abans
(_, _), (x_test_img, y_test) = keras.datasets.mnist.load_data()
codis = encoder.predict(x_test) # forma (10000, 2)
plt.figure(figsize=(8, 8))
plt.scatter(codis[:, 0], codis[:, 1], c=y_test, cmap="tab10", s=3)
plt.colorbar(label="digit")
plt.xlabel("z1"); plt.ylabel("z2")
plt.show()Cal esperar agrupacions per dígit: encara que la xarxa no va veure mai etiquetes, exemples del mateix dígit s'assemblen entre si i acaben en regions properes del pla latent (amb solapaments entre dígits visualment afins, com 4/9 o 3/8). La reconstrucció amb només 2 dimensions serà notablement pitjor que amb 32: és el preu d'una compressió tan agressiva.
Solució 3.
- (a) Fals: fa servir la mateixa entrada com a objectiu (
fit(x, x)); és aprenentatge no supervisat de representacions. - (b) Fals en general: l'espai latent clàssic té forats sense dades; un
zarbitrari sol descodificar-se com una taca borrosa. Justament això motiva el VAE. - (c) Fals: l'entrada és la versió sorollosa, però l'objectiu és la versió neta; d'aquí que aprengui a eliminar soroll.
- (d) Vertader: el VAE suma a la pèrdua de reconstrucció un terme que empeny els codis cap a una distribució normal, deixant l'espai latent continu i apte per generar.
Conclusió
L'autoencoder converteix l'absència d'etiquetes en virtut: fent servir cada dada com el seu propi objectiu, aprèn un espai latent que resumeix allò essencial, i d'aquest resum neixen les seves aplicacions — reduir dimensionalitat millor que una projecció lineal, netejar soroll, i assenyalar com a anòmal tot allò que es reconstrueix malament, que és la base del detector de frau que TecnoMarket construirà a 07-03. El VAE afegeix l'ingredient probabilístic que converteix la reconstrucció en generació, estenent el pont de tornada cap a les GAN.
Queda una constant incòmoda en tot el que portem de mòdul: entrenar des de zero costa dades, temps i GPU. A la propera lliçó aprendrem la drecera més rendible del deep learning pràctic: el transfer learning, o com recolzar-se en les arquitectures preentrenades que vam catalogar a 03-03 per resoldre problemes de TecnoMarket amb unes poques desenes d'imatges.
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
