想象你是一家超大工厂的厂长,工厂里挤着几百万名工人(神经元),原料从大门进去(输入的 token),产品从大门出来(预测的 token)。你一直有个心病:产品里某个行为“为什么会出现”?比如模型突然说“我不能回答这个问题”,到底是哪位工人、哪条流水线决定的?站在厂门口盯着箱子看不出答案。电路分析(Circuit Analysis)就是派出一支“内部审计队”,贴着传送带记录物料轨迹(激活值),最终在喧嚣的车间里找到一小群配合默契的工人,他们专门负责某一种“工序”——比如把上文的某个词复制到预测位置,或是判断“该不该拒绝这个请求”。这样一小群工人连同他们之间的传送路径,就叫一条“电路”。找到电路后,你还能拧动它的阀门(电路编辑)验证它的作用,甚至定向修改模型的行为。这就是机制解释性最迷人的地方:黑盒不再神秘,我们可以拆开它,像拆解一块手表那样看清每个齿轮。

岗位关联

对 AI 从业者而言,掌握电路分析意味着你能从“模型表现如何”进阶到“模型为什么这样做”,无论做安全审计、能力溯源还是精细化调优,都拥有一把手术刀般的诊断工具。

目录
  1. 可视化演示
  2. 电路发现方法
  3. 注意力头功能
  4. 诱导头机制
  5. 复制电路原理
  6. 电路编辑技术
  7. 因果验证方法
  8. 自动化工具
  9. 跨层电路追踪
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示Transformer模型中功能电路的识别与结构,包含注意力头电路发现和因果验证流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

神经网络功能电路 诱导头:跨token位置信息检索 复制电路:token复制与重复 注意力头:QKV计算功能单元 Circuit = {Heads, Connections} 电路是执行特定功能的最小组件集合。

电路发现方法

接管一家来路不明的工厂,几百条传送带交错。你想知道“这个产品是哪些工人做出来的”,可没人有图纸。唯一办法是混进车间,看哪台机器在加工这批货时转得特别快(激活强),哪些机器之间物料流动频繁,然后在地图上圈出一个候选小组。

对应到神经网络,机器的“转速”就是激活值(神经元输出的信号强度)。电路发现的第一步“激活模式定位”,就是在大量输入样本下统计每个神经元对特定任务的响应强度,筛出明显高响应的神经元;第二步“子网络识别”,是沿着这些活跃神经元之间的连接抽出它们组成的子图;第三步“电路边界确定”,则是不断做“断路”实验,把去掉后任务输出不变的连接裁掉,留下的最核心结构就是电路边界。

电路的每次计算,都发生在一层层的线性变换加非线性激活中。给定输入特征 x,当前层的输出 a 这样计算:

a=σ(Wx+b)\displaystyle a = \sigma(Wx + b)

1. 输入特征 x:上一层传来的信号向量,相当于物料进入工位时的状态。

x∈Rdx \in \mathbb{R}^{d}

2. 权重矩阵 W:神经元对输入各维度的重视程度,决定“物料该重点加工哪部分”。

W∈Rd′×dW \in \mathbb{R}^{d' \times d}

3. 偏置 b:神经元自带的倾向值,即使输入为 0 也有一个基础响应。

b∈Rd′b \in \mathbb{R}^{d'}

4. 非线性激活 σ:像闸门一样,让输出不是输入的简单复制,而是有选择地放行或压制。

a=σ(Wx+b)a = \sigma(Wx + b)

就这样,审计队在地图上画出了一条从原料口到产品口的高亮路径,下一步就是走近这条线,看看每一位关键工人到底在做什么——这正是下一节要聊的注意力头。

注意力头功能

在找到的那条生产线上,注意力头就像几位各司其职的“分拣员”。有的擅长“找相同”,只要传送带上出现和前面零件一样的形状,它就立刻亮灯;有的擅长“汇总”,把周围一圈零件的重量取个平均;还有的专职“报位置”,告诉下游这个零件是从第几个货位取来的。

在 Transformer 中,注意力头通过查询(Query)、键(Key)、值(Value)三张表完成一次“定向取货”:Q 发送“我在找什么”的请求,K 表明“我是什么”,两者点乘打分,分数高低决定该从 V 中取多少内容。打分后经过缩放和归一化,变成一组和为 1 的权重。

单个注意力头的计算公式如下:

Attention(Q,K,V)=softmax(QK⊤dk)V\displaystyle \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^{\top}}{\sqrt{d_k}}\right)V

