Ejemplo práctico · GPT-2 · Self-Attention

Ejemplo GPT-2 Transformer

Documento explicativo paso a paso sobre cómo se tokeniza el texto, cómo se construyen los embeddings, cómo funciona el mecanismo de atención, y cómo evolucionan los vectores a través de las capas del modelo.

Ejemplo GPT-2 transformer

Codigo usando el diseño del Transformer
Como el modelo de transformer NO es igual a otros modelos, no se debe de interpretar como la clasica red neuronal de varias capas de neuronas y las entradas son independientes (en paralelo). Aqui son secuenciales.

Ver la tokenizacion

tokens = tokenizer(texto, return_tensors="pt")
print("=== IDS DE TOKENS (input_ids) ===")
print(tokens["input_ids"])
print("Shape de input_ids:", tokens["input_ids"].shape)
  # (1, n_tokens)
print()
# esto devolveria la lista normal y no un tensor
print("Lista normal de tokens:", tokens["input_ids"]) 
resultado :
=== IDS DE TOKENS (input_ids) ===
tensor([[ 39, 5708, 27943, 78, 198, 22362, 64, 1658, 555, 64, 778, 518, 7012, 390, 11241, 528, 49443, 1103, 13, 198]])
Shape de input_ids: torch.Size([1, 20])

Lista normal de tokens: tensor([[ 39, 5708, 27943, 78, 198, 22362, 64, 1658, 555, 64, 778, 518, 7012, 390, 11241, 528, 49443, 1103, 13, 198]])

Esto quiere decir que del texto original que es:
Hola mundo
Esta es una prueba de tokenizacion real. 
Se generaron 20 tokens, o sea 20 entradas.

