02

El mundo hecho de números

¿Cómo ve una máquina una imagen, un sonido o un texto?

10 minRuta ejecutiva

El mundo hecho de números

Con voz. Puedes pausar y saltar a cualquier paso.

Lección completa

Subtítulos

En la lección anterior, a cada correo le bastaron dos números. Pero ¿y una foto? Una foto no parece un número. Veamos cómo se convierte en números.

Voz

Sin voz: la lección avanza sola con subtítulos.

La voz de esta lección está en preparación: por ahora avanza sola con subtítulos.

0:00 / 0:00

Qué lograrás

  • Explicar cómo una imagen, un sonido y un texto se convierten en listas de números que un modelo puede recibir.
  • Calcular cuántos números tiene una imagen, en grises o en color, a partir de su tamaño.
  • Predecir qué ocurre con los números de una imagen cuando se desenfoca, aunque a simple vista parezca igual.

Ideas clave

  1. Un modelo solo recibe números. Una imagen en grises es una tabla de brillos de 0 (negro) a 255 (blanco); en color son tres tablas, una por canal (rojo, verde, azul).
  2. Aplanar la tabla da un vector: una lista ordenada con una característica (feature) por píxel. Cada ejemplo llega al modelo como un vector o un tensor.
  3. Una imagen en color de alto × ancho píxeles tiene alto × ancho × 3 números. Una foto de 12 megapíxeles tiene unos 36 millones.
  4. El sonido se guarda midiendo la señal muchas veces por segundo (muestras). Si se mide demasiado pocas veces, la onda ya no se puede reconstruir y se pierde información que ningún modelo recupera después.
  5. El texto también se convierte en vectores. Un código por letra solo etiqueta; los vectores aprendidos hacen que lo cercano en números sea cercano en significado.
  6. Una imagen casi igual para ti puede ser un vector distinto para el modelo: un desenfoque suave cambia todos los números de la carita.

Lo que mucha gente cree

Creencia común La IA «ve» una foto como nosotros y reconoce lo que hay en ella por lo que ve.

Lo correcto Recibe una tabla de números (brillos o colores) y nada más: dentro del modelo no hay «foto». Reconocer es encontrar patrones en esos números, y los aprende de ejemplos.

Compruébalo

Cuatro preguntas. Sin nota ni cuenta: sirven para ver si la idea quedó.

Concepto¿Qué recibe un modelo cuando le muestras una foto?
CálculoUna imagen en color de 100 × 100 píxeles tiene tres canales. ¿Cuántos números la describen?
ConceptoDesenfocas una imagen apenas un poco y a simple vista sigue siendo la misma. ¿Qué ocurre con el vector que recibe el modelo?
AplicaciónUna empresa transcribe llamadas con IA. Para ahorrar espacio, guarda el audio con muy pocas muestras por segundo. ¿Cuál es el riesgo principal?

Por dentroPara quien quiere las fórmulas y el código. No hace falta para seguir el curso.

De la imagen al vector

Una imagen en escala de grises es una matriz X∈{0,…,255}H×WX \in \{0,\dots,255\}^{H \times W}. Aplanarla, fila por fila, da el vector x∈RHW\mathbf{x} \in \mathbb{R}^{HW} con

xiW+j=Xij(i=0,…,H−1; j=0,…,W−1)x_{iW+j} = X_{ij} \qquad (i = 0,\dots,H-1;\ j = 0,\dots,W-1)

La carita de la lección tiene H=W=8H = W = 8, así que x\mathbf{x} tiene 64 componentes. Cada valor cabe en un byte: 28=2562^8 = 256 niveles. Antes de entrenar es habitual normalizar, x′=x/255∈[0,1]x' = x/255 \in [0,1].

La vecindad se pierde al aplanar: el píxel (i,j)(i,j) y el (i+1,j)(i+1,j) son vecinos en la imagen, pero sus posiciones en el vector difieren en WW (ocho, en la carita). Un modelo que trata cada componente como una medida independiente, como el de los correos de la lección 1 o una red totalmente conectada, no sabe cuáles píxeles son vecinos; las redes convolucionales (lección 11) sí lo aprovechan y reciben la imagen como matriz.