1. 查询矩阵 Q:由当前 token 生成,代表“此刻我在找什么”。

Q=XWQQ = XW_Q

2. 键矩阵 K:由所有位置的 token 生成,代表“每个位置我是什么”。

K=XWKK = XW_K

3. 匹配分数 QKᵀ:查询与所有键做点乘,分数越高表示越匹配。

score(i,j)=qi⋅kj\text{score}(i, j) = q_i \cdot k_j

4. 缩放因子 √d_k:防止维度大时分数过大导致 softmax 饱和,让梯度更稳定。

QK⊤dk\frac{QK^{\top}}{\sqrt{d_k}}

5. softmax 归一化:把分数压成 0 到 1 且和为 1 的注意力权重。

αij=exp⁡(sij)∑kexp⁡(sik)\alpha_{ij} = \frac{\exp(s_{ij})}{\sum_k \exp(s_{ik})}

6. 加权求值:用权重对 V 做加权平均,得到该头的输出。

∑jαijvj\sum_j \alpha_{ij} v_j

就像分拣员先看一眼货位标签(K),再按订单需求(Q)决定从哪些货位(V)拿多少货。搞清楚每个头的分工,接下来才能认出那些“黄金组合”——比如下面要讲的诱导头。

诱导头机制

生产线上有一位记忆力惊人的老员工。他看见当前零件,先回想“这个零件之前是不是也出现过?”,如果记得上一次它出现时后面跟着零件 B,他立刻告诉下游:“接下来很可能是 B!”他不是凭空猜的,而是靠“历史重现”来做预测。

这位老员工在神经网络里就是“诱导头(Induction Head)”。它的经典行为是:在序列 [A, B, A] 中,看到第二个 A 时关注第一个 A,然后把 A 后面的 B 复制到当前预测位置,所以模型倾向于输出 B。它由两个更简单的头协作而成:一个“前缀匹配头”先找出“前文哪里出现过和当前一样的 token”,另一个“复制头”再把那个位置之后的 token 搬过来。

用公式表达,预测下一个 token 的分布正比于所有历史匹配位置的“后续 token 嵌入”的加权和:

P(xn+1)=∑i:xi=xnαn,i ei+1\displaystyle P(x_{n+1}) = \sum_{i: x_i = x_n} \alpha_{n,i} \, e_{i+1}

1. 匹配条件 xᵢ = xₙ:把前文中与当前 token 相同的位置全部找出。

{i∣xi=xn,i<n}\{i \mid x_i = x_n, i < n\}

2. 注意力权重 αₙᵢ:当前 token 对第 i 个历史 token 的关注强度,由前缀匹配头提供。

αn,i=softmax(qn⋅ki)\alpha_{n,i} = \text{softmax}(q_n \cdot k_i)

3. 后续 token 嵌入 eᵢ₊₁:匹配位置之后那个 token 的向量,这是要“复制”的候选答案。

ei+1∈Rde_{i+1} \in \mathbb{R}^{d}

4. 加权求和:多个匹配位置各出一份候选,按关注强度混合,得到预测分布。

P(xn+1)=∑αn,i ei+1P(x_{n+1}) = \sum \alpha_{n,i} \, e_{i+1}

老员工的秘诀是“见过 + 记得后手”。他一个人干不了,还需要一个帮手记录“上次是谁跟在他后面”——这种两人组队的模式,就是电路分析里“两层协作”的经典样例。类似的组合还有复制电路。

复制电路原理

工厂里有个“复印小组”,专门把前文某个位置的词“复印”到当前位置的输出上。和诱导头不同,复印小组不一定要“当前零件出现过”才动手;只要任务需要,比如括号配对、代码补全、引用前文,它都会把远处的信息搬过来。

复制电路(Copy Circuit)通常由一组注意力头构成,它们协作完成“从上下文某个位置取出 token 信息并写入当前位置的残差流,最终影响输出”的全过程。在 A B A → B 这样的任务中,模型就是靠复制电路把第一个 A 后面的 B 搬到预测位置。