Como funciona

  1. Generacion de token:
    Partimos desde los 20 token (lo que hicimos arriba)

  2. embedding x index ID:
    Ahora GPT tiene una tabla de embeddings token que usara para crear un vector de 768 columnas. con los tokens IDs se obtendra un vector fijo de 768 dimensiones.
    Lo que esperamos un vector de 768 columnas x 20 filas que sea igual al que tiene asignado ese tokenID. Esto valor es unico y por ejemplo 'H' o 'ello' tiene un token y siempre va a tener el mismo token.

  3. embedding de posicion:
    Despues generamos otro vector de 768 columnas tambien desde una tabla a parte (no es la misma que antes) pero segun la posicion, es decir, cuando tiene la posicion 1, tendra un vector de 768 segun la posicion.
    Se obtiene otro embedding desde una tabla diferente (embedding de posicion).
    Se genera un vector de 768 dimensiones segun la posicion del token en la secuencia.

  4. embeddings iniciales contextualizados y por posicion:
    Ahora sumamos el primer vector segun el ID Token + el Vector segun su Posicion.
    Nota:
    La logica es que las palabras hello indican algo en el lenguaje... Todos sabemos que es para saludar , y la posicion en donde se encuentre en el prompt tambien quiere decir algo.
    Aqui esta la magia: Todo esto se hace en el entrenamiento y esta enorme ! y despues queda fijo despues del entrenamiento y no cambia, lo cual lo mas muy manejable.
    El codigo para generar estas tablas tan precisas es absolutamente genial, el equipo de programadores que hizo esto fue el que hizo posible que essto funcionara sin duda !!!
    Y ahora tiene sentido la cantidad increible que se gasta al entrenar a una AI.

    En esta linea se puede ver el numero de token y el largo de 768 que es fijo para cada vector en particular.
    Shape de embeddings: torch.Size([1, 20, 768])
    Y aqui se ven algunos ejemplos de los embedding finales:
    Primer embedding (primeros 10 valores):
    tensor([-0.2077, -0.1556, -0.1638, 0.0468, -0.0956, -0.3012, 0.1546, 0.1558, -0.3139, -0.0316])
    Aqui solo se mostraron los primeros 10 pero en realidad hay 768 valores que forman ese vector.

  5. Mirar la relacion de la atencion
    Que cada token pueda "mirar" a los demas para reinterpretarse considerando el contexto completo.
    Ahora GPT tiene como su entrenamiento tambien otra tabla con matrices de pesos entrenadas (W_Q, W_K, W_V). Elemento .Que es? .De donde viene? X Embedding inicial (ID + posicion) Calculado despues de la tokenizacion W_Q Matriz de pesos para Query Aprendida en entrenamiento (valor fijo) W_K Matriz de pesos para Key Aprendida en entrenamiento (valor fijo) W_V Matriz de pesos para Value Aprendida en entrenamiento (valor fijo)

    Q y K se obtienen multiplicando el embedding X por W_Q y W_K respectivamente:
    Asi que ahora puede calcular la formula de abajo con los valores. Q = Query (Que estoy buscando)
    K = Key (Que informacion tengo)
    V = Value (La informacion que se comparte)
    Eso se hace asi:

    ini

    Formula para calcular cuanto un token debe atender a los demas tokens usando los datos de Q y K:
    attention_scores = softmax(Q * K^T / √d_k)
    Nota: En esta formula no esta el valor de "V", aqui aun no se modifica el embedding, solo se calculan los pesos de atencion.

    X = el embeding ultimo que se formo con el ID token + posicion y que es un vector de 768 columnas.
    Asi se obtiene un vector N, donde N es el total de Token originales.
    En el vector se haya un numero decimal, y la suma de todos los valores de atencion debe de resultar en 1.
    0.1 + 0.8 + 0,1 +..... = 1
    Resumen: Vamos a obtener un vector de 20 filas y 20 columnas. Solo representa pesos de atencion entre tokens. Cada fila es el token que observa. Cada columna es el token al que se le presta atencion.

    Como era de esperarse con una sola atencion no es suficiente para comprender el sentido de una frase, asi que aqui se complica porque GTP-2 toma 12 headers o punto de vista o Valores de las Matrices de W que son pre-entrenadas y no solo una matriz de atencion. Asi que el mismmo procedimiento anterior se añaden otras 11 veces. obteniendo 12 matrices de 20 x 20 de pesos de relacion de atencion.
  6. "preparar" los embeddings para el mecanismo de atencion:
    V = X * W_V
    X = (embedding_token + embedding_posicion) (el que vimos arriba = 20x768)
    W_V es una matriz de pesos entrenada, parte del modelo.
    W_V -> matriz de dimensiones (768 x 768)
    (20 x 768) = (20 x 768) * (768 x 768)
    Nota:
    Q y K se usan para calcular cuanto se debe prestar atencion.
    V es la informacion que realmente se transfiere entre tokens.

    Como era de esperarse con una sola atencion no es suficiente para comprender el sentido de una frase, asi que aqui se complica porque GTP-2 toma 12 headers o punto de vista o Valores de las Matrices de W que son pre-entrenadas y no solo una matriz de atencion. Asi que el mismmo procedimiento anterior se añaden otras 11 veces. obteniendo 12 matrices embeddings.
  7. Aplicacion de los pesos de atencion sobre V:
    Una vez calculada la matriz de atencion (20 x 20), se aplica a los vectores V como resolvimos arriba.
    (20 x 768) para generar el nuevo embedding contextualizado para cada token:
        nuevo_embedding[i] = Σ (attention_scores x V) 
        
    (i y j son filas y columnas)
    Resultado final de esta etapa:
    (20 x 768)

    Ahora cada token contiene informacion propia (embedding inicial) + informacion proveniente de todos los demas tokens (dentro del contexto).
    Aqui el modelo aplica relaciones aprendidas durante entrenamiento, pero las aplica dinamicamente al contexto del input, sin requerir acceso al dataset en tiempo de inferencia. Operacion: se multiplica el valor de atencion de cada token por su correspondiente vector V[j], y luego se suman todos los resultados (se incluye a su mismo).
    El resultado es el nuevo embedding del token i, ya contextualizado.
    Este resultado es el Embedding Score Como era de esperarse con una sola atencion no es suficiente para comprender el sentido de una frase, asi que aqui se complica porque GTP-2 toma 12 headers o punto de vista o Valores de las Matrices de W que son pre-entrenadas y no solo una matriz de atencion. Asi que el mismmo procedimiento anterior se añaden otras 11 veces. obteniendo 12 matrices embeddings.
    Ejemplo ilustrativo
        Frase:
        "Hoy martes llueve"
        Queremos calcular el nuevo embedding de "hoy".
        Supongamos la atencion de "hoy" es:
        + Esto quiere decir que estamos usando el token "hoy"
        y en base a ese token sacamos la atencion de hoy, 
        martes y llueve.
        Asi que la atencion de "hoy" con respecto a si mismo 
        (hoy) es 0.2
        --------- Valores de Atencion ---------
        token j "hoy" "martes"  "llueve"
        peso   0.2     0.7       0.1
    
        Y V[j] (simplificado a 4 valores):
        + Estos son los valores no en tokens sino en 
        un vector de 4 dimensiones de cada uno de los 
        tokens.
        V["hoy"]    = [0.3, 0.2, 0.1, 0.5]
        V["martes"] = [-0.4, 0.6, 0.3, -0.2]
        V["llueve"] = [0.7, -0.1, 0.0, 0.2]
    
    
        + Como no hacerlo +
        Si multiplicaras solo por su propia atencion:
        nuevo("hoy") = 0.2 x V["hoy"] 
                     = [0.06, 0.04, 0.02, 0.10]
        + Ok
    
        No refleja contexto.
        Ahora con la sumatoria real:
        nuevo("hoy") =
          0.2xV["hoy"] +
          0.7xV["martes"] +
          0.1xV["llueve"]
    
        0.2x[0.3, 0.2, 0.1, 0.5]  =  [0.06, 0.04, 0.02, 0.10]
        0.7x[-0.4, 0.6, 0.3, -0.2] = [-0.28, 0.42, 0.21, -0.14]
        0.1x[0.7, -0.1, 0.0, 0.2]  =  [0.07, -0.01, 0.00, 0.02]
        --------------------------------------------------------
        Total                     = [-0.15, 0.45, 0.23, -0.02]
    
    
        Ahora "hoy" esta influenciado por el hecho de que es 
        martes, un contexto que antes no tenia. 
        + Esto es cierto porque esta sumando el valor de 
        [-0.28, 0.42, 0.21, -0.14] y eso es valioso, pero 
        tambien esta sumando los otros dos valores de hoy y 
        llueve, asi que no la influencia en realidad no es 
        solo de martes sino de los 3. 
    Sin embargo, al tener ‘martes' el mayor peso de atencion (0.7), su contribucion es la dominante, aunque numericamente no haya forma de reflejarlo." Esto es exactamente lo que permite que el modelo " entienda" relaciones.

    En realidad la atencion que vimos arriba es de un sola cabeza. Podemos decir que es de un solo punto de vista. Dijimos anteriormente que el unico punto de vista es un tabla pre-entrenada que se toma como base para definir la atencion.
    Pero en la practica GPT-2 tiene 12 cabezas, esto es para tener multiples puntos de vista o multiples atenciones para poder evaluar mejor los token y la relacion entre ellos (contexto).

    Contatenar Valores de los 12 headers

    Como operar ahora con 12 valores de cabezas:
    Aqui no sumamos los valores de las atenciones sino que las concatenamos.
    MultiHead(Q,K,V) = Concat(head₁, head₂, ..., headₙ) * Wᵒ
    Ejemplo:
    head1 = [0.5, -0.2]
        head2 = [1.3, 0.4]
    
        Concat = [0.5, -0.2, 1.3, 0.4]
        Resultado = Concat × Wᵒ
    Nota: Forma típica en GPT-2 (base) -> 768 × 768 -> Porque 12 cabezas × 64 dims = 768

    Aplicar Wº

    Cada head, claro que no SABE cual es la cabeza que tiene preferencia..... ya se que multiplica matrices. A lo que voy es IMPORTANTE es que PORQUE ? tengo 12 puntos de vista de como se puede entender una frase y solo uno o dos son mas preferente que los otros para darle sentido a la frase. El mecanismo es la matrix Wº que "deberia" de hacer prevalecer algunos valores mas que otros y de esta manera hacer que tome el contexto del token original y no le responda al usuario con alguna alucinacion.
    La matrix de forma matermatica simplemente se multiplica, los valores de la matriz en el entrenamiento es la MAGIA del asunto que hace funcionar al modelo.
    *** Ese mecanismo es lo que reduce la probabilidad de alucinaciones.
    No las elimina completamente (por eso ocurren)
    Embedding_Score_2 = Concat(head₁ ... head₁₂) @ Wº

    Resumen de Atencion

    1. ) calcular Q; K y V
    2. ) esto se obtiene de las matrices de datos pre-entrenados
      attention_scores = softmax(Q * K^T / √d_k)
    3. ) nuevo_embedding[i] = Σ (attention_scores x V)
    4. ) Concatenar los headers.
    5. ) aplicar Wº
  8. Residual Connection (Skip Connection):
    Embedding_Residual = X + Embedding_Score_2 

    Correcto.
    El embedding contextualizado por la atencion no reemplaza al original. Se combina con el mediante suma elemento a elemento.

    Esto es clave respecto a tu duda anterior:

    "Como se conserva la informacion original si la atencion lleva parte de ella hacia otro token?"

    Gracias al residual, el embedding mantiene parte de la representacion original (X) + la representacion contextualizada (Embedding_Score).
    Por eso no se pierde completamente el significado propio del token ya que es el Embedding 'X'

  9. LayerNorm
    embedding_Normalized = (x - media) / sqrt(varianza + epsilon)

    x = Es el vector anterior con el Residual.
    Ejemplo: x = [2.0, 0.5, 1.5, 3.0]

    Calculo de la Varianza:
    Media = es el promedio, = (2.0 + 0.5 + 1.5 + 3.0) / 4 = 1.75
    Varianza: Promedio de (x_i - media)^2
    Esto se hace con todos los valores del vector embedding :
    i xi  xi - media  (xi - media)^2 
    1) x= 2.0 --> 2.0 - 1.75 = 0.25 --> 0.25^2 = 0.0625
    Varianza= 0.0625
    Esto lo hacemos con todos las filas del vector:
    2) x= 0.5 --> 0.5 - 1.75 = -1.25 --> (-1.25)^2 = 1.5625

    Ahora hacemos el promedio:
    varianza = (0.0625 + 1.5625 + 0.0625 + 1.5625) / 4
    varianza = (3.25) / 4
    varianza = 0.8125

    Seguimos (para completar el concepto)
    Con epsilon = 1e-5 -> 0.00001
    sqrt(varianza + epsilon)
    = sqrt(0.8125 + 0.00001)
    ≈ sqrt(0.81251)
    ≈ 0.90139
    fin del segundo termino.

    Ahora el primer termino:
    x_normalizado = (x - media) / 0.90139
    Y aplicamos esto a cada uno de los valores del vector:
    [2.0 - 1.75] / 0.90139 = 0.25 / 0.90139 = 0.277
    [0.5 - 1.75] / 0.90139 = -1.25 / 0.90139 = -1.386
    [1.5 - 1.75] / 0.90139 = -0.25 / 0.90139 = -0.277
    [3.0 - 1.75] / 0.90139 = 1.25 / 0.90139 = 1.386
    ≈ [ 0.277, -1.386, -0.277, 1.386 ]

    Esto permite estabilizar los valores sin perder la direccion del vector.
    La forma (direccion) del vector sigue apuntando hacia donde apuntaba originalmente, pero ahora esta escalada con una media = 0 y varianza ≈ 1.

    Resumen:
    media ≈ (1.28864 + (-1.0993) + (-0.638) + 1.88958) / 4
    ≈ 0.36048
    varianza ≈ media((xi - media)^2)
    ≈ aprox 1.07

    desviacion estandar ≈ sqrt(1.07) ≈ 1.034

    embedding_Normalized = (Embedding_Residual - media) / desviacion estandar
    Resultado aprox:
    embedding_Normalized ≈ [ 0.894, -1.41, -0.97, 1.48 ]

  10. Feed Forward Network (FFN):
      Modelo simplificado:
      1a).Expansion: 4 -> 6
      1b).ReLU
      1c).Contraccion: 6 -> 4
      (los pesos son inventados para ilustrar el proceso, NO importan los valores exactos, sino la transformacion)

    1. Paso 1a). Proyeccion hacia dimension mayor:
      h1 = x_norm * W1 + b1
      Aqui W1 y b1 son pesos aprendedidos en el entrenamiento, los genera el sistema cuando se le entrena.
      Seguimos con el ejemplo anterior del ultimo vector normalizado:
      estos son ejemplos de w1=
      W1 =
              [
                [ 0.5, -0.3,  0.2,  0.0,  0.1, -0.4 ],
                [ 0.1,  0.7, -0.5,  0.3, -0.2,  0.6 ],
                [ 0.4, -0.1,  0.3, -0.2,  0.8,  0.5 ],
                [-0.2,  0.2,  0.4,  0.1,  0.3,  0.1 ]
              ]
      Esto es la bias o sesgo:
      b1 = [ 0.1, 0.0, 0.2, -0.1, 0.05, 0.0 ] 
      Este es un ejemplo de la columna 1 de multiplicar (x_norm * 1) + b1:
      0.277 x 0.5  =  0.1385
              -1.386 x 0.1 = -0.1386
              -0.277 x 0.4 = -0.1108
               1.386 x -0.2 = -0.2772
              -----------------------------------
              Suma parcial = -0.3881
              + b1[0] = 0.1
              = **-0.2881**
      Este es el resultado:
      h1 = [ -0.2881, -0.7484, 1.4197, -0.3218, 0.5491, -0.9423 ]
      (el primer resultado es el de la columna 1 )
      Resultado de las operaciones: Este vector ya cambio su direccion original (transformacion lineal).
      Ahora tiene dimension mayor (expansion a 6D) -> permite que la red capture relaciones mas complejas.

    2. Paso 1b). - Aplicacion de ReLU
      ReLU(x) = max(0, x)
      Los valores negativos se reemplazan por 0
      Los valores positivos quedan tal cual
      Resultado:
      h1_relu = [ 0,  0,  1.4197,  0,  0.5491,  0 ] 
      Se eliminaron dimensiones negativas -> se descartan activaciones no utiles.
      Se mantienen solo las que representan señales "activas".
      Se agrega no linealidad, lo cual permite al modelo aprender funciones complejas.
      Si solo usaramos X*W + b sin ReLU, todo seria lineal, y una sola capa equivaldria a toda la red (sin sumar capacidad estructural).
      Aqui puede cambiar de dimension al multiplicar una matriz no por las columnas sino por las filas y asi se puede agrandar o achivar.

    3. 1c). Contraccion: Segunda transformacion lineal
      Esto es como un red tradicional densa.
      output_ffn = h1_relu * W2 + b2  
              Empezamos desde : 
              
      h1_relu = [ 0, 0, 1.4197, 0, 0.5491, 0 ]
      Vuelve a dimension original (4 en este ejemplo)
      Esta capa reconvierte de la dimension expandida (6) a la original (4).
      Aqui puede cambiar de dimension al multiplicar una matriz no por las columnas sino por las filas y asi se puede agrandar o achivar.

      Proposito:
      W1: permite crear una representacion mas rica (mas dimensiones -> + capacidad expresiva).
      W2: reduce a la dimension original, integrando la informacion que W1 activo.

      resultado en numeros:
      output_ffn ≈ [ 1.01164,  0.2867,  -0.361,  0.50358 ]

    Resultado :
    Eso significa que W2 aprende a dar importancia solo a los rasgos relevantes generados por W1.
    W1 -> decide que rasgos activar (amplia el rango)
    ReLU -> descarta los no utiles
    W2 -> transforma esos rasgos activados en nueva representacion (reduce)

  11. Resumenes:
    Comparacion Completa:
    layerNorm genero[ 0.277 , -1.386 , -0.277, 1.386 ]
    1. Etapa Vector
    2. Entrada a FFN [ 0.277, -1.386, -0.277, 1.386 ]
    3. Salida FFN [ 1.01164, 0.2867, -0.361, 0.50358 ]
    4. Suma residual [ 1.28864, -1.0993, -0.638, 1.88958 ]
    5. LayerNorm final [ 0.894, -1.41, -0.97, 1.48 ]

    Interpretacion tecnica
    1. La FFN ajusta el embedding agregando una transformacion no lineal aprendida, que puede amplificar o reformular señales relevantes.
    2. La suma residual mantiene informacion original, evitando que la FFN modifique demasiado el sentido semantico.
    3. La LayerNorm estabiliza la escala, manteniendo el vector listo para pasar a la siguiente capa sin explotar ni colapsar activaciones.
    4. Este vector resultante es ahora el nuevo embedding de "hoy" despues de la capa completa de Transformer.

  12. Concepto de Capas: :
    Este concepto esta dado de poder revisar una y otra vez con el mismo procedimiento, lo que cambia es que la salida despues del procesamiento se puede refinar o ajustar.
    El principio nacio de la electronica hace varias decadas atras. Siempre usamos parte de la salida para reingresarla o reinyectarla para correccion o estabilizacion.
    Obviamente una maquina podria analizar todo de una sola vez y seria mas rapido pero seria mas complicado de manejar y lo que esta de moda ahora es usar mas y mas hardware y cada vez mas rapido y cada vez mas almacenamiento, asi que hoy en dia es algo que podemos usar con una espectatvia que va a seguir ocurriendo de esta manera.
    El proceso se hara segun el modelo, chat GPT puede hacerlo 96 veces.

    Ahora un EJEMPLO
    Este ejemplo no es mio, sino que se lo pedi a chatGPT, es lo adecuado ya que ella me dice como 'piensa'.
    Lo que tenemos que tener en cuenta es que:
    1. ) La AI no piensa,
    2. ) La AI aprovecha lo que hemos cosechado por varios anos ( internet y una cantidad ENORME de informacion digital),
    3. ) el lenguaje es finito. Aunque parezca que no lo es, y que hay infinitas palabras y que hay un combinacion infitas de como poner las palabras, NO lo es.
      Tenemos unas cuentos cientos de palabras que usamos normalmete, y claro, hay personas que conocen muchas mas palabras y conocen muchas mas estructuras para formarla, pero lo normal es que son pocas cientas de palabras , incluso para aprender un idioma con 500 palabras estaria bien.
    4. La AI no es linguistica, es decir, contetara de forma general cuando no tengo informacion.
      Cuando no tenga una respuesta al 100% no le importara, solo resolvera con el porcentaje mas cercano. El problema NO es de ella, es SUYO. Si usted lee, analize y compara con otros escritos y experiencia podra saber si la AI esta delirando o no. Un ejemplo de esto es que yo personalizo GPT y le exigo que cuando NO sepa, o no esta segura me escribe (verificar) al lado del texto. Y me escribe esto muchisimas veces y ademas otras veces no me lo escribe y la regaño porque esta haciendo trampa.
    Empezamos
    1. Frase: "Hoy martes llueve, asi que..."

    2. Capa 1 - Entiende relaciones basicas (lo que ya viste)
      Token Representacion semantica tras capa 1
      "hoy" [es dia actual, relacionado con martes]
      "martes" [tercer dia de semana, se identifica como fecha actual]
      "llueve" [evento climatico presente]
      Correlaciones simples, directas.

    3. Capa 2 - Empieza a deducir implicaciones
      Las relaciones empiezan a cruzarse entre si.
      Token Representacion tras capa 2
      "hoy" [dia actual y lluvioso -> posible accion afectada]
      "martes" [dia laboral tipico -> posible rutina diaria]
      "llueve" [contexto meteorologico -> afecta movilidad]
      Ya hay inferencia causal leve.

    4. Capa 3 - Incorporacion de conocimiento aprendido durante entrenamiento
      El modelo utiliza patrones comunes del dataset.
      Ahora cada token contiene informacion propia + informacion proveniente del contexto. Esta relacion no se obtiene consultando el dataset, sino aplicando patrones aprendidos durante el entrenamiento. En inferencia no se accede al dataset, solo se utilizan los pesos que capturan ese conocimiento.
      Nota: Como se dara cuenta esta es una expliccion absurdamente computacional.
      analizando:
      1. coocurrencias frecuentes
      2. relaciones sintacticas
      3. relaciones semanticas
      4. estructuras linguisticas tipicas
      5. implicaciones causales comunes
      6. dependencia contextual
      Durante entrenamiento el modelo ve ejemplos como:
      "Si llueve, llevo paraguas"
      "Esta lloviendo, me voy en coche"
      "Lluvia -> paraguas"
      Estas frases generan gradientes que modifican los pesos, de forma que:
      Tokens como ("llueve", "paraguas") adquieren embeddings que tienen alta similitud
      Nota: Asi que patrones aprendidos se refiere a: adquieren embeddings que tienen alta similitud.
      Otro ejemplo:
      Entrada Resultado esperado
      "El perro ladra" --> al
      "El gato maulla" --> por
      "Hace frio, llevo…" --> abrigo
      "Hace calor, llevo…" --> camiseta
      Nota: Los "patrones" para los humanos es la logica, vemos un dibujo y que sabemos que es, facil, vemos un dibujo de un niño y ya sabemos que es (al menos los papas sabemos).
      Una maquina entraria en un bucle infinito... son relaciones muy complejas de logicas, estructura de lenguaje, etc.
      Pero lo que si hace es como vimos arriba: asociar Lluvia y paraguas con un numero similar. Asi que esa palabra cerca de la otra indica algo probable no ningun patron humano aprendido o logica de entendimiento, solamente hay una relacion matematica numerica.

      Token Representacion tras capa 3
      "hoy" [dia actual + clima -> puede influir en decision posterior]*
      "martes" [dia normal de semana, no festividad -> rutina normal]*
      "llueve" [probablemente implica proteccion (paraguas), trafico, ropa]*
      Aqui aparecen asociaciones aprendidas ("llueve" -> paraguas).

    5. Capa 4 - Contextualizacion con sintaxis de la frase
      Empieza a prepararse para decidir que sigue.
      Token Representacion tras capa 4
      "hoy" [dia con situacion contextual relevante -> se espera consumo logico]
      "llueve" [clima -> podria sugerir accion futura]
      "lunes/martes/etc." [baja relevancia para accion pero util en coherencia]
      "hoy" empieza a "preguntarse": .que deberia venir despues?

    6. Capa N-1 - Comprension semantica de alto nivel
      Se integran todas las inferencias.
      Token Representacion
      "hoy" [contexto personal + meteorologico -> consecuencias sobre logistica o decisiones ("llevar paraguas")]
      "llueve" [condicion causal prioritaria sobre el token siguiente]
      Aqui la red entiende el proposito de la frase.
      Nota: Como habra visto la cantidad de variacion que hay que tener en cuenta son de millones y millones y mas y mas. Bueno el hardware de las tarjetas de video ha sido muy bien aporvechado, incluso hay una empresa que aora hace chips especialmente dirigidos para AI.
      Un ejemplo, es tratar de enseñarle a un niño como debe de responder socialmente.. Hay tantas cosas que puede decir mal en un reunion social, que cuando un niño habla los papas ponen atencion, porque podria decir que le gusta el pastel o que ayer noche hecho a su papa diciendo a su mama: quiero mas y mas...
      No nos enfocamos a enseñarle a los niños que decir y que no decir TODO el tiempo, sino seria chat GPT, le ensenamos a entender a crear la logica de que las cosas personales no son para contarlas en una reunion y que ponerse en el lugar de la otra persona es importante porque nos hace ser respetuosos.

    7. Ultima capa - Proyeccion hacia salida
      Ya no esta pensando en descripcion, sino en que token completar.
      Embedding "llueve" -> "por eso" -> alta probabilidad de "llevar" / "usar" / "paraguas"
      Salida final de ejemplo
      "Hoy martes llueve, asi que ... me llevo un paraguas."
      El modelo podria generar probabilidades asi:
      Token probabilidad
      llevar 0.18
      sacar 0.05
      paraguas 0.64 ← destino final
      abrigo 0.03
      coche 0.01

      Dónde se ven más los cambios?

      1. Capas bajas (primeras) o Más “locales”:
        Subpalabras (token + iz + acion), vecinos inmediatos.
        Patrones muy de superficie: mayúsculas, signos, estructura corta.
        Más sintaxis básica / forma.
      2. Capas medias
        Mezcla:
        Sintaxis más compleja (sujeto–verbo–objeto).
        Dependencias algo más largas.
        Entidades empezando a estabilizarse.
      3. Capas altas (últimas)
        Más “globales / semánticas”:
        Relación entre partes distantes de la frase o párrafos.
        Coherencia del mensaje (qué se está diciendo).
        Tokens “clave” que resumen el sentido.
    8. Analisis segun las cabezas
      Segun dijimos las cabezas es la atencion desde diferentes matrices pre-entrenadas lo que puede tomar distintos punto de vista y contextos.
      Cabeza En capas bajas ve… En capas altas ve…
      Head 1 subpalabras adyacentes palabras clave distantes
      Head 3 signos o estructura token de inicio o resumen
      Head 7 entidades (Ej: “Madrid”) qué tipo de contexto tiene
      Head 12 último token o separadores coherencia global
      Creo que es un gran ejemplo, aunque hay que verificarlo con resultado practicos.
  13. Resumen tecnico de evolucion de capas:
    Que aporta cada capa
    1 Entiende relaciones inmediatas
    2 Deduccion leve
    3 Saberes aprendidos del dataset
    4-N-2 Coherencia linguistica y relacional
    N-1 Preparacion para inferir intencion
    N Conversion a probabilidad sobre vocabulario

    Ejemplo real sobre la atencion

    Sobre la frase que vimos al inicio.
    Los valores de atencion que se muestran es sobre un token en particular, no es la ponderacion de la frase completa. desde ‘real’ → hacia los demás, o sea, la atencion que le da real a los demas tokens.
    === ANALISIS COMPARATIVO DE ATENCION ===
    Capas con atención: 12
    Token analizado idx = 17 , texto = ' real'

    ----- CAPA primera (0) -----
    num_heads = 12, seq_len = 20
    
         Cabeza 1 (índice Python 0):
          Top 5 tokens más atendidos:
            idx= 7  token=' es'            peso=0.0994
            idx= 2  token=' mund'          peso=0.0985
            idx= 0  token='H'              peso=0.0969
            idx=10  token=' pr'            peso=0.0858
            idx=14  token=' token'         peso=0.0834
    
         Cabeza 12 (índice Python 11):
          Top 5 tokens más atendidos:
            idx= 0  token='H'              peso=0.1710
            idx= 5  token='Est'            peso=0.1124
            idx= 4  token='\n'             peso=0.0945
            idx= 8  token=' un'            peso=0.0794
            idx=17  token=' real'          peso=0.0693
      
    Aqui se puede ver que en la capa uno solo tiene un relacion muy lejana. Pero en la cabeza 12 la atencion es mucho mas cercana a un,real y el salto de linea.
    Ahora probamos con la ultima capa:
    ----- CAPA última (-1) -----
    num_heads = 12, seq_len = 20
         Cabeza 1 (índice Python 0):
          Top 5 tokens más atendidos:
            idx= 0  token='H'              peso=0.3917
            idx= 8  token=' un'            peso=0.0961
            idx= 7  token=' es'            peso=0.0918
            idx= 2  token=' mund'          peso=0.0621
            idx=13  token=' de'            peso=0.0506
    
         Cabeza 12 (índice Python 11):
          Top 5 tokens más atendidos:
            idx= 0  token='H'              peso=0.5678
            idx=12  token='ba'             peso=0.1157
            idx= 9  token='a'              peso=0.0880
            idx= 6  token='a'              peso=0.0386
            idx=16  token='acion'          peso=0.0337
      
    Aqui la diferencia es bastante mas grande entre la cabeza 1 y la ultima cabeza.
    Aún más extrema:
    ~57 % de la atención va a 'H'.
    Algo de peso en 'ba' (de “prueba”), 'a', 'acion'.
    Claramente una cabeza de “contexto global” muy fuerte: para ' real', casi todo lo recupera vía el primer token.

  14. Como evoluciona el embeddings en capas
    === EVOLUCION DEL TOKEN idx = 17 , texto = ' ia' ===
    Aqui me encontre con algo muy interesante. GPT 'sabe' que cuando empieza con hola, va por hola mundo y demas.
    Asi que vamos a cambiar la frase para tokenizar : Hoy llueve pero mañana hará sol si no cambia el viento.
        ***** ANALISIS LOCAL vs GLOBAL POR CABEZA (ultima capa) *****
    
        Token analizado idx=17, texto='ia'
        Ventana local: ±3 tokens
    
        Cabeza  1: GLOBAL | local=0.09 | top= 4 've'         w=0.1535
        Cabeza  2: GLOBAL | local=0.04 | top= 0 'H'          w=0.5709
        Cabeza  3: GLOBAL | local=0.00 | top= 0 'H'          w=0.8434
        Cabeza  4: GLOBAL | local=0.04 | top= 0 'H'          w=0.7307
        Cabeza  5: GLOBAL | local=0.10 | top= 0 'H'          w=0.3323
        Cabeza  6: GLOBAL | local=0.27 | top= 9 'ana'        w=0.1744
        Cabeza  7: GLOBAL | local=0.04 | top= 0 'H'          w=0.3942
        Cabeza  8: GLOBAL | local=0.13 | top= 0 'H'          w=0.3993
        Cabeza  9: GLOBAL | local=0.36 | top=17 'ia'         w=0.2922
        Cabeza 10: GLOBAL | local=0.02 | top= 0 'H'          w=0.6924
        Cabeza 11: GLOBAL | local=0.15 | top= 0 'H'          w=0.4112
        Cabeza 12: GLOBAL | local=0.16 | top= 0 'H'          w=0.4600
      
    Todas las cabezas salen como GLOBAL con el umbral que pusiste (ratio_local < 0.5):
    Es decir, menos del 50 % de la atención está en los vecinos ±3 posiciones.
    La mayor parte de la probabilidad se va a tokens lejanos (sobre todo índice 0 'H' y otros fuera de la ventana).
    Patrón dominante:
    En muchas cabezas, el top es 'H' con pesos muy altos (0.57, 0.84, 0.73, 0.69, etc.).
    Esto indica que en la última capa, para 'ia', el modelo usa el inicio 'H' como ancla de contexto global (igual que te pasó con ' real').
    (verificar con otras frases más largas)
    Cabezas “distintas”:
    Cabeza 1: top = 've' → está conectando 'ia' con alguna parte media ('e').
    Cabeza 6: top = 'ana' → local respecto a “mañana” (probable subtoken).
    Cabeza 9: top = 'ia' → se mira a sí mismo (refuerza su propia representación).

    evolución del embedding de 'ia' por capa

     Capa  0: norma=4.8473, media=-0.0000
        Capa  1: norma=54.2466, media=0.0180
        Capa  2: norma=60.2778, media=0.0158
        Capa  3: norma=66.8600, media=0.0163
        Capa  4: norma=71.2855, media=0.0082
        Capa  5: norma=80.0347, media=0.0141
        Capa  6: norma=84.9959, media=0.0139
        Capa  7: norma=92.5661, media=0.0280
        Capa  8: norma=103.3779, media=0.0379
        Capa  9: norma=113.4324, media=0.0333
        Capa 10: norma=147.4632, media=0.0618
        Capa 11: norma=214.7635, media=0.1528
        Capa 12: norma=216.8823, media=0.4136
      
    Capas 11–12
    Explosión fuerte → el modelo está construyendo la representación final para inferencia. Representación altamente contextual, optimizada para generar el siguiente token.
    a media también pasa de negativa casi cero (-0.0003) a positiva (+0.4405) → el embedding pasa de casi neutro a una activación fuerte y sesgada hacia el significado final de la frase.
    “El modelo está usando el token inicial como referencia global para estabilizar el significado final de toda la secuencia.”
    Esto le parecera una locura porque el analisis de atencion esta mal, y es cierto. Lo que pasa el que la despues de normalizar se compensar el resultado. Evidentemente no sabe de sintaxis.

    Analises entre capas

    Hemos visto como cambia las capas.
    Tambien vimos para el factor de atencion puede cambiar capa tras capa, ademas de que son varios headers o atenciones.
    En nuestros vector usamos 768 direcciones, asi que nuestro vector es grande.
    Cuanto mas atencion tenga el vector se puedes hacer mas o menso y tambien mas pequeño pero el vector podria seguir apuntando hacia la mismo direccion.
    Para obtener de cuanto cambia un vector en cuanto a direccion usamos el coseno, es que solo una relacion entre sus vector.
    El token puede apuntar hacia un token y eso seria el significado, puede apuntar mucho o poco.
    Pero cuando apunta hacia otro token, cambia el significado o semantica.
    Asi que podemos ver como un vector puede cambiar su significado capa a capa.
    La AI empezo con un sentido semantico y ahora tiene otro.

    **** SIMILITUD COSENO ENTRE CAPA 0 Y CAPA FINAL ===
    Similitud coseno entre capa 0 y capa final para token 'ia': -0.1577
    Valor cercano a 0 y además negativo → los vectores de capa 0 y capa 12 apuntan casi a direcciones “ortogonales/tirando a opuestas”.

    Traducción en “significado”:

    El embedding final de 'ia' no se parece en casi nada a su embedding inicial.
    El modelo ha re-interpretado completamente ese token con el contexto de la frase.

    Embeddings capa a capa:

        Similitud coseno entre capas sucesivas:
      Capa  0 -> Capa  1: sim=0.1011
      Capa  1 -> Capa  2: sim=0.9581
      Capa  2 -> Capa  3: sim=0.9657
      Capa  3 -> Capa  4: sim=0.9608
      Capa  4 -> Capa  5: sim=0.9721
      Capa  5 -> Capa  6: sim=0.9789
      Capa  6 -> Capa  7: sim=0.9578
      Capa  7 -> Capa  8: sim=0.9576
      Capa  8 -> Capa  9: sim=0.9678
      Capa  9 -> Capa 10: sim=0.9462
      Capa 10 -> Capa 11: sim=0.9193
      Capa 11 -> Capa 12: sim=0.2838

    La norma sube mucho (vector más “fuerte”). El coseno 0→12 ≈ −0.16 indica que el vector final está casi en otra dirección → el contexto reescribe su significado.
    Los cambios grandes están en:
    0→1 (primera interpretación contextual),
    11→12 (ajuste final para la salida).

    Comparativa token 'ia' vs token 'ana' por capa:

    Capa  0: sim=0.6597
        Capa  1: sim=0.8559
        Capa  2: sim=0.8475
        Capa  3: sim=0.8145
        Capa  4: sim=0.7909
        Capa  5: sim=0.8056
        Capa  6: sim=0.8099
        Capa  7: sim=0.8277
        Capa  8: sim=0.8632
        Capa  9: sim=0.8837
        Capa 10: sim=0.9072
        Capa 11: sim=0.9407
        Capa 12: sim=0.9984
      
    En las últimas capas, GPT-2 considera que “estudiar” está casi completamente conectado con lo que ocurrirá “mañana”.
    El modelo codifica internamente la relación de causa-efecto y temporalidad entre ambos tokens.
    No significa que los trate como sinónimos, sino que comparte contexto fuertemente al momento de construir la representación final para predicción.
    'mañana' depende de 'estudias'
    'entender' depende de 'mañana'
    estudias ───────────▶ afecta ▶ mañana ──────────▶ afecta ▶ entender
               │                     │                             │
              capa 0: aislado        capa 6: vinculado             capa 12: casi fusionado
      
    Tambien se podria hacer esta comparacion: 1. Comparar 'mañana' con 'entender'
  15. Sobre por qué aún hay alucinaciones:
    Porque:
    El mecanismo depende de datos de entrenamiento.
    Si todas las cabezas extraen interpretaciones malas (contenido inventado), Wº no puede corregirlo.
    GPT-2 no tiene mecanismo explícito de veracidad, solo de coherencia lingüística.
  16. Texto
    PERO no tienes la cabeza de lenguaje (LM head) que convierte esos vectores en probabilidades sobre el vocabulario (logits).
    Es decir: con AutoModel NO estás listo para generar texto todavía.