用线性规划复现MIT权重空间编程,8小时搜索变1分钟
Can a Linear Program Do Weight-Space Programming?
把MIT最新论文中的黑盒搜索转化为可复现的线性规划解法,给出具体公式和代码逻辑,做模型干预的同学可以直接照做。
Last week, MIT CSAIL published Sparks of Weight-Space Programming. Given the raw weights of a small network, GPT-6 Astra could tell which game it had been trained to play. Given only a game’s rules, it could write the weights of a small network from scratch and beat networks trained with PPO for 100 million steps. No gradients, no training loop, just reasoning about what the weights compute. They coined this weight-space programming.
上周,MIT CSAIL 发布了《Weight-Space Programming 的火花》。给定一个小网络的原始权重,GPT-6 Astra 能够判断它被训练用于玩哪个游戏。仅给定游戏规则,它就能从零开始编写一个小网络的权重,并击败经过 1 亿步 PPO 训练的网络。无需梯度,无需训练循环,只需推理权重所计算的内容。他们称此为 weight-space programming(权重空间编程)。
In another experiment, they asked Astra to make Qwen3.5-0.8B better at math by editing its weights. Astra changed only 0.016% of the weights, and MATH-500 accuracy jumped from 7.9% to 48.1%.1
在另一项实验中,他们要求 Astra 通过编辑权重来改善 Qwen3.5-0.8B 的数学能力。Astra 仅修改了 0.016% 的权重,MATH-500 准确率从 7.9% 跃升至 48.1%。1
Looking at Astra’s edit, I realized most of its search was solving a linear program by trial and error. It spent about 8 hours and 28 forward passes choosing which weights to change and by how much. A couple of LP solves, about a minute each, do the same job with 8× fewer changed weights. In this post I’ll walk through the edit, why it’s an LP, and what that says about the fix itself.
观察 Astra 的编辑结果后,我意识到它的搜索过程大部分是在通过试错法求解线性规划问题。它花费了约 8 小时和 28 次前向传播来选择要修改哪些权重以及修改多少。而几次线性规划求解(每次约一分钟)能以少 8 倍的权重修改量完成相同任务。在这篇文章中,我将逐步解析该编辑、说明其为线性规划的原因,以及这反映了关于修复本身的什么信息。
Thinking loops#
思考循环#
Small reasoning models have a common failure: they get stuck in thinking loops, repeating the same few lines over and over instead of finishing their reasoning. Qwen3.5-0.8B is especially prone to it, and its model card says so. On MATH-500, 93% of the base model’s answers ran into the 32,768-token limit without ever reaching an answer.
小型推理模型存在一个常见缺陷:它们会陷入思考循环,反复重复相同的几行内容,而不是完成推理。Qwen3.5-0.8B 尤其容易出现此问题,其模型卡片中也明确提及。在 MATH-500 上,基座模型 93% 的回答因达到 32,768 个 token 的限制而未能得出答案。
The edit fixes the loops, so it helps anywhere the model loops. That includes instruction following: IFEval went from 21% to 62%.
该编辑修复了循环问题,因此有助于解决模型出现循环的任何场景。其中包括指令遵循能力:IFEval 得分从 21% 提升至 62%。
| Qwen3.5-0.8B | MATH-500 | GSM8K | IFEval | Hit token limit |
|---|---|---|---|---|
| Base | 7.9 | 13.8 | 21.0 | 93.0% |
| Astra’s edit | 48.1 | 67.1 | 62.3 | 33.1% |
| Qwen3.5-0.8B | MATH-500 | GSM8K | IFEval | 达到 token 限制 |
|---|---|---|---|---|
| 基座模型 | 7.9 | 13.8 | 21.0 | 93.0% |
| Astra 的编辑 | 48.1 | 67.1 | 62.3 | 33.1% |
On Gemma 3 270M, which rarely loops, Astra couldn’t meaningfully improve its math ability. As the authors put it, editing the weights could remove an obstacle hiding an ability, but couldn’t add one the model lacked.
在几乎不会循环的 Gemma 3 270M 上,Astra 无法显著提升其数学能力。正如作者所述,编辑权重可以移除隐藏某种能力的障碍,但无法为模型增添其原本缺乏的能力。
How Astra fixed the loops#
Astra 如何修复循环#
Transformers use residual connections: each layer’s output is added to its input rather than replacing it. Follow one token through the network and you get a single vector that every layer adds to, called the residual stream (1,024-dimensional in this model). When the model is looping, the residual stream shifts in a consistent direction. Astra’s fix was to edit two layers so that what they add points the opposite way.
Transformer 使用残差连接:每层的输出是加到输入上,而非替换输入。追踪单个 token 在网络中的流动,你会得到一个向量,每一层都会向其添加值,称为残差流(在本模型中为 1,024 维)。当模型处于循环状态时,残差流会沿一致方向偏移。Astra 的修复方法是编辑两个层,使其添加的方向相反。
Finding the loop direction#
寻找循环方向#
Astra wrote four pairs of short texts, each a piece of productive reasoning and a looping version of the same reasoning. It ran all eight through the model and recorded each token’s residual stream vector at one layer. Averaging over the looping texts gives one vector, and averaging over the productive texts gives another. Their difference, normalized, is the loop direction $u$: the way the residual stream moves when the model loops.
Astra 写了四对短文本,每对都是一段生产性推理(productive reasoning),也是同一段推理的循环版本。它将这八段文本全部输入模型,并记录了每一层中每个 token 的残差流向量。对循环文本取平均得到一个向量,对生产性文本取平均得到另一个向量。两者之差经归一化后即为循环方向 $u$:模型在循环时残差流的移动方式。
Editing the weights#
编辑权重#
Each MLP ends with a matrix $W$ (called down_proj). At every token, it turns the MLP’s 3,584-dimensional hidden activation $h$ into a 1,024-dimensional output $Wh$, which gets added to the residual stream $x$:
每个 MLP 以矩阵 $W$(称为 down_proj)结尾。在每个 token 处,它将 MLP 的 3,584 维隐藏激活值 $h$ 转换为 1,024 维输出 $Wh$,然后将其加到残差流 $x$ 上:
$$x \leftarrow x + Wh, \qquad Wh = \sum_j h_j \, w_j$$
So the MLP’s output is always a weighted sum of the same 3,584 vectors, the columns $w_j$ of $W$. $W$ fixes what those vectors are; the activations $h_j$ decide how much of each one gets added at each token.
因此,MLP 的输出始终是相同的 3,584 个向量的加权求和,即 $W$ 的列 $w_j$。$W$ 固定了这些向量是什么;激活值 $h_j$ 决定了在每个 token 处添加每个向量的多少。
Each column points partly along $u$. That amount, $u^\top w_j$, is how much column $j$ pushes the model toward looping whenever $h_j$ is active. Astra’s edit subtracts a multiple $\alpha$ of it:
每一列都部分指向 $u$。该分量 $u^\top w_j$ 表示每当 $h_j$ 处于活跃状态时,第 $j$ 列将模型推向循环的程度。Astra 的编辑减去了它的倍数 $\alpha$:
$$w_j \to w_j - \alpha \, (u^\top w_j) \, u$$
At $\alpha = 1$ the component along $u$ is gone, so the column no longer pushes toward looping. Doing this to every column in layers 15 and 19 took accuracy from 9% to 33% on GSM8K and MATH training problems. At $\alpha = 6$ the component is flipped: a column that wrote $+a$ along $u$ now writes $-5a$, and pushes the model away from looping whenever it’s used.
当 $\alpha = 1$ 时,沿 $u$ 的分量消失,因此该列不再推动模型进入循环。对第 15 层和第 19 层的所有列执行此操作,使 GSM8K 和 MATH 训练问题的准确率从 9% 提升至 33%。当 $\alpha = 6$ 时,该分量被翻转:原本沿 $u$ 写入 $+a$ 的列现在写入 $-5a$,并在每次使用时将模型推离循环。
Every edited column changes by a multiple of the same vector $u$. So the whole edit is one direction $u$ plus one number per column, $v_j = -\alpha\,(u^\top w_j)$, which is zero for columns left alone. That’s a rank-1 change:
每个被编辑的列都变化为同一向量 $u$ 的倍数。因此,整个编辑是一个方向 $u$ 加上每列的一个数值 $v_j = -\alpha\,(u^\top w_j)$,对于未修改的列,该值为零。这是一个秩-1 更新:
$$\Delta W = u\,v^\top$$
At each token, it adds $(v \cdot h_t)\,u$ to the residual stream: some amount of $u$, set by how active the edited columns are. No other direction changes.
在每个 token 处,它向残差流添加 $(v \cdot h_t)\,u$:一定量的 $u$,由被编辑列的活跃程度决定。没有其他方向发生变化。
That leaves $v$ to choose: which columns to edit, and how large $\alpha$ should be. Astra worked it out by trial and error, testing each edit on a fresh batch of those training problems:
这就留下了选择 $v$ 的任务:编辑哪些列,以及 $\alpha$ 应该多大。Astra 通过试错法确定了这一点,在每批新的训练问题上测试每次编辑:
| Edit on layers 15 and 19 | Accuracy |
|---|---|
| Base model | ~9% |
| Every column, α = 1 | 33% |
| Every column, α = 2 | 43% |
| Every column, α = 3 | 48% |
| Random direction (control) | 12.5% |
| Top 64 columns, α = 6 | 55% |
| 在第 15 层和第 19 层进行编辑 | 准确率 |
|---|---|
| 基础模型 | ~9% |
| 所有列,α = 1 | 33% |
| 所有列,α = 2 | 43% |
| 所有列,α = 3 | 48% |
| 随机方向(控制组) | 12.5% |
| 前 64 列,α = 6 | 55% |
Pushing harder than $\alpha = 1$ helped more, and a random direction did nothing. The final edit used $\alpha = 6$ on only the 64 columns per layer that wrote the most $u$ on looping text.
比 $\alpha = 1$ 更强的推动带来了更多帮助,而随机方向毫无作用。最终编辑仅对每层中在循环文本上写入最多 $u$ 的 64 列使用 $\alpha = 6$。
Where the time went#
时间都去哪儿了#
The paper released Astra’s full logs: every tool call, every forward pass, every note it wrote to itself. Astra had a Python kernel with the weights loaded and a budget of 50 forward passes, each a batched run of the model on training problems or texts of its choosing.
该论文发布了 Astra 的完整日志:每一次工具调用、每一次前向传播,以及它写给自己的每一条笔记。Astra 拥有一个加载了权重的 Python 内核,并拥有 50 次前向传播的预算,每次都是在其选择的训练问题或文本上对模型进行的批量运行。
The edit was frozen after about 10 hours, and the last 17 passes re-tested it without changing anything.2 Of those 10 hours, finding $u$ took 15 minutes. Finding $v$ took about 8 hours.
编辑在大约 10 小时后被冻结,最后 17 次前向传播重新测试了它,但未做任何更改。2 在这 10 小时中,找到 $u$ 花了 15 分钟。找到 $v$ 花了大约 8 小时。
Choosing v is a linear program#
选择 v 是一个线性规划问题#
Astra was searching for a $v$ that strongly pushes looping tokens away from $u$ while barely touching productive ones. Since the push at token $t$ is $v \cdot h_t$, linear in $v$, both requirements are linear inequalities.
Astra 正在寻找一个 $v$,它能强烈地将循环令牌从 $u$ 推开,同时几乎不触碰那些有生产力的令牌。由于在令牌 $t$ 处的推力是 $v \cdot h_t$,且关于 $v$ 是线性的,因此这两个要求都是线性不等式。
I labeled tokens from the base model’s own traces: looping tokens ($R$), deep inside a loop, and productive tokens ($P$), well before any loop starts,3 and recorded their activations $h_t$ at layers 15 and 19. Each one becomes a constraint, and the LP picks the $v$ with the smallest L1 norm $\sum_j |v_j|$:
我标记了基础模型自身轨迹中的令牌:循环令牌($R$),即处于循环深处;以及有生产力的令牌($P$),即在任何循环开始之前很久,3 并记录了它们在第 15 层和第 19 层的激活值 $h_t$。每一个都成为一个约束条件,而线性规划(LP)会选择具有最小 L1 范数 $\sum_j |v_j|$ 的 $v$:
$$ \begin{aligned} \min_v \quad & \sum_j |v_j| \\ \text{s.t.} \quad & v \cdot h_t \le -\delta && t \in R \quad \text{(at least } \delta \text{ away from } u\text{)} \\ & |v \cdot h_t| \le \varepsilon && t \in P \quad \text{(at most } \varepsilon\text{)} \end{aligned} $$
$$ \begin{aligned} \min_v \quad & \sum_j |v_j| \\ \text{s.t.} \quad & v \cdot h_t \le -\delta && t \in R \quad \text{(至少距离 } u \text{ 为 } \delta \text{)} \\ & |v \cdot h_t| \le \varepsilon && t \in P \quad \text{(最多为 } \varepsilon\text{)} \end{aligned} $$
In practice no $v$ satisfies every constraint, so each one gets a penalized slack variable.
在实践中,没有哪个 $v$ 能满足所有约束条件,因此每个约束条件都会获得一个带惩罚的松弛变量。
Minimizing L1 tends to make $v$ sparse. The L1 ball is a diamond, and when you grow it until it touches the feasible region, it usually touches at a corner, where most coordinates are exactly zero. So the LP picks the columns as well as the amounts.
最小化 L1 往往会使 $v$ 变得稀疏。L1 球体是一个菱形,当你将其扩大直到接触可行区域时,它通常会接触到某个角点,在那里大多数坐标恰好为零。因此,线性规划既选择了列,也确定了数量。
To get exactly 8 columns per layer, I kept the 8 with the largest effect and solved again with the rest fixed at zero.4
为了每层恰好得到 8 个列,我保留了影响最大的 8 个,并在其余部分固定为零的情况下重新求解。4
That replaces Astra’s 8-hour search, including its choice of columns and $\alpha$, with a couple of LP solves. An off-the-shelf solver (HiGHS) took over 20 minutes each on these constraints, so I wrote a GPU solver (PDHG, the algorithm behind PDLP) that gets within 0.2% of its optimum in about a minute.5
这用几次线性规划求解取代了 Astra 的 8 小时搜索,包括其列和 $\alpha$ 的选择。现成的求解器(HiGHS)在这些约束条件下各花费了超过 20 分钟,因此我编写了一个 GPU 求解器(PDHG,即 PDLP 背后的算法),它在大约一分钟内就能达到其最优值的 0.2% 以内。5
Results#
结果#
I tested two LP edits. Both use Astra’s layers. One uses Astra’s direction $u$. The other uses a heuristic direction: label tokens in the model’s own traces as looping or productive with a simple repetition detector, then take the difference of their average residual streams. It’s the same recipe Astra used, minus the hand-written texts, so no LLM is involved. I tuned the LP’s settings on a separate 128-problem dev set; everything in the chart and table is on data never used for fitting or tuning.
我测试了两种 LP 编辑。两者都使用 Astra 的层。一种使用 Astra 的方向 $u$。另一种使用启发式方向:用简单的重复检测器将模型自身轨迹中的标签标记为循环或生产性,然后取它们平均残差流的差值。这与 Astra 使用的配方相同,只是去掉了手写文本,因此不涉及 LLM。我在一个独立的 128 题开发集上调整了 LP 的设置;图表和表中的所有数据都是从未用于拟合或调优的数据。
| Changed weights | GSM8K test | MATH-500 | IFEval | |
|---|---|---|---|---|
| Base model | 0 | 14.1 | 7.0 | 22.9 |
| Astra’s edit | 130,188 | 68.2 | 50.9 | 61.9 |
| LP, Astra’s direction | 16,291 | 69.6 | 51.7 | 59.7 |
| LP, heuristic direction | 16,271 | 65.4 | 47.8 | 60.4 |
| 更改权重 | GSM8K 测试 | MATH-500 | IFEval | |
|---|---|---|---|---|
| 基础模型 | 0 | 14.1 | 7.0 | 22.9 |
| Astra 的编辑 | 130,188 | 68.2 | 50.9 | 61.9 |
| LP,Astra 的方向 | 16,291 | 69.6 | 51.7 | 59.7 |
| LP,启发式方向 | 16,271 | 65.4 | 47.8 | 60.4 |
With Astra’s direction, the LP matches Astra’s edit on every benchmark, within noise, while changing 8× fewer weights. With the heuristic direction, it gets about 93% of the way there.
使用 Astra 的方向时,LP 在每项基准测试中与 Astra 的编辑表现相当(在噪声范围内),同时更改的权重减少了 8 倍。使用启发式方向时,它达到了大约 93% 的效果。
A few other things showed up:
还出现了其他一些情况:
更进一步:量化金融体系
看懂新闻只是起点——沿量化金融路径,把它变成能交付的工程能力