把复制电路的作用写进输出,预测词是得分最高的那个:

y^=arg⁡max⁡y  WU(hn+∑m∈CAm(hn))y\displaystyle \hat{y} = \arg\max_y \; W_U \left( h_n + \sum_{m \in \mathcal{C}} A_m(h_n) \right)_y

1. 当前状态 hₙ:当前位置的残差流向量,是所有信息汇聚的“工作台”。

hn∈Rdh_n \in \mathbb{R}^{d}

2. 注意力头输出 Aₘ(hₙ):复制电路中第 m 个头从远处取回的信息。

Am(hn)=∑jαm,jvjA_m(h_n) = \sum_j \alpha_{m,j} v_j

3. 电路集合 C:参与复制任务的一组注意力头,往往不止一个。

C={m1,m2,… }\mathcal{C} = \{m_1, m_2, \dots\}

4. 输出映射 W_U:把残差流状态映射到每个词表的得分。

logits=WU(⋅)\text{logits} = W_U(\cdot)

5. argmax 取最大:得分最高的词就是模型预测的下一个 token。

y^=arg⁡max⁡y logitsy\hat{y} = \arg\max_y \, \text{logits}_y

复印小组的搬运路径在电路图上清晰可见:从“原稿位置”经注意力头到“当前位置”,再经输出层变成最终答案。下次你看到模型补全代码、配对括号时,就可以猜测是复印小组在加班。

电路编辑技术

现在你知道是哪条线在干活了,下一步是“拧阀门”。车间主管想去掉生产线上某个有问题的工位,不必把整条线拆了,只需把那个工位的阀门拧小(甚至关死),看看产品会不会变化。

电路编辑(Circuit Editing)就是对已定位的电路做定向干预:把某个注意力头的输出乘以一个系数(0 表示完全关闭),或把某条路径的权重从模型中“卸载”,从而观察行为如何变化。这种干预比重训整个模型便宜得多,而且作用范围精准。

最常见的编辑操作是对目标头的输出做抑制:

h′=h−η⋅Atarget(h)\displaystyle h' = h - \eta \cdot A_{\text{target}}(h)

1. 原始状态 h:未编辑时该位置的残差流状态。

hh

2. 目标头输出 A_target(h):被选中编辑的注意力头的贡献,比如诱导头中的复制头。

Atarget(h)A_{\text{target}}(h)

3. 抑制系数 η:0 表示完全关掉这个头,0.5 表示把贡献减半。

η∈[0,1]\eta \in [0, 1]

4. 编辑后状态 h′:用编辑后的状态接下游计算,比较模型输出变化。

h′=h−ηAtarget(h)h' = h - \eta A_{\text{target}}(h)

拧阀门比拆机器安全得多,而且可以反复拧回去。这也让电路编辑成了安全修复和模型控制的实用工具——先找到有问题的阀门,再优雅地拧小它。

因果验证方法

光靠“看到某个工位转得快”就断言它是关键,车间主任不答应。你得做个实验:让那个工位临时停工一天,看产量是不是真的掉下来。如果掉了,说明它真是关键环节;如果产量没变,那它可能只是“看着忙”。

这就是因果验证的核心思想。“让工人停工”叫消融(Ablation)——把某个注意力头或神经元的输出置零或替换。更进一步,激活修补(Activation Patching)的做法是:拿一个“损坏样本”(输入被破坏导致模型答错的样本),把干净样本在第 l 层的激活替换成损坏样本的激活,然后看模型输出是否被“带偏”。带偏程度大,说明这条路径对正确答案贡献大。

激活修补的效果度量可写成:

Effect=∥F(xpatch)−F(xclean)∥\displaystyle \text{Effect} = \left\| F(x_{\text{patch}}) - F(x_{\text{clean}}) \right\|

1. 干净样本 x_clean:模型能正确处理的输入。

xcleanx_{\text{clean}}

2. 修补状态 x_patch:把第 l 层激活替换为损坏样本的激活后的输入状态。

xpatch=xclean  with  al←alcorruptx_{\text{patch}} = x_{\text{clean}} \;\text{with}\; a_l \leftarrow a_l^{\text{corrupt}}

