En 05-01 vimos que una neurona sola traza una recta y que apilar neuronas en capas rompe ese límite. Ahora toca la pregunta práctica que Marta se hace delante del portátil: ¿cuántas capas, cuántas neuronas, qué función de activación, qué salida? Esas decisiones son la arquitectura de la red, y son los hiperparámetros más importantes del deep learning. En esta lección desmontamos un perceptrón multicapa (MLP) pieza a pieza: capas densas, anchura y profundidad, cómo contar parámetros a mano; las funciones de activación modernas (ReLU y su familia, softmax) y por qué la sigmoide dejó de usarse en las capas ocultas (el gradiente que se desvanece, a nivel intuitivo); cómo elegir la capa de salida y la función de pérdida según el problema; y cómo representar las entradas, con los embeddings como idea clave para texto y productos. Cerraremos con un mapa de las familias de arquitecturas (convolucionales, recurrentes, transformers, autoencoders) que 05-04 y 05-05 desarrollan, y con código: construiremos en PyTorch el MLP del predictor de devoluciones de NovaMarket sobre las 21 columnas preparadas en el módulo 4, contaremos sus parámetros y le haremos una predicción sin entrenar. Es importante porque la arquitectura fija lo que la red puede aprender: una mala elección no se arregla con más épocas.

Contenido

  1. Anatomía de un perceptrón multicapa: capas densas, anchura y profundidad
  2. Contar parámetros a mano: 21 → 16 → 8 → 1
  3. Funciones de activación: sigmoide, tanh, ReLU y variantes, softmax
  4. El gradiente que se desvanece (intuición) y por qué ReLU
  5. Capa de salida y función de pérdida según el problema
  6. Cómo representar las entradas: numéricas, categóricas y embeddings
  7. Panorama de familias de arquitecturas
  8. Código: el MLP del predictor de devoluciones en PyTorch
  9. Errores Comunes y Consejos
  10. Ejercicios
  11. Conclusión

  1. Anatomía de un perceptrón multicapa: capas densas, anchura y profundidad

Un perceptrón multicapa (MLP, multilayer perceptron) es la red de 05-01 generalizada: una capa de entrada, una o más capas ocultas densas (cada neurona conectada a todas las salidas de la capa anterior) y una capa de salida. Cada capa densa calcula, para todas sus neuronas a la vez, h = f(W · x + b), donde W es una matriz con una fila por neurona y una columna por entrada, b un vector de sesgos y f la activación aplicada elemento a elemento. Es la misma neurona de 05-01, escrita en forma matricial para que el ordenador la calcule de golpe.

Dos dimensiones describen la forma de un MLP:

  • Anchura: cuántas neuronas tiene cada capa. Más neuronas = más "escalones" para dibujar la función (el aproximador universal de 05-01), y más parámetros.
  • Profundidad: cuántas capas ocultas hay. Cada capa reescribe la salida de la anterior, así que una red profunda compone transformaciones simples en una compleja: la primera capa detecta rasgos elementales, la siguiente combinaciones de rasgos, etc. Con la misma cantidad de parámetros, la profundidad suele ser más eficiente que la anchura para funciones complejas; y es lo que da nombre al deep learning (05-04).
Decisión Efecto de subirla Efecto de bajarla Regla práctica de partida
Anchura (neuronas por capa) Más capacidad, más parámetros, más riesgo de sobreajuste Puede subajustar Potencias de 2 entre 8 y 512; decreciente hacia la salida ("embudo")
Profundidad (capas ocultas) Representaciones más abstractas; más difícil de entrenar (sección 4) Menos capacidad de composición 1-3 capas para datos tabulares; decenas o cientos en visión y lenguaje
Parámetros totales Del orden de los ejemplos de entrenamiento o menos, salvo con regularización fuerte (05-03)

Para el predictor de devoluciones de NovaMarket (2.249 pedidos de entrenamiento, 21 columnas) usaremos un embudo modesto: 21 → 16 → 8 → 1.

  1. Contar parámetros a mano: 21 → 16 → 8 → 1

Cada capa densa con n_in entradas y n_out neuronas tiene n_in × n_out pesos más n_out sesgos. Contemos:

