¡Esta es una revisión vieja del documento!
Tabla de Contenidos
Apuntes Técnicos: Arquitectura de IA Generativa y Grandes Modelos de Lenguaje (LLMs)
1. La Arquitectura Base: El Transformer
El Transformer (Vaswani et al., 2017) supuso una ruptura absoluta con las redes secuenciales anteriores (como RNN y LSTM) al tratar el procesamiento del lenguaje como un problema relacional global en lugar de una cadena temporal paso a paso.
El Mecanismo de Autoatención (Scaled Dot-Product Attention)
En lugar de procesar palabra por palabra, el modelo proyecta cada token en tres vectores distintos mediante matrices de pesos entrenables: Query ($Q$), Key ($K$) y Value ($V$).
- Query (Consulta): Qué busca esa palabra.
- Key (Clave): Qué ofrece esa palabra al resto.
- Value (Valor): El contenido semántico real de la palabra una vez que se encuentra la relación.
La operación matemática fundamental que ocurre en cada capa es:
$$\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{Q K^T}{\sqrt{d_k}}\right) V$$
Donde $d_k$ es la dimensión de los vectores de clave. Esto genera una matriz de atención donde cada token recibe un peso de importancia respecto a todos los demás tokens del contexto, resolviendo de forma nativa la dependencia a larga distancia.
Procesamiento en Paralelo vs. Secuencial
Las redes antiguas mantenían un “estado oculto” (hidden state) que se pasaba linealmente del paso $t-1$ al paso $t$, impidiendo la paralelización. El Transformer elimina esta dependencia temporal. Al introducir toda la secuencia de tokens simultáneamente en la GPU, las operaciones de multiplicación de matrices se ejecutan de golpe en los miles de núcleos CUDA de la tarjeta gráfica.
[Image comparing RNN sequential processing vs Transformer parallel processing]
Codificación Posicional Rotatoria (RoPE)
Como el procesamiento es paralelo, la red no sabe inherentemente qué palabra va antes y cuál después. Los LLM modernos sustituyen las funciones trigonométricas fijas del Transformer original por RoPE (Rotary Position Embedding). RoPE aplica una matriz de rotación interna a los vectores $Q$ y $K$. La propiedad matemática clave de RoPE es que el producto escalar entre dos tokens codificados conserva la información de la distancia relativa entre ellos, lo que permite al modelo extrapolar su comprensión a contextos masivos (de 32k a más de un millón de tokens) sin que la geometría espacial del modelo se rompa.
2. El Pipeline de un LLM: Del Texto al Asistente
Un modelo no nace sabiendo chatear o seguir órdenes; se le esculpe a lo largo de tres fases críticas.
Fase 1: Tokenización y Embeddings
El texto plano es indigerible para una red neuronal. Un algoritmo (como Byte-Pair Encoding) fragmenta el texto en tokens (raíces de palabras, prefijos o signos de puntuación). Cada token se asocia a un ID entero dentro de un vocabulario fijo (por ejemplo, 128,000 tokens en la familia Llama 3). Ese ID recupera un vector continuo de alta dimensión (ej. 4096 dimensiones) de la matriz de embeddings. En este espacio geométrico se codifica la semántica inicial de cada fragmento de texto.
Fase 2: Preentrenamiento (Pre-training)
Es un aprendizaje autosupervisado a escala masiva que requiere meses de computación en clústeres de miles de GPUs. El objetivo es el Modelado de Lenguaje Causal: maximizar la probabilidad de predecir el token correcto dada una ventana de tokens anteriores.
$$\mathcal{L} = \sum_{i} \log P(x_i \mid x_{<i}; \Theta)$$
Donde $\Theta$ representa los parámetros (pesos) del modelo. Al repetir esta operación matemática miles de millones de veces sobre terabytes de texto de internet, el modelo absorbe de forma colateral la estructura del mundo, la gramática, la lógica y la sintaxis de programación. El resultado es un Modelo Base (incapaz de chatear, solo autocompleta).
Fase 3: Ajuste Fino Instructivo (SFT) y Alineación (RLHF/DPO)
El modelo base se refina para convertirlo en un asistente mediante dos pasos:
- SFT (Supervised Fine-Tuning): Se entrena al modelo con plantillas estructuradas de conversación de alta calidad.
- DPO (Direct Preference Optimization) / RLHF: Se entrena al modelo exponiéndolo a pares de respuestas (una preferida por humanos y otra rechazada) mediante una función de pérdida que penaliza comportamientos dañinos, mentiras (alucinaciones) o salidas incoherentes. En esta fase es donde el modelo aprende conceptualmente a obedecer las directrices del System Prompt.
<|user|>¿Cómo se calcula una derivada?<|assistant|>Para calcular una derivada...
3. Modificación y Personalización de Modelos de Pesos Abiertos
Tener acceso a los pesos libres del modelo permite alterar su estructura interna o su comportamiento directamente mediante código de Python.
"Descabezar" un Modelo (Headless LLM)
La penúltima capa de un LLM genera un vector denso que condensa toda la información semántica del contexto (el hidden state). Normalmente, la última capa (LM Head) es una capa lineal simple que mapea este vector contra los 128,000 tokens del vocabulario para calcular las probabilidades de la siguiente palabra.
Si eliminamos esa capa con el comando model.lm_head = torch.nn.Identity(), podemos conectar una capa lineal propia con, por ejemplo, solo 2 neuronas de salida. Esto permite reutilizar toda la inteligencia analítica profunda del modelo para tareas de clasificación de texto (Spam / No Spam) o regresión a un coste computacional infinitamente menor.
LoRA y QLoRA (Adaptación de Bajo Rango)
Modificar todos los pesos de un modelo durante un entrenamiento tradicional requiere actualizar matrices gigantescas de dimensiones $d \times k$, algo inviable en hardware doméstico. LoRA (Low-Rank Adaptation) asume que la matriz de actualización de pesos ($\Delta W$) tiene un “rango intrínseco” muy bajo.
En lugar de modificar la matriz original $W_0$ (que se congela), LoRA añade dos matrices auxiliares paralelas y delgadas, $A$ y $B$, de rango $r$ (donde $r \ll d$).
$$W = W_0 + \Delta W = W_0 + B \cdot A$$
Si el peso original es una matriz de $4096 \times 4096$ (16 millones de parámetros), con LoRA ($r=8$) se entrenan dos matrices de $4096 \times 8$ y $8 \times 4096$, reduciendo los parámetros activos a entrenar en más de un 99%.
QLoRA lleva esta técnica al límite: mantiene la matriz base $W_0$ comprimida en un formato ultra-reducido de 4 bits (NF4) y calcula los gradientes exclusivamente sobre los adaptadores LoRA en precisión FP16, permitiendo entrenar modelos en GPUs de consumo.
4. Técnicas de Cuantización
La cuantización consiste en mapear un espacio continuo de alta precisión (como los números en punto flotante de 16 bits, FP16, donde cada peso ocupa 2 bytes) a un espacio discreto de baja precisión (como enteros de 4 bits, INT4, donde cada peso ocupa 0,5 bytes).
La fórmula básica de cuantización lineal es:
$$Q(X) = \text{round}\left(\frac{X}{S}\right) + Z$$
Donde $S$ es el factor de escala (scale) y $Z$ es el punto cero (zero-point). Esto permite reducir el tamaño de un modelo en un 75% con una pérdida de precisión matemática casi imperceptible.
Formatos de Cuantización Principales
| Formato | Entorno de Ejecución | Características Clave |
|---|---|---|
| GGUF | CPU / GPU (Local) | Formato contenedor binario unificado (pesos + tokenizador). Permite offloading (repartir capas de forma dinámica entre la VRAM de la gráfica y la RAM del sistema mediante la CPU). Es el motor nativo de Ollama. |
| AWQ | 100% GPU (Servidores) | Analiza las activaciones del modelo con datos reales para identificar el 1% de pesos críticos que dictan la lógica. Aplica un factor de escala para proteger estos pesos antes de comprimir el resto a 4 bits rígidos. Optimizado para Tensor Cores. |
| EXL2 | 100% GPU (Consumo) | Diseñado exclusivamente para exprimir tarjetas NVIDIA en local. Permite cuantizaciones con precisión fraccionaria (ej. 4.25 o 4.65 bits) para ajustar el tamaño del modelo exactamente al límite físico de la VRAM disponible. |
5. Anatomía de la VRAM y Gestión del Contexto
Durante el proceso de inferencia (generación de texto en tiempo real), el consumo de memoria de video (VRAM) de la tarjeta gráfica se divide estrictamente en tres bloques:
[ Memoria del Modelo (Fija) ] + [ Overheads del Sistema / CUDA (~1GB) ] + [ KV Cache (Dinámica) ]
El KV Cache y Grouped-Query Attention (GQA)
En la atención tradicional (MHA), cada cabeza de consulta ($Q$) tiene su propia cabeza de clave ($K$) y valor ($V$). En textos largos, almacenar todas estas matrices $K$ y $V$ para no recalcularlas satura la VRAM.
Los modelos modernos optimizan este espacio usando GQA (Grouped-Query Attention), donde múltiples cabezas de consulta comparten una única cabeza de clave y valor. Esto reduce drásticamente el tamaño del KV Cache en memoria en un factor de 4 u 8, permitiendo ventanas de contexto mucho más amplias en tarjetas de consumo.
El cálculo preciso de memoria para el KV Cache
Para estimar la memoria exacta del KV Cache en bytes para una longitud de contexto $L$, la fórmula de ingeniería es:
$$\text{Memoria}_{KVCache} = 2 \times 2 \times L \times N_{\text{capas}} \times H_{kv} \times D_{\text{cabeza}}$$
Donde $L$ es la longitud del contexto, $N_{\text{capas}}$ es el número de bloques del modelo, $H_{kv}$ es el número de cabezas de clave/valor (reducido por GQA) y $D_{\text{cabeza}}$ es la dimensión interna de la cabeza.
- Regla de oro: En arquitecturas GQA de la escala de 8B de parámetros, el KV Cache consume aproximadamente 125 MB de VRAM por cada 1.000 tokens de contexto.
Importante: El Contexto es la suma geométrica de todo lo que tiene el modelo en memoria en ese instante: System Prompt + Historial de chat + Pregunta actual + Respuesta generándose. Todo ello reside indexado dentro del KV Cache.
Desbordamiento del Contexto (num_ctx)
Cuando la conversación se alarga tanto que el KV Cache alcanza el límite configurado en el motor de inferencia (num_ctx), el sistema activa estrategias de mitigación:
- Truncado (Bruto): Elimina los tokens más antiguos de la conversación, manteniendo intacto el System Prompt. El modelo olvida el principio del chat.
- Resumen por Inferencia (Inteligente): De forma transparente al usuario, la capa de software superior intercepta el historial al llegar al 90% de capacidad, ejecuta una inferencia interna pidiendo al propio modelo que resuma los turnos antiguos, elimina los mensajes pesados originales y añade el mini-resumen resultante justo debajo del System Prompt, liberando miles de tokens en el KV Cache de un plumazo.
6. Estructura de Software en Entornos Locales
En un entorno de desarrollo o producción local, las herramientas interactúan mediante una arquitectura de capas bien definida:
[Open WebUI] ---(Petición HTTP/JSON API)---> [Ollama Engine] ---> [Drivers CUDA] ---> [RTX 3060 VRAM]
(UI/Chat) (Carga de GGUF / (Cálculo de Tensores (Pesos + KVCache)
Gestión de Capas) con PyTorch de bajo nivel)
- Capa de Abstracción y UI (Ej. Open WebUI / LangChain): Normaliza la experiencia. Gestionalas plantillas de chat (Chat Templates), inyecta datos externos en el prompt (como búsquedas web) y maneja el estado de la sesión, enviando una petición limpia vía API HTTP/JSON.
- Motor de Inferencia (Ej. Ollama / Llama.cpp): Es el corazón operativo. Se encarga de parsear el archivo cuantizado (GGUF), orquestar el offloading de capas a la GPU, gestionar dinámicamente el espacio del KV Cache y aplicar los parámetros de muestreo (
temperature,top_p,repeat_penalty) sobre las probabilidades de salida de la red. - Entorno de Contenerización (Ej. Docker): Proporciona un entorno seguro y aislado (sandbox) con permisos restringidos para que agentes locales ejecuten código creado por la IA sin poner en riesgo el sistema operativo anfitrión.
- Capa Matemática de Bajo Nivel (Ej. PyTorch / CUDA): Framework subyacente que traduce las operaciones de tensores del script a instrucciones binarias de álgebra lineal ejecutables directamente por el silicio de la GPU.
Nota de autoría: Generado con Gemini Flash con nivel de pensamiento avanzado a partir de conversación mantenida.