3. 模型函数 F:从该层状态出发的后续计算(注意力、MLP、输出层)。

F(⋅)F(\cdot)

4. 范数差异:两个输出向量之间的距离越大,修补的路径越关键。

Effect=∥F(xpatch)−F(xclean)∥\text{Effect} = \|F(x_{\text{patch}}) - F(x_{\text{clean}})\|

通过一次次“停工实验”和“换零件实验”,审计队才能写出可信的电路报告。因果验证也因此被称作电路分析的“试金石”。

自动化工具

工厂太大了,人工盯着几百条传送带太慢。于是工程师给审计队配了自动巡检机器人:它们整夜扫描海量物料轨迹,自动标记每一段传送带的“语义标签”——“这段负责颜色识别”“那段负责位置记忆”。

在真实大模型中,激活维度高达数千甚至上万,人不可能逐个神经元去“访谈”。自动化工具应运而生。最常用的是稀疏自编码器(SAE):它把每个激活向量分解成少量“可解释方向”的加权组合,每个方向往往对应一个清晰的语义概念(比如“这句话在谈论法律”)。有了这些方向,就能更快定位特征对应的神经元和注意力头,再聚合成候选电路。

SAE 的分解重构公式如下:

x≈xb+∑i=1mcidi\displaystyle x \approx x_b + \sum_{i=1}^{m} c_i d_i

1. 原始激活 x:某一层在某个输入下的激活向量,维度很高。

x∈Rdx \in \mathbb{R}^{d}

2. 基线 x_b:平均激活或偏置项,代表“最普通的激活状态”。

xbx_b

3. 可解释方向 d_i:单位向量,代表某个语义特征的方向。

di∈Rd,∥di∥=1d_i \in \mathbb{R}^{d}, \|d_i\| = 1

4. 稀疏系数 c_i:该方向的激活强度,稀疏意味着大多数为 0,少数非零。

ci=ReLU(Wenc(x−xb))ic_i = \text{ReLU}(W_{\text{enc}}(x - x_b))_i

5. 近似重构:用少量非零方向的加权和近似原始激活。

x≈xb+∑cidix \approx x_b + \sum c_i d_i

巡检机器人把“哪些传送带在哪个时刻运送什么语义”记成台账,电路分析员只需读台账就能圈出候选电路,再配合因果验证,整个“发现电路”的流程就自动化、规模化起来了。

跨层电路追踪

电路往往不是单层的——物料要从一楼传到三楼,经过很多工位。审计队最想搞清楚:“哪一段信息是在哪一层被哪种工人加进去的?”于是他们顺着一条贯穿全厂的主传送带,一段一段地检查。

这条主传送带在 Transformer 里叫残差流(Residual Stream)。每一层都是在主传送带上“增量写入”:注意力子层写一笔(跨位置搬运),MLP 子层写一笔(单点加工),传送带本身一直向前,把前面所有层的信息都带在身上。所以电路分析里常把残差流当作“信息叠加的总线”来追踪。

残差流的逐层更新表达式非常简洁:

xl+1=xl+Al(xl)+Ml(xl)\displaystyle x_{l+1} = x_l + A_l(x_l) + M_l(x_l)

1. 第 l 层状态 x_l:进入第 l 层时,主传送带上的累计信息。

xl∈Rdx_l \in \mathbb{R}^{d}

2. 注意力子层 A_l:完成跨位置的信息搬运,读取别处内容写入当前位置。

Al(xl)A_l(x_l)

3. MLP 子层 M_l:对当前位置做单点加工,像给零件打磨抛光。

Ml(xl)M_l(x_l)

4. 加法更新:新状态 = 旧状态 + 注意力增量 + MLP 增量,信息不丢失,只是越叠越厚。

xl+1=xl+Al+Mlx_{l+1} = x_l + A_l + M_l

顺着主传送带,审计队可以精确回答“这条信息是哪一层加的”。如果再配合把中间层状态投影到词表空间观察,就能看到信息在每一层如何一步步变成最终答案——跨层追踪,画出了大模型的“等高线地图”。

AI 应用场景

大模型安全审计:定位越狱漏洞

阶段:安全审计 / 部署前检查

