diff --git a/benchmarks/audit_native_outputs.py b/benchmarks/audit_native_outputs.py new file mode 100644 index 000000000..86cfc36f7 --- /dev/null +++ b/benchmarks/audit_native_outputs.py @@ -0,0 +1,228 @@ +"""Compare complete native training and held-out outputs across fresh recovery.""" + +import argparse +import hashlib +import json +from pathlib import Path + +import torch + +from benchmarks.audit_native_learning_signal import audit as audit_signal +from benchmarks.audit_native_runtime import audit as audit_runtime +from vime.rollout.native_eval import evaluation_seed +from vime.rollout.rm_hub.math_utils import grade_answer_verl + +SCORE_ATOL, SCORE_RTOL = 1e-5, 3e-5 +DATASET = "qualification-development" + + +def compare_samples(left: dict, right: dict) -> float: + for key in ( + "index", + "group_index", + "prompt", + "tokens", + "response_length", + "response", + "label", + "reward", + "status", + "metadata", + "weight_versions", + ): + assert left[key] == right[key], f"Changed sample {left['index']}: {key}" + traces = [ + {key: value for key, value in sample["recurrent_trace"].items() if key not in {"runtime_epoch", "request_id"}} + for sample in (left, right) + ] + assert traces[0] == traces[1], "Changed semantic trace" + return compare_scores(left["rollout_log_probs"], right["rollout_log_probs"]) + + +def compare_scores(left, right) -> float: + a, b = torch.as_tensor(left), torch.as_tensor(right) + assert a.shape == b.shape and a.numel() > 0 and bool(torch.isfinite(a).all()) and bool(torch.isfinite(b).all()) + torch.testing.assert_close(a, b, atol=SCORE_ATOL, rtol=SCORE_RTOL) + return float((a - b).abs().max()) + + +def validate_response(sample: dict, limit: int, tokenizer) -> None: + length, trace = sample["response_length"], sample["recurrent_trace"] + assert 0 < length <= limit and len(sample["tokens"]) > length + assert trace["finish_reason"] in ("stop", "length") + assert sample["status"] == ("completed" if trace["finish_reason"] == "stop" else "truncated") + if trace["finish_reason"] == "length": + assert length == limit + else: + assert sample["tokens"][-1] == tokenizer.eos_token_id + assert sample["response"] == tokenizer.decode(sample["tokens"][-length:], skip_special_tokens=True), ( + "Saved text does not decode from its tokens" + ) + assert ( + sample["reward"] in (0, 1) and int(grade_answer_verl(sample["response"], sample["label"])) == sample["reward"] + ) + scores = torch.as_tensor(sample["rollout_log_probs"]) + assert scores.shape == (length,) and bool(torch.isfinite(scores).all()) + + +def audit(continuous: Path, resumed: Path, packet: Path, input_audit: Path, algorithm: str, tokenizer) -> dict: + runtime = audit_runtime(continuous, resumed, packet) + signals = [audit_signal(run, packet, input_audit, algorithm) for run in (continuous, resumed)] + consumed = dict(runtime["consumed_sha256"]) + + def consume(path): + consumed[str(path.resolve())] = hashlib.sha256(path.read_bytes()).hexdigest() + return path + + def load(path): + return torch.load(consume(path), map_location="cpu", weights_only=False) + + profile = json.loads(consume(packet / "qualification.json").read_text()) + assert profile["eval_completions_per_prompt"] == 1 + assert profile["prompts_per_rollout"] == 4 and profile["completions_per_prompt"] == 8 + train_rows = [json.loads(line) for line in consume(packet / "train.jsonl").read_text().splitlines()] + train_ids = [row["metadata"]["id"] for row in train_rows] + assert len(train_ids) == len(set(train_ids)) == 12 and train_ids == profile["selected_ids"]["train"] + inputs = json.loads(consume(input_audit).read_text()) + development = packet / "development.jsonl" + assert ( + hashlib.sha256(consume(development).read_bytes()).hexdigest() == profile["files"][development.name]["sha256"] + ) + rows = [json.loads(line) for line in development.read_text().splitlines()] + ids = [row["metadata"]["id"] for row in rows] + assert len(ids) == len(set(ids)) == profile["files"][development.name]["rows"] == 8 + assert ids == profile["selected_ids"]["development"] and not set(ids) & set(profile["selected_ids"]["train"]) + assert len(inputs["rows"]) == 20 and {row["id"] for row in inputs["rows"]} == set(train_ids + ids) + token_rows = [row for row in inputs["rows"] if row["split"] == "development"] + assert len(token_rows) == 8 and [row["id"] for row in token_rows] == ids + token_hashes = {row["id"]: row["token_ids_sha256"] for row in token_rows} + training, evaluation, summaries = [], [], [] + for run_index, run in enumerate((continuous, resumed)): + train_rounds, eval_rounds, curve = [], [], [] + for step in range(3): + data = load(run / f"details/rollout_data/{step}.pt") + trained = load(run / f"details/train_data/{step}.pt") + for sample in data["samples"]: + validate_response(sample, profile["response_limit"], tokenizer) + train_rounds.append((data["samples"], trained["samples"])) + consume(run / f"grad-actor-{step}-0.pt") + for step in range(4): + data = load(run / f"details/rollout_data/eval_{step}.pt") + samples = data["samples"] + assert data["rollout_id"] == step and len(samples) == len(rows) + phase = "continuous" if run_index == 0 else ("split" if step <= 2 else "resume") + epoch = runtime["phases"][phase]["runtime_epoch"] + digests, requests = set(), set() + for index, (sample, row) in enumerate(zip(samples, rows, strict=True)): + assert sample["index"] == sample["group_index"] == index + assert sample["metadata"]["id"] == row["metadata"]["id"] and sample["label"] == row["label"] + assert sample["metadata"]["native_eval"] == { + "dataset": DATASET, + "prompt_index": index, + "completion": 0, + "seed_profile": "native-heldout-v1", + "top_p": 1, + "top_k": -1, + "max_tokens": profile["response_limit"], + "stop_token_ids": [], + } + length, trace = sample["response_length"], sample["recurrent_trace"] + validate_response(sample, profile["response_limit"], tokenizer) + prefix = hashlib.sha256(json.dumps(sample["tokens"][:-length]).encode()).hexdigest() + assert prefix == token_hashes[row["metadata"]["id"]] + assert trace["runtime_epoch"] == epoch and trace["policy_version"] == step + 1 + assert sample["weight_versions"] == [str(step + 1)] + assert trace["model_family"] == "ouro" and trace["schema_version"] == 1 + assert ( + trace["model_revision"] == profile["model_revision"] + and trace["engine_revision"] == profile["engine_revision"] + ) + assert trace["prefill_depth"] == 4 and trace["decode_depths"] == [4] * length + assert trace["temperature"] == 0 and trace["seed"] == evaluation_seed( + profile["seed"], DATASET, index, 0 + ) + assert trace["latent_seed"] is None and trace["latent_profile"] is None + assert ( + isinstance(trace["request_id"], str) + and trace["request_id"] + and trace["request_id"] not in requests + ) + requests.add(trace["request_id"]) + assert len(trace["publication_digest"]) == 64 + digests.add(trace["publication_digest"]) + assert len(digests) == 1, "Mixed held-out policy publications" + digest = digests.pop() + if step < 3: + assert digest == signals[run_index]["rounds"][step]["publication_digest"], ( + "Held-out and training policy differ" + ) + curve.append( + dict( + completed_updates=step, + reward_mean=sum(sample["reward"] for sample in samples) / len(samples), + response_tokens=sum(sample["response_length"] for sample in samples), + truncated=sum(sample["status"] == "truncated" for sample in samples), + publication_digest=digest, + ) + ) + eval_rounds.append(samples) + assert len({row["publication_digest"] for row in curve}) == 4, "An update reused an old publication" + training.append(train_rounds) + evaluation.append(eval_rounds) + summaries.append(curve) + errors = {"training_scores": 0.0, "heldout_scores": 0.0, "training_tensors": 0.0, "gradient_norm": 0.0} + for left, right in zip(signals[0]["rounds"], signals[1]["rounds"], strict=True): + errors["gradient_norm"] = max( + errors["gradient_norm"], compare_scores(left["gradient_norm"], right["gradient_norm"]) + ) + for left, right in zip(*training, strict=True): + for a, b in zip(left[0], right[0], strict=True): + errors["training_scores"] = max(errors["training_scores"], compare_samples(a, b)) + for a, b in zip(left[1], right[1], strict=True): + assert torch.equal(torch.as_tensor(a["loss_masks"]), torch.as_tensor(b["loss_masks"])) + for key in ("advantages", "returns", "kl", "ref_log_probs" if algorithm == "rltt" else "log_probs"): + errors["training_tensors"] = max(errors["training_tensors"], compare_scores(a[key], b[key])) + for left, right in zip(*evaluation, strict=True): + for a, b in zip(left, right, strict=True): + errors["heldout_scores"] = max(errors["heldout_scores"], compare_samples(a, b)) + useful = sorted(set(signals[0]["useful_updates"]) & set(signals[1]["useful_updates"])) + return { + "output_equivalence_pass": True, + "joint_signal_updates": useful, + "output_and_signal_pass": bool(useful), + "training_samples_per_run": 96, + "heldout_samples_per_run": 32, + "numeric_tolerance": {"atol": SCORE_ATOL, "rtol": SCORE_RTOL}, + "max_absolute_errors": errors, + "continuous_curve": summaries[0], + "resumed_curve": summaries[1], + "runtime": runtime, + "signals": signals, + "consumed_sha256": consumed, + "scope": "complete three-update native output/held-out recovery qualification, not a convergence experiment", + "weights_optimizer_frozen_sources": "REQUIRES_SEPARATE_AUDITS", + "reward_convergence": "NOT_ESTABLISHED", + } + + +def main(): + from transformers import AutoTokenizer + + parser = argparse.ArgumentParser(description=__doc__) + for name in ("continuous", "resumed", "packet", "input-audit", "tokenizer", "output"): + parser.add_argument("--" + name, type=Path, required=True) + parser.add_argument("--algorithm", choices=("grpo", "rltt"), required=True) + args = parser.parse_args() + tokenizer = AutoTokenizer.from_pretrained(args.tokenizer, local_files_only=True, trust_remote_code=False) + report = audit(args.continuous, args.resumed, args.packet, args.input_audit, args.algorithm, tokenizer) + report["tokenizer_sha256"] = { + name: hashlib.sha256((args.tokenizer / name).read_bytes()).hexdigest() + for name in ("tokenizer.json", "tokenizer_config.json", "special_tokens_map.json", "vocab.json", "merges.txt") + if (args.tokenizer / name).is_file() + } + args.output.write_text(json.dumps(report, indent=2) + "\n") + raise SystemExit(0 if report["output_and_signal_pass"] else 1) + + +if __name__ == "__main__": + main() diff --git a/benchmarks/results/native-output-recovery/audit_native_response_tokenizer.py b/benchmarks/results/native-output-recovery/audit_native_response_tokenizer.py new file mode 100644 index 000000000..428e15698 --- /dev/null +++ b/benchmarks/results/native-output-recovery/audit_native_response_tokenizer.py @@ -0,0 +1,55 @@ +"""Validate answer-replay controls with the retained official tokenizer, not model output.""" + +import hashlib +import json +from pathlib import Path + +import torch +from transformers import AutoTokenizer + +from benchmarks.audit_native_outputs import validate_response +from vime.rollout.rm_hub.math_utils import grade_answer_verl +from vime.utils.data import Dataset + +task = Path(__file__).resolve().parents[1] +packet = task / "data/native-qualification-v1" +model = task / "data/math-v1/model-config/ouro-thinking" +profile = json.loads((packet / "qualification.json").read_text()) +inputs = json.loads((task / "evidence/native-qualification-input-audit.json").read_text()) +assert inputs["qualification_sha256"] == hashlib.sha256((packet / "qualification.json").read_bytes()).hexdigest() +token_hashes = {row["id"]: row["token_ids_sha256"] for row in inputs["rows"]} +tokenizer = AutoTokenizer.from_pretrained(model, local_files_only=True, trust_remote_code=False) +assert tokenizer.eos_token_id == json.loads((model / "config.json").read_text())["eos_token_id"] == 2 +rows = [] +for split in ("train", "development"): + source = packet / f"{split}.jsonl" + assert hashlib.sha256(source.read_bytes()).hexdigest() == profile["files"][source.name]["sha256"] + dataset = Dataset(str(source), tokenizer, None, None, prompt_key="prompt", label_key="label", + metadata_key="metadata", apply_chat_template=True, apply_chat_template_kwargs={}) + for sample in dataset.samples: + prefix = tokenizer.encode(sample.prompt, add_special_tokens=False) + assert hashlib.sha256(json.dumps(prefix).encode()).hexdigest() == token_hashes[sample.metadata["id"]] + wrong = r"\boxed{0}" if not grade_answer_verl(r"\boxed{0}", sample.label) else r"\boxed{1}" + for expected, response in ((1, r"\boxed{" + sample.label + "}"), (0, wrong)): + output = tokenizer.encode(response, add_special_tokens=False) + [tokenizer.eos_token_id] + decoded = tokenizer.decode(output, skip_special_tokens=True) + assert int(grade_answer_verl(decoded, sample.label)) == expected + record = dict(tokens=prefix + output, response_length=len(output), response=decoded, label=sample.label, + reward=expected, status="completed", recurrent_trace={"finish_reason": "stop"}, + rollout_log_probs=[-1.0] * len(output)) + validate_response(record, profile["response_limit"], tokenizer) + rows.append(dict(split=split, id=sample.metadata["id"], expected_reward=expected, + response_tokens=len(output), token_sha256=hashlib.sha256(json.dumps(output).encode()).hexdigest())) +assert len(rows) == 40 and not torch.cuda.is_initialized() +result = { + "scope": "answer-replay controls from known labels with invented scores; no model generation or training", + "qualification_sha256": inputs["qualification_sha256"], "eos_token_id": tokenizer.eos_token_id, + "tokenizer_class": type(tokenizer).__name__, "trust_remote_code": False, "local_files_only": True, + "rows": rows, "cuda_initialized": False, "model_generation": "NOT_RUN", + "source_sha256": hashlib.sha256((task / "vime/benchmarks/audit_native_outputs.py").read_bytes()).hexdigest(), + "tokenizer_sha256": {name: hashlib.sha256((model / name).read_bytes()).hexdigest() for name in + ("tokenizer.json", "tokenizer_config.json", "special_tokens_map.json", "vocab.json", "merges.txt")}, +} +(task / "evidence/native-output-tokenizer.json").write_text(json.dumps(result, indent=2) + "\n") +print(json.dumps({"answer_replay_controls": len(rows), "eos_token_id": tokenizer.eos_token_id, + "model_generation": "NOT_RUN", "cuda_initialized": False})) diff --git a/benchmarks/results/native-output-recovery/manifest.json b/benchmarks/results/native-output-recovery/manifest.json new file mode 100644 index 000000000..290c279aa --- /dev/null +++ b/benchmarks/results/native-output-recovery/manifest.json @@ -0,0 +1,33 @@ +{ + "source_sha256": { + "benchmarks/audit_native_outputs.py": "e55d2fa5f89a45d7afdb8fa22724f33f4fb70396830e4584957bcffbcb6fb598", + "benchmarks/audit_native_runtime.py": "b676295b99a7489d7d80810186e5b414bbeb36a3258d073fd696cc92dad40e50", + "benchmarks/audit_native_learning_signal.py": "48dda7c53d488d826e6ee19dfa8dff4342c6f68c7b104109ba02f9ea33930fbd", + "tests/test_native_output_audit.py": "07eed856325720541eb67842fea529c6decf7fb9f86932e95d85035e4b24515a", + "tests/plugins/test_native_heldout_training.py": "d18dca50a47aaa4a7bd49d644e8b74a4651225a79e23a3935bd833f4ff54f738", + "tests/plugins/test_rltt_online_cycle.py": "d2e36ca16f5fed6d229612aa42da0c97cfc53147f9936b89e5c614814190d893", + "tests/plugins/test_looped_grpo.py": "51af0f220b21331b745a0a3fdd21e403dec31cc8053c5f1ac41e9839b4479610", + "tests/test_native_learning_signal_audit.py": "60674e58a5a6ab1e42c8e080d02ae2fc255baa73e5d5ec6137b7d70b0eba505c", + "tests/test_native_runtime_audit.py": "583de0496f5b3424c617dd7238f7c1500da68a4864fa400d9548ac207a0da15f", + "vime/rollout/native_eval.py": "06a7aab463bd888f4d7946544f8f390d1d462504fe88120305e0fa5f4ca4a363", + "vime/rollout/vllm_rlt_rollout.py": "aa18f8806f6bfa0a894b3b0f67ecad0e669f7695351309e6f2f4e5b55ddbbeee", + "docs/native_output_recovery.md": "d3e1df1441a0e87ffdd5bfd128b61d142fb67f06989f4522cc538d42e26e9429" + }, + "artifact_sha256": { + "audit_native_response_tokenizer.py": "0216710e96363e0c9d32f83bf53701e4acae71f37906b2c12cd9de529f79d321", + "native-output-final.log": "2fd155bf8c51f66251af04e218270ec383a6db962e63500495ad0411bb25f273", + "native-output-final.xml": "f5c4a9f88986fe8a674c9a346fbc7d5e32cd8e94c15cb1eb92e4b25a2654b7a0", + "native-output-initial.log": "d4867a66fdc061af434e11cb92ec551223f1190a2ac581eced1b876361eb022e", + "native-output-initial.xml": "66b8a1636dd56ea3df2e3f935f147d5371fdc91ddd1912a00b301caeaaf9af5f", + "native-output-tiny.log": "3352127eebc7b499ccfeb03af616890924ee0f9bb8a97cd9e92117067a0bd46f", + "native-output-tiny.xml": "f74f3d826fa947e9c34f7815a9e81aac8dfceae8a4954a74c5bedf68bacbda5e", + "native-output-tokenizer-source.json": "bdd16bb7077b9548dc9f0a690b41ef6e439072331980413bcb289942f52c1542", + "native-output-tokenizer-v1.json": "812e0cfa18af358ff9ca1e490bbb1c038bca1fdf09b3d3f9454069b5ceedcb90", + "native-output-tokenizer-v1.log": "c17bfecb66747c0e4a67ee13d6490400fa03dcf682d7545c80d1297d5cb38514", + "native-output-tokenizer.json": "6ce20866b2fc7dd5f0b0f3f3d4f0cb485c9a73ff0d0651d62fc39c598fe591bd", + "native-output-tokenizer.log": "c17bfecb66747c0e4a67ee13d6490400fa03dcf682d7545c80d1297d5cb38514", + "ouro-thinking-model-manifest.json": "22b0ab9886d283181acb6e51a4dbd19420be8c2da4474b653a042d2bb2e36081", + "resident_pytest.py": "2af5ce445da14f656c71e8d4817dcf85cd57402a77f50f612898c47f52f4d4f4", + "validation.json": "ef6cbaeb1f4b2f2ebb090cec90d689c25b7f4ca26dc5129cc6305dd1e12c9583" + } +} diff --git a/benchmarks/results/native-output-recovery/native-output-final.log b/benchmarks/results/native-output-recovery/native-output-final.log new file mode 100644 index 000000000..12602c688 --- /dev/null +++ b/benchmarks/results/native-output-recovery/native-output-final.log @@ -0,0 +1,244 @@ +torch=2.13.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/__init__.py +setuptools=84.0.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/setuptools/__init__.py +============================= test session starts ============================== +platform darwin -- Python 3.12.14, pytest-9.1.1, pluggy-1.6.0 +rootdir: /Users/0z5a/Documents/infra/flashrlt-20261005/vime +configfile: pyproject.toml +plugins: platformdirs-4.12.2, anyio-4.15.1 +collected 245 items + +tests/test_native_output_audit.py .................... [ 8%] +tests/plugins/test_native_heldout_training.py ... [ 9%] +tests/test_native_eval_schedule.py ..... [ 11%] +tests/test_native_runtime_identity.py ............ [ 16%] +tests/test_native_runtime_audit.py ............. [ 21%] +tests/test_native_runtime_mcore.py ... [ 22%] +tests/test_native_checkpoint_audit.py ................... [ 30%] +tests/test_native_learning_signal_audit.py ........ [ 33%] +tests/test_native_qualification_recipe.py ....... [ 36%] +tests/test_looped_grpo_recipe.py ....................................... [ 52%] +........................................................................ [ 82%] +.......... [ 86%] +tests/rollout_backends/test_native_rlt_contract.py ..... [ 88%] +tests/rollout_backends/test_native_colocation.py ............ [ 93%] +tests/rollout_backends/test_native_rlt_evaluation.py ................. [100%] + +=============================== warnings summary =============================== +../../looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/jit/_script.py:365: 14 warnings + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/jit/_script.py:365: DeprecationWarning: `torch.jit.script_method` is deprecated. Please switch to `torch.compile` or `torch.export`. + warnings.warn( + +../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/distributed/fsdp/src/megatron_fsdp/mixed_precision.py:113 + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/distributed/fsdp/src/megatron_fsdp/mixed_precision.py:113: UserWarning: Transformer Engine and Apex are not installed. Falling back to local implementations of multi_tensor_applier and multi_tensor_scale + warnings.warn( + +../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/inference/contexts/__init__.py:9 + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/inference/contexts/__init__.py:9: DeprecationWarning: The following imports from `dynamic_context.py` will be removed in this file in `megatron-core` 0.14. The imports here result in a cyclic import issue that causes rotary embeddings to import from Apex rather than Transformer Engine. + warnings.warn( + +../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/__init__.py:24 + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/__init__.py:24: UserWarning: Transformer Engine and Apex are not installed. Falling back to Torch optimizers. + warnings.warn( + +../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/optimizer.py:28 + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/optimizer.py:28: UserWarning: Transformer Engine and Apex are not installed. Falling back to local implementations of multi_tensor_applier and multi_tensor_scale + warnings.warn( + +../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/clip_grads.py:29 + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/clip_grads.py:29: UserWarning: Transformer Engine and Apex are not installed. Falling back to local implementations of multi_tensor_applier, multi_tensor_l2norm, and multi_tensor_scale + warnings.warn( + +tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[ouro] +tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[nanbeige] +tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[huginn_raven] + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/transformer/transformer_config.py:1734: UserWarning: full scope is deprecated. Use empty cuda_graph_scope to capture the whole layer. + warnings.warn( + +tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[ouro] + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/models/backends.py:21: UserWarning: Apex is not installed. Falling back to Torch Norm + warnings.warn("Apex is not installed. Falling back to Torch Norm") + +tests/test_native_checkpoint_audit.py: 16 warnings + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/distributed/checkpoint/utils.py:485: UserWarning: torch.distributed is disabled, unavailable or uninitialized, assuming the intent is to save in a single process. + return func(*args, **kwargs) + +tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[model] + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/distributed/checkpoint/state_dict_saver.py:472: UserWarning: Detected an existing checkpoint in /private/var/folders/12/3pb2615n5wddcr6spjcz8_pw0000gn/T/pytest-of-0z5a/pytest-310/test_rejects_corrupted_state_e0/right/iter_0000002, overwriting since self.overwrite=True. Past version 2.5 of PyTorch, `overwrite` will default to False. Set this variable to True to maintain this functionality or False to raise when an existing checkpoint is found. + local_plan = storage_writer.prepare_local_plan(local_plan) + +tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[moment] + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/distributed/checkpoint/state_dict_saver.py:472: UserWarning: Detected an existing checkpoint in /private/var/folders/12/3pb2615n5wddcr6spjcz8_pw0000gn/T/pytest-of-0z5a/pytest-310/test_rejects_corrupted_state_e1/right/iter_0000002, overwriting since self.overwrite=True. Past version 2.5 of PyTorch, `overwrite` will default to False. Set this variable to True to maintain this functionality or False to raise when an existing checkpoint is found. + local_plan = storage_writer.prepare_local_plan(local_plan) + +tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[rng] + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/distributed/checkpoint/state_dict_saver.py:472: UserWarning: Detected an existing checkpoint in /private/var/folders/12/3pb2615n5wddcr6spjcz8_pw0000gn/T/pytest-of-0z5a/pytest-310/test_rejects_corrupted_state_e2/right/iter_0000002, overwriting since self.overwrite=True. Past version 2.5 of PyTorch, `overwrite` will default to False. Set this variable to True to maintain this functionality or False to raise when an existing checkpoint is found. + local_plan = storage_writer.prepare_local_plan(local_plan) + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +- generated xml file: /Users/0z5a/Documents/infra/flashrlt-20261005/evidence/native-output-final.xml - +============================== slowest durations =============================== +2.66s call tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[ouro] +0.89s call tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[huginn_raven] +0.79s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[nonfinite] +0.60s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[publication] +0.50s call tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[nanbeige] +0.49s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_round] +0.48s call tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[rltt] +0.48s call tests/test_native_output_audit.py::test_identical_outputs_with_zero_learning_signal_do_not_qualify +0.45s call tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[grpo] +0.38s call tests/test_native_checkpoint_audit.py::test_combined_cli_reads_actual_state_and_both_raw_signal_runs[None] +0.36s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[publication] +0.36s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_round] +0.36s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[version] +0.35s setup tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[grpo] +0.35s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_tensor] +0.34s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_text] +0.34s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[nonfinite] +0.33s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[gradient] +0.33s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_tensor] +0.33s call tests/test_native_learning_signal_audit.py::test_rejects_mismatched_evidence[reward] +0.32s setup tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[rltt] +0.32s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[stale_final] +0.32s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_row] +0.31s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[changed_output] +0.31s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[seed] +0.30s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[reordered_id] +0.30s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[decoded_text] +0.30s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[prefix] +0.29s call tests/test_native_learning_signal_audit.py::test_rejects_mismatched_evidence[prefix] +0.29s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[version] +0.28s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[epoch] +0.28s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_text] +0.28s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[seed] +0.27s call tests/test_native_output_audit.py::test_predeclared_score_tolerance_reports_small_finite_difference +0.27s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[eos] +0.26s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[stale_final] +0.25s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[prefix] +0.25s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[gradient] +0.24s call tests/test_native_checkpoint_audit.py::test_combined_cli_reads_actual_state_and_both_raw_signal_runs[counters] +0.23s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_row] +0.22s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[eos] +0.22s setup tests/test_native_output_audit.py::test_identical_outputs_with_zero_learning_signal_do_not_qualify +0.20s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[decoded_text] +0.20s call tests/test_native_runtime_identity.py::test_reports_process_and_loaded_bytes_without_copying_model_state +0.20s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[reordered_id] +0.19s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[epoch] +0.19s setup tests/test_native_output_audit.py::test_predeclared_score_tolerance_reports_small_finite_difference +0.18s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[changed_output] +0.16s call tests/test_native_checkpoint_audit.py::test_combined_cli_reads_actual_state_and_both_raw_signal_runs[optimizer_mode] +0.13s call tests/test_native_learning_signal_audit.py::test_signal_gate_never_claims_optimizer_resume_or_convergence[grpo] +0.13s call tests/test_native_learning_signal_audit.py::test_rejects_mismatched_evidence[gradient] +0.13s call tests/test_native_learning_signal_audit.py::test_signal_gate_never_claims_optimizer_resume_or_convergence[rltt] +0.12s call tests/test_native_learning_signal_audit.py::test_nonzero_gradient_and_new_versions_alone_do_not_pass +0.09s call tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[optimizer_step] +0.08s call tests/rollout_backends/test_native_rlt_contract.py::test_http_client_concurrency_matches_backend[vllm] +0.07s call tests/rollout_backends/test_native_rlt_evaluation.py::test_complete_datasets_fixed_seeds_and_unchanged_training_state[ouro] +0.06s call tests/test_native_runtime_identity.py::test_native_init_records_real_model_through_explicit_cpu_transport[True] +0.06s call tests/rollout_backends/test_native_rlt_evaluation.py::test_complete_datasets_fixed_seeds_and_unchanged_training_state[huginn] +0.05s call tests/test_native_learning_signal_audit.py::test_rejects_mismatched_evidence[reference] +0.05s call tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[iteration] +0.04s call tests/test_native_checkpoint_audit.py::test_actual_adamw_distinguishes_new_signal_from_decay_and_old_momentum[0.001-learning-expected0] +0.04s call tests/test_native_learning_signal_audit.py::test_rejects_mismatched_evidence[index] +0.04s call tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[rng] +0.04s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-dppo-True-nanbeige] +0.03s call tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[moment] +0.03s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[environment] +0.03s call tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[model] +0.03s call tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[scheduler] +0.03s call tests/rollout_backends/test_native_rlt_evaluation.py::test_complete_datasets_fixed_seeds_and_unchanged_training_state[nanbeige] +0.03s call tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[resume-grpo] +0.03s call tests/rollout_backends/test_native_rlt_contract.py::test_publication_cohort_and_serialization +0.03s call tests/test_native_checkpoint_audit.py::test_actual_adamw_distinguishes_new_signal_from_decay_and_old_momentum[1e-06-learning-expected0] +0.02s call tests/test_native_checkpoint_audit.py::test_actual_adamw_distinguishes_new_signal_from_decay_and_old_momentum[1e-06-momentum-expected2] +0.02s call tests/test_native_checkpoint_audit.py::test_actual_adamw_distinguishes_new_signal_from_decay_and_old_momentum[0.001-momentum-expected2] +0.02s call tests/test_native_checkpoint_audit.py::test_actual_adamw_distinguishes_new_signal_from_decay_and_old_momentum[0.001-decay-expected1] +0.02s call tests/rollout_backends/test_native_rlt_contract.py::test_huginn_aliases_static_buffer_and_noise_profile +0.02s call tests/test_native_checkpoint_audit.py::test_actual_adamw_distinguishes_new_signal_from_decay_and_old_momentum[1e-06-decay-expected1] +0.02s setup tests/rollout_backends/test_native_rlt_contract.py::test_publication_cohort_and_serialization +0.02s call tests/test_native_checkpoint_audit.py::test_missing_adam_and_rng_do_not_qualify +0.02s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[revision] +0.01s call tests/rollout_backends/test_native_rlt_contract.py::test_incomplete_publication_cannot_resume_or_reuse_old_manifest +0.01s call tests/rollout_backends/test_native_rlt_evaluation.py::test_policy_publication_between_batches_invalidates_evaluation +0.01s setup tests/rollout_backends/test_native_rlt_evaluation.py::test_unsupported_eval_settings_reject_before_generation[min_new_tokens-1] +0.01s setup tests/test_native_checkpoint_audit.py::test_rejects_corrupted_state_even_with_reusable_fingerprints[scheduler] +0.01s call tests/rollout_backends/test_native_rlt_evaluation.py::test_sampling_and_chat_overrides_are_used +0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[job] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-rltt-True-nanbeige] +0.01s call tests/rollout_backends/test_native_rlt_evaluation.py::test_reward_key_and_metadata_override +0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[actor] +0.01s setup tests/test_native_runtime_audit.py::test_cli_binds_all_six_synthetic_reports_and_records_input_hashes +0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[epoch] +0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[source] +0.01s call tests/test_native_runtime_identity.py::test_actual_learner_function_records_after_load_without_importing_full_framework[vllm-True] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-rltt-False-nanbeige] +0.01s call tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[continuous-grpo] +0.01s teardown tests/rollout_backends/test_native_rlt_contract.py::test_publication_cohort_and_serialization +0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[worker] +0.01s call tests/rollout_backends/test_native_rlt_contract.py::test_http_client_concurrency_matches_backend[vllm-rlt] +0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[optimizer] +0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[duplicate] +0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[iteration] +0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[process] +0.01s teardown tests/test_native_learning_signal_audit.py::test_rejects_mismatched_evidence[gradient] +0.01s call tests/test_native_runtime_identity.py::test_actual_learner_function_records_after_load_without_importing_full_framework[vllm-rlt-True] +0.01s setup tests/test_native_qualification_recipe.py::test_changed_data_and_new_cluster_are_rejected +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-ppo-False-ouro] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-grpo-True-huginn_raven] +0.01s call tests/test_native_runtime_audit.py::test_cli_binds_all_six_synthetic_reports_and_records_input_hashes +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-rltt-True-ouro] +0.01s setup tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[unfinished] +0.01s call tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[resume-rltt] +0.01s call tests/test_native_runtime_identity.py::test_actual_learner_function_records_after_load_without_importing_full_framework[vllm-rlt-False] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-flow-dppo-True-ouro] +0.01s setup tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[resume-rltt] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-rltt-False-ouro] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-grpo-True-huginn_raven] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-grpo-False-nanbeige] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-ppo-True-ouro] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-grpo-False-ouro] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-rltt-True-ouro] +0.01s call tests/rollout_backends/test_native_rlt_evaluation.py::test_reordered_or_missing_heldout_samples_are_rejected +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-dppo-True-huginn_raven] +0.01s call tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[split-grpo] +0.01s setup tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[continuous-grpo] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-rltt-False-huginn_raven] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[True-None-ppo-False-ouro] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-rltt-True-huginn_raven] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-rltt-True-huginn_raven] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-ppo-True-huginn_raven] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-dppo-True-ouro] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-rltt-False-huginn_raven] +0.01s call tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[iteration] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-flow-dppo-True-nanbeige] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-grpo-False-ouro] +0.01s call tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[split-rltt] +0.01s setup tests/rollout_backends/test_native_rlt_evaluation.py::test_complete_datasets_fixed_seeds_and_unchanged_training_state[ouro] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-rltt-True-nanbeige] +0.01s setup tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[continuous-rltt] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-grpo-False-huginn_raven] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-grpo-False-nanbeige] +0.01s setup tests/rollout_backends/test_native_rlt_contract.py::test_huginn_aliases_static_buffer_and_noise_profile +0.01s call tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[continuous-rltt] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-dppo-True-huginn_raven] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[True-None-ppo-True-nanbeige] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-grpo-True-ouro] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-grpo-True-nanbeige] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-dppo-True-ouro] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-ppo-True-ouro] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-ppo-True-huginn_raven] +0.01s setup tests/test_native_qualification_recipe.py::test_actual_recipe_receives_optimizer_data_eval_and_resume[resume-grpo] +0.01s setup tests/rollout_backends/test_native_rlt_contract.py::test_incomplete_publication_cannot_resume_or_reuse_old_manifest +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-dppo-False-huginn_raven] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-ppo-False-nanbeige] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[True-3-dppo-False-nanbeige] +0.01s call tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[worker] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[True-None-flow-dppo-True-ouro] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-grpo-True-ouro] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-dppo-True-nanbeige] +0.01s call tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[revision] +0.01s call tests/test_native_runtime_audit.py::test_rejects_stale_or_mismatched_records[epoch] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-3-flow-dppo-False-huginn_raven] +0.01s call tests/test_looped_grpo_recipe.py::test_recipe_roles_groups_precision_and_resume[False-None-dppo-False-ouro] + +(573 durations < 0.005s hidden. Use -vv to show these durations.) +====================== 245 passed, 42 warnings in 34.25s ======================= diff --git a/benchmarks/results/native-output-recovery/native-output-final.xml b/benchmarks/results/native-output-recovery/native-output-final.xml new file mode 100644 index 000000000..e1b4553f7 --- /dev/null +++ b/benchmarks/results/native-output-recovery/native-output-final.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/benchmarks/results/native-output-recovery/native-output-initial.log b/benchmarks/results/native-output-recovery/native-output-initial.log new file mode 100644 index 000000000..7fbadb3a8 --- /dev/null +++ b/benchmarks/results/native-output-recovery/native-output-initial.log @@ -0,0 +1,52 @@ +torch=2.13.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/__init__.py +setuptools=84.0.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/setuptools/__init__.py +============================= test session starts ============================== +platform darwin -- Python 3.12.14, pytest-9.1.1, pluggy-1.6.0 +rootdir: /Users/0z5a/Documents/infra/flashrlt-20261005/vime +configfile: pyproject.toml +plugins: platformdirs-4.12.2, anyio-4.15.1 +collected 18 items + +tests/test_native_output_audit.py .................. [100%] + +- generated xml file: /Users/0z5a/Documents/infra/flashrlt-20261005/evidence/native-output-initial.xml - +============================== slowest durations =============================== +0.25s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[changed_output] +0.23s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[epoch] +0.23s call tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[grpo] +0.22s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[stale_final] +0.22s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_tensor] +0.22s call tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[rltt] +0.21s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[nonfinite] +0.20s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_row] +0.19s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_tensor] +0.19s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[eos] +0.18s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[gradient] +0.18s setup tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[grpo] +0.17s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[gradient] +0.17s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_round] +0.17s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[changed_output] +0.17s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[nonfinite] +0.17s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[publication] +0.17s setup tests/test_native_output_audit.py::test_full_cli_reads_all_saved_outputs_with_real_tokenizer[rltt] +0.16s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[eos] +0.16s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[stale_final] +0.16s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_text] +0.16s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_row] +0.16s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[missing_round] +0.15s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[publication] +0.15s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[training_text] +0.15s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[prefix] +0.15s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[decoded_text] +0.15s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[decoded_text] +0.15s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[seed] +0.15s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[seed] +0.15s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[version] +0.14s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[reordered_id] +0.14s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[prefix] +0.14s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[reordered_id] +0.14s setup tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[version] +0.14s call tests/test_native_output_audit.py::test_rejects_incomplete_or_changed_outputs[epoch] + +(18 durations < 0.005s hidden. Use -vv to show these durations.) +============================= 18 passed in 10.66s ============================== diff --git a/benchmarks/results/native-output-recovery/native-output-initial.xml b/benchmarks/results/native-output-recovery/native-output-initial.xml new file mode 100644 index 000000000..6c0278ec9 --- /dev/null +++ b/benchmarks/results/native-output-recovery/native-output-initial.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/benchmarks/results/native-output-recovery/native-output-tiny.log b/benchmarks/results/native-output-recovery/native-output-tiny.log new file mode 100644 index 000000000..762fcb7aa --- /dev/null +++ b/benchmarks/results/native-output-recovery/native-output-tiny.log @@ -0,0 +1,55 @@ +torch=2.13.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/__init__.py +setuptools=84.0.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/setuptools/__init__.py +============================= test session starts ============================== +platform darwin -- Python 3.12.14, pytest-9.1.1, pluggy-1.6.0 +rootdir: /Users/0z5a/Documents/infra/flashrlt-20261005/vime +configfile: pyproject.toml +plugins: platformdirs-4.12.2, anyio-4.15.1 +collected 3 items + +tests/plugins/test_native_heldout_training.py ... [100%] + +=============================== warnings summary =============================== +../../looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/jit/_script.py:365: 14 warnings + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/jit/_script.py:365: DeprecationWarning: `torch.jit.script_method` is deprecated. Please switch to `torch.compile` or `torch.export`. + warnings.warn( + +../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/distributed/fsdp/src/megatron_fsdp/mixed_precision.py:113 + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/distributed/fsdp/src/megatron_fsdp/mixed_precision.py:113: UserWarning: Transformer Engine and Apex are not installed. Falling back to local implementations of multi_tensor_applier and multi_tensor_scale + warnings.warn( + +../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/inference/contexts/__init__.py:9 + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/inference/contexts/__init__.py:9: DeprecationWarning: The following imports from `dynamic_context.py` will be removed in this file in `megatron-core` 0.14. The imports here result in a cyclic import issue that causes rotary embeddings to import from Apex rather than Transformer Engine. + warnings.warn( + +../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/__init__.py:24 + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/__init__.py:24: UserWarning: Transformer Engine and Apex are not installed. Falling back to Torch optimizers. + warnings.warn( + +../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/optimizer.py:28 + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/optimizer.py:28: UserWarning: Transformer Engine and Apex are not installed. Falling back to local implementations of multi_tensor_applier and multi_tensor_scale + warnings.warn( + +../../looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/clip_grads.py:29 + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/optimizer/clip_grads.py:29: UserWarning: Transformer Engine and Apex are not installed. Falling back to local implementations of multi_tensor_applier, multi_tensor_l2norm, and multi_tensor_scale + warnings.warn( + +tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[ouro] +tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[nanbeige] +tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[huginn_raven] + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/transformer/transformer_config.py:1734: UserWarning: full scope is deprecated. Use empty cuda_graph_scope to capture the whole layer. + warnings.warn( + +tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[ouro] + /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron/megatron/core/models/backends.py:21: UserWarning: Apex is not installed. Falling back to Torch Norm + warnings.warn("Apex is not installed. Falling back to Torch Norm") + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +- generated xml file: /Users/0z5a/Documents/infra/flashrlt-20261005/evidence/native-output-tiny.xml - +============================== slowest durations =============================== +0.55s call tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[huginn_raven] +0.44s call tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[ouro] +0.26s call tests/plugins/test_native_heldout_training.py::test_evaluation_preserves_updates_and_fresh_resume[nanbeige] + +(6 durations < 0.005s hidden. Use -vv to show these durations.) +======================== 3 passed, 23 warnings in 7.18s ======================== diff --git a/benchmarks/results/native-output-recovery/native-output-tiny.xml b/benchmarks/results/native-output-recovery/native-output-tiny.xml new file mode 100644 index 000000000..061b6715d --- /dev/null +++ b/benchmarks/results/native-output-recovery/native-output-tiny.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/benchmarks/results/native-output-recovery/native-output-tokenizer-source.json b/benchmarks/results/native-output-recovery/native-output-tokenizer-source.json new file mode 100644 index 000000000..2ea7515ae --- /dev/null +++ b/benchmarks/results/native-output-recovery/native-output-tokenizer-source.json @@ -0,0 +1,13 @@ +{ + "revision": "3aaa2224253a92ca45cf2e3d427c360e1ef9c93d", + "source_manifest_sha256": "22b0ab9886d283181acb6e51a4dbd19420be8c2da4474b653a042d2bb2e36081", + "verified_local_sha256": { + "config.json": "44e42ec2ed97f49f20f87985688b6e1be9dd61bbfe9f8a349daac192126e2c55", + "merges.txt": "0b54e8aa4e53d5383e2e4bc635a56b43f9647f7b13832d5d9ecd8f82dac4f510", + "special_tokens_map.json": "688ac94df221b18a4d2d4579dfa3c4f0fd5ca3e394da46cd0a317fb5d57d4685", + "tokenizer.json": "fcb808fe5e7642f5299be28aea07fc7f6d4f4364c3ac5e408e15a772cbc8fa8d", + "tokenizer_config.json": "e41eafc6bf7269d6f90f2531124949073a57965f5f0765238a744c1c528e2448", + "vocab.json": "7b9de3f47796abf8d00ab96be299fea0dc9afdf1827f34e7e0b9fb44593efe5c" + }, + "scope": "six retained local configuration/tokenizer files; no weight file or remote node read" +} diff --git a/benchmarks/results/native-output-recovery/native-output-tokenizer-v1.json b/benchmarks/results/native-output-recovery/native-output-tokenizer-v1.json new file mode 100644 index 000000000..6e3b14e76 --- /dev/null +++ b/benchmarks/results/native-output-recovery/native-output-tokenizer-v1.json @@ -0,0 +1,300 @@ +{ + "scope": "answer-replay controls from known labels with invented scores; no model generation or training", + "qualification_sha256": "d7bf3edcd0a05ee25b93bf7abaf1f739a4f8da4a769ac5fc00cf87a423e67f9c", + "eos_token_id": 2, + "tokenizer_class": "GPT2TokenizerFast", + "trust_remote_code": false, + "local_files_only": true, + "rows": [ + { + "split": "train", + "id": "number_theory/train/483", + "expected_reward": 1, + "response_tokens": 7, + "token_sha256": "fc1f7be12dbfa224a035deacb237385eaa186254f1bb5c0ec09d88b16c040fda" + }, + { + "split": "train", + "id": "number_theory/train/483", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "prealgebra/train/799", + "expected_reward": 1, + "response_tokens": 8, + "token_sha256": "f6685e2e3e68191bf764c6522e00cbbb3c4a0418273b0849026cbf249914abb6" + }, + { + "split": "train", + "id": "prealgebra/train/799", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "geometry/train/445", + "expected_reward": 1, + "response_tokens": 9, + "token_sha256": "095e4e4bd915611b027de271873d6290329f8bf905f2df91e996ea6403ad27ad" + }, + { + "split": "train", + "id": "geometry/train/445", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "algebra/train/1647", + "expected_reward": 1, + "response_tokens": 9, + "token_sha256": "7cf3be7279e406330d89d2f9fe549bff02019fb3bb5c15646d836b4f06ae2e41" + }, + { + "split": "train", + "id": "algebra/train/1647", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "prealgebra/train/161", + "expected_reward": 1, + "response_tokens": 8, + "token_sha256": "fa315fb7666d9cb89a5bbfb70b23326f9b9709281d35cf44749156c70b39319a" + }, + { + "split": "train", + "id": "prealgebra/train/161", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "precalculus/train/467", + "expected_reward": 1, + "response_tokens": 17, + "token_sha256": "2549be62b1653f6ac90e1c0342a29db92860aeb858eb6b5dc5b3dc582165f0cc" + }, + { + "split": "train", + "id": "precalculus/train/467", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "algebra/train/963", + "expected_reward": 1, + "response_tokens": 11, + "token_sha256": "24ab47bd34a444b3d3a2aab5f325ee0eccde32e0ab679f07ccf0412981f6b665" + }, + { + "split": "train", + "id": "algebra/train/963", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "algebra/train/1201", + "expected_reward": 1, + "response_tokens": 8, + "token_sha256": "29555376478bc957b03657f950165fc0bbf29cd570d498a735e9fa70185e6f21" + }, + { + "split": "train", + "id": "algebra/train/1201", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "geometry/train/264", + "expected_reward": 1, + "response_tokens": 8, + "token_sha256": "b0f6ebc703631ae26a44d7e5a44e1ea79edd2d61067318fcc82ce66b186a1154" + }, + { + "split": "train", + "id": "geometry/train/264", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "geometry/train/682", + "expected_reward": 1, + "response_tokens": 7, + "token_sha256": "4f1aec4a17fc68722817f90a976ab9394ae6921953a978df7447444109f7c49c" + }, + { + "split": "train", + "id": "geometry/train/682", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "prealgebra/train/304", + "expected_reward": 1, + "response_tokens": 9, + "token_sha256": "84cdf72152c7a477452a56afb50422429510a9f3fa9c89422c9f003262662c55" + }, + { + "split": "train", + "id": "prealgebra/train/304", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "geometry/train/496", + "expected_reward": 1, + "response_tokens": 9, + "token_sha256": "109b0ae07355941d124dcdc04519aaae711021b08c1cbdaa7e9659fda9978467" + }, + { + "split": "train", + "id": "geometry/train/496", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "precalculus/test/309", + "expected_reward": 1, + "response_tokens": 11, + "token_sha256": "2bf959d161f53afd06216fd96013e723b8121129c3b88d40748b9824637ed1f6" + }, + { + "split": "development", + "id": "precalculus/test/309", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "algebra/test/348", + "expected_reward": 1, + "response_tokens": 7, + "token_sha256": "3f39f147dc7f937eda7abcc49449cb2fdaadfd511e12a38b0f17dd32e4dbcbc3" + }, + { + "split": "development", + "id": "algebra/test/348", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "precalculus/test/72", + "expected_reward": 1, + "response_tokens": 13, + "token_sha256": "5b93508ebc8426814ba885a3731c087995b3d66a7afea226a119870416d4b5c3" + }, + { + "split": "development", + "id": "precalculus/test/72", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "intermediate_algebra/test/267", + "expected_reward": 1, + "response_tokens": 13, + "token_sha256": "bc42ed00afc072fa9957397815f2c935e7bab86131ac675ee554da6444c8bdbd" + }, + { + "split": "development", + "id": "intermediate_algebra/test/267", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "intermediate_algebra/test/285", + "expected_reward": 1, + "response_tokens": 11, + "token_sha256": "9a78c195a1a46e853ffb6106c66ec595bdc0a1dd799372af509699f3df40295d" + }, + { + "split": "development", + "id": "intermediate_algebra/test/285", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "geometry/test/284", + "expected_reward": 1, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "geometry/test/284", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "7acedb2271a5fef175b49f5e86e0546ba44fcbe6dfef254139e2d58f80413e15" + }, + { + "split": "development", + "id": "prealgebra/test/822", + "expected_reward": 1, + "response_tokens": 11, + "token_sha256": "286ce91e738b4aacb334049b5cd9cc221a374a1865f120b31561f031843e12f3" + }, + { + "split": "development", + "id": "prealgebra/test/822", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "prealgebra/test/748", + "expected_reward": 1, + "response_tokens": 9, + "token_sha256": "d766509ed8a47817b152b1b1a9558a9b8dac03859e17be0a35adb58a96fa0ebf" + }, + { + "split": "development", + "id": "prealgebra/test/748", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + } + ], + "cuda_initialized": false, + "model_generation": "NOT_RUN", + "source_sha256": "d8c99bfc902c5b24973d0b00b03d5d8f8b7fab98cb5ce77e0827fb1cac666a92", + "tokenizer_sha256": { + "tokenizer.json": "fcb808fe5e7642f5299be28aea07fc7f6d4f4364c3ac5e408e15a772cbc8fa8d", + "tokenizer_config.json": "e41eafc6bf7269d6f90f2531124949073a57965f5f0765238a744c1c528e2448", + "special_tokens_map.json": "688ac94df221b18a4d2d4579dfa3c4f0fd5ca3e394da46cd0a317fb5d57d4685", + "vocab.json": "7b9de3f47796abf8d00ab96be299fea0dc9afdf1827f34e7e0b9fb44593efe5c", + "merges.txt": "0b54e8aa4e53d5383e2e4bc635a56b43f9647f7b13832d5d9ecd8f82dac4f510" + } +} diff --git a/benchmarks/results/native-output-recovery/native-output-tokenizer-v1.log b/benchmarks/results/native-output-recovery/native-output-tokenizer-v1.log new file mode 100644 index 000000000..a59ddbfe8 --- /dev/null +++ b/benchmarks/results/native-output-recovery/native-output-tokenizer-v1.log @@ -0,0 +1,3 @@ +torch=2.13.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/__init__.py +setuptools=84.0.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/setuptools/__init__.py +{"answer_replay_controls": 40, "eos_token_id": 2, "model_generation": "NOT_RUN", "cuda_initialized": false} diff --git a/benchmarks/results/native-output-recovery/native-output-tokenizer.json b/benchmarks/results/native-output-recovery/native-output-tokenizer.json new file mode 100644 index 000000000..af7fa02a6 --- /dev/null +++ b/benchmarks/results/native-output-recovery/native-output-tokenizer.json @@ -0,0 +1,300 @@ +{ + "scope": "answer-replay controls from known labels with invented scores; no model generation or training", + "qualification_sha256": "d7bf3edcd0a05ee25b93bf7abaf1f739a4f8da4a769ac5fc00cf87a423e67f9c", + "eos_token_id": 2, + "tokenizer_class": "GPT2TokenizerFast", + "trust_remote_code": false, + "local_files_only": true, + "rows": [ + { + "split": "train", + "id": "number_theory/train/483", + "expected_reward": 1, + "response_tokens": 7, + "token_sha256": "fc1f7be12dbfa224a035deacb237385eaa186254f1bb5c0ec09d88b16c040fda" + }, + { + "split": "train", + "id": "number_theory/train/483", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "prealgebra/train/799", + "expected_reward": 1, + "response_tokens": 8, + "token_sha256": "f6685e2e3e68191bf764c6522e00cbbb3c4a0418273b0849026cbf249914abb6" + }, + { + "split": "train", + "id": "prealgebra/train/799", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "geometry/train/445", + "expected_reward": 1, + "response_tokens": 9, + "token_sha256": "095e4e4bd915611b027de271873d6290329f8bf905f2df91e996ea6403ad27ad" + }, + { + "split": "train", + "id": "geometry/train/445", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "algebra/train/1647", + "expected_reward": 1, + "response_tokens": 9, + "token_sha256": "7cf3be7279e406330d89d2f9fe549bff02019fb3bb5c15646d836b4f06ae2e41" + }, + { + "split": "train", + "id": "algebra/train/1647", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "prealgebra/train/161", + "expected_reward": 1, + "response_tokens": 8, + "token_sha256": "fa315fb7666d9cb89a5bbfb70b23326f9b9709281d35cf44749156c70b39319a" + }, + { + "split": "train", + "id": "prealgebra/train/161", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "precalculus/train/467", + "expected_reward": 1, + "response_tokens": 17, + "token_sha256": "2549be62b1653f6ac90e1c0342a29db92860aeb858eb6b5dc5b3dc582165f0cc" + }, + { + "split": "train", + "id": "precalculus/train/467", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "algebra/train/963", + "expected_reward": 1, + "response_tokens": 11, + "token_sha256": "24ab47bd34a444b3d3a2aab5f325ee0eccde32e0ab679f07ccf0412981f6b665" + }, + { + "split": "train", + "id": "algebra/train/963", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "algebra/train/1201", + "expected_reward": 1, + "response_tokens": 8, + "token_sha256": "29555376478bc957b03657f950165fc0bbf29cd570d498a735e9fa70185e6f21" + }, + { + "split": "train", + "id": "algebra/train/1201", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "geometry/train/264", + "expected_reward": 1, + "response_tokens": 8, + "token_sha256": "b0f6ebc703631ae26a44d7e5a44e1ea79edd2d61067318fcc82ce66b186a1154" + }, + { + "split": "train", + "id": "geometry/train/264", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "geometry/train/682", + "expected_reward": 1, + "response_tokens": 7, + "token_sha256": "4f1aec4a17fc68722817f90a976ab9394ae6921953a978df7447444109f7c49c" + }, + { + "split": "train", + "id": "geometry/train/682", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "prealgebra/train/304", + "expected_reward": 1, + "response_tokens": 9, + "token_sha256": "84cdf72152c7a477452a56afb50422429510a9f3fa9c89422c9f003262662c55" + }, + { + "split": "train", + "id": "prealgebra/train/304", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "train", + "id": "geometry/train/496", + "expected_reward": 1, + "response_tokens": 9, + "token_sha256": "109b0ae07355941d124dcdc04519aaae711021b08c1cbdaa7e9659fda9978467" + }, + { + "split": "train", + "id": "geometry/train/496", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "precalculus/test/309", + "expected_reward": 1, + "response_tokens": 11, + "token_sha256": "2bf959d161f53afd06216fd96013e723b8121129c3b88d40748b9824637ed1f6" + }, + { + "split": "development", + "id": "precalculus/test/309", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "algebra/test/348", + "expected_reward": 1, + "response_tokens": 7, + "token_sha256": "3f39f147dc7f937eda7abcc49449cb2fdaadfd511e12a38b0f17dd32e4dbcbc3" + }, + { + "split": "development", + "id": "algebra/test/348", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "precalculus/test/72", + "expected_reward": 1, + "response_tokens": 13, + "token_sha256": "5b93508ebc8426814ba885a3731c087995b3d66a7afea226a119870416d4b5c3" + }, + { + "split": "development", + "id": "precalculus/test/72", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "intermediate_algebra/test/267", + "expected_reward": 1, + "response_tokens": 13, + "token_sha256": "bc42ed00afc072fa9957397815f2c935e7bab86131ac675ee554da6444c8bdbd" + }, + { + "split": "development", + "id": "intermediate_algebra/test/267", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "intermediate_algebra/test/285", + "expected_reward": 1, + "response_tokens": 11, + "token_sha256": "9a78c195a1a46e853ffb6106c66ec595bdc0a1dd799372af509699f3df40295d" + }, + { + "split": "development", + "id": "intermediate_algebra/test/285", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "geometry/test/284", + "expected_reward": 1, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "geometry/test/284", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "7acedb2271a5fef175b49f5e86e0546ba44fcbe6dfef254139e2d58f80413e15" + }, + { + "split": "development", + "id": "prealgebra/test/822", + "expected_reward": 1, + "response_tokens": 11, + "token_sha256": "286ce91e738b4aacb334049b5cd9cc221a374a1865f120b31561f031843e12f3" + }, + { + "split": "development", + "id": "prealgebra/test/822", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + }, + { + "split": "development", + "id": "prealgebra/test/748", + "expected_reward": 1, + "response_tokens": 9, + "token_sha256": "d766509ed8a47817b152b1b1a9558a9b8dac03859e17be0a35adb58a96fa0ebf" + }, + { + "split": "development", + "id": "prealgebra/test/748", + "expected_reward": 0, + "response_tokens": 7, + "token_sha256": "b8a5f65f453b6c99b4ef479445e04bf0a0ac07bb33561e9f193e88b62864fcd3" + } + ], + "cuda_initialized": false, + "model_generation": "NOT_RUN", + "source_sha256": "e55d2fa5f89a45d7afdb8fa22724f33f4fb70396830e4584957bcffbcb6fb598", + "tokenizer_sha256": { + "tokenizer.json": "fcb808fe5e7642f5299be28aea07fc7f6d4f4364c3ac5e408e15a772cbc8fa8d", + "tokenizer_config.json": "e41eafc6bf7269d6f90f2531124949073a57965f5f0765238a744c1c528e2448", + "special_tokens_map.json": "688ac94df221b18a4d2d4579dfa3c4f0fd5ca3e394da46cd0a317fb5d57d4685", + "vocab.json": "7b9de3f47796abf8d00ab96be299fea0dc9afdf1827f34e7e0b9fb44593efe5c", + "merges.txt": "0b54e8aa4e53d5383e2e4bc635a56b43f9647f7b13832d5d9ecd8f82dac4f510" + } +} diff --git a/benchmarks/results/native-output-recovery/native-output-tokenizer.log b/benchmarks/results/native-output-recovery/native-output-tokenizer.log new file mode 100644 index 000000000..a59ddbfe8 --- /dev/null +++ b/benchmarks/results/native-output-recovery/native-output-tokenizer.log @@ -0,0 +1,3 @@ +torch=2.13.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/torch/__init__.py +setuptools=84.0.0 /Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/setuptools/__init__.py +{"answer_replay_controls": 40, "eos_token_id": 2, "model_generation": "NOT_RUN", "cuda_initialized": false} diff --git a/benchmarks/results/native-output-recovery/ouro-thinking-model-manifest.json b/benchmarks/results/native-output-recovery/ouro-thinking-model-manifest.json new file mode 100644 index 000000000..96f2b6edd --- /dev/null +++ b/benchmarks/results/native-output-recovery/ouro-thinking-model-manifest.json @@ -0,0 +1,49 @@ +{ + "repo": "ByteDance/Ouro-1.4B-Thinking", + "revision": "3aaa2224253a92ca45cf2e3d427c360e1ef9c93d", + "files": [ + { + "path": "config.json", + "bytes": 1471, + "sha256": "44e42ec2ed97f49f20f87985688b6e1be9dd61bbfe9f8a349daac192126e2c55" + }, + { + "path": "merges.txt", + "bytes": 466391, + "sha256": "0b54e8aa4e53d5383e2e4bc635a56b43f9647f7b13832d5d9ecd8f82dac4f510" + }, + { + "path": "model.safetensors", + "bytes": 2869336434, + "sha256": "6730581fd366f6d1689728c61637520228385cdfc17c0b24f19aa840b00565fb" + }, + { + "path": "special_tokens_map.json", + "bytes": 965, + "sha256": "688ac94df221b18a4d2d4579dfa3c4f0fd5ca3e394da46cd0a317fb5d57d4685" + }, + { + "path": "tokenizer.json", + "bytes": 3522644, + "sha256": "fcb808fe5e7642f5299be28aea07fc7f6d4f4364c3ac5e408e15a772cbc8fa8d" + }, + { + "path": "tokenizer_config.json", + "bytes": 4392, + "sha256": "e41eafc6bf7269d6f90f2531124949073a57965f5f0765238a744c1c528e2448" + }, + { + "path": "vocab.json", + "bytes": 800656, + "sha256": "7b9de3f47796abf8d00ab96be299fea0dc9afdf1827f34e7e0b9fb44593efe5c" + } + ], + "source": "official immutable metadata and official CDN", + "task_owned_root": "/root/autodl-tmp/0z5a/flashrlt-20261005/models/ouro-1.4b-thinking", + "independent_hash_completed_utc": "2026-10-04T20:59:49Z", + "stage_exit_code": 0, + "large_weight_inode": "2304:2159281731", + "source_reader_released": true, + "cleanup_eligible": false, + "cleanup_reason": "Required experiments remain unfinished; own read-only hardlinks retained" +} diff --git a/benchmarks/results/native-output-recovery/resident_pytest.py b/benchmarks/results/native-output-recovery/resident_pytest.py new file mode 100644 index 000000000..e18b0b8e3 --- /dev/null +++ b/benchmarks/results/native-output-recovery/resident_pytest.py @@ -0,0 +1,64 @@ +"""Run existing local dependencies, failing promptly on iCloud-evicted source. + +No package is installed, replaced or stubbed. Evicted bytecode falls back to +its original source through Python's normal SourceFileLoader behavior. +""" + +import base64 +import csv +import hashlib +import importlib.machinery +import linecache +import os +import runpy +import sys + +import pytest +import torch + +original_get_data = importlib.machinery.SourceFileLoader.get_data +original_getline = linecache.getline +site = "/Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/lib/python3.12/site-packages/" +mirror = "/Users/0z5a/Documents/infra/vime-sm120-initial-20260912/.venv/lib/python3.12/site-packages/" +with open(site + "setuptools-84.0.0.dist-info/RECORD") as stream: + recorded = {row[0]: row[1] for row in csv.reader(stream)} + + +def concise_exception(kind, error, trace): + while trace is not None: + print(f"{trace.tb_frame.f_code.co_filename}:{trace.tb_lineno}", file=sys.stderr) + trace = trace.tb_next + print(f"{kind.__name__}: {error}", file=sys.stderr) + + +def resident_line(filename, lineno, module_globals=None): + if os.path.exists(filename) and os.stat(filename).st_flags & 0x40000000: + return "" + return original_getline(filename, lineno, module_globals) + + +def resident_data(loader, path): + if os.path.exists(path) and os.stat(path).st_flags & 0x40000000: + relative = path.removeprefix(site) + other = mirror + relative + if relative in recorded and path.endswith(".py") and os.path.isfile(other) and not os.stat(other).st_flags & 0x40000000: + data = original_get_data(loader, other) + digest = "sha256=" + base64.urlsafe_b64encode(hashlib.sha256(data).digest()).decode().rstrip("=") + assert digest == recorded[relative], relative + print(f"resident same-RECORD source: {other}", flush=True) + return data + raise OSError(61, "iCloud file is not resident", path) + return original_get_data(loader, path) + + +importlib.machinery.SourceFileLoader.get_data = resident_data +linecache.getline = resident_line +sys.excepthook = concise_exception +import setuptools +print(f"torch={torch.__version__} {torch.__file__}", flush=True) +print(f"setuptools={setuptools.__version__} {setuptools.__file__}", flush=True) +if sys.argv[1:2] == ["--script"]: + sys.argv = sys.argv[2:] + runpy.run_path(sys.argv[0], run_name="__main__") +else: + raise SystemExit(pytest.main(sys.argv[1:])) diff --git a/benchmarks/results/native-output-recovery/validation.json b/benchmarks/results/native-output-recovery/validation.json new file mode 100644 index 000000000..2ffb9965e --- /dev/null +++ b/benchmarks/results/native-output-recovery/validation.json @@ -0,0 +1,82 @@ +{ + "parent": "11efa7420172bcf348b28c32bbcd88cae482f94a", + "cpu_component_rlt_head": "334f243e1b7b374682e138b641ce9cb8236a9157", + "official_qualification_rlt_pin": "fd993ec5512904b68e16f4d541682c076c487b5d", + "tests": { + "name": "pytest", + "errors": "0", + "failures": "0", + "skipped": "0", + "tests": "245", + "time": "33.845", + "timestamp": "2026-10-05T15:19:16.497705+08:00", + "hostname": "192.168.10.10" + }, + "new_output_audit_cases": 20, + "expanded_existing_model_cases": 3, + "other_existing_cases": 222, + "paired_tiny_cpu_outputs": [ + { + "case": "test_evaluation_preserves_updates_and_fresh_resume[ouro]", + "samples": 8, + "max_score_error": 0.0 + }, + { + "case": "test_evaluation_preserves_updates_and_fresh_resume[nanbeige]", + "samples": 8, + "max_score_error": 0.0 + }, + { + "case": "test_evaluation_preserves_updates_and_fresh_resume[huginn_raven]", + "samples": 8, + "max_score_error": 0.0 + } + ], + "answer_replay_controls": 40, + "natural_exit": { + "29315": 0, + "90984": 0, + "18693": 0, + "22020": 0, + "22814": 0 + }, + "scope": "CPU controls; actual tiny sampling/Adam with fresh objects in one process; synthetic Ray/process records; no official model generation", + "actual_ray_cuda_e2e": "NOT_RUN", + "reward_convergence": "NOT_ESTABLISHED", + "existing_python": "/Users/0z5a/Documents/infra/looped-grpo-integration-20261003/.venv/bin/python", + "test_environment": { + "PYTHONDONTWRITEBYTECODE": "1", + "FROZENLIST_NO_EXTENSIONS": "1", + "MULTIDICT_NO_EXTENSIONS": "1", + "AIOHTTP_NO_EXTENSIONS": "1", + "YARL_NO_EXTENSIONS": "1", + "OMP_NUM_THREADS": "1", + "PYTHONPATH": ".:../rlt:tests/plugins:/Users/0z5a/Documents/infra/looped-grpo-integration-20261003/runtime/megatron" + }, + "test_files": [ + "tests/plugins/test_native_heldout_training.py", + "tests/rollout_backends/test_native_colocation.py", + "tests/rollout_backends/test_native_rlt_contract.py", + "tests/rollout_backends/test_native_rlt_evaluation.py", + "tests/test_looped_grpo_recipe.py", + "tests/test_native_checkpoint_audit.py", + "tests/test_native_eval_schedule.py", + "tests/test_native_learning_signal_audit.py", + "tests/test_native_output_audit.py", + "tests/test_native_qualification_recipe.py", + "tests/test_native_runtime_audit.py", + "tests/test_native_runtime_identity.py", + "tests/test_native_runtime_mcore.py" + ], + "pytest_options": [ + "-q", + "-p", + "no:cacheprovider", + "--tb=short", + "-o", + "junit_family=legacy" + ], + "harness": "../bench/resident_pytest.py", + "environment_mutation": false, + "process_signals": false +} diff --git a/docs/native_output_recovery.md b/docs/native_output_recovery.md new file mode 100644 index 000000000..313233055 --- /dev/null +++ b/docs/native_output_recovery.md @@ -0,0 +1,95 @@ +# Native output and held-out recovery qualification + +Checkpoint equality alone cannot establish that a resumed worker generated the +same samples, used the same publication, or evaluated every held-out example. +`benchmarks/audit_native_outputs.py` checks those outputs for the frozen +three-update Ouro Thinking qualification. It builds on the runtime records in +[draft #20](https://github.com/0z5a/vime/pull/20) and the raw learning-signal audit. +No training or serving behavior changes in this increment. + +For each continuous/resumed run, it reopens all 96 training samples and all +32 held-out samples: eight development questions at completed updates 0,1,2,3. +It verifies actual train/development IDs against the frozen selection and token +audit, includes every development row in order, and checks seeds, R4 traces, +greedy evaluation settings, policy versions, EOS/truncation and finite scores. +Saved response text must decode from the saved response tokens; rewards are +regraded from that text and the fixed label. + +Each evaluation has one publication digest. Evaluations 0–2 must match the +corresponding subsequent training rollouts; the final evaluation must use a +fourth distinct publication. The first three resumed evaluations belong to the +split worker, while evaluation 3 belongs to the newly started worker. The raw +startup and process records are rechecked, not replaced by a detached summary. + +Across runs, tokens, answers, rewards, statuses, metadata and semantic traces +must match. Only `runtime_epoch` and `request_id` are excluded from direct trace +equality: epoch is separately bound to the phase's worker record, and held-out +request IDs must be nonempty and unique within their round. Scores, advantages, +returns, KL, reference/current policy scores and gradient norms use the declared +FP32 comparison tolerance `atol=1e-5, rtol=3e-5`; maximum absolute differences are +reported. Masks match exactly. This tolerance is fixed before official model +execution and is not a BF16 qualification. + +An identical pair with no mixed-reward/nonzero-advantage/gradient update remains +`output_equivalence_pass=true`, but `output_and_signal_pass=false` and the CLI +returns 1. The report hashes all 39 consumed evidence inputs and the local +tokenizer files, and preserves both four-point reward curves. It does not turn +this short qualification into a convergence experiment. + +```bash +python -m benchmarks.audit_native_outputs \ + --continuous RUNS/rltt/continuous --resumed RUNS/rltt/resumed \ + --packet PACKET --input-audit INPUT_AUDIT.json \ + --tokenizer LOCAL_TOKENIZER --algorithm rltt --output output-audit.json +``` + +Use `--algorithm grpo` for the matched GRPO run. The tokenizer loads from local +files with remote code disabled. This command consumes completed, task-owned +experiment dumps; it does not launch workers. Weight identity, checkpoint/Adam +state, frozen-source membership and full-framework/GPU execution still require +their separate evidence. The older/fused Adam format restriction is unchanged. + +## Validation + +The final suite has **245 distinct CPU passes** in 34.25 seconds, with 42 retained +MCore/DCP warnings. It includes 20 new output-gate cases, three expanded existing +native sampling/RLTT/Adam tests, and 222 existing scheduling, runtime, checkpoint, +signal, recipe and adapter checks. Earlier 18- and 3-case runs overlap it. + +The CLI controls use synthetic saved runs and Ray/process records with a real +WordLevel tokenizer. Sixteen corruption cases cover missing rounds/rows, +incorrect IDs/prefixes/text/seeds/versions/epochs/EOS, nonfinite scores, wrong or +stale publications, changed output, changed training tensors, changed gradient +norm and training text that does not decode from its tokens. Separate controls +exercise zero learning signal and a small finite score difference. + +The three existing model tests generate real tiny native samples, compute +token-parity training rewards, perform AdamW updates and restore actor/reference/ +optimizer state into fresh objects in the **same process**. Their held-out +tokenizer and Ray transport are doubles. The new comparator consumes their raw +held-out sample dictionaries before and after the recovered update: + +| Tiny CPU model | Paired held-out samples | Tokens/reward/semantic trace | Maximum score difference | Speedup | +|---|---:|---|---:|---| +| Ouro | 8 | Exact | 0 | NOT_MEASURED | +| Nanbeige | 8 | Exact | 0 | NOT_MEASURED | +| Huginn | 8 | Exact | 0 | NOT_MEASURED | + +The retained official Ouro Thinking tokenizer also passes 40 answer-replay +controls over the 12 training and eight development inputs. These use known +labels and invented scores, and verify decoding, reward grading and EOS ID 2; +they are **not model-generated answers**. Six local configuration/tokenizer files +match the retained model manifest at `3aaa2224253a92ca45cf2e3d427c360e1ef9c93d`; +all input prefixes match the retained qualification evidence. No weight file or +remote node was read for this check. No CUDA initialization or environment +mutation occurred. + +| Required E2E comparison | Baseline throughput | FlashRLT throughput | Speedup | Peak memory reduction | Reward convergence | +|---|---:|---:|---:|---:|---| +| Official Ouro Thinking continuous/fresh-process recovery | NOT_RUN | NOT_RUN | NOT_MEASURED | NOT_MEASURED | NOT_ESTABLISHED | +| RLTT / FlashLoop / slime / Megatron campaign | NOT_RUN | NOT_RUN | NOT_MEASURED | NOT_MEASURED | NOT_ESTABLISHED | + +Raw logs/XML, tokenizer-control records, validation receipt and source/artifact +hashes are in `benchmarks/results/native-output-recovery/`. CPU suite elapsed +time is not a model speedup. The full experiment matrix and paper's quality and +system claims remain pending their actual measurements. diff --git a/tests/plugins/test_native_heldout_training.py b/tests/plugins/test_native_heldout_training.py index 79369499e..93febcf21 100644 --- a/tests/plugins/test_native_heldout_training.py +++ b/tests/plugins/test_native_heldout_training.py @@ -14,11 +14,12 @@ from test_looped_grpo import cpu_engine, publish from test_rltt_online_cycle import pair, update +from benchmarks.audit_native_outputs import compare_samples from vime.rollout import native_eval from vime.utils.eval_config import EvalDatasetConfig -def evaluate(engine, data, monkeypatch): +def evaluate(engine, data, monkeypatch, capture=None): tokenizer = SimpleNamespace( encode=lambda prompt, **kwargs: [int(value) for value in prompt.split()], decode=lambda tokens, **kwargs: r"\boxed{" + str(tokens[-1]) + "}", @@ -59,6 +60,8 @@ def evaluate(engine, data, monkeypatch): ) ) output = native_eval.evaluate(args) + if capture is not None: + capture.append([sample.to_dict() for sample in output.data["heldout"]["samples"]]) return [ { "tokens": sample.tokens, @@ -82,7 +85,7 @@ def assert_optimizer_equal(left, right): def test_evaluation_preserves_updates_and_fresh_resume(family, tmp_path, monkeypatch, record_property): data = tmp_path / "heldout.jsonl" data.write_text('{"prompt":"4 5","label":"2"}\n{"prompt":"7 8","label":"3"}\n') - evaluations, reference_runs, final_states = [], [], [] + evaluations, raw_evaluations, reference_runs, final_states = [], [], [], [] for enabled in (False, True): directory = tmp_path / str(enabled) directory.mkdir() @@ -94,7 +97,7 @@ def test_evaluation_preserves_updates_and_fresh_resume(family, tmp_path, monkeyp for step in range(3): records.append(update(actor, reference, optimizer, engine, family, directory, step, "sdpa-reference")) if enabled: - evaluations.append(evaluate(engine, data, monkeypatch)) + evaluations.append(evaluate(engine, data, monkeypatch, raw_evaluations)) if enabled and step == 1: torch.save( { @@ -123,12 +126,19 @@ def test_evaluation_preserves_updates_and_fresh_resume(family, tmp_path, monkeyp engine = cpu_engine(native, family) publish(resumed, engine, family, tmp_path / "restored-policy", 3) torch.set_rng_state(checkpoint["rng"]) - assert evaluate(engine, data, monkeypatch) == evaluations[1] + resumed_outputs = [] + assert evaluate(engine, data, monkeypatch, resumed_outputs) == evaluations[1] directory = tmp_path / "fresh" directory.mkdir() actual = update(resumed, reference, optimizer, engine, family, directory, 2, "sdpa-reference") assert actual == reference_runs[1][2] - assert evaluate(engine, data, monkeypatch) == evaluations[2] + assert evaluate(engine, data, monkeypatch, resumed_outputs) == evaluations[2] + errors = [ + compare_samples(left, right) + for expected, actual in zip(raw_evaluations[1:], resumed_outputs, strict=True) + for left, right in zip(expected, actual, strict=True) + ] + assert len(errors) == 8 for name, expected in final_states[1][0].items(): assert torch.equal(expected, resumed.state_dict()[name]), name assert_optimizer_equal(final_states[1][1], optimizer.state_dict()) @@ -136,3 +146,5 @@ def test_evaluation_preserves_updates_and_fresh_resume(family, tmp_path, monkeyp record_property("scope", "tiny CPU native/RLTT/Adam recovery; transport and tokenizer doubles; no quality claim") record_property("training", json.dumps(reference_runs[1])) record_property("heldout", json.dumps(evaluations)) + record_property("paired_raw_heldout_samples", len(errors)) + record_property("paired_raw_score_max_error", max(errors)) diff --git a/tests/test_native_output_audit.py b/tests/test_native_output_audit.py new file mode 100644 index 000000000..6b391a1f3 --- /dev/null +++ b/tests/test_native_output_audit.py @@ -0,0 +1,285 @@ +"""Synthetic saved runs exercise complete-output gates, with a real local tokenizer.""" + +import copy +import hashlib +import json +import shutil +import sys +from pathlib import Path + +import pytest +import torch +from tokenizers import Tokenizer +from tokenizers.models import WordLevel +from transformers import PreTrainedTokenizerFast + +from benchmarks.audit_native_outputs import audit, main +from tests.test_native_learning_signal_audit import evidence +from vime.rollout.native_eval import evaluation_seed +from vime.utils.types import RecurrentTrace + +pytest_plugins = ["tests.test_native_runtime_audit"] + + +@pytest.fixture +def runs(tmp_path, records): + tokenizer = PreTrainedTokenizerFast( + tokenizer_object=Tokenizer( + WordLevel( + {"[UNK]": 0, "[BOS]": 1, "p": 2, "q": 3, "other": 4, r"\boxed{0}": 5, r"\boxed{1}": 6, "[EOS]": 7}, + unk_token="[UNK]", + ) + ), + unk_token="[UNK]", + bos_token="[BOS]", + eos_token="[EOS]", + ) + tokenizer_path = tmp_path / "tokenizer" + tokenizer.save_pretrained(tokenizer_path) + built = [] + for index, original in enumerate(records[:2]): + directory = tmp_path / f"signals-{index}" + directory.mkdir() + run, packet, inputs = evidence(directory) + shutil.copytree(original / "runtime", run / "runtime") + for path in original.glob("*-process.json"): + shutil.copyfile(path, run / path.name) + for step in range(3): + rollout_path, train_path = run / f"details/rollout_data/{step}.pt", run / f"details/train_data/{step}.pt" + rollout, trained = (torch.load(path, weights_only=False) for path in (rollout_path, train_path)) + phase = "continuous" if index == 0 else ("split" if step < 2 else "resume") + for sample, batch in zip(rollout["samples"], trained["samples"], strict=True): + sample["tokens"] = [2, 3, 6 if sample["reward"] else 5, 7] + sample["response_length"], sample["rollout_log_probs"] = 2, [-1.0, -1.0] + sample["recurrent_trace"].update(runtime_epoch=phase, decode_depths=[4, 4]) + batch["tokens"], batch["response_lengths"] = torch.tensor(sample["tokens"]), 2 + batch["recurrent_inputs"] = RecurrentTrace(**sample["recurrent_trace"]) + batch["loss_masks"] = [1, 1] + for key in ("rollout_log_probs", "log_probs", "ref_log_probs", "advantages", "returns", "kl"): + batch[key] = batch[key].repeat(2) + torch.save(rollout, rollout_path) + torch.save(trained, train_path) + built.append(run) + development = [{"prompt": "p q", "label": "1", "metadata": {"id": f"dev-{i}"}} for i in range(8)] + data_path = packet / "development.jsonl" + data_path.write_text("".join(json.dumps(row) + "\n" for row in development)) + profile_path = packet / "qualification.json" + profile = json.loads(profile_path.read_text()) + profile.update( + response_limit=2, + eval_completions_per_prompt=1, + split_stop_after=2, + precision="fp32", + selected_ids={ + "train": [str(i) for i in range(12)], + "development": [row["metadata"]["id"] for row in development], + }, + ) + profile["files"]["development.jsonl"] = {"rows": 8, "sha256": hashlib.sha256(data_path.read_bytes()).hexdigest()} + profile_path.write_text(json.dumps(profile)) + profile_sha = hashlib.sha256(profile_path.read_bytes()).hexdigest() + input_rows = [{**row, "split": "train"} for row in json.loads(inputs.read_text())["rows"]] + input_rows.extend( + { + "split": "development", + "id": row["metadata"]["id"], + "token_ids_sha256": hashlib.sha256(json.dumps([2, 3]).encode()).hexdigest(), + } + for row in development + ) + inputs.write_text(json.dumps({"qualification_sha256": profile_sha, "rows": input_rows})) + for index, run in enumerate(built): + for path in run.glob("*-process.json"): + receipt = json.loads(path.read_text()) + receipt["qualification_sha256"] = profile_sha + path.write_text(json.dumps(receipt)) + template = torch.load(run / "details/rollout_data/0.pt", weights_only=False)["samples"][0] + for step in range(4): + samples = [] + for i, row in enumerate(development): + sample = copy.deepcopy(template) + reward = int(i % 2 == 0) + sample.update( + index=i, + group_index=i, + prompt="p q", + tokens=[2, 3, 6 if reward else 5, 7], + response=tokenizer.decode([6 if reward else 5, 7], skip_special_tokens=True), + reward=reward, + metadata={ + **row["metadata"], + "native_eval": { + "dataset": "qualification-development", + "prompt_index": i, + "completion": 0, + "seed_profile": "native-heldout-v1", + "top_p": 1, + "top_k": -1, + "max_tokens": 2, + "stop_token_ids": [], + }, + }, + weight_versions=[str(step + 1)], + ) + phase = "continuous" if index == 0 else ("split" if step <= 2 else "resume") + sample["recurrent_trace"].update( + runtime_epoch=phase, + policy_version=step + 1, + publication_digest=str(step + 1) * 64, + request_id=f"{phase}-{step}-{i}", + temperature=0, + seed=evaluation_seed(42, "qualification-development", i, 0), + ) + samples.append(sample) + torch.save({"rollout_id": step, "samples": samples}, run / f"details/rollout_data/eval_{step}.pt") + return *built, packet, inputs, tokenizer_path, tokenizer + + +@pytest.mark.parametrize("algorithm", ["grpo", "rltt"]) +def test_full_cli_reads_all_saved_outputs_with_real_tokenizer(runs, tmp_path, monkeypatch, algorithm): + continuous, resumed, packet, inputs, tokenizer_path, _ = runs + output = tmp_path / "audit.json" + monkeypatch.setattr( + sys, + "argv", + [ + "audit", + "--continuous", + str(continuous), + "--resumed", + str(resumed), + "--packet", + str(packet), + "--input-audit", + str(inputs), + "--tokenizer", + str(tokenizer_path), + "--algorithm", + algorithm, + "--output", + str(output), + ], + ) + with pytest.raises(SystemExit) as result: + main() + assert result.value.code == 0 + report = json.loads(output.read_text()) + assert report["output_and_signal_pass"] and report["joint_signal_updates"] == [0, 1, 2] + assert report["training_samples_per_run"] == 96 and report["heldout_samples_per_run"] == 32 + assert report["continuous_curve"] == report["resumed_curve"] + assert all(value == 0 for value in report["max_absolute_errors"].values()) + assert report["reward_convergence"] == "NOT_ESTABLISHED" and len(report["consumed_sha256"]) == 39 + for path, digest in report["consumed_sha256"].items(): + assert hashlib.sha256(Path(path).read_bytes()).hexdigest() == digest + for name, digest in report["tokenizer_sha256"].items(): + assert hashlib.sha256((tokenizer_path / name).read_bytes()).hexdigest() == digest + + +@pytest.mark.parametrize( + "corruption", + [ + "missing_round", + "missing_row", + "reordered_id", + "prefix", + "decoded_text", + "seed", + "version", + "epoch", + "eos", + "nonfinite", + "publication", + "stale_final", + "changed_output", + "training_tensor", + "gradient", + "training_text", + ], +) +def test_rejects_incomplete_or_changed_outputs(runs, corruption): + continuous, resumed, packet, inputs, _, tokenizer = runs + path = resumed / "details/rollout_data/eval_3.pt" + data = torch.load(path, weights_only=False) + sample = data["samples"][1] + if corruption == "missing_round": + path.unlink() + elif corruption == "missing_row": + data["samples"].pop() + elif corruption == "reordered_id": + sample["metadata"]["id"] = "dev-0" + elif corruption == "prefix": + sample["tokens"][0] = 4 + elif corruption == "decoded_text": + sample.update(response=r"\boxed{1}", reward=1) + elif corruption == "seed": + sample["recurrent_trace"]["seed"] += 1 + elif corruption == "version": + sample["recurrent_trace"]["policy_version"] = 3 + elif corruption == "epoch": + sample["recurrent_trace"]["runtime_epoch"] = "split" + elif corruption == "eos": + sample["tokens"][-1] = 4 + elif corruption == "nonfinite": + sample["rollout_log_probs"][0] = float("nan") + elif corruption in ("publication", "stale_final"): + if corruption == "publication": + path = resumed / "details/rollout_data/eval_1.pt" + data = torch.load(path, weights_only=False) + for row in data["samples"]: + row["recurrent_trace"]["publication_digest"] = ("f" if corruption == "publication" else "3") * 64 + elif corruption == "changed_output": + sample["tokens"][-2] = 6 + sample.update(response=r"\boxed{1}", reward=1) + elif corruption == "training_tensor": + target = resumed / "details/train_data/2.pt" + training = torch.load(target, weights_only=False) + training["samples"][0]["kl"].add_(0.1) + torch.save(training, target) + elif corruption == "gradient": + torch.save(2.0, resumed / "grad-actor-2-0.pt") + elif corruption == "training_text": + target = resumed / "details/rollout_data/2.pt" + rollout = torch.load(target, weights_only=False) + rollout["samples"][1].update(response=r"\boxed{1}", reward=1) + torch.save(rollout, target) + target = resumed / "details/train_data/2.pt" + training = torch.load(target, weights_only=False) + training["samples"][1]["local_raw_reward"] = 1 + torch.save(training, target) + if corruption != "missing_round": + torch.save(data, path) + with pytest.raises((AssertionError, FileNotFoundError)): + audit(continuous, resumed, packet, inputs, "rltt", tokenizer) + + +def test_identical_outputs_with_zero_learning_signal_do_not_qualify(runs): + continuous, resumed, packet, inputs, _, tokenizer = runs + for run in (continuous, resumed): + for step in range(3): + rollout_path, train_path = run / f"details/rollout_data/{step}.pt", run / f"details/train_data/{step}.pt" + rollout, trained = (torch.load(path, weights_only=False) for path in (rollout_path, train_path)) + for sample, batch in zip(rollout["samples"], trained["samples"], strict=True): + sample.update(reward=0, response=r"\boxed{0}") + sample["tokens"][-2] = 5 + batch["tokens"] = torch.tensor(sample["tokens"]) + batch["local_raw_reward"] = 0 + batch["advantages"].zero_() + batch["returns"].zero_() + torch.save(rollout, rollout_path) + torch.save(trained, train_path) + torch.save(0.0, run / f"grad-actor-{step}-0.pt") + report = audit(continuous, resumed, packet, inputs, "rltt", tokenizer) + assert report["output_equivalence_pass"] and not report["output_and_signal_pass"] + assert report["joint_signal_updates"] == [] and report["reward_convergence"] == "NOT_ESTABLISHED" + + +def test_predeclared_score_tolerance_reports_small_finite_difference(runs): + continuous, resumed, packet, inputs, _, tokenizer = runs + path = resumed / "details/rollout_data/eval_3.pt" + data = torch.load(path, weights_only=False) + data["samples"][0]["rollout_log_probs"][0] += 1e-6 + torch.save(data, path) + report = audit(continuous, resumed, packet, inputs, "rltt", tokenizer) + assert report["output_and_signal_pass"] + assert 0 < report["max_absolute_errors"]["heldout_scores"] < 2e-6 + assert report["numeric_tolerance"] == {"atol": 1e-5, "rtol": 3e-5}