Capa Entradas Neuronas Pesos Sesgos Parámetros
Oculta 1 21 16 21 × 16 = 336 16 352
Oculta 2 16 8 16 × 8 = 128 8 136
Salida 8 1 8 × 1 = 8 1 9
Total 497

Frente a los 22 parámetros de la regresión logística (21 pesos + 1 sesgo) son 22 veces más, y aun así es una red diminuta: un modelo de visión típico tiene decenas de millones y un gran modelo de lenguaje miles de millones. Saber contar parámetros sirve para tres cosas: estimar la memoria (cada parámetro es un número de 32 bits, 4 bytes: 497 parámetros ocupan 2 KB; 7.000 millones, 28 GB), estimar el riesgo de sobreajuste (497 parámetros para 2.249 ejemplos es razonable; 50.000 no lo sería sin mucha regularización) y detectar errores al construir la red (si PyTorch dice un número distinto del que has calculado, algo no está conectado como crees).

  1. Funciones de activación: sigmoide, tanh, ReLU y variantes, softmax

La activación de las capas ocultas es lo que aporta la no linealidad (sin ella, 05-01, la red colapsa a un modelo lineal). Las opciones principales:

Función Fórmula Rango Valores en z = −3, −1, 0, 1, 3 Uso hoy
Sigmoide 1 / (1 + e^(−z)) (0, 1) 0,047; 0,269; 0,5; 0,731; 0,953 Solo en la salida de clasificación binaria
Tanh (e^z − e^(−z)) / (e^z + e^(−z)) (−1, 1) −0,995; −0,762; 0; 0,762; 0,995 Recurrentes (05-04); centrada en 0, mejor que sigmoide en ocultas
ReLU max(0, z) [0, ∞) 0; 0; 0; 1; 3 Por defecto en capas ocultas
Leaky ReLU z si z > 0; 0,01·z si no (−∞, ∞) −0,03; −0,01; 0; 1; 3 Cuando muchas ReLU "mueren" (sección 4)
ELU / GELU / SiLU Variantes suaves de ReLU ≈ (−1, ∞) GELU es la habitual en transformers (05-05)
Softmax e^(zᵢ) / Σⱼ e^(zⱼ) (sobre un vector) Cada salida en (0, 1), suman 1 Ver ejemplo Salida de clasificación multiclase

Observaciones:

  • La sigmoide y la tanh se saturan: para |z| > 3 la salida ya casi no cambia (0,953 → 0,999...). Eso las hace malas para capas ocultas, como veremos en la sección 4.
  • La ReLU (rectified linear unit) es de una simplicidad casi ofensiva: deja pasar los positivos y anula los negativos. Es barata de calcular, no se satura por la derecha y su pendiente es exactamente 1 para z > 0. Desde 2012 es la activación por defecto de las capas ocultas.
  • La softmax no es una activación por neurona sino sobre un vector: convierte k números cualesquiera (llamados logits) en k probabilidades que suman 1, exagerando las diferencias. Ejemplo con tres clases y z = (2, 1, −1): los exponenciales son e² = 7,389, e¹ = 2,718, e⁻¹ = 0,368, que suman 10,475; dividiendo, softmax = (0,705; 0,259; 0,035). La clase con mayor logit se lleva la mayor probabilidad; si sumas una constante a todos los logits el resultado no cambia. Con dos clases, softmax equivale a la sigmoide.

  1. El gradiente que se desvanece (intuición) y por qué ReLU