解决的问题:传统安全测试只看输入输出,只知道“这个 prompt 让模型说出了不该说的话”,却不知道是哪条神经通路被利用了。电路分析把“指令跟随”行为对应的电路找出来,再观察越狱输入下这些电路的激活异常,就能定位漏洞源头。

具体案例:某企业客服大模型频繁被“越狱”攻击,泄露系统提示词。可解释性团队对模型进行电路分析,定位到一组负责“服从用户指令”的注意力头。在恶意输入下,其中一个复制头把攻击文本中的指令拷贝到响应位置,绕过安全检查。团队用激活修补验证后,对该头输出做小幅抑制,越狱成功率从 78% 降到 9%,正常对话质量几乎不受影响。

模型能力溯源与幻觉诊断

阶段:模型评估 / 质量诊断

解决的问题:大模型产生幻觉时,工程师不知道错误发生在“记忆提取”还是“上下文整合”环节。跨层电路追踪可以直接回答:这条错误信息是从哪一层、哪个注意力头写入残差流的。

具体案例:某医疗问答模型在长病历场景下频繁出现幻觉。通过残差流追踪,团队发现一个“记忆提取头”错误地关注了病历中一段无关的个人史描述,并将其当作事实写入输出。用路径修补确认该头是主要贡献路径后,团队改进了上下文构造方式(把个人史信息移到更远处),模型幻觉率下降约 30%。

Python 演示

python112 行
import torchimport torch.nn as nnimport torch.nn.functional as F torch.manual_seed(0)VOCAB = 12SEQ = 4D = 16  def attn(q, k, v):    scores = torch.matmul(q, k.transpose(-2, -1)) / (D ** 0.5)    w = F.softmax(scores, dim=-1)    return torch.matmul(w, v)  def make_data(n):    xs, ys = [], []    for _ in range(n):        a = torch.randint(0, VOCAB, (1,)).item()        b = torch.randint(0, VOCAB, (1,)).item()        while b == a:            b = torch.randint(0, VOCAB, (1,)).item()        xs.append(torch.tensor([[a, b, a]]))        ys.append(torch.tensor([b]))    return torch.cat(xs), torch.cat(ys)  class Head(nn.Module):    def __init__(self):        super().__init__()        self.wq = nn.Linear(D, D)        self.wk = nn.Linear(D, D)        self.wv = nn.Linear(D, D)     def forward(self, x):        return attn(self.wq(x), self.wk(x), self.wv(x))  class MiniGPT(nn.Module):    def __init__(self):        super().__init__()        self.tok = nn.Embedding(VOCAB, D)        self.pos = nn.Embedding(SEQ, D)        self.h1a = Head()        self.h1b = Head()        self.h2a = Head()        self.h2b = Head()        self.ln = nn.LayerNorm(D)        self.out = nn.Linear(D, VOCAB)     def forward(self, x, patch=None, replace=None, return_acts=False):        acts = {}        h = self.tok(x) + self.pos(torch.arange(x.shape[1]).unsqueeze(0))        acts['h1a'] = self.h1a(h)        acts['h1b'] = self.h1b(h)        a, b = acts['h1a'], acts['h1b']        if patch == 'h1a':            a = replace        if patch == 'h1b':            b = replace        h = h + a + b        acts['h2a'] = self.h2a(h)        acts['h2b'] = self.h2b(h)        a, b = acts['h2a'], acts['h2b']        if patch == 'h2a':            a = replace        if patch == 'h2b':            b = replace        h = h + a + b        logits = self.out(self.ln(h))        if return_acts:            return logits, acts        return logits  def main():    xs, ys = make_data(4000)    model = MiniGPT()    opt = torch.optim.Adam(model.parameters(), lr=0.01)    for step in range(300):        logits = model(xs)        loss = F.cross_entropy(logits[:, -1], ys)        opt.zero_grad()        loss.backward()        opt.step()        if step % 60 == 0:            print('step', step, 'loss', round(loss.item(), 3))     with torch.no_grad():        acc = (model(xs)[:, -1].argmax(-1) == ys).float().mean().item()        print('训练准确率:', round(acc, 3))         xt, yt = make_data(1)        clean_logits, clean_acts = model(xt, return_acts=True)        clean_p = F.softmax(clean_logits[:, -1], dim=-1)        print('正确token:', yt.item(),              '干净预测概率:', round(clean_p[0, yt.item()].item(), 3))         xc, _ = make_data(1)  # 损坏样本        _, corrupt_acts = model(xc, return_acts=True)         for head in ['h1a', 'h1b', 'h2a', 'h2b']:            patched, _ = model(xt, patch=head,                               replace=corrupt_acts[head], return_acts=True)            p = F.softmax(patched[:, -1], dim=-1)            effect = clean_p[0, yt.item()].item() - p[0, yt.item()].item()            print(head, '修补后正确概率下降:', round(effect, 3))  if __name__ == '__main__':    main()
目的:训练一个极小的两注意力层模型完成 "A B A → B" 复制任务,然后用激活修补(Activation Patching)逐头验证哪些注意力头构成了复制电路。
  1. while b == a: b = torch.randint(...)保证 a、b 不重复,任务要求模型学会“复制前面的 b”而非猜一个相同的数。
  2. class Head(nn.Module)把每个注意力头做成独立模块,便于逐头记录和替换激活。
  3. acts['h1a'] = self.h1a(h)记录第一个注意力头的输出,后面修补实验要用它作为“干净状态”。
  4. if patch == 'h1a': a = replace激活修补的核心:把这个头的输出换成损坏样本的激活。
  5. corrupt_acts = model(xc, return_acts=True)在损坏样本上跑一遍,拿到“被破坏”的各头激活值。
  6. effect = clean_p[0, yt.item()].item() - p[0, yt.item()].item()计算修补后正确 token 概率下降了多大,下降越多说明这个头在电路中越关键。

