Un filtro chiquito, deslizado sobre una imagen, detecta un patrón local en todas partes a la vez.
Weight sharing + pooling = el prior correcto para datos en rejilla. Construido desde cero en NumPy; el mecanismo, no un loop de entrenamiento.
Un MLP toma una imagen como una bolsa de pixeles: sin noción de que el pixel 9 está debajo del pixel 1. La convolución trae de fábrica lo que ya sabemos: los patrones son locales, y un patrón que vale la pena encontrar en una esquina vale la pena encontrarlo en todas partes.
Un filtro = un detector chiquito de patrones, reutilizado en cada posición. 9 pesos, no 4,096, y la cuenta nunca crece con la imagen.
load_digits — 1,797 dígitos manuscritos, 8×8, intensidades 0–16. El primo diminuto
de MNIST. Lo bastante chico para animar cada una de las 36 paradas de un filtro.
La suma ponderada deslizante, un pixel de salida:
S(i,j)=m=0∑kh−1n=0∑kw−1I(i+m, j+n)K(m,n)Rectifica, y luego haz pooling con la respuesta más fuerte por bloque:
ReLU(x)=max(0, x) P(i,j)=0≤a,b<smaxS(i⋅s+a, j⋅s+b)El kernel K no tiene índice i,j: los mismos pesos en todas partes. Eso es weight sharing, todo el prior.
Un filtro de bordes se desliza sobre un 3 manuscrito. El campo receptivo va remarcado en la entrada; el feature map se llena un pixel por cuadro; el pie de imagen nombra el valor calculado.
Los valores se vuelven positivos en un flanco del trazo, negativos en el otro: los dos lados de un borde. ReLU conserva uno y pone el otro en cero.
Cada filtro es un especialista: vertical, horizontal, las dos diagonales, cada uno con su negación. Los feature maps tras ReLU para un 3:
El mismo clasificador, el mismo split (1,257 train / 540 test). Solo cambia la representación: 72 features conv vs. 64 pixeles crudos.
Features conv 0.9796 vs. pixeles crudos 0.9722: una victoria estrecha, pero real. ReLU descarta el 52% de las respuestas: features dispersos y orientados que valen más cada uno.