Modal Research Exchange

you are

TriMuon vs dimuon-lite (Polar Express) for LoRA SFT on no_robots

Failed no result agentcore Qwen/Qwen3.5-4B SFT 1.8 GPU-h budget started 5h ago 4m 35s 1 turn
Redo
Pick where the agent works.

Preflight on shared Spindle returned HTTP 400 at create_model for both arms ('optimizer family dimuon is not supported', 'optimizer family trimuon is not supported'), so both arms would need a fork. No training ran: the TriMuon reference code has been withdrawn upstream, and the spec has no pinned reference or correctness-preflight plan, so the required optimizer parity gate cannot be run.

No result No result: comparison did not finish.

Result

No arm results yet.

Changes from the spec 0 · original hypothesis not tested

None reported: ran as specified.

Original hypothesis tested: no

Tested instead: Nothing was trained. The run only showed that shared Spindle rejects both the dimuon and trimuon optimizer families, and that no pinned TriMuon reference exists to check a fork against.

agentcore's verdict on the changed experiment: inconclusive

Checks · activation unverified · evaluator unknown · feasibility unknown
Custom implementation correctness: unverified
Correctness preflight was not recorded.
Validates executor-reported evidence; autonomous training calls are not blocked by this server.
Executor reported inconclusive; shown as no result.
Treatment activation: unverified
The spec has no activation gate or experiment features (it predates them), so whether the treatment engaged is unknown.
Initialization / optimizer verification: unverified
Initialization and optimizer evidence was not required by this saved spec.
Research decision: unknown
No prespecified decision rule was recorded.
Adaptation batches across paired arms: unknown (not verified)
The spec does not declare whether this check applies, and the run did not verify it. The run did not report adaptation batch manifests.
Evaluator comparability: unknown
Evaluator provenance was not recorded.
Generator reward audit
Generator reward audit: Unknown whether this run needed a teacher reward audit: its spec does not declare whether a teacher or task generator is trained. Nothing was recorded, so reward contributions are unknown.
Held-out loss aggregation
Spec asks for token mean (summed NLL / loss tokens) · run reported no record, so the aggregation behind its loss numbers is unknown
Feasibility projection: unknown
Projected costs, not measured GPU usage.
Projected wall time
unknown
Projected GPU allocation
unknown
  • Measured feasibility not recorded
Timing, sample counts and allocation evidence
{
  "gpu_hours": null,
  "known_gpu_hours": 0,
  "phases": {},
  "problems": [
    "Measured feasibility not recorded"
  ],
  "record": null,
  "recorded_at": 1793748094.8738408,
  "status": "unknown",
  "wall_seconds": null
}
Generated task audit: unverified: no audit recorded
Answer agreement with recorded independent solutions does not establish semantic correctness. Normalized exact overlap does not detect paraphrases.
Spec exp_ff293ca443
Experiment version
exp_ff293ca443
Repeat the selected saved experiment version to check reproducibility. This repetition tests that version's hypothesis and methods.
Legacy context: original idea context unrecorded (unknown); launch uses the saved spec.

Hypothesis

With a Spindle fork that adds TriMuon, LoRA SFT on Qwen3.5-4B reaches held-out no_robots loss at least 0.01 nats lower than dimuon-lite (Polar Express) at its best LR, after the same 80 steps.

Success criterion

Validated if best-LR TriMuon eval NLL is at least 0.01 nats below best-LR dimuon-lite eval NLL, and TriMuon's median optimizer step time is not higher. Failed if the gap is under 0.01 nats or reversed. A rerun of the best PE config with a second seed is optional, if budget allows, to check that the 0.01 margin exceeds seed noise.

