Qwen3.5-0.8B: Astra Weight Edit

Qwen3.5-0.8B with 2 tensors edited directly by an LLM (GPT-6 Astra), with no training. This fixes the model's thinking-mode repeat loops.

All credit goes to Rikiya Takehi, Jayden Teoh, Alex Zhang and Omar Khattab (MIT CSAIL). I only applied their released diff and checked that it matches their evaluated checkpoint hash for hash. Not affiliated with or endorsed by the authors, OpenAI or Qwen.

What changed

The loop direction was subtracted from 64 output columns of mlp.down_proj in layers 15 and 19 (about 130k weights, 0.016% of the model). Everything else is byte-identical to the base model.

How to run

The edit only helps with thinking on. The chat template turns thinking off unless you pass enable_thinking=True. Recommended sampling (the paper's): temperature 0.6, top_p 0.95, top_k 20, presence penalty 1.5.

You want to run it in… Use Files
Python, GPU servers πŸ€— Transformers / vLLM / SGLang model.safetensors-* (bf16)
The browser (WebGPU) or Node.js πŸ€— Transformers.js onnx/*
Any ONNX Runtime app (C#, C++, Java, mobile…) ONNX Runtime onnx/*
A laptop / CPU / Mac, local apps llama.cpp, LM Studio, Ollama, Jan… Qwen3.5-0.8B-Astra-WeightEdit-BF16.gguf
Transformers (Python)
from transformers import AutoModelForImageTextToText, AutoTokenizer
repo = "JonathanColetti/Qwen3.5-0.8B-Astra-WeightEdit"
tok = AutoTokenizer.from_pretrained(repo)
model = AutoModelForImageTextToText.from_pretrained(repo, dtype="bfloat16", device_map="auto")
msgs = [{"role": "user", "content": "What is 17 * 23? Please reason step by step, and put your final answer within \\boxed{}."}]
inputs = tok.apply_chat_template(msgs, add_generation_prompt=True, enable_thinking=True,
                                 return_tensors="pt", return_dict=True).to(model.device)
out = model.generate(**inputs, max_new_tokens=4096, do_sample=True, temperature=0.6, top_p=0.95, top_k=20)
print(tok.decode(out[0, inputs["input_ids"].shape[1]:], skip_special_tokens=True))
vLLM
vllm serve JonathanColetti/Qwen3.5-0.8B-Astra-WeightEdit
# then send chat requests with: "chat_template_kwargs": {"enable_thinking": true}
Transformers.js (browser / Node.js)
npm i @huggingface/transformers@next
import { AutoProcessor, Qwen3_5ForConditionalGeneration, TextStreamer } from "@huggingface/transformers";

const repo = "JonathanColetti/Qwen3.5-0.8B-Astra-WeightEdit";
const processor = await AutoProcessor.from_pretrained(repo);
const model = await Qwen3_5ForConditionalGeneration.from_pretrained(repo, {
  dtype: { embed_tokens: "fp16", vision_encoder: "fp16", decoder_model_merged: "fp16" },
  device: "webgpu", // or "wasm" in the browser, "cpu" in Node.js (use "quantized" there)
});
const messages = [{ role: "user", content: "What is 17 * 23? Please reason step by step, and put your final answer within \\boxed{}." }];
const text = processor.apply_chat_template(messages, { add_generation_prompt: true, enable_thinking: true });
const inputs = await processor(text);
await model.generate({
  ...inputs, max_new_tokens: 4096, do_sample: true, temperature: 0.6, top_p: 0.95, top_k: 20,
  streamer: new TextStreamer(processor.tokenizer, { skip_prompt: true, skip_special_tokens: true }),
});

Which dtype to pick (each graph comes in all five; size is the language-model decoder):

dtype decoder size Best for Agrees with bf16*
fp32 3.0 GB reference 100%
fp16 1.5 GB WebGPU 100%
quantized (int8) 0.87 GB CPU / WASM 100%
q4f16 0.44 GB smallest download, WebGPU ~69%
q4 0.48 GB smallest download, CPU / WASM ~69%

*Next-token argmax agreement with the PyTorch model over a 35-token prompt (spot check). The 4-bit builds lose about as much against the bf16 base model as they do here, so treat them as noticeably lossy at this size.

llama.cpp / LM Studio / Ollama (GGUF)
# llama.cpp
llama-cli -hf JonathanColetti/Qwen3.5-0.8B-Astra-WeightEdit:BF16 \
  --jinja --chat-template-kwargs '{"enable_thinking":true}' \
  --temp 0.6 --top-p 0.95 --top-k 20 --presence-penalty 1.5 -c 32768

# Ollama (a version with Qwen3.5 support)
ollama run hf.co/JonathanColetti/Qwen3.5-0.8B-Astra-WeightEdit:BF16

LM Studio: search for JonathanColetti/Qwen3.5-0.8B-Astra-WeightEdit. Only a BF16 GGUF is provided (1.56 GB). This is text only: no mmproj vision file.

How the ONNX and GGUF files were made

Neither was re-exported. I took existing conversions of the same base revision and rewrote only the two edited tensors, so every other byte matches those well-tested builds:

  • ONNX: onnx-community/Qwen3.5-0.8B-ONNX-OPT @ 9a4c21d8. The down_proj tensors of layers 15 and 19 are overwritten in place in each decoder_model_merged* data file. Before writing, the script regenerates the base tensors from the bf16 weights and requires a byte-for-byte match with the shipped files in all five dtypes, including the int8/int4 block quantization. So the edited bytes are exactly what that export pipeline would have produced. embed_tokens* and vision_encoder* are unchanged copies.
  • GGUF: ggml-org/Qwen3.5-0.8B-GGUF Qwen3.5-0.8B-BF16.gguf @ 807dfd9a, converted from Qwen revision 2fc06364. blk.{15,19}.ffn_down.weight are swapped after checking that the base bytes match the base sha256 in astra_edit/manifest.json. The edited bytes match the edited sha256. Only general.name, general.repo_url and the base-model metadata were changed.
  • Checks: the ONNX fp32/fp16/int8 logits match PyTorch (mean KL ≀ 6e-4, same argmax). Transformers.js fp32 greedy output is token-for-token identical to PyTorch over 120 tokens.
  • Scripts: conversion/.

The root config.json gained a transformers.js_config block, and a minimal generation_config.json (eos_token_id: [<|im_end|>, <|endoftext|>], no sampling defaults) was added so generation stops at the end of the turn. The weights, tokenizer and chat template are unchanged.

Independent benchmark

The authors' prompts, sampling and graders (scores + scripts), vLLM bf16, seed 0. MATH-500: 500 Γ— 4 samples. GSM8K: 1,319 Γ— 2. IFEval: 541 Γ— 2, strict prompt-level, official checkers, answer after </think>. Thinking on: temperature 0.6, top_p 0.95, top_k 20, presence_penalty 1.5, 32k tokens. Thinking off: temperature 0.7, top_p 0.8, 8k tokens. In parentheses: the share of answers that hit the token limit.

MATH-500 GSM8K IFEval
Base, thinking on 7.4 (93%) 13.0 (89%) 19.2 (76%)
Edited, thinking on 50.2 (32%) 67.6 (7%) 62.1 (2%)
Authors, thinking on 7.9 β†’ 48.1 13.8 β†’ 67.1 21.0 β†’ 62.3
Base, thinking off 45.8 (32%) 57.1 (4%) 52.9 (0.4%)
Edited, thinking off 43.6 (31%) 55.7 (4%) 51.2 (0.1%)

Edited minus base, paired by problem, 95% CI:

MATH-500 GSM8K IFEval
Both thinking on (the paper's claim) +42.8 [39.3, 46.3] +54.7 [52.5, 56.9] +42.9 [39.1, 46.6]
Edited thinking on vs. base thinking off (the base model's best setting) +4.3 [1.9, 6.8] +10.5 [8.3, 12.7] +9.2 [5.2, 13.2]
Both thinking off βˆ’2.2 [βˆ’4.3, βˆ’0.1] βˆ’1.4 [βˆ’3.4, +0.6] βˆ’1.7 [βˆ’4.2, +0.9]

All three of the authors' thinking-on results reproduce within about 2 points. The edited model with thinking on also beats the base model's best setting (thinking off) on every benchmark. With thinking off, the edit costs about 1.5–2 points, which is significant only on MATH-500.

⚠️ This removes a failure mode; it doesn't add capability. Almost all of the gain comes from answers that no longer loop to the token limit.

TODO

  • Independent MATH-500 benchmark
  • GSM8K / IFEval reproduction
  • ONNX / Transformers.js build
  • GGUF (BF16) for llama.cpp / LM Studio / Ollama
  • In-browser demo

Notes

  • The authors' grader (mathqa.py) imports an internal module (mcqa) that isn't in their release. It's only used for loop diagnostics, so the benchmark uses a one-function stand-in and leaves their file untouched.
  • evaluate.py also needs their internal package, so I wrote a small MATH-500 script that copies its prompt, sampling and vLLM settings.
  • Rebuild it yourself with exp8_math/code/apply_edit.py (base revision 2fc06364). The script checks every tensor's hash.

License

The base model is Apache 2.0 Β© Qwen (LICENSE). This is a modified version: 2 tensors changed. The edit is CC BY 4.0, by the authors above.

@misc{takehi2026weightspace,
  title  = {Sparks of Weight-Space Programming: LLMs can natively read \& write neural network weights},
  author = {Takehi, Rikiya and Teoh, Jayden and Zhang, Alex and Khattab, Omar},
  year   = {2026},
  url    = {https://rikiyat.github.io/blog/weight-space-programming/}
}
Downloads last month
975
Safetensors
Model size
0.9B params
Tensor type
BF16
Β·
F32
Β·
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for JonathanColetti/Qwen3.5-0.8B-Astra-WeightEdit

Finetuned
(719)
this model

Space using JonathanColetti/Qwen3.5-0.8B-Astra-WeightEdit 1