Color, canales y tensores

Una imagen en color es un tensor X∈{0,…,255}H×W×3X \in \{0,\dots,255\}^{H \times W \times 3} con 3HW3HW valores. Una foto de 12 megapíxeles, por ejemplo de 4000×30004000 \times 3000 píxeles, tiene

12 000 000×3=36 000 000 valores12\,000\,000 \times 3 = 36\,000\,000 \text{ valores}

es decir, unos 36 MB sin comprimir a un byte por valor. Los archivos como JPEG ocupan mucho menos, pero el modelo trabaja con los píxeles ya decodificados (o con una versión reducida: AlexNet, por ejemplo, redujo todas las imágenes de ImageNet a 256×256256 \times 256 —reescalando el lado corto a 256 y recortando el centro—, o sea 256×256×3=196 608256 \times 256 \times 3 = 196\,608 valores, unas 183 veces menos que la foto de 12 megapíxeles; la red recibía además recortes de 224×224×3=150 528224 \times 224 \times 3 = 150\,528 valores; Krizhevsky et al., 2012). El orden de los ejes depende de la biblioteca: alto × ancho × canales, o canales × alto × ancho. En rigor, un número, un vector y una matriz también son tensores (de 0, 1 y 2 ejes).

En la lección, el gris de cada píxel sale de su color con la receta de luma de la recomendación ITU-R BT.601 (versión 7, 2011): Y′=0.299 R′+0.587 G′+0.114 B′Y' = 0.299\,R' + 0.587\,G' + 0.114\,B', aplicada a valores ya corregidos con gamma. Con tres canales de 8 bits hay 2563=16 777 216256^3 = 16\,777\,216 colores posibles.

Desenfoque: mezclar con los vecinos

El desenfoque de la lección mezcla cada píxel con el promedio de su ventana 3×33\times 3, en una proporción λ\lambda:

yij=(1−λ) xij+λ 1∣Vij∣∑(a,b)∈Vijxi+a, j+by_{ij} = (1-\lambda)\,x_{ij} + \lambda\,\frac{1}{|V_{ij}|} \sum_{(a,b)\in V_{ij}} x_{i+a,\,j+b}

con λ=0, 0.25, 0.5, 0.75, 1\lambda = 0,\ 0.25,\ 0.5,\ 0.75,\ 1 en los niveles 0 a 4, y VijV_{ij} la ventana restringida a los vecinos que existen (9 píxeles en el interior, 6 en los bordes, 4 en las esquinas). Para el píxel de la fila 3, columna 3 (contando desde 1), los nueve valores son 146, 202, 255, 202, 0, 202, 202, 0 y 202, y su promedio es ≈156.8\approx 156.8. Es un caso particular de convolución (lección 11). Medido sobre la carita (valores redondeados a enteros): en cada nivel de 1 a 4 cambian los 64 números, con un cambio medio de 15.0, 29.9, 44.9 y 59.9 niveles de gris (de 255), y el contraste (máximo menos mínimo) baja de 255 a 205, 175, 145 y 131.

Con λ<1\lambda < 1 la operación se puede deshacer en teoría (la matriz es invertible; con λ=0.75\lambda = 0.75 ya amplifica 40 veces el redondeo), pero con λ=1\lambda = 1 pierde información de verdad. La suma de una ventana es K⊗KK \otimes K, con KK la matriz 8×88\times 8 tridiagonal de unos, y KK tiene un vector nulo, u=(1,−1,0,1,−1,0,1,−1)u = (1,-1,0,1,-1,0,1,-1): tres vecinos seguidos siempre suman cero. Por eso el desenfoque completo tiene rango 7×7=497 \times 7 = 49, no 64, y desaparecen 15 direcciones. Ejemplo exacto: sumar +25,−25,0,+25,−25,0,+25,−25+25,-25,0,+25,-25,0,+25,-25 a la columna 4 de la carita cambia seis píxeles y da otra imagen con el mismo desenfoque completo, número por número.

