En el módulo anterior conociste la neurona artificial de forma conceptual con la analogía del "comité de compras": varias entradas, cada una con su peso, un sesgo y una decisión final. Ahora que tu entorno tecnomarket-dl/ está listo, toca pasar de la intuición a la mecánica real. En esta lección formalizamos esa neurona con su nombre histórico —el perceptrón—, veremos cómo aprende ajustando sus pesos, lo implementaremos desde cero con numpy para construir el primer filtro antifraude de TecnoMarket, descubriremos su gran limitación (solo separa datos linealmente) y entenderemos por qué apilar capas —el perceptrón multicapa o MLP— rompe esa barrera. Es la base sobre la que se construye todo lo demás en el curso.

Contenido

  1. Del comité de compras al perceptrón formal
  2. La regla de aprendizaje del perceptrón
  3. Implementación en numpy: filtro antifraude de TecnoMarket
  4. La limitación fatal: separabilidad lineal y el problema XOR
  5. El Perceptrón Multicapa (MLP): apilar capas para resolver XOR

Del comité de compras al perceptrón formal

En la lección de conceptos básicos vimos que una neurona artificial funciona como un miembro de un comité: escucha varias opiniones (entradas), da más o menos importancia a cada una (pesos), tiene una predisposición propia (sesgo) y finalmente decide. El perceptrón, propuesto por Frank Rosenblatt en 1958 (lo situamos en la lección de historia), es exactamente eso escrito en matemáticas.

Dado un vector de entradas $x = (x_1, x_2, \dots, x_n)$, un vector de pesos $w = (w_1, w_2, \dots, w_n)$ y un sesgo $b$:

Paso 1 — Suma ponderada:

$$z = w_1 x_1 + w_2 x_2 + \dots + w_n x_n + b = w \cdot x + b$$

Paso 2 — Función escalón (step function):

$$\hat{y} = \begin{cases} 1 & \text{si } z \geq 0 \ 0 & \text{si } z < 0 \end{cases}$$

Es decir: si la evidencia acumulada supera el umbral, la neurona "dispara" (salida 1); si no, permanece en silencio (salida 0). La función escalón es la activación original de los años 50; en la siguiente lección veremos que hoy usamos funciones más suaves, pero para el perceptrón clásico el escalón es suficiente y fiel a la historia.

Fíjate en el papel del sesgo $b$: desplaza el umbral de decisión. Sin sesgo, la neurona solo podría decidir "dispara si $w \cdot x \geq 0$"; con sesgo, puede decidir "dispara si $w \cdot x \geq -b$", es decir, puede ser más exigente o más permisiva.

Elemento Analogía del comité (01-04) Símbolo Qué hace
Entradas Opiniones que llegan al comité $x_i$ Los datos del problema
Pesos Credibilidad de cada opinión $w_i$ Cuánto influye cada entrada
Sesgo Predisposición del comité $b$ Desplaza el umbral de decisión
Suma ponderada Balance de opiniones $z$ Evidencia total acumulada
Escalón Votación final sí/no $\hat{y}$ Decisión binaria (0 o 1)

La regla de aprendizaje del perceptrón

Hasta ahora los pesos eran fijos. La gran aportación de Rosenblatt fue una regla para aprenderlos automáticamente a partir de ejemplos, la primera materialización del principio "entrenar = medir error y corregir" que vimos con la analogía del grifo de la ducha.

La regla es sorprendentemente simple. Para cada ejemplo de entrenamiento $(x, y)$ donde $y$ es la etiqueta correcta (0 o 1):

  1. Calcula la predicción $\hat{y}$ con el perceptrón actual.
  2. Calcula el error: $e = y - \hat{y}$ (puede valer $-1$, $0$ o $+1$).
  3. Actualiza cada peso y el sesgo:

$$w_i \leftarrow w_i + \eta \cdot e \cdot x_i \qquad b \leftarrow b + \eta \cdot e$$

