5. Arquitectura LLM
Reading time: 20 minutes
tip
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripci贸n!
- 脷nete al 馃挰 grupo de Discord o al grupo de telegram o s铆guenos en Twitter 馃惁 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Arquitectura LLM
tip
El objetivo de esta quinta fase es muy simple: Desarrollar la arquitectura del LLM completo. Juntar todo, aplicar todas las capas y crear todas las funciones para generar texto o transformar texto a IDs y viceversa.
Esta arquitectura se utilizar谩 tanto para entrenar como para predecir texto despu茅s de haber sido entrenada.
Ejemplo de arquitectura LLM de https://github.com/rasbt/LLMs-from-scratch/blob/main/ch04/01_main-chapter-code/ch04.ipynb:
Se puede observar una representaci贸n de alto nivel en:
 (1) (1) (1).png)
- Entrada (Texto Tokenizado): El proceso comienza con texto tokenizado, que se convierte en representaciones num茅ricas.
- Capa de Embedding de Tokens y Capa de Embedding Posicional: El texto tokenizado se pasa a trav茅s de una capa de embedding de tokens y una capa de embedding posicional, que captura la posici贸n de los tokens en una secuencia, cr铆tica para entender el orden de las palabras.
- Bloques de Transformer: El modelo contiene 12 bloques de transformer, cada uno con m煤ltiples capas. Estos bloques repiten la siguiente secuencia:
- Atenci贸n Multi-Cabeza enmascarada: Permite que el modelo se enfoque en diferentes partes del texto de entrada a la vez.
- Normalizaci贸n de Capa: Un paso de normalizaci贸n para estabilizar y mejorar el entrenamiento.
- Capa Feed Forward: Responsable de procesar la informaci贸n de la capa de atenci贸n y hacer predicciones sobre el siguiente token.
- Capas de Dropout: Estas capas previenen el sobreajuste al eliminar aleatoriamente unidades durante el entrenamiento.
- Capa de Salida Final: El modelo produce un tensor de 4x50,257 dimensiones, donde 50,257 representa el tama帽o del vocabulario. Cada fila en este tensor corresponde a un vector que el modelo utiliza para predecir la siguiente palabra en la secuencia.
- Objetivo: El objetivo es tomar estos embeddings y convertirlos de nuevo en texto. Espec铆ficamente, la 煤ltima fila de la salida se utiliza para generar la siguiente palabra, representada como "adelante" en este diagrama.
Representaci贸n de C贸digo
import torch
import torch.nn as nn
import tiktoken
class GELU(nn.Module):
def __init__(self):
super().__init__()
def forward(self, x):
return 0.5 * x * (1 + torch.tanh(
torch.sqrt(torch.tensor(2.0 / torch.pi)) *
(x + 0.044715 * torch.pow(x, 3))
))
class FeedForward(nn.Module):
def __init__(self, cfg):
super().__init__()
self.layers = nn.Sequential(
nn.Linear(cfg["emb_dim"], 4 * cfg["emb_dim"]),
GELU(),
nn.Linear(4 * cfg["emb_dim"], cfg["emb_dim"]),
)
def forward(self, x):
return self.layers(x)
class MultiHeadAttention(nn.Module):
def __init__(self, d_in, d_out, context_length, dropout, num_heads, qkv_bias=False):
super().__init__()
assert d_out % num_heads == 0, "d_out must be divisible by num_heads"
self.d_out = d_out
self.num_heads = num_heads
self.head_dim = d_out // num_heads # Reduce the projection dim to match desired output dim
self.W_query = nn.Linear(d_in, d_out, bias=qkv_bias)
self.W_key = nn.Linear(d_in, d_out, bias=qkv_bias)
self.W_value = nn.Linear(d_in, d_out, bias=qkv_bias)
self.out_proj = nn.Linear(d_out, d_out) # Linear layer to combine head outputs
self.dropout = nn.Dropout(dropout)
self.register_buffer('mask', torch.triu(torch.ones(context_length, context_length), diagonal=1))
def forward(self, x):
b, num_tokens, d_in = x.shape
keys = self.W_key(x) # Shape: (b, num_tokens, d_out)
queries = self.W_query(x)
values = self.W_value(x)
# We implicitly split the matrix by adding a `num_heads` dimension
# Unroll last dim: (b, num_tokens, d_out) -> (b, num_tokens, num_heads, head_dim)
keys = keys.view(b, num_tokens, self.num_heads, self.head_dim)
values = values.view(b, num_tokens, self.num_heads, self.head_dim)
queries = queries.view(b, num_tokens, self.num_heads, self.head_dim)
# Transpose: (b, num_tokens, num_heads, head_dim) -> (b, num_heads, num_tokens, head_dim)
keys = keys.transpose(1, 2)
queries = queries.transpose(1, 2)
values = values.transpose(1, 2)
# Compute scaled dot-product attention (aka self-attention) with a causal mask
attn_scores = queries @ keys.transpose(2, 3) # Dot product for each head
# Original mask truncated to the number of tokens and converted to boolean
mask_bool = self.mask.bool()[:num_tokens, :num_tokens]
# Use the mask to fill attention scores
attn_scores.masked_fill_(mask_bool, -torch.inf)
attn_weights = torch.softmax(attn_scores / keys.shape[-1]**0.5, dim=-1)
attn_weights = self.dropout(attn_weights)
# Shape: (b, num_tokens, num_heads, head_dim)
context_vec = (attn_weights @ values).transpose(1, 2)
# Combine heads, where self.d_out = self.num_heads * self.head_dim
context_vec = context_vec.contiguous().view(b, num_tokens, self.d_out)
context_vec = self.out_proj(context_vec) # optional projection
return context_vec
class LayerNorm(nn.Module):
def __init__(self, emb_dim):
super().__init__()
self.eps = 1e-5
self.scale = nn.Parameter(torch.ones(emb_dim))
self.shift = nn.Parameter(torch.zeros(emb_dim))
def forward(self, x):
mean = x.mean(dim=-1, keepdim=True)
var = x.var(dim=-1, keepdim=True, unbiased=False)
norm_x = (x - mean) / torch.sqrt(var + self.eps)
return self.scale * norm_x + self.shift
class TransformerBlock(nn.Module):
def __init__(self, cfg):
super().__init__()
self.att = MultiHeadAttention(
d_in=cfg["emb_dim"],
d_out=cfg["emb_dim"],
context_length=cfg["context_length"],
num_heads=cfg["n_heads"],
dropout=cfg["drop_rate"],
qkv_bias=cfg["qkv_bias"])
self.ff = FeedForward(cfg)
self.norm1 = LayerNorm(cfg["emb_dim"])
self.norm2 = LayerNorm(cfg["emb_dim"])
self.drop_shortcut = nn.Dropout(cfg["drop_rate"])
def forward(self, x):
# Shortcut connection for attention block
shortcut = x
x = self.norm1(x)
x = self.att(x) # Shape [batch_size, num_tokens, emb_size]
x = self.drop_shortcut(x)
x = x + shortcut # Add the original input back
# Shortcut connection for feed forward block
shortcut = x
x = self.norm2(x)
x = self.ff(x)
x = self.drop_shortcut(x)
x = x + shortcut # Add the original input back
return x
class GPTModel(nn.Module):
def __init__(self, cfg):
super().__init__()
self.tok_emb = nn.Embedding(cfg["vocab_size"], cfg["emb_dim"])
self.pos_emb = nn.Embedding(cfg["context_length"], cfg["emb_dim"])
self.drop_emb = nn.Dropout(cfg["drop_rate"])
self.trf_blocks = nn.Sequential(
*[TransformerBlock(cfg) for _ in range(cfg["n_layers"])])
self.final_norm = LayerNorm(cfg["emb_dim"])
self.out_head = nn.Linear(
cfg["emb_dim"], cfg["vocab_size"], bias=False
)
def forward(self, in_idx):
batch_size, seq_len = in_idx.shape
tok_embeds = self.tok_emb(in_idx)
pos_embeds = self.pos_emb(torch.arange(seq_len, device=in_idx.device))
x = tok_embeds + pos_embeds # Shape [batch_size, num_tokens, emb_size]
x = self.drop_emb(x)
x = self.trf_blocks(x)
x = self.final_norm(x)
logits = self.out_head(x)
return logits
GPT_CONFIG_124M = {
"vocab_size": 50257, # Vocabulary size
"context_length": 1024, # Context length
"emb_dim": 768, # Embedding dimension
"n_heads": 12, # Number of attention heads
"n_layers": 12, # Number of layers
"drop_rate": 0.1, # Dropout rate
"qkv_bias": False # Query-Key-Value bias
}
torch.manual_seed(123)
model = GPTModel(GPT_CONFIG_124M)
out = model(batch)
print("Input batch:\n", batch)
print("\nOutput shape:", out.shape)
print(out)
Funci贸n de Activaci贸n GELU
# From https://github.com/rasbt/LLMs-from-scratch/tree/main/ch04
class GELU(nn.Module):
def __init__(self):
super().__init__()
def forward(self, x):
return 0.5 * x * (1 + torch.tanh(
torch.sqrt(torch.tensor(2.0 / torch.pi)) *
(x + 0.044715 * torch.pow(x, 3))
))
Prop贸sito y Funcionalidad
- GELU (Unidad Lineal de Error Gaussiano): Una funci贸n de activaci贸n que introduce no linealidad en el modelo.
- Activaci贸n Suave: A diferencia de ReLU, que anula las entradas negativas, GELU mapea suavemente las entradas a salidas, permitiendo valores peque帽os y no nulos para entradas negativas.
- Definici贸n Matem谩tica:
 (1) (1) (1).png)
