1 · Lo básico de MLLección 6 de 8
Redes neuronales y CNNs
Neural networks and CNNs
Qué hay dentro de la ResNet-50 de C01, desde una sola neurona hasta el modelo completo: cómo se cuentan sus parámetros y sus cuentas, cómo mira una foto y por qué se empieza con un modelo que ya vio más de un millón de fotos.
Secciones14
- 01Una neurona y su límite
- 02Capas y MLP: la red completa y lo que cuesta
- 03Del perceptrón a la inicialización extra
- 04Convolución: un filtro que recorre la foto
- 05El campo receptivo: cuánto de la foto ve cada neurona extra
- 06La ResNet-50 por dentro: atajos, BatchNorm y model.eval()
- 07Backbone, cabeza y transfer learning
- 08Vision Transformers: la foto como una frase de parches extra
- 09Errores comunes
- 10En la vida real extra
- 11Ejercicios
- 12Lo que sigue
- 13Palabras que vas a oír
- 14Chequeo
¿Qué es exactamente una «red neuronal», qué cuentas hace por dentro y por qué funciona tan bien con fotos?
Una neurona y su límite
EsencialOne neuron and its limit
En las lecciones anteriores viste que un modelo es una función con parámetros y que entrenar es ajustarlos. Ahora vamos a abrir la caja: ¿qué cuentas hace por dentro?
La pieza más chica es la neurona. Hace tres cosas:
- 1
Multiplica cada entrada por su peso
Recibe varios números de entrada y a cada uno lo multiplica por un número propio, su peso (weight). El peso dice qué tanto le importa esa entrada, y si la cuenta a favor (positivo) o en contra (negativo).
- 2
Suma todo y le agrega su sesgo
Suma esos productos y les agrega otro número propio, el sesgo (bias), que mueve el resultado hacia arriba o hacia abajo.
- 3
Pasa el resultado por una activación
Al final aplica una función sencilla, la activación, que decide qué sale. La más usada es la ReLU: si el número es negativo, sale 0; si no, sale igual.
¿Para qué la activación?
Parece un detalle, pero sin ella nada funcionaría. Sin activación, una neurona solo multiplica y suma: es una función lineal, una recta. Y si apilas rectas, sale otra recta. Por ejemplo, si una capa hace y = 3x + 1 y la siguiente hace z = 2y − 1, juntas hacen z = 2 × (3x + 1) − 1 = 6x + 1. Otra recta. Cien capas sin activación valen lo mismo que una.
La activación dobla la recta. La ReLU la dobla en el 0: todo lo negativo se aplana. Con muchas neuronas, cada una doblada en un lugar distinto, la red puede formar curvas tan complicadas como haga falta, como la frontera entre «foto de tenis» y «foto de bota». Antes se usaban activaciones suaves, como la sigmoide, que aplasta cualquier número entre 0 y 1; la ReLU se impuso en la década de 2010 porque es baratísima y con ella las redes profundas aprenden más rápido.
Lo que una neurona sola no puede: el XOR
Pongamos a una neurona a contestar «sí» o «no» sobre dos entradas que valen 0 o 1. En vez de la ReLU usa una activación de escalón: si la suma pasa de 0 sale 1 («sí»), y si no, 0 («no»). Dos funciones para probarla: el AND vale 1 solo si las dos entradas valen 1; el XOR («o exclusivo») vale 1 si exactamente una vale 1.
La neurona responde 1 cuando w₁x₁ + w₂x₂ + b > 0 y 0 cuando no. La frontera entre las dos respuestas, w₁x₁ + w₂x₂ + b = 0, es una recta: una neurona sola parte el plano en dos con una recta, y nada más.
Pon los cuatro casos como puntos, con x₁ a lo ancho y x₂ a lo alto. En el AND, el único 1 es la esquina (1, 1), y una recta la aparta: con w₁ = 2, w₂ = 1 y b = −2, solo (1, 1) da una suma positiva (2 + 1 − 2 = 1). En el XOR, los unos están en esquinas opuestas, (0, 1) y (1, 0): cualquier recta que los deje del mismo lado deja también a alguno de los ceros. No es que falten pesos buenos: lo que le pides no se puede dibujar con una recta.
Una neurona así, con escalón, es el perceptrón que Frank Rosenblatt publicó en 1958, una de las primeras neuronas artificiales que aprendían solas. Aprendía el AND, pero nunca el XOR; su historia, con código, está en la sección extra «Del perceptrón a la inicialización». La salida es juntar varias neuronas, en capas.
Capas y MLP: la red completa y lo que cuesta
EsencialLayers and MLPs: the whole network and its cost
Una neurona sola traza una recta. Se juntan muchas en una capa: todas reciben las mismas entradas, cada una con sus propios pesos, y cada una saca un número. Las salidas de una capa son las entradas de la siguiente. Eso es una red neuronal.
Cuando cada neurona de una capa ve todas las salidas de la anterior, la capa se llama densa (dense o fully connected). Una red de capas densas con activaciones entre ellas es un MLP (multilayer perceptron, perceptrón multicapa), un nombre que viene del perceptrón, aunque ya no usa escalón. Las capas de en medio se llaman capas ocultas (hidden layers).
El XOR, resuelto con una capa oculta
¿Qué hizo la capa oculta? Movió los puntos: con las coordenadas (h₁, h₂), los dos casos que valen 1 caen juntos en (1, 0), y ahí una recta sí los separa de los ceros (el panel de abajo de la figura). Esa es la idea de toda red neuronal: cada capa acomoda los datos para que a la siguiente le sea más fácil.
Aquí los pesos los puse a mano. En una red de verdad los encuentra el entrenamiento, con la backpropagation que viste en «Cómo aprende un modelo»: una forma de repartir la culpa del error entre todas las capas, también las ocultas. Es justo lo que le faltaba a la regla del perceptrón, que solo sabe corregir la neurona que da la respuesta.
Usar redes con muchas capas es el deep learning (aprendizaje profundo): «profundo» se refiere a la cantidad de capas. Cada capa trabaja sobre lo que encontró la anterior, así que más capas dan más pasos para combinar cosas simples en complicadas. La ResNet-50 de C01 tiene 50 capas con pesos.
Un forward pass con lápiz
Hacer pasar una entrada por todas las capas, de la primera a la última, se llama forward pass (pasada hacia adelante). Es lo que hace el modelo cada vez que responde. Hagamos uno a mano en una red de juguete: 2 entradas → 3 neuronas con ReLU → 2 salidas, una para «Tenis» y otra para «Botas».
Eso es todo lo que hace una red al responder: multiplicar, sumar y aplicar la activación, capa por capa. La ResNet-50 hace lo mismo con la foto de Ana, solo que con unos 4,100 millones de multiplicaciones (cada una con su suma) en lugar de una docena.
Contar parámetros y multiplicaciones
Los parámetros de una red son todos sus pesos y todos sus sesgos. En la red de juguete:
- Capa 1: 2 entradas × 3 neuronas = 6 pesos, más 3 sesgos = 9
- Capa 2: 3 entradas × 2 salidas = 6 pesos, más 2 sesgos = 8
- Total: 9 + 8 = 17 parámetros
La regla sirve para cualquier capa densa: parámetros = entradas × salidas + salidas.
La otra cuenta es cuánto trabajo hace. Cada peso se usa una vez por ejemplo: se multiplica por su entrada y se suma a lo acumulado. Ese par «multiplica y suma» se llama MAC (multiply-accumulate) y es la unidad con que se mide el trabajo de una red. Una capa densa hace entradas × salidas MACs por ejemplo; la red de juguete, 2 × 3 + 3 × 2 = 12.
¿Y si le das la foto entera a un MLP? La calculadora empieza con el clásico de los años 90: dígitos escritos a mano de 28 × 28 píxeles en gris (el dataset MNIST), 128 neuronas ocultas y 10 salidas, una por dígito.
Una capa oculta densa y una de salida. Mueve el tamaño de la foto y mira cómo crecen los parámetros de la primera capa: cada píxel de cada canal necesita un peso por cada neurona oculta.
Con 224 × 224 en color y solo 128 ocultas, la primera capa ya tiene 19.3 millones de parámetros, y cada peso conecta un solo número de la foto (un píxel de un color) con una sola neurona.
Después prueba lado 224, 3 canales y 500 salidas: la foto de C01.
Con los dígitos son 101,770 parámetros. Con la foto de C01 y apenas 128 neuronas ocultas, la primera capa ya tiene 150,528 × 128 + 128 = 19,267,712, tres cuartas partes de la ResNet-50 entera. Y como cada píxel tiene su propio peso, la red tendría que aprender a encontrar el tenis en cada posición por separado. La convolución arregla las dos cosas.
Contar parámetros dice cuánta memoria pide el modelo. Guardado como float32, cada uno ocupa 4 bytes: los 25.6 millones de una ResNet-50 son 25.6 M × 4 B ≈ 102 MB, la primera cuenta de la Ronda en M04 para saber cuánta memoria de GPU necesita.
Contar MACs dice cuánto cálculo pide cada foto: la ResNet-50 hace ≈ 4,100 millones, 4.1 GMACs (G es «giga», mil millones). Cuánto tarda eso en una GPU de verdad lo ves con la T4 de C01 en «En la vida real».
Del perceptrón a la inicialización
ExtraFrom the perceptron to initialization
Esta sección es para una segunda pasada: cómo aprendía una de las primeras neuronas artificiales, por qué las redes se atoraron durante años y con qué números empiezan los pesos de una red de hoy.
El perceptrón: una neurona que aprendía de sus errores
En 1958, el psicólogo estadounidense Frank Rosenblatt publicó el perceptrón: una neurona con escalón, como la del XOR de la primera sección. Lo nuevo era que aprendía solo, con una regla simple. Si acierta, no cambia nada. Si dijo 0 y era 1, le suma cada entrada a su peso (y 1 al sesgo), para que la próxima vez su suma salga más alta; si dijo 1 y era 0, se las resta.
Probémoslo con el AND y el XOR de la primera sección. Cada «vuelta» es una pasada por los cuatro casos.
# El perceptrón de Rosenblatt: si se equivoca, mueve sus pesos hacia la respuesta
def entrenar(datos, vueltas=20):
w1, w2, b = 0, 0, 0
for vuelta in range(1, vueltas + 1):
errores = 0
for x1, x2, y in datos:
pred = 1 if w1 * x1 + w2 * x2 + b > 0 else 0 # el escalón
if pred != y:
errores += 1
w1 += (y - pred) * x1 # dijo 0 y era 1: suma la entrada
w2 += (y - pred) * x2 # dijo 1 y era 0: la resta
b += (y - pred)
if errores == 0:
return f"aprendió en la vuelta {vuelta}: w1={w1}, w2={w2}, b={b}"
return f"tras {vueltas} vueltas sigue fallando {errores} de 4"
AND = [(0, 0, 0), (0, 1, 0), (1, 0, 0), (1, 1, 1)]
XOR = [(0, 0, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0)]
print("AND:", entrenar(AND))
print("XOR:", entrenar(XOR))AND: aprendió en la vuelta 6: w1=2, w2=1, b=-2
XOR: tras 20 vueltas sigue fallando 4 de 4Con el AND, a la sexta vuelta ya no se equivoca: llega a w₁ = 2, w₂ = 1 y b = −2, los pesos que viste en la primera sección. Con el XOR se queda en un ciclo en el que cada corrección deshace la anterior; ni con mil vueltas aprende.
Rosenblatt llegó a construir una máquina, la Mark I Perceptron, que veía con una cámara de 20 × 20 = 400 fotoceldas, y un periódico de 1958 contó que la Marina de Estados Unidos esperaba que una máquina así llegara a caminar, hablar y ver. No pasó: el perceptrón tenía un límite que ninguna cantidad de vueltas arregla, el del XOR.
En 1969, Marvin Minsky y Seymour Papert publicaron Perceptrons, un libro que convirtió este tipo de límites en teoremas. Se le suele culpar de que el interés y el dinero para las redes neuronales se enfriaran durante años; la historia real tiene más causas (computadoras lentas, pocos datos), pero el límite es real. La salida fueron las capas ocultas y una forma de entrenarlas, la backpropagation.
Para ir más hondoDe 1958 a hoy, en ocho fechas+
| Año | Qué pasó |
|---|---|
| 1958 | Rosenblatt publica el perceptrón, una neurona que aprende de sus errores. |
| 1969 | Minsky y Papert publican Perceptrons: una sola capa no puede con el XOR. |
| 1986 | Rumelhart, Hinton y Williams popularizan la backpropagation: ya se entrenan capas ocultas. |
| 1989–1998 | Yann LeCun y su equipo entrenan CNNs que leen dígitos escritos a mano; a finales de los 90 una lee cheques en bancos de Estados Unidos. |
| 2009 | Se publica ImageNet. De 2010 a 2017 hay una competencia anual con su versión de 1,000 categorías. |
| 2012 | AlexNet, una CNN entrenada en dos GPUs, gana con 15.3 % de error top-5 contra 26.2 % del segundo lugar. Despega el deep learning. |
| 2015 | Gana la ResNet, con atajos y 152 capas. Salen también la BatchNorm y la U-Net. |
| 2020 | El Vision Transformer muestra que un transformer, la arquitectura de los LLMs, también ve fotos. |
Desde 1986 la idea básica casi no cambió. Cambiaron tres cosas: muchos más datos, GPUs para hacer las cuentas y trucos para entrenar redes profundas. La ReLU y el Dropout ya los usó AlexNet en 2012; una buena inicialización, la BatchNorm y los atajos se sumaron entre 2010 y 2015. Están todos en esta lección.
Inicialización: con qué números empieza una red
Antes del primer paso del entrenamiento, cada peso necesita un valor. Elegirlo se llama inicialización (initialization). Parece un detalle, pero durante años fue una de las razones por las que las redes profundas no aprendían.
¿Por qué no empezar todo en cero? Piensa en dos neuronas ocultas que empiezan con los mismos pesos. Reciben las mismas entradas, así que calculan lo mismo; la backpropagation les reparte la misma culpa, así que se mueven igual. Paso tras paso siguen siendo gemelas: dos neuronas que valen por una. Es el problema de la simetría. Con todo en cero es peor: las ocultas sacan 0, la salida las multiplica por pesos que valen 0, la culpa regresa multiplicada por esos mismos ceros y nada se mueve.
# Dos neuronas ocultas que empiezan iguales: ¿se separan al entrenar?
r = lambda fila: [round(a, 4) for a in fila]
def entrenar(w0, pasos=3, lr=0.01):
x, y = [1.0, 2.0], 1.0 # un ejemplo y su respuesta
W = [[w0, w0], [w0, w0]] # pesos de las 2 neuronas ocultas
v = [w0, w0] # pesos de la salida
for paso in range(1, pasos + 1):
h = [max(0.0, W[i][0] * x[0] + W[i][1] * x[1]) for i in range(2)] # ReLU
err = v[0] * h[0] + v[1] * h[1] - y # la pérdida es err²
for i in range(2): # backpropagation, a mano
culpa = 2 * err * v[i] * (1 if h[i] > 0 else 0)
v[i] -= lr * 2 * err * h[i]
W[i] = [W[i][j] - lr * culpa * x[j] for j in range(2)]
print(f" paso {paso}: neurona 1 {r(W[0])} neurona 2 {r(W[1])}")
print("Todo en 0.5:"); entrenar(0.5)
print("Todo en 0:"); entrenar(0.0)Todo en 0.5:
paso 1: neurona 1 [0.495, 0.49] neurona 2 [0.495, 0.49]
paso 2: neurona 1 [0.4908, 0.4816] neurona 2 [0.4908, 0.4816]
paso 3: neurona 1 [0.4873, 0.4746] neurona 2 [0.4873, 0.4746]
Todo en 0:
paso 1: neurona 1 [0.0, 0.0] neurona 2 [0.0, 0.0]
paso 2: neurona 1 [0.0, 0.0] neurona 2 [0.0, 0.0]
paso 3: neurona 1 [0.0, 0.0] neurona 2 [0.0, 0.0]Con 0.5, las dos neuronas se mueven, pero en cada paso tienen exactamente los mismos pesos. Con 0, ni se mueven. La salida es romper la simetría con números al azar: cada neurona empieza distinta, recibe una culpa distinta y termina aprendiendo algo distinto.
¿Qué tan grandes?
Al azar, sí, pero ¿de qué tamaño? Si los pesos son un poco grandes, los números crecen un poco en cada capa y después de 20 o 50 capas explotan; si son un poco chicos, se encogen hasta casi 0. Lo mismo le pasa a la culpa del entrenamiento, que viaja de regreso por los mismos pesos.
El tamaño justo depende de cuántas entradas suma cada neurona: entre más entradas, más chicos los pesos, para que la suma no crezca. La regla más usada con ReLU es la de He (Kaiming He y otros, 2015, el mismo primer autor de la ResNet): pesos al azar alrededor de 0 con una desviación estándar de √(2 ÷ entradas). La desviación estándar mide qué tan lejos de 0 caen: es la raíz del promedio de sus cuadrados, la misma cuenta que hace tamano en el código de abajo. El 2 compensa que la ReLU apaga más o menos la mitad de los números, los negativos.
# ¿Qué le pasa a la señal después de 20 capas, según el tamaño de los pesos?
import math, random
random.seed(0)
n, capas = 100, 20 # 100 neuronas por capa
def tamano(x): # qué tan grandes son los números
return math.sqrt(sum(v * v for v in x) / len(x))
for nombre, sigma in [("chicos, 0.05", 0.05), ("He, √(2/100)", math.sqrt(2 / n)), ("grandes, 0.3", 0.3)]:
x = [random.gauss(0, 1) for _ in range(n)]
for capa in range(capas):
W = [[random.gauss(0, sigma) for _ in range(n)] for _ in range(n)]
x = [max(0.0, sum(w * xi for w, xi in zip(fila, x))) for fila in W] # ReLU
print(f"pesos {nombre:<14} tamaño tras {capas} capas: {tamano(x):.3g}")pesos chicos, 0.05 tamaño tras 20 capas: 3.45e-09
pesos He, √(2/100) tamaño tras 20 capas: 1.48
pesos grandes, 0.3 tamaño tras 20 capas: 1.34e+06La entrada empieza con números de tamaño ≈ 1. 3.45e-09 es como Python escribe 3.45 × 10⁻⁹ (0.00000000345), y 1.34e+06 es 1.34 millones. Con 0.05 la señal casi desaparece; con 0.3 se dispara; con la regla de He, √(2 ÷ 100) ≈ 0.141, llega viva. No es un ajuste fino: es la diferencia entre aprender y no aprender.
En la práctica no lo escribes tú: PyTorch inicializa cada capa con una regla de este tipo al crearla, y la ResNet de torchvision usa la de He en sus convoluciones. En C01 casi ni importa, porque la red llega ya entrenada con ImageNet, más de un millón de fotos (lo ves en «Backbone, cabeza y transfer learning»): solo la capa nueva de 2,048 → 500 empieza al azar, con números entre −1/√2,048 y +1/√2,048, o sea entre −0.022 y +0.022.
Convolución: un filtro que recorre la foto
EsencialConvolution: a filter that slides over the photo
Ya viste el problema del MLP: una foto de 224 × 224 píxeles con 3 colores son 150,528 números, y una sola capa densa de 1,000 neuronas sobre ellos necesitaría 150,528 × 1,000 ≈ 150 millones de pesos, casi 6 veces la ResNet-50 entera. Además desperdicia algo obvio: en una foto lo que importa son los píxeles cercanos entre sí. Un píxel de la esquina tiene poco que decirle a uno del centro.
La solución es la convolución. En vez de que cada neurona vea toda la foto, un filtro chico, por ejemplo de 3 × 3, se va deslizando por la foto. En cada posición mira solo 9 píxeles, los multiplica por sus 9 pesos, suma todo y escribe un número; luego se mueve un lugar y repite.
Nadie programó ese filtro. En una red de verdad, los 9 pesos los encuentra el entrenamiento, y muchos filtros de las primeras capas terminan pareciéndose a detectores de bordes como este.
Canales y mapas de activaciones
Una foto de color no es una cuadrícula sino tres, una por color: rojo, verde y azul. Cada una es un canal. Por eso, un filtro de verdad no es de 3 × 3 sino de 3 × 3 × 3: mira los tres canales a la vez. Son 27 pesos más 1 sesgo = 28 parámetros.
Y una capa no tiene un solo filtro, sino muchos: uno busca bordes verticales, otro horizontales, otro un cambio de color. Cada filtro produce su propia cuadrícula de salida, su mapa de activaciones (feature map), que dice dónde encontró lo que busca. Una capa con 64 filtros produce 64 mapas, y esos son los 64 canales de entrada de la capa siguiente.
Esa es la diferencia de fondo: en una capa densa cada peso se usa una vez por foto; en una convolución, una vez por posición. Por eso la Ronda, en M04, dice que una CNN en GPU, con batches moderados, suele estar limitada por el cálculo y no por la memoria (compute-bound): la GPU pasa más tiempo haciendo cuentas que esperando números de la memoria, porque cada peso que lee lo usa miles de veces.
Stride y padding: el tamaño de la salida
En el ejemplo, la entrada era de 5 × 5 y la salida de 3 × 3: en una fila de 5, una ventana de 3 cabe en 5 − 3 + 1 = 3 posiciones. Dos perillas cambian esa cuenta:
- El stride (paso): cuántos píxeles salta el filtro de una posición a la siguiente. Con stride 2 salta de dos en dos, y la salida queda más o menos de la mitad de ancho y de alto.
- El padding (relleno): un marco de ceros alrededor de la entrada, para que el filtro también se centre en las orillas y la salida no se encoja.
Con las dos, el lado de la salida es:
lado de salida = (n + 2p − k) ÷ s + 1, redondeando la división hacia abajo
Aquí n es el lado de la entrada, k el del filtro, p el padding (filas de ceros por lado) y s el stride. ¿De dónde sale? Con el marco, la entrada mide n + 2p; la primera ventana ocupa k píxeles y caben (n + 2p − k) ÷ s saltos más antes de salirse, más la posición de arranque. Si la división no es exacta, la última ventana no cabe completa y esas columnas se quedan sin visitar.
El stride es la forma barata de achicar: con stride 2 queda la cuarta parte de las posiciones, así que la capa siguiente hace cuatro veces menos cuentas por filtro.
Empieza en la primera capa de la ResNet-50: 64 filtros de 7 × 7 con padding 3 y stride 2 sobre la foto de 224 × 224 × 3. El lado de la salida es (n + 2p − k) ÷ s + 1, con la división redondeada hacia abajo.
Con k = 3, p = 1 y s = 1 la salida mide lo mismo que la entrada. Cada stride de 2 deja la cuarta parte de las posiciones, y con ellas, la cuarta parte de las MACs.
Prueba n = 5, k = 3, p = 1 y s = 1: la salida mide 5, como la entrada. Luego sube el stride a 2.
Pooling: resumir para achicar
La otra forma de achicar es el pooling. El más común, el max pooling de 2 × 2, parte el mapa en cuadritos de 2 × 2 y de cada uno se queda con el número más grande. Su tamaño sale de la misma fórmula, con k = 2, s = 2 y p = 0.
Hoy muchas redes achican con convoluciones de stride 2, porque así el achique también aprende. La ResNet-50 usa un solo max pooling, al principio; el resto lo hace con stride 2, y al final un pooling global promedia cada mapa entero en un número.
Por qué las CNNs sirven tan bien para fotos
Una red hecha de convoluciones, activaciones y pooling es una CNN (convolutional neural network, red neuronal convolucional). Les va bien a las fotos por tres razones:
- Mira de cerca. Cada filtro mira un pedacito, y en una foto el significado está en los píxeles vecinos: un borde, una textura, una agujeta.
- Usa el mismo filtro en todas partes. El filtro que encuentra una agujeta la encuentra en la esquina o en el centro. El tenis de Ana puede estar en cualquier lugar de la foto y no hay que aprenderlo una vez por cada lugar. Por eso tiene tan pocos parámetros.
- Arma lo complicado con lo simple. Las primeras capas encuentran bordes y manchas de color. Las de en medio combinan bordes en texturas y formas (una suela, una costura). Las últimas combinan partes en objetos (un tenis). Funciona porque cada capa ve un pedazo de la foto más grande que la anterior: su campo receptivo crece, como verás en la sección extra que sigue. Nadie programa esa jerarquía: sale del entrenamiento.
El campo receptivo: cuánto de la foto ve cada neurona
ExtraReceptive field: how much of the photo a neuron sees
Una neurona de la primera capa, con un filtro de 3 × 3, ve 3 × 3 píxeles. Una de la segunda ve 3 × 3 neuronas de la primera, cada una con su propio cuadro de 3 × 3; como se enciman, juntas cubren 5 × 5 píxeles. La de la tercera cubre 7 × 7. El pedazo de la foto que puede influir en una neurona es su campo receptivo (receptive field).
Con stride 1, cada capa de 3 × 3 le suma 2 píxeles al lado: 3, 5, 7, 9… Para ver 224 píxeles harían falta más de 100 capas. El stride lo acelera: después de una capa con stride 2, dos neuronas vecinas están separadas por 2 píxeles de la foto, así que un filtro de 3 × 3 en la capa siguiente abarca más terreno.
La cuenta, capa por capa, lleva dos números: el campo receptivo r y el salto j, cuántos píxeles de la foto hay entre dos neuronas vecinas de esa capa. Se empieza con r = 1 y j = 1 (un píxel se ve a sí mismo), y en cada capa con filtro k y stride s:
r nuevo = r + (k − 1) × j · j nuevo = j × s
Con tres capas de 3 × 3 y stride 1: r = 1 + 2 = 3, luego 3 + 2 = 5, luego 5 + 2 = 7, como en la figura. Si las tres tienen stride 2: 1 + 2 × 1 = 3 (salto 2), 3 + 2 × 2 = 7 (salto 4), 7 + 2 × 4 = 15 (salto 8).
Una pila de capas iguales, todas con el mismo filtro y el mismo stride. En cada capa, el campo crece (k − 1) × salto, y el salto se multiplica por el stride.
Con stride 1, cada capa de 3 × 3 suma apenas 2 píxeles. Con stride 2 en todas, 5 capas ya ven 63 píxeles y el último mapa de una foto de 224 mide 7: el mismo que el de la ResNet-50.
La calculadora usa el mismo filtro y el mismo stride en todas las capas. Las redes reales mezclan, pero la fórmula de arriba sirve igual, capa por capa.
En la ResNet-50 las capas son distintas. La primera es de 7 × 7. Después vienen 16 bloques, cada uno con dos convoluciones de 1 × 1 (que no suman nada, porque k − 1 = 0) y una de 3 × 3, repartidos en cuatro etapas; cada etapa a partir de la segunda empieza con stride 2:
Para ir más hondoEl campo que de verdad se usa+
Los 427 píxeles son un máximo teórico: dicen qué píxeles pueden influir. Los del centro pesan muchísimo más que los de la orilla, porque llegan a la neurona por muchos más caminos. Un estudio de 2016 (Luo y otros) lo midió: el campo «efectivo» es una mancha que se desvanece del centro hacia afuera y ocupa solo una parte del teórico. Que algo «quepa» en el campo receptivo no garantiza que la red lo note.
¿Para qué sirve en producción? Para dos preguntas de diseño: ¿la red alcanza a ver un objeto grande entero?, y ¿lo chico sobrevive? Con un salto de 32, dos números vecinos del último mapa están a 32 píxeles uno del otro: a cada uno le toca una celda de 32 × 32 píxeles, y un defecto de 3 píxeles es casi nada en ella. Lo verás con números en la inspección de C03.
La ResNet-50 por dentro: atajos, BatchNorm y model.eval()
EsencialInside ResNet-50: shortcuts, BatchNorm and model.eval()
Ya tienes todas las piezas: convoluciones, ReLU, stride y pooling. La ResNet-50 de C01 las junta así. Las dos franjas del diagrama son las dos partes de toda CNN que clasifica: el backbone, que convierte la foto en 2,048 números, y la cabeza, la última capa, que decide la categoría (las ves a fondo en la sección que sigue).
- Foto · 3 × 224 × 224
La foto de Ana, ya preprocesada: 3 canales (rojo, verde y azul) de 224 × 224 píxeles, 150,528 números. Está aquí porque es lo único que el modelo sabe leer: números, no imágenes. - Primera capa · conv 7 × 7
Una convolución con 64 filtros de 7 × 7 y stride 2 deja la foto en 112 × 112, y un max pooling la baja a 56 × 56: 64 mapas que ya no son colores, son respuestas a filtros. Está aquí para achicar pronto la foto y que lo que sigue cueste menos: solo hace el 2.9 % de las cuentas. - 16 bloques · residuales
Casi todo vive aquí: ≈ 23.5 millones de parámetros y ≈ 97 % de las multiplicaciones-sumas. Cuatro etapas de 3, 4, 6 y 3 bloques, cada uno con su atajo (resnet). Los mapas se achican (56 → 28 → 14 → 7 de lado) mientras los canales crecen (256 → 512 → 1,024 → 2,048). Aquí la red combina bordes en texturas y texturas en partes: es lo que sabe «ver». - Pooling global · un promedio por mapa
Cada uno de los 2,048 mapas de 7 × 7 se promedia en un solo número. Ya no importa dónde estaba algo en la foto, solo qué tanto hay. Está aquí para que la cabeza reciba siempre una lista fija de 2,048 números, sin importar el tamaño de la foto. - Features · 2,048 números
Lo que el backbone entrega: una descripción de la foto en 2,048 números. Es la frontera entre lo que se aprendió con ImageNet y lo nuevo de C01. Fotos parecidas dan listas parecidas; por eso también sirven como embedding. - Cabeza · 2,048 → 500
Una sola capa densa: 2,048 × 500 pesos + 500 sesgos = 1,024,500 parámetros, el 4.2 % del modelo, pero solo el 0.025 % de las cuentas. Está aquí porque es la única parte que sabe de las categorías de C01: es la que se cambia con transfer learning (la original de ImageNet sacaba 1,000). - Softmax · → probabilidades
Convierte los 500 logits en probabilidades que suman 100 % (el softmax). No tiene parámetros. Está aquí para que los números se puedan ordenar y leer como «qué tan seguro está». - Top-5 · Tenis 94 % …
Se ordenan las 500 probabilidades y se le muestran a Ana las 5 más altas. Está aquí porque la app muestra 5 sugerencias: si la correcta está entre ellas, funcionó (top-5).
El atajo que permitió ir profundo
Durante años, apilar más capas parecía la forma obvia de mejorar. Pero a partir de cierta profundidad, una red más profunda acertaba menos, incluso en las fotos de entrenamiento. No era overfitting (que empeora la validación, no el entrenamiento): la red más profunda simplemente era más difícil de entrenar.
En 2015, Kaiming He y sus colegas de Microsoft Research propusieron una solución sencilla, la ResNet (residual network, red residual). Cada grupo de capas, un bloque, tiene un atajo, la conexión residual (skip connection): la entrada del bloque se le suma a su salida.
salida = bloque(x) + x
¿Por qué ayuda tanto? Dos intuiciones:
- Cada bloque solo aprende una corrección. No tiene que reconstruir todo lo que ya traía la entrada, solo lo que hay que agregarle. Si un bloque no sirve, le basta aprender a sacar casi 0, y la entrada pasa por el atajo sin daño. Agregar bloques ya no puede empeorar tanto las cosas.
- El aprendizaje llega hasta abajo. Al entrenar, la corrección del error viaja de la última capa hacia la primera (es la backpropagation). Con 50 capas apiladas, esa señal se debilita en el camino; los atajos le dan una vía directa.
Con esa idea, el equipo entrenó en ImageNet redes de hasta 152 capas y ganó la competencia de 2015.
La ResNet-50, en números
| Qué | Cuánto |
|---|---|
| Capas con pesos | 50 en el camino principal: 49 convolucionales y la densa del final |
| Bloques residuales | 16, en cuatro etapas de 3, 4, 6 y 3 bloques |
| Entrada | Una foto de 3 × 224 × 224; con el batch al frente, el tensor [1, 3, 224, 224] |
| Salida del backbone | 2,048 números |
| Parámetros, versión original (1,000 categorías de ImageNet) | ≈ 25.6 millones |
| Parámetros en C01 (500 categorías) | ≈ 24.5 millones |
| Pesos de la versión original en memoria | ≈ 102 MB en float32 · ≈ 51 MB en float16 (2 bytes por número) |
| Cuentas por foto | ≈ 4,100 millones de MACs (4.1 GMACs) |
| Campo receptivo de un número del último mapa | 427 × 427 píxeles (teórico) |
BatchNorm
Hay dos tipos de capa que se portan distinto al entrenar y al responder. Si se te olvida decirle a la red en qué momento está, en producción da respuestas raras sin ningún error: uno de los bugs más clásicos de llevar un modelo a producción.
La primera vive dentro de cada bloque de la ResNet. Los números pueden crecer o achicarse mucho de capa en capa, y eso hace difícil entrenar. La BatchNorm (batch normalization, Ioffe y Szegedy, 2015) los acomoda: en cada canal les resta su promedio y los divide entre su desviación estándar, para que queden alrededor de 0 con una dispersión de más o menos 1. Después los escala y los mueve con dos parámetros propios, que también se entrenan.
La pregunta clave es: ¿el promedio de qué?
- Al entrenar, el de las fotos del batch actual. Y de paso va guardando, a lo largo de todo el entrenamiento, un promedio de esos promedios y de esas desviaciones (un promedio móvil, que pesa más los batches recientes): sus running stats (estadísticas acumuladas).
- Al responder, debe usar esas estadísticas acumuladas, que ya no cambian.
Dropout
El dropout (Srivastava, Hinton y otros, 2014) es una traba contra el overfitting. Al entrenar, en cada paso apaga al azar una fracción de las neuronas, por ejemplo la mitad, y multiplica las que quedan para compensar (con la mitad apagada, por 2). Así la red no puede depender de unas pocas neuronas que memorizaron algo: tiene que repartir lo que sabe. Al responder no apaga nada.
Si se queda en modo entrenamiento en producción, cada request apaga neuronas distintas: la misma foto, enviada dos veces, da dos respuestas diferentes.
El interruptor: model.eval()
En PyTorch, un modelo tiene un interruptor con dos posiciones: model.train() y model.eval(). En modo eval, la BatchNorm usa sus estadísticas acumuladas y el Dropout no apaga nada. Un modelo recién creado o cargado está en modo train, así que el servidor lo cambia una vez, al arrancar (ilustración: necesita PyTorch y un archivo de pesos):
import torch
from torchvision.models import resnet50
model = resnet50(num_classes=500)
model.load_state_dict(torch.load("pesos.pt", weights_only=True))
model.eval() # BatchNorm y Dropout en modo inferencia
with torch.inference_mode(): # y además: no guardes nada para aprender
logits = model(x)Lo traicionero de este bug es que nada truena: no hay error, la respuesta tiene el formato correcto y en tu notebook la accuracy se veía bien (porque ahí sí llamaste a model.eval()). Solo baja la calidad, en silencio. Por eso la Ronda insiste en la prueba de paridad: comparar, foto por foto, las respuestas del modelo que se sirve contra las del modelo que se evaluó.
Backbone, cabeza y transfer learning
EsencialBackbone, head and transfer learning
Una CNN que clasifica tiene dos partes:
- El backbone («columna vertebral»): todas las capas convolucionales. Recibe la foto y la convierte en una lista de números que describen lo que hay en ella, sus features. Al final del backbone de la ResNet-50, un pooling global promedia cada uno de sus 2,048 mapas de 7 × 7 en un solo número: salen 2,048 números por foto.
- La cabeza (head): lo que convierte esas features en la respuesta de la tarea. En C01 es una sola capa densa que da un logit por categoría: 500 logits. Luego el softmax los vuelve probabilidades y se toman las 5 más altas.
Separarlo así sirve mucho en producción. El backbone es lo caro y lo que sabe «ver»; la cabeza es chica y es la que sabe de tus categorías. Además, esos 2,048 números sirven solos: fotos parecidas dan listas parecidas, útiles para buscar productos similares. Una lista así, donde lo parecido queda cerca, es un embedding, el tema de la siguiente lección.
¿De dónde sale la diferencia entre los 25.6 millones de parámetros de la ResNet-50 original y los 24.5 de la de C01? Solo de la cabeza. Con 1,000 categorías: 2,048 × 1,000 + 1,000 = 2,049,000. Con 500: 2,048 × 500 + 500 = 1,024,500. La diferencia es 1,024,500: 25,557,032 − 1,024,500 = 24,532,532. El backbone, que es casi todo, es idéntico.
Transfer learning y fine-tuning
Entrenar una ResNet-50 desde cero pide muchísimas fotos etiquetadas y mucho tiempo de GPU. Pero hay un atajo: alguien ya la entrenó. ImageNet es un dataset público de fotos etiquetadas; su versión más usada tiene ≈ 1.28 millones de fotos de entrenamiento en 1,000 categorías (perros, coches, frutas, instrumentos…). Un modelo entrenado con ImageNet ya aprendió en su backbone lo que sirve para casi cualquier foto: bordes, texturas, formas, partes de objetos. Y esos pesos se pueden descargar.
Usar lo que un modelo aprendió en una tarea para resolver otra se llama transfer learning (aprendizaje por transferencia). En C01 se hace así:
- 1
Partir de un modelo preentrenado
Se carga la ResNet-50 con los pesos de ImageNet. Su backbone ya sabe «ver».
- 2
Cambiar la cabeza
La cabeza original saca 1,000 logits, uno por cada categoría de ImageNet, que no son las del marketplace. Se quita y se pone una nueva de 2,048 → 500, con pesos al azar.
- 3
Seguir entrenando con las fotos propias
Se entrena con las fotos de C01, con un learning rate chico para no destruir lo que el backbone ya sabía. Eso es el fine-tuning (ajuste fino). En la Ronda, el de C01 usa un learning rate de 0.0003, 8 épocas y batches de 64 fotos, y cabe en una sola GPU en unas horas.
En código, los dos primeros pasos son dos líneas (otra ilustración que necesita PyTorch):
import torch
from torchvision.models import resnet50, ResNet50_Weights
model = resnet50(weights=ResNet50_Weights.IMAGENET1K_V2) # backbone que ya vio ImageNet
model.fc = torch.nn.Linear(2048, 500) # cabeza nueva: 500 categoríasEl fine-tuning se puede hacer de dos formas, y se pueden combinar: congelar el backbone (no mover sus pesos) y entrenar solo la cabeza, que es rápido y sirve con pocos datos; o entrenar todo con learning rate chico, que es más lento y suele dar mejor resultado cuando hay muchas fotos, como en C01. Congelado, el entrenamiento solo mueve 1,024,500 de los 24,532,532 parámetros: el 4.2 %.
¿Por qué C01 empieza así? Porque con un modelo preentrenado hacen falta muchas menos fotos y horas de GPU para llegar a una buena top-5. Y como C01 se reentrena cada mes, cada reentrenamiento parte de pesos que ya saben ver.
Vision Transformers: la foto como una frase de parches
ExtraVision Transformers: the photo as a sentence of patches
Las CNNs no son la única forma de ver fotos. En 2020, un equipo de Google (Dosovitskiy y otros) tomó el transformer, la arquitectura de los LLMs (los modelos de lenguaje de los chats), y le dio una foto como si fuera una frase. Lo llamaron ViT (Vision Transformer).
Un transformer recibe una lista de tokens (en un LLM, pedazos de texto: palabras o partes de palabras), cada uno convertido en un vector (una lista de números). El ViT parte la foto en cuadritos de 16 × 16 píxeles, los parches (patches), y cada parche se vuelve un token.
Después, el ViT es un transformer como el de los LLMs: 12 bloques, cada uno con atención (cada parche mira a todos los demás y decide cuáles le importan; la ves en la lección de transformers y LLMs) y con un MLP de dos capas que procesa cada token por separado. Dos detalles:
- La posición se suma aparte. Al convertir los parches en una lista, se pierde dónde estaba cada uno. Por eso a cada token se le suma un vector aprendido que dice «soy el parche 37»: un embedding posicional.
- La respuesta sale del token [CLS]. Al final, una cabeza densa convierte su vector de 768 números en los logits, como la de la ResNet.
| ResNet-50 | ViT-B/16 | |
|---|---|---|
| Parámetros | ≈ 25.6 millones | ≈ 86 millones |
| MACs por foto de 224 × 224 | ≈ 4,100 millones | ≈ 17,600 millones |
| Qué mira al principio | cada filtro de la primera capa, 7 × 7 píxeles | cada parche, de 16 × 16; desde el primer bloque, todos los parches a la vez |
| Lo que trae de fábrica | ver de cerca y el mismo filtro en todas partes | casi nada: lo tiene que aprender |
| Cuántas fotos necesita | le basta ImageNet | brilla con preentrenamientos de decenas o cientos de millones de fotos |
La CNN trae dos ideas metidas en su diseño; el ViT tiene que aprenderlas de los datos. Con pocos datos eso es una desventaja: en el artículo original, entrenado solo con ImageNet, el ViT quedaba unos puntos por debajo de una ResNet de tamaño parecido; preentrenado con muchísimas más fotos (14 millones en un caso, 300 millones en otro), la superaba.
¿Y para C01? La Ronda, en M04, cuenta el ViT-B/16 entre los modelos que hay que saber medir: ≈ 172 MB en float16. Para sugerir 500 categorías a ≈ 2.5 millones de publicaciones al día, la ResNet-50 sigue siendo una elección sólida, con 3.5 veces menos parámetros y unas 4 veces menos cuentas por foto. Donde los ViT dominan es en los modelos que ponen fotos y textos en el mismo espacio (multimodales), que verás en la lección de embeddings.
Errores comunes
EsencialCommon mistakes
1. Olvidar model.eval() en el servidor
La BatchNorm normaliza con las estadísticas del batch y el Dropout, si lo hay, apaga neuronas al azar. La misma foto da respuestas distintas según con qué otras llegó, y nada truena.
Cómo evitarlo: que la función que carga el modelo termine en model.eval(), una prueba que revise que model.training sea False y la prueba de paridad de la Ronda (M08).
2. Una normalización distinta a la del entrenamiento
Si en el servidor olvidas dividir entre 255, el rojo de un píxel que vale 236 entra como (236 − 0.485) ÷ 0.229 ≈ 1,028 en vez de (0.925 − 0.485) ÷ 0.229 ≈ 1.92. Si cargas la foto en orden azul-verde-rojo (BGR), los canales se cruzan. El modelo no truena: ve una foto «rara» y se equivoca más, en silencio.
Cómo evitarlo: el mismo código de preprocesamiento al entrenar y al servir (lo contrario es el training-serving skew) y una prueba que compare, número por número, el tensor del servidor con el de la evaluación.
3. Confundir el padding y el redondeo
«Padding 1 deja el mapa igual» solo es cierto con filtro de 3 × 3 y stride 1. Y con stride 2 la salida no siempre es la mitad exacta: una entrada de 56 sale de 28, pero una de 57 sale de (57 + 2 − 3) ÷ 2 + 1 = 29, no de 28.5. Un error de uno en el tamaño basta para que dos ramas que se suman (como el atajo de una ResNet) no cuadren.
Cómo evitarlo: hacer la cuenta con la fórmula antes de escribir la capa y, en código, pasar un tensor de prueba e imprimir su forma (shape) después de cada capa.
4. Contar mal los parámetros
Los resbalones típicos: olvidar los canales de entrada (un filtro de 3 × 3 sobre 64 canales tiene 576 pesos, no 9); poner sesgos donde no hay (las convoluciones de la ResNet no llevan); contar como parámetros las estadísticas acumuladas de la BatchNorm (se guardan con el modelo, pero el gradiente no las ajusta); o confundir parámetros (memoria) con MACs (cálculo).
Cómo evitarlo: contar con las fórmulas y compararlo con lo que dice PyTorch, sum(p.numel() for p in model.parameters()). Para la ResNet-50 debe dar 25,557,032, o 24,532,532 con 500 categorías.
5. Cargar pesos con la cabeza equivocada
Los pesos de un modelo de 1,000 categorías no caben en uno de 500: PyTorch truena con un error de size mismatch en la capa final. Para quitárselo de encima, lo común es borrar la capa final de los pesos guardados y cargar el resto con strict=False, que deja pasar sin avisar las capas cuyos nombres no coinciden (un tamaño distinto sigue tronando). El peligro es que no avisa: si los nombres no coinciden (por ejemplo, porque al guardar se les pegó el prefijo module.), el modelo se queda con sus pesos al azar y responde basura sin un solo error.
Cómo evitarlo: crear el modelo con el número correcto de categorías antes de cargar; si usas strict=False, revisar la lista de capas que no se cargaron, que devuelve la misma función; y evaluar con el golden set después de cargar.
6. Achicar la foto y perder lo chico
El resize del preprocesamiento es parte del modelo, aunque viva en otro archivo. Si un defecto mide 3 píxeles y achicas la foto a menos de la mitad, ya no está cuando la red la ve, y ninguna capa lo recupera.
Cómo evitarlo: antes de elegir el tamaño de entrada, calcula cuántos píxeles mide lo más chico que hay que ver. Si son pocos, no achiques: corta la imagen en tiles (cuadros que la red procesa por separado) a resolución completa.
En la vida real
ExtraIn real life
Un backbone, tres cabezas
El backbone no sabe de categorías: solo describe la foto. Por eso sirve para tareas distintas, cambiando solo la cabeza:
- Clasificación (C01): promedia cada mapa en un número y una capa densa da un logit por categoría. Ya no importa dónde estaba algo, solo qué tanto hay.
- Detección (C02): no puede promediar, porque necesita saber dónde. Su cabeza mira cada posición de los mapas y propone ahí una caja (4 números: dónde está y de qué tamaño) con un puntaje por clase.
- Segmentación (C04): quiere una respuesta por píxel, así que su cabeza es un decoder, una red que agranda los mapas de regreso al tamaño de la foto. A la parte que achica, el backbone, en este contexto se le dice encoder.
- Foto · ya preprocesada
La imagen ya convertida en tensor: 224 × 224 en C01, 640 × 640 en el detector de C02, tiles de 512 × 512 en C04. Las convoluciones aceptan tamaños distintos, así que el tipo de backbone puede ser el mismo. - Backbone · convoluciones
Todas las capas convolucionales, casi siempre preentrenadas con ImageNet. Es lo caro: en la ResNet-50, el 99.97 % de las MACs. Es la parte que se reutiliza de una tarea a otra (transfer learning). - Mapas · las features
Lo que entrega el backbone: mapas de activaciones. En C01, 2,048 mapas de 7 × 7. Detección y segmentación toman también mapas de capas anteriores, más grandes, porque necesitan saber dónde está cada cosa. - Clasificación · pooling + densa
Promedia cada mapa en un número (2,048) y una capa densa da un logit por categoría: 2,048 × 500 + 500 = 1,024,500 parámetros. Promediar borra el dónde: aquí solo importa el qué. - Detección · una caja por posición
En cada posición de los mapas propone una caja (4 números: dónde está y de qué tamaño) y un puntaje por clase. Un detector como YOLOv8 a 640 × 640 lo hace en 80 × 80 + 40 × 40 + 20 × 20 = 8,400 posiciones. - Segmentación · decoder que agranda
Un decoder agranda los mapas de regreso al tamaño de la entrada y da una respuesta por píxel. Como en la U-Net, recibe atajos desde el backbone (ahí llamado encoder) para no perder los bordes finos. - Top-5 · C01 · 500 categorías
El softmax vuelve los 500 logits probabilidades y Ana ve las 5 más altas (top-5). - Cajas · C02 · tras el NMS
Casi todas las candidatas se tiran por puntaje bajo, y varias marcan el mismo objeto. El NMS (non-maximum suppression) deja la de puntaje más alto y borra las que se enciman mucho con ella. Quedan unas cuantas cajas, cada una con su clase. - Máscara · C04 · una por píxel
Una probabilidad por píxel: en un tile de 512 × 512 son 262,144 respuestas. En C04, la probabilidad de que cada píxel sea tumor.
C01: la línea del caso, leída
El caso C01 resume su modelo en una frase: «ResNet-50 con una capa final de 500 clases: 24.5 M parámetros (…) y ≈ 4.1 GMACs a 224×224». Ya sabes leerla: memoria, cálculo, cabeza y preprocesamiento.
La ResNet-50 se arma con 16 bloques (grupos de tres convoluciones) repartidos en cuatro etapas. Dentro de una etapa los mapas no cambian de tamaño, y a partir de la segunda, cada etapa los achica a la mitad de lado. Con la fórmula del lado de salida se puede contar la red capa por capa. En Python, la primera capa, el max pooling y una convolución de 3 × 3 de cada etapa:
def lado(n, k, s, p):
return (n + 2 * p - k) // s + 1 # // divide y redondea hacia abajo
def conv(nombre, n, c_in, c_out, k, s, p):
m = lado(n, k, s, p)
params = k * k * c_in * c_out # sin sesgo, como en la ResNet
macs = m * m * c_out * k * k * c_in # posiciones × filtros × pesos por filtro
print(f"{nombre:<24}{n:>4} -> {m:<4}{params:>12,}{macs:>15,}")
print(f"{'capa':<24}{'lado':>4}{'':8}{'parámetros':>12}{'MACs':>15}")
conv("primera, 7x7 stride 2", 224, 3, 64, 7, 2, 3)
print(f"{'max pooling 3x3 s2':<24}{112:>4} -> {lado(112, 3, 2, 1)}")
conv("3x3 de la etapa 1", 56, 64, 64, 3, 1, 1)
conv("3x3 de la etapa 2", 28, 128, 128, 3, 1, 1)
conv("3x3 de la etapa 3", 14, 256, 256, 3, 1, 1)
conv("3x3 de la etapa 4", 7, 512, 512, 3, 1, 1)capa lado parámetros MACs
primera, 7x7 stride 2 224 -> 112 9,408 118,013,952
max pooling 3x3 s2 112 -> 56
3x3 de la etapa 1 56 -> 56 36,864 115,605,504
3x3 de la etapa 2 28 -> 28 147,456 115,605,504
3x3 de la etapa 3 14 -> 14 589,824 115,605,504
3x3 de la etapa 4 7 -> 7 2,359,296 115,605,504Fíjate en las últimas cuatro filas. Cada vez que la ResNet achica el mapa a la mitad de lado, duplica los canales: las posiciones bajan 4 veces y los filtros y los pesos por filtro suben 2 veces cada uno. Las MACs quedan idénticas, pero los parámetros se multiplican por 4 en cada etapa: el trabajo se reparte parejo y los parámetros se amontonan al final.
¿Dónde viven los parámetros y dónde el trabajo? Contando capa por capa toda la ResNet-50 de C01, con su capa final de 500:
| Parte | Mapa que sale | Parámetros | MACs por foto |
|---|---|---|---|
| Primera capa y max pooling | 64 × 56 × 56 | 9,536 (< 0.1 %) | 118 millones (2.9 %) |
| Etapa 1 · 3 bloques | 256 × 56 × 56 | 0.2 millones (0.9 %) | 668 millones (16.3 %) |
| Etapa 2 · 4 bloques | 512 × 28 × 28 | 1.2 millones (5.0 %) | 1,028 millones (25.1 %) |
| Etapa 3 · 6 bloques | 1,024 × 14 × 14 | 7.1 millones (28.9 %) | 1,464 millones (35.8 %) |
| Etapa 4 · 3 bloques | 2,048 × 7 × 7 | 15.0 millones (61.0 %) | 809 millones (19.8 %) |
| Capa final (500) | 500 | 1.0 millones (4.2 %) | 1 millón (0.025 %) |
| Total | 24.5 millones | ≈ 4,088 millones |
La etapa 4 guarda el 61 % de los parámetros, pero hace menos de una quinta parte del trabajo; la etapa 1, al revés, casi no tiene parámetros y hace el 16 % del trabajo, porque sus mapas son grandes. Para la memoria (M04) mandan las últimas etapas; el cálculo (M03) se reparte entre todas.
Y el cálculo cabe de sobra en una GPU. Cada MAC son dos operaciones, así que una foto son 8.2 GFLOPs (FLOPs: operaciones con números decimales). La Ronda, en M03, lo usa como chequeo de cordura: una GPU T4 hace a lo mucho ≈ 65 × 10¹² operaciones por segundo en float16, así que nunca pasará de 65 × 10¹² ÷ 8.2 × 10⁹ ≈ 7,900 fotos por segundo. Lo que se mide de verdad es mucho menos (la Ronda supone ≈ 1,200 fotos por segundo para C01): el techo dice qué es imposible, no qué vas a obtener.
El presupuesto de C01 es un p99 ≤ 200 ms del lado del servidor: 99 de cada 100 respuestas en menos de 200 ms. La Ronda estima ≈ 3–6 ms de cómputo en la GPU T4 (la mediana, con batches de 1 a 8 fotos), así que el modelo es una parte chica de ese tiempo. Si el servicio no contesta en 300 ms, la app le muestra a Ana el selector manual de categorías.
C02: detectar en video, una caja por posición
C02 vigila zonas restringidas con 1,000 cámaras en 25 centros de distribución, con un detector ligero tipo YOLO (≈ 10–30 millones de parámetros) que recibe cada frame a 640 × 640 y busca personas y vehículos.
Su cabeza no promedia, porque necesita saber dónde. En detectores como YOLOv8 mira tres mapas, con saltos de 8, 16 y 32 píxeles: a 640 son 80 × 80 + 40 × 40 + 20 × 20 = 8,400 posiciones, y en cada una propone una caja y un puntaje por clase. Las de puntaje bajo se tiran, y de las que marcan el mismo objeto, el NMS (non-maximum suppression) deja la de puntaje más alto y borra las que se enciman mucho con ella (lo mide el IoU).
¿Por qué tres tamaños? Por el campo receptivo: el mapa de salto 8 tiene celdas chicas, buenas para una persona lejana; el de salto 32, un campo enorme para un camión que llena el cuadro. Y como 640 × 640 son 8.2 veces los píxeles de 224 × 224, la Ronda (M04) nota que en detección lo que más crece con la resolución son las activaciones.
C03: inspección en la línea, defectos de 3 píxeles
C03 revisa soportes metálicos en una planta de autopartes de Nuevo León, con una cámara de 2,448 × 2,048 píxeles por línea, y tiene que encontrar fisuras de 0.2 mm. Aquí manda la aritmética de esta lección:
Por eso la Ronda no achica la imagen: la procesa en 20 tiles, como un batch de tamaño fijo. Si 3 píxeles resultan pocos, la solución es óptica (un campo de visión más chico o más resolución), no un modelo más grande. Y para que lo chico no se diluya, muchos métodos de inspección usan mapas de salto 8 o 16 y califican cada posición: la pieza es mala si alguna posición es mala (el máximo, no el promedio).
C03 usa también la otra idea de esta lección: un solo engine (el modelo ya convertido para la GPU) con un backbone compartido y dos cabezas, una con un puntaje de anomalía y otra con un puntaje por tipo de defecto. Dos backbones casi duplicarían el tiempo, y la inferencia tiene que caber en ≤ 120 ms en el Jetson, la computadora con GPU que va junto a cada línea.
C04: segmentación, un decoder que agranda
C04 marca tumor en laminillas de patología escaneadas a tan alta resolución que se procesan en tiles de 512 × 512. Un modelo tipo U-Net, de ≈ 30 millones de parámetros, da para cada píxel la probabilidad de que sea tumor: 512 × 512 = 262,144 respuestas por tile, en vez de 500 por foto.
La U-Net (Ronneberger y otros, 2015) se diseñó para imágenes médicas. Es un encoder-decoder: el encoder es un backbone que achica el mapa (por ejemplo, 512 → 256 → 128 → 64 → 32 de lado) y el decoder hace el camino de regreso. El mapa de 32 × 32 sabe qué hay, pero ya no dónde están los bordes; por eso, en cada tamaño, el decoder recibe por un atajo largo el mapa del encoder de ese tamaño, que los conserva. Dibujada, parece una U.
Los tiles avanzan de 448 en 448 píxeles (un stride, otra vez), así que se enciman 64: cerca de la orilla de un tile la red ve ceros de padding en vez de tejido, y el solape evita depender de esas orillas.
Fuera de ML: los filtros de tu editor de fotos
El «desenfocar» más simple de un editor de fotos es una convolución con un filtro de 3 × 3 cuyos 9 pesos valen 1/9: cada píxel se vuelve el promedio de sus vecinos. «Enfocar» usa un 5 en el centro y −1 arriba, abajo y a los lados. Y el detector de bordes del ejemplo (columnas de 1, 0 y −1) es el filtro de Prewitt, de los años 70. La diferencia con una CNN es quién elige los pesos: ahí una persona; en la red, el entrenamiento.
Ejercicios
EsencialExercises
Resuélvelos con lápiz antes de abrir la solución; los de tamaños y parámetros se pueden comprobar con las calculadoras.
- 1Fácil
Una neurona tiene entradas 1, 2 y 3, pesos 0.5, −1 y 1, y sesgo 0.5. ¿Qué sale después de la ReLU? ¿Y si el sesgo fuera −3?
Ver la solución paso a paso
- Productos: 1 × 0.5 = 0.5, 2 × (−1) = −2 y 3 × 1 = 3.
- Suma con el sesgo: 0.5 − 2 + 3 + 0.5 = 2. No es negativo: la ReLU deja salir 2.
- Con sesgo −3: 0.5 − 2 + 3 − 3 = −1.5, negativo: sale 0. El sesgo decide qué tan fácil se activa la neurona.
- 2Fácil
Un MLP para dígitos de 28 × 28 en gris tiene 784 entradas, una capa oculta de 128 neuronas y 10 salidas. ¿Cuántos parámetros tiene y cuántas MACs hace por imagen?
Ver la solución paso a paso
- Capa oculta: 784 × 128 + 128 = 100,352 + 128 = 100,480.
- Capa de salida: 128 × 10 + 10 = 1,290.
- Parámetros: 100,480 + 1,290 = 101,770.
- MACs: una por peso, 784 × 128 + 128 × 10 = 100,352 + 1,280 = 101,632 por imagen.
- 3Fácil
Una entrada de 32 × 32 pasa por una convolución de 5 × 5 sin padding y con stride 1. ¿De qué tamaño sale? ¿Qué padding necesitas para que salga de 32 × 32?
Ver la solución paso a paso
- Sin padding: (32 + 0 − 5) ÷ 1 + 1 = 28, como en la primera capa de LeNet-5, la CNN de dígitos de 1998.
- Para 32: (32 + 2p − 5) + 1 = 32, así que 2p = 4 y p = 2: la regla (k − 1) ÷ 2.
- 4Fácil
Un max pooling de 2 × 2 con stride 2 recibe 256 mapas de 56 × 56. ¿Qué sale y cuántos parámetros tiene?
Ver la solución paso a paso
- Lado: (56 + 0 − 2) ÷ 2 + 1 = 28. Salen 256 mapas de 28 × 28: el pooling actúa en cada mapa por separado y no cambia la cantidad de canales.
- Números: de 802,816 a 200,704, cuatro veces menos.
- Parámetros: 0. Solo toma el máximo.
- 5Medio
Una convolución de 3 × 3 recibe 64 canales, tiene 128 filtros, no lleva sesgo y su salida es de 28 × 28. ¿Cuántos parámetros tiene, cuántas MACs hace y cuántas veces se usa cada peso?
Ver la solución paso a paso
- Pesos por filtro: 3 × 3 × 64 = 576. Parámetros: 576 × 128 = 73,728.
- MACs: 28 × 28 posiciones × 128 filtros × 576 = 784 × 128 × 576 = 57,802,752, unos 58 millones.
- Cada peso se usa una vez por posición: 784 veces, y por eso hay 784 veces más MACs que parámetros.
- 6Medio
Alguien olvida el center crop y le pasa a la ResNet-50 fotos de 256 × 256. ¿De qué tamaño sale la primera capa (7 × 7, padding 3, stride 2) y después el max pooling (3 × 3, padding 1, stride 2)? ¿De qué tamaño queda el último mapa? ¿Truena el modelo?
Ver la solución paso a paso
- Primera capa: (256 + 6 − 7) ÷ 2 = 127.5, que baja a 127; más 1: 128.
- Max pooling: (128 + 2 − 3) ÷ 2 = 63.5, que baja a 63; más 1: 64.
- Último mapa: con salto 32, 256 ÷ 32 = 8: mapas de 8 × 8 en vez de 7 × 7.
- No truena: el pooling global promedia cada mapa, sea de 7 × 7 o de 8 × 8, y la cabeza recibe siempre 2,048 números. Por eso es peligroso: la respuesta cambia un poco y nada avisa, un caso de training-serving skew.
- 7Medio
(Usa la sección extra del campo receptivo.) Cuatro capas de 3 × 3: la segunda tiene stride 2 y las demás stride 1. ¿Cuál es el campo receptivo de una neurona de la cuarta capa? ¿Y si las cuatro tuvieran stride 1?
Ver la solución paso a paso
- Empieza con r = 1 y j = 1. Capa 1 (k = 3, s = 1): r = 1 + 2 × 1 = 3, j = 1.
- Capa 2 (s = 2): r = 3 + 2 × 1 = 5, y el salto pasa a j = 2.
- Capa 3: r = 5 + 2 × 2 = 9. Capa 4: r = 9 + 2 × 2 = 13.
- Todas con stride 1: 1 + 4 × 2 = 9. El stride de en medio le ganó 4 píxeles al campo.
- 8Reto
(Usa el salto de la sección extra del campo receptivo y el caso C03.) Una cámara de inspección cubre 300 mm con 2,448 píxeles y hay que ver defectos de 0.3 mm. (a) ¿Cuántos píxeles mide un defecto? (b) Si la red recibe tiles de 512 y su backbone tiene salto 32, ¿qué fracción del ancho de una celda del último mapa ocupa el defecto? (c) ¿Qué cambiarías para verlo mejor?
Ver la solución paso a paso
- (a) 300 ÷ 2,448 ≈ 0.1225 mm por píxel, así que 0.3 ÷ 0.1225 ≈ 2.45 píxeles. Menos que la fisura de C03.
- (b) 2.45 ÷ 32 ≈ 7.7 % del ancho de una celda de 32 × 32. Y el tile de 512 tiene 16 × 16 = 256 celdas.
- (c) Primero la óptica: un campo de visión más chico (por ejemplo, dos cámaras de 150 mm) duplica los píxeles por defecto. Después, no achicar la imagen; usar mapas de salto 8, donde el defecto ocupa ≈ 31 % del ancho de una celda; y calificar cada posición y tomar el máximo en vez de promediar.
- 9Reto
La capa final de la ResNet-50 de C01 guarda ≈ 4 % de los parámetros pero hace ≈ 0.025 % de las MACs; la primera capa tiene 9,408 parámetros pero hace 118 millones de MACs. Explica las dos cosas con números: ¿cuántas veces se usa cada peso en cada capa?
Ver la solución paso a paso
- Capa final, densa: cada peso se usa una vez por foto, así que sus MACs (1,024,000) son casi sus parámetros (1,024,500); contra ≈ 4,100 millones del modelo, son ≈ 0.025 %.
- Primera capa, convolucional: cada peso se usa en cada posición de la salida, 112 × 112 = 12,544 veces; 9,408 × 12,544 = 118,013,952 MACs.
- La conclusión: los parámetros dicen cuánta memoria pide un modelo y las MACs cuánto cálculo. En una CNN no van de la mano, porque cada peso se reutiliza miles de veces.
Lo que sigue
EsencialWhat comes next
En la Ronda:
- M03 · Latencia y capacidad hace el chequeo de cordura de esta lección: 8.2 GFLOPs por foto contra ≈ 65 TFLOPS de una T4, un techo de ≈ 7,900 fotos por segundo.
- M04 · Hardware para inferencia arranca con la cuenta de los parámetros: 25.6 M × 4 bytes ≈ 102 MB en float32 (la Ronda le dice FP32) y ≈ 51 MB en float16 (FP16); para C01, ≈ 49 MB en float16. Ahí verás también por qué una CNN suele estar limitada por el cálculo, y cuánto pesan YOLOv8m (≈ 25.9 M parámetros) y ViT-B/16 (≈ 86 M).
- M07 · Servidores de modelos carga el modelo una vez al arrancar, con
model.eval()ytorch.inference_mode(): sin lo primero, la BatchNorm usa las estadísticas del batch. - M08 · Optimización muestra que algunas herramientas que capturan el modelo para acelerarlo (
torch.export,torch.compile) conservan la BatchNorm en modo train si olvidasteeval(), mientras que la exportación a ONNX (un formato estándar para guardar el modelo y correrlo fuera de PyTorch) te protege; y que al convertir el modelo a un formato rápido la BatchNorm se «pliega» dentro de la convolución anterior. - Los casos. C01 da el modelo por hecho («ResNet-50 con una capa final de 500 clases»); C02 usa un detector a 640 × 640 con NMS; C03, 20 tiles con un backbone y dos cabezas; C04, una U-Net sobre tiles que se enciman. Ahora sabes qué quiere decir cada palabra.
En el Dojo: la estación 7, Empaquetado, usa la cuenta de esta lección, 25.6 M parámetros × 2 bytes ≈ 51 MB, para decidir que el modelo puede ir dentro del paquete del servidor (la imagen de Docker). Cuando abran las estaciones 3 (Entrenamiento) y 5 (Export, engine y paridad), ahí vas a practicar el fine-tuning y la prueba de paridad con model.eval().
En Sensei: la siguiente lección, «Embeddings: el significado como coordenadas», usa los 2,048 números del backbone. «Transformers y LLMs» explica la atención que usa el ViT. Más adelante, «Cómo guarda números una computadora» explica float32 y float16, y «Matrices, FLOPs y qué tan rápido calcula una GPU» convierte las MACs de esta lección en milisegundos.
Palabras que vas a oír
EsencialWords you will hear
Estos son los conceptos que presentó esta lección. Cada uno tiene su tarjeta con la definición completa.
Neuronaneuron · unitLa pieza más chica de una red neuronal: multiplica cada entrada por un peso, suma todo más un sesgo y pasa el resultado por una activación.Más +
Sus pesos y su sesgo son parámetros: los ajusta el entrenamiento. Una neurona con 3 entradas tiene 4 parámetros. Se juntan muchas en una capa. El nombre viene de las neuronas del cerebro, pero es solo una multiplicación y una suma.
Ejemplo. Entradas 0.5, 0.8 y 0.2; pesos 2, −1 y 3; sesgo 0.1: 1.0 − 0.8 + 0.6 + 0.1 = 0.9, y la ReLU deja pasar 0.9.
Activaciónactivation functionLa función sencilla que una neurona aplica al final de su suma. Sin ella, apilar capas no serviría de nada: todo seguiría siendo una recta.Más +
Una capa sin activación solo multiplica y suma, y dos así juntas equivalen a una sola. La activación «dobla» la recta, y con muchas neuronas la red puede formar curvas tan complicadas como haga falta. La más usada es la ReLU; antes se usaban activaciones suaves, como la sigmoide, que aplasta el número entre 0 y 1. También se le dice «activación» al número que sale de una neurona.
Ejemplo. Sin activación, y = 3x + 1 seguida de z = 2y − 1 da z = 6x + 1: otra recta. Con una ReLU en medio, la red se dobla en el 0.
ReLUrectified linear unitLa activación más usada: si el número es negativo, sale 0; si no, sale igual. ReLU(−0.3) = 0 y ReLU(0.9) = 0.9.Más +
Es barata de calcular y funciona muy bien en redes profundas; se impuso en la década de 2010. Cuando una neurona saca 0 se dice que «no se activó». Como apaga más o menos la mitad de los números, la regla de inicialización de He usa un 2 para compensar.
Ejemplo. En la red que calcula el XOR, h₂ = ReLU(x₁ + x₂ − 1) vale 0 en tres casos y 1 solo cuando las dos entradas valen 1.
PerceptrónperceptronUna de las primeras neuronas artificiales que aprendían solas (Frank Rosenblatt, 1958): suma sus entradas con pesos y responde 1 si la suma pasa de 0. Solo puede separar lo que se separa con una recta.Más +
Su regla de aprendizaje es corregirse solo cuando se equivoca: si dijo 0 y era 1, le suma cada entrada a su peso; si dijo 1 y era 0, se la resta. Aprende el AND en unas cuantas vueltas, pero nunca el XOR, porque su frontera es una recta y los casos del XOR no se separan con una. Minsky y Papert convirtieron ese límite en teorema en 1969; se resolvió con capas ocultas, el MLP.
Ejemplo. Con w₁ = 2, w₂ = 1 y b = −2 calcula el AND: solo la entrada (1, 1) da una suma positiva, 2 + 1 − 2 = 1.
CapalayerUn grupo de neuronas que reciben las mismas entradas, cada una con sus propios pesos. Lo que sale de una capa entra a la siguiente.Más +
En una capa densa (dense, fully connected o linear) cada neurona ve todas las entradas: tiene entradas × salidas pesos más un sesgo por salida, y hace entradas × salidas multiplicaciones-sumas por ejemplo. En una capa convolucional cada filtro ve solo un pedacito (convolución). Una red de capas densas es un MLP.
Ejemplo. Una capa densa de 2,048 entradas y 500 salidas tiene 2,048 × 500 + 500 = 1,024,500 parámetros: es la cabeza de la ResNet-50 de C01.
Red neuronalneural networkUn modelo hecho de capas de neuronas, una tras otra. Por dentro solo multiplica, suma y aplica activaciones, capa por capa, millones de veces.Más +
Sus parámetros son todos sus pesos y sesgos. Responder es hacer un forward pass; aprender es ajustar los parámetros con backpropagation y descenso de gradiente. Cada capa acomoda los datos para que a la siguiente le sea más fácil.
Ejemplo. Una red de juguete de 2 entradas, 3 neuronas y 2 salidas tiene (2 × 3 + 3) + (3 × 2 + 2) = 17 parámetros.
MLPmultilayer perceptron · perceptrón multicapaUna red neuronal hecha solo de capas densas, con activaciones entre ellas: cada neurona de una capa ve todas las salidas de la anterior.Más +
Las capas de en medio se llaman ocultas. Con una sola capa oculta ya resuelve problemas que una neurona sola no puede, como el XOR. Cada capa tiene entradas × salidas + salidas parámetros. Sobre fotos desperdicia parámetros (cada píxel lleva su propio peso), por eso para imágenes se usan CNNs; pero dentro de cada bloque de un transformer hay un MLP de dos capas.
Ejemplo. 784 entradas (un dígito de 28 × 28), 128 ocultas y 10 salidas: (784 × 128 + 128) + (128 × 10 + 10) = 101,770 parámetros.
Deep learningdeep learning · aprendizaje profundoUsar redes neuronales con muchas capas. «Profundo» se refiere a la cantidad de capas, no a nada filosófico.Más +
Cada capa trabaja sobre lo que encontró la anterior, así que con muchas capas la red combina cosas simples (bordes) en cosas complicadas (un tenis). No hay un número oficial de capas a partir del cual algo es «deep». Despegó en 2012, cuando se juntaron muchos datos (ImageNet), GPUs y trucos para entrenar redes profundas.
Ejemplo. La ResNet-50 tiene 50 capas con pesos; la red de juguete de la lección, 2. Las dos son redes neuronales, pero solo la primera se llamaría profunda.
Inicializacióninitialization · weight initLos valores con que empiezan los pesos de una red antes de entrenar: al azar y chiquitos, con un tamaño que depende de cuántas entradas suma cada neurona.Más +
No pueden empezar todos iguales, ni en cero: las neuronas de una capa calcularían lo mismo, recibirían la misma culpa y seguirían siendo gemelas para siempre. Y el tamaño importa: pesos un poco grandes hacen que los números exploten capa tras capa, y un poco chicos, que se apaguen. Con ReLU se usa la regla de He: desviación estándar √(2 ÷ entradas). PyTorch inicializa cada capa al crearla; en un fine-tuning, solo la cabeza nueva empieza al azar.
Ejemplo. Una convolución de 3 × 3 sobre 64 canales suma 576 entradas por neurona: sus pesos empiezan con desviación √(2 ÷ 576) ≈ 0.059.
ConvoluciónconvolutionPasar un filtro chico (por ejemplo de 3 × 3) por toda la foto: en cada posición multiplica los píxeles que cubre por sus pesos, suma y escribe un número.Más +
El mismo filtro se usa en todas las posiciones, así que una capa convolucional tiene muy pocos parámetros, encuentra un patrón esté donde esté y reutiliza cada peso miles de veces por foto. Cada filtro produce un mapa de activaciones, cuyo tamaño depende del stride y del padding. (En matemáticas, una convolución voltea el filtro antes de aplicarlo; las redes no lo voltean, pero se le sigue llamando así.)
Ejemplo. Un filtro con columnas 1, 0 y −1 sobre una ventana con filas 9 · 9 · 1, 8 · 9 · 0 y 9 · 8 · 1 da 8 + 8 + 8 = 24: hay un borde de claro a oscuro.
Filtrofilter · kernelLa cuadrícula chica de pesos que recorre la foto en una convolución. Cada filtro busca un patrón: un borde, un cambio de color, una textura.Más +
Sobre una entrada de varios canales, un filtro de 3 × 3 mira todos a la vez: sobre una foto de color es de 3 × 3 × 3, 27 pesos más 1 sesgo. Sus pesos los aprende el entrenamiento; nadie los escribe a mano.
Ejemplo. Una capa de 64 filtros de 3 × 3 sobre una foto de color: 64 × (27 + 1) = 1,792 parámetros.
Mapa de activacionesfeature map · activation mapLa cuadrícula que produce un filtro al recorrer la foto. Dice dónde de la foto encontró lo que busca ese filtro.Más +
Una capa con 64 filtros produce 64 mapas, que son los 64 canales de entrada de la capa siguiente. En una CNN los mapas se van achicando y multiplicando: la ResNet-50 termina con 2,048 mapas de 7 × 7.
Ejemplo. La primera capa de la ResNet-50 convierte la foto de 3 × 224 × 224 en 64 mapas de 112 × 112.
Stridestride · pasoCuántos píxeles salta un filtro de una posición a la siguiente. Con stride 2, la salida queda más o menos de la mitad de ancho y de la mitad de alto.Más +
Entra en la fórmula del tamaño de salida de una convolución o de un pooling: lado = (n + 2p − k) ÷ s + 1, redondeando la división hacia abajo, con n el lado de la entrada, k el del filtro, p el padding y s el stride. Cada capa con stride 2 deja la cuarta parte de las posiciones y hace crecer más rápido el campo receptivo.
Ejemplo. La primera capa de la ResNet-50 (7 × 7, padding 3, stride 2) convierte la foto de 224 × 224 en mapas de 112 × 112: (224 + 6 − 7) ÷ 2 = 111.5, que baja a 111, más 1.
Paddingpadding · rellenoUn marco de ceros alrededor de la entrada de una convolución, para que el filtro también se centre en las orillas y la salida no se encoja.Más +
Con un filtro de k × k (k impar), padding (k − 1) ÷ 2 y stride 1, la salida mide lo mismo que la entrada: por eso casi todas las convoluciones de 3 × 3 llevan padding 1. Cerca de la orilla el filtro ve ceros en vez de imagen, así que las respuestas de la orilla suelen ser peores.
Ejemplo. Una entrada de 5 × 5 con un filtro de 3 × 3: sin padding sale de 3 × 3; con padding 1, (5 + 2 − 3) ÷ 1 + 1 = 5, del mismo tamaño.
Poolingpooling · max pooling · average poolingResumir cada cuadrito de un mapa en un solo número (el mayor, o el promedio) para achicarlo. No tiene parámetros: no aprende nada.Más +
Un max pooling de 2 × 2 con stride 2 deja los mapas con la cuarta parte de los números; su tamaño sale de la misma fórmula que el de una convolución. Se pierde exactamente dónde estaba algo dentro del cuadrito, pero se conserva que sí estaba. Al final de la ResNet-50, un pooling global promedia cada mapa entero en un número.
Ejemplo. El cuadrito 5, 6, 7, 3 con max pooling da 7.
CNNconvolutional neural networkUna red neuronal hecha sobre todo de convoluciones, activaciones y pooling. Es la familia clásica para imágenes.Más +
Le va bien a las fotos por tres razones: cada filtro mira cerca (el significado está en los píxeles vecinos), usa el mismo filtro en todas partes (reconoce un tenis esté donde esté, con pocos parámetros) y arma lo complicado con lo simple, capa tras capa, porque su campo receptivo crece. La ResNet-50 de C01 es una CNN.
Ejemplo. Una capa convolucional de 64 filtros de 3 × 3 sobre la foto de color tiene 1,792 parámetros; una capa densa de 1,000 neuronas sobre los mismos 150,528 números tendría ≈ 150 millones.
Campo receptivoreceptive fieldEl pedazo de la foto original que puede influir en una neurona. Crece con cada capa, y más rápido con stride.Más +
Se calcula capa por capa con dos números, el campo r y el salto j (píxeles de la foto entre dos neuronas vecinas): r nuevo = r + (k − 1) × j y j nuevo = j × s, empezando con r = 1 y j = 1. Es un máximo teórico: los píxeles del centro pesan mucho más que los de la orilla. Decide si una red alcanza a ver un objeto grande y si un detalle chico sobrevive.
Ejemplo. Tres capas de 3 × 3 con stride 1 ven 3, 5 y 7 píxeles. Un número del último mapa de la ResNet-50 puede depender de 427 × 427 píxeles.
ResNetresidual network · ResNet-50Una familia de CNNs (He y otros, Microsoft Research, 2015) en la que cada bloque tiene un atajo: su entrada se le suma a su salida. Eso permitió entrenar redes muy profundas.Más +
Con el atajo (skip connection), salida = bloque(x) + x: cada bloque solo aprende una corrección, y la señal del aprendizaje llega bien hasta las primeras capas. Ganó la competencia de ImageNet de 2015. La ResNet-50 tiene 50 capas con pesos en su camino principal, 16 bloques residuales en cuatro etapas y hace ≈ 4.1 mil millones de multiplicaciones-sumas por foto de 224 × 224.
Ejemplo. La ResNet-50 original (1,000 categorías) tiene ≈ 25.6 millones de parámetros: ≈ 102 MB en float32. La de C01, con 500 categorías, ≈ 24.5 millones.
BatchNormbatch normalizationUna capa que acomoda los números de cada canal para que queden alrededor de 0 y con dispersión parecida a 1. Se porta distinto al entrenar y al responder.Más +
Al entrenar usa el promedio y la desviación del batch actual y va guardando un promedio acumulado (running stats). Al responder, en modo eval, usa esos valores acumulados. Si el modelo se queda en modo entrenamiento en producción, la respuesta de una foto depende de las otras fotos de su batch. Cada bloque de la ResNet lleva varias.
Ejemplo. Un canal da 2, 4, 6 y 8 en un batch: promedio 5, desviación ≈ 2.24. La foto que dio 4 queda en ≈ −0.45. Con las estadísticas acumuladas da eso siempre; con las de otro batch, otra cosa.
DropoutdropoutUna traba contra el overfitting: al entrenar, apaga al azar una fracción de las neuronas en cada paso. Al responder no apaga nada.Más +
Obliga a la red a repartir lo que sabe en lugar de depender de unas pocas neuronas. Las que quedan se multiplican para compensar (con la mitad apagada, por 2). Si el modelo se queda en modo entrenamiento en producción, la misma foto da respuestas distintas cada vez. La ResNet-50 estándar no tiene Dropout; muchos otros modelos sí.
Ejemplo. Con dropout de 0.5, una capa de 4 neuronas que saca 1, 2, 3 y 4 podría sacar al entrenar 2, 0, 6 y 0: la mitad apagada y el resto multiplicado por 2. Al responder saca 1, 2, 3 y 4.
Modo evaleval mode · model.eval()El interruptor de PyTorch que le dice al modelo «ahora vas a responder, no a entrenar». BatchNorm usa sus estadísticas guardadas y Dropout deja de apagar neuronas.Más +
Un modelo recién creado o cargado está en modo entrenamiento (model.train()). Olvidar model.eval() en el servidor es un bug clásico: no da error, solo baja la calidad. No apaga el cálculo para aprender: para eso es torch.inference_mode(). En producción van los dos.
Ejemplo. En modo eval, la foto del ejemplo de BatchNorm da −0.45 llegue sola o acompañada. En modo train, sola en su batch, daría 0.
Backbonebackbone · feature extractor · encoderLa parte de la red que «ve»: recibe la foto y la convierte en una lista de números (features) que describen lo que hay en ella. Después va la cabeza, que decide.Más +
Es la parte grande y cara (en la ResNet-50, el 99.97 % de las multiplicaciones-sumas), y casi siempre viene preentrenada (transfer learning). La cabeza es chica y es la que sabe de la tarea: el mismo backbone sirve para clasificar, detectar o segmentar cambiando solo la cabeza. Sus features también sirven solas, como embedding.
Ejemplo. En la ResNet-50 de C01, el backbone entrega 2,048 números por foto y la cabeza los convierte en 500 logits.
CabezaheadLa parte final de una red, chica, que convierte lo que entrega el backbone en la respuesta de la tarea: un logit por categoría, cajas o una máscara.Más +
Es lo que se cambia al reutilizar un backbone para otra tarea (transfer learning). En clasificación es un pooling más una capa densa; en detección, una capa que propone una caja y un puntaje por clase en cada posición; en segmentación, un decoder que agranda los mapas hasta dar una respuesta por píxel. No confundir con las «cabezas de atención» de un transformer, que son otra cosa.
Ejemplo. La cabeza de C01 es una capa densa de 2,048 → 500: 2,048 × 500 + 500 = 1,024,500 parámetros. La original de ImageNet, de 1,000 categorías, tiene 2,049,000.
Transfer learningtransfer learning · aprendizaje por transferenciaUsar lo que un modelo ya aprendió en una tarea para resolver otra. Se parte de un modelo preentrenado en vez de empezar de cero.Más +
Lo típico en visión: un backbone entrenado con ImageNet (≈ 1.28 millones de fotos, 1,000 categorías) ya sabe ver bordes, texturas y formas. Se le cambia la cabeza por una con las categorías propias y se sigue entrenando (fine-tuning). Hacen falta muchos menos datos y tiempo. Ayuda menos cuando las imágenes se parecen poco a las del preentrenamiento, como radiografías.
Ejemplo. C01 parte de una ResNet-50 preentrenada en ImageNet y cambia su cabeza de 1,000 a 500 categorías.
Fine-tuningfine-tuning · ajuste finoSeguir entrenando un modelo preentrenado con tus propios datos, con un learning rate chico para no borrar lo que ya sabía.Más +
Se puede congelar el backbone y entrenar solo la cabeza (rápido, sirve con pocos datos) o entrenar todo con learning rate chico (más lento, suele dar mejor resultado con muchos datos). Es la forma más común de transfer learning.
Ejemplo. En la Ronda, el fine-tuning de C01 usa learning rate 0.0003, 8 épocas y batches de 64, y cabe en una GPU en horas. Con el backbone congelado, solo se moverían 1,024,500 de los 24,532,532 parámetros.
ViTVision TransformerUn modelo de visión que parte la foto en parches de 16 × 16 píxeles y los trata como los tokens de una frase, con un transformer.Más +
Lo presentaron Dosovitskiy y otros en 2020. Cada parche (16 × 16 × 3 = 768 números) se convierte en un vector, se le suma su posición y entra a un transformer junto con un token extra, [CLS], de donde sale la respuesta. No trae de fábrica las ideas de una CNN (mirar de cerca, el mismo filtro en todas partes): las aprende de los datos, así que brilla con preentrenamientos enormes. El ViT-B/16 tiene ≈ 86 millones de parámetros.
Ejemplo. Una foto de 224 × 224 con parches de 16: 224 ÷ 16 = 14 por lado, 14 × 14 = 196 parches; con el [CLS], 197 tokens.
Chequeo
EsencialCheck
Intenta responder en tu cabeza antes de abrir cada respuesta.
1¿Por qué un perceptrón no puede aprender el XOR, y qué lo resuelve?Ver respuesta
Una neurona con escalón separa el plano con una recta, y en el XOR los dos casos que valen 1 están en esquinas opuestas: ninguna recta los aparta de los ceros. Lo resuelve una capa oculta (un MLP), que mueve los puntos para que una recta sí sirva.
2¿Cuántos parámetros tiene una capa densa con 2,048 entradas y 500 salidas, y cuántas MACs hace por foto?Ver respuesta
2,048 × 500 pesos + 500 sesgos = 1,024,500 parámetros, y 2,048 × 500 = 1,024,000 MACs: cada peso se usa una vez. Es la capa final de la ResNet-50 de C01.
3¿Por qué una CNN necesita tan pocos parámetros comparada con una red densa sobre los mismos píxeles?Ver respuesta
Porque cada filtro mira solo un pedacito y se usa en todas las posiciones de la foto. Una capa de 64 filtros de 3 × 3 × 3 tiene 1,792 parámetros; una densa de 1,000 neuronas sobre los mismos 150,528 números tendría ≈ 150 millones.
4Una entrada de 56 × 56 pasa por una convolución de 3 × 3 con padding 1 y stride 2. ¿De qué tamaño sale?Ver respuesta
(56 + 2 − 3) ÷ 2 = 27.5, que baja a 27; más 1: 28. Con stride 1 habría salido de 56.
5¿Qué hace la conexión residual de una ResNet?Ver respuesta
Le suma al bloque su propia entrada: salida = bloque(x) + x. Cada bloque solo aprende una corrección y la señal del aprendizaje llega bien hasta las primeras capas; eso permitió entrenar en ImageNet redes de hasta 152 capas.
6En producción, la misma foto da respuestas distintas según qué otras fotos venían en su batch. ¿Qué revisas primero?Ver respuesta
Que el modelo esté en modo eval (
model.eval()). En modo train, la BatchNorm normaliza con las estadísticas del batch actual, así que la respuesta depende de las otras fotos.7¿Por qué C01 parte de una ResNet-50 preentrenada en ImageNet en vez de entrenar desde cero?Ver respuesta
Porque su backbone ya aprendió a ver bordes, texturas y formas con ≈ 1.28 millones de fotos. Basta cambiar la cabeza a 500 categorías y hacer fine-tuning, con muchas menos fotos y horas de GPU.