donde $\eta$ (eta) es la tasa de aprendizaje (learning rate), un número pequeño como 0.1 que controla el tamaño de cada corrección — exactamente el "giro pequeño del grifo" para no pasarnos de frío a hirviendo.

Interpretemos los tres casos posibles:

  • Acierto ($e = 0$): no se toca nada. Si funciona, no lo arregles.
  • Falso negativo ($y=1$, $\hat{y}=0$, $e=+1$): la neurona debió disparar y no lo hizo. Se suben los pesos de las entradas activas para que la próxima vez la suma sea mayor.
  • Falso positivo ($y=0$, $\hat{y}=1$, $e=-1$): disparó sin deber. Se bajan los pesos de las entradas activas.

Un teorema clásico (teorema de convergencia del perceptrón) garantiza que, si los datos se pueden separar con una línea recta (o un plano, en más dimensiones), esta regla encuentra una solución en un número finito de pasos. Guárdate ese "si": volveremos a él en el apartado 4.

Implementación en numpy: filtro antifraude de TecnoMarket

Vamos a aplicar la metodología del curso al revés de lo habitual por ser un caso tan pequeño: directamente sobre datos ficticios de TecnoMarket. Recuperamos la neurona antifraude que planteamos como ejercicio conceptual en 01-04, y ahora la construimos y entrenamos de verdad.

El equipo antifraude describe cada pedido con tres señales binarias (1 = presente, 0 = ausente):

  • x1: el importe supera los 500 €
  • x2: la cuenta del cliente tiene menos de 24 horas
  • x3: la dirección de envío no coincide con la de facturación

Y disponemos de 8 pedidos históricos etiquetados a mano (y = 1 significa fraude confirmado):

import numpy as np

# Datos ficticios de TecnoMarket: cada fila es un pedido [x1, x2, x3]
X = np.array([
    [0, 0, 0],  # pedido normal
    [1, 0, 0],  # caro, pero cliente veterano y direcciones coherentes
    [0, 1, 0],  # cuenta nueva, compra barata
    [0, 0, 1],  # direcciones distintas (un regalo, por ejemplo)
    [1, 1, 0],  # caro + cuenta nueva -> fraude
    [1, 0, 1],  # caro + direcciones distintas -> fraude
    [0, 1, 1],  # cuenta nueva + direcciones distintas -> fraude
    [1, 1, 1],  # todas las señales -> fraude
])
y = np.array([0, 0, 0, 0, 1, 1, 1, 1])

Observa el patrón: una señal aislada es inocente; dos o más señales juntas indican fraude. Es una regla de "al menos 2 de 3". Implementemos el perceptrón:

class Perceptron:
    def __init__(self, n_entradas, tasa_aprendizaje=0.1):
        self.w = np.zeros(n_entradas)  # pesos iniciales a cero
        self.b = 0.0                   # sesgo inicial a cero
        self.eta = tasa_aprendizaje

    def predecir(self, x):
        z = np.dot(self.w, x) + self.b   # suma ponderada: w·x + b
        return 1 if z >= 0 else 0        # función escalón

    def entrenar(self, X, y, epocas=10):
        for epoca in range(epocas):
            errores = 0
            for xi, yi in zip(X, y):
                e = yi - self.predecir(xi)     # error: -1, 0 o +1
                self.w += self.eta * e * xi    # regla del perceptrón
                self.b += self.eta * e
                errores += int(e != 0)
            print(f"Época {epoca+1}: {errores} errores, "
                  f"w={self.w}, b={self.b:.2f}")
            if errores == 0:                   # convergencia: todo correcto
                break

Desglose línea a línea de lo importante:

  • np.dot(self.w, x) calcula la suma ponderada $w_1x_1 + w_2x_2 + w_3x_3$ en una sola operación. Es la misma multiplicación de vectores que verificamos en el script de comprobación del entorno en 01-05.
  • e = yi - self.predecir(xi) mide el error de este pedido concreto.
  • self.w += self.eta * e * xi aplica la corrección: solo se modifican los pesos de las señales presentes en el pedido (si xi[j] == 0, ese peso no cambia).
  • Una época (vocabulario de 01-04) es una pasada completa por los 8 pedidos.