常见误区

误区以为神经网络里有一条肉眼可见的、预先存在的电路,电路分析就是把它找出来,像翻开电路板看到铜线一样。

正解电路不是预先“画好”的,而是事后通过分析激活模式和干预实验“重构”出来的推断性结构。就像工厂里没人贴过“生产线流程图”,分析员是根据物料轨迹猜出来的。同一个头在不同输入下可能走不同的路,电路更像一张“行为地图”而不是物理线路。

为何常见:“电路”这个词容易让人联想到电路板上的印刷电路,误以为它是固定物理存在。

误区只要把某个神经元或注意力头去掉,模型表现下降,就断定它是电路的必要组成部分。

正解模型有大量冗余和备份,单个节点消融影响不大但多个节点一起消融影响会很大;也可能只是破坏了整体分布而非特定功能。要结合激活修补、路径修补等多种干预实验交叉验证,而不是单次消融就下结论。

为何常见:单变量实验最简单直观,初学者容易把“相关性”当成“因果性”。

误区注意力可视化图中权重越高的连接,就是电路中越关键的路径。

正解注意力权重只表示“关注强度”,真正的作用还要看值向量携带的信息以及它如何影响后续层。一个头可能注意力很集中,但携带的信息对最终答案毫无帮助。只有通过因果干预(如修补)才能判断真实贡献。

为何常见:注意力图是最容易拿到的可视化结果,很多人第一眼就把它当成了“模型思考的证据”。

误区以为把信号从输入层到输出层的传播路径画出来,就等于发现了一条电路。

正解跨层追踪是“画路线”的手段,电路发现还要做功能分离、边界确定和因果验证。追踪只能告诉你信号走了哪条路,不能告诉你这条路是不是“专门负责某功能”的电路。两者是不同环节。

为何常见:工具与方法混淆,初学者看到残差流路径图就以为看到了电路全貌。

面试题

Q1. 电路分析(Circuit Analysis)的核心目标是什么?

单选题 · easy

  • A.提升模型推理速度
  • B.识别功能性子网络← 正确答案
  • C.压缩模型参数量
  • D.改善模型泛化能力

答案:B。电路分析旨在识别神经网络中执行特定功能的子网络(电路),理解计算逻辑。速度优化、参数压缩、泛化改进都是工程目标,不是电路分析的核心。B 准确描述了“找小团队”的本质。

Q2. 注意力头的 Query 向量承担什么职责?

