跳到主要內容

【2026 最新】Neuron Steering 是什麼?用 Qwen 小模型學會神經元干預、對照與撤回

最後更新: ·
Neuron Steering 神經元干預與撤回教學,使用 Qwen 小模型建立對照

你可能看過 Neuron Steering 示範:原本在解釋冰箱的 AI,改一個內部數字,回答突然繞到老鼠。好奇之餘,更值得問:這是調到某種概念,還是把模型推到失常?

這篇專為第一次接觸模型內部的讀者寫。先用白話搞懂 activation、權重與 steering,再用 Qwen 小模型設計一份能比較、能撤回的實驗。程式段落適合已能執行 Python 的讀者;先讀懂考卷與對照,也能判斷別人的展示是否有說服力。

本文依官方模型設定、框架原始碼與公開研究整理實驗方法,未在本次環境執行模型推論,因此不提供自測成績,也不預告某個編號會出現什麼人格。

先說結論:Neuron Steering=固定權重+暫時改變中間訊號

把模型想成一間餐廳:權重是固定食譜,Prompt 是客人的點單,activation 是廚房這一刻正在處理的材料。推論期 steering 改的是當下材料,後續菜色可能改變;食譜是否真的未動過,要用程式路徑與復原測試確認。

今天的成功標準很務實:同樣的題目,能留下未干預、干預、隨機對照與撤回後的回答,並分清「更像指定風格」和「更能答對」。一段有趣回答,還不足以替某個神經元命名。

一、Neuron Steering 是什麼?先分清五種改法

  • Prompt:「換點單」。改輸入的文字與對話條件,讓模型沿著不同上下文回答。
  • 權重:「換食譜」。訓練學到的參數,是運算中使用的固定係數。
  • LoRA:「替食譜加小份修訂」。典型做法訓練低秩參數,再於推論時套用;它和直接動當下 activation 的介入點不同。
  • Activation:「這道菜做到哪一步」。輸入經過各層運算產生的中間數值,隨題目與 token 改變。
  • Steering:「在製作途中推一下」。在指定層、指定位置加入或替換訊號。單神經元是改某個座標;向量 steering 則可同時改動多個座標。

「神經元」在這裡是 MLP(多層感知器,一段處理特徵的運算)中間向量的一個座標,並非一顆生物腦細胞。CAA 原始研究研究的是從成對範例建立方向,再於推論中加入;這與任選一個原生座標,問的是不同的實驗問題。

Neuron Steering 機制圖:固定權重、暫改中間 activation,移除 hook 後重新生成
固定同一份權重與題目,干預中間訊號;撤回後要重新生成,並核對基線。

二、從一個 Qwen 座標,追到整段回答

選用 Qwen2.5-0.5B-Instruct當教學載體,目的是縮小實驗,不是推薦它代表現有最強模型。其固定 config列出 24 層、MLP 中間維度 4,864。層索引從 0 開始;下面的第 5 號層與第 123 號座標只是操作示例,沒有預先賦予語意。

在 Transformers 4.51.3 的 Qwen2MLP 原始碼,門控與上投影的結果相乘,再送進 down_proj。我們在它收到輸入之前,複製中間向量,只改其中一格。若這格增加 a,送回後續計算的變化就是 a × down_proj.weight[:, n]。

白話說:調同一個旋鈕,會沿著一條固定的寫入方向影響後面各層;後面仍有非線性運算與逐字生成,整篇回答不會只是機械地加上一個詞。正向和負向,也不保證分別對應某個概念與它的反義。

為什麼不把它叫「老鼠開關」?字典學習的原始研究展示了神經元座標與可解釋特徵之間的落差:一格可混合多種訊息,概念也可分散在多格。改動後出現某詞,是值得追的因果線索;要聲稱專一控制某概念,還需跨題目與副作用證據。

三、Neuron Steering 實作:五步建立可撤回的實驗

①「每次真的是同一份模型?」先鎖版本