tip
El objetivo del uso de esta funci贸n despu茅s de las capas lineales dentro de la capa FeedForward es cambiar los datos lineales a no lineales para permitir que el modelo aprenda relaciones complejas y no lineales.
Red Neuronal FeedForward
Las formas se han a帽adido como comentarios para entender mejor las formas de las matrices:
# From https://github.com/rasbt/LLMs-from-scratch/tree/main/ch04
class FeedForward(nn.Module):
def __init__(self, cfg):
super().__init__()
self.layers = nn.Sequential(
nn.Linear(cfg["emb_dim"], 4 * cfg["emb_dim"]),
GELU(),
nn.Linear(4 * cfg["emb_dim"], cfg["emb_dim"]),
)
def forward(self, x):
# x shape: (batch_size, seq_len, emb_dim)
x = self.layers[0](x)# x shape: (batch_size, seq_len, 4 * emb_dim)
x = self.layers[1](x) # x shape remains: (batch_size, seq_len, 4 * emb_dim)
x = self.layers[2](x) # x shape: (batch_size, seq_len, emb_dim)
return x # Output shape: (batch_size, seq_len, emb_dim)
Prop贸sito y Funcionalidad
- Red FeedForward por Posici贸n: Aplica una red completamente conectada de dos capas a cada posici贸n de manera separada e id茅ntica.
- Detalles de la Capa:
- Primera Capa Lineal: Expande la dimensionalidad de
emb_dim
a4 * emb_dim
. - Activaci贸n GELU: Aplica no linealidad.
- Segunda Capa Lineal: Reduce la dimensionalidad de nuevo a
emb_dim
.
tip
Como puedes ver, la red Feed Forward utiliza 3 capas. La primera es una capa lineal que multiplicar谩 las dimensiones por 4 usando pesos lineales (par谩metros a entrenar dentro del modelo). Luego, se utiliza la funci贸n GELU en todas esas dimensiones para aplicar variaciones no lineales y capturar representaciones m谩s ricas y, finalmente, se utiliza otra capa lineal para volver al tama帽o original de las dimensiones.
Mecanismo de Atenci贸n Multi-Cabeza
Esto ya fue explicado en una secci贸n anterior.
Prop贸sito y Funcionalidad
- Autoatenci贸n Multi-Cabeza: Permite que el modelo se enfoque en diferentes posiciones dentro de la secuencia de entrada al codificar un token.
- Componentes Clave:
- Consultas, Claves, Valores: Proyecciones lineales de la entrada, utilizadas para calcular puntajes de atenci贸n.
- Cabezas: M煤ltiples mecanismos de atenci贸n que funcionan en paralelo (
num_heads
), cada uno con una dimensi贸n reducida (head_dim
). - Puntajes de Atenci贸n: Calculados como el producto punto de consultas y claves, escalados y enmascarados.
- Enmascaramiento: Se aplica una m谩scara causal para evitar que el modelo preste atenci贸n a tokens futuros (importante para modelos autorregresivos como GPT).
- Pesos de Atenci贸n: Softmax de los puntajes de atenci贸n enmascarados y escalados.
- Vector de Contexto: Suma ponderada de los valores, de acuerdo con los pesos de atenci贸n.
- Proyecci贸n de Salida: Capa lineal para combinar las salidas de todas las cabezas.
tip
El objetivo de esta red es encontrar las relaciones entre tokens en el mismo contexto. Adem谩s, los tokens se dividen en diferentes cabezas para prevenir el sobreajuste, aunque las relaciones finales encontradas por cabeza se combinan al final de esta red.
Adem谩s, durante el entrenamiento se aplica una m谩scara causal para que los tokens posteriores no se tengan en cuenta al buscar las relaciones espec铆ficas con un token y tambi茅n se aplica un dropout para prevenir el sobreajuste.
Normalizaci贸n de Capa
# From https://github.com/rasbt/LLMs-from-scratch/tree/main/ch04
class LayerNorm(nn.Module):
def __init__(self, emb_dim):
super().__init__()
self.eps = 1e-5 # Prevent division by zero during normalization.
self.scale = nn.Parameter(torch.ones(emb_dim))
self.shift = nn.Parameter(torch.zeros(emb_dim))
def forward(self, x):
mean = x.mean(dim=-1, keepdim=True)
var = x.var(dim=-1, keepdim=True, unbiased=False)
norm_x = (x - mean) / torch.sqrt(var + self.eps)
return self.scale * norm_x + self.shift
Prop贸sito y Funcionalidad
- Layer Normalization: Una t茅cnica utilizada para normalizar las entradas a trav茅s de las caracter铆sticas (dimensiones de embedding) para cada ejemplo individual en un lote.
- Componentes:
eps
: Una constante peque帽a (1e-5
) a帽adida a la varianza para prevenir la divisi贸n por cero durante la normalizaci贸n.scale
yshift
: Par谩metros aprendibles (nn.Parameter
) que permiten al modelo escalar y desplazar la salida normalizada. Se inicializan en unos y ceros, respectivamente.- Proceso de Normalizaci贸n:
- Calcular Media (
mean
): Calcula la media de la entradax
a trav茅s de la dimensi贸n de embedding (dim=-1
), manteniendo la dimensi贸n para la difusi贸n (keepdim=True
). - Calcular Varianza (
var
): Calcula la varianza dex
a trav茅s de la dimensi贸n de embedding, tambi茅n manteniendo la dimensi贸n. El par谩metrounbiased=False
asegura que la varianza se calcule utilizando el estimador sesgado (dividiendo porN
en lugar deN-1
), lo cual es apropiado al normalizar sobre caracter铆sticas en lugar de muestras. - Normalizar (
norm_x
): Resta la media dex
y divide por la ra铆z cuadrada de la varianza m谩seps
. - Escalar y Desplazar: Aplica los par谩metros aprendibles
scale
yshift
a la salida normalizada.
tip
El objetivo es asegurar una media de 0 con una varianza de 1 a trav茅s de todas las dimensiones del mismo token. El objetivo de esto es estabilizar el entrenamiento de redes neuronales profundas al reducir el cambio interno de covariables, que se refiere al cambio en la distribuci贸n de las activaciones de la red debido a la actualizaci贸n de par谩metros durante el entrenamiento.
Bloque Transformer
Las formas se han a帽adido como comentarios para entender mejor las formas de las matrices:
# From https://github.com/rasbt/LLMs-from-scratch/tree/main/ch04
class TransformerBlock(nn.Module):
def __init__(self, cfg):
super().__init__()
self.att = MultiHeadAttention(
d_in=cfg["emb_dim"],
d_out=cfg["emb_dim"],
context_length=cfg["context_length"],
num_heads=cfg["n_heads"],
dropout=cfg["drop_rate"],
qkv_bias=cfg["qkv_bias"]
)
self.ff = FeedForward(cfg)
self.norm1 = LayerNorm(cfg["emb_dim"])
self.norm2 = LayerNorm(cfg["emb_dim"])
self.drop_shortcut = nn.Dropout(cfg["drop_rate"])
def forward(self, x):
# x shape: (batch_size, seq_len, emb_dim)
# Shortcut connection for attention block
shortcut = x # shape: (batch_size, seq_len, emb_dim)
x = self.norm1(x) # shape remains (batch_size, seq_len, emb_dim)
x = self.att(x) # shape: (batch_size, seq_len, emb_dim)
x = self.drop_shortcut(x) # shape remains (batch_size, seq_len, emb_dim)
x = x + shortcut # shape: (batch_size, seq_len, emb_dim)
# Shortcut connection for feedforward block
shortcut = x # shape: (batch_size, seq_len, emb_dim)
x = self.norm2(x) # shape remains (batch_size, seq_len, emb_dim)
x = self.ff(x) # shape: (batch_size, seq_len, emb_dim)
x = self.drop_shortcut(x) # shape remains (batch_size, seq_len, emb_dim)
x = x + shortcut # shape: (batch_size, seq_len, emb_dim)
return x # Output shape: (batch_size, seq_len, emb_dim)
Prop贸sito y Funcionalidad
- Composici贸n de Capas: Combina atenci贸n multi-cabeza, red de avance, normalizaci贸n de capas y conexiones residuales.
- Normalizaci贸n de Capas: Aplicada antes de las capas de atenci贸n y avance para un entrenamiento estable.
- Conexiones Residuales (Atajos): A帽aden la entrada de una capa a su salida para mejorar el flujo de gradientes y permitir el entrenamiento de redes profundas.
- Dropout: Aplicado despu茅s de las capas de atenci贸n y avance para regularizaci贸n.
Funcionalidad Paso a Paso
- Primer Camino Residual (Autoatenci贸n):
- Entrada (
shortcut
): Guarda la entrada original para la conexi贸n residual. - Norma de Capa (
norm1
): Normaliza la entrada. - Atenci贸n Multi-Cabeza (
att
): Aplica autoatenci贸n. - Dropout (
drop_shortcut
): Aplica dropout para regularizaci贸n. - A帽adir Residual (
x + shortcut
): Combina con la entrada original.
- Segundo Camino Residual (FeedForward):
- Entrada (
shortcut
): Guarda la entrada actualizada para la siguiente conexi贸n residual. - Norma de Capa (
norm2
): Normaliza la entrada. - Red de Avance (
ff
): Aplica la transformaci贸n de avance. - Dropout (
drop_shortcut
): Aplica dropout. - A帽adir Residual (
x + shortcut
): Combina con la entrada del primer camino residual.
tip
El bloque transformer agrupa todas las redes y aplica alguna normalizaci贸n y dropouts para mejorar la estabilidad y los resultados del entrenamiento.
Nota c贸mo se realizan los dropouts despu茅s del uso de cada red mientras que la normalizaci贸n se aplica antes.
Adem谩s, tambi茅n utiliza atajos que consisten en a帽adir la salida de una red con su entrada. Esto ayuda a prevenir el problema del gradiente que se desvanece al asegurar que las capas iniciales contribuyan "tanto" como las 煤ltimas.
GPTModel
Las formas se han a帽adido como comentarios para entender mejor las formas de las matrices:
# From https://github.com/rasbt/LLMs-from-scratch/tree/main/ch04
class GPTModel(nn.Module):
def __init__(self, cfg):
super().__init__()
self.tok_emb = nn.Embedding(cfg["vocab_size"], cfg["emb_dim"])
# shape: (vocab_size, emb_dim)
self.pos_emb = nn.Embedding(cfg["context_length"], cfg["emb_dim"])
# shape: (context_length, emb_dim)
self.drop_emb = nn.Dropout(cfg["drop_rate"])
self.trf_blocks = nn.Sequential(
*[TransformerBlock(cfg) for _ in range(cfg["n_layers"])]
)
# Stack of TransformerBlocks
self.final_norm = LayerNorm(cfg["emb_dim"])
self.out_head = nn.Linear(cfg["emb_dim"], cfg["vocab_size"], bias=False)
# shape: (emb_dim, vocab_size)
def forward(self, in_idx):
# in_idx shape: (batch_size, seq_len)
batch_size, seq_len = in_idx.shape
# Token embeddings
tok_embeds = self.tok_emb(in_idx)
# shape: (batch_size, seq_len, emb_dim)
# Positional embeddings
pos_indices = torch.arange(seq_len, device=in_idx.device)
# shape: (seq_len,)
pos_embeds = self.pos_emb(pos_indices)
# shape: (seq_len, emb_dim)
# Add token and positional embeddings
x = tok_embeds + pos_embeds # Broadcasting over batch dimension
# x shape: (batch_size, seq_len, emb_dim)
x = self.drop_emb(x) # Dropout applied
# x shape remains: (batch_size, seq_len, emb_dim)
x = self.trf_blocks(x) # Pass through Transformer blocks
# x shape remains: (batch_size, seq_len, emb_dim)
x = self.final_norm(x) # Final LayerNorm
# x shape remains: (batch_size, seq_len, emb_dim)
logits = self.out_head(x) # Project to vocabulary size
# logits shape: (batch_size, seq_len, vocab_size)
return logits # Output shape: (batch_size, seq_len, vocab_size)
Prop贸sito y Funcionalidad
- Capas de Embedding:
- Embeddings de Tokens (
tok_emb
): Convierte 铆ndices de tokens en embeddings. Como recordatorio, estos son los pesos dados a cada dimensi贸n de cada token en el vocabulario. - Embeddings Posicionales (
pos_emb
): Agrega informaci贸n posicional a los embeddings para capturar el orden de los tokens. Como recordatorio, estos son los pesos dados a los tokens de acuerdo a su posici贸n en el texto. - Dropout (
drop_emb
): Aplicado a los embeddings para regularizaci贸n. - Bloques de Transformer (
trf_blocks
): Pila den_layers
bloques de transformer para procesar embeddings. - Normalizaci贸n Final (
final_norm
): Normalizaci贸n de capa antes de la capa de salida. - Capa de Salida (
out_head
): Proyecta los estados ocultos finales al tama帽o del vocabulario para producir logits para la predicci贸n.
tip
El objetivo de esta clase es usar todas las otras redes mencionadas para predecir el siguiente token en una secuencia, lo cual es fundamental para tareas como la generaci贸n de texto.
Nota c贸mo usar谩 tantos bloques de transformer como se indique y que cada bloque de transformer est谩 utilizando una red de atenci贸n multi-cabeza, una red de avance y varias normalizaciones. As铆 que si se utilizan 12 bloques de transformer, multiplica esto por 12.
Adem谩s, se agrega una capa de normalizaci贸n antes de la salida y se aplica una capa lineal final al final para obtener los resultados con las dimensiones adecuadas. Nota c贸mo cada vector final tiene el tama帽o del vocabulario utilizado. Esto se debe a que est谩 tratando de obtener una probabilidad por cada token posible dentro del vocabulario.
N煤mero de Par谩metros a Entrenar
Teniendo la estructura de GPT definida, es posible averiguar el n煤mero de par谩metros a entrenar:
GPT_CONFIG_124M = {
"vocab_size": 50257, # Vocabulary size
"context_length": 1024, # Context length
"emb_dim": 768, # Embedding dimension
"n_heads": 12, # Number of attention heads
"n_layers": 12, # Number of layers
"drop_rate": 0.1, # Dropout rate
"qkv_bias": False # Query-Key-Value bias
}
model = GPTModel(GPT_CONFIG_124M)
total_params = sum(p.numel() for p in model.parameters())
print(f"Total number of parameters: {total_params:,}")
# Total number of parameters: 163,009,536
C谩lculo Paso a Paso
1. Capas de Embedding: Embedding de Tokens y Embedding de Posici贸n
- Capa:
nn.Embedding(vocab_size, emb_dim)
- Par谩metros:
vocab_size * emb_dim
token_embedding_params = 50257 * 768 = 38,597,376
- Capa:
nn.Embedding(context_length, emb_dim)
- Par谩metros:
context_length * emb_dim
position_embedding_params = 1024 * 768 = 786,432
Total de Par谩metros de Embedding
embedding_params = token_embedding_params + position_embedding_params
embedding_params = 38,597,376 + 786,432 = 39,383,808
2. Bloques de Transformador
Hay 12 bloques de transformador, as铆 que calcularemos los par谩metros para un bloque y luego multiplicaremos por 12.
Par谩metros por Bloque de Transformador
a. Atenci贸n Multi-Cabeza
-
Componentes:
-
Capa Lineal de Consulta (
W_query
):nn.Linear(emb_dim, emb_dim, bias=False)
-
Capa Lineal de Clave (
W_key
):nn.Linear(emb_dim, emb_dim, bias=False)
-
Capa Lineal de Valor (
W_value
):nn.Linear(emb_dim, emb_dim, bias=False)
-
Proyecci贸n de Salida (
out_proj
):nn.Linear(emb_dim, emb_dim)
-
C谩lculos:
-
Cada uno de
W_query
,W_key
,W_value
:
qkv_params = emb_dim * emb_dim = 768 * 768 = 589,824
Dado que hay tres capas de este tipo:
total_qkv_params = 3 * qkv_params = 3 * 589,824 = 1,769,472
- Proyecci贸n de Salida (
out_proj
):
out_proj_params = (emb_dim * emb_dim) + emb_dim = (768 * 768) + 768 = 589,824 + 768 = 590,592
- Total de Par谩metros de Atenci贸n Multi-Cabeza:
mha_params = total_qkv_params + out_proj_params
mha_params = 1,769,472 + 590,592 = 2,360,064
b. Red FeedForward
-
Componentes:
-
Primera Capa Lineal:
nn.Linear(emb_dim, 4 * emb_dim)
-
Segunda Capa Lineal:
nn.Linear(4 * emb_dim, emb_dim)
-
C谩lculos:
-
Primera Capa Lineal:
ff_first_layer_params = (emb_dim * 4 * emb_dim) + (4 * emb_dim)
ff_first_layer_params = (768 * 3072) + 3072 = 2,359,296 + 3,072 = 2,362,368
- Segunda Capa Lineal:
ff_second_layer_params = (4 * emb_dim * emb_dim) + emb_dim
ff_second_layer_params = (3072 * 768) + 768 = 2,359,296 + 768 = 2,360,064
- Total de Par谩metros FeedForward:
ff_params = ff_first_layer_params + ff_second_layer_params
ff_params = 2,362,368 + 2,360,064 = 4,722,432
c. Normalizaciones de Capa
- Componentes:
- Dos instancias de
LayerNorm
por bloque. - Cada
LayerNorm
tiene2 * emb_dim
par谩metros (escala y desplazamiento). - C谩lculos:
layer_norm_params_per_block = 2 * (2 * emb_dim) = 2 * 768 * 2 = 3,072
d. Total de Par谩metros por Bloque de Transformador
pythonCopy codeparams_per_block = mha_params + ff_params + layer_norm_params_per_block
params_per_block = 2,360,064 + 4,722,432 + 3,072 = 7,085,568
Total de Par谩metros para Todos los Bloques de Transformadores
pythonCopy codetotal_transformer_blocks_params = params_per_block * n_layers
total_transformer_blocks_params = 7,085,568 * 12 = 85,026,816
3. Capas Finales
a. Normalizaci贸n de la Capa Final
- Par谩metros:
2 * emb_dim
(escalar y desplazar)
pythonCopy codefinal_layer_norm_params = 2 * 768 = 1,536
b. Capa de Proyecci贸n de Salida (out_head
)
- Capa:
nn.Linear(emb_dim, vocab_size, bias=False)
- Par谩metros:
emb_dim * vocab_size
pythonCopy codeoutput_projection_params = 768 * 50257 = 38,597,376
4. Resumiendo Todos los Par谩metros
pythonCopy codetotal_params = (
embedding_params +
total_transformer_blocks_params +
final_layer_norm_params +
output_projection_params
)
total_params = (
39,383,808 +
85,026,816 +
1,536 +
38,597,376
)
total_params = 163,009,536
Generar Texto
Teniendo un modelo que predice el siguiente token como el anterior, solo es necesario tomar los valores del 煤ltimo token de la salida (ya que ser谩n los del token predicho), que ser谩 un valor por entrada en el vocabulario y luego usar la funci贸n softmax
para normalizar las dimensiones en probabilidades que sumen 1 y luego obtener el 铆ndice de la entrada m谩s grande, que ser谩 el 铆ndice de la palabra dentro del vocabulario.
C贸digo de https://github.com/rasbt/LLMs-from-scratch/blob/main/ch04/01_main-chapter-code/ch04.ipynb:
def generate_text_simple(model, idx, max_new_tokens, context_size):
# idx is (batch, n_tokens) array of indices in the current context
for _ in range(max_new_tokens):
# Crop current context if it exceeds the supported context size
# E.g., if LLM supports only 5 tokens, and the context size is 10
# then only the last 5 tokens are used as context
idx_cond = idx[:, -context_size:]
# Get the predictions
with torch.no_grad():
logits = model(idx_cond)
# Focus only on the last time step
# (batch, n_tokens, vocab_size) becomes (batch, vocab_size)
logits = logits[:, -1, :]
# Apply softmax to get probabilities
probas = torch.softmax(logits, dim=-1) # (batch, vocab_size)
# Get the idx of the vocab entry with the highest probability value
idx_next = torch.argmax(probas, dim=-1, keepdim=True) # (batch, 1)
# Append sampled index to the running sequence
idx = torch.cat((idx, idx_next), dim=1) # (batch, n_tokens+1)
return idx
start_context = "Hello, I am"
encoded = tokenizer.encode(start_context)
print("encoded:", encoded)
encoded_tensor = torch.tensor(encoded).unsqueeze(0)
print("encoded_tensor.shape:", encoded_tensor.shape)
model.eval() # disable dropout
out = generate_text_simple(
model=model,
idx=encoded_tensor,
max_new_tokens=6,
context_size=GPT_CONFIG_124M["context_length"]
)
print("Output:", out)
print("Output length:", len(out[0]))
Referencias
tip
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripci贸n!
- 脷nete al 馃挰 grupo de Discord o al grupo de telegram o s铆guenos en Twitter 馃惁 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.