En 05-03 veremos que la red aprende calculando la pendiente de la pérdida respecto a cada peso, y que esa pendiente se obtiene multiplicando, capa a capa desde la salida hacia atrás, las pendientes de cada función que atraviesa la señal. Aquí basta con la intuición numérica:

  • La pendiente de la sigmoide es σ(z)·(1 − σ(z)), que vale como máximo 0,25 (en z = 0) y cae rápidamente: en z = 2 es 0,105 y en z = 5, 0,0066. En una red de 10 capas con sigmoide, en el mejor de los casos la pendiente que llega a la primera capa se ha multiplicado por 0,25¹⁰ ≈ 0,000001; en la práctica, mucho menos, porque casi ninguna neurona está en z = 0. Las primeras capas reciben una señal de corrección casi nula: no aprenden. Es el problema del gradiente que se desvanece (vanishing gradient), y es una de las razones de que en los 90 las redes se quedaran en dos o tres capas.
  • La pendiente de la ReLU es 1 para z > 0 y 0 para z < 0. Multiplicar unos no reduce nada: la señal llega intacta a las capas profundas por los caminos activos. Eso, junto con más datos y GPU, es lo que permitió entrenar redes de decenas de capas a partir de 2012 (05-04).

La ReLU tiene su propio riesgo: una neurona cuya z es negativa para todos los ejemplos devuelve siempre 0 y su pendiente también es 0, así que nunca vuelve a actualizarse ("ReLU muerta"). Suele ocurrir con tasas de aprendizaje demasiado altas; Leaky ReLU y ELU lo evitan dejando pasar una pequeña pendiente en los negativos. Regla práctica: ReLU en las ocultas; si ves muchas neuronas siempre a cero, prueba Leaky ReLU o baja la tasa de aprendizaje.

  1. Capa de salida y función de pérdida según el problema

La capa de salida y la función de pérdida (04-01: el número que el entrenamiento minimiza) van siempre en pareja y las dicta el tipo de problema:

Problema Neuronas de salida Activación de salida Pérdida Ejemplo NovaMarket
Clasificación binaria 1 Sigmoide Entropía cruzada binaria (BCE, la pérdida logarítmica de 04-01) Devuelto / no devuelto; reseña positiva / negativa; foto de paquete dañado / correcto
Clasificación multiclase (una sola clase correcta) k (una por clase) Softmax Entropía cruzada (categórica) Motivo de devolución (4 clases); categoría de una incidencia
Clasificación multietiqueta (varias a la vez) k Sigmoide en cada una BCE por salida Etiquetas de una reseña: "precio", "envío", "calidad"
Regresión 1 (o varias) Ninguna (lineal) Error cuadrático medio (MSE) o MAE Unidades del NovaClean la semana que viene; días hasta la entrega

La entropía cruzada binaria para un ejemplo con etiqueta y y probabilidad predicha p es −[y·log(p) + (1 − y)·log(1 − p)]. Si el pedido se devolvió (y = 1) y la red dijo p = 0,9, la pérdida es −log(0,9) = 0,105; si dijo p = 0,5, 0,693; si dijo p = 0,1, 2,303. Castiga mucho la confianza equivocada, exactamente como en la regresión logística. Un detalle de implementación que verás en 05-03: PyTorch ofrece nn.BCEWithLogitsLoss, que junta la sigmoide y la BCE en una operación numéricamente más estable; con ella la capa de salida se deja sin sigmoide y se aplica después solo para leer probabilidades. En esta lección, para que la salida sea legible, mantenemos la sigmoide explícita.

  1. Cómo representar las entradas: numéricas, categóricas y embeddings

Una red solo come números en un rango razonable, así que la preparación de 04-03 sigue vigente y es incluso más crítica:

  • Numéricas: estandarizadas (media 0, desviación 1) o escaladas a [0, 1]. Sin escalar, las columnas grandes dominan las sumas ponderadas y el entrenamiento se vuelve inestable (lo vimos con distancia en 05-01). Reutilizaremos tal cual el ColumnTransformer del módulo 4.
  • Binarias: 0/1 tal cual.
  • Categóricas con pocas categorías: one-hot (una columna por categoría), como categoria o metodo_pago en el módulo 4.
  • Categóricas con muchas categorías (los 12.000 productos de NovaMarket, las palabras de un idioma, los códigos postales): el one-hot es inviable (12.000 columnas casi todas a cero) y además trata todas las categorías como igual de distintas entre sí. La solución del deep learning es el embedding: asignar a cada categoría un vector denso de pocas dimensiones (por ejemplo 8 o 64) cuyos valores son parámetros que la red aprende junto con el resto. Tras el entrenamiento, categorías que se comportan parecido acaban con vectores parecidos: el NovaClean y otro robot aspirador quedarán cerca; "excelente" y "genial" también.