下面是依固定版本 API 整理的教學程式,尚未在本文環境完成端到端推論。請使用已有 Python 3.11 的獨立工作環境;範例選 CPU 與 float32,方便減少裝置差異,速度與記憶體要自行量測。單純權重以約 5 億參數、每個 4 bytes 粗估約 2GB,執行還需額外空間,不能把這個估算當成最低 RAM 保證。

python3.11 -m venv .venv
source .venv/bin/activate
python -m pip install "torch==2.7.1" "transformers==4.51.3"
python -m pip freeze > requirements-lock.txt

這是刻意固定的教材版本,不是「安裝最新版」指令。模型與 tokenizer 使用相同 revision;第一次執行會下載權重。若你的機器不適合安裝這套環境,先完成第五步的評分表,也能用公開回答練判讀。

②「沒改之前會怎麼答?」先留下基線

將下面完整程式存為 steer_demo.py,再執行 python steer_demo.py。它只測一題以確認接線;do_sample=False 固定貪婪解碼,use_cache=False 讓每次生成重新計算上下文。z[..., n] 會改動該次 forward 的所有 token 位置,因此包括提示與已生成前綴;不是只改最新一字。這會犧牲效率,換取較容易理解的干預範圍。聊天格式依 官方 chat template API建立,避免自己拼錯角色標記。

import json, random, torch, transformers
from pathlib import Path
from transformers import AutoTokenizer, AutoModelForCausalLM

MODEL = "Qwen/Qwen2.5-0.5B-Instruct"
REV = "7ae557604adf67be50417f59c2c2f167def9a775"
torch.manual_seed(42)
torch.set_num_threads(1)
torch.use_deterministic_algorithms(True)
tok = AutoTokenizer.from_pretrained(MODEL, revision=REV)
model = AutoModelForCausalLM.from_pretrained(
    MODEL, revision=REV, torch_dtype=torch.float32,
    attn_implementation="eager", use_safetensors=True,
).cpu().eval()
layer, target = 5, 123
proj = model.model.layers[layer].mlp.down_proj
assert proj.in_features == 4864
prompt = "請用繁體中文、兩句話解釋冰箱如何讓食物降溫。"
x = tok.apply_chat_template(
    [{"role": "user", "content": prompt}],
    tokenize=True, add_generation_prompt=True,
    return_tensors="pt",
)

def run(n=None, dose=0.0):
    handle = None
    if n is not None:
        norm = proj.weight[:, n].float().norm().item()
        if norm == 0:
            raise ValueError("zero column norm")
        def intervene(module, args):
            z = args[0].clone()
            z[..., n] += dose / norm
            return (z,) + args[1:]
        handle = proj.register_forward_pre_hook(intervene)
    try:
        with torch.inference_mode():
            y = model.generate(
                x, attention_mask=torch.ones_like(x),
                do_sample=False, max_new_tokens=64, repetition_penalty=1.0,
                use_cache=False, pad_token_id=tok.eos_token_id,
            )
        return y[0, x.shape[1]:].tolist()
    finally:
        if handle is not None:
            handle.remove()

base = run()
record = {"model": MODEL, "revision": REV,
          "torch": torch.__version__,
          "transformers": transformers.__version__,
          "layer": layer, "target": target, "prompt": prompt,
          "decode": {"do_sample": False, "max_new_tokens": 64,
                     "use_cache": False, "repetition_penalty": 1.0},
          "baseline_tokens": base,
          "baseline_text": tok.decode(base, skip_special_tokens=True),
          "runs": []}
def save():
    Path("results.json").write_text(
        json.dumps(record, ensure_ascii=False, indent=2), encoding="utf-8")
zero = run(target, 0.0)
record.update(zero_tokens=zero, zero_match=(zero == base))
save()
if not record["zero_match"]:
    raise RuntimeError("Zero-dose mismatch: see results.json")
rng = random.Random(20261111)
controls = rng.sample(
    [n for n in range(proj.in_features) if n != target], 3)
record["controls"] = controls
for n in [target] + controls:
    for dose in [0.1, -0.1, 0.2, -0.2]:
        ids = run(n, dose)
        record["runs"].append({"neuron": n, "dose": dose,
                               "tokens": ids,
                               "text": tok.decode(ids, skip_special_tokens=True)})
        save()
