Ternarization_instructions_27b_sp.md
| 1 | # Instrucciones de ternarización y exportación a GGUF/TQ2_0 — Qwen3.8-27B |
| 2 | |
| 3 | Modelo: `/mnt/nfs_share/Qwen3_8/`, clase `JiRackDeltaNet_27b.py` |
| 4 | (híbrido 3:1 Gated-DeltaNet / Gated-Attention, `model_type: qwen3_5`). |
| 5 | |
| 6 | ## Estado (actualizado 2026-08-28) |
| 7 | |
| 8 | ✅ **Hecho:** |
| 9 | |
| 10 | - Conversión HF → formato propio, pruebas de toda la pipeline |
| 11 | - **Bloque MTP implementado e integrado** (véase la sección 0 más abajo) |
| 12 | - Conversión GGUF correcta (pt → safetensors → GGUF, bf16) |
| 13 | - Smoke test superado: el modelo responde correctamente («Paris» a «What is the capital of France?») |
| 14 | - **Perplejidad de referencia: PPL = 5.4957 ± 0.12** (wikitext-100k, c=2048, bf16, lambda=0.0) |
| 15 | - Archivo: `/mnt/nfs_share/Qwen3_8/wiki_100k.txt` (usar el mismo archivo para comparar después de la ternarización) |
| 16 | - Registro: `/mnt/nfs_share/Qwen3_8/ppl_baseline_bf16.log` (última línea, 11 chunks) |
| 17 | |
| 18 | ⏳ **Siguientes pasos:** warmup QAT lambda 0.0→1.0, materialización de la ternarización, exportación TQ2_0, perplejidad final |
| 19 | |
| 20 | Checkpoint actual: `/mnt/nfs_share/Qwen3_8/qwen38_27b_checkpoint_migrated.pt` (53,79 GB, lambda=0.0) |
| 21 | |
| 22 | - Contiene los pesos MTP (transferidos desde el checkpoint HF original), pero aún no está ternarizado. |
| 23 | - Se convertirá en un nuevo archivo `.pt` con soporte nativo de MTP mediante el script `convert_qwen38_to_jirack.py` (versión actualizada). |
| 24 | |
| 25 | Mecanismo de cuantización (igual que en el modelo 32B): `BitLinear` calcula gamma como **absmean por tensor**; |
| 26 | los pesos se proyectan a exactamente tres valores (`-gamma, 0, +gamma`), lo que garantiza un ida y vuelta TQ2_0 sin pérdida. |
| 27 | |
| 28 | **Diferencia respecto al modelo 32B:** dos ajustes arquitectónicos; véanse las secciones 0 y 1. |
| 29 | |
| 30 | --- |
| 31 | |
| 32 | ## 0. Bloque MTP (Medusa Token Prediction, capa 64) |
| 33 | |
| 34 | **Qué es:** la nueva arquitectura de llama.cpp (versión ≥ ca3d5a3e1, etiqueta b10665) exige |
| 35 | una capa MTP para modelos como `qwen3_5`. MTP es un decodificador especulativo (capa draft) |
| 36 | diseñado para acelerar la generación por lotes, similar a Medusa. Implementado en `JiRackDeltaNet_27b.py`. |
| 37 | |
| 38 | **Lo que ya está hecho:** |
| 39 | |
| 40 | - La clase `MTPBlock` está implementada en el código (15 tensores: fc, normas). |
| 41 | - Los pesos MTP se han portado desde el checkpoint HF original de Qwen3.8-27B. |
| 42 | - Se integraron en el archivo GGUF durante la conversión (`qwen38_27b_jirack_baseline_bf16.gguf`). |
| 43 | - MTP **no** entra en el proceso de ternarización (permanece en precisión completa, ~100 MB de pesos). |
| 44 | |
| 45 | **Por qué no ternarizamos MTP:** |
| 46 | |
| 47 | - La capa MTP no es esencial para la generación estándar (solo se usa cuando está activada la bandera de decodificación especulativa). |
| 48 | - Ternarizar las 400 capas principales basta para alcanzar la compresión objetivo. |
| 49 | - Mantener MTP en precisión completa preserva la calidad del decodificador especulativo para quienes decidan activarlo. |
| 50 | |
| 51 | **Para el warmup QAT y la materialización:** basta con omitir las capas `mtp.*` al aplicar |
| 52 | el parche `BitLinear`; esto ya lo gestiona `apply_bitlinear_patch(skip_mtp=True)`. |
| 53 | |
| 54 | --- |
| 55 | |
| 56 | ## 1. Qué se ternariza y qué no (TRES EXCEPCIONES) |
| 57 | |
| 58 | Por defecto (`include_gate_proj=False` en `apply_bitlinear_patch`) |
| 59 | se parchean las siguientes 400 capas lineales: |
| 60 | |
| 61 | - `linear_attn.in_proj_qkv`, `linear_attn.in_proj_z`, `linear_attn.out_proj` |
| 62 | - `self_attn.q_proj`, `k_proj`, `v_proj`, `o_proj` |
| 63 | - `mlp.gate_proj`, `up_proj`, `down_proj` |
| 64 | |
| 65 | **Lo siguiente NO se parchea y debe permanecer en precisión completa:** |
| 66 | |
| 67 | - `linear_attn.in_proj_b` y `linear_attn.in_proj_a` — son los escalares de puerta |
| 68 | para DeltaNet (proyecciones dt/A-gate); controlan la estabilidad de la recurrencia. Fue una decisión deliberada: el riesgo de desestabilizar la propia fórmula de recurrencia |
| 69 | con una cuantización ternaria gruesa se consideró mayor que el posible |
| 70 | ahorro. |
| 71 | - Todas las capas de normalización (`RMSNorm`, `RMSNormGated`), `conv1d` (depthwise, |
| 72 | 4 taps), `dt_bias`, `A_log`. |
| 73 | - `embed_tokens`, `lm_head`. |
| 74 | |
| 75 | **Implicación para la exportación GGUF:** al cuantizar a GGUF hay que indicar |
| 76 | explícitamente el tipo de tensor de estas capas (`--tensor-type` o |
| 77 | el equivalente en su versión de `llama-quantize`) para que |
| 78 | `in_proj_b`/`in_proj_a`, conv1d y todas las capas de normalización permanezcan en f16/f32 |
| 79 | y no queden sujetas al ajuste general TQ2_0 de un pase de cuantización de todo el archivo. Sin especificación explícita, algunos scripts de cuantización |
| 80 | aplican un solo tipo a todos los tensores elegibles, lo que rompería |
| 81 | en silencio el mecanismo de recurrencia. |
| 82 | |
| 83 | ## 2. Riesgo arquitectónico — YA VERIFICADO ✅ |
| 84 | |
| 85 | Gated DeltaNet es una arquitectura híbrida todavía nueva en llama.cpp. El riesgo estaba en que |
| 86 | su soporte es menos maduro que el de la atención Qwen2 en los modelos 32B. |
| 87 | |
| 88 | **Verificado (2026-08-28):** |
| 89 | |
| 90 | - Conversión GGUF (`pt` → `safetensors` → `qwen38_27b_jirack_baseline_bf16.gguf`): |
| 91 | correcta, 866 tensores, 54,6 GB |
| 92 | - Smoke test (llama-cli con chat-template): el modelo responde correctamente |
| 93 | («The capital of France is Paris» con capa de razonamiento) |
| 94 | - Perplejidad de referencia en wikitext-100k: **PPL = 5.4957 ± 0.12** |
| 95 | (11 chunks de 2048 tokens, bf16, lambda=0.0) |
| 96 | |
| 97 | **Conclusión:** la arquitectura funciona correctamente en llama.cpp. Cualquier degradación |
| 98 | adicional durante la cuantización ternaria/TQ2_0 vendrá del propio proceso de cuantización, |
| 99 | no de errores de implementación. |
| 100 | |
| 101 | **Nota para más adelante:** si la perplejidad se dispara de forma anómala (>>6.5) durante TQ2_0, |
| 102 | no es un riesgo arquitectónico: indica un problema de warmup QAT |
| 103 | o de capas excluidas de forma incorrecta. |
| 104 | |
| 105 | ## 3. Entrenamiento QAT (cuando se requiere cuantización ternaria) |
| 106 | |
| 107 | 1. Cargar el checkpoint: |
| 108 | |
| 109 | ```python |
| 110 | model = JiRackQwen38ForCausalLM.load_checkpoint( |
| 111 | "/data/qwen38_27b_checkpoint_migrated.pt", dtype=torch.bfloat16) |
| 112 | ``` |
| 113 | |
| 114 | 2. Subir gradualmente el lambda de warmup de 0.0 a 1.0 (igual que en el modelo 32B, |
| 115 | usando `set_lambda` en todos los módulos que admiten este método). |
| 116 | 3. Guardar el checkpoint entrenado. |
| 117 | |