import torch, torch.nn as nn

tabla = nn.Embedding(num_embeddings=12000, embedding_dim=8)   # 12.000 productos -> vectores de 8
print(tabla.weight.shape)                                       # torch.Size([12000, 8]): 96.000 parámetros
ids = torch.tensor([3, 4587])                                   # dos productos por su índice
print(tabla(ids).shape)                                         # torch.Size([2, 8]): su vector cada uno

nn.Embedding es literalmente una tabla de consulta: fila i = vector del producto i. Al principio es aleatoria; el entrenamiento la va moviendo. La idea es central en recomendación (caso de uso 1: cliente y producto como embeddings cuyo producto escalar predice la afinidad, 05-04) y en lenguaje (cada palabra o token es un embedding; es la primera capa de cualquier transformer, 05-05).

  1. Panorama de familias de arquitecturas

El MLP es la arquitectura "genérica". Para cada tipo de dato ha surgido una familia que incorpora supuestos sobre la estructura de los datos y por eso aprende con muchos menos parámetros y ejemplos:

flowchart TD
    RN["Redes neuronales"] --> MLP["MLP / densas<br/>datos tabulares<br/>(esta lección y 05-03)"]
    RN --> CNN["Convolucionales (CNN)<br/>imágenes, señales<br/>fotos de incidencias (05-04)"]
    RN --> RNN["Recurrentes (RNN, LSTM, GRU)<br/>secuencias, series temporales<br/>demanda semanal (05-04)"]
    RN --> AE["Autoencoders<br/>compresión, anomalías<br/>fraude (05-04)"]
    RN --> TR["Transformers<br/>texto, y hoy casi todo<br/>reseñas, asistente (05-05)"]
Familia Supuesto que incorpora Dato típico Lección
MLP (densa) Ninguno: cada entrada es independiente Tabla de columnas 05-02, 05-03
Convolucional Los patrones son locales y se repiten en cualquier posición Imágenes, audio, series 05-04
Recurrente El orden importa; hay un estado que se arrastra Series temporales, texto (histórico) 05-04
Autoencoder Los datos viven en un espacio de menos dimensiones Cualquiera (sin etiquetas) 05-04
Transformer Cada elemento debe "mirar" a todos los demás (atención) Texto, imágenes, audio, código 05-05

Todas comparten los ingredientes de esta lección: capas de neuronas, activaciones ReLU o similares, una capa de salida con su pérdida y embeddings para lo categórico. Cambian en cómo se conectan las neuronas.

  1. Código: el MLP del predictor de devoluciones en PyTorch

Reutilizamos la preparación del módulo 4 (generar_pedidos_ml, ensuciar_pedidos, preparar_pedidos y crear_preparacion de novamarket_ml.py, que producen las 21 columnas) y construimos la red 21 → 16 → 8 → 1.

import numpy as np
import torch
import torch.nn as nn
from sklearn.model_selection import train_test_split
from novamarket_ml import generar_pedidos_ml, ensuciar_pedidos, preparar_pedidos, crear_preparacion

# 1. Datos: la misma división de 04-05 (750 pedidos de test)
X, y = preparar_pedidos(ensuciar_pedidos(generar_pedidos_ml(3000, 42), 42))
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.25, random_state=42, stratify=y)
prep = crear_preparacion().fit(Xtr)                 # ajusta imputación, escalado y one-hot SOLO con train
Xtr_m = prep.transform(Xtr).astype(np.float32)      # matriz numpy 2249 x 21, en float32 (lo que usa PyTorch)
Xte_m = prep.transform(Xte).astype(np.float32)
print(Xtr_m.shape, Xte_m.shape)

# 2. Arquitectura
torch.manual_seed(42)                                # los pesos iniciales son aleatorios: fijamos la semilla
red = nn.Sequential(
    nn.Linear(21, 16), nn.ReLU(),                    # capa oculta 1: 21 entradas -> 16 neuronas, ReLU
    nn.Linear(16, 8),  nn.ReLU(),                    # capa oculta 2: 16 -> 8, ReLU
    nn.Linear(8, 1),   nn.Sigmoid())                 # salida: 8 -> 1 probabilidad de devolución