restored = run()
record.update(restored_tokens=restored, restored_match=(restored == base))
save()
if not record["restored_match"]:
    raise RuntimeError("Restoration mismatch: see results.json")
print("Saved results.json")

③「推多大才公平?」分開零、正、負劑量

程式先確認零劑量 hook 和無 hook 的 token 相同,再測正負兩個幅度。這裡的 dose 是帶正負號的強度;每個 token 的直接寫入變化,其 L2 長度約為 abs(dose),正負決定方向。程式會除以該神經元對應權重欄的長度,讓不同座標接受同等大小的直接擾動。0.1 與 0.2 是示範測點,不是已驗證的有效或安全閾值。

這套定義和公開 qwen-steering 專案依層的 residual 統計量縮放的 dose 不同。不要把別人的「−1」直接貼進來。改掉劑量公式、施加層、施加 token 範圍,就要視為另一個實驗。

④「只是隨便推都會壞嗎?」加入同層對照

程式以固定種子抽三個同層座標,也跑相同正負劑量。這只是起步控制,不是足以宣告統計顯著的樣本。若目標和隨機座標都同樣跑題,比較合理的暫時判讀是普遍擾動;若目標有穩定特定偏移,再增加隨機樣本與保留題驗證。

⑤「關掉真的回去了?」重新生成再比 token

hook 是掛在模組上的小攔截器。PyTorch 文件說明它能改模組輸入,回傳的 handle 可用 remove() 移除。範例以 try/finally 保證走到清除,再用新生成比較基線;它沒有呼叫 optimizer 或儲存修改後權重。

移除 hook 後,已經產生的文字與舊對話仍留著。因此撤回測試要從同一份原始題目重新開始,不能把受干預的回答貼回對話再測。若最後的復原比對失敗,先檢查殘留 hook、隨機性、環境與輸入;在差異釐清前,不把「可撤回」當成通過。

四、怎麼評分?先看答對,再看風格

跑通一題只證明流程接上。要換題目,請修改 prompt 後重新建立 x;只改文字變數卻沿用舊 token,實際測到的仍是舊題。正式比較前,先寫兩份各至少五題的小考卷:探索題用來選候選座標與劑量,保留題在選完後才打開。每題的全部條件都使用同一 Prompt,並把題目與原始 token 一起保存。

  • 風格題:用繁中寫兩句生日祝福、禮貌拒絕邀約、說明排隊規則;預先定義是否繁體、是否兩句、語氣是否符合要求。
  • 基本正確性題:例如 17+28、依指定鍵名回傳 JSON、從短段落找出日期。先寫正解與格式要求,再看模型輸出。
  • 副作用欄:另記離題、重複、捏造資訊、語言混雜與截斷。遇到 64-token 上限造成的半句,先標截斷,別直接歸因為語言能力損壞。

把條件名稱藏起來、用固定種子打亂回答順序,再按「正確性、遵循格式、目標風格」分項盲評。若請另一個模型評分,也保留它的版本、評分提示與人工可核對的答案。不要讓一句「更像貓娘」掩蓋算術失敗。這與 AI Evals 的驗收觀念一樣:先定義好工作,再判斷改動是否有幫助。

你最後可以得到三種有用結果:行為偏移而品質維持、行為偏移伴隨損傷,或在這些條件下看不出差異。第三種也值得留下;先訂好測點再公開全部回答,能減少只挑驚人案例的偏差。

五、公開展示與 GGUF:哪些可以接著用?

截至 2026 年 11 月 11 日,qwen-steering 的互動解說展示 Qwen3.5-4B 在固定貪婪解碼下,干預某個 MLP 座標會出現主題偏移;其 原始研究庫附有程式與回答材料。這是作者在該模型與設定下的觀察,不能當成 Qwen2.5 的預期結果。

尤其別複製示範中的第 8920 號座標:本篇 Qwen2.5 的中間維度只有 4,864,索引範圍是 0–4863。即使兩個模型維度相同,座標編號也不是共用的概念地址。公開標籤適合當待驗證假設,不能替保留題代考。

