Al mòdul anterior vas conèixer la neurona artificial de manera conceptual amb l'analogia del "comitè de compres": diverses entrades, cadascuna amb el seu pes, un biaix i una decisió final. Ara que el teu entorn tecnomarket-dl/ està a punt, toca passar de la intuïció a la mecànica real. En aquesta lliçó formalitzem aquesta neurona amb el seu nom històric —el perceptró—, veurem com aprèn ajustant els seus pesos, l'implementarem des de zero amb numpy per construir el primer filtre antifrau de TecnoMarket, descobrirem la seva gran limitació (només separa dades linealment) i entendrem per què apilar capes —el perceptró multicapa o MLP— trenca aquesta barrera. És la base sobre la qual es construeix tota la resta del curs.
Contingut
- Del comitè de compres al perceptró formal
- La regla d'aprenentatge del perceptró
- Implementació en numpy: filtre antifrau de TecnoMarket
- La limitació fatal: separabilitat lineal i el problema XOR
- El Perceptró Multicapa (MLP): apilar capes per resoldre XOR
Del comitè de compres al perceptró formal
A la lliçó de conceptes bàsics vam veure que una neurona artificial funciona com un membre d'un comitè: escolta diverses opinions (entrades), dona més o menys importància a cadascuna (pesos), té una predisposició pròpia (biaix) i finalment decideix. El perceptró, proposat per Frank Rosenblatt el 1958 (el vam situar a la lliçó d'història), és exactament això escrit en matemàtiques.
Donat un vector d'entrades $x = (x_1, x_2, \dots, x_n)$, un vector de pesos $w = (w_1, w_2, \dots, w_n)$ i un biaix $b$:
Pas 1 — Suma ponderada:
$$z = w_1 x_1 + w_2 x_2 + \dots + w_n x_n + b = w \cdot x + b$$
Pas 2 — Funció esglaó (step function):
$$\hat{y} = \begin{cases} 1 & \text{si } z \geq 0 \ 0 & \text{si } z < 0 \end{cases}$$
És a dir: si l'evidència acumulada supera el llindar, la neurona "dispara" (sortida 1); si no, es queda en silenci (sortida 0). La funció esglaó és l'activació original dels anys 50; a la propera lliçó veurem que avui fem servir funcions més suaus, però per al perceptró clàssic l'esglaó és suficient i fidel a la història.
Fixa't en el paper del biaix $b$: desplaça el llindar de decisió. Sense biaix, la neurona només podria decidir "dispara si $w \cdot x \geq 0$"; amb biaix, pot decidir "dispara si $w \cdot x \geq -b$", és a dir, pot ser més exigent o més permissiva.
| Element | Analogia del comitè (01-04) | Símbol | Què fa |
|---|---|---|---|
| Entrades | Opinions que arriben al comitè | $x_i$ | Les dades del problema |
| Pesos | Credibilitat de cada opinió | $w_i$ | Quant influeix cada entrada |
| Biaix | Predisposició del comitè | $b$ | Desplaça el llindar de decisió |
| Suma ponderada | Balanç d'opinions | $z$ | Evidència total acumulada |
| Esglaó | Votació final sí/no | $\hat{y}$ | Decisió binària (0 o 1) |
La regla d'aprenentatge del perceptró
Fins ara els pesos eren fixos. La gran aportació de Rosenblatt va ser una regla per aprendre'ls automàticament a partir d'exemples, la primera materialització del principi "entrenar = mesurar l'error i corregir" que vam veure amb l'analogia de l'aixeta de la dutxa.
La regla és sorprenentment simple. Per a cada exemple d'entrenament $(x, y)$ on $y$ és l'etiqueta correcta (0 o 1):
- Calcula la predicció $\hat{y}$ amb el perceptró actual.
- Calcula l'error: $e = y - \hat{y}$ (pot valer $-1$, $0$ o $+1$).
- Actualitza cada pes i el biaix:
$$w_i \leftarrow w_i + \eta \cdot e \cdot x_i \qquad b \leftarrow b + \eta \cdot e$$
on $\eta$ (eta) és el learning rate (taxa d'aprenentatge), un nombre petit com 0.1 que controla la mida de cada correcció — exactament el "gir petit de l'aixeta" per no passar-nos de freda a bullint.
Interpretem els tres casos possibles:
- Encert ($e = 0$): no es toca res. Si funciona, no ho arreglis.
- Fals negatiu ($y=1$, $\hat{y}=0$, $e=+1$): la neurona havia de disparar i no ho va fer. Es pugen els pesos de les entrades actives perquè la propera vegada la suma sigui més gran.
- Fals positiu ($y=0$, $\hat{y}=1$, $e=-1$): va disparar sense haver-ho de fer. Es baixen els pesos de les entrades actives.
Un teorema clàssic (teorema de convergència del perceptró) garanteix que, si les dades es poden separar amb una línia recta (o un pla, en més dimensions), aquesta regla troba una solució en un nombre finit de passos. Guarda't aquest "si": hi tornarem a l'apartat 4.
Implementació en numpy: filtre antifrau de TecnoMarket
Aplicarem la metodologia del curs al revés de l'habitual perquè és un cas molt petit: directament sobre dades fictícies de TecnoMarket. Recuperem la neurona antifrau que vam plantejar com a exercici conceptual a 01-04, i ara la construïm i l'entrenem de debò.
L'equip antifrau descriu cada comanda amb tres senyals binaris (1 = present, 0 = absent):
x1: l'import supera els 500 €x2: el compte del client té menys de 24 horesx3: l'adreça d'enviament no coincideix amb la de facturació
I disposem de 8 comandes històriques etiquetades a mà (y = 1 vol dir frau confirmat):
import numpy as np
# Dades fictícies de TecnoMarket: cada fila és una comanda [x1, x2, x3]
X = np.array([
[0, 0, 0], # comanda normal
[1, 0, 0], # cara, però client veterà i adreces coherents
[0, 1, 0], # compte nou, compra barata
[0, 0, 1], # adreces diferents (un regal, per exemple)
[1, 1, 0], # cara + compte nou -> frau
[1, 0, 1], # cara + adreces diferents -> frau
[0, 1, 1], # compte nou + adreces diferents -> frau
[1, 1, 1], # tots els senyals -> frau
])
y = np.array([0, 0, 0, 0, 1, 1, 1, 1])Observa el patró: un senyal aïllat és innocent; dos o més senyals junts indiquen frau. És una regla de "com a mínim 2 de 3". Implementem el perceptró:
class Perceptro:
def __init__(self, n_entrades, taxa_aprenentatge=0.1):
self.w = np.zeros(n_entrades) # pesos inicials a zero
self.b = 0.0 # biaix inicial a zero
self.eta = taxa_aprenentatge
def predir(self, x):
z = np.dot(self.w, x) + self.b # suma ponderada: w·x + b
return 1 if z >= 0 else 0 # funció esglaó
def entrenar(self, X, y, epoques=10):
for epoca in range(epoques):
errors = 0
for xi, yi in zip(X, y):
e = yi - self.predir(xi) # error: -1, 0 o +1
self.w += self.eta * e * xi # regla del perceptró
self.b += self.eta * e
errors += int(e != 0)
print(f"Època {epoca+1}: {errors} errors, "
f"w={self.w}, b={self.b:.2f}")
if errors == 0: # convergència: tot correcte
breakDesglossem línia a línia el que és important:
np.dot(self.w, x)calcula la suma ponderada $w_1x_1 + w_2x_2 + w_3x_3$ en una sola operació. És la mateixa multiplicació de vectors que vam verificar a l'script de comprovació de l'entorn a 01-05.e = yi - self.predir(xi)mesura l'error d'aquesta comanda concreta.self.w += self.eta * e * xiaplica la correcció: només es modifiquen els pesos dels senyals presents a la comanda (sixi[j] == 0, aquest pes no canvia).- Una època (vocabulari de 01-04) és una passada completa per les 8 comandes.
Entrenem i provem:
p = Perceptro(n_entrades=3)
p.entrenar(X, y, epoques=10)
# Una comanda nova: cara i amb compte acabat de crear
comanda_sospitosa = np.array([1, 1, 0])
print("Frau?", p.predir(comanda_sospitosa)) # -> 1Sortida típica (els valors exactes poden variar lleugerament segons l'ordre de les dades):
Època 1: 5 errors, w=[0.1 0.1 0.1], b=-0.10
Època 2: 3 errors, w=[0.1 0.1 0.2], b=-0.20
Època 3: 2 errors, w=[0.2 0.1 0.2], b=-0.20
Època 4: 0 errors, w=[0.2 0.1 0.2], b=-0.20
Frau? 1El perceptró ha après tot sol una regla equivalent a "com a mínim 2 senyals": amb pesos al voltant de 0.1–0.2 i biaix al voltant de $-0.2$, un sol senyal no arriba al llindar, però dos sí. Ningú no va programar la regla: va emergir de les dades. Aquest és el salt qualitatiu respecte a l'exercici conceptual de 01-04, on els pesos els vam triar a mà.
La limitació fatal: separabilitat lineal i el problema XOR
L'equació $w \cdot x + b = 0$ defineix geomètricament una recta (amb 2 entrades), un pla (amb 3) o un hiperplà (amb més). El perceptró classifica segons el costat d'aquesta frontera on cau cada punt. Per tant, només pot resoldre problemes linealment separables: aquells en què una única recta n'hi ha prou per separar les dues classes.
El nostre filtre antifrau va funcionar perquè "com a mínim 2 de 3 senyals" és separable per un pla. Però el 1969 Minsky i Papert van assenyalar un contraexemple devastadorament simple: la funció XOR (o exclusiu), que retorna 1 quan les entrades són diferents:
| $x_1$ | $x_2$ | XOR | Exemple TecnoMarket |
|---|---|---|---|
| 0 | 0 | 0 | Client habitual, horari normal: OK |
| 0 | 1 | 1 | Només una anomalia: revisar |
| 1 | 0 | 1 | Només l'altra anomalia: revisar |
| 1 | 1 | 0 | Totes dues alhora: és el patró d'un client majorista conegut, OK |
Dibuixa mentalment els quatre punts en un pla: els que valen 1 són a cantonades oposades ((0,1) i (1,0)), i els que valen 0 a les altres dues cantonades ((0,0) i (1,1)). No existeix cap recta que deixi els uns a una banda i els zeros a l'altra. Ho pots comprovar empíricament: entrena el perceptró anterior amb aquests 4 punts i veuràs que mai no arriba a 0 errors, per moltes èpoques que li donis — el teorema de convergència només s'aplicava a dades separables.
Aquest resultat, aparentment menor, va contribuir al primer "hivern de la IA" que vam veure a la lliçó d'història: si el perceptró no pot amb XOR, com ha de reconèixer una cara?
El Perceptró Multicapa (MLP): apilar capes per resoldre XOR
La sortida del problema ja la coneixes de 01-04: capes ocultes. Un Perceptró Multicapa (MLP, Multi-Layer Perceptron) encadena capes de neurones: la sortida de cada capa és l'entrada de la següent, exactament com a la xarxa 3-4-2-1 de 29 paràmetres que vam comptar a mà.
La idea clau: cada neurona oculta traça la seva pròpia recta, i la neurona de sortida combina aquestes rectes en fronteres que ja no són rectes. Amb XOR n'hi ha prou amb una capa oculta de 2 neurones:
graph LR
x1((x1)) --> h1((h1: OR))
x1 --> h2((h2: AND))
x2((x2)) --> h1
x2 --> h2
h1 --> s((sortida: h1 AND NO h2))
h2 --> s
- La neurona oculta h1 aprèn "com a mínim una entrada activa" (OR): recta separable, un perceptró pot fer-ho.
- La neurona oculta h2 aprèn "les dues entrades actives" (AND): també separable.
- La sortida combina: "h1 sí, però h2 no" — és a dir, alguna entrada activa però no totes dues. Això és XOR!
Comprovem-ho amb numpy fent servir pesos triats a mà (encara no sabem entrenar-los: això requereix backpropagation, el tema de la lliçó de propagació cap endavant i cap enrere):
import numpy as np
def esglao(z):
return (z >= 0).astype(int)
# Capa oculta: 2 neurones. Cada COLUMNA de W1 són els pesos d'una neurona.
W1 = np.array([[1.0, 1.0], # pesos de x1 cap a h1 i h2
[1.0, 1.0]]) # pesos de x2 cap a h1 i h2
b1 = np.array([-0.5, -1.5]) # h1 dispara amb suma>=0.5 (OR); h2 amb >=1.5 (AND)
# Capa de sortida: combina h1 (positiu) i h2 (molt negatiu)
W2 = np.array([[1.0], [-2.0]])
b2 = np.array([-0.5])
def mlp_xor(x):
h = esglao(x @ W1 + b1) # forward de la capa oculta
return esglao(h @ W2 + b2) # forward de la capa de sortida
for x in [[0,0], [0,1], [1,0], [1,1]]:
print(x, "->", mlp_xor(np.array(x))[0])Funciona. Observa dos detalls d'implementació que reapareixeran constantment:
x @ W1 + b1processa totes les neurones d'una capa alhora amb una multiplicació matricial: cada columna deW1conté els pesos d'una neurona. És la forma vectoritzada de la suma ponderada, i la raó per la qual les GPU acceleren tant el deep learning (lliçó d'història i instal·lació de l'entorn).- L'estructura és idèntica a la xarxa 3-4-2-1 de 01-04, només que en versió 2-2-1. Compta els paràmetres: capa oculta $2\times2+2 = 6$, capa de sortida $2\times1+1 = 3$; total 9 paràmetres, amb el mateix mètode de recompte que hi vam fer servir.
Queda pendent una pregunta enorme: aquí els pesos els hem posat a mà, i la regla d'aprenentatge del perceptró no serveix per a capes ocultes (quin "error" té una neurona oculta, si ningú no li diu quina era la seva sortida correcta?). Resoldre això va costar gairebé 20 anys i es diu backpropagation; ho veurem d'aquí a dues lliçons. Abans necessitem un ingredient: substituir l'esglaó per funcions d'activació derivables, el tema de la propera lliçó.
Errors Comuns i Consells
- Oblidar el biaix. Sense $b$, la frontera de decisió passa obligatòriament per l'origen i molts problemes separables es tornen impossibles. Inclou-lo sempre.
- Confondre la sortida de l'esglaó amb una probabilitat. El perceptró clàssic retorna 0 o 1 secs, sense matís de confiança. Per obtenir probabilitats necessitaràs la sigmoide (propera lliçó).
- Esperar convergència amb dades no separables. Si el perceptró oscil·la i mai no arriba a 0 errors, probablement les teves dades no són linealment separables; no és un bug del teu codi. Atura l'entrenament per nombre màxim d'èpoques, no només per convergència.
- Fer servir un learning rate enorme "per anar més ràpid". Amb el perceptró pur l'efecte és menys greu que en xarxes modernes, però acostuma't ja a valors petits (0.01–0.1): és el gir suau de l'aixeta.
- Confondre files i columnes a les matrius de pesos. En la convenció que farem servir,
Xté una fila per exemple iWuna columna per neurona;X @ Wsurt llavors amb una fila per exemple i una columna per neurona. Verifica sempre les dimensions amb.shapeabans de buscar errors més exòtics.
Exercicis
- Portes lògiques. Entrena el perceptró de la classe
Perceptrosobre les funcions AND i OR de 2 entrades (4 exemples cadascuna). Comprova que convergeix en poques èpoques i anota els pesos finals. Després intenta-ho amb XOR i descriu què observes en el recompte d'errors per època. - Filtre antifrau ampliat. Afegeix un quart senyal al dataset antifrau:
x4 = "la comanda fa servir una targeta rebutjada prèviament". Genera les 16 comandes possibles, etiqueta com a frau les que tinguin 2 o més senyals actius, i entrena el perceptró. Convergeix? Quins pesos aprèn i com els interpretes? - MLP a mà per a NAND-de-senyals. Dissenya (sense entrenar, triant pesos a mà com vam fer amb XOR) un MLP 2-2-1 amb funció esglaó que implementi XNOR (la negació de XOR: retorna 1 quan les entrades són iguals). Pista: pots reutilitzar les neurones OR i AND de l'exemple i canviar només la capa de sortida.
Solucions
Exercici 1. Per a AND: X = [[0,0],[0,1],[1,0],[1,1]], y = [0,0,0,1]; per a OR, y = [0,1,1,1]. Totes dues convergeixen (són separables); solucions típiques partint de zeros amb $\eta=0.1$: AND acaba amb pesos propers a w=[0.2, 0.1], b=-0.2 (exigeix totes dues entrades) i OR amb w=[0.1, 0.1], b=-0.1 (n'hi ha prou amb una). Amb XOR el nombre d'errors per època mai no baixa de manera estable a 0: oscil·la (per exemple 2, 3, 2, 3, ...) indefinidament, cosa que confirma la no separabilitat.
Exercici 2. El problema "2 o més senyals de 4" continua sent linealment separable (és una funció llindar). Generant els 16 casos amb itertools.product([0,1], repeat=4) i etiquetant amb y = (X.sum(axis=1) >= 2).astype(int), el perceptró convergeix; aprèn pesos aproximadament iguals entre si (tots els senyals pesen el mateix, perquè la regla els tracta simètricament) i un biaix negatiu tal que calen dos senyals per superar el llindar, per exemple w≈[0.2, 0.2, 0.2, 0.2], b≈-0.3.
Exercici 3. XNOR és 1 a (0,0) i (1,1). Reutilitza h1 = OR i h2 = AND amb els mateixos W1, b1 de l'exemple. La sortida ha de valer 1 quan "no n'hi ha cap d'activa" (h1=0) o "hi són totes dues" (h2=1): serveix W2 = [[-1.0], [2.0]], b2 = [0.5]. Verificació: (0,0) → h=(0,0), z=0.5 → 1; (0,1) → h=(1,0), z=-0.5 → 0; (1,0) → igual → 0; (1,1) → h=(1,1), z=1.5 → 1. Correcte.
Conclusió
En aquesta lliçó hem formalitzat la neurona del comitè de compres com a perceptró (suma ponderada + esglaó), hem vist la primera regla d'aprenentatge de la història i l'hem feta servir per entrenar des de zero un filtre antifrau per a TecnoMarket en numpy. També hem topat amb el seu límit —només separa allò linealment separable, i XOR no ho és— i hem comprovat que apilar capes (l'MLP) trenca aquest límit, encara que de moment triant els pesos a mà.
Queden dos caps per lligar: l'esglaó és una funció de "tot o res" que no admet matisos ni derivades, i no sabem entrenar les capes ocultes. El primer es resol a la propera lliçó amb les funcions d'activació modernes (sigmoide, tanh, ReLU, softmax); el segon, just després, amb backpropagation. Pas a pas, estem construint totes les peces de la primera xarxa completa que entrenaràs al final d'aquest mòdul.
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