print(red)

# 3. Parámetros
for nombre, p in red.named_parameters():
    print(f"{nombre:10s} {str(tuple(p.shape)):10s} {p.numel():4d}")
print("Total:", sum(p.numel() for p in red.parameters()))

Salida:

(2249, 21) (750, 21)
Sequential(
  (0): Linear(in_features=21, out_features=16, bias=True)
  (1): ReLU()
  (2): Linear(in_features=16, out_features=8, bias=True)
  (3): ReLU()
  (4): Linear(in_features=8, out_features=1, bias=True)
  (5): Sigmoid()
)
0.weight   (16, 21)    336
0.bias     (16,)        16
2.weight   (8, 16)     128
2.bias     (8,)          8
4.weight   (1, 8)        8
4.bias     (1,)          1
Total: 497

Explicación: nn.Linear(21, 16) crea la matriz W de 16 × 21 (PyTorch guarda una fila por neurona) y el vector b de 16; named_parameters() recorre todos los tensores entrenables, y la cuenta coincide con la tabla de la sección 2 (497). Los índices 0, 2, 4 son las posiciones dentro del Sequential (las activaciones ocupan 1, 3, 5 y no tienen parámetros).

Una función pequeña que imprime la arquitectura con su conteo (útil para revisar cualquier Sequential):

def resumen(red):
    print(f"{'capa':<10}{'entrada':>8}{'salida':>8}{'parámetros':>12}")
    total = 0
    for i, capa in enumerate(red):
        if isinstance(capa, nn.Linear):
            n = capa.in_features * capa.out_features + capa.out_features
            total += n
            print(f"Linear {i:<3}{capa.in_features:>8}{capa.out_features:>8}{n:>12}")
        else:
            print(f"{capa.__class__.__name__:<10}{'':>8}{'':>8}{0:>12}")
    print(f"{'TOTAL':<10}{'':>8}{'':>8}{total:>12}")

resumen(red)

Salida:

capa       entrada  salida  parámetros
Linear 0        21      16         352
ReLU                                 0
Linear 2        16       8         136
ReLU                                 0
Linear 4         8       1           9
Sigmoid                              0
TOTAL                              497

Ahora el paso hacia delante (forward): pasamos cinco pedidos de test por la red sin haberla entrenado:

from sklearn.metrics import roc_auc_score

X_t = torch.tensor(Xte_m[:5])                        # numpy -> tensor de PyTorch (5 x 21)
with torch.no_grad():                                # no necesitamos pendientes todavía
    prob = red(X_t)                                  # forward: aplica las 6 piezas en orden
print("Probabilidades:", prob.numpy().ravel().round(3), " reales:", yte.values[:5])

with torch.no_grad():
    todas = red(torch.tensor(Xte_m)).numpy().ravel()
print("Media:", todas.mean().round(3), " mín:", todas.min().round(3), " máx:", todas.max().round(3))
print("AUC sin entrenar:", round(roc_auc_score(yte, todas), 3))

Salida (varía con la semilla y la versión de PyTorch):

Probabilidades: [0.546 0.547 0.54  0.558 0.549]  reales: [0 1 0 0 1]
Media: 0.551  mín: 0.531  máx: 0.605
AUC sin entrenar: 0.517

Lectura: la red no sabe nada. Con pesos aleatorios pequeños, todas las z de salida rondan 0 y la sigmoide devuelve ≈ 0,55 para todos los pedidos; el AUC de 0,517 es el de una moneda (0,5). Podemos mirar dentro para ver el flujo de un pedido:

with torch.no_grad():
    z1 = red[0](X_t[:1])          # suma ponderada de la capa 1 (16 valores)
    h1 = red[1](z1)               # tras ReLU: los negativos se anulan
    h2 = red[3](red[2](h1))       # capa 2 + ReLU (8 valores)
    z3 = red[4](h2)               # logit de salida
