Skip to content

Commit 6c744db

Browse files
committed
Fix league eval summary compatibility
1 parent 5aa20e5 commit 6c744db

3 files changed

Lines changed: 434 additions & 2 deletions

File tree

Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
# AtaxxZero - Post-mortem 03: por que los modelos no mejoraban y por que `v6` si despego
2+
3+
> **Resumen:** durante varias semanas el entrenamiento parecia "estable" pero no
4+
> producia checkpoints claramente mejores. El problema no era una sola cosa ni
5+
> se resolvia eligiendo otro bootstrap. Habia varias fugas de calidad en la
6+
> generacion de datos, en la representacion del estado y en la integracion del
7+
> search con el training. `policy_spatial_v6` fue la primera corrida que junto
8+
> suficientes fixes correctos como para producir una mejora real.
9+
10+
---
11+
12+
## Sintoma
13+
14+
Los checkpoints anteriores mostraban uno o varios de estos patrones:
15+
16+
- `eval_composite` clavado en `0.0`
17+
- head-to-head contaminado por lineas de apertura degeneradas
18+
- modelos que "se movian" pero no parecian entender el juego
19+
- mejoras marginales entre iteraciones, pero sin salto real de fuerza
20+
21+
El punto importante es este:
22+
23+
> El pipeline corria, pero el modelo estaba aprendiendo sobre datos de calidad
24+
> insuficiente o inconsistente.
25+
26+
---
27+
28+
## Diagnostico correcto
29+
30+
El error operativo durante un tiempo fue leer el problema como:
31+
32+
- "faltan mas iteraciones"
33+
- "falta otro bootstrap"
34+
- "hay que empezar de cero"
35+
36+
Esas hipotesis eran incompletas.
37+
38+
La causa real era acumulativa: el sistema tenia varios defectos pequenos o
39+
medianos que, juntos, degradaban justo la parte mas importante del proyecto:
40+
41+
1. la calidad del self-play;
42+
2. la coherencia entre estado, reward e inferencia;
43+
3. la utilidad de heuristicas y checkpoints como teachers.
44+
45+
---
46+
47+
## Causas raiz
48+
49+
### 1. Cache de inferencia de MCTS incoherente con la observacion real
50+
51+
**Problema**
52+
53+
La cache de inferencia de `MCTS` estaba indexada por `grid` y jugador actual,
54+
pero la red tambien veia `half_moves`.
55+
56+
Eso permitia reutilizar policy/value entre estados distintos desde el punto de
57+
vista del modelo.
58+
59+
**Efecto**
60+
61+
- priors stale dentro del search
62+
- evaluacion inconsistente de estados similares pero no equivalentes
63+
- contaminacion de self-play, eval y comparacion de checkpoints
64+
65+
**Fix**
66+
67+
La cache se paso a construir desde la observacion real que entra a la red.
68+
69+
---
70+
71+
### 2. La red no veia todo el estado que define draws por repeticion
72+
73+
**Problema**
74+
75+
El juego podia terminar por repeticion y el reward shaping tambien castigaba
76+
forced draws, pero esa informacion no estaba en la observacion.
77+
78+
Habia estados con el mismo input para la red que podian diferir en:
79+
80+
- `is_game_over()`
81+
- `is_forced_draw()`
82+
83+
**Efecto**
84+
85+
El target de valor no era Markoviano en la zona donde el modelo mas se atascaba:
86+
los loops.
87+
88+
**Fix**
89+
90+
Se agrego un canal de presion de repeticion y tambien se corrigio la
91+
serializacion para preservar `_position_counts`.
92+
93+
---
94+
95+
### 3. Las heuristicas fuertes castigaban, pero casi no enseñaban policy
96+
97+
**Problema**
98+
99+
En partidas contra heuristicas, el buffer guardaba sobre todo los turnos del
100+
modelo. Cuando movia el rival heuristico, su jugada normalmente no entraba como
101+
target de policy.
102+
103+
**Efecto**
104+
105+
`hard`, `apex`, `gambit` y `sentinel` funcionaban mas como castigo para el
106+
value head que como teacher real para la policy.
107+
108+
**Fix**
109+
110+
Las jugadas de heuristica pasaron a guardarse como ejemplos supervisados en el
111+
buffer.
112+
113+
---
114+
115+
### 4. Training e inferencia no usaban el mismo espacio de decision
116+
117+
**Problema**
118+
119+
En inferencia/MCTS se aplicaba mascara legal. En training, no.
120+
121+
La red tenia que gastar capacidad en aprender "que acciones son ilegales" en
122+
vez de concentrarse en ordenar bien las legales.
123+
124+
**Efecto**
125+
126+
- peor eficiencia del trunk y la policy head
127+
- mismatch entre lo que la red aprende y como se usa en runtime
128+
129+
**Fix**
130+
131+
Training paso a construir la legal-action mask desde el board y a usarla en el
132+
forward igual que MCTS.
133+
134+
---
135+
136+
### 5. Self-play paralelo estaba cayendo a CPU cuando mas importaba
137+
138+
**Problema**
139+
140+
En configuraciones cortas de Kaggle, la generacion de experiencia estaba
141+
corriendo peor de lo necesario porque los workers de self-play terminaban en CPU.
142+
143+
**Efecto**
144+
145+
El sistema estaba optimizando mas el fit que la calidad/cantidad de experiencia.
146+
Eso es la direccion equivocada para AlphaZero-style training.
147+
148+
**Fix**
149+
150+
Se cambio la politica de devices:
151+
152+
- `CUDA x1`: sin pool paralelo, self-play secuencial en GPU
153+
- `CUDA xN`: workers repartidos por GPU
154+
- `CPU`: pool normal en CPU
155+
156+
---
157+
158+
### 6. El sampler de ejemplos recientes repetia demasiado
159+
160+
**Problema**
161+
162+
`sample_recent_mix()` usaba reemplazo de manera agresiva.
163+
164+
**Efecto**
165+
166+
Aunque el buffer fuera grande, el set efectivo de entrenamiento repetia
167+
demasiado ejemplos recientes y estrechaba la diversidad.
168+
169+
**Fix**
170+
171+
El sampler ahora evita reemplazo cuando puede y reparte repeticiones de manera
172+
mucho menos degenerada cuando no queda otra.
173+
174+
---
175+
176+
### 7. Los oponentes checkpoint tampoco estaban enseñando policy
177+
178+
**Problema**
179+
180+
Cuando el rival era otro checkpoint del pool, su politica tampoco se estaba
181+
aprovechando del todo como teacher.
182+
183+
**Efecto**
184+
185+
La liga interna y el pool de checkpoints aportaban oposicion, pero no tanta
186+
senal de imitacion como podian.
187+
188+
**Fix**
189+
190+
Los turnos del checkpoint pasaron a guardarse como targets de policy y, ademas,
191+
se agrego temperatura temprana para que esas aperturas no fueran demasiado
192+
rigidas.
193+
194+
---
195+
196+
### 8. La observacion era demasiado pobre para la estructura real de Ataxx
197+
198+
**Problema**
199+
200+
La red veia piezas, vacios, progreso y repeticion, pero seguia teniendo que
201+
inferir desde cero demasiada estructura del espacio tactico.
202+
203+
**Efecto**
204+
205+
Aprendizaje mas lento de:
206+
207+
- movilidad
208+
- distincion clone/jump
209+
- actividad real de piezas
210+
- cierre y bloqueo de posiciones
211+
212+
**Fix**
213+
214+
La observacion se expandio a 11 canales:
215+
216+
- piezas propias
217+
- piezas rivales
218+
- vacias
219+
- progreso de `half_moves`
220+
- presion de repeticion
221+
- destinos legales de clone propios
222+
- destinos legales de jump propios
223+
- destinos legales de clone rivales
224+
- destinos legales de jump rivales
225+
- piezas propias activas
226+
- piezas rivales activas
227+
228+
Esto no mete libro de aperturas ni heuristicas duras. Solo le da a la red una
229+
representacion mas fiel y util del estado.
230+
231+
---
232+
233+
### 9. La liga interna fallaba al guardar resultados de eval
234+
235+
**Problema**
236+
237+
La liga esperaba resumentes estilo duelo:
238+
239+
- `checkpoint_a_wins`
240+
- `checkpoint_b_wins`
241+
242+
Pero `evaluate_model()` producia:
243+
244+
- `wins`
245+
- `losses`
246+
- `draws`
247+
248+
**Efecto**
249+
250+
La corrida no se caia, pero salia el warning:
251+
252+
`league update failed, continuing training: 'checkpoint_a_wins'`
253+
254+
**Fix**
255+
256+
`record_checkpoint_in_league()` ahora normaliza ambos formatos de resumen antes
257+
de llamar a la liga Elo.
258+
259+
---
260+
261+
## Lo que no era la causa principal
262+
263+
### "Solo faltaban mas iteraciones"
264+
265+
No. Varias corridas anteriores ya estaban entrenando sobre datos suboptimos o
266+
inconsistentes. Mas iteraciones sobre eso solo reforzaban una politica mediocre.
267+
268+
### "Solo habia que cambiar bootstrap"
269+
270+
Tampoco. El bootstrap importaba, pero no era el cuello de botella dominante.
271+
El problema principal era la calidad del loop de aprendizaje.
272+
273+
### "Solo hacia falta otra heuristica"
274+
275+
No por si sola. El problema era que las heuristicas no estaban dejando suficiente
276+
senal de policy en el buffer.
277+
278+
---
279+
280+
## Por que `v6` si mejoro
281+
282+
`policy_spatial_v6_iter_180` fue la primera corrida que combino suficientes fixes
283+
correctos a la vez:
284+
285+
- observacion mas rica y coherente
286+
- search sin cache incoherente
287+
- repeticion visible para la red
288+
- heuristicas y checkpoints funcionando como teachers reales
289+
- training alineado con legal-action mask
290+
- mejor uso de GPU para generar experiencia
291+
- sampler menos degenerado
292+
293+
El resultado ya no fue solo "se mueve distinto". Hubo mejora medible.
294+
295+
Benchmarks locales posteriores al run:
296+
297+
- `v6_180 vs v2_093`: `40-0`
298+
- `v6_180 vs v4_135`: `24-0`
299+
- gauntlet `v6_180`:
300+
- vs `hard`: `9-3`
301+
- vs `apex`: `4-8`
302+
- vs `sentinel`: `8-4`
303+
304+
Y el checkpoint final quedo con:
305+
306+
- `iteration = 180`
307+
- `best_eval_score = 0.8055555555555555`
308+
309+
Eso ya es una mejora real, no una ilusion de logs.
310+
311+
---
312+
313+
## Lecciones
314+
315+
### 1. En AlphaZero, "que el loop corra" no significa "que el loop sirva"
316+
317+
Un pipeline puede:
318+
319+
- generar checkpoints
320+
- subir a HF
321+
- mostrar losses normales
322+
323+
y aun asi estar entrenando sobre una senal mediocre.
324+
325+
### 2. Los bugs de integracion pesan tanto como los hiperparametros
326+
327+
En este caso, varios de los mayores bloqueos no eran:
328+
329+
- learning rate
330+
- tamano de modelo
331+
- numero de iteraciones
332+
333+
Eran problemas de integracion entre:
334+
335+
- board state
336+
- observacion
337+
- MCTS
338+
- replay buffer
339+
- training loop
340+
341+
### 3. Las heuristicas deben enseñar, no solo castigar
342+
343+
Si el rival fuerte solo te gana pero no deja policy targets utiles, el
344+
aprendizaje de la policy avanza mucho mas lento.
345+
346+
### 4. El modelo necesita ver estado estructural, no solo piezas
347+
348+
Movilidad, actividad de piezas y distincion clone/jump resultaron ser features
349+
de alto valor sin romper el espiritu de self-play.
350+
351+
---
352+
353+
## Estado final
354+
355+
La conclusion operativa despues de este post-mortem es:
356+
357+
1. el estancamiento anterior no fue un misterio ni un tema de "mala suerte";
358+
2. habia causas tecnicas concretas y acumulativas;
359+
3. ya se corrigieron las mas importantes;
360+
4. `v6` confirma que el sistema, con esas correcciones, si puede mejorar;
361+
5. los siguientes pasos deben enfocarse en escalar bien ese progreso, no en
362+
volver a discutir eternamente bootstrap vs. reset total.
363+

0 commit comments

Comments
 (0)