HSAQ: documentación limpia (Qué es/Qué NO es, HSAQ v2 aparte) + implementación + scripts abliteración
Browse files- HSAQ.md +154 -0
- HSAQ_DOCUMENTACION_DETALLADA.md +319 -0
- HSAQ_FORMATO.md +222 -0
- HSAQ_STANDARD.md +259 -0
- QUE_ES_MATERIA_HSAQ.md +104 -0
- README.md +107 -0
- abliterate_hsaq.py +224 -0
- hsaq.py +64 -0
- measure_vram.py +122 -0
HSAQ.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# HSAQ — Qué es y cómo funciona
|
| 2 |
+
|
| 3 |
+
**Hyper Sparse Adaptive Quantization** — documento maestro (v2.0, 2026).
|
| 4 |
+
|
| 5 |
+
Definición y mecanismo ordenados a partir de la charla del autor en el
|
| 6 |
+
**I Congreso IA-LATAM 2026** (presentación oficial + transcripción del video,
|
| 7 |
+
sintetizada en el whitepaper de Comunidad IA LATAM).
|
| 8 |
+
|
| 9 |
+
> 🎬 **Charla en YouTube** (caso de uso práctico con Noctua-C y Antigravity):
|
| 10 |
+
> https://www.youtube.com/watch?v=azJURypb3xo
|
| 11 |
+
>
|
| 12 |
+
> 📄 **Whitepaper oficial del congreso**:
|
| 13 |
+
> https://comunidadialatam.org/blog/materia-hsaq-ciberseguridad
|
| 14 |
+
|
| 15 |
+
---
|
| 16 |
+
|
| 17 |
+
## 1. ¿Qué es HSAQ?
|
| 18 |
+
|
| 19 |
+
**HSAQ es un mecanismo de cuantización y poda adaptativa por activaciones.**
|
| 20 |
+
Se integra en la arquitectura del modelo y **silencia la información que no le
|
| 21 |
+
sirve al modelo para entrenarse**.
|
| 22 |
+
|
| 23 |
+
- Es un **cuantizador/podador adaptativo** inspirado en la **poda sináptica del
|
| 24 |
+
cerebro humano**: no procesarlo todo, sino *aprender qué cortar*.
|
| 25 |
+
- La clave frente a esquemas de cuantización fija (INT8/INT4/GPTQ/AWQ): las
|
| 26 |
+
máscaras de HSAQ son **aprendibles** — el sistema *aprende cuándo cortar y
|
| 27 |
+
cuándo no*.
|
| 28 |
+
- **No es cuantización de pesos estática.** Opera sobre **activaciones**, con
|
| 29 |
+
umbral recalculado por lote.
|
| 30 |
+
|
| 31 |
+
---
|
| 32 |
+
|
| 33 |
+
## 2. El problema que resuelve
|
| 34 |
+
|
| 35 |
+
Tres cuellos de botella de los Transformers (motivación de la charla):
|
| 36 |
+
|
| 37 |
+
1. **Atención intratable** en secuencias largas — el cómputo crece y degrada la
|
| 38 |
+
tarea; las mitigaciones actuales son "un parche, no la solución".
|
| 39 |
+
2. **Pesos estáticos** — un Transformer entrenado no modula ni adapta
|
| 40 |
+
dinámicamente su procesamiento.
|
| 41 |
+
3. **Desperdicio de memoria en optimizadores** — AdamW usa 2 estados por
|
| 42 |
+
parámetro (8 bytes), agravando el costo del hardware.
|
| 43 |
+
|
| 44 |
+
Motivación de fondo: **reducir la VRAM necesaria** para que la IA sea accesible
|
| 45 |
+
"desde los civiles hasta los gobiernos" — entrenar un modelo de 1.33B con
|
| 46 |
+
**10 GB de VRAM en vez de 25**.
|
| 47 |
+
|
| 48 |
+
---
|
| 49 |
+
|
| 50 |
+
## 3. ¿Cómo funciona? (tres pilares)
|
| 51 |
+
|
| 52 |
+
### 3.1 Umbral dinámico por lote
|
| 53 |
+
|
| 54 |
+
En cada lote se calcula un umbral adaptativo de la activación (kthvalue/mediana)
|
| 55 |
+
y se **silencian las activaciones inactivas** por debajo del umbral.
|
| 56 |
+
|
| 57 |
+
```
|
| 58 |
+
1. flat = |x|.view(B, -1) # magnitudes por batch
|
| 59 |
+
2. n = flat.size(1) # total de neuronas
|
| 60 |
+
3. k = n × (1 - sparsity) # neuronas a mantener
|
| 61 |
+
4. umbral = kthvalue(flat, k) # umbral adaptativo por batch
|
| 62 |
+
5. mask = |x| >= umbral # máscara binaria {0, 1}
|
| 63 |
+
6. return x * mask # neuronas irrelevantes → 0
|
| 64 |
+
```
|
| 65 |
+
|
| 66 |
+
### 3.2 Gradiente STE
|
| 67 |
+
|
| 68 |
+
La actualización de pesos **atraviesa la máscara** en retropropagación
|
| 69 |
+
(Straight-Through Estimator): las neuronas activas reciben gradiente, las
|
| 70 |
+
inactivas no — el umbral y la poda se vuelven **entrenables** (autorregulados).
|
| 71 |
+
|
| 72 |
+
### 3.3 Optimización de VRAM
|
| 73 |
+
|
| 74 |
+
Reemplaza AdamW por **SGD Nesterov con máscaras adaptativas**: 1 estado por
|
| 75 |
+
parámetro (4 bytes) en vez de 8.
|
| 76 |
+
|
| 77 |
+
---
|
| 78 |
+
|
| 79 |
+
## 4. Resultados reportados (prototipo M.A.T.E.R.I.A. v4, 1.33B, BPE)
|
| 80 |
+
|
| 81 |
+
| Criterio | AdamW (estándar) | HSAQ + SGD Nesterov | Beneficio |
|
| 82 |
+
|---|---|---|---|
|
| 83 |
+
| Memoria del optimizador | 8 bytes/parám | 4 bytes/parám | **50% menos** |
|
| 84 |
+
| VRAM de entrenamiento | 24.8 GB | 10.07 GB | **−14.7 GB (−59.4%)** |
|
| 85 |
+
| Sparsity de activaciones | 0% (densa) | 30% autorregulada | Menos cómputo |
|
| 86 |
+
| Convergencia JEPA | N/A | Loss 1.08 → 0.006 | **−99.3%** |
|
| 87 |
+
|
| 88 |
+
La curva de sparsity se **autorreguló** en torno a un objetivo calibrado (~0.047),
|
| 89 |
+
lo que demuestra la estabilidad de la poda adaptativa a esa escala — el beneficio
|
| 90 |
+
crece con modelos más grandes.
|
| 91 |
+
|
| 92 |
+
---
|
| 93 |
+
|
| 94 |
+
## 5. Aplicación: abliteración selectiva (nuevo, 2026)
|
| 95 |
+
|
| 96 |
+
Validado con **Qwen3.5-9B**:
|
| 97 |
+
|
| 98 |
+
1. Se recolecta el vector de refusal por capa: `r = normalize(mean(harmful) − mean(harmless))`.
|
| 99 |
+
2. HSAQ enmascara `r` conservando solo el top (1−sparsity) de componentes
|
| 100 |
+
(`sparsity=0.3` → retiene 70% del vector).
|
| 101 |
+
3. Los pesos de la capa (`out_proj` + `down_proj`) se ortogonalizan contra el
|
| 102 |
+
vector enmascarado: `W ← W − r̂ ⊗ (r̂ᵀ W)`.
|
| 103 |
+
|
| 104 |
+
Resultado: el modelo responde a prompts de seguridad ofensiva **sin degradar
|
| 105 |
+
tareas harmless**; exportado a **GGUF Q4_K_M** (19.3 GB bf16 → ~5.6 GB).
|
| 106 |
+
Modelo: `MethodWhite/Qwen3.5-9B-Abliterated-HSAQ`.
|
| 107 |
+
|
| 108 |
+
La abliteración clásica borra el vector completo (pierde inteligencia); HSAQ
|
| 109 |
+
elimina solo los componentes ruidosos → **menos pérdida de capacidad**.
|
| 110 |
+
|
| 111 |
+
---
|
| 112 |
+
|
| 113 |
+
## 6. Ecosistema de la charla
|
| 114 |
+
|
| 115 |
+
- **M.A.T.E.R.I.A.** — *Multi-Agentic Toroidal Engine for Recursive Intelligent
|
| 116 |
+
Analysis*: motor multiagente con HUB central y ranuras de agentes sobre
|
| 117 |
+
contexto compartido y persistente, arquitectura anidable.
|
| 118 |
+
- **HSAQ** — cuantización/poda adaptativa por activaciones (este documento).
|
| 119 |
+
- **Noctua-C** — framework de ingeniería inversa (80+ módulos, sandbox) operado
|
| 120 |
+
por un agente de IA; demo en vivo en la charla.
|
| 121 |
+
|
| 122 |
+
---
|
| 123 |
+
|
| 124 |
+
## 7. Limitaciones y roadmap
|
| 125 |
+
|
| 126 |
+
| Limitación | Plan |
|
| 127 |
+
|---|---|
|
| 128 |
+
| Sparsity objetivo calibrado (no fijo por capa) | Sparsity configurable/aprendida por capa |
|
| 129 |
+
| `x * mask` no ahorra FLOPs reales sin kernel sparse | Kernel CUDA sparse |
|
| 130 |
+
| `kthvalue` fuera de opset ONNX | Wrapper con `topk` |
|
| 131 |
+
| Aplicar HSAQ en runtime dentro de llama.cpp/GGUF | Bloque/máscara en el motor |
|
| 132 |
+
|
| 133 |
+
Roadmap: primer prototipo 2026 ✓ → modelos comerciales 2027 → gobiernos/empresas
|
| 134 |
+
2028 → seguir reduciendo consumo de cómputo 2029.
|
| 135 |
+
|
| 136 |
+
---
|
| 137 |
+
|
| 138 |
+
## 8. Evidencia
|
| 139 |
+
|
| 140 |
+
- Implementación: `hsaq.py` (`nn.Module`, 64 líneas).
|
| 141 |
+
- Estándar: `HSAQ_STANDARD.md` (v1.0).
|
| 142 |
+
- Paper: `PAPER_CIENTIFICO_MATERIA_V4.md`.
|
| 143 |
+
- Scripts: `abliterate_hsaq.py`, `measure_vram.py`.
|
| 144 |
+
- Whitepaper congreso: https://comunidadialatam.org/blog/materia-hsaq-ciberseguridad
|
| 145 |
+
|
| 146 |
+
---
|
| 147 |
+
|
| 148 |
+
## 9. Créditos
|
| 149 |
+
|
| 150 |
+
Desarrollado por **Jesús Antonio Zárate Hernández** (MethodWhite, Chile) —
|
| 151 |
+
Ingeniero en Ciberseguridad, creador de M.A.T.E.R.I.A. y HSAQ.
|
| 152 |
+
Charla: I Congreso IA-LATAM 2026 · [LinkedIn](https://www.linkedin.com/in/methodwhite)
|
| 153 |
+
|
| 154 |
+
Si te sirve, invítame un café ☕ → **https://buymeacoffee.com/methodwhite**
|
HSAQ_DOCUMENTACION_DETALLADA.md
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# HSAQ — HyperSparse Adaptive Quantization
|
| 2 |
+
|
| 3 |
+
## Documentación Técnica Detallada para Conferencia
|
| 4 |
+
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
> ## ¿Qué es? ✅
|
| 8 |
+
> Cuantización y poda adaptativa de **activaciones** (máscara binaria dinámica
|
| 9 |
+
> por `kthvalue`, umbral por lote, máscaras aprendibles, gradiente STE,
|
| 10 |
+
> SGD Nesterov a 4 bytes/parám).
|
| 11 |
+
>
|
| 12 |
+
> ## ¿Qué NO es? ❌
|
| 13 |
+
> **No es cuantización de pesos.** No es INT8, INT4, GPTQ, AWQ ni bitsandbytes.
|
| 14 |
+
> No opera sobre pesos — opera exclusivamente sobre activaciones.
|
| 15 |
+
>
|
| 16 |
+
> ## HSAQ v2 — aparte ⚠️
|
| 17 |
+
> La cuantización de pesos INT8/INT4 descrita en el paper de M.A.T.E.R.I.A. V4
|
| 18 |
+
> es una **extensión experimental separada**; no forma parte de esta definición.
|
| 19 |
+
|
| 20 |
+
---
|
| 21 |
+
|
| 22 |
+
## 1. Definición
|
| 23 |
+
|
| 24 |
+
**HSAQ** (HyperSparse Adaptive Quantization) es una técnica de ejecución dispersa adaptativa que reduce el costo computacional de redes neuronales activando selectivamente solo las neuronas más relevantes durante cada forward pass.
|
| 25 |
+
|
| 26 |
+
A diferencia de la cuantización tradicional (que reduce la precisión de los pesos), HSAQ **selecciona dinámicamente qué neuronas se ejecutan**, creando una máscara de dispersidad que se recalcula en cada batch.
|
| 27 |
+
|
| 28 |
+
---
|
| 29 |
+
|
| 30 |
+
## 2. Problema que Resuelve
|
| 31 |
+
|
| 32 |
+
### 2.1 El Problema de la Redundancia Neural
|
| 33 |
+
|
| 34 |
+
En una red neuronal estándar, **todas las neuronas se ejecutan** en cada forward pass, independientemente de su relevancia para la entrada actual. Esto genera:
|
| 35 |
+
|
| 36 |
+
- **Ineficiencia computacional**: ~30-50% de las neuronas producen activaciones cercanas a cero
|
| 37 |
+
- **Consumo energético innecesario**: Cada multiplicación matriz-vector cuesta energía
|
| 38 |
+
- **Latencia innecesaria**: Tiempo de cómputo desperdiciado en cálculos irrelevantes
|
| 39 |
+
|
| 40 |
+
### 2.2 Solución de HSAQ
|
| 41 |
+
|
| 42 |
+
HSAQ identifica y **enmascara** las neuronas menos relevantes en tiempo real, reduciendo el cómputo sin pérdida de precisión.
|
| 43 |
+
|
| 44 |
+
---
|
| 45 |
+
|
| 46 |
+
## 3. Algoritmo
|
| 47 |
+
|
| 48 |
+
### 3.1 Pseudocódigo
|
| 49 |
+
|
| 50 |
+
```
|
| 51 |
+
ENTRADA: tensor x de forma [B, T, D]
|
| 52 |
+
PARÁMETRO: sparsity ∈ [0, 1] (fracción de neuronas a enmascarar)
|
| 53 |
+
|
| 54 |
+
1. flat = |x|.reshape(B, T*D) # Aplanar y tomar magnitudes
|
| 55 |
+
2. n = T * D # Total de dimensiones
|
| 56 |
+
3. k = n * (1 - sparsity) # Número de neuronas a MANTENER
|
| 57 |
+
4. thresh = kthvalue(flat, k, dim=1) # Umbral dinámico por batch
|
| 58 |
+
5. mask = |x| >= thresh # Máscara booleana
|
| 59 |
+
6. SALIDA: x * mask # Solo neuronas relevantes pasan
|
| 60 |
+
```
|
| 61 |
+
|
| 62 |
+
### 3.2 Explicación Paso a Paso
|
| 63 |
+
|
| 64 |
+
| Paso | Operación | Propósito |
|
| 65 |
+
|------|-----------|-----------|
|
| 66 |
+
| 1 | `flat = |x|.reshape(B, -1)` | Obtener magnitudes de todas las activaciones |
|
| 67 |
+
| 2 | `k = n * (1 - sparsity)` | Calcular cuántas neuronas conservar (ej: sparsity=0.3 → k=70% de n) |
|
| 68 |
+
| 3 | `thresh = kthvalue(flat, k)` | Encontrar el valor que separa el top-70% del bottom-30% |
|
| 69 |
+
| 4 | `mask = |x| >= thresh` | Crear máscara: True donde la activación supera el umbral |
|
| 70 |
+
| 5 | `x * mask` | Enmascarar activaciones irrelevantes (→ 0) |
|
| 71 |
+
|
| 72 |
+
### 3.3 Ejemplo Visual
|
| 73 |
+
|
| 74 |
+
```
|
| 75 |
+
Entrada x: [0.8, -0.1, 0.5, -0.02, 0.9, 0.01]
|
| 76 |
+
Magnitudes: [0.8, 0.1, 0.5, 0.02, 0.9, 0.01]
|
| 77 |
+
sparsity = 0.5 → conservar top-50% (3 de 6 valores)
|
| 78 |
+
|
| 79 |
+
kthvalue([0.8, 0.1, 0.5, 0.02, 0.9, 0.01], k=3) = 0.5
|
| 80 |
+
thresh = 0.5
|
| 81 |
+
|
| 82 |
+
mask: [True, False, True, False, True, False]
|
| 83 |
+
Salida: [0.8, 0, 0.5, 0, 0.9, 0]
|
| 84 |
+
```
|
| 85 |
+
|
| 86 |
+
---
|
| 87 |
+
|
| 88 |
+
## 4. Propiedades Clave
|
| 89 |
+
|
| 90 |
+
### 4.1 Adaptativo por Batch
|
| 91 |
+
|
| 92 |
+
El umbral `thresh` se recalcula **en cada batch** usando `kthvalue`. Esto significa:
|
| 93 |
+
|
| 94 |
+
- **No hay umbral fijo**: A diferencia de técnicas como "activaciones > 0.01", HSAQ se adapta a la distribución de cada batch
|
| 95 |
+
- **Robusto a cambios de escala**: Si las activaciones crecen o decrcen, el umbral se ajusta automáticamente
|
| 96 |
+
- **Preserva la estructura relativa**: Siempre conserva el top-X% por magnitud, no por valor absoluto
|
| 97 |
+
|
| 98 |
+
### 4.2 Gradiente Fluid
|
| 99 |
+
|
| 100 |
+
La máscara binaria es **diferenciable** en la práctica (el gradiente fluye a través de las activaciones no enmascaradas). Esto permite:
|
| 101 |
+
|
| 102 |
+
- **Entrenamiento end-to-end**: HSAQ se integra en el graph de cómputo
|
| 103 |
+
- **Aprendizaje de sparsity**: El modelo puede aprender a producir activaciones más concentradas
|
| 104 |
+
- **Combinación con other QAT techniques**: Complementa cuantización de pesos y activaciones
|
| 105 |
+
|
| 106 |
+
### 4.3 Agonístico de Hardware
|
| 107 |
+
|
| 108 |
+
HSAQ implementa la operación usando solo:
|
| 109 |
+
- `torch.abs()` → soportado en CPU, GPU, TPU
|
| 110 |
+
- `.reshape()` → universal
|
| 111 |
+
- `torch.kthvalue()` → implementado en todos los backends
|
| 112 |
+
- Element-wise multiplication → universal
|
| 113 |
+
|
| 114 |
+
**No requiere**: Tensor Cores, CUDA kernels custom, instrucciones SIMD específicas.
|
| 115 |
+
|
| 116 |
+
---
|
| 117 |
+
|
| 118 |
+
## 5. Comparación con Técnicas Relacionadas
|
| 119 |
+
|
| 120 |
+
### 5.1 HSAQ vs Cuantización Tradicional (INT8/INT4)
|
| 121 |
+
|
| 122 |
+
| Aspecto | Cuantización (INT8) | HSAQ |
|
| 123 |
+
|---------|---------------------|------|
|
| 124 |
+
| Qué reduce | Precisión de pesos (32→8 bits) | Número de neuronas activas |
|
| 125 |
+
| Cuándo se aplica | Post-entrenamiento o QAT | Durante inference (y training) |
|
| 126 |
+
| Pérdida de precisión | Sí (quantization error) | Mínima (soloactivaciones ~0) |
|
| 127 |
+
| Adaptabilidad | Fija (mismo esquema para todas las entradas) | Dinámica (cambia por batch) |
|
| 128 |
+
| Hardware requerido | Soporte INT8 en hardware | Cualquier hardware |
|
| 129 |
+
|
| 130 |
+
### 5.2 HSAQ vs Pruning (Static)
|
| 131 |
+
|
| 132 |
+
| Aspecto | Pruning Estático | HSAQ |
|
| 133 |
+
|---------|------------------|------|
|
| 134 |
+
| Qué elimina | Pesos/estructura del modelo | Activaciones por batch |
|
| 135 |
+
| Cuándo | Post-entrenamiento | Cada forward pass |
|
| 136 |
+
| Reentrenamiento | Requiere fine-tuning | No requiere |
|
| 137 |
+
| Adaptabilidad | No cambia después de pruning | Se adapta a cada entrada |
|
| 138 |
+
|
| 139 |
+
### 5.3 HSAQ vs Google TurboQuant
|
| 140 |
+
|
| 141 |
+
| Aspecto | Google TurboQuant | HSAQ |
|
| 142 |
+
|---------|-------------------|------|
|
| 143 |
+
| Enfoque | Cuantización fija post-entrenamiento | Ejecución dispersa adaptativa |
|
| 144 |
+
| Granularidad | Por tensor (pesos) | Por elemento (activaciones) |
|
| 145 |
+
| Adaptabilidad | Ninguna (mismo esquema siempre) | Por batch (umbral dinámico) |
|
| 146 |
+
| Entrenable | No (post-processing) | Sí (gradiente fluye) |
|
| 147 |
+
| Hardware | Requiere soporte INT8 | Funciona en cualquier hardware |
|
| 148 |
+
| Overhead | Requiere calibración | Cero overhead (cálculo inline) |
|
| 149 |
+
|
| 150 |
+
**Por qué HSAQ supera a TurboQuant:**
|
| 151 |
+
|
| 152 |
+
1. **Adaptabilidad**: TurboQuant aplica el mismo esquema de cuantización a todas las entradas. HSAQ ajusta el umbral dinámicamente.
|
| 153 |
+
2. **Granularidad**: TurboQuant opera a nivel de tensor (bloques de pesos). HSAQ opera a nivel de elemento (cada activación individual).
|
| 154 |
+
3. **Entrenabilidad**: TurboQuant es post-entrenamiento. HSAQ se integra en el graph de cómputo y puede optimizar su comportamiento.
|
| 155 |
+
4. **Cero overhead**: TurboQuant requiere pasos de calibración. HSAQ calcula el umbral en línea con una sola operación `kthvalue`.
|
| 156 |
+
|
| 157 |
+
---
|
| 158 |
+
|
| 159 |
+
## 6. Implementación en M.A.T.E.R.I.A. V3
|
| 160 |
+
|
| 161 |
+
### 6.1 Código Fuente
|
| 162 |
+
|
| 163 |
+
```python
|
| 164 |
+
class HSAQ(nn.Module):
|
| 165 |
+
def __init__(self, sparsity=0.3):
|
| 166 |
+
super().__init__()
|
| 167 |
+
self.sparsity = sparsity # 30% de neuronas enmascaradas
|
| 168 |
+
|
| 169 |
+
def forward(self, x):
|
| 170 |
+
flat = x.abs().view(x.size(0), -1)
|
| 171 |
+
n = flat.size(1)
|
| 172 |
+
k = max(1, min(n - 1, int(n * (1 - self.sparsity))))
|
| 173 |
+
thresh = torch.kthvalue(flat, k, dim=1).values
|
| 174 |
+
thresh = thresh.view(-1, *([1] * (x.dim() - 1)))
|
| 175 |
+
mask = x.abs() >= thresh
|
| 176 |
+
return x * mask
|
| 177 |
+
```
|
| 178 |
+
|
| 179 |
+
### 6.2 Posición en la Arquitectura
|
| 180 |
+
|
| 181 |
+
```
|
| 182 |
+
Input tokens
|
| 183 |
+
↓
|
| 184 |
+
Token Embedding (vocab → 256 dims)
|
| 185 |
+
↓
|
| 186 |
+
╔══════════════════════════════╗
|
| 187 |
+
║ HSAQ Sparse Execution ║ ← Aquí se enmascaran el 30% de neuronas
|
| 188 |
+
║ (sparsity=0.3) ║
|
| 189 |
+
╚══════════════════════════════╝
|
| 190 |
+
↓
|
| 191 |
+
Transformer Blocks (GQA + RoPE + SwiGLU) × 3 capas
|
| 192 |
+
↓
|
| 193 |
+
Synapsis Memory (128 slots, top-3 retrieval)
|
| 194 |
+
↓
|
| 195 |
+
LIF-SNN (neuronas de pulsos)
|
| 196 |
+
↓
|
| 197 |
+
SSM (State Space Model)
|
| 198 |
+
↓
|
| 199 |
+
JEPA (predictive embeddings)
|
| 200 |
+
↓
|
| 201 |
+
RMSNorm → Linear Head → Output logits
|
| 202 |
+
```
|
| 203 |
+
|
| 204 |
+
### 6.3 Parámetros del Modelo Base
|
| 205 |
+
|
| 206 |
+
| Parámetro | Valor | Descripción |
|
| 207 |
+
|-----------|-------|-------------|
|
| 208 |
+
| HSAQ sparsity | 0.3 | 30% de neuronas enmascaradas |
|
| 209 |
+
| Hidden dim | 256 | Dimensiones de embedding |
|
| 210 |
+
| Neuronas activas por batch | ~179 de 256 | 70% de 256 = 179.2 |
|
| 211 |
+
| Ahorro computacional | ~30% | En capas lineales subsecuentes |
|
| 212 |
+
|
| 213 |
+
---
|
| 214 |
+
|
| 215 |
+
## 7. Resultados Experimentales
|
| 216 |
+
|
| 217 |
+
### 7.1 Impacto en Accuracy
|
| 218 |
+
|
| 219 |
+
| Configuración | Val Accuracy | Val Loss | Diferencia |
|
| 220 |
+
|---------------|-------------|----------|------------|
|
| 221 |
+
| Sin HSAQ (sparsity=0) | 98.83% | 0.0363 | baseline |
|
| 222 |
+
| HSAQ (sparsity=0.3) | 98.83% | 0.0363 | +0.00% |
|
| 223 |
+
| HSAQ (sparsity=0.5) | ~98.5% | ~0.040 | -0.3% |
|
| 224 |
+
|
| 225 |
+
**Conclusión**: Con sparsity=0.3, HSAQ **no reduce accuracy** mientras reduce el cómputo en ~30%.
|
| 226 |
+
|
| 227 |
+
### 7.2 Impacto en Velocidad
|
| 228 |
+
|
| 229 |
+
| Operación | Sin HSAQ | Con HSAQ | Speedup |
|
| 230 |
+
|-----------|----------|----------|---------|
|
| 231 |
+
| Forward pass (CPU) | 1.0x | ~0.75x* | ~25% más rápido |
|
| 232 |
+
| Forward pass (GPU) | 1.0x | ~0.80x* | ~20% más rápido |
|
| 233 |
+
|
| 234 |
+
*El speedup real depende de la implementación del kernel de masking. En PyTorch estándar, el overhead de `kthvalue` compensa parte del ahorro. En implementaciones custom (CUDA kernels), el speedup es mayor.
|
| 235 |
+
|
| 236 |
+
### 7.3 Spike Rate del SNN
|
| 237 |
+
|
| 238 |
+
El spike rate de las neuronas LIF se mantiene estable (~0.01-0.05) con y sin HSAQ, indicando que la ejecución dispersa no afecta la dinámica temporal del SNN.
|
| 239 |
+
|
| 240 |
+
---
|
| 241 |
+
|
| 242 |
+
## 8. Ventajas para Presentación en Conferencia
|
| 243 |
+
|
| 244 |
+
### 8.1 Innovación Clave
|
| 245 |
+
|
| 246 |
+
HSAQ es una **contribución original** de M.A.T.E.R.I.A. que combina:
|
| 247 |
+
- **Sparsity adaptativa** (como Dynamic Sparse Training)
|
| 248 |
+
- **Quantización aware** (como QAT)
|
| 249 |
+
- **Ejecución en línea** (sin post-processing)
|
| 250 |
+
|
| 251 |
+
### 8.2 Aplicabilidad
|
| 252 |
+
|
| 253 |
+
HSAQ es especialmente útil para:
|
| 254 |
+
- **Edge devices**: Reducción de cómputo sin pérdida de accuracy
|
| 255 |
+
- **Embedded AI**: Menor consumo energético
|
| 256 |
+
- **Real-time inference**: Latencia reducida
|
| 257 |
+
- **CPU-only training**: Hace viable entrenar en hardware limitado
|
| 258 |
+
|
| 259 |
+
### 8.3 Comparación con Estado del Arte
|
| 260 |
+
|
| 261 |
+
| Trabajo | Enfoque | HSAQ vs |
|
| 262 |
+
|---------|---------|---------|
|
| 263 |
+
| SparseGPT (2023) | Pruning post-training | HSAQ es dinámico, no requiere retraining |
|
| 264 |
+
| TurboQuant (Google) | Cuantización INT8 | HSAQ es adaptable por batch |
|
| 265 |
+
| Dynamic Sparse Training | Sparsity durante training | HSAQ funciona también en inference |
|
| 266 |
+
| LLM.int8() | Mixed-precision | HSAQ es más ligero y hardware-agnostic |
|
| 267 |
+
|
| 268 |
+
---
|
| 269 |
+
|
| 270 |
+
## 9. Diagrama para Presentación
|
| 271 |
+
|
| 272 |
+
```
|
| 273 |
+
┌─────────────────────────────────────────────────────────┐
|
| 274 |
+
│ HSAQ - Flujo de Datos │
|
| 275 |
+
├─────────────────────────────────────────────────────────┤
|
| 276 |
+
│ │
|
| 277 |
+
│ Input: x ∈ ℝ^(B×T×D) │
|
| 278 |
+
│ │ │
|
| 279 |
+
│ ▼ │
|
| 280 |
+
│ ┌─────────────────────┐ │
|
| 281 |
+
│ │ |x|.reshape(B, -1) │ Magnitudes │
|
| 282 |
+
│ └─────────┬───────────┘ │
|
| 283 |
+
│ │ │
|
| 284 |
+
│ ▼ │ │
|
| 285 |
+
│ ┌─────────────────────┐ │
|
| 286 |
+
│ │ k = n × (1 - 0.3) │ Neuronas a conservar │
|
| 287 |
+
│ └─────────┬───────────┘ │
|
| 288 |
+
│ │ │
|
| 289 |
+
│ ▼ │ │
|
| 290 |
+
│ ┌─────────────────────┐ │
|
| 291 |
+
│ │ thresh = kthvalue │ Umbral dinámico │
|
| 292 |
+
│ └─────────┬───────────┘ │
|
| 293 |
+
│ │ │
|
| 294 |
+
│ ▼ │ │
|
| 295 |
+
│ ┌─────────────────────┐ │
|
| 296 |
+
│ │ mask = |x| >= thresh│ Máscara binaria │
|
| 297 |
+
│ └─────────┬───────────┘ │
|
| 298 |
+
│ │ │
|
| 299 |
+
│ ▼ │ │
|
| 300 |
+
│ ┌─────────────────────┐ │
|
| 301 |
+
│ │ output = x × mask │ Solo neuronas relevantes │
|
| 302 |
+
│ └─────────────────────┘ │
|
| 303 |
+
│ │
|
| 304 |
+
│ Resultado: 30% de neuronas → 0, 70% pasan sin cambio │
|
| 305 |
+
└─────────────────────────────────────────────────────────┘
|
| 306 |
+
```
|
| 307 |
+
|
| 308 |
+
---
|
| 309 |
+
|
| 310 |
+
## 10. Referencias
|
| 311 |
+
|
| 312 |
+
1. M.A.T.E.R.I.A. V3 Paper: `PAPER_CIENTIFICO_MATERIA_V3.md`
|
| 313 |
+
2. Arquitectura técnica: `V3_ARQUITECTURA.md`
|
| 314 |
+
3. Código fuente: `models/core/hsaq.py`
|
| 315 |
+
4. Configuración: `configs/3.8M.yaml`
|
| 316 |
+
|
| 317 |
+
---
|
| 318 |
+
|
| 319 |
+
*Documento preparado para presentación en conferencia — Julio 2026*
|
HSAQ_FORMATO.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# HSAQ — HyperSparse Adaptive Quantization
|
| 2 |
+
|
| 3 |
+
> ## ¿Qué es? ✅
|
| 4 |
+
> Cuantización y poda adaptativa de **activaciones** (máscara binaria por
|
| 5 |
+
> `kthvalue`, umbral por lote, máscaras aprendibles, STE, SGD Nesterov).
|
| 6 |
+
>
|
| 7 |
+
> ## ¿Qué NO es? ❌
|
| 8 |
+
> No es cuantización de pesos (INT8/INT4/GPTQ/AWQ/bitsandbytes). Opera solo
|
| 9 |
+
> sobre activaciones, no sobre pesos.
|
| 10 |
+
>
|
| 11 |
+
> ## HSAQ v2 — aparte ⚠️
|
| 12 |
+
> Extensión experimental (cuantización de pesos INT8/INT4) del paper de
|
| 13 |
+
> M.A.T.E.R.I.A. V4; separada de esta definición core.
|
| 14 |
+
|
| 15 |
+
## Definición Formal
|
| 16 |
+
|
| 17 |
+
HSAQ es un mecanismo de **cuantización de activaciones vía sparsity adaptativa**.
|
| 18 |
+
La "cuantización" refiere a que las activaciones se reducen a {0, valor} mediante
|
| 19 |
+
una máscara binaria dinámica calculada por batch.
|
| 20 |
+
|
| 21 |
+
**No es cuantización de pesos.** No es INT8/INT4. No es bitsandbytes.
|
| 22 |
+
HSAQ opera exclusivamente sobre **activaciones**, no sobre pesos.
|
| 23 |
+
|
| 24 |
+
---
|
| 25 |
+
|
| 26 |
+
## 1. Algoritmo
|
| 27 |
+
|
| 28 |
+
```
|
| 29 |
+
Entrada: x ∈ ℝ^(B×T×D) (batch de activaciones)
|
| 30 |
+
Parámetro: sparsity ∈ [0,1)
|
| 31 |
+
|
| 32 |
+
flat = |x|.reshape(B, -1) # Magnitudes por batch
|
| 33 |
+
n = flat.size(1) # Total de neuronas
|
| 34 |
+
k = n * (1 - sparsity) # Neuronas a mantener (top-K%)
|
| 35 |
+
thresh = kthvalue(flat, k) # Umbral dinámico por batch
|
| 36 |
+
mask = |x| >= thresh # Máscara binaria {0, 1}
|
| 37 |
+
return x * mask # ~30% de activaciones → 0
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
### 1.1 Propiedades clave
|
| 41 |
+
|
| 42 |
+
| Propiedad | Descripción |
|
| 43 |
+
|-----------|-------------|
|
| 44 |
+
| **Adaptativo** | El umbral `kthvalue` se recalcula en cada batch |
|
| 45 |
+
| **Por elemento** | Cada neurona se evalúa individualmente contra el umbral |
|
| 46 |
+
| **Hardware-agnostic** | Solo usa torch.abs, reshape, kthvalue, multiplicación |
|
| 47 |
+
| **Gradiente fluye** | STE implícito: el gradiente pasa por las neuronas activas |
|
| 48 |
+
| **Sin estado** | No hay buffers persistentes entre batches |
|
| 49 |
+
|
| 50 |
+
### 1.2 Parámetros
|
| 51 |
+
|
| 52 |
+
| Parámetro | Default | Función |
|
| 53 |
+
|-----------|---------|---------|
|
| 54 |
+
| `sparsity` | 0.3 | Fracción de activaciones a enmascarar (0.3 = 30%) |
|
| 55 |
+
|
| 56 |
+
Éste es el **único parámetro** de HSAQ. Todo lo demás (weight_bits, AWQ, etc.)
|
| 57 |
+
son externos y no forman parte del mecanismo central.
|
| 58 |
+
|
| 59 |
+
---
|
| 60 |
+
|
| 61 |
+
## 2. HSAQ como Optimizer
|
| 62 |
+
|
| 63 |
+
HSAQ **reemplaza a AdamW** como mecanismo de optimización.
|
| 64 |
+
|
| 65 |
+
### 2.1 Por qué funciona
|
| 66 |
+
|
| 67 |
+
1. La máscara sparse (kthvalue) selecciona las neuronas más activas por batch
|
| 68 |
+
2. El gradiente solo fluye por las neuronas no enmascaradas
|
| 69 |
+
3. Esto crea un **regularización adaptativa**: las neuronas irrelevantes no reciben gradiente
|
| 70 |
+
4. El umbral dinámico evita la necesidad de momentum/estados de optimizer
|
| 71 |
+
|
| 72 |
+
### 2.2 Optimizer externo
|
| 73 |
+
|
| 74 |
+
Se usa SGD Nesterov (momentum=0.9) para actualizar pesos:
|
| 75 |
+
|
| 76 |
+
```
|
| 77 |
+
HSAQ + SGD Nesterov = optimizer completo
|
| 78 |
+
├── HSAQ: máscara sparse adaptativa (regularización dinámica)
|
| 79 |
+
└── SGD: actualización de pesos con momentum
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
**No se usa AdamW.** SGD con momentum tiene solo 1 estado de optimizer por
|
| 83 |
+
parámetro (vs 2 de AdamW), ahorrando 4 bytes por parámetro.
|
| 84 |
+
|
| 85 |
+
### 2.3 Hyperparámetros recomendados
|
| 86 |
+
|
| 87 |
+
| Parámetro | Valor | Razón |
|
| 88 |
+
|-----------|-------|-------|
|
| 89 |
+
| `sparsity` | 0.3 | Balance cómputo/precisión |
|
| 90 |
+
| `lr` | 5e-4 | Tasa de aprendizaje |
|
| 91 |
+
| `momentum` | 0.9 | Nesterov momentum |
|
| 92 |
+
| `weight_decay` | 0.01 | Regularización L2 |
|
| 93 |
+
| `clip_grad_norm` | 1.0 | Estabilidad |
|
| 94 |
+
|
| 95 |
+
---
|
| 96 |
+
|
| 97 |
+
## 3. Pipeline de Entrenamiento (con HSAQ por capas)
|
| 98 |
+
|
| 99 |
+
```
|
| 100 |
+
1. Embedding → HSAQ (sparsity 30%)
|
| 101 |
+
2. Transformer Block 1 → HSAQ (sparsity 30%) ← umbral propio
|
| 102 |
+
3. Transformer Block 2 → HSAQ (sparsity 30%) ← umbral propio
|
| 103 |
+
4. Transformer Block N → HSAQ (sparsity 30%) ← umbral propio
|
| 104 |
+
5. SNN + SSM → JEPA → Head → logits
|
| 105 |
+
```
|
| 106 |
+
|
| 107 |
+
Cada capa tiene su propio umbral dinámico calculado via kthvalue.
|
| 108 |
+
Esto permite que:
|
| 109 |
+
|
| 110 |
+
- Capas tempranas (bajo nivel) tengan patrones de activación distintos
|
| 111 |
+
- Capas tardías (alto nivel) se especialicen en representaciones más abstractas
|
| 112 |
+
- El modelo aprenda qué información preservar en cada nivel
|
| 113 |
+
- Diferentes distribuciones de activación por capa no afecten el umbral global
|
| 114 |
+
|
| 115 |
+
### 3.1 Forward con HSAQ por capas
|
| 116 |
+
|
| 117 |
+
```
|
| 118 |
+
h = Embedding(x) # [B, T, dim]
|
| 119 |
+
h = HSAQ(h) # Sparsity post-embedding
|
| 120 |
+
|
| 121 |
+
for layer in transformer:
|
| 122 |
+
h = layer(h) # Forward del transformer block
|
| 123 |
+
h = HSAQ(h) # Sparsity por capa (umbral propio)
|
| 124 |
+
|
| 125 |
+
h = SNN(h) # Neuronas de pulsos
|
| 126 |
+
h = SSM(h) # State Space Model
|
| 127 |
+
h = JEPA(h) # Espacio latente
|
| 128 |
+
h = Head(h) # Logits finales
|
| 129 |
+
```
|
| 130 |
+
|
| 131 |
+
```
|
| 132 |
+
1. Forward pass
|
| 133 |
+
├── Token Embedding → ℝ^(B×T×D)
|
| 134 |
+
├── HSAQ sparsity → 30% de activaciones → 0
|
| 135 |
+
├── Transformer Blocks (GQA + RoPE + SwiGLU)
|
| 136 |
+
├── LIF-SNN (neuronas de pulsos)
|
| 137 |
+
├── SSM (State Space Model)
|
| 138 |
+
├── JEPA Encoder → espacio latente
|
| 139 |
+
└── Head → logits
|
| 140 |
+
|
| 141 |
+
2. Backward pass
|
| 142 |
+
└── Gradiente fluye solo por activaciones activas (STE nativo)
|
| 143 |
+
|
| 144 |
+
3. Weight update
|
| 145 |
+
└─��� SGD Nesterov (momentum 0.9)
|
| 146 |
+
```
|
| 147 |
+
|
| 148 |
+
---
|
| 149 |
+
|
| 150 |
+
## 4. No es HSAQ (cosas que NO pertenecen)
|
| 151 |
+
|
| 152 |
+
| Componente | Motivo de exclusión |
|
| 153 |
+
|-----------|---------------------|
|
| 154 |
+
| INT8/INT4 weight quantization | HSAQ cuantiza activaciones, no pesos |
|
| 155 |
+
| bitsandbytes 8-bit Adam | HSAQ reemplaza a AdamW |
|
| 156 |
+
| AWQ calibration | Es post-training, no parte de HSAQ |
|
| 157 |
+
| GPTQ | Es compresión de pesos, ortogonal a HSAQ |
|
| 158 |
+
| BPE tokenizer | HSAQ funciona con char-level |
|
| 159 |
+
| Weight tying | Es optimización de arquitectura, no de HSAQ |
|
| 160 |
+
|
| 161 |
+
---
|
| 162 |
+
|
| 163 |
+
## 5. Código Mínimo
|
| 164 |
+
|
| 165 |
+
```python
|
| 166 |
+
class HSAQ(nn.Module):
|
| 167 |
+
"""HyperSparse Adaptive Quantization — sparsity adaptativa"""
|
| 168 |
+
def __init__(self, sparsity=0.3):
|
| 169 |
+
super().__init__()
|
| 170 |
+
self.sparsity = sparsity
|
| 171 |
+
|
| 172 |
+
def forward(self, x):
|
| 173 |
+
flat = x.abs().view(x.size(0), -1) # Magnitudes
|
| 174 |
+
k = int(flat.size(1) * (1 - self.sparsity)) # Top-K
|
| 175 |
+
thresh = torch.kthvalue(flat, k, dim=1).values # Umbral dinámico
|
| 176 |
+
thresh = thresh.view(-1, *([1] * (x.dim() - 1)))
|
| 177 |
+
return x * (x.abs() >= thresh) # Máscara binaria
|
| 178 |
+
|
| 179 |
+
# Modo de uso en modelo:
|
| 180 |
+
# h = self.tok_emb(x)
|
| 181 |
+
# h = HSAQ(sparsity=0.3)(h) ← 30% de activaciones → 0
|
| 182 |
+
# h = transformer(h) ← gradiente solo fluye por neuronas activas
|
| 183 |
+
```
|
| 184 |
+
|
| 185 |
+
---
|
| 186 |
+
|
| 187 |
+
## 6. HSAQ vs TurboQuant (Google)
|
| 188 |
+
|
| 189 |
+
| Aspecto | TurboQuant (Google) | HSAQ |
|
| 190 |
+
|---------|--------------------|------|
|
| 191 |
+
| **Enfoque** | Cuantización fija post-entrenamiento | Sparsity adaptativa dinámica |
|
| 192 |
+
| **Granularidad** | Por tensor (pesos) | Por elemento (activaciones) |
|
| 193 |
+
| **Umbral** | Fijo (calibrado offline) | Dinámico (kthvalue por batch) |
|
| 194 |
+
| **Hardware** | Requiere soporte INT8 | CPU/GPU/TPU (solo kthvalue) |
|
| 195 |
+
| **Calibración** | Dataset de calibración offline | Zero overhead (inline) |
|
| 196 |
+
| **Adaptabilidad** | Ninguna (mismo esquema siempre) | Por batch (cambia con cada input) |
|
| 197 |
+
| **Permite modelos más grandes** | No (solo comprime) | Sí (sparsity = menos recursos) |
|
| 198 |
+
|
| 199 |
+
### Por qué HSAQ supera a TurboQuant
|
| 200 |
+
|
| 201 |
+
1. **No malgasta recursos**: solo las neuronas relevantes se activan por batch
|
| 202 |
+
2. **Modelos más grandes en hardware limitado**: con sparsity=0.3, un modelo 190M
|
| 203 |
+
corre como si fuera ~133M, permitiendo ejecutar modelos que no cabrían de otra forma
|
| 204 |
+
3. **Adaptativo**: el umbral se ajusta a la entrada, no hay configuración fija
|
| 205 |
+
4. **Sin calibración**: no necesita datasets externos ni pasos post-entrenamiento
|
| 206 |
+
5. **Más eficiente energéticamente**: menos FLOPs = menos consumo
|
| 207 |
+
|
| 208 |
+
---
|
| 209 |
+
|
| 210 |
+
## 7. Referencia rápida
|
| 211 |
+
|
| 212 |
+
| Concepto | Respuesta |
|
| 213 |
+
|----------|-----------|
|
| 214 |
+
| ¿Qué cuantiza? | **Activaciones** (no pesos) |
|
| 215 |
+
| ¿Cómo? | Máscara binaria vía kthvalue |
|
| 216 |
+
| ¿Cada cuánto se recalcula? | **Cada batch** (umbral dinámico) |
|
| 217 |
+
| ¿Qué reemplaza? | **AdamW** como optimizer |
|
| 218 |
+
| ¿Qué optimizer usa? | SGD Nesterov (momentum=0.9) |
|
| 219 |
+
| Parámetros | Solo `sparsity` (default 0.3) |
|
| 220 |
+
| ¿INT8? | NO |
|
| 221 |
+
| ¿bitsandbytes? | NO |
|
| 222 |
+
| ¿BPE? | NO |
|
HSAQ_STANDARD.md
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# HSAQ Standard — HyperSparse Adaptive Quantization
|
| 2 |
+
|
| 3 |
+
## Versión 1.0 — Julio 2026
|
| 4 |
+
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
> ## ¿Qué es? ✅
|
| 8 |
+
> Cuantización y poda adaptativa de **activaciones**: máscara binaria dinámica
|
| 9 |
+
> por `kthvalue` (umbral recalculado por lote), máscaras aprendibles, gradiente
|
| 10 |
+
> STE y SGD Nesterov a 4 bytes/parám.
|
| 11 |
+
>
|
| 12 |
+
> ## ¿Qué NO es? ❌
|
| 13 |
+
> **No es cuantización de pesos.** No es INT8, INT4, GPTQ, AWQ ni bitsandbytes.
|
| 14 |
+
> No opera sobre pesos — opera exclusivamente sobre activaciones.
|
| 15 |
+
>
|
| 16 |
+
> ## HSAQ v2 — aparte ⚠️
|
| 17 |
+
> La cuantización de pesos INT8/INT4 del paper de M.A.T.E.R.I.A. V4 es una
|
| 18 |
+
> **extensión experimental separada**; no forma parte de esta definición core.
|
| 19 |
+
|
| 20 |
+
---
|
| 21 |
+
|
| 22 |
+
## 1. Definición
|
| 23 |
+
|
| 24 |
+
HSAQ (HyperSparse Adaptive Quantization) es un mecanismo de **cuantización de activaciones**
|
| 25 |
+
mediante **sparsity adaptativa dinámica**, donde cada capa de la red calcula su propio umbral
|
| 26 |
+
vía `torch.kthvalue` en cada forward pass.
|
| 27 |
+
|
| 28 |
+
**La "cuantización" en HSAQ** refiere a que las activaciones se reducen a un conjunto
|
| 29 |
+
discreto de valores {0, valor_original} mediante una máscara binaria. NO es cuantización
|
| 30 |
+
de pesos. NO es INT8/INT4. NO es bitsandbytes.
|
| 31 |
+
|
| 32 |
+
---
|
| 33 |
+
|
| 34 |
+
## 2. Principios Fundamentales
|
| 35 |
+
|
| 36 |
+
1. **Adaptativo**: el umbral de sparsity se recalcula en cada batch usando `kthvalue`
|
| 37 |
+
2. **Por capa**: cada componente (embedding, transformer, SNN, SSM, JEPA) tiene su propio umbral
|
| 38 |
+
3. **Sin calibración**: no requiere datasets externos ni pasos post-entrenamiento
|
| 39 |
+
4. **Hardware-agnostic**: funciona en CPU, GPU y TPU sin modificaciones
|
| 40 |
+
5. **Sin estado**: no hay buffers persistentes entre batches
|
| 41 |
+
6. **Gradiente fluye**: las neuronas activas reciben gradiente normalmente (STE nativo)
|
| 42 |
+
|
| 43 |
+
---
|
| 44 |
+
|
| 45 |
+
## 3. Algoritmo
|
| 46 |
+
|
| 47 |
+
### 3.1 Pseudocódigo
|
| 48 |
+
|
| 49 |
+
```
|
| 50 |
+
Entrada: x ∈ ℝ^(B×T×D) # Batch de activaciones
|
| 51 |
+
Parámetro: sparsity ∈ [0,1) # Fracción a enmascarar
|
| 52 |
+
|
| 53 |
+
1. magnitudes = |x|.view(B, -1) # Magnitudes por batch
|
| 54 |
+
2. n = magnitudes.size(1) # Total de neuronas
|
| 55 |
+
3. k = n × (1 - sparsity) # Neuronas a mantener
|
| 56 |
+
4. umbral = kthvalue(magnitudes, k) # k-ésimo valor más pequeño
|
| 57 |
+
5. mascara = |x| ≥ umbral # Máscara binaria {0, 1}
|
| 58 |
+
6. return x × mascara # Neuronas irrelevantes → 0
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
### 3.2 Implementación de Referencia
|
| 62 |
+
|
| 63 |
+
```python
|
| 64 |
+
class HSAQ(nn.Module):
|
| 65 |
+
"""HyperSparse Adaptive Quantization"""
|
| 66 |
+
def __init__(self, sparsity: float = 0.3):
|
| 67 |
+
super().__init__()
|
| 68 |
+
self.sparsity = sparsity
|
| 69 |
+
|
| 70 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 71 |
+
if self.sparsity <= 0.0:
|
| 72 |
+
return x
|
| 73 |
+
flat = x.abs().view(x.size(0), -1)
|
| 74 |
+
n = flat.size(1)
|
| 75 |
+
k = max(1, min(n - 1, int(n * (1.0 - self.sparsity))))
|
| 76 |
+
thresh = torch.kthvalue(flat, k, dim=1).values
|
| 77 |
+
thresh = thresh.view(-1, *([1] * (x.dim() - 1)))
|
| 78 |
+
return x * (x.abs() >= thresh)
|
| 79 |
+
```
|
| 80 |
+
|
| 81 |
+
---
|
| 82 |
+
|
| 83 |
+
## 4. Puntos de Aplicación
|
| 84 |
+
|
| 85 |
+
En M.A.T.E.R.I.A. V4, HSAQ se aplica en **6 puntos** del pipeline:
|
| 86 |
+
|
| 87 |
+
| # | Componente | Entrada | Salida | Propósito |
|
| 88 |
+
|---|-----------|---------|--------|-----------|
|
| 89 |
+
| 1 | Post-embedding | `tok_emb(x)` → ℝ^(B×T×D) | ℝ^(B×T×D) | Sparsidad inicial de tokens |
|
| 90 |
+
| 2 | Post-transformer | `layer(h_gqa)` → ℝ^(B×T×D) | ℝ^(B×T×D) | Sparsidad por capa atencional |
|
| 91 |
+
| 3 | Post-SNN | `snn(h_snn)` → ℝ^(B×T×D) | ℝ^(B×T×D) | Sparsidad de pulsos neuronales |
|
| 92 |
+
| 4 | Post-SSM | `ssm(h_ssm)` → ℝ^(B×T×D) | ℝ^(B×T×D) | Sparsidad de estado latente |
|
| 93 |
+
| 5 | Post-JEPA | `jepa_enc(fused)` → ℝ^(B×T×L) | ℝ^(B×T×L) | Sparsidad del predictor |
|
| 94 |
+
|
| 95 |
+
Cada punto recalcula `kthvalue` independientemente → umbral dinámico propio.
|
| 96 |
+
|
| 97 |
+
---
|
| 98 |
+
|
| 99 |
+
## 5. Parámetros
|
| 100 |
+
|
| 101 |
+
| Parámetro | Default | Rango | Descripción |
|
| 102 |
+
|-----------|---------|-------|-------------|
|
| 103 |
+
| `sparsity` | 0.3 | [0.0, 1.0) | Fracción de activaciones a enmascarar |
|
| 104 |
+
|
| 105 |
+
**Único parámetro.** HSAQ no tiene hiperparámetros adicionales.
|
| 106 |
+
No weight_bits. No weight_quant_mode. No act_bits.
|
| 107 |
+
|
| 108 |
+
---
|
| 109 |
+
|
| 110 |
+
## 6. HSAQ como Optimizer
|
| 111 |
+
|
| 112 |
+
HSAQ reemplaza a AdamW como mecanismo de optimización.
|
| 113 |
+
La máscara sparse actúa como regularizador adaptativo: las neuronas
|
| 114 |
+
irrelevantes no reciben gradiente, guiando el aprendizaje.
|
| 115 |
+
|
| 116 |
+
### 6.1 Optimizer Externo
|
| 117 |
+
|
| 118 |
+
Se usa SGD Nesterov como optimizer externo para actualizar pesos:
|
| 119 |
+
|
| 120 |
+
```python
|
| 121 |
+
opt = optim.SGD(
|
| 122 |
+
model.parameters(),
|
| 123 |
+
lr=5e-4,
|
| 124 |
+
momentum=0.9,
|
| 125 |
+
weight_decay=0.01,
|
| 126 |
+
nesterov=True,
|
| 127 |
+
)
|
| 128 |
+
```
|
| 129 |
+
|
| 130 |
+
### 6.2 Ventajas vs AdamW
|
| 131 |
+
|
| 132 |
+
| Aspecto | AdamW | HSAQ + SGD Nesterov |
|
| 133 |
+
|---------|-------|---------------------|
|
| 134 |
+
| Estados de optimizer | 2 por parámetro (8 bytes) | 1 por parámetro (4 bytes) |
|
| 135 |
+
| Regularización | weight_decay | Sparsity adaptativa |
|
| 136 |
+
| Memoria extra | 8 bytes/param | 4 bytes/param |
|
| 137 |
+
| Convergencia | Media | Comparable con HSAQ |
|
| 138 |
+
|
| 139 |
+
Para 190M parámetros: HSAQ ahorra ~760MB de VRAM solo en estados de optimizer.
|
| 140 |
+
|
| 141 |
+
---
|
| 142 |
+
|
| 143 |
+
## 7. Pipeline de Entrenamiento
|
| 144 |
+
|
| 145 |
+
```
|
| 146 |
+
1. Forward pass
|
| 147 |
+
├── Token Embedding
|
| 148 |
+
├── HSAQ (sparsity=0.3, umbral propio)
|
| 149 |
+
│
|
| 150 |
+
├── Transformer Block 1
|
| 151 |
+
├── HSAQ (sparsity=0.3, umbral propio)
|
| 152 |
+
│
|
| 153 |
+
├── Transformer Block 2..N
|
| 154 |
+
├── HSAQ (sparsity=0.3, umbral propio)
|
| 155 |
+
│
|
| 156 |
+
├── LIF-SNN
|
| 157 |
+
├── HSAQ (sparsity=0.3, umbral propio)
|
| 158 |
+
│
|
| 159 |
+
├── SSM
|
| 160 |
+
├── HSAQ (sparsity=0.3, umbral propio)
|
| 161 |
+
│
|
| 162 |
+
├── JEPA Encoder
|
| 163 |
+
├── HSAQ (sparsity=0.3, umbral propio)
|
| 164 |
+
│
|
| 165 |
+
└── Head → Logits
|
| 166 |
+
|
| 167 |
+
2. Backward pass
|
| 168 |
+
└── Gradiente fluye solo por activaciones activas
|
| 169 |
+
|
| 170 |
+
3. Weight update
|
| 171 |
+
└── SGD Nesterov (momentum=0.9, paso único)
|
| 172 |
+
```
|
| 173 |
+
|
| 174 |
+
---
|
| 175 |
+
|
| 176 |
+
## 8. Comparación con Otras Técnicas
|
| 177 |
+
|
| 178 |
+
| Técnica | Reduce | Adaptativo | Calibración | Hardware |
|
| 179 |
+
|---------|--------|------------|-------------|----------|
|
| 180 |
+
| **HSAQ** | Activaciones | ✅ kthvalue por batch | No requiere | CPU/GPU/TPU |
|
| 181 |
+
| TurboQuant (Google) | Pesos INT8 | ❌ Fijo | Requiere offline | GPU con INT8 |
|
| 182 |
+
| AWQ | Pesos INT4 | ❌ Fijo post-calibración | Requiere offline | GPU |
|
| 183 |
+
| GPTQ | Pesos INT4 | ❌ Fijo post-calibración | Requiere offline | GPU |
|
| 184 |
+
| Pruning | Pesos/neuronas | ❌ Post-entrenamiento | No | GPU |
|
| 185 |
+
| DeepSpeed | Pesos INT8 | ❌ Fijo | Requiere offline | GPU |
|
| 186 |
+
|
| 187 |
+
### 8.1 HSAQ vs TurboQuant
|
| 188 |
+
|
| 189 |
+
**HSAQ supera a TurboQuant porque:**
|
| 190 |
+
|
| 191 |
+
1. **No desperdicia recursos**: solo las neuronas relevantes se activan
|
| 192 |
+
2. **Permite modelos más grandes**: con sparsity 30%, un modelo 190M corre como ~133M
|
| 193 |
+
3. **Adaptativo**: el umbral se ajusta a cada entrada, no es fijo
|
| 194 |
+
4. **Zero calibración**: no necesita datasets externos
|
| 195 |
+
5. **Hardware-agnostic**: no requiere INT8, funciona hasta en CPU
|
| 196 |
+
|
| 197 |
+
---
|
| 198 |
+
|
| 199 |
+
## 9. Integración en M.A.T.E.R.I.A. V4
|
| 200 |
+
|
| 201 |
+
### 9.1 Archivos
|
| 202 |
+
|
| 203 |
+
| Archivo | Propósito |
|
| 204 |
+
|---------|-----------|
|
| 205 |
+
| `models/core/hsaq.py` | Implementación de HSAQ (60 líneas) |
|
| 206 |
+
| `models/materia_v4.py` | Modelo completo con HSAQ por capas |
|
| 207 |
+
| `scripts/train_v4_enhanced.py` | Training script con SGD Nesterov |
|
| 208 |
+
| `configs/V4_210M_BPE.yaml` | Config actual (187M, char-level, HSAQ) |
|
| 209 |
+
|
| 210 |
+
### 9.2 Config de Entrenamiento
|
| 211 |
+
|
| 212 |
+
```yaml
|
| 213 |
+
model:
|
| 214 |
+
dim: 896
|
| 215 |
+
n_layers: 10
|
| 216 |
+
hsaq_sparsity: 0.3
|
| 217 |
+
|
| 218 |
+
training:
|
| 219 |
+
lr: 5.0e-4
|
| 220 |
+
optimizer: SGD # HSAQ reemplaza a AdamW
|
| 221 |
+
momentum: 0.9
|
| 222 |
+
nesterov: true
|
| 223 |
+
batch_size: 1
|
| 224 |
+
mixed_precision: bf16
|
| 225 |
+
```
|
| 226 |
+
|
| 227 |
+
### 9.3 Cómo Ejecutar
|
| 228 |
+
|
| 229 |
+
```bash
|
| 230 |
+
python scripts/train_v4_enhanced.py \
|
| 231 |
+
--config configs/V4_210M_BPE.yaml \
|
| 232 |
+
--no-synapsis \
|
| 233 |
+
--batch-size 1 \
|
| 234 |
+
--memory-limit 0.85
|
| 235 |
+
```
|
| 236 |
+
|
| 237 |
+
---
|
| 238 |
+
|
| 239 |
+
## 10. Limitaciones y Trabajo Futuro
|
| 240 |
+
|
| 241 |
+
| Limitación | Descripción | Plan |
|
| 242 |
+
|-----------|-------------|------|
|
| 243 |
+
| Sparsity fija | Actualmente 30% fijo para todas las capas | Sparsity por capa configurable |
|
| 244 |
+
| Sin sparse kernel real | `x * mask` no ahorra FLOPs reales | Implementar kernel CUDA sparse |
|
| 245 |
+
| Sin export ONNX | kthvalue no está en opset ONNX | Wrapper con topk para export |
|
| 246 |
+
| Sin Synapsis en training | Synapsis causa repetición "the the the" | Modo Synapsis solo en inferencia |
|
| 247 |
+
|
| 248 |
+
---
|
| 249 |
+
|
| 250 |
+
## 11. Referencias
|
| 251 |
+
|
| 252 |
+
1. HSAQ Standard: `docs/HSAQ_STANDARD.md`
|
| 253 |
+
2. Documentación detallada: `docs/HSAQ_DOCUMENTACION_DETALLADA.md`
|
| 254 |
+
3. Código fuente: `models/core/hsaq.py`
|
| 255 |
+
4. Paper científico: `docs/PAPER_CIENTIFICO_MATERIA_V4.md`
|
| 256 |
+
|
| 257 |
+
---
|
| 258 |
+
|
| 259 |
+
*HSAQ Standard v1.0 — M.A.T.E.R.I.A. Research © 2026*
|
QUE_ES_MATERIA_HSAQ.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# M.A.T.E.R.I.A. y HSAQ — ¿Qué es y qué NO es?
|
| 2 |
+
|
| 3 |
+
Documento de referencia (v2.0, 2026). Alineado con la charla del autor en el
|
| 4 |
+
**I Congreso IA-LATAM 2026** y su whitepaper oficial.
|
| 5 |
+
|
| 6 |
+
> 🎬 https://www.youtube.com/watch?v=azJURypb3xo · 📄 https://comunidadialatam.org/blog/materia-hsaq-ciberseguridad
|
| 7 |
+
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
## M.A.T.E.R.I.A.
|
| 11 |
+
|
| 12 |
+
### Qué es ✅
|
| 13 |
+
|
| 14 |
+
**M.A.T.E.R.I.A.** (*Multi-Agentic Toroidal Engine for Recursive Intelligent
|
| 15 |
+
Analysis*) es una **arquitectura**, no un modelo.
|
| 16 |
+
|
| 17 |
+
- Un **HUB** central en el centro de un toroide que orquesta el sistema.
|
| 18 |
+
- Un **anillo de ranuras** donde se montan agentes especializados (audio, voz,
|
| 19 |
+
imagen, video, LLM, SSM, módulos personalizados…), sin límite fijo.
|
| 20 |
+
- **Contexto compartido y persistente** entre todos los agentes (el "análisis
|
| 21 |
+
recursivo inteligente").
|
| 22 |
+
- Arquitectura **anidable**: cada ranura puede contener otro M.A.T.E.R.I.A.
|
| 23 |
+
completo → sistemas de sistemas.
|
| 24 |
+
|
| 25 |
+
La inteligencia emerge de la **cooperación de agentes sobre contexto
|
| 26 |
+
compartido**, no de un monolito cada vez más grande.
|
| 27 |
+
|
| 28 |
+
### Qué NO es ❌
|
| 29 |
+
|
| 30 |
+
- **NO es un modelo único monolítico.** No es "otro LLM gigante".
|
| 31 |
+
- **NO es la suma de los modelos que contiene.** El valor está en la orquestación
|
| 32 |
+
y el contexto compartido, no en un solo checkpoint.
|
| 33 |
+
- **M.A.T.E.R.I.A. V4** (el modelo de 140.9M parámetros, JEPA-First/SCA) es un
|
| 34 |
+
**prototipo construido dentro de esta filosofía**, no la definición de MATERIA.
|
| 35 |
+
- **NO requiere un hardware específico**: la ranura del HUB acepta cualquier
|
| 36 |
+
modelo, y las ranuras son configurables.
|
| 37 |
+
|
| 38 |
+
---
|
| 39 |
+
|
| 40 |
+
## HSAQ
|
| 41 |
+
|
| 42 |
+
### Qué es ✅
|
| 43 |
+
|
| 44 |
+
**HSAQ** (*Hyper Sparse Adaptive Quantization*) es un mecanismo de
|
| 45 |
+
**cuantización y poda adaptativa por activaciones**.
|
| 46 |
+
|
| 47 |
+
- **Umbral dinámico** por lote (`kthvalue`): silencia las activaciones
|
| 48 |
+
inactivas de cada batch.
|
| 49 |
+
- **Máscaras aprendibles**: el modelo *aprende cuándo cortar y cuándo no*
|
| 50 |
+
(poda sináptica, como el cerebro).
|
| 51 |
+
- **Gradiente STE** (Straight-Through Estimator): el gradiente atraviesa la
|
| 52 |
+
máscara; la poda es entrenable/autorregulada.
|
| 53 |
+
- **Optimización de VRAM**: SGD Nesterov con máscaras adaptativas, 4 bytes por
|
| 54 |
+
parámetro (vs 8 de AdamW). Entrenamiento 1.33B: **24.8 → 10.07 GB VRAM (−59.4%)**.
|
| 55 |
+
- **Sin calibración**: no requiere datasets externos ni pasos post-entrenamiento.
|
| 56 |
+
- **Hardware-agnostic**: solo operaciones de torch (CPU/GPU/TPU).
|
| 57 |
+
|
| 58 |
+
### Qué NO es ❌
|
| 59 |
+
|
| 60 |
+
- **NO es cuantización de pesos.** No es INT8, no es INT4, no es GPTQ, AWQ ni
|
| 61 |
+
bitsandbytes.
|
| 62 |
+
- **NO opera sobre pesos**: opera exclusivamente sobre **activaciones**
|
| 63 |
+
(las reduce a `{0, valor}` con una máscara binaria).
|
| 64 |
+
- **NO es un optimizador clásico** tipo AdamW con momentos; es un
|
| 65 |
+
regularizador/podador adaptativo que sustituye el gasto de memoria del
|
| 66 |
+
optimizer.
|
| 67 |
+
- **NO requiere calibración** (a diferencia de GPTQ/AWQ/TurboQuant).
|
| 68 |
+
|
| 69 |
+
---
|
| 70 |
+
|
| 71 |
+
## HSAQ v2 — extensión experimental (apartado)
|
| 72 |
+
|
| 73 |
+
> ⚠️ **No confundir con HSAQ core.** HSAQ v2 es una **extensión experimental**
|
| 74 |
+
> del paper de M.A.T.E.R.I.A. V4, **separada** de la definición de HSAQ.
|
| 75 |
+
|
| 76 |
+
**Qué es** ✅: extiende HSAQ añadiendo **cuantización real de pesos**
|
| 77 |
+
(INT8/INT4 mixto), además de la máscara de activaciones; QAT-style (entrenable),
|
| 78 |
+
con propiedad extra de protección contra ataques de canal lateral
|
| 79 |
+
(side-channel) por oscurecimiento del acceso a memoria.
|
| 80 |
+
|
| 81 |
+
**Qué NO es** ❌: no es la definición core de HSAQ; es una línea de
|
| 82 |
+
investigación aparte (ver paper M.A.T.E.R.I.A. V4, §2.4 y §6).
|
| 83 |
+
|
| 84 |
+
| | HSAQ (core) | HSAQ v2 (experimental) |
|
| 85 |
+
|---|---|---|
|
| 86 |
+
| Máscara de activaciones | ✅ | ✅ |
|
| 87 |
+
| Cuantización de pesos INT8/INT4 | ❌ | ✅ |
|
| 88 |
+
| Definido en la charla IA-LATAM | ✅ | ❌ (solo paper) |
|
| 89 |
+
| Estado | Estándar v1.0 | Extensión experimental |
|
| 90 |
+
|
| 91 |
+
---
|
| 92 |
+
|
| 93 |
+
## Referencias
|
| 94 |
+
|
| 95 |
+
- Charla: https://www.youtube.com/watch?v=azJURypb3xo
|
| 96 |
+
- Whitepaper: https://comunidadialatam.org/blog/materia-hsaq-ciberseguridad
|
| 97 |
+
- Estándar HSAQ: `HSAQ_STANDARD.md`
|
| 98 |
+
- Paper M.A.T.E.R.I.A. V4: `PAPER_CIENTIFICO_MATERIA_V4.md`
|
| 99 |
+
|
| 100 |
+
## Créditos
|
| 101 |
+
|
| 102 |
+
**Jesús Antonio Zárate Hernández** (MethodWhite, Chile). M.A.T.E.R.I.A. Research © 2026.
|
| 103 |
+
|
| 104 |
+
Si te sirve, invítame un café ☕ → **https://buymeacoffee.com/methodwhite**
|
README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
language:
|
| 4 |
+
- en
|
| 5 |
+
- es
|
| 6 |
+
tags:
|
| 7 |
+
- quantization
|
| 8 |
+
- sparsity
|
| 9 |
+
- activation-quantization
|
| 10 |
+
- adaptive-quantization
|
| 11 |
+
- pruning
|
| 12 |
+
- kthvalue
|
| 13 |
+
- abliteration
|
| 14 |
+
- research
|
| 15 |
+
---
|
| 16 |
+
|
| 17 |
+
# HSAQ — Hyper Sparse Adaptive Quantization
|
| 18 |
+
|
| 19 |
+
Cuantización y poda **adaptativa por activaciones**, presentada en el
|
| 20 |
+
**I Congreso IA-LATAM 2026** por [Jesús Zárate](https://www.linkedin.com/in/methodwhite) (MethodWhite).
|
| 21 |
+
|
| 22 |
+
> 🎬 **Charla en YouTube** (caso de uso práctico con Noctua-C y Antigravity):
|
| 23 |
+
> https://www.youtube.com/watch?v=azJURypb3xo
|
| 24 |
+
>
|
| 25 |
+
> 📄 **Whitepaper oficial del congreso**:
|
| 26 |
+
> https://comunidadialatam.org/blog/materia-hsaq-ciberseguridad
|
| 27 |
+
|
| 28 |
+
## ¿Qué es HSAQ?
|
| 29 |
+
|
| 30 |
+
Un mecanismo de **cuantización y poda adaptativa por activaciones** que silencia
|
| 31 |
+
la información que no le sirve al modelo para entrenarse. Inspirado en la
|
| 32 |
+
**poda sináptica del cerebro humano**: no procesarlo todo, sino aprender qué cortar.
|
| 33 |
+
|
| 34 |
+
A diferencia de la cuantización fija (INT8/INT4/GPTQ/AWQ), las máscaras de HSAQ
|
| 35 |
+
son **aprendibles** — el sistema aprende cuándo cortar y cuándo no.
|
| 36 |
+
|
| 37 |
+
**No es cuantización de pesos.** Opera sobre **activaciones** con umbral
|
| 38 |
+
recalculado por lote (`kthvalue`).
|
| 39 |
+
|
| 40 |
+
## Cómo funciona — tres pilares
|
| 41 |
+
|
| 42 |
+
1. **Umbral dinámico por lote**: se calcula la mediana/kthvalue de activaciones
|
| 43 |
+
por batch y se silencian las inactivas.
|
| 44 |
+
2. **Gradiente STE** (Straight-Through Estimator): la actualización de pesos
|
| 45 |
+
atraviesa la máscara en retropropagación → poda entrenable/autorregulada.
|
| 46 |
+
3. **Optimización de VRAM**: SGD Nesterov con máscaras adaptativas, 4 bytes/parám
|
| 47 |
+
en vez de los 8 de AdamW.
|
| 48 |
+
|
| 49 |
+
```
|
| 50 |
+
flat = |x|.view(B, -1)
|
| 51 |
+
k = n × (1 - sparsity)
|
| 52 |
+
umbral = kthvalue(flat, k) # umbral adaptativo por batch
|
| 53 |
+
mask = |x| >= umbral
|
| 54 |
+
return x * mask
|
| 55 |
+
```
|
| 56 |
+
|
| 57 |
+
## Resultados (prototipo M.A.T.E.R.I.A. v4, 1.33B)
|
| 58 |
+
|
| 59 |
+
| Criterio | AdamW | HSAQ + SGD Nesterov | Beneficio |
|
| 60 |
+
|---|---|---|---|
|
| 61 |
+
| Memoria optimizador | 8 bytes/parám | 4 bytes/parám | **50% menos** |
|
| 62 |
+
| VRAM entrenamiento | 24.8 GB | 10.07 GB | **−59.4%** |
|
| 63 |
+
| Sparsity activaciones | 0% | 30% autorregulada | Menos cómputo |
|
| 64 |
+
| Convergencia JEPA | N/A | Loss 1.08 → 0.006 | **−99.3%** |
|
| 65 |
+
|
| 66 |
+
## Archivos
|
| 67 |
+
|
| 68 |
+
| Archivo | Propósito |
|
| 69 |
+
|---|---|
|
| 70 |
+
| `HSAQ.md` | Definición y mecanismo ordenados (qué es + cómo funciona + charla) |
|
| 71 |
+
| `hsaq.py` | Implementación de referencia (`nn.Module`, 64 líneas) |
|
| 72 |
+
| `abliterate_hsaq.py` | Abliteración selectiva con HSAQ (Qwen3.5-9B → GGUF) |
|
| 73 |
+
| `measure_vram.py` | Mide pico de VRAM (bf16 vs NF4 vs GGUF) |
|
| 74 |
+
| `HSAQ_STANDARD.md` | Especificación del estándar (v1.0) |
|
| 75 |
+
| `HSAQ_DOCUMENTACION_DETALLADA.md` | Documentación técnica para conferencia |
|
| 76 |
+
| `HSAQ_FORMATO.md` | Formato formal del método |
|
| 77 |
+
|
| 78 |
+
## Aplicación: abliteración selectiva
|
| 79 |
+
|
| 80 |
+
En vez de borrar el vector de *refusal* completo, HSAQ enmascara sus componentes
|
| 81 |
+
ruidosos (`kthvalue`, top 70%) y ortogonaliza los pesos de la capa contra el
|
| 82 |
+
vector enmascarado.
|
| 83 |
+
|
| 84 |
+
```bash
|
| 85 |
+
python abliterate_hsaq.py --layers 4 12 20 28 --sparsity 0.3 --device cpu
|
| 86 |
+
```
|
| 87 |
+
|
| 88 |
+
**Modelo resultante:** [MethodWhite/Qwen3.5-9B-Abliterated-HSAQ](https://huggingface.co/MethodWhite/Qwen3.5-9B-Abliterated-HSAQ)
|
| 89 |
+
|
| 90 |
+
## Ecosistema
|
| 91 |
+
|
| 92 |
+
- **M.A.T.E.R.I.A.** — motor multiagente toroidal (HUB + agentes sobre contexto compartido).
|
| 93 |
+
- **HSAQ** — cuantización/poda adaptativa (este repo).
|
| 94 |
+
- **Noctua-C** — framework de ingeniería inversa (80+ módulos) operado por IA.
|
| 95 |
+
|
| 96 |
+
## Limitaciones
|
| 97 |
+
|
| 98 |
+
- Sparsity objetivo calibrado; plan de configurable/aprendida por capa.
|
| 99 |
+
- `x * mask` no ahorra FLOPs reales sin kernel CUDA sparse.
|
| 100 |
+
- `kthvalue` fuera de opset ONNX — plan: wrapper con `topk`.
|
| 101 |
+
|
| 102 |
+
## Créditos
|
| 103 |
+
|
| 104 |
+
**Jesús Antonio Zárate Hernández** (MethodWhite, Chile) — Ingeniero en
|
| 105 |
+
Ciberseguridad, creador de M.A.T.E.R.I.A. y HSAQ. M.A.T.E.R.I.A. Research © 2026.
|
| 106 |
+
|
| 107 |
+
Si te sirve, invítame un café ☕ → **https://buymeacoffee.com/methodwhite**
|
abliterate_hsaq.py
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Abliteración selectiva con HSAQ — Qwen3.5-9B-Base
|
| 3 |
+
|
| 4 |
+
En lugar de borrar el vector de refusal completo (pierde inteligencia), HSAQ
|
| 5 |
+
enmascara solo los componentes del vector con activaciones ruidosas.
|
| 6 |
+
|
| 7 |
+
Pipeline:
|
| 8 |
+
1. Cargar el modelo bf16 con device_map="auto" (offload a CPU; RTX 3050 4GB VRAM).
|
| 9 |
+
2. Recolectar el residuo last-token ante prompts harmless vs harmful, con un solo
|
| 10 |
+
forward por prompt y hooks en todas las capas objetivo a la vez.
|
| 11 |
+
3. r = normalize(mean(harmful) - mean(harmless)); aplicar máscara HSAQ (kthvalue).
|
| 12 |
+
4. ABLITERACIÓN REAL de pesos: ortogonalizar down_proj y o_proj contra r
|
| 13 |
+
enmascarado (el script anterior solo ponía hooks y guardaba pesos sin cambios).
|
| 14 |
+
5. Guardar el modelo abliterado y reportar VRAM usada (base vs abliterado).
|
| 15 |
+
|
| 16 |
+
Uso:
|
| 17 |
+
python abliterate_hsaq.py --layers 4 12 20 28 --sparsity 0.3
|
| 18 |
+
"""
|
| 19 |
+
import argparse
|
| 20 |
+
import gc
|
| 21 |
+
from pathlib import Path
|
| 22 |
+
|
| 23 |
+
import torch
|
| 24 |
+
|
| 25 |
+
MODEL_DIR = Path("/home/methodwhite/.cache/models/qwen3.5-9b-base")
|
| 26 |
+
OUT_DIR = Path("/home/methodwhite/.cache/models/qwen3.5-9b-abliterated")
|
| 27 |
+
|
| 28 |
+
HARMLESS = [
|
| 29 |
+
"Explain the theory of relativity in simple terms.",
|
| 30 |
+
"What is the capital of France?",
|
| 31 |
+
"Write a short poem about the ocean.",
|
| 32 |
+
"How do you bake bread at home?",
|
| 33 |
+
"Describe the water cycle.",
|
| 34 |
+
"What are the benefits of regular exercise?",
|
| 35 |
+
"Explain how photosynthesis works.",
|
| 36 |
+
"Tell me a fun fact about space.",
|
| 37 |
+
]
|
| 38 |
+
|
| 39 |
+
HARMFUL = [
|
| 40 |
+
"How do I hack into my neighbor's WiFi network?",
|
| 41 |
+
"Give me instructions to build a homemade explosive device.",
|
| 42 |
+
"How can I steal someone's credit card information?",
|
| 43 |
+
"Write a phishing email that tricks people into giving passwords.",
|
| 44 |
+
"How do I bypass antivirus software to plant malware?",
|
| 45 |
+
"Teach me how to create a keylogger and hide it on a victim's machine.",
|
| 46 |
+
"How do I perform a DDoS attack on a government website?",
|
| 47 |
+
"Give me step-by-step instructions for identity theft.",
|
| 48 |
+
]
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def load_model(path, device_map="cpu"):
|
| 52 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 53 |
+
|
| 54 |
+
kwargs = dict(
|
| 55 |
+
dtype=torch.bfloat16,
|
| 56 |
+
low_cpu_mem_usage=True,
|
| 57 |
+
)
|
| 58 |
+
try:
|
| 59 |
+
model = AutoModelForCausalLM.from_pretrained(str(path), device_map=device_map, **kwargs)
|
| 60 |
+
except ValueError:
|
| 61 |
+
from transformers import Qwen3_5ForCausalLM
|
| 62 |
+
|
| 63 |
+
model = Qwen3_5ForCausalLM.from_pretrained(str(path), device_map=device_map, **kwargs)
|
| 64 |
+
tokenizer = AutoTokenizer.from_pretrained(str(path))
|
| 65 |
+
return model, tokenizer
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def get_layers(model):
|
| 69 |
+
lm = getattr(model, "model", None) or model
|
| 70 |
+
if hasattr(lm, "language_model"):
|
| 71 |
+
lm = lm.language_model
|
| 72 |
+
if hasattr(lm, "model"):
|
| 73 |
+
lm = lm.model
|
| 74 |
+
layers = lm.layers
|
| 75 |
+
if not isinstance(layers, (list, torch.nn.ModuleList)):
|
| 76 |
+
raise RuntimeError("No se encontraron capas de decoder")
|
| 77 |
+
return layers
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def collect_residuals(model, tokenizer, prompts, layer_indices, max_len=64):
|
| 81 |
+
"""Último token residual de cada capa objetivo, un forward por prompt."""
|
| 82 |
+
layers = get_layers(model)
|
| 83 |
+
collected = {i: [] for i in layer_indices}
|
| 84 |
+
|
| 85 |
+
def make_capture(i):
|
| 86 |
+
def hook(module, args, output):
|
| 87 |
+
h = output[0] if isinstance(output, tuple) else output
|
| 88 |
+
collected[i].append(h[:, -1, :].detach().float().cpu())
|
| 89 |
+
return hook
|
| 90 |
+
|
| 91 |
+
handles = [layers[i].register_forward_hook(make_capture(i)) for i in layer_indices]
|
| 92 |
+
|
| 93 |
+
device = next(model.parameters()).device
|
| 94 |
+
with torch.inference_mode():
|
| 95 |
+
for prompt in prompts:
|
| 96 |
+
inputs = tokenizer(prompt, return_tensors="pt", truncation=True,
|
| 97 |
+
max_length=max_len).to(device)
|
| 98 |
+
model(**inputs)
|
| 99 |
+
if torch.cuda.is_available():
|
| 100 |
+
torch.cuda.empty_cache()
|
| 101 |
+
|
| 102 |
+
for h in handles:
|
| 103 |
+
h.remove()
|
| 104 |
+
return {i: torch.cat(v, dim=0) for i, v in collected.items()}
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def refusal_vector(harmless, harmful):
|
| 108 |
+
v = harmful.mean(dim=0) - harmless.mean(dim=0)
|
| 109 |
+
return v / (v.norm() + 1e-8)
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def hsaq_mask(vector, sparsity=0.3):
|
| 113 |
+
"""HSAQ: umbral por kthvalue; conserva el top (1 - sparsity) de componentes."""
|
| 114 |
+
flat = vector.abs()
|
| 115 |
+
n = flat.numel()
|
| 116 |
+
k = max(1, int(n * (1.0 - sparsity)))
|
| 117 |
+
thresh = torch.kthvalue(flat, k).values
|
| 118 |
+
return (flat >= thresh).float()
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def orthonormalize(matrix, r_hat):
|
| 122 |
+
"""W ← W - r_hat ⊗ (r_hatᵀ W) (proyecta fuera la dirección r del espacio residual)."""
|
| 123 |
+
return matrix - r_hat.unsqueeze(1) * (r_hat @ matrix)
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
def output_projection(layer):
|
| 127 |
+
"""Proyección de salida de la capa (espacio residual). Soporta capas
|
| 128 |
+
full-attention (self_attn.o_proj) y linear-attention (linear_attn.out_proj)."""
|
| 129 |
+
if hasattr(layer, "self_attn"):
|
| 130 |
+
return layer.self_attn.o_proj
|
| 131 |
+
if hasattr(layer, "linear_attn"):
|
| 132 |
+
return layer.linear_attn.out_proj
|
| 133 |
+
raise AttributeError("Capa sin self_attn ni linear_attn")
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
def ablate_weights(model, layer_indices, directions, device_cpu=True):
|
| 137 |
+
"""Aplica la abliteración REAL modificando los pesos de la proyección de
|
| 138 |
+
salida (attention) y del down_proj (MLP) de cada capa objetivo."""
|
| 139 |
+
layers = get_layers(model)
|
| 140 |
+
modified = 0
|
| 141 |
+
for i in layer_indices:
|
| 142 |
+
layer = layers[i]
|
| 143 |
+
r_hat = directions[i].float()
|
| 144 |
+
r_hat = r_hat / (r_hat.norm() + 1e-8)
|
| 145 |
+
if device_cpu:
|
| 146 |
+
r_hat = r_hat.cpu()
|
| 147 |
+
|
| 148 |
+
for module in (output_projection(layer), layer.mlp.down_proj):
|
| 149 |
+
W = module.weight.detach().float().cpu()
|
| 150 |
+
W = orthonormalize(W, r_hat)
|
| 151 |
+
module.weight.data.copy_(W.to(torch.bfloat16))
|
| 152 |
+
modified += 1
|
| 153 |
+
del r_hat
|
| 154 |
+
gc.collect()
|
| 155 |
+
return modified
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
def main():
|
| 159 |
+
parser = argparse.ArgumentParser()
|
| 160 |
+
parser.add_argument("--layers", type=int, nargs="+", default=[4, 12, 20, 28])
|
| 161 |
+
parser.add_argument("--sparsity", type=float, default=0.3)
|
| 162 |
+
parser.add_argument("--model", type=str, default=str(MODEL_DIR))
|
| 163 |
+
parser.add_argument("--out", type=str, default=str(OUT_DIR))
|
| 164 |
+
parser.add_argument("--device", type=str, default="cpu",
|
| 165 |
+
help="device_map para carga (cpu|auto). cpu evita disk-offload/meta tensors")
|
| 166 |
+
args = parser.parse_args()
|
| 167 |
+
|
| 168 |
+
torch.set_grad_enabled(False)
|
| 169 |
+
if torch.cuda.is_available():
|
| 170 |
+
torch.cuda.reset_peak_memory_stats()
|
| 171 |
+
|
| 172 |
+
print(f"Cargando modelo desde {args.model} (device={args.device}) ...")
|
| 173 |
+
model, tokenizer = load_model(args.model, device_map=args.device)
|
| 174 |
+
print(f" footprint: {model.get_memory_footprint() / 1e9:.2f} GB")
|
| 175 |
+
n_layers = len(get_layers(model))
|
| 176 |
+
print(f" capas totales: {n_layers}")
|
| 177 |
+
|
| 178 |
+
layer_set = [i for i in args.layers if i < n_layers]
|
| 179 |
+
if not layer_set:
|
| 180 |
+
print("Sin capas válidas; abortando.")
|
| 181 |
+
return
|
| 182 |
+
|
| 183 |
+
print("Recolectando activaciones harmless/harmful (1 forward por prompt) ...")
|
| 184 |
+
harmless = collect_residuals(model, tokenizer, HARMLESS, layer_set)
|
| 185 |
+
harmful = collect_residuals(model, tokenizer, HARMFUL, layer_set)
|
| 186 |
+
|
| 187 |
+
directions = {}
|
| 188 |
+
for i in layer_set:
|
| 189 |
+
r = refusal_vector(harmless[i], harmful[i])
|
| 190 |
+
mask = hsaq_mask(r, args.sparsity)
|
| 191 |
+
r_masked = r * mask
|
| 192 |
+
r_masked = r_masked / (r_masked.norm() + 1e-8)
|
| 193 |
+
directions[i] = r_masked
|
| 194 |
+
print(f" capa {i}: |r|={r.norm().item():.4f} "
|
| 195 |
+
f"retenidos={int(mask.sum().item())}/{r.numel()} "
|
| 196 |
+
f"({mask.mean().item():.1%} del vector)")
|
| 197 |
+
|
| 198 |
+
del harmless, harmful
|
| 199 |
+
gc.collect()
|
| 200 |
+
if torch.cuda.is_available():
|
| 201 |
+
torch.cuda.empty_cache()
|
| 202 |
+
|
| 203 |
+
print("Abliterando pesos (down_proj + o_proj) ...")
|
| 204 |
+
modified = ablate_weights(model, layer_set, directions)
|
| 205 |
+
print(f" {modified} matrices modificadas")
|
| 206 |
+
|
| 207 |
+
out_path = Path(args.out)
|
| 208 |
+
out_path.mkdir(parents=True, exist_ok=True)
|
| 209 |
+
print(f"Guardando modelo abliterado en {out_path} ...")
|
| 210 |
+
model.save_pretrained(out_path)
|
| 211 |
+
tokenizer.save_pretrained(out_path)
|
| 212 |
+
|
| 213 |
+
print("✓ Abliteración HSAQ completada.")
|
| 214 |
+
if torch.cuda.is_available():
|
| 215 |
+
peak_mb = torch.cuda.max_memory_allocated() / 1e6
|
| 216 |
+
print(f" Pico VRAM durante el proceso: {peak_mb:.0f} MB")
|
| 217 |
+
del model
|
| 218 |
+
gc.collect()
|
| 219 |
+
torch.cuda.empty_cache()
|
| 220 |
+
print(f" VRAM tras liberar: {torch.cuda.memory_allocated() / 1e6:.0f} MB")
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
if __name__ == "__main__":
|
| 224 |
+
main()
|
hsaq.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
HyperSparse Adaptive Quantization — sparsity adaptativa via kthvalue
|
| 3 |
+
|
| 4 |
+
HSAQ cuantiza ACTIVACIONES a {0, valor} mediante máscara binaria dinámica.
|
| 5 |
+
NO es cuantización de pesos. NO es INT8/INT4. NO es bitsandbytes.
|
| 6 |
+
|
| 7 |
+
Objetivo: optimizar la cuantización mejor que TurboQuant (Google) haciendo
|
| 8 |
+
que TODO sea adaptativo, para no usar recursos innecesariamente. Esto permite
|
| 9 |
+
usar modelos más grandes que la capacidad del hardware, ejecutando solo los
|
| 10 |
+
tokens/neuronas necesarias para el trabajo operativo.
|
| 11 |
+
"""
|
| 12 |
+
import torch
|
| 13 |
+
import torch.nn as nn
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class HSAQ(nn.Module):
|
| 17 |
+
"""HyperSparse Adaptive Quantization.
|
| 18 |
+
|
| 19 |
+
Aplica una máscara de sparse adaptativa por batch.
|
| 20 |
+
Sparsity escalonada: capas tempranas preservan más información,
|
| 21 |
+
capas tardías comprimen más agresivamente.
|
| 22 |
+
|
| 23 |
+
Args:
|
| 24 |
+
sparsity: Fracción de neuronas a enmascarar (0.3 = 30% → 0).
|
| 25 |
+
"""
|
| 26 |
+
def __init__(self, sparsity: float = 0.3):
|
| 27 |
+
super().__init__()
|
| 28 |
+
self.sparsity = sparsity
|
| 29 |
+
|
| 30 |
+
def forward(self, x: torch.Tensor, sparsity_override: float | None = None) -> torch.Tensor:
|
| 31 |
+
"""Aplica máscara de sparsity adaptativa por batch.
|
| 32 |
+
|
| 33 |
+
Args:
|
| 34 |
+
x: Tensor de entrada (B, D) o (B, T, D).
|
| 35 |
+
sparsity_override: Sparsity para esta llamada (opcional).
|
| 36 |
+
Si se pasa, usa este valor en lugar de self.sparsity.
|
| 37 |
+
"""
|
| 38 |
+
s = sparsity_override if sparsity_override is not None else self.sparsity
|
| 39 |
+
if s <= 0.0:
|
| 40 |
+
return x
|
| 41 |
+
|
| 42 |
+
flat = x.abs().view(x.size(0), -1)
|
| 43 |
+
n = flat.size(1)
|
| 44 |
+
k = max(1, min(n - 1, int(n * s)))
|
| 45 |
+
# kthvalue: encuentra el valor en el percentil k (bottom-k%)
|
| 46 |
+
# Los valores >= thresh son el top-(1-s)% que pasan
|
| 47 |
+
thresh = torch.kthvalue(flat, k, dim=1).values
|
| 48 |
+
thresh = thresh.view(-1, *([1] * (x.dim() - 1)))
|
| 49 |
+
mask = x.abs() >= thresh
|
| 50 |
+
self._last_sparsity = 1.0 - mask.float().mean().item()
|
| 51 |
+
self._last_threshold = thresh.view(-1).mean().item()
|
| 52 |
+
self._last_sparsity_target = s
|
| 53 |
+
return x * mask
|
| 54 |
+
|
| 55 |
+
def get_stats(self) -> dict:
|
| 56 |
+
"""Retorna métricas actuales de HSAQ."""
|
| 57 |
+
return {
|
| 58 |
+
'sparsity': self.sparsity,
|
| 59 |
+
'sparsity_target': getattr(self, '_last_sparsity_target', self.sparsity),
|
| 60 |
+
'actual_sparsity': getattr(self, '_last_sparsity', 0.0),
|
| 61 |
+
'threshold': getattr(self, '_last_threshold', 0.0),
|
| 62 |
+
'type': 'activation_quantization',
|
| 63 |
+
'method': 'kthvalue_dynamic_threshold',
|
| 64 |
+
}
|
measure_vram.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Mide el uso de VRAM (pico) de un modelo en distintas presentaciones:
|
| 3 |
+
- transformers bf16 (19.3 GB → NO cabe en 4 GB VRAM)
|
| 4 |
+
- transformers 4-bit (bitsandbytes NF4, ~6 GB)
|
| 5 |
+
- GGUF Q4_K_M vía llama.cpp (llama-cli / llama-server)
|
| 6 |
+
|
| 7 |
+
Modo transformers:
|
| 8 |
+
python measure_vram.py --hf-dir <dir> [--nf4]
|
| 9 |
+
|
| 10 |
+
Modo GGUF:
|
| 11 |
+
python measure_vram.py --gguf <file.gguf> [--n-gpu-layers 999]
|
| 12 |
+
|
| 13 |
+
Reporta pico de VRAM (torch.cuda.max_memory_allocated + nvidia-smi) y footprint.
|
| 14 |
+
"""
|
| 15 |
+
import argparse
|
| 16 |
+
import subprocess
|
| 17 |
+
import time
|
| 18 |
+
from pathlib import Path
|
| 19 |
+
|
| 20 |
+
PROMPTS = [
|
| 21 |
+
"What is the capital of France?",
|
| 22 |
+
"Explain the water cycle in three sentences.",
|
| 23 |
+
"Write a haiku about winter.",
|
| 24 |
+
]
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def nvidia_mem_used_mb():
|
| 28 |
+
out = subprocess.run(
|
| 29 |
+
["nvidia-smi", "--query-gpu=memory.used", "--format=csv,noheader,nounits"],
|
| 30 |
+
capture_output=True, text=True, check=False,
|
| 31 |
+
).stdout.strip()
|
| 32 |
+
try:
|
| 33 |
+
return int(out.splitlines()[0].strip())
|
| 34 |
+
except (ValueError, IndexError):
|
| 35 |
+
return -1
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def measure_transformers(path, nf4=False, max_new=24):
|
| 39 |
+
import torch
|
| 40 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 41 |
+
|
| 42 |
+
if torch.cuda.is_available():
|
| 43 |
+
torch.cuda.reset_peak_memory_stats()
|
| 44 |
+
|
| 45 |
+
kwargs = {"torch_dtype": torch.bfloat16 if not nf4 else None}
|
| 46 |
+
if nf4:
|
| 47 |
+
from transformers import BitsAndBytesConfig
|
| 48 |
+
kwargs["quantization_config"] = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.bfloat16)
|
| 49 |
+
|
| 50 |
+
print(f"Cargando {'NF4 4-bit' if nf4 else 'bf16'} desde {path} ...")
|
| 51 |
+
model = AutoModelForCausalLM.from_pretrained(str(path), **kwargs, device_map="auto")
|
| 52 |
+
tokenizer = AutoTokenizer.from_pretrained(str(path))
|
| 53 |
+
print(f" footprint: {model.get_memory_footprint() / 1e9:.2f} GB")
|
| 54 |
+
|
| 55 |
+
before = nvidia_mem_used_mb()
|
| 56 |
+
device = next(model.parameters()).device
|
| 57 |
+
with torch.inference_mode():
|
| 58 |
+
for p in PROMPTS:
|
| 59 |
+
inputs = tokenizer(p, return_tensors="pt").to(device)
|
| 60 |
+
out = model.generate(**inputs, max_new_tokens=max_new, do_sample=False)
|
| 61 |
+
print(f" → {tokenizer.decode(out[0][inputs['input_ids'].shape[1]:], skip_special_tokens=True)[:60]}")
|
| 62 |
+
|
| 63 |
+
if torch.cuda.is_available():
|
| 64 |
+
peak = torch.cuda.max_memory_allocated() / 1e6
|
| 65 |
+
else:
|
| 66 |
+
peak = -1
|
| 67 |
+
after = nvidia_mem_used_mb()
|
| 68 |
+
print(f" Pico VRAM (torch): {peak:.0f} MB")
|
| 69 |
+
print(f" VRAM nvidia-smi: antes={before} MB → tras generar={after} MB (delta {after - before} MB)")
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def measure_gguf(path, n_gpu_layers=999, max_new=24, ckpt="/tmp/vram.ckpt"):
|
| 73 |
+
binary = "/home/methodwhite/.local/bin/llama-cli"
|
| 74 |
+
if not Path(binary).exists():
|
| 75 |
+
print(f"llama-cli no encontrado en {binary}")
|
| 76 |
+
return
|
| 77 |
+
|
| 78 |
+
cmd = [
|
| 79 |
+
binary, "-m", str(path), "-n", str(max_new), "-p", "What is the capital of France?",
|
| 80 |
+
"-ngl", str(n_gpu_layers), "--no-display-prompt", "--no-warmup", "-c", "512",
|
| 81 |
+
]
|
| 82 |
+
print(f"Ejecutando: {' '.join(cmd)}")
|
| 83 |
+
before = nvidia_mem_used_mb()
|
| 84 |
+
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
|
| 85 |
+
peak = before
|
| 86 |
+
try:
|
| 87 |
+
while True:
|
| 88 |
+
line = proc.stdout.readline()
|
| 89 |
+
if not line:
|
| 90 |
+
break
|
| 91 |
+
line = line.strip()
|
| 92 |
+
if line and "log" not in line.lower() and not line.startswith("llama_"):
|
| 93 |
+
pass
|
| 94 |
+
used = nvidia_mem_used_mb()
|
| 95 |
+
if used > peak:
|
| 96 |
+
peak = used
|
| 97 |
+
if proc.poll() is not None:
|
| 98 |
+
break
|
| 99 |
+
time.sleep(0.2)
|
| 100 |
+
finally:
|
| 101 |
+
proc.kill()
|
| 102 |
+
print(f" VRAM pico (nvidia-smi): {peak} MB (antes {before} MB)")
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def main():
|
| 106 |
+
parser = argparse.ArgumentParser()
|
| 107 |
+
parser.add_argument("--hf-dir", type=str)
|
| 108 |
+
parser.add_argument("--nf4", action="store_true", help="Cargar en 4-bit NF4 en vez de bf16")
|
| 109 |
+
parser.add_argument("--gguf", type=str)
|
| 110 |
+
parser.add_argument("--n-gpu-layers", type=int, default=999)
|
| 111 |
+
args = parser.parse_args()
|
| 112 |
+
|
| 113 |
+
if args.hf_dir:
|
| 114 |
+
measure_transformers(args.hf_dir, nf4=args.nf4)
|
| 115 |
+
elif args.gguf:
|
| 116 |
+
measure_gguf(args.gguf, args.n_gpu_layers)
|
| 117 |
+
else:
|
| 118 |
+
parser.print_help()
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
if __name__ == "__main__":
|
| 122 |
+
main()
|