Modal Research Exchange

you are

Indexer warmup from full attention versus cold-start indexer for sparse LoRA adaptation

Failed no result Devin Qwen/Qwen3-4B SFT 2.0 GPU-h budget started 23h ago 1h 23m
Redo
Pick where the agent works.
View session in Devin ↗

On throwaway fork app spindle-fork-run_70c15f2619, which added a lightning indexer and top-512 sparse attention to Qwen/Qwen3-4B (LoRA r32, Adam 1e-4, 4096-token PG19 chunks, batch 2 not 64), the 50-step warmup treatment scored 2.6362 nats on sparse PG19 eval (top-512 recall 0.866) and the cold-start baseline scored 2.6348 nats (recall 0.858), so treatment came out 0.0014 nats worse. The dense reference died at step 80 and the second baseline seed never ran because the fork started rejecting the proxy credentials with 401 errors, so not every arm finished and the result is inconclusive.

No result No result: the run finished without measuring the effect.

Result

No arm results yet.

treatment_warmup_eval_loss_nats
2.636
treatment_warmup_topk512_recall
0.8661
baseline_seed0_eval_loss_nats
2.635
baseline_seed0_topk512_recall
0.8578
gap_baseline_minus_treatment_nats
-0.00143
treatment_final10_train_loss
2.612
baseline_final10_train_loss
2.608
treatment_train_minutes
17.59
baseline_train_minutes
17.97
eval_examples
194
train_batch_size
2
Changes from the spec 0

Not recorded: this run didn't report its changes from the spec, so they are unknown.

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. Spec example defect (the run may not have copied it): The spec's example command walks one batch stream for both phases (batches[:WARMUP + 100] with a step < WARMUP switch), so an arm with WARMUP > 0 starts adaptation at batch WARMUP while the WARMUP = 0 baseline starts at batch 0. Iterate warmup and adaptation batches separately.
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 no specific aggregation · run reported no record, so the aggregation behind its loss numbers is unknown
Feasibility projection: unknown
Projected costs, not measured GPU usage.
Measured feasibility was not recorded for this run.
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_5606f51aaf

Hypothesis

Warming up a top-k indexer by KL distillation from frozen full attention, then LoRA-adapting under sparse attention, gives held-out PG19 loss at least 0.05 nats lower than the same sparse LoRA run with a randomly initialized indexer.

Success criterion

Validated if treatment eval loss is at least 0.05 nats below baseline and within 0.05 nats of the dense LoRA reference. Seed noise is to be checked to be under 0.02 nats via a second baseline seed. Failed if the gap to baseline is under 0.02 nats.