print("z1:", z1.numpy().round(2))
print("h1:", h1.numpy().round(2))
print("h2:", h2.numpy().round(2))
print("z3:", z3.numpy().round(3), " sigmoide:", torch.sigmoid(z3).numpy().round(3))

Salida:

z1: [[-0.2   0.03  0.51 -0.63 -0.01 -0.71 -0.   -0.78 -0.31 -0.13 -0.34 -0.46  0.34 -0.64 -0.21  0.21]]
h1: [[0.   0.03 0.51 0.   0.   0.   0.   0.   0.   0.   0.   0.   0.34 0.    0.    0.21]]
h2: [[0.01 0.12 0.   0.11 0.   0.   0.07 0.  ]]
z3: [[0.187]]  sigmoide: [[0.546]]

Se ve la ReLU en acción: de las 16 sumas ponderadas de la primera capa, 12 eran negativas y quedan a 0; solo 4 neuronas "hablan" para este pedido. En la segunda capa, 4 de 8. Es normal (y deseable: representaciones dispersas), siempre que no sean siempre las mismas neuronas para todos los pedidos (ReLU muertas). Los pesos concretos (red[0].weight[0, :5] da algo como [0.167, 0.181, -0.051, 0.2, -0.048]) no significan nada todavía: son el punto de partida aleatorio del descenso que haremos en 05-03.

Errores Comunes y Consejos

  • Sigmoide en las capas ocultas. Es el reflejo natural tras el módulo 4, pero provoca el gradiente que se desvanece. Reserva la sigmoide para la salida binaria; ReLU (o Leaky ReLU/GELU) en las ocultas.
  • Softmax con una sola neurona, o sigmoide con varias clases excluyentes. Softmax de un solo valor es siempre 1; y para "motivo de devolución" (una clase entre cuatro) las sigmoides independientes pueden dar 0,9 a dos clases a la vez. Respeta la tabla de la sección 5.
  • Emparejar mal salida y pérdida. Sigmoide + MSE entrena mal (la pérdida se aplana en las zonas saturadas); usa BCE. Y no apliques sigmoide dos veces (una en la red y otra dentro de BCEWithLogitsLoss).
  • Olvidar el escalado. Con entradas en escalas dispares, ReLU y descenso del gradiente se comportan mal. Reutiliza el ColumnTransformer de 04-03 y ajústalo solo con entrenamiento.
  • Sobredimensionar por defecto. 3 capas de 512 neuronas para 2.249 pedidos son casi 400.000 parámetros: memorizará el entrenamiento. Empieza pequeño (como 21 → 16 → 8 → 1) y crece solo si la validación lo pide (04-06).
  • Fiarse de la salida antes de entrenar. Como acabamos de ver, la red devuelve ≈ 0,55 para todo; una arquitectura correcta no es un modelo. Hasta 05-03 no hay predicción.

Ejercicios

Ejercicio 1. Calcula a mano los parámetros de una red 21 → 32 → 16 → 8 → 1 (todas densas, ReLU en ocultas, sigmoide en salida). Constrúyela con nn.Sequential, comprueba la cifra con resumen y compárala con el número de pedidos de entrenamiento (2.249). ¿Te parece prudente sin regularización?

Ejercicio 2. Sustituye la salida nn.Linear(8, 1), nn.Sigmoid() por nn.Linear(8, 2) seguida de torch.softmax(..., dim=1) (dos neuronas: "no devuelto" y "devuelto"). Cuenta los parámetros y comprueba que las dos probabilidades suman 1 para cualquier pedido. ¿Es una red distinta de la binaria con sigmoide? ¿Qué pérdida le correspondería según la tabla de la sección 5?

Ejercicio 3. Para cada problema de NovaMarket, indica número de neuronas de salida, activación de salida, pérdida y cómo representarías la entrada principal: (a) predecir la valoración de 1 a 5 estrellas de una reseña a partir del texto; (b) predecir las unidades semanales del NovaClean a partir de las 8 semanas anteriores; (c) predecir el motivo de devolución (4 categorías) a partir de las 21 columnas del pedido más el identificador del producto (12.000 valores).

Soluciones

