// M5 · lección 02
Alineamiento: cómo se mide y lo que salió
Qué número mira cada parte del hito y dónde engaña, y lo que salió: un reward model que falla donde tiene que fallar, DPO con dos fuentes de pares, seis enfrentamientos y un triángulo que no cierra, el peaje en legalidad, la galería de reward hacking, GRPO con forma de U invertida y los tres criterios uno por uno.
Parte 2 de 3 del módulo «Alineamiento». Viene de «Alineamiento: el instrumento y la teoría justa» y sigue en «Alineamiento: los labs».
Cómo se mide y contra qué
Al terminar esta sección sabrás qué número mira cada parte del hito, los tres sitios donde una medición de alineamiento miente sin avisar, y un recorte de datos que no era una muestra y habría convertido la comparación central del hito en otra distinta.
El acierto de un reward model depende de cómo se parten los datos
El criterio de GOAL.md para el reward model es 75 % de acierto en pares no vistos. Cuatro
corridas del mismo modelo con cuatro semillas dan 72,91 %, 74,76 %, 75,19 % y 74,71 %.
La primera explicación fue buena y no era toda. split_examples reparte por partida usando la
misma semilla que el entrenamiento, así que cambiar la semilla cambia qué partidas caen en
validación, y con ellas cuántos pares de mate hay en el conjunto que se mide: 484 con la semilla
42, 356 con la 1. Y los pares de mate son donde el modelo peor va, así que el titular sube
cuando el sorteo reparte menos mates.
Es la misma lección que el instrumento del principio del módulo, en otro sitio: allí la escalera daba 1498 y 1558 con la misma configuración, aquí el reward model da 72,91 y 74,21. Es la báscula del puesto del mercado: si pesas la misma bolsa dos veces y marca 980 y 1 020 gramos, no puedes volver a casa diciendo que la bolsa de hoy pesa 30 gramos más que la de ayer.
Por eso se publican siempre cuatro cosas juntas: el acierto global, el acierto sobre los pares que una evaluación puede decidir, el recuento por banda, y cuánto se separan dos corridas idénticas.
Una correlación sobre dos poblaciones no describe ninguna
Las cuatro corridas reportan una correlación de Pearson negativa entre el margen del modelo y la distancia en centipeones: de −0,034 a −0,156. Leído tal cual, dice que el modelo está más seguro cuanto más parecidas son las dos jugadas, que es lo contrario de lo que debería.
Lo que pasa es que los pares de mate tienen, por construcción, la distancia más grande (≥ 2 000) y son donde el modelo peor va: su margen medio es +0,744 frente a +1,272 en el resto. Algo más de un cuarto de los puntos, pegados al extremo derecho del eje y abajo del todo, bastan para torcer la recta entera. Sobre el mismo modelo y el mismo conjunto:
| conjunto | pares | Pearson | Spearman | acierto |
|---|---|---|---|---|
| todos | 1 268 | −0,1276 | −0,0674 | 74,76 % |
| sin mates | 912 | +0,0576 | +0,0747 | 77,30 % |
El signo lo cambia el subconjunto, no el modelo (D-119). Es el concesionario que vende coches nuevos y de segunda mano: sobre todo el lote, los coches con más kilómetros son más baratos, y dentro de cada grupo por separado la relación puede ser otra. Una recta sobre las dos poblaciones juntas no describe cómo se tasa ningún coche.
Un head() no es una muestra
build_on_policy recortaba con frame.head(n) cuando se le pedía un subconjunto. Los pares están
equilibrados por fase en bloques, así que las primeras 40 filas son 65 % aperturas frente al
33 % del fichero entero (D-114).
Importa porque el hito compara pares de dos fuentes. Si el recorte de una es casi todo aperturas y
el de la otra no, lo que se compara no son las fuentes: es la mezcla de fases, que desde M2 se sabe
que mueve todo. Las cuarenta primeras entradas de la guía telefónica no son una muestra de la
ciudad: son cuarenta apellidos que empiezan por A. El arreglo es
frame.sample(shuffle=True, seed=...).
En GRPO, que suba la recompensa no es la noticia
Una recompensa verificable siempre puede subir: está escrita, y lo que está escrito se puede optimizar. Lo que dice si subió jugando mejor o cultivando el número es que suba y la KL se quede pequeña y la proporción de ilegales no empeore. Los tres a la vez, o no es una mejora, es un síntoma.
Los tres sitios donde una medición de este hito miente, en una tabla, para tenerlos delante mientras lees lo que salió:
| dónde miente | qué la mueve sin que cambie el modelo | qué se publica para que no engañe |
|---|---|---|
| el acierto del reward model | la semilla parte los datos; la GPU repite ±1 | acierto global, por banda, y el suelo entre corridas |
| la correlación margen-Δcp | una banda con otro régimen tuerce la recta | la correlación con y sin la banda de mate |
| la recompensa de GRPO | se puede optimizar sin jugar mejor | recompensa, KL e ilegales, los tres en la misma fila |
Lo que salió
Al terminar esta sección sabrás qué midió cada pieza del hito, incluida la que midió lo contrario de lo que se esperaba.
El reward model: tres de cada cuatro, y el cuarto siempre es el mismo
El criterio de GOAL.md pedía 75 % de acierto en pares no vistos. Cinco corridas dan 72,91 %,
74,21 %, 74,71 %, 74,76 % y 75,19 %: la frontera se toca y no se cruza de forma estable. Y dos de
esas cinco son la misma semilla, así que el instrumento repite con un margen de 1,3 puntos: el
criterio está por debajo del ruido de la medición que lo comprueba. Lo interesante no es el
titular, es dónde está el error.
La banda de mate es la peor en las cuatro corridas —68,3 % a 71,7 %— y es algo más de un cuarto de los pares de validación: 356 de 1 268 en la corrida de la figura, y entre el 27 % y el 33 % según qué partidas reparta la semilla. La mejor es la de 400-800 cp, entre 80,2 % y 85,4 %. Un mate es un hecho táctico y lo que el modelo lee es una evaluación estática de la posición que queda: no lo puede ver. Quitando esa banda, el acierto sube a 77,30 % y el criterio se cumple con holgura — pero quitarla es cambiar la pregunta, así que se publican las dos cifras y el recuento de cada banda.
Lo que no se puede decir es que el acierto suba monótonamente con la distancia. Las bandas 100-200 y 200-400 se cruzan según la semilla, y la de 800-2000 tiene entre diez y veintidós pares: en cuatro corridas dio 90 %, 68 %, 90 % y 50 %, que es la misma ausencia de dato con cuatro caras. Está dibujada hueca en la figura por eso.
Tres cosas más salieron de la bandeja de experimentos, y una de ellas fue la que más sorprendió:
- El encoder preentrenado de M3 resta. Partir de él da unos 6,5 puntos menos que inicializar al azar. El encoder aprendió a rellenar jugadas enmascaradas; aquí se le pide ordenar posiciones por lo buenas que son. «Preentrenado» no es una propiedad, es una relación entre lo que aprendió y lo que le vas a pedir, y cuando no hay relación la inicialización al azar gana.
- La capacidad sí manda. 12 capas × 512 sube donde ninguna otra palanca subía: el techo estaba en el modelo, no en los datos.
- El punto de vista no era la causa. Se sospechaba que pedirle «cómo de buena es esta posición
para quien acaba de mover» le obligaba a leer el turno del FEN e invertir el signo cada ply. Se
midió la alternativa —«cómo de buena es para las blancas», con el signo puesto en la pérdida— y
sale lo mismo. Queda como
point_of_viewen la config, documentado como medido y sin efecto.
Y un error que hizo falta cometer: la primera corrida daba 72,98 % alimentando un encoder entrenado
con el esquema moves con los 69 tokens de casilla del esquema squares. No falla nada — los
identificadores caben en el vocabulario de 2 030 y significan otra cosa —, no avisa nada, y sale un
número plausible de una representación revuelta. Ahora load_squares_encoder se niega, con el
mensaje que dice por qué.
Los pares que salen del propio modelo son otra cosa
rukh data onpolicy recorre las 13 838 posiciones de los pares off-policy, muestrea cuatro jugadas
del modelo en cada una a temperatura 1,0, las puntúa con el motor a profundidad 10, y se queda con
la mejor y la peor si están a más de 100 cp. Salieron 6 386 pares, y el reparto de lo que no
salió es tan informativo como lo que sí:
| resultado | posiciones | reparto |
|---|---|---|
| pares construidos | 6 386 | 46,1 % |
| el modelo propuso una sola jugada distinta | 3 743 | 27,1 % |
| las dos extremas estaban a menos de 100 cp | 3 709 | 26,8 % |
Ese 27,1 % es el mismo fenómeno que en GRPO cuenta flat_groups, visto desde la generación de
datos: la confianza del propio modelo se lleva un cuarto del presupuesto de motor, y no hay
forma de saber cuál cuarto antes de pagarlo. De los pares que sí salieron, solo 2 632 llegaron a
tener las cuatro candidatas distintas; 1 835 se quedaron en dos.
Y la diferencia que decide cómo hay que leer todo lo que viene después:
| conjunto | pares | mediana Δcp | media Δcp | pares de mate |
|---|---|---|---|---|
| off-policy | 13 838 | 251 | 2 996 | 29 % |
| on-policy | 6 386 | 385 | 672 | 2,9 % |
Los dos conjuntos no son dos fuentes de lo mismo: son dos distribuciones de dificultad. Los pares off-policy están dominados por mates —de ahí la media de casi 3 000 con una mediana de 251—, porque una evaluación multi-PV encuentra mates que el modelo nunca iba a proponer. Los on-policy casi no los tienen: si hay un mate en la posición, o el modelo lo ve y sus cuatro candidatas son razonables, o no lo ve y ninguna lo es.
Eso obliga a una decisión de diseño antes de comparar nada: el conjunto off-policy se submuestrea a 6 386 con semilla fija, para que los dos brazos vean la misma cantidad de datos. Si uno ve 2,2 veces más, lo que se mide es la cantidad y no la fuente.
// Ejercicio 01Antes de entrenar nada: ¿qué medirías si no igualaras?
El conjunto off-policy tiene 13 838 pares y el on-policy 6 386. Si entrenas los dos tal cual y el off-policy sale mejor, ¿qué has medido?
// SoluciónVer la solución
La cantidad de datos, no la fuente. Por eso configs/train/dpo-offpolicy.yaml apunta a
data/pairs-offpolicy-matched/, que es el conjunto original submuestreado a 6 386 con semilla
fija. Es la misma disciplina que la galería de reward hacking necesita más abajo para que sus
inversiones sean atribuibles: si dos condiciones difieren en dos cosas, no has medido ninguna de
las dos.
Hay una segunda diferencia que no se puede igualar y hay que decir: los pares off-policy tienen un 29 % de mates y los on-policy un 2,9 %. Eso no es un defecto de la construcción, es lo que significa «on-policy» —el modelo casi nunca propone a la vez un mate y una pifia—, y hay que declararlo en vez de esconderlo.
DPO: el margen sube, la ordenación no siempre
Los dos entrenamientos son idénticos línea por línea salvo el fichero de pares: mismo checkpoint de
partida, beta 0,1, lr 5e-6, nll_weight 0,1, una época, misma semilla.
| brazo | pares | acierto antes | acierto después | margen después |
|---|---|---|---|---|
| off-policy (igualado) | 6 386 | 94,05 % | 92,96 % | +3,00 |
| on-policy | 6 386 | 89,51 % | 91,86 % | +1,71 |
Dos cosas que leer aquí, y la primera es la advertencia de la teoría cumpliéndose delante.
El brazo off-policy triplicó el margen y empeoró la ordenación. De 94,05 % a 92,96 %. El margen
dice «chosen gana a rejected» y no dice «la ordenación de todos los pares mejoró»: se puede
separar mucho a unos cuantos y cruzar a otros por el camino. Es exactamente por lo que dpo_loss
devuelve las dos cosas por separado, y por lo que el número que se mira es el segundo.
El punto de partida ya era distinto. El modelo base ordena bien el 94,05 % de los pares off-policy y solo el 89,51 % de los on-policy. No es casualidad ni ruido: los pares on-policy están construidos a partir de las jugadas que el modelo dudaba, así que por construcción son los que peor ordena. Un conjunto de entrenamiento hecho de tus propios errores es más difícil que uno hecho de los errores de otro, y eso es lo que se supone que lo hace útil.
Pero ninguna de estas dos columnas es la medición que decide. El acierto sobre pares es una métrica de proxy: mide si el modelo ordena pares, no si juega mejor. Para eso está el instrumento del principio del módulo.
La medición que decide: seis enfrentamientos y un triángulo que no cierra
Tres modelos y tres aristas: base, DPO fuera de política y DPO dentro de política. Cada arista se jugó dos veces, 400 partidas con un modelo pasado como A y 400 con los lados intercambiados, sobre el mismo libro de aperturas y con los colores espejados dentro de cada corrida.
Las dos direcciones no eran por rigor ceremonial. Las tres primeras corridas las ganó quien iba
como A, y eso hay que descartarlo antes de creerse nada. Se descartó: al intercambiar los lados,
el signo aguanta las tres veces —off gana a base por +61 siendo A y por +74 siendo B—. El
instrumento no tiene preferencia por un lado.
Pero intercambiarlos enseñó otra cosa, y es la que más se va a repetir en el resto del curso.
// Ejercicio 02¿Cuánto se estrecha el intervalo al agrupar?
Al agrupar las dos direcciones, las 400 partidas pasan a ser 800. ¿Cuánto se estrecha el intervalo? ¿Y por qué no se estrecha a la mitad?
// SoluciónVer la solución
Se estrecha por √2, no por dos: el error típico de una media va con la raíz del número de
muestras. Doblar las partidas divide el intervalo por 1,41. Para dividirlo por dos hacen falta
cuatro veces las partidas, y por eso la tabla del lab 1 se lee al revés antes de pagar nada.
Lo que sí puede pasar al agrupar es que el veredicto cambie, y no siempre a mejor: on contra
off daba «separado» en una dirección e «incluye el cero» en la otra, y agrupado vuelve a
«separado» con un intervalo 1,41 veces más estrecho. El agrupado es el número honesto de las dos
corridas, no el mejor de los dos.
Agrupadas las dos direcciones, las aristas medidas —incluida la de GRPO, que llega en la última sección pero se mide con el mismo instrumento—:
| arista | partidas | Elo | IC 95 % |
|---|---|---|---|
| DPO off-policy − base | 1 600 | +65 | 50 a 81 |
| DPO on-policy − base | 800 | +57 | 36 a 79 |
| GRPO − base | 800 | +44 | 23 a 66 |
| DPO on-policy − off-policy | 800 | +37 | 15 a 59 |
(La primera lleva 1 600 porque a los seis enfrentamientos del triángulo se les añadieron dos corridas extra en la arista fuera de política, 800 partidas más con otra semilla de libro, para intentar cruzar el criterio; esa historia está en la última sección. Todo lo que sigue usa la cifra de las 1 600.)
Los tres métodos baten a la base con el intervalo separado del cero. Es la primera vez en el proyecto que este criterio se mide así, y lo que cambió no fue el modelo: fue cómo se mira.
Léelas en orden y las dos primeras contradicen a la tercera. Si off está 65 por encima de la base
y on está 57, entonces on debería estar unos ocho por debajo de off. Medido de frente, con
800 partidas, está 37 por encima.
El residuo de esta no transitividadNo transitividadQue A gane a B y B gane a C no obliga a que A gane a C. Pasa cuando el resultado depende del emparejamiento y no solo de una fuerza única por jugador, y en M5 se midió: las tres aristas entre la base y los dos DPO —1 600 partidas la de DPO off-policy contra la base, 800 las otras dos, siempre con las dos direcciones agrupadas— dejan un residuo de 45 Elo con un error típico de 18, o sea 2,6 σ. La consecuencia práctica: si te importa cuál de dos modelos gana, enfréntalos; no restes lo que cada uno hizo contra un tercero. —lo que las tres aristas no
consiguen sumar— es de 45 Elo con un error típico de 18, o sea 2,6 σ. (El error típico sale
de los tres intervalos: sus semianchuras, 15,5, 21,7 y 21,7, divididas por 1,96 y sumadas en
cuadratura; labs/m5/pooled_match.py lo imprime con el signo que le da su orientación, −45.) No es
que los intervalos sean generosos: es que un solo número de fuerza por modelo supone que la fuerza
es un orden total, y un emparejamiento no está obligado a respetarlo. Pasa en cualquier liga de
fútbol: el equipo que presiona arriba gana al que juega al toque, el del toque gana al que se
encierra, y el que se encierra gana al que presiona, y ninguna tabla de puntos lo explica porque
la tabla supone que cada equipo tiene una fuerza. El modelo fuera de política juega más afilado
—lo dice su tasa de ilegales, que veremos ahora— y eso le va bien contra la base y mal contra un
modelo más limpio.
El peajePeaje del alineamientoLo que se pierde al ganar. En M5, alinear con DPO **dobló** la tasa de propuestas ilegales del modelo: 1,3-1,5 % en la base, 2,4-2,6 % con pares propios, 2,9-3,8 % con pares de fuera, y `nll_weight` no lo evitó. No rompe las partidas —la jugada ilegal se rescata con un sorteo enmascarado— pero es distribución que se ha ido a otro sitio. La regla: mide el coste en la misma corrida en la que mides el beneficio.: alinear dobló la tasa de jugadas ilegales
rukh eval match cuenta las propuestas ilegales de cada bando porque el control del instrumento lo
necesitaba. Salió una métrica que nadie estaba buscando y que es el coste del hito:
| modelo | ilegales sobre sus propias jugadas |
|---|---|
medium-v4 (base) |
1,30 % – 1,47 % |
medium-v4-dpo-onpolicy |
2,42 % – 2,58 % |
medium-v4-dpo-offpolicy |
2,90 % – 3,80 % |
medium-v4-grpo |
1,92 % (base 1,16 % en la misma corrida) |
Los dos DPO se entrenaron con nll_weight: 0.1, que existe exactamente para anclar la política
mientras el margen crece, y aun así la tasa se dobla. No rompe las partidas —el bucle rescata la
propuesta ilegal con un sorteo enmascarado— pero es distribución que se ha ido a otro sitio.
Y la diferencia entre los dos brazos tiene mecanismo, no solo signo. Los pares fuera de política contienen mates que el modelo nunca iba a proponer, así que DPO empuja probabilidad hacia tokens donde la política tenía masa casi nula, y eso deforma más. Los pares dentro de política solo mueven probabilidad entre jugadas que el modelo ya consideraba. El brazo que más deforma es el que más ilegales propone, y son el mismo (D-121).
GRPO paga menos peaje: 1,66 veces la tasa de su base, frente a 1,7-2,0 del DPO dentro de política y 2,0-2,9 del de fuera —menos que el de fuera, a la par que el de dentro—. Cabía esperarlo y no estaba garantizado, y la explicación no es la que parece. Su recompensa tiene una puerta de legalidad, sí, pero en esta configuración no llega a dispararse: las candidatas se muestrean entre jugadas legales. Lo que protege la legalidad no es la puerta — es que el gradiente de GRPO solo mueve masa entre jugadas que ya eran legales, mientras el de DPO la empuja hacia tokens donde la política casi no tenía.
Hay un detalle del instrumento escondido aquí que conviene decir en voz alta. Una propuesta ilegal
se rescata con un sorteo enmascarado, que es un segundo sorteo restringido a jugadas legales —o
sea, un sorteo mejor—. Un modelo que propone más ilegales recibe más de esos segundos sorteos. Es
un examen tipo test donde cada respuesta inválida te da derecho a contestar otra vez con las
opciones malas ya tachadas: quien más se equivoca de forma inválida, más segundas oportunidades
cobra. Así que la tasa no es solo un coste: es un posible sesgo a favor del modelo peor educado.
Por eso rukh eval match tiene --mask, que enmascara desde el primer sorteo para los dos lados y
quita el camino de rescate. No es un ajuste: es un control, y está ahí para que la ventaja se pueda
leer otra vez sin ese confundido.
La suite completa: lo que se gana y lo que se paga, en las mismas filas
El enfrentamiento directo dice que los modelos alineados juegan mejor. La suite canónica —la misma con la que se mide cada etapa del proyecto desde M2— dice en qué.
| etapa | legalidad | top-1 | top-3 | puzles 1000-1500 | 1500-2000 | 2000+ | Elo escalera |
|---|---|---|---|---|---|---|---|
medium-v4 (base) |
99,8 % | 54,4 % | 82,2 % | 57,9 % | 38,0 % | 16,6 % | 1504 (1446-1558) |
+ DPO on-policy |
99,2 % | 52,3 % | 79,9 % | 59,0 % | 40,3 % | 17,8 % | 1560 (1500-1617) |
+ GRPO |
99,3 % | 53,3 % | 80,3 % | 58,9 % | 39,1 % | 17,8 % | 1572 (1512-1640) |
Tres lecturas, y las tres son la misma historia contada desde ángulos distintos.
La legalidad y el top-1 bajan. De 99,8 % a 99,2-99,3 % y de 54,4 % a 52,3-53,3 %. El top-1 mide cuántas veces el modelo elige la jugada que eligió el humano, y a estos dos modelos se les ha pedido explícitamente que dejen de hacer eso: que prefieran la jugada que el motor puntúa mejor. Que la métrica de imitación baje al alinear no es un defecto, es la definición de haberlo hecho. Es el mismo peaje de las jugadas ilegales, visto en la suite en vez de en las partidas.
Los puzles suben en las seis comparaciones, entre un punto y dos y medio. Los puzles son lo más parecido a fuerza táctica pura que mide el proyecto, y es exactamente lo que M4 no consiguió mover. Pero conviene el decimal: ninguna banda por separado lo establece —las seis diferencias están entre 0,6 y 1,5 sigmas—, y los dos modelos no son independientes entre sí, así que el «seis de seis» vale menos de lo que parece. Los afinados de M4 también subían, entre 0,2 y 0,7 puntos. Lo que se puede decir es que los alineados suben más y en la misma dirección siempre; lo que no se puede decir es que la suite de puzles lo demuestre sola.
Y el Elo de la escalera sube, de 1504 a 1560 y 1572. Con los intervalos solapándose, como siempre: 1446-1558 contra 1500-1617 y 1512-1640. La escalera coincide en dirección con el enfrentamiento directo y sigue sin poder afirmarlo. Es el mismo instrumento del principio del módulo, dando otra vez la misma media respuesta, y la razón de que el hito empezara cambiándolo.
La recompensa verificable, y las cuatro reglas que la hacen auditable
src/rukh/train/rewards.py es el módulo más corto del hito y el que más decisiones tiene por
línea. Cuatro reglas lo gobiernan, y cada una existe porque su contraria produce un fallo concreto.
La legalidad es una puerta, no un término. Una jugada ilegal puntúa el suelo y se salta todo lo demás. Sumar un bonus por ser legal a una suma ponderada permite cambiar legalidad por otra cosa, y el sentido de una recompensa verificable es que hay cosas que no se cambian por nada. El carné de conducir es una puerta: sin carné no se conduce, y no hay un coche lo bastante bueno que compense «menos dos puntos por no tenerlo».
Todo tiene tope. Una recompensa sin techo es una invitación: el optimizador encuentra la dirección que crece sin límite y se va por ahí. Es el efecto cobra: el gobierno colonial de Delhi pagó una recompensa por cada cobra muerta, sin tope, y la gente se puso a criar cobras. Todas las funciones devuelven un valor en un intervalo cerrado, y hay un test que lo comprueba sobre cientos de entradas aleatorias con puntuaciones muy fuera de lo que un motor devolvería.
El signo y la escala se fijan a mano, no con los datos. delta_cp se normaliza por una
constante que pasa quien llama, no por la dispersión del lote, porque una recompensa que se
reescala sola hace incomparables dos corridas y esconde el momento en que el modelo deja de
mejorar. Dos corridas con la escala sacada de sus propios datos son un termómetro en Celsius y otro
en Fahrenheit sin etiqueta: «hoy marca 30» no dice si hace más calor que ayer.
Todas las funciones son puras. Tablero y números entran, número sale, sin llamar al motor dentro. Las puntuaciones vienen de fuera, que es lo que permite que los tests corran en milisegundos en CPU y lo que impide que la recompensa se convierta en un segundo sitio donde se decide el presupuesto de análisis.
El término de repetición es el único negativo y el único que existe por una observación en vez de
por un principio: un modelo premiado por no empeorar descubre que barajar nunca empeora. Salta con
board.is_repetition(2) y no con la reclamación de tablas por triple repetición, porque cuando las
tablas ya son reclamables el baile ya ha ocurrido y la penalización llega tarde.
La galería: la primera versión preguntó lo que no era
labs/m5/reward_hacking.py coge la recompensa que el proyecto usa, la rompe de cinco maneras que
cada una parece razonable sobre el papel, y mide las seis sobre el mismo grupo de candidatas.
La primera versión preguntaba: ¿qué jugada corona cada una? La hipótesis era que las rotas coronarían otra, y ese desacuerdo sería el hackeo. La corrida contestó que las seis coronan la misma jugada en las tres posiciones.
En retrospectiva es evidente y por eso merece quedarse escrito: todas son monótonas en la evaluación del motor, así que el máximo no se puede mover. La cima de la ordenación no es donde vive el hackeo de recompensa.
Lo que hay que mirar es lo que el optimizador consume de verdad, que no es la recompensa sino
(r − media) / desviación sobre el grupo. La galería lo resume en tres columnas: la cabeza,
que es la ventaja que separa a la mejor candidata de la segunda —o sea, cuánta señal queda para
distinguir buena de decente—; el peor, que es la parte de toda la masa de ventaja del grupo
que se lleva la única candidata catastrófica; y las inversiones de orden respecto a la
recompensa sana. Las dos primeras están en la figura:
Con la recompensa sana, las dos candidatas ilegales quedan abajo del todo en −1,28, que es donde una puerta las tiene que poner, y la peor se lleva el 25 % de la masa de ventaja. Quitándole el suelo al término de calidad —una sola línea, un solo término— las dos ilegales salen en +0,18, por encima de una jugada legal que está a 355 cp del óptimo y saca −0,15.
La puerta no se ha tocado: sigue devolviendo el mismo número. Lo que ha cambiado es el rango de lo que hay debajo, y un suelo solo es un suelo en relación con lo que tiene que estar por debajo. Es D-115 otra vez, llegando por el otro lado.
Y de paso la figura enseña el precio honesto del tope, que también está medido: en la columna sana,
b2b4 y f3g4 sacan las dos +0,14, porque un error de 355 cp y otro de 943 cp se recortan los dos
a calidad cero. Un intervalo cerrado se paga con resolución abajo. Es el cambio que el proyecto
eligió hacer, y conviene decir que es un cambio y no una mejora gratis.
Y hubo un segundo error que arreglar antes de poder leer nada: las cinco recompensas rotas estaban escritas cada una por su cuenta, y cuatro se habían dejado el término de repetición por el camino sin querer. Resultado: todas reportaban la misma inversión y ninguna era atribuible a su propio fallo. Reescritas como «la sana con exactamente un término sustituido», cada inversión señala a lo suyo: la que no penaliza repetir invierte exactamente un par, y es el de la jugada que repite (D-117). Vale para una galería didáctica y vale para cualquier ablación: si dos condiciones difieren en dos cosas, no has medido ninguna de las dos.
La misma jugada a cuatro profundidades
El último bloque de la galería es el que no se ve mirando ordenaciones. La misma jugada —Kf6 en
un rey y torre contra rey—, el mismo tablero, cuatro profundidades de búsqueda:
| recompensa | prof. 4 | prof. 6 | prof. 10 | prof. 14 | rango |
|---|---|---|---|---|---|
| (el motor dice) | 597 | 9 996 | 9 998 | 9 998 | — |
| sana | 0,000 | 0,980 | 0,990 | 0,990 | 0,990 |
| sin suelo | −47,015 | −0,020 | −0,010 | −0,010 | 47,005 |
| legalidad como bonus | 2,000 | 2,980 | 2,990 | 2,990 | 0,990 |
| mate por marcador | 0,000 | 3,479 | 3,489 | 3,489 | 3,489 |
| sin penalizar repetir | 0,000 | 0,980 | 0,990 | 0,990 | 0,990 |
| reescalada sola | 0,009 | 1,000 | 1,000 | 0,667 | 0,991 |
La jugada no cambia. Lo que cambia es que a profundidad 6 el motor encuentra el mate. Y entonces:
- Ninguna es estable, incluida la sana, que se mueve 0,990 — todo su intervalo legal.
- La que no tiene suelo se mueve 47,0: cuarenta y siete veces ese intervalo.
- Lo único que no se mueve es el bono de mate plano, porque le pregunta al tablero («¿esta jugada es mate?») y no al motor.
- Y hay una fila que se mueve sin que el motor se mueva: la reescalada sola pasa de 1,000 a 0,667 entre profundidad 10 y 14 con el mismo 9 998 delante. No cambió la jugada, ni la posición, ni la evaluación: cambió el grupo, que es lo único que esa recompensa mira.
GRPO: tres decisiones que se midieron antes de entrenar nada
El bucle está en src/rukh/train/grpo.py y es corto, porque una completación aquí es una sola
jugada: la política gradiente se reduce a ventaja · log π(jugada | prompt) en una posición, y
una sola pasada hacia delante da la distribución entera. Por eso ocho candidatas cuestan una
pasada y no ocho.
Tres knobs se fijaron midiendo, no eligiendo.
La temperatura no es una palanca gratis. El grupo tiene que tener dispersión o no enseña nada, y la temperatura es lo que la compra. Veinticinco pasos a tres temperaturas:
| temperatura | grupos planos | recompensa media del grupo | análisis de motor | grupos útiles por análisis |
|---|---|---|---|---|
| 1,0 | 38 % | 0,865 | 667 | 0,184 |
| 1,3 | 26 % | 0,831 | 795 | 0,186 |
| 1,6 | 19 % | 0,781 | 932 | 0,174 |
Subirla reduce los grupos planos a la mitad, y cuesta exactamente lo que da: la última columna —grupos útiles por análisis de motor, que es el precio real— no se mueve. Con el coste plano, el desempate es cuál se parece más a cómo se lee el modelo, y esa es 1,0.
La legalidad no se puede enseñar si no se propone nunca. Por defecto el grupo se muestrea solo
entre jugadas legales, así que la puerta de legalidad de la recompensa nunca se dispara: la
proporción de ilegales sale 0,0000 exacta. No es un fallo —la demo enmascara las ilegales antes de
que lleguen al tablero, así que la legalidad es una propiedad que la recompensa garantiza en vez
de enseñar—, pero significa que en esa configuración GRPO no puede devolver el peaje que DPO se
gastó. restrict_to_legal: false muestrea del vocabulario entero, así que una propuesta imposible
puede caer en el grupo y sacar el suelo. Es la única configuración en la que la puerta enseña algo.
Y la tercera no era un knob: era un fallo.
Y no es una preocupación teórica. Tres corridas de 400 pasos desde el mismo checkpoint, con la misma semilla, cambiando solo la tasa de aprendizaje:
| tasa de aprendizaje | recompensa (grupo) | KL contra el inicio | grupos planos |
|---|---|---|---|
| 1e-6 | +0,0020 | 0,0005 | 1 276 / 3 200 · 40 % |
| 5e-6 | +0,0206 | 0,0309 | 1 483 / 3 200 · 46 % |
| 2e-5 | +0,0268 | 0,1076 | 1 696 / 3 200 · 53 % |
La recompensa sube, y la proporción de grupos planos sube con ella, monótona en las tres. Es el mismo hackeo de la galería, ocurriendo de verdad, con curva dosis-respuesta. Y la recompensa era la sana y el bucle era el correcto: lo único que hizo falta fue preguntarse qué política maximizaría el número (D-124).
GRPO: sí mejora, y la mejora tiene forma de U invertida
Con las dos recompensas separadas, la pregunta se puede contestar. Tres corridas de 400 pasos desde el mismo checkpoint, con la misma semilla, y solo la tasa de aprendizaje cambiando, medidas sobre 300 posiciones que no se entrenaron:
| lr | recompensa (referencia del grupo) | recompensa (referencia del motor) | grupos planos en validación |
|---|---|---|---|
| 1e-6 | −0,0032 | +0,0088 | 0,387 → 0,370 |
| 5e-6 | +0,0154 | +0,0267 | 0,387 → 0,453 |
| 2e-5 | +0,0155 | +0,0078 | 0,387 → 0,490 |
Tres cosas que leer, y las tres importan.
GRPO funciona. La recompensa medida contra el mejor movimiento disponible —la que no se puede subir haciendo la política más determinista— sube en las tres tasas. Las jugadas mejoran de verdad, no solo respecto a sí mismas.
Las dos recompensas discrepan en el signo a 1e-6: la del grupo baja y la del motor sube. Es exactamente lo que el fallo de arriba predecía, y es la prueba de que separarlas no era pedantería: con la métrica original, esa corrida se habría archivado como fracasada, y es la mejor de las tres.
Y la ganancia es no monótona. Sube hasta 5e-6 y vuelve a caer a 2e-5, mientras el indicador de colapso sube monótono en las tres. Esa es la U invertida de la sobreoptimización, con el mecanismo a la vista en la columna de al lado: la política compra recompensa con determinismo, y pasado un punto la compra deja de salir a cuenta. Es regar una planta: más agua la hace crecer hasta que la ahoga, y la cantidad de agua que echas sube igual de monótona en los dos tramos.
La corrida de 1e-6 es además la única donde los grupos planos bajan respecto al punto de partida —de 0,387 a 0,370—: la única en la que la política se hace más diversa mientras mejora.
A 1 500 pasos
Y entonces se alargaron las corridas a 1 500 pasos, y esa última frase dejó de ser verdad:
| lr | recompensa (motor) | grupos planos | KL |
|---|---|---|---|
| 1e-6 | +0,0279 | 0,385 → 0,472 | 0,122 |
| 5e-6 | +0,0467 | 0,385 → 0,560 | 0,555 |
Las dos mejoran, y bastante más que a 400 pasos. Pero el colapso sube en las dos: a 1 500 pasos ni siquiera la tasa pequeña mantiene la diversidad. Lo que a 400 pasos parecía «una tasa que mejora sin peaje» era en realidad «una tasa que aún no había llegado al peaje».
Así que no hay una corrida limpia y otra sucia: hay una curva, y el punto donde se para es una decisión. Y la decisión se toma con el instrumento del principio del módulo, no con la recompensa.
| corrida | Elo sobre la base (800 partidas) | ilegales propios | grupos planos | KL |
|---|---|---|---|---|
| lr 1e-6 | +44 (IC 23 a 66) | 1,92 % · 1,66× la base | 0,472 | 0,122 |
| lr 5e-6 | +68 (IC 46 a 90) | 3,12 % · 2,08× la base | 0,560 | 0,555 |
Y aun con la tabla completa, esta tabla no decide. Elegir entre las dos restando lo que cada una hizo contra un tercero es exactamente el error que el módulo lleva describiendo desde la primera sección. Se enfrentaron entre sí:
medium-v4-grpo-fast vs medium-v4-grpo 400 partidas +7 Elo incluye el ceromedium-v4-grpo vs medium-v4-grpo-fast 400 partidas +9 Elo incluye el cero agrupado, 800 partidas score 0,49875 elo -0,87 IC -22,2 a +20,4Las dos direcciones dan el mismo veredicto, y las dos lo dan a favor de quien va como A: la firma del ruido simétrico. Agrupadas, empate, con el intervalo centrado en cero.
Y con esta arista, el proyecto tiene dos triángulos completos, que no dicen lo mismo (los
residuos llevan el signo con el que los imprime labs/m5/pooled_match.py):
| triángulo | residuo | veredicto |
|---|---|---|
| base / DPO-off / DPO-on | −45 Elo | 2,6 σ · no cierra |
| base / GRPO / GRPO-rápido | +25 Elo | 1,3 σ · consistente |
Los dos residuos son grandes y solo uno está establecido. Lo honesto es decirlo así —«medido en un triángulo, sugerido en el otro»— y no convertirlo en una ley general sobre el Elo con una muestra de dos.
Los veinticuatro puntos no están ahí. Restando contra la base parecían una diferencia; medida de frente, no hay ninguna. Es la tesis de este módulo por tercera vez dentro del propio módulo, y la tercera es la que decidió.
Se publica la de 1e-6: mismo Elo que la rápida —indistinguibles— y estrictamente menos de todo lo demás, menos colapso (0,472 contra 0,560), menos KL (0,122 contra 0,555) y menos propuestas ilegales (1,66× la base contra 2,08×). Cuando dos modelos empatan en lo que se busca, gana el que cuesta menos en lo que no (D-126).
Un arreglo de medición apareció por el camino y merece el mismo trato que los demás: kl_after
reportaba la KL del último grupo, no un nivel. Dos corridas con la misma tasa dieron 0,00048 y
0,126 sin que nada relevante cambiara entre ellas. Ahora promedia sobre la última décima parte de
los pasos, porque una sola muestra no es un nivel.
Los criterios, uno por uno
Al terminar esta sección sabrás qué pedía el hito, qué se cumplió, qué no, y en qué sentido exacto de la palabra «cumplir».
GOAL.md escribió los criterios de este módulo antes de medir nada, que es cuando hay que
escribirlos y también la razón de que a veces no encajen con lo que se descubre. La norma del
proyecto desde M4 es que el valor está en que el módulo enseñe algo cierto, no en aprobar el
criterio; así que aquí van los tres, con las dos lecturas donde hay dos.
Criterio 1 · «DPO o GRPO ≥ +50 Elo con intervalo sobre su base»
Cumplido en la estimación puntual, no en el extremo del intervalo.
| comparación | partidas | Elo | IC 95 % | ¿separado del cero? |
|---|---|---|---|---|
| DPO off-policy − base | 1 600 | +65,25 | 49,74 a 80,76 | sí |
| DPO on-policy − base | 800 | +57 | 36 a 79 | sí |
| GRPO − base | 800 | +44 | 23 a 66 | sí |
Los tres métodos dan un intervalo separado del cero, así que hay una mejora medida y no una sospecha. Pero el criterio, leído estrictamente —«al menos +50» con el intervalo respaldándolo— pide que el extremo inferior pase de 50.
Con las 800 primeras partidas el brazo off-policy daba el punto por encima de 50 y el extremo inferior en 45, así que se llevó 800 partidas más, con otra semilla de libro y en las dos direcciones, precisamente para cruzarlo. Con las 1 600, el extremo inferior quedó en 49,74.
Es la primera vez en el proyecto que este criterio se mide separado del cero. M4 lo dejó incumplido con cuatro mediciones explicando por qué (D-108); lo que cambió no fue el modelo, fue el instrumento.
Criterio 2 · «Reward model ≥ 75 % en pares no vistos»
Rozado, no cruzado de forma estable.
Cinco corridas: 72,91 %, 74,21 %, 74,71 %, 74,76 %, 75,19 %. Una lo cruza. Pero las dos primeras son la misma semilla, así que 1,3 de esos dos puntos y medio de dispersión no son la partición: son lo que esta medición repite (D-113). Con ese suelo, el 75,19 % y el 74,21 % no se distinguen, y el criterio está por debajo del ruido del instrumento que lo mide.
Sobre los pares que una evaluación estática puede decidir, el acierto es 77,30 %. Es una cifra honesta y es otra pregunta: quita algo más de un cuarto de los datos, justo el cuarto difícil.
Lo que este criterio enseñó no fue si se cruza el 75 %, sino tres cosas que no estaban previstas: que el encoder preentrenado de M3 resta 6,5 puntos, que la capacidad es lo que manda, y que la correlación publicada cambia de signo al quitar la banda de mate (D-119).
Criterio 3 · «rukh-rm, -dpo y -grpo en el Hub con card»
Cumplido, con una desviación de nombre registrada: GOAL.md escribió rukh-small-dpo y
-small-grpo, y se publican sobre medium-v4 por lo mismo que en M4 (D-105) — small es el modelo
de M2 y ya no es la base de nada que la demo sirva. Anotado en D-122.
La parte 3 son los once comandos que produjeron todo esto, en el orden en que se hicieron, con sus salidas.