Entrenamos y probamos:

p = Perceptron(n_entradas=3)
p.entrenar(X, y, epocas=10)

# Un pedido nuevo: caro y con cuenta recién creada
pedido_sospechoso = np.array([1, 1, 0])
print("¿Fraude?", p.predecir(pedido_sospechoso))   # -> 1

Salida típica (los valores exactos pueden variar ligeramente según el orden de los datos):

Época 1: 5 errores, w=[0.1 0.1 0.1], b=-0.10
Época 2: 3 errores, w=[0.1 0.1 0.2], b=-0.20
Época 3: 2 errores, w=[0.2 0.1 0.2], b=-0.20
Época 4: 0 errores, w=[0.2 0.1 0.2], b=-0.20
¿Fraude?  1

El perceptrón ha aprendido solo una regla equivalente a "al menos 2 señales": con pesos en torno a 0.1–0.2 y sesgo alrededor de $-0.2$, una sola señal no llega al umbral, pero dos sí. Nadie programó la regla: emergió de los datos. Ese es el salto cualitativo respecto al ejercicio conceptual de 01-04, donde los pesos los elegimos a mano.

La limitación fatal: separabilidad lineal y el problema XOR

La ecuación $w \cdot x + b = 0$ define geométricamente una recta (con 2 entradas), un plano (con 3) o un hiperplano (con más). El perceptrón clasifica según el lado de esa frontera en que cae cada punto. Por tanto, solo puede resolver problemas linealmente separables: aquellos en los que una única recta basta para separar las dos clases.

Nuestro filtro antifraude funcionó porque "al menos 2 de 3 señales" es separable por un plano. Pero en 1969 Minsky y Papert señalaron un contraejemplo devastadoramente simple: la función XOR (o exclusivo), que devuelve 1 cuando las entradas son distintas:

$x_1$ $x_2$ XOR Ejemplo TecnoMarket
0 0 0 Cliente habitual, horario normal: OK
0 1 1 Solo una anomalía: revisar
1 0 1 Solo la otra anomalía: revisar
1 1 0 Ambas a la vez: es el patrón de un cliente mayorista conocido, OK

Dibuja mentalmente los cuatro puntos en un plano: los que valen 1 están en esquinas opuestas ((0,1) y (1,0)), y los que valen 0 en las otras dos esquinas ((0,0) y (1,1)). No existe ninguna recta que deje los unos a un lado y los ceros al otro. Puedes comprobarlo empíricamente: entrena el perceptrón anterior con estos 4 puntos y verás que nunca llega a 0 errores, por muchas épocas que le des — el teorema de convergencia solo aplicaba a datos separables.

Este resultado, aparentemente menor, contribuyó al primer "invierno de la IA" que vimos en la lección de historia: si el perceptrón no puede con XOR, ¿cómo va a reconocer una cara?

El Perceptrón Multicapa (MLP): apilar capas para resolver XOR

La salida del problema ya la conoces de 01-04: capas ocultas. Un Perceptrón Multicapa (MLP, Multi-Layer Perceptron) encadena capas de neuronas: la salida de cada capa es la entrada de la siguiente, exactamente como en la red 3-4-2-1 de 29 parámetros que contamos a mano.

La idea clave: cada neurona oculta traza su propia recta, y la neurona de salida combina esas rectas en fronteras que ya no son rectas. Con XOR basta una capa oculta de 2 neuronas:

graph LR
    x1((x1)) --> h1((h1: OR))
    x1 --> h2((h2: AND))
    x2((x2)) --> h1
    x2 --> h2
    h1 --> s((salida: h1 AND NO h2))
    h2 --> s
  • La neurona oculta h1 aprende "al menos una entrada activa" (OR): recta separable, un perceptrón puede.
  • La neurona oculta h2 aprende "las dos entradas activas" (AND): también separable.
  • La salida combina: "h1 sí, pero h2 no" — es decir, alguna entrada activa pero no las dos. ¡Eso es XOR!