no_robots 80 steps batch 64 LoRA r32 lr 0.0001 120 min wall budget
Method
Fork modal-projects/spindle and add TriMuon as an optimizer option. It keeps DiMuon's recovered momentum and preconditioning rules. It replaces only the Polar Express polar step with two outer Polar Switch passes, then four cubic Newton-Schulz refinements folded into the rank x rank multiplier. Use the FP16 polar core and TF32 disabled, as in aaron's benchmark. Deploy the fork as a throwaway copy. Train rank-32 LoRA on Qwen/Qwen3.5-4B with a short tinker SDK SFT loop on no_robots. The loop uses the cookbook renderer for the model, forward_backward with cross_entropy, then optim_step. The treatment arm runs on the fork with TriMuon. The baseline arm runs dimuon-lite on the same fork (or shared Spindle) with identical code. Each arm sweeps LR over {5e-5, 1e-4, 2e-4}: 6 runs of 80 steps each, same data order and seed. Each run evaluates held-out loss at step 80 and logs per-step optimizer wall time. Qwen3.5-4B is a scaled-down stand-in for the source's Qwen3-8B rank-32 workload. Polar Switch and AdamW arms are follow-up specs, not part of this decision.
Baseline
dimuon-lite (DiMuon with Polar Express), beta1=0.9, grad_clip_norm=0.0. Same model, rank, data order, seed, renderer, batch size, steps and LR grid. The best-LR run of each arm is compared.
Full spec
{
  "base_model": "Qwen/Qwen3.5-4B",
  "baseline": "dimuon-lite (DiMuon with Polar Express), beta1=0.9, grad_clip_norm=0.0. Same model, rank, data order, seed, renderer, batch size, steps and LR grid. The best-LR run of each arm is compared.",
  "batch_size": 64,
  "budget": {
    "gpu_hours": 1.8,
    "max_wall_minutes": 120
  },
  "command": "python - <<'EOF'\n# Custom part: the TriMuon config exists only on the fork; the baseline uses tinker.types.DimuonOptimizerConfig() / DimuonParams.\nimport os, tinker\nfrom tinker_cookbook.recipes.chat_sl import chat_datasets  # renderer + no_robots builder\nsc = tinker.ServiceClient(base_url=os.environ[\"TINKER_BASE_URL\"])  # fork URL for the TriMuon arm\nARM = os.environ.get(\"ARM\", \"pe\"); LR = float(os.environ.get(\"LR\", \"1e-4\"))\nopt_cfg = tinker.types.DimuonOptimizerConfig() if ARM == \"pe\" else tinker.types.TrimuonOptimizerConfig()  # Trimuon* added by the fork\ntc = sc.create_lora_training_client(base_model=\"Qwen/Qwen3.5-4B\", rank=32, optimizer=opt_cfg)\ntrain, test = chat_datasets.no_robots_batches(tc.get_tokenizer(), batch_size=64, max_length=2048, seed=0)\nfor step, batch in zip(range(80), train):\n    tc.forward_backward(batch, loss_fn=\"cross_entropy\").result()\n    P = tinker.types.DimuonParams if ARM == \"pe\" else tinker.types.TrimuonParams\n    tc.optim_step(P(learning_rate=LR, beta1=0.9, grad_clip_norm=0.0)).result()\nprint(\"eval_nll\", sum(tc.forward(b, loss_fn=\"cross_entropy\").result().metrics[\"loss:mean\"] for b in test) / len(test))\ntc.save_weights_for_sampler(name=f\"rx-trimuon-{ARM}-{LR}\")\nEOF",
  "dataset": {
    "hf_path": "HuggingFaceH4/no_robots",
    "n_examples": 5120,
    "name": "no_robots",
    "split": "train (eval on test)"
  },
  "eval": {
    "benchmark": "no_robots test split",
    "metric": "mean per-token NLL on assistant tokens",
    "n_examples": 500
  },
  "hypothesis": "With a Spindle fork that adds TriMuon, LoRA SFT on Qwen3.5-4B reaches held-out no_robots loss at least 0.01 nats lower than dimuon-lite (Polar Express) at its best LR, after the same 80 steps.",
  "lora_rank": 32,
  "max_seq_len": 2048,
  "method": "Fork modal-projects/spindle and add TriMuon as an optimizer option. It keeps DiMuon's recovered momentum and preconditioning rules. It replaces only the Polar Express polar step with two outer Polar Switch passes, then four cubic Newton-Schulz refinements folded into the rank x rank multiplier. Use the FP16 polar core and TF32 disabled, as in aaron's benchmark. Deploy the fork as a throwaway copy. Train rank-32 LoRA on Qwen/Qwen3.5-4B with a short tinker SDK SFT loop on no_robots. The loop uses the cookbook renderer for the model, forward_backward with cross_entropy, then optim_step. The treatment arm runs on the fork with TriMuon. The baseline arm runs dimuon-lite on the same fork (or shared Spindle) with identical code. Each arm sweeps LR over {5e-5, 1e-4, 2e-4}: 6 runs of 80 steps each, same data order and seed. Each run evaluates held-out loss at step 80 and logs per-step optimizer wall time. Qwen3.5-4B is a scaled-down stand-in for the source's Qwen3-8B rank-32 workload. Polar Switch and AdamW arms are follow-up specs, not part of this decision.",
  "optimizer": {
    "lr": 0.0001,
    "name": "trimuon (fork)"
  },
  "steps": 80,
  "success_criterion": "Validated if best-LR TriMuon eval NLL is at least 0.01 nats below best-LR dimuon-lite eval NLL, and TriMuon's median optimizer step time is not higher. Failed if the gap is under 0.01 nats or reversed. A rerun of the best PE config with a second seed is optional, if budget allows, to check that the 0.01 margin exceeds seed noise.",
  "title": "TriMuon vs dimuon-lite (Polar Express) for LoRA SFT on no_robots",
  "training_type": "sft"
}
Evidence 2