Sonido: muestreo

Una señal s(t)s(t) se guarda como x[n]=s(n/fs)x[n] = s(n/f_s), con fsf_s muestras por segundo. Shannon (1949, teorema 1) lo enuncia así: si una función no tiene frecuencias por encima de WW, queda completamente determinada por sus valores en puntos separados 1/2W1/2W segundos; en la práctica se pide fs>2Bf_s > 2B para una señal sin frecuencias por encima de BB (en el límite exacto, fs=2Bf_s = 2B, el tono de frecuencia BB no queda determinado, como se ve en la demostración). Shannon atribuye a Nyquist la importancia de ese intervalo. Whisper remuestrea todo el audio a fs=16 000f_s = 16\,000 Hz (Radford et al., 2022, sección 2.2), con lo que se representan componentes de hasta 8 kHz: un minuto son 16 000×60=960 00016\,000 \times 60 = 960\,000 valores. El modelo no recibe esos valores tal cual: calcula un espectrograma logarítmico de 80 canales con ventanas de 25 ms y paso de 10 ms, es decir 100 columnas por segundo, 80×100=8 00080 \times 100 = 8\,000 números por segundo.

La señal de juguete de la lección suma un tono de 200 y otro de 500 ciclos por segundo y se repite cada 10 ms; se toman n=fs/100n = f_s/100 muestras por periodo. La línea discontinua es lo que reconstruiría un conversor ideal (interpolación trigonométrica de las nn muestras). Se comprobó con el código de la lección: con fs≥1 100f_s \ge 1\,100 la reconstrucción coincide con la señal sin error; con fs=1 000f_s = 1\,000 el error relativo es 0.43 (el tono de 500 queda justo en el límite) y por debajo es aún mayor (de 0.67 a 1.65). Por eso la compuerta pide bajar a 1 000 o menos.

Texto: de códigos a vectores

Unicode asigna un número, el punto de código, a cada carácter: «N» es 78, «e» es 101, «u» es 117, «ñ» es 241 (tablas de códigos del estándar Unicode). Es una etiqueta, no un significado. Los modelos de lenguaje parten el texto en tokens (lección 20), cada token es un entero, y una tabla de embeddings E∈RV×dE \in \mathbb{R}^{V \times d} entrega a cada uno un vector Eid∈RdE_{\text{id}} \in \mathbb{R}^{d}, aprendido durante el entrenamiento. En GPT-3 175B la dimensión del modelo es dmodel=12 288d_{\text{model}} = 12\,288 (Brown et al., 2020, tabla 2.1). Los cuatro rasgos de la lección (d=4d=4) son inventados; en un modelo real los rasgos se aprenden y no tienen nombre. La cercanía en el espacio, medida por ejemplo con la distancia euclídea ∥a−b∥\lVert \mathbf{a}-\mathbf{b}\rVert, se llena de significado en la lección 14. En la lección, «gato» y «perro» están a 0.22; «gato» y «tigre», a 1.08; «gato» y «pan», a 1.68.

MNIST (LeCun et al., 1998) parte de dígitos escritos por empleados de la Oficina del Censo de EE. UU. y por estudiantes de secundaria (bases NIST SD-3 y SD-1). Las imágenes originales eran en blanco y negro; al normalizarlas a una caja de 20×2020\times 20 píxeles aparecieron los grises, y se centraron en un cuadro de 28×2828\times 28 por el centro de masa. La imagen de la lección es una ilustración, no un dígito del conjunto.

En código

import numpy as np

# la carita en grises (8x8), la misma de la lección
carita = np.array([
    [ 20,  20, 146, 146, 146, 146,  20,  20],
    [ 20, 146, 202, 255, 202, 202, 146,  20],
    [146, 202,   0, 202, 202,   0, 202, 146],
    [146, 202,   0, 202, 202,   0, 202, 146],
    [146, 202, 202, 202, 202, 202, 202, 146],
    [146, 202,   0, 202, 202,   0, 202, 146],
    [ 20, 146, 202,   0,   0, 202, 146,  20],
    [ 20,  20, 146, 146, 146, 146,  20,  20],
], dtype=np.uint8)