Comprobémoslo con numpy usando pesos elegidos a mano (aún no sabemos entrenarlos: eso requiere backpropagation, el tema de la lección de propagación hacia adelante y hacia atrás):

import numpy as np

def escalon(z):
    return (z >= 0).astype(int)

# Capa oculta: 2 neuronas. Cada COLUMNA de W1 son los pesos de una neurona.
W1 = np.array([[1.0, 1.0],     # pesos de x1 hacia h1 y h2
               [1.0, 1.0]])    # pesos de x2 hacia h1 y h2
b1 = np.array([-0.5, -1.5])    # h1 dispara con suma>=0.5 (OR); h2 con >=1.5 (AND)

# Capa de salida: combina h1 (positivo) y h2 (muy negativo)
W2 = np.array([[1.0], [-2.0]])
b2 = np.array([-0.5])

def mlp_xor(x):
    h = escalon(x @ W1 + b1)      # forward de la capa oculta
    return escalon(h @ W2 + b2)   # forward de la capa de salida

for x in [[0,0], [0,1], [1,0], [1,1]]:
    print(x, "->", mlp_xor(np.array(x))[0])
[0, 0] -> 0
[0, 1] -> 1
[1, 0] -> 1
[1, 1] -> 0

Funciona. Observa dos detalles de implementación que reaparecerán constantemente:

  • x @ W1 + b1 procesa todas las neuronas de una capa a la vez con una multiplicación matricial: cada columna de W1 contiene los pesos de una neurona. Es la forma vectorizada de la suma ponderada, y la razón por la que las GPU aceleran tanto el deep learning (lección de historia e instalación del entorno).
  • La estructura es idéntica a la red 3-4-2-1 de 01-04, solo que en versión 2-2-1. Cuenta los parámetros: capa oculta $2\times2+2 = 6$, capa de salida $2\times1+1 = 3$; total 9 parámetros, con el mismo método de recuento que usamos allí.

Queda una pregunta enorme pendiente: aquí los pesos los hemos puesto a mano, y la regla de aprendizaje del perceptrón no sirve para capas ocultas (¿qué "error" tiene una neurona oculta, si nadie le dice cuál era su salida correcta?). Resolver eso costó casi 20 años y se llama backpropagation; lo veremos en dos lecciones. Antes necesitamos un ingrediente: sustituir el escalón por funciones de activación derivables, el tema de la próxima lección.

Errores Comunes y Consejos

  • Olvidar el sesgo. Sin $b$, la frontera de decisión pasa obligatoriamente por el origen y muchos problemas separables se vuelven imposibles. Inclúyelo siempre.
  • Confundir la salida del escalón con una probabilidad. El perceptrón clásico devuelve 0 o 1 secos, sin matiz de confianza. Para obtener probabilidades necesitarás la sigmoide (próxima lección).
  • Esperar convergencia con datos no separables. Si el perceptrón oscila y nunca llega a 0 errores, probablemente tus datos no son linealmente separables; no es un bug de tu código. Detén el entrenamiento por número máximo de épocas, no solo por convergencia.
  • Usar una tasa de aprendizaje enorme "para ir más rápido". Con el perceptrón puro el efecto es menos grave que en redes modernas, pero acostúmbrate ya a valores pequeños (0.01–0.1): es el giro suave del grifo.
  • Confundir filas y columnas en las matrices de pesos. En la convención que usaremos, X tiene una fila por ejemplo y W una columna por neurona; X @ W sale entonces con una fila por ejemplo y una columna por neurona. Verifica siempre las dimensiones con .shape antes de buscar errores más exóticos.