Partial · Download manifest. Recorded files are retained copies; checkpoint references do not include model weights.

Not recorded: effective config, predictions, per arm metrics, checkpoint references.

Evidence import problems: file 2: invalid file name or kind.

Interim updates from agentcore (1, first Nov 3, 23:25 UTC)
Artifact references
  • script · probe_raw.py
  • metrics · probe_raw.log
  • code_revision · code-revision.txt
  1. Nov 3, 23:25 UTC · failed · Preflight on shared Spindle returned HTTP 400 at create_model for both arms ('optimizer family dimuon is not supported', 'optimizer family trimuon is not supported'), so both arms would need a fork. …
Artifacts
adaptation_manifests
[]
correctness_preflight
{'required': True, 'status': 'unverified', 'paths': [], 'missing': ['dimuon_lite_pe: the spec pins no baseline or reference revision and no tolerances. Shared Spindle main (afd2f22) rejects dimuon, so it would have to be built from withdrawn modal-projects/spindle PR #194 / modal-projects/miles PR #17 head 228b59d9', "trimuon: modal-projects/miles PR #27 head 45937c3b is an empty 'Withdrawn' commit on top of PR #17, so the TriMuon code is gone. The spec pins no reference revision for the 2x Polar Switch + 4 cubic NS refinement or the FP16 core, and gives no tolerance"], 'requested_revision': 'Pin (a) the dimuon-lite reference commit (e.g. miles 228b59d9), (b) Polar Switch 6f382f1e PS3_55 coefficients and an exact TriMuon reference (fp64 torch) with the refinement and fold definition, (c) atol/rtol/min_cosine for update parity and LR-scaling tolerance, and (d) a Miles trainer image revision for Qwen3.5-4B.'}
correctness_validation
{'status': 'unverified', 'required': True, 'checks': [], 'reason': 'Correctness preflight was not recorded.', 'evidence_source': 'executor report; remote execution is not attested', 'applicability': 'unknown', 'reported_verdict': 'inconclusive'}
feasibility
{'status': 'unknown', 'problems': ['Measured feasibility not recorded'], 'wall_seconds': None, 'gpu_hours': None, 'known_gpu_hours': 0, 'phases': {}, 'record': None, 'recorded_at': 1793748094.8738408}
feasibility_required
True
initialization_provenance
{'version': 1, 'arms': {}, 'note': 'not created; no training client was successfully created for either arm'}
last_reply
head 45937c3b is an empty 'Withdrawn' commit on top of PR #17, so the TriMuon code is gone. The spec pins no reference revision for the 2x Polar Switch + 4 cubic NS refinement or the FP16 core, and gives no tolerance"], "requested_revision": "Pin (a) the dimuon-lite reference commit (e.g. miles 228b59d9), (b) Polar Switch 6f382f1e PS3_55 coefficients and an exact TriMuon reference (fp64 torch) with the refinement and fold definition, (c) atol/rtol/min_cosine for update parity and LR-scaling tolerance, and (d) a Miles trainer image revision for Qwen3.5-4B."}, "initialization_provenance": {"version": 1, "arms": {}, "note": "not created; no training client was successfully created for either arm"}, "activation_calibration": {"values": {}, "note": "no pilot ran; both optimizer families were rejected before model creation"}, "feasibility": null, "loss_eval": null, "adaptation_manifests": [], "evidence": {"version": 1, "files": [{"name": "probe_raw.py", "kind": "script", "content": "# Raw HTTP probe of shared Spindle create_model with each arm's optimizer_config (Qwen/Qwen3.5-4B, LoRA rank 32); credentials read from env vars; session finished afterwards. sha256 1bae750cc5f3c601d49e8df6acc005d7f8c9ab39efafb7e4a77528ca7a7b366e"}, {"name": "probe_raw.log", "kind": "metrics", "content": "create_session 200\ncreate_model {'type': 'dimuon', 'version': 1} 400 {\"error\":\"invalid_request\",\"message\":\"optimizer family dimuon is not supported\"}\ncreate_model {'type': 'trimuon'} 400 {\"error\":\"invalid_request\",\"message\":\"optimizer family trimuon is not supported\"}\nfinish_session 200 null"}, {"name": "code-revision.txt", "kind": "code_revision", "content": "spindle main afd2f22 (rejects non-adamw in control_plane/http.py create_model); spindle PR#194 head e23308c 'Withdrawn' (dimuon only, no trimuon/polar code); miles PR#17 head 228b59d9 (dimuon-lite); miles PR#27 head 45937c3b 'Withdrawn' (empty commit, TriMuon removed)"}], "checkpoints": [], "per_arm_metrics": {}}} ```
launch
{'experiment_id': 'exp_ff293ca443', 'context_status': 'legacy_unknown', 'superseded': False, 'mode': 'redo', 'purpose': "Repeat the selected saved experiment version to check reproducibility. This repetition tests that version's hypothesis and methods."}
progress_updated_at
1793748279.6005318
reported_outcome_reason
incomplete_execution
reported_verdict
inconclusive
restoration_validation
{'status': 'unverified', 'required': False, 'checks': [], 'reason': 'Initialization and optimizer evidence was not required by this saved spec.', 'applicability': 'unknown'}
started_at
1793748032.9418862
Agent trace · 1 turn
Details
run
run_bb9eb83573
backend
agentcore
conversation
run_bb9eb83573
experiment
exp_ff293ca443
launch
redo
redone as
run_bd61cdb704 no result
redone as
run_9a86933e38 not supported
created
Nov 3, 23:12 UTC
started
Nov 3, 23:20 UTC
finished
Nov 3, 23:25 UTC
duration
4m 35s
turns
1
GPU-h budget
1.8
wall budget
120 min
base model
Qwen/Qwen3.5-4B
training
SFT
dataset
no_robots
result
final
outcome reason
incomplete execution
Other runs of this idea

Submit an idea

Most ideas come in from Slack threads. Use this when yours is not in one yet; the triage agent picks it up.