vector = carita.flatten()               # de tabla a lista, fila por fila
print(carita.shape, vector.shape)       # (8, 8) (64,)

# un píxel y el de abajo: vecinos en la imagen, lejos en el vector
i, j = 2, 2
print(i * 8 + j, (i + 1) * 8 + j)       # 18 26

# desenfoque de un píxel: promedio de su ventana 3x3
ventana = carita[i - 1:i + 2, j - 1:j + 2]
print(ventana.mean())                   # 156.77777777777777

# desenfoque de toda la imagen (en los bordes, solo los vecinos que existen)
def desenfoque(img):
    out = np.zeros(img.shape)
    for r in range(8):
        for c in range(8):
            out[r, c] = img[max(r - 1, 0):r + 2, max(c - 1, 0):c + 2].mean()
    return out

x = carita.astype(float)
otra = x.copy()
otra[:, 3] += [25, -25, 0, 25, -25, 0, 25, -25]    # otra imagen: seis píxeles distintos
print(int((otra != x).sum()), np.abs(desenfoque(x) - desenfoque(otra)).max())   # 6 0.0

# desenfoque suave (25 %): todos los números cambian, pero poco
suave = 0.75 * x + 0.25 * desenfoque(x)
print(round(np.abs(suave - x).mean(), 1), int((np.round(suave) != x).sum()))    # 15.0 64

# una foto de 12 megapíxeles en color (4000 x 3000 píxeles, 3 canales)
foto = np.zeros((3000, 4000, 3), dtype=np.uint8)
print(foto.shape, foto.size)            # (3000, 4000, 3) 36000000

# texto: el código de cada letra
print([ord(c) for c in "Neu"])          # [78, 101, 117]

Lo que viene

Con los datos ya en vectores, la lección 3 pone el primer modelo encima: una recta y=wx+by = wx + b y su error. Más adelante, las convoluciones (lección 11) recuperan la vecindad de los píxeles, los embeddings (lección 14) dan geometría al significado y los tokens (lección 20) explican qué «piezas» de texto lee de verdad un modelo de lenguaje.

Lente de decisión

Qué significa esta idea si tu trabajo es decidir, no programar.

  • Lo que un modelo puede aprender tiene un techo: lo que sobrevive en los números. Resolución, compresión, frecuencia de muestreo y calidad de la transcripción fijan ese techo, y ninguna IA recupera con certeza lo que no se midió (puede inventar algo plausible). Pregunta a qué calidad se captura lo que vas a usar.
  • Más números por ejemplo significan más memoria y más cómputo. Una foto de 12 megapíxeles son unos 36 millones de valores, por eso los sistemas suelen reducir las imágenes antes de procesarlas (AlexNet las bajó a 256 × 256 en 2012). Pregunta qué versión ve realmente el modelo y cuánto detalle pierde.
  • «Basura entra, basura sale»: otra cámara, otro micrófono o otro escáner producen números distintos aunque a ti te parezca lo mismo (como el desenfoque suave de la lección, que cambia los 64 números de la carita). Prueba el sistema con muestras de tu operación real, no solo con la demostración.
  • Si con esos números se puede identificar a alguien, siguen siendo datos personales: el RGPD europeo (art. 4) llama datos personales a cualquier información sobre una persona identificable, y biométricos a los que resultan de procesar técnicamente sus rasgos físicos para identificarla, como las imágenes faciales. Trata la representación numérica con las mismas reglas de privacidad que el original.

Términos de la lección

Transcripción completa
ComentariosConversación pública de esta lección: dudas, datos por revisar, ideas.

Los comentarios viven en GitHub Discussions, en el repositorio público del curso; para escribir se necesita una cuenta de GitHub. Se cargan desde giscus.app al abrir esta sección. Las personas que revisan el curso los leen, y si un cambio se acepta, se aplica en los dos idiomas. Abrir el hilo en GitHub

Fuentes