Solución 1. 21×32 + 32 = 704; 32×16 + 16 = 528; 16×8 + 8 = 136; 8×1 + 1 = 9; total 1.377, y resumen lo confirma. Son 0,6 parámetros por ejemplo de entrenamiento: manejable, pero ya del orden en que conviene usar parada temprana y dropout (05-03); con la red de 497 tenemos margen y por eso la elegimos.

Solución 2. La red tiene 497 − 9 + (8×2 + 2) = 506 parámetros. Con torch.softmax(red2(x), dim=1) obtienes, por ejemplo, [[0.535 0.465]] para un pedido: suman 1. Matemáticamente es equivalente a la binaria con sigmoide (la softmax de dos logits z₀, z₁ es la sigmoide de z₁ − z₀), solo que con un parámetro redundante por entrada de la última capa. Le correspondería la entropía cruzada categórica (nn.CrossEntropyLoss, que en PyTorch incluye la softmax). En la práctica, para problemas binarios se usa la versión de una neurona.

Solución 3. (a) 5 neuronas, softmax, entropía cruzada categórica; la entrada, el texto, se representa como secuencia de embeddings de palabras (o, como línea base, bolsa de palabras: 05-05). Alternativa razonable: tratarlo como regresión de 1 a 5 con salida lineal + MSE, si importa "cuánto" se equivoca (predecir 4 cuando era 5 es menos grave que predecir 1). (b) 1 neurona, salida lineal, MSE o MAE; entrada: las 8 unidades anteriores estandarizadas (un MLP de 8 entradas o, mejor, una red recurrente que respete el orden, 05-04). (c) 4 neuronas, softmax, entropía cruzada; las 21 columnas del ColumnTransformer concatenadas con un nn.Embedding(12000, 8) del producto (8 dimensiones aprendidas en lugar de 12.000 columnas one-hot).

Conclusión

Hemos desmontado la arquitectura de un perceptrón multicapa: capas densas que calculan f(W·x + b), la anchura y la profundidad como decisiones de diseño, y el conteo de parámetros a mano (21 → 16 → 8 → 1 = 497, frente a los 22 de la logística). Hemos comparado las funciones de activación y entendido por qué la ReLU sustituyó a la sigmoide en las capas ocultas: la sigmoide se satura y su pendiente máxima de 0,25 hace que la señal de corrección se desvanezca en redes profundas, mientras que la ReLU la transmite intacta. Hemos emparejado capa de salida y pérdida según el problema (sigmoide + BCE, softmax + entropía cruzada, lineal + MSE), repasado cómo representar las entradas y presentado los embeddings como la forma de dar vectores aprendidos a productos y palabras. Y hemos construido en PyTorch el MLP del predictor de devoluciones de NovaMarket sobre las 21 columnas del módulo 4, contado sus parámetros e inspeccionado un forward: con pesos aleatorios, la red dice ≈ 0,55 a todo y su AUC es 0,517. La red no sabe nada todavía.

En la siguiente lección, Cómo Aprende una Red: Descenso del Gradiente y Retropropagación, le enseñaremos: veremos la pérdida como un paisaje del que ahora sí conocemos la pendiente, el descenso del gradiente paso a paso, la regla de la cadena que reparte el error hacia atrás capa a capa, y escribiremos el bucle de entrenamiento completo en PyTorch (DataLoader, Adam, épocas, parada temprana y dropout) para comprobar si esta red de 497 parámetros mejora, o no, el 0,844 de AUC de la regresión logística.

Fundamentos de Inteligencia Artificial (IA)

Módulo 1: Introducción a la Inteligencia Artificial

Módulo 2: Principios Básicos de la IA

Módulo 3: Algoritmos en IA

Módulo 4: Aprendizaje Automático (Machine Learning)

Módulo 5: Redes Neuronales y Deep Learning

Módulo 6: Lógica y Sistemas Expertos

Módulo 7: Herramientas y Lenguajes de Programación en IA

Módulo 8: Proyectos y Casos de Estudio

Módulo 9: Ejercicios y Prácticas

Módulo 10: Recursos Adicionales

© Copyright 2026. Todos los derechos reservados