Harness de evaluación
laya.evals convierte un conjunto de datos etiquetado en una puntuación repetible, y una línea base en
una puerta de aprobado/suspenso, de modo que un cambio de calidad es un diff revisable en lugar de una
comprobación manual.
Las matemáticas de las métricas y el analizador del conjunto de datos son Python puro más numpy y nunca importan torch, así que se ejecutan sin pesos. Ejecutar un conjunto de datos contra un checkpoint necesita el checkpoint y requiere su tiempo de carga normal.
Inicio rápido
# check the format without a model
laya-evals validate research/evals/fixture.jsonl
# score a labelled set on one checkpoint, with thresholds and a baseline
laya-evals run data.jsonl --model english --device cpu \
--min-accuracy 0.8 --max-ece 0.05 --score-within 0.25 --slice language \
--json report.json --markdown report.md
# compare a saved report to a baseline
laya-evals compare report.json --baseline baseline.json --tolerance choice_accuracy=0.02
laya eval ... es lo mismo a través de la CLI principal, así que laya eval validate data.jsonl también
funciona.
Códigos de salida: 0 en caso de éxito, 1 cuando falla un umbral o una tolerancia de línea base, 2
ante un error de uso. run imprime las métricas generales y las particiones solicitadas en stdout, y
escribe el informe completo y un resumen en Markdown cuando se dan --json / --markdown.
Atribuir los errores de la lista corta
Para un conjunto de elecciones etiquetado de alta cardinalidad, laya.evals_shortlist.evaluate_shortlist
usa la ruta existente predict_shortlist y el harness de evaluación habitual. Responde a dos
preguntas distintas: ¿la recuperación conservó la etiqueta de referencia, y Laya la eligió cuando
estaba presente? Esta es una API de Python opcional para etiquetas choice;
los informes normales de laya-evals run no cambian.
import laya
from laya.evals import Dataset
from laya.evals_shortlist import evaluate_shortlist
from laya.shortlist import embed_fn_from_agent
agent = laya.load()
dataset_path = "intents.jsonl"
dataset = Dataset.from_jsonl(dataset_path)
report = evaluate_shortlist(
agent, dataset, embed_fn_from_agent(agent), k=20,
checkpoint_id="my-checkpoint@revision", embedder_id="my-encoder@revision",
dataset_path=dataset_path,
)
print(report.overall)
print(report.cases[0]["shortlist_status"])
Usa la misma función de embedding y el mismo checkpoint que el despliegue que estás midiendo.
Los dos identificadores los proporciona quien llama y deben nombrar revisiones inmutables;
el informe no puede inferir los pesos detrás de un callable arbitrario. dataset_path
registra el SHA256 del archivo junto a la huella de preguntas ya existente. Cada caso
conserva las etiquetas reales de la lista corta y uno de correct, retrieval_miss o
decision_miss. shortlist_recall_at_k es la fracción de etiquetas de referencia conservadas.
shortlist_accuracy_on_recalled son las decisiones correctas divididas entre los casos conservados;
se omite cuando no se conservó ninguno. El choice_accuracy existente sigue siendo
la precisión de extremo a extremo sobre todos los casos, incluidas las fallas de recuperación. Las
métricas de la lista corta aparecen en las mismas particiones por idioma, modelo, pregunta y etiqueta. La
latencia de la solicitud incluye el embedding y la llamada de decisión; el informe no aísla
los tiempos por etapa. Con k >= n, la pregunta original pasa tal cual y el recall de la
recuperación es 1 sin llamar al embedder.
Esto no reproduce los resultados de BANKING77 en issue #102: esos números dependen de su conjunto de datos, su checkpoint y su bi-encoder. Esta API hace repetible el mismo tipo de diagnóstico sobre un conjunto etiquetado propio de quien llama.
Evaluar una exportación ONNX
run --onnx PATH puntúa un modelo ONNX exportado a través de ONNXAgent en lugar del Router de torch,
de modo que un despliegue ONNX (incluida una copia INT8 de
scripts/export_onnx.py --quantize) queda sujeto a los mismos umbrales y líneas base que la ruta de torch:
python scripts/export_onnx.py --model convaiinnovations/laya --output laya.onnx --quantize
laya-evals run data.jsonl --onnx laya.int8.onnx --max-ece 0.05
--model nombra el checkpoint del que vino la exportación — un id del Hub o una ruta local, no un nombre
corto de Router como english, ya que en esta ruta no hay Router (por defecto
convaiinnovations/laya). Su configuración y su tokenizador se cargan desde ahí. El agente sirve un solo
checkpoint, así que una fila del conjunto de datos cuyo campo model nombre otro distinto falla con un
error claro en lugar de ser respondida silenciosamente por el modelo equivocado; --device no se aplica.
--batch-size usa la API por lotes del agente cuando la tiene y recurre a una llamada por estado si no;
--sort-by-length se reenvía a esa API por lotes; el respaldo por estado no tiene grupo que reordenar.
Pasa --calibration PATH para cargar un mapa de calibración ajustado en ONNXAgent, de modo que las
puertas de calibración como --max-ece evalúen contra probabilidades calibradas. El bloque config del
informe registra la ruta onnx y la ruta calibration (cuando se establece).
Medido sobre research/evals/fixture.jsonl (12 filas etiquetadas, checkpoint inglés, CPU):
| runner | choice_acc | noul_acc | score_mae | ece | mean_conf | p50 ms |
|---|---|---|---|---|---|---|
| torch Router | 0.75 | 1.00 | 1.3418 | 0.1596 | 0.7304 | 116.8 |
--onnx fp32 |
0.75 | 1.00 | 1.3418 | 0.1596 | 0.7304 | 66.3 |
--onnx int8 |
0.75 | 1.00 | 1.3512 | 0.1658 | 0.7304 | 46.3 |
La exportación fp32 reproduce los números de torch exactamente, y la copia cuantizada mueve score_mae
en 0.009 y ece en 0.006 — el tipo de deriva que compare --tolerance está pensado para controlar.
Formato del conjunto de datos
Un objeto JSON por línea (JSONL). Las líneas en blanco y las líneas que empiezan por # se ignoran.
| campo | obligatorio | significado |
|---|---|---|
state |
sí | texto, correo, ticket o documento JSON sobre el que decidir |
questions |
sí | un diccionario de pregunta de Laya, exactamente como lo acepta Router.predict |
expected |
sí | la verdad de referencia indexada por id de pregunta: una etiqueta para choice, un número para score, true/false para noul |
tags |
no | cadenas por las que particionar |
language |
no | un código por el que particionar |
model |
no | fuerza un checkpoint para esta fila; --model lo anula. Una fila que no fuerza nada se etiqueta con el checkpoint con el que respondió el Router |
research/evals/dataset.template.jsonl tiene un ejemplo comentado.
Métricas
Cada métrica se calcula por respuesta donde aplica y se agrega sobre el conjunto de datos:
| métrica | aplica a | significado |
|---|---|---|
choice_accuracy |
choice |
fracción cuya etiqueta elegida coincide |
noul_accuracy |
noul |
fracción cuyo booleano (probabilidad >= 0.5) coincide |
score_mae |
score |
error absoluto medio |
score_within_<tol> |
score |
fracción dentro de una tolerancia absoluta |
ece |
cualquier respuesta con una confianza | error de calibración esperado, 15 bins, calculado sobre answer["answer_confidence"], la probabilidad calibrada que Laya informa en todos los tipos de respuesta |
brier |
cualquier respuesta con una confianza y una etiqueta conocida | puntuación de Brier de la confianza como P(correcta), mean((confidence - correct)**2); más bajo es mejor |
aurc |
cualquier respuesta con una confianza y una etiqueta conocida | área bajo la curva de riesgo–cobertura: un valor de riesgo por cada nivel de confianza distinto, cada uno ponderado por las respuestas que abarca ese nivel; más bajo es mejor, y premia una confianza que ordena correctas de incorrectas en lugar de solo estar calibrada |
selective_accuracy@50, selective_accuracy@80 |
cualquier respuesta con una confianza y una etiqueta conocida | precisión sobre las respuestas que acepta un umbral de confianza en el punto de cobertura del 50% / 80% – lo que compra abstenerse de la cola menos confiable. Un umbral no puede dividir un grupo de confianzas iguales, así que esto puede cubrir más que la fracción nombrada; consulta cortes de cobertura |
mean_confidence |
cualquier respuesta con una confianza | media del answer["answer_confidence"] informado |
latency_p50_ms, latency_p95_ms |
por solicitud | tiempo de reloj que esperó cada solicitud, informativo – consulta procesamiento por lotes |
cost_per_decision_p50_ms, cost_per_decision_p95_ms |
por decisión | el tiempo de reloj de una llamada dividido por las filas que llevó, informativo |
Cortes de cobertura y empates
Ambas métricas de cobertura cortan en un umbral de confianza, y un umbral acepta toda respuesta en su
propia confianza. Así que un corte nunca divide un grupo de respuestas que comparten una: cuando
coverage * n cae dentro de un grupo así, se acepta cada miembro del grupo. El número de respuestas
detrás de la cifra es, por lo tanto, el borde superior del grupo en lugar de la fracción nombrada –
selective_accuracy@50 sobre una partición cuyas confianzas son todas iguales es la precisión de esa
misma partición, no la mejor mitad de ella. El recuento que imprime la puerta (n= en el mensaje de
fallo de una regla) es el tamaño de la partición, no el tamaño aceptado, así que un grupo muy amplio no
es visible solo a partir del mensaje.
Los empates son el caso normal, no un caso límite: una temperatura ajustada puede dejar que un bucket
informe una masa puntual, algo que laya.common.answer_confidence registra del choice:11+ que se
distribuye, y un checkpoint real produjo un grupo de seis filas en exactamente 1.0 sobre doce
respuestas. Cortar en un índice de fila hizo, en cambio, que ambas métricas dependieran del orden en que
llegaban los datos – las mismas filas, barajadas, movieron selective_accuracy@50 entre 0.000 y 1.000.
aurc integra un valor de riesgo por cada nivel distinto, ponderado por las respuestas que abarca ese
nivel, así que sigue siendo un área bajo la curva de riesgo–cobertura en lugar de un promedio de puntos
de tamaño desigual.
Dos consecuencias que conviene anticipar:
- Un número puede moverse en cualquier dirección, más de lo que podría reordenarlo. Donde un grupo
cruza el corte, la lectura por umbral difiere de toda lectura por índice de fila de los mismos datos:
medida sobre 400,001 conjuntos de datos con forma de empate, hasta 0.500 para
selective_accuracy@50y 0.351 paraaurc. Sobre la forma de doce respuestas de arriba – seis correctas, todas con confianza 1.0 –aurcse mueve 0.327 (0.173 a 0.500). Una puerta que aprobaba puede fallar, y una que fallaba puede aprobar; el veredicto anterior dependía del orden de las filas, incluso para un límite absolutominomax, que no lo rechaza nada porque lee una sola ejecución. - Regenera las líneas base confirmadas.
config.coverage_metric_definitionregistra qué definición produjo un informe. Comparar una métrica de cobertura entre dos definiciones se rechaza en ambas puertas que restan una línea base –--baseline --tolerance(EvalReport.compare) y una regla relativa (max_drop/max_increase) bajo--gate-policy– y en cualquiera de los dos lados obsoleto, no solo en la línea base: un candidato producido por unlayamás antiguo arrastra un artefacto de orden de filas que puede leerse mejor que la verdad, así que evaluarlo contra una línea base regenerada correctamente aprobaría una regresión que el informe bien puntuado suspende. Sin ese rechazo, una línea base obsoleta oculta una regresión real: una partición registrada en 0.033 bajo la definición antigua se lee como 0.517 bajo esta, así que un candidato que de verdad cayó 0.217 superaría unmax_dropde 0.05.eceybrierno cortan y siguen siendo comparables.
Cuando no hay empates en los datos hay un nivel por respuesta, y ambas métricas son exactamente las que siempre han sido – idénticas bit a bit, no solo parecidas.
Añade ScoreWithin(0.25) a la lista del evaluador para obtener una métrica de tolerancia; el conjunto por
defecto es choice_accuracy, noul_accuracy, score_mae, mean_confidence, más ece. Desde la CLI, lo
mismo es una sola bandera: laya-evals run data.jsonl --score-within 0.25 informa score_within_0.25
junto a las predeterminadas, y la bandera se repite, así que --score-within 0.25 --score-within 0.5
informa de ambas.
Una métrica de tolerancia necesita una respuesta score con una etiqueta numérica, así que en un conjunto
de datos sin ninguna no tiene valor: run nombra la métrica que no pudo calcular en lugar de publicar un
cero silencioso, y una puerta --min / --max que nombre esa métrica falla como ausente. Las tolerancias
que se pidieron en una ejecución se registran en el bloque config del informe, así que una línea base
revisada dice qué columnas espera.
Procesamiento por lotes y tiempos
--batch-size N puntúa hasta N filas consecutivas que comparten checkpoint y esquema de preguntas en una
sola llamada. Ambas métricas de tiempo provienen de las mismas mediciones y responden a preguntas
distintas: cada fila de un lote vuelve cuando vuelve el lote, así que su latency es la llamada entera,
mientras que su cost_per_decision es 1/N de ella. Por lo tanto, el procesamiento por lotes sube
latency_* y baja cost_per_decision_* sobre un conjunto de decisiones sin cambios, y
--max latency_p50_ms=... pregunta si las solicitudes se sirvieron rápido, no si la ejecución fue barata.
Sin --batch-size las dos coinciden.
compare ignora cualquier métrica *_ms a menos que una tolerancia la nombre, así que estas nunca hacen
fallar una línea base por ruido de tiempos. Lo que hizo realmente el harness – el tamaño de lote pedido,
la forma de runner a la que se resolvió, cuántas filas compartieron una llamada y el fragmento más grande –
se registra en config.timing del informe, porque la bandera por sí sola no dice si se procesó algo por
lotes. Esos contadores registran las llamadas emitidas, no las llamadas que volvieron: con
laya-evals run --on-error skip, un fragmento cuya llamada lanzó una excepción sigue contando en rows_grouped y
max_chunk, junto a sus entradas en config.errored. La opción por defecto es --on-error fail, que
vuelve a lanzar la excepción en lugar de publicar un informe cuyas métricas solo cubren las llamadas que
volvieron. Las dos métricas *_ms cuentan solo las llamadas que volvieron, así que una llamada fallida
nunca aporta una latencia que no midió.
Agrupar las filas dentro de un lote
--sort-by-length agrupa filas de tamaño similar en la misma pasada hacia adelante, de modo que cada
pasada se rellena hasta un máximo más corto en lugar de hasta la fila más larga que contiene. Es la forma
de las llamadas, no sus respuestas: los resultados vuelven en el mismo orden y puntúan igual, que es por
lo que research/ puede informar 2.15x sobre 10,000 tickets sin que cambie ninguna decisión.
Tiene que haber más de una pasada para reordenar, así que solo surte efecto con un --batch-size N por
debajo del número de filas que agrupa la ejecución. config.timing mantiene separadas las dos
afirmaciones: sort_by_length es lo que dijo la línea de comandos, sort_by_length_sent es lo que llegó
al runner. Una ejecución sin --batch-size pide algo que no puede ocurrir, y lo dice con sent: false;
un runner cuyo predict_batch es anterior al parámetro se puntúa sin ordenar en lugar de lanzar
TypeError a mitad de una ejecución larga.
La puerta de abstención en un umbral
--min-confidence T reenvía el umbral de abstención opcional del núcleo (#361) a cada llamada que hace
la ejecución, así que Router y ONNXAgent marcan las respuestas cuyo answer_confidence cae por
debajo de T con low_confidence: True antes de que el harness las vea. A diferencia de la agrupación,
esto cambia las respuestas que puntúan: la misma ejecución con T=0 y T=0.7 es un experimento
distinto, y un barrido de precision@coverage es una serie de estos, no una única línea base a la deriva.
El rango aceptado es el de laya.confidence.check_min_confidence del núcleo – [0.0, 1.0], finito, no
un bool – en lugar de una copia local, así que un valor que la propia puerta rechazaría falla como error
de uso (salida 2) antes de que se cargue ningún checkpoint. 0.0 es una petición legal: es el brazo de
control de un barrido de precision@coverage, y una comprobación que lo descartara ocultaría el propio
piso del barrido.
Un runner cuyo predict o (para una ejecución por lotes) cuyo predict_batch sea anterior a la puerta
es rechazado con un EvalError con nombre, no puntuado sin el umbral. Descartar en silencio un
control de puntuación es la clase de mentira que este harness existe para evitar: el informe publicaría
una cifra de precision@coverage para una política que nunca se ejecutó. config.timing registra tanto
la petición como el hecho: min_confidence es el umbral que se solicitó, min_confidence_sent dice si
alguna llamada de esta ejecución lo llevó realmente.
Particiones
compare y run informan números generales y, para --slice language|model|qid|tag, las mismas métricas
por valor de partición, de modo que una regresión en un idioma o en una pregunta es visible sin leer el
agregado. La partición model contiene el checkpoint que respondió cada fila: la propia elección del
Router por solicitud, o el model del runner para un runner que no enruta.
Puertas de partición opcionales
La puerta de línea base general puede aprobar mientras una partición más pequeña de idioma o de
pregunta regresa mal. Para convertir una partición revisada en un requisito de CI, guarda una política
JSON como gates.json:
{
"version": 1,
"rules": [
{"slice": {"language": "zh"}, "metric": "choice_accuracy",
"min_count": 50, "max_drop": 0.05},
{"slice": {"qid": "intent"}, "metric": "ece",
"min_count": 50, "max": 0.10}
]
}
laya-evals run data.jsonl --baseline baseline.json --tolerance choice_accuracy=0.02 \
--gate-policy gates.json --json report.json
laya-evals compare report.json --baseline baseline.json \
--tolerance choice_accuracy=0.02 --gate-policy gates.json
Cada regla selecciona exactamente un valor de language, model, qid o tag y nombra la métrica
exactamente como aparece en el informe de particiones. Tiene un min_count positivo y exactamente un
límite: min o max comprueba el valor del candidato; max_drop permite como máximo esa disminución
respecto a la línea base; max_increase permite como máximo ese aumento. Los dos últimos requieren
--baseline. El recuento es el número de respuestas puntuadas para esa métrica en la partición
seleccionada, en ambos informes para una regla relativa. Para ece, es el número de respuestas con
una confianza finita y un valor booleano correct. Una partición o métrica ausente, muy pocas
respuestas puntuadas, o casos omitidos/con error hacen fallar la puerta opcional. Las reglas relativas
también exigen que ambos informes lleven identidades de ejecución coincidentes, de modo que la evidencia
ausente no pueda aparecer como aprobada. Una regresión medida informa de la partición, la métrica, los
recuentos, los valores y el límite. Una sintaxis de política no válida sale con 2 antes de que se cargue
un checkpoint; un fallo de calidad sale con 1. La política se registra en config.gate_policy de un
informe run --json. compare --gate-policy aplica a las mediciones guardadas la política
proporcionada en esa línea de comandos. Si difiere de la política registrada del informe, compare lo
dice; una reverificación explícita bajo una política nueva no cambia la política con la que se hizo la
ejecución original.
La comparación general habitual sigue aplicándose, incluida su tolerancia y su comportamiento de línea
base heredada. Sin --gate-policy, el informe y la comparación de particiones se comportan como antes.
Identidad de la ejecución
run registra lo que midió en el bloque config del informe, así que el artefacto que lee un revisor es
revisable por sí solo:
| clave | significado |
|---|---|
schema |
la forma del informe, laya-evals-report/1, para que un consumidor pueda rechazar uno que no sepa leer |
dataset |
la ruta tal como se escribió – un nombre, no un hash |
dataset_sha256 |
el sha256 de los bytes del conjunto de datos que se analizaron |
questions_sha256 |
una huella del esquema de preguntas: el id, el tipo, las instructions y los criteria de cada pregunta, sobre todo el conjunto de datos |
laya_version |
el laya que calculó los números |
coverage_metric_definition |
qué definición de aurc / selective_accuracy@* produjo este informe (consulta cortes de cobertura). Una regla de puerta relativa sobre cualquiera de ellas rechaza una línea base registrada bajo otra distinta, en lugar de restar números que no significan lo mismo |
gate_policy |
la política opcional de puertas de partición aplicada por run --gate-policy |
thresholds |
la puerta que aplicó esta ejecución: min, max y baseline_tolerance |
revisions |
el commit del que se cargó cada checkpoint que respondió (consulta más abajo) |
dataset es una ruta, y una ruta no es una identidad: un conjunto de datos se puede editar in situ, mover
o volver a obtener con el mismo nombre, y una caché de CI puede entregar a dos ejecuciones el mismo nombre
de archivo y bytes distintos. questions_sha256 cubre lo que se preguntó en lugar de cuántas filas
había, así que añadir estados a un conjunto de preguntas sin cambios deja la huella intacta —
dataset_sha256 sigue moviéndose, y añadir una fila es un cambio en los datos, no en la pregunta.
También cubre instructions, porque el texto de las instrucciones es el prompt. build_sequence renderiza
"<type> question: <instructions>" en la cabeza tokenizada, Agent rechaza una pregunta sin instrucciones
(“add the text the model should answer”), y la propia identidad de pregunta de Laya ya lo cuenta:
Router._question_schema y la agrupación por lotes de este harness se basan en todo el diccionario de
preguntas, y tests/test_router_batch.py fija que reformular solo instructions mueve una fila a su
propio grupo de lote. Entonces, ¿una instrucción reformulada sigue comparando igual con una línea base?
No — y ese es el punto. “Judge whether a refund is justified” y “Be conservative and only approve explicit
refund requests” formulan preguntas distintas, y la puerta de métricas solo puede darse cuenta cuando la
diferencia mueve un número más allá de la tolerancia que nombraste. Nombrar una opción choice es el
mismo argumento: criteria es el espacio de decisión, y las comprobaciones metamórficas de
research/eval/metamorphic.py existen porque renombrar una etiqueta cambia las respuestas.
Nada del texto de las instrucciones se normaliza salvo el único paso que aplica el propio motor: unas
instructions no textuales se hashean como json.dumps(ins, ensure_ascii=False), igual que
Agent._to_internal. Así que tanto los espacios en blanco como la redacción cuentan, y una reformulación
que una persona considera una corrección de estilo se trata como un experimento nuevo. Esa es la opción
honesta por defecto — la alternativa es una heurística de similitud interponiéndose entre una ejecución y
su línea base, y ningún sistema de evaluación de uso común tiene una.
No se registra nada con marca temporal, así que un informe sigue siendo reproducible byte a byte para un runner fijo.
REPORT_SCHEMA, questions_fingerprint(dataset) y file_fingerprint(path) son públicos, así que un
llamador que maneje laya.evals.evaluate directamente obtiene la misma identidad que una ejecución de la CLI.
Línea base y puerta de CI
- Mantén juntos el conjunto de datos, un informe de línea base (la salida
--jsonque hayas revisado) y las tolerancias, y confírmalos en el repositorio, de modo que un cambio sea un diff revisable.--tolerance METRIC=VALUEes la deriva absoluta máxima permitida para esa métrica. laya-evals run ... --baseline baseline.json --tolerance ...sale con un código distinto de cero ante una deriva, así que se integra en CI sin cambios.laya.evals.EvalReport.compareyassert_regressionexponen la misma lógica para los tests.
La puerta de métricas responde “¿se movieron los números”. No puede responder “¿eran estos los mismos
números”, porque compare lee overall y solo overall — así que una línea base registrada contra un
conjunto de datos daría por bueno un candidato puntuado sobre otro, con una aritmética idéntica.
EvalReport.comparable_to cierra ese hueco: compara schema, dataset_sha256 y questions_sha256, y
run --baseline y compare siguen imprimiendo todos los deltas, y luego fallan con una salida distinta
de cero que nombra la clave y ambos valores:
FAIL: baseline is not comparable: dataset_sha256 (dataset bytes): baseline is <sha>, this run is <sha>
Una clave ausente en cualquiera de los dos lados es desconocida, no un conflicto, así que todo informe
escrito antes de que existiera la identidad sigue comparando exactamente como lo hacía. Eso incluye la
línea base de la puerta programada de abajo, que proviene de research/eval/ y no tiene ningún
config.schema.
Dos superficies de CI usan esto:
- un trabajo sin pesos en
.github/workflows/ci.ymlejecutatests/test_evals.pyytests/test_evals_api.py, así que las matemáticas de las métricas, el análisis del conjunto de datos y la CLI quedan cubiertos en cada PR sin descargar un checkpoint; .github/workflows/evals.ymlse ejecuta semanalmente, antes de una publicación y bajo demanda: evalúa el checkpoint inglés sobre la suite MASSIVE en inglés y lo compara conresearch/results/eval_english_51_languages.jsoncon las tolerancias deresearch/evals/thresholds.json. Sube el informe como artefacto y no bloquea un PR.
El harness es determinista para una revisión de checkpoint fija, así que un informe es reproducible. run
registra el conjunto de datos, el modelo y la unidad, más los hechos de tiempos
de la ejecución, en el bloque config del informe, y revisions: el commit del que se cargó realmente
cada checkpoint que respondió. --revision <SHA> fija ese commit para cada checkpoint que carga la
ejecución, y --revision english=<SHA> fija uno (repetible) — que es la forma que quiere una ejecución
con enrutamiento automático, ya que los tres checkpoints son tres repositorios y un commit no puede
existir en todos ellos. Sin fijar, la ejecución toma la rama por defecto del checkpoint y el informe sigue
diciendo qué commit respondió, así que una deriva de línea base se puede atribuir a los pesos o al código.
laya/revisions.py publica SHAs de commit revisados en PINNED_REVISIONS para los llamadores que quieran
optar por ellos. Con --onnx, solo se aplica un --revision <SHA> simple, a la descarga de configuración
y tokenizador.
Añadir el conjunto etiquetado real
Suelta un JSONL en research/evals/ y una línea base revisada junto a él, y luego apunta un flujo de
trabajo (o research/evals/check_regression.py) a ambos. El formato es el mismo que el del fixture; nada
en el harness sabe de MASSIVE.