单选题 · easy

  • A.发送我要找什么的请求← 正确答案
  • B.保存被关注者的信息
  • C.计算残差流的增量
  • D.为输出做最终映射

答案:A。Q 由当前 token 生成,表达“我在找什么”;K 表明“我是什么”;V 携带内容。B 是 V 的职责,C/D 与注意力头无关。就像分拣员先看订单(Q)再对货位标签(K)。

Q3. 诱导头的核心行为是什么?

单选题 · easy

  • A.匹配前缀并复制后一个词← 正确答案
  • B.对所有词元做平均池化
  • C.提升低频词元的出现
  • D.抑制与语法无关的信息

答案:A。诱导头在序列中找当前 token 在前文出现的位置,并复制该位置之后的 token。例如 [A, B, A] 预测 B。B/C/D 都不是诱导头的典型行为。

Q4. 激活修补的具体做法是什么?

单选题 · mid

  • A.用损坏样本激活替换干净激活← 正确答案
  • B.给损失函数添加正则项约束
  • C.随机删除模型中一半神经元
  • D.对注意力权重做归一化处理

答案:A。激活修补把干净样本某层激活替换为损坏样本的激活,观察输出是否被“带偏”,从而判断该路径的因果贡献。B 是正则化,C 是随机消融,D 是归一化,都不属于反事实干预。

Q5. 残差流在电路分析中扮演什么角色?

单选题 · mid

  • A.各层输出沿它叠加传递信息← 正确答案
  • B.存储模型训练时的梯度值
  • C.替代注意力头完成特征提取
  • D.用于压缩隐藏层的特征维度

答案:A。残差流是贯穿所有层的主传送带,每层将注意力与 MLP 的输出作为增量写入。它不存梯度、不替代注意力、也不做压缩。跨层电路追踪正是沿着残差流观察信息如何叠加。

Q6. 电路编辑最常见的做法是什么?

单选题 · mid

  • A.缩放或抑制目标头输出← 正确答案
  • B.重新训练全部网络参数
  • C.更换词表并重新初始化
  • D.把注意力头数量手动加倍

答案:A。电路编辑通过缩放/置零特定注意力头的输出,或卸载相关权重,定向改变行为,比重训更轻量精准。B/C/D 都是重量级的全局操作,不符合“拧阀门”的精准思想。

Q7. 关于电路边界确定,正确的理解是什么?

单选题 · hard

  • A.通过干预实验裁剪非必要连接← 正确答案
  • B.电路边界在训练前就已固定
  • C.边界只根据权重数值来判断
  • D.所有被激活的神经元都属于电路

答案:A。电路边界要通过反复断路/修补实验确定:去掉某条连接输出不变,就把它裁掉。训练前不存在固定边界;权重数值不等于功能证据;“被激活”和“必要”是两回事。

Q8. 下列哪些属于因果验证技术?

多选题 · mid

  • A.注意力头消融实验← 正确答案
  • B.激活修补技术← 正确答案
  • C.稀疏自编码器
  • D.路径修补技术← 正确答案

答案:ABD。消融、激活修补、路径修补都是通过干预模型内部状态来验证因果贡献。稀疏自编码器是自动化解释工具,用于分解激活、分离特征,不是因果验证技术。

Q9. 稀疏自编码器在电路发现中能做哪些事?

多选题 · hard

  • A.把高维激活分解为稀疏方向← 正确答案
  • B.帮助定位特征对应神经元← 正确答案
  • C.直接替代需要人工标注的测试集
  • D.自动计算模型输出层梯度

答案:AB。SAE 将高维激活分解为少量可解释方向,这些方向可对应到具体神经元或注意力头,从而辅助电路发现。它不生成测试集,也不计算梯度,C/D 是干扰项。

Q10. 关于跨层电路追踪的正确说法是什么?

多选题 · extreme

  • A.借助残差流观察信息跨层累积← 正确答案
  • B.把中间层状态投影到词表空间← 正确答案
  • C.追踪结果可直接证明因果作用
  • D.需要结合干预实验交叉验证← 正确答案

答案:ABD。跨层追踪沿残差流观察信息如何逐层累积,也可用投影方法查看中间状态对应哪个词。但“看到路径”不等于“证明因果”,必须结合激活修补等干预实验验证,C 错误。