Ejercicios

  1. Puertas lógicas. Entrena el perceptrón de la clase Perceptron sobre las funciones AND y OR de 2 entradas (4 ejemplos cada una). Comprueba que converge en pocas épocas y anota los pesos finales. Después inténtalo con XOR y describe qué observas en el recuento de errores por época.
  2. Filtro antifraude ampliado. Añade una cuarta señal al dataset antifraude: x4 = "el pedido usa una tarjeta rechazada previamente". Genera los 16 pedidos posibles, etiqueta como fraude los que tengan 2 o más señales activas, y entrena el perceptrón. ¿Converge? ¿Qué pesos aprende y cómo los interpretas?
  3. MLP a mano para NAND-de-señales. Diseña (sin entrenar, eligiendo pesos a mano como hicimos con XOR) un MLP 2-2-1 con función escalón que implemente XNOR (la negación de XOR: devuelve 1 cuando las entradas son iguales). Pista: puedes reutilizar las neuronas OR y AND del ejemplo y cambiar solo la capa de salida.

Soluciones

Ejercicio 1. Para AND: X = [[0,0],[0,1],[1,0],[1,1]], y = [0,0,0,1]; para OR, y = [0,1,1,1]. Ambas convergen (son separables); soluciones típicas partiendo de ceros con $\eta=0.1$: AND termina con pesos cercanos a w=[0.2, 0.1], b=-0.2 (exige ambas entradas) y OR con w=[0.1, 0.1], b=-0.1 (basta una). Con XOR el número de errores por época nunca baja de forma estable a 0: oscila (por ejemplo 2, 3, 2, 3, ...) indefinidamente, confirmando la no separabilidad.

Ejercicio 2. El problema "2 o más señales de 4" sigue siendo linealmente separable (es una función umbral). Generando los 16 casos con itertools.product([0,1], repeat=4) y etiquetando con y = (X.sum(axis=1) >= 2).astype(int), el perceptrón converge; aprende pesos aproximadamente iguales entre sí (todas las señales pesan lo mismo, porque la regla las trata simétricamente) y un sesgo negativo tal que hacen falta dos señales para superar el umbral, por ejemplo w≈[0.2, 0.2, 0.2, 0.2], b≈-0.3.

Ejercicio 3. XNOR es 1 en (0,0) y (1,1). Reutiliza h1 = OR y h2 = AND con los mismos W1, b1 del ejemplo. La salida debe valer 1 cuando "no hay ninguna activa" (h1=0) o "están las dos" (h2=1): sirve W2 = [[-1.0], [2.0]], b2 = [0.5]. Verificación: (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. Correcto.

Conclusión

En esta lección hemos formalizado la neurona del comité de compras como perceptrón (suma ponderada + escalón), hemos visto la primera regla de aprendizaje de la historia y la hemos usado para entrenar desde cero un filtro antifraude para TecnoMarket en numpy. También hemos chocado con su límite —solo separa lo linealmente separable, y XOR no lo es— y hemos comprobado que apilar capas (el MLP) rompe ese límite, aunque de momento eligiendo los pesos a mano.

Dos cabos quedan sueltos: el escalón es una función "todo o nada" que no admite matices ni derivadas, y no sabemos entrenar las capas ocultas. El primero se resuelve en la próxima lección con las funciones de activación modernas (sigmoide, tanh, ReLU, softmax); el segundo, justo después, con backpropagation. Paso a paso, estamos construyendo todas las piezas de la primera red completa que entrenarás al final de este módulo.

Curso de Deep Learning

Módulo 1: Introducción a Deep Learning

Módulo 2: Fundamentos de Redes Neuronales

Módulo 3: Redes Neuronales Convolucionales (CNN)

Módulo 4: Redes Neuronales Recurrentes (RNN)

Módulo 5: Técnicas Avanzadas en Deep Learning

Módulo 6: Herramientas y Frameworks

Módulo 7: Proyectos Prácticos

Módulo 8: Consideraciones Éticas y Futuro del Deep Learning

© Copyright 2026. Todos los derechos reservados