PG19 150 steps batch 64 LoRA r32 lr 0.0001 120 min wall budget
Method
Needs a Spindle fork that adds a DSA-style lightning indexer to Qwen/Qwen3-4B. Qwen3-4B is used because it is pure full attention, while Qwen3.5 uses hybrid linear attention. The indexer is a few low-dim heads per layer that score past tokens. The fork exposes three things: (a) an indexer-KL loss against the aggregated full-attention distribution, with the main model frozen; (b) top-k (k=512) token-selection sparse attention in forward and backward; (c) the indexer as a trainable parameter alongside the LoRA weights. Treatment stage 1 runs 50 steps that train only the indexer with KL to dense attention, using dense forward and a frozen base. Treatment stage 2 runs 100 steps of LoRA rank 32 next-token SFT on 4096-token PG19 chunks under top-k sparse attention. During stage 2 the indexer keeps its KL loss on selected tokens, detached from the LM loss, as in DSA. Both arms use the same data order, seed and LR. A dense-attention LoRA run with the same 100 steps is logged as a reference ceiling, not as an arm. Neither linked source could be read, so the design follows the Slack description and the DeepSeek/GLM indexer recipe.
Baseline
Same fork, data, and 100 sparse LoRA steps with indexer KL during training, but no 50-step indexer warmup. The indexer starts from random init. Dense-attention LoRA is logged as an upper-bound reference.
Full spec
{
  "base_model": "Qwen/Qwen3-4B",
  "baseline": "Same fork, data, and 100 sparse LoRA steps with indexer KL during training, but no 50-step indexer warmup. The indexer starts from random init. Dense-attention LoRA is logged as an upper-bound reference.",
  "batch_size": 64,
  "budget": {
    "gpu_hours": 2.0,
    "max_wall_minutes": 120
  },
  "command": "python - <<'EOF'\n# custom: indexer warmup + sparse attention come from the forked Spindle; loop is stock tinker SDK\nimport os, tinker\nsc = tinker.ServiceClient(base_url=os.environ['TINKER_BASE_URL'])\ntc = sc.create_lora_training_client(base_model='Qwen/Qwen3-4B', rank=32)\nbatches = load_pg19_chunks(seq_len=4096, batch_size=64)  # user helper, fixed seed\nWARMUP = int(os.environ.get('WARMUP', 50))  # 0 for baseline arm\nfor step, b in enumerate(batches[:WARMUP + 100]):\n    loss = 'indexer_kl' if step < WARMUP else 'cross_entropy'  # 'indexer_kl' added by fork\n    tc.forward_backward(b, loss).result()\n    tc.optim_step(tinker.AdamParams(learning_rate=1e-4)).result()\ntc.save_weights_for_sampler(name=f'sparse-idx-warmup{WARMUP}').result()\nEOF",
  "dataset": {
    "hf_path": "deepmind/pg19",
    "n_examples": 9600,
    "name": "PG19",
    "split": "train"
  },
  "eval": {
    "benchmark": "PG19 validation, 4096-token chunks, evaluated with sparse top-512 attention",
    "metric": "mean next-token cross-entropy (nats), plus top-k recall of dense attention mass",
    "n_examples": 200
  },
  "hypothesis": "Warming up a top-k indexer by KL distillation from frozen full attention, then LoRA-adapting under sparse attention, gives held-out PG19 loss at least 0.05 nats lower than the same sparse LoRA run with a randomly initialized indexer.",
  "lora_rank": 32,
  "max_seq_len": 4096,
  "method": "Needs a Spindle fork that adds a DSA-style lightning indexer to Qwen/Qwen3-4B. Qwen3-4B is used because it is pure full attention, while Qwen3.5 uses hybrid linear attention. The indexer is a few low-dim heads per layer that score past tokens. The fork exposes three things: (a) an indexer-KL loss against the aggregated full-attention distribution, with the main model frozen; (b) top-k (k=512) token-selection sparse attention in forward and backward; (c) the indexer as a trainable parameter alongside the LoRA weights. Treatment stage 1 runs 50 steps that train only the indexer with KL to dense attention, using dense forward and a frozen base. Treatment stage 2 runs 100 steps of LoRA rank 32 next-token SFT on 4096-token PG19 chunks under top-k sparse attention. During stage 2 the indexer keeps its KL loss on selected tokens, detached from the LM loss, as in DSA. Both arms use the same data order, seed and LR. A dense-attention LoRA run with the same 100 steps is logged as a reference ceiling, not as an arm. Neither linked source could be read, so the design follows the Slack description and the DeepSeek/GLM indexer recipe.",
  "optimizer": {
    "lr": 0.0001,
    "name": "adam"
  },
  "steps": 150,
  "success_criterion": "Validated if treatment eval loss is at least 0.05 nats below baseline and within 0.05 nats of the dense LoRA reference. Seed noise is to be checked to be under 0.02 nats via a second baseline seed. Failed if the gap to baseline is under 0.02 nats.",
  "title": "Indexer warmup from full attention versus cold-start indexer for sparse LoRA adaptation",
  "training_type": "sft"
}
Evidence

Unknown: this run has no recorded evidence bundle.

All metrics
treatment_warmup_eval_loss_nats
2.636
treatment_warmup_topk512_recall
0.8661
baseline_seed0_eval_loss_nats
2.635
baseline_seed0_topk512_recall
0.8578
gap_baseline_minus_treatment_nats
-0.00143
treatment_final10_train_loss
2.612
baseline_final10_train_loss
2.608
treatment_train_minutes
17.59
baseline_train_minutes
17.97
eval_examples
194
train_batch_size
2
Agent trace full trace with commands in Devin ↗
Details
run
run_70c15f2619
backend
Devin
session
devin-627f9b7aa0aa44efb3181da418d2b841
experiment
exp_5606f51aaf
redone as
run_3e43999905 not supported
created
Nov 3, 05:20 UTC
started
Nov 3, 05:20 UTC
finished
Nov 3, 06:43 UTC
duration
1h 23m
GPU-h budget
2.0
wall budget
120 min
base model
Qwen/Qwen3-4B
training
SFT
dataset
PG19
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.