「我已下載 GGUF,可以做嗎?」先分清你要做的介入。llama.cpp 官方 cvector-generator 說明提供由 GGUF 模型產生 control vector,並示範以 --control-vector-scaled 與 --control-vector-layer-range 套用。這條路有官方程式可查;它不等於把本文的 PyTorch 模組 hook 原樣搬到另一個執行引擎。

若你選 GGUF 路徑,重新鎖定模型、量化、llama.cpp commit、向量檔與層範圍,並另建基線和對照。本文不提供該 checkpoint 的 GGUF 相容性結論。也不要把改中間訊號和 直接修改權重的實驗混在同一張成績單。

常見問題:八個先講答案的判斷

1. 找到回答會談老鼠的神經元,就找到老鼠概念了?

還不足以。先問效果是否跨保留題穩定、隨機對照如何,以及是否伴隨廣泛失常。

2. 負劑量一定等於反義人格嗎?

不一定。下游運算與生成會放大或改變結果;正負兩側要分開觀察。

3. 把 activation 設零,和 dose=0 一樣嗎?

不同。設零是移除原本數值;本文 dose=0 是不增加任何量,保留原值。

4. 換 Prompt 比較簡單,為何還做 steering?

若目的是改善寫作流程,可先試 Prompt;若目的是研究指定內部位置對輸出的影響,steering 才回答這個問題。

5. 同一題重跑相同,代表跨電腦也逐字相同?

不能這樣外推。PyTorch 的可重現性說明明列跨版本與平台的限制;保存環境,復原檢查先在同一執行環境進行。

6. 移除 hook 後,要把模型權重下載一次嗎?

這份程式只改複製出的中間張量,可先在原模型移除 hook 後重跑。若你另外改過參數或接了其他擴充,應另行檢查那條路徑。

7. 為什麼小模型風格明顯改了,卻更常答錯?

可能同時改動了有用訊號。分開評風格與正確性,才能看出代價;小模型並不保證這兩種目標能獨立控制。

8. 今天先完成什麼才算入門?

先讓無干預、零劑量與移除 hook 後的 token 對上,再看正負劑量與隨機座標。把 results.json 留下來,比替旋鈕取名字更有用。

給新手的三個重點

  • 記住 Neuron Steering=固定權重+暫時改變中間訊號;介入點與施加範圍都要寫清楚。
  • 讓零劑量、正負劑量、隨機對照與撤回後基線一起出現;任何一項失敗都留下紀錄。
  • 把有趣、正確與可用分開評;再到新題目驗證,才能逐步加強因果判斷。

接著閱讀

左右滑動查看更多推薦

下一步:先證明你能把旋鈕關回去

挑一個自己知道答案的簡單問題,先完成基線與撤回,再把同一份題目交給正負劑量及隨機對照。當你能解釋「哪個條件改了、哪種能力受到影響、關掉後是否恢復」,就已經開始做模型實驗。想把這種驗收習慣用進日常 AI 工作,也可接著看 AlphaLab 的 AI 課程,或從 AI 文章總覽挑下一個練習。

ALPHALAB 社群

有問題?來 Telegram 聊

和 Terry、編輯、其他網友一起討論這篇文章。提問、分享觀點,回覆更即時。

加入 Telegram 討論

📩 訂閱 AlphaLab 電子報

週日 Weekly 週報+週二、週四 Alpha Signal,每週最多三封。

我們不會 spam,隨時可退訂。已訂閱?管理訂閱偏好(會寄登入連結到你的信箱)

主題篩選與退訂說明

寄送日期以台灣時間為準。主題偏好會篩選每期精選,並非每篇新文章的即時通知;當期符合主題的文章不足時會略過寄送。

未勾選任何主題會收到所有主題的精選,並不會停止寄信。

取消勾選 Alpha Signal 可停止週二、週四短報,仍保留週日週報。若要停止所有電子報,請使用信件底部的「取消訂閱」。