Views
No views yet

| Property | Value |
|---|---|
| Base model | Qwen3.5-2B |
SAE width (d_sae) | 32768 |
Hidden size (d_model) | 2048 |
| Expansion factor | 16× |
| Top-K | 50 |
| Hook point | Residual stream |
| Layers covered | 0 – 23 (24 layers total) |
| File format | PyTorch .pt dict |
layer{n}.sae.pt is a Python dict with four tensors:| Key | Shape | Description |
|---|---|---|
W_enc | (32768, 2048) | Encoder weight matrix |
W_dec | (2048, 32768) | Decoder weight matrix |
b_enc | (32768,) | Encoder bias |
b_dec | (2048,) | Decoder bias |
layer0.sae.pt
layer1.sae.pt
...
layer23.sae.pt1import torch
2from transformers import AutoTokenizer, AutoModelForCausalLM
3
4# ── 1. Load base model ────────────────────────────────────────────────────────
5model_name = "Qwen/Qwen3.5-2B"
6tokenizer = AutoTokenizer.from_pretrained(model_name)
7model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.float32)
8model.eval()
9
10# ── 2. Load SAE for a target layer ───────────────────────────────────────────
11LAYER = 0 # choose any layer in 0–23
12sae = torch.load(f"layer{LAYER}.sae.pt", map_location="cpu")
13W_enc = sae["W_enc"] # (32768, 2048)
14b_enc = sae["b_enc"] # (32768,)
15
16def get_feature_acts(residual: torch.Tensor) -> torch.Tensor:
17 """residual: (..., 2048) → sparse feature activations (..., 32768)"""
18 pre_acts = residual @ W_enc.T + b_enc
19 topk_vals, topk_idx = pre_acts.topk(50, dim=-1)
20 acts = torch.zeros_like(pre_acts)
21 acts.scatter_(-1, topk_idx, topk_vals)
22 return acts
23
24# ── 3. Hook residual stream after the target transformer layer ────────────────
25captured = {}
26
27def _hook(module, input, output):
28 hidden = output[0] if isinstance(output, tuple) else output
29 captured["residual"] = hidden.detach().cpu()
30
31hook = model.model.layers[LAYER].register_forward_hook(_hook)
32
33# ── 4. Forward pass ───────────────────────────────────────────────────────────
34text = "The capital of France is"
35inputs = tokenizer(text, return_tensors="pt")
36with torch.no_grad():
37 model(**inputs)
38hook.remove()
39
40# ── 5. Extract feature activations ───────────────────────────────────────────
41residual = captured["residual"] # (1, seq_len, 2048)
42feature_acts = get_feature_acts(residual) # (1, seq_len, 32768)
43
44# Inspect active features for the last token
45last_token_acts = feature_acts[0, -1] # (32768,)
46active_idx = last_token_acts.nonzero(as_tuple=True)[0]
47print(f"Active features : {active_idx.tolist()}")
48print(f"Feature values : {last_token_acts[active_idx].tolist()}")app.py. You can run it locally:python app.py \
--model Qwen/Qwen3.5-2B \
--model-name-sae-trained-from qwen3.5-2b-base \
--model-name-analyzing-now qwen3.5-2b \
--sae-path Qwen/SAE-Res-Qwen3.5-2B-Base-W32K-L0_50 \
--top-k 50 \
--num-layers 24 \
--sae-width 32768 \
--d-model 2048 \
--server-port 78601@misc{qwen_scope,
2 title = {{Qwen-Scope}: Turning Sparse Features into Development Tools for Large Language Models},
3 url = {https://qianwen-res.oss-accelerate.aliyuncs.com/qwen-scope/Qwen_Scope.pdf},
4 author = {{Qwen Team}},
5 month = {April},
6 year = {2026}
7}