juiceb0xc0de commited on
Commit
99d89e0
·
1 Parent(s): 536f664

Add EXAONE layer/attention/MLP name aliases; attn/trust flags

Browse files
1.ipynb ADDED
File without changes
analyze_ov_circuits.py CHANGED
@@ -93,13 +93,23 @@ def run(model_id: str, output: Path, token: str | None = None, trust_remote_code
93
  for layer_idx, layer in enumerate(layers):
94
  attn = getattr(layer, "self_attn", None)
95
  if attn is None:
96
- print(f"[ov] layer {layer_idx}: no self_attn, skipping")
 
 
97
  continue
98
 
99
- q_proj = attn.q_proj
100
- k_proj = attn.k_proj
101
- v_proj = attn.v_proj
102
- o_proj = attn.o_proj
 
 
 
 
 
 
 
 
103
 
104
  n_heads = getattr(attn, "num_heads", None)
105
  n_kv_heads = getattr(attn, "num_key_value_heads", None)
 
93
  for layer_idx, layer in enumerate(layers):
94
  attn = getattr(layer, "self_attn", None)
95
  if attn is None:
96
+ attn = getattr(layer, "attn", None)
97
+ if attn is None:
98
+ print(f"[ov] layer {layer_idx}: no self_attn/attn, skipping")
99
  continue
100
 
101
+ # EXAONE nests attention under attn.attention.
102
+ if hasattr(attn, "attention"):
103
+ attn = attn.attention
104
+
105
+ q_proj = getattr(attn, "q_proj", None)
106
+ k_proj = getattr(attn, "k_proj", None)
107
+ v_proj = getattr(attn, "v_proj", None)
108
+ o_proj = getattr(attn, "o_proj", None) or getattr(attn, "out_proj", None)
109
+
110
+ if q_proj is None or k_proj is None or v_proj is None or o_proj is None:
111
+ print(f"[ov] layer {layer_idx}: missing projections, skipping")
112
+ continue
113
 
114
  n_heads = getattr(attn, "num_heads", None)
115
  n_kv_heads = getattr(attn, "num_key_value_heads", None)
qwip_atlas/layers.py CHANGED
@@ -20,22 +20,55 @@ def parse_layer_spec(spec: str) -> list[int]:
20
 
21
 
22
  def layers_container(model: Any):
23
- """Find the module that owns the decoder `layers` ModuleList."""
 
 
 
24
  import torch.nn as nn
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  queue = deque([model])
 
27
  while queue:
28
  module = queue.popleft()
29
- layers = getattr(module, "layers", None)
30
- if isinstance(layers, nn.ModuleList) and len(layers) > 0:
31
- return module
 
 
32
  for _, child in module.named_children():
33
  queue.append(child)
 
 
34
  raise RuntimeError(f"Cannot find decoder layers ModuleList on {type(model).__name__}")
35
 
36
 
37
  def resolve_layers(model: Any) -> list[Any]:
38
- return list(layers_container(model).layers)
 
 
 
 
 
39
 
40
 
41
  def inspect_layer(layer_mod: Any, text_cfg: Any) -> dict[str, Any]:
@@ -65,9 +98,27 @@ def inspect_layer(layer_mod: Any, text_cfg: Any) -> dict[str, Any]:
65
  mlp = getattr(layer_mod, "mlp", None) or getattr(layer_mod, "feed_forward", None)
66
  if mlp is not None:
67
  info["mlp"]["module"] = mlp
68
- info["mlp"]["down_proj"] = getattr(mlp, "down_proj", None) or getattr(mlp, "wo", None)
69
- info["mlp"]["gate_proj"] = getattr(mlp, "gate_proj", None) or getattr(mlp, "w1", None)
70
- info["mlp"]["up_proj"] = getattr(mlp, "up_proj", None) or getattr(mlp, "w3", None)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  info["mlp"]["act_fn"] = getattr(mlp, "act_fn", None)
72
  down_proj = info["mlp"]["down_proj"]
73
  if down_proj is not None and hasattr(down_proj, "in_features"):
@@ -81,6 +132,10 @@ def inspect_layer(layer_mod: Any, text_cfg: Any) -> dict[str, Any]:
81
  if attn is not None:
82
  info["attn"]["module"] = attn
83
  info["attn"]["class_name"] = type(attn).__name__
 
 
 
 
84
  info["attn"]["q_proj"] = getattr(attn, "q_proj", None)
85
  info["attn"]["k_proj"] = getattr(attn, "k_proj", None)
86
  info["attn"]["v_proj"] = getattr(attn, "v_proj", None)
 
20
 
21
 
22
  def layers_container(model: Any):
23
+ """Find the module that owns the decoder layers ModuleList.
24
+
25
+ Handles both standard `.layers` (Llama-style) and GPT-NeoX-style `.h`.
26
+ """
27
  import torch.nn as nn
28
 
29
+ # Direct known aliases first.
30
+ transformer = getattr(model, "transformer", None)
31
+ if transformer is not None:
32
+ h = getattr(transformer, "h", None)
33
+ if isinstance(h, nn.ModuleList) and len(h) > 0:
34
+ return transformer
35
+ layers = getattr(transformer, "layers", None)
36
+ if isinstance(layers, nn.ModuleList) and len(layers) > 0:
37
+ return transformer
38
+
39
+ model_module = getattr(model, "model", None)
40
+ if model_module is not None:
41
+ h = getattr(model_module, "h", None)
42
+ if isinstance(h, nn.ModuleList) and len(h) > 0:
43
+ return model_module
44
+ layers = getattr(model_module, "layers", None)
45
+ if isinstance(layers, nn.ModuleList) and len(layers) > 0:
46
+ return model_module
47
+
48
+ # BFS fallback.
49
  queue = deque([model])
50
+ best = None
51
  while queue:
52
  module = queue.popleft()
53
+ for attr_name in ("layers", "h"):
54
+ layers = getattr(module, attr_name, None)
55
+ if isinstance(layers, nn.ModuleList) and len(layers) > 0:
56
+ # Prefer the deepest container (closest to actual decoder layers).
57
+ best = module
58
  for _, child in module.named_children():
59
  queue.append(child)
60
+ if best is not None:
61
+ return best
62
  raise RuntimeError(f"Cannot find decoder layers ModuleList on {type(model).__name__}")
63
 
64
 
65
  def resolve_layers(model: Any) -> list[Any]:
66
+ container = layers_container(model)
67
+ for attr_name in ("h", "layers"):
68
+ layers = getattr(container, attr_name, None)
69
+ if layers is not None:
70
+ return list(layers)
71
+ raise RuntimeError(f"Cannot enumerate layers from {type(container).__name__}")
72
 
73
 
74
  def inspect_layer(layer_mod: Any, text_cfg: Any) -> dict[str, Any]:
 
98
  mlp = getattr(layer_mod, "mlp", None) or getattr(layer_mod, "feed_forward", None)
99
  if mlp is not None:
100
  info["mlp"]["module"] = mlp
101
+ # Llama/Gemma/Phi style
102
+ down_proj = getattr(mlp, "down_proj", None)
103
+ gate_proj = getattr(mlp, "gate_proj", None)
104
+ up_proj = getattr(mlp, "up_proj", None)
105
+ # GPT-NeoX / EXAONE style
106
+ if down_proj is None:
107
+ down_proj = getattr(mlp, "c_proj", None)
108
+ if gate_proj is None:
109
+ gate_proj = getattr(mlp, "c_fc_0", None) or getattr(mlp, "c_fc", None)
110
+ if up_proj is None:
111
+ up_proj = getattr(mlp, "c_fc_1", None)
112
+ # Mixtral/Mistral older names
113
+ if down_proj is None:
114
+ down_proj = getattr(mlp, "wo", None)
115
+ if gate_proj is None:
116
+ gate_proj = getattr(mlp, "w1", None)
117
+ if up_proj is None:
118
+ up_proj = getattr(mlp, "w3", None)
119
+ info["mlp"]["down_proj"] = down_proj
120
+ info["mlp"]["gate_proj"] = gate_proj
121
+ info["mlp"]["up_proj"] = up_proj
122
  info["mlp"]["act_fn"] = getattr(mlp, "act_fn", None)
123
  down_proj = info["mlp"]["down_proj"]
124
  if down_proj is not None and hasattr(down_proj, "in_features"):
 
132
  if attn is not None:
133
  info["attn"]["module"] = attn
134
  info["attn"]["class_name"] = type(attn).__name__
135
+ # EXAONE nests attention under attn.attention; most models use attn directly.
136
+ if hasattr(attn, "attention"):
137
+ attn = attn.attention
138
+
139
  info["attn"]["q_proj"] = getattr(attn, "q_proj", None)
140
  info["attn"]["k_proj"] = getattr(attn, "k_proj", None)
141
  info["attn"]["v_proj"] = getattr(attn, "v_proj", None)
qwip_atlas/sub_zero_surgery.py CHANGED
@@ -326,36 +326,64 @@ def _model_device(model: torch.nn.Module) -> torch.device:
326
 
327
 
328
  def _resolve_layers(model: torch.nn.Module) -> List[torch.nn.Module]:
329
- """Find the layers ModuleList in a model."""
 
330
  from collections import deque
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
  queue = deque([model])
332
  while queue:
333
  m = queue.popleft()
334
- layers = getattr(m, "layers", None)
335
- if isinstance(layers, torch.nn.ModuleList) and len(layers) > 0:
336
- return list(layers)
 
337
  for _, child in m.named_children():
338
  queue.append(child)
339
- raise RuntimeError(f"Cannot find layers ModuleList on {type(model).__name__}")
340
 
341
 
342
  def _get_projection_map(layer: torch.nn.Module) -> Dict[str, torch.nn.Module]:
343
  """Get projection modules for a layer."""
344
  result = {}
345
- # MLP projections
346
  mlp = getattr(layer, "mlp", None)
347
  if mlp is not None:
348
- for name in ["gate_proj", "up_proj", "down_proj"]:
349
- mod = getattr(mlp, name, None)
350
- if mod is not None and hasattr(mod, "weight"):
351
- result[name] = mod
 
 
 
 
 
 
 
352
  # Attention projections
353
  attn = getattr(layer, "self_attn", None) or getattr(layer, "attention", None) or getattr(layer, "attn", None)
 
 
354
  if attn is not None:
355
- for name in ["q_proj", "k_proj", "v_proj", "o_proj"]:
356
  mod = getattr(attn, name, None)
357
  if mod is not None and hasattr(mod, "weight"):
358
- result[name] = mod
 
 
359
  return result
360
 
361
 
 
326
 
327
 
328
  def _resolve_layers(model: torch.nn.Module) -> List[torch.nn.Module]:
329
+ """Find the decoder layers in a model. Handles Llama-style .layers and
330
+ GPT-NeoX/EXAONE-style transformer.h."""
331
  from collections import deque
332
+
333
+ transformer = getattr(model, "transformer", None)
334
+ if transformer is not None:
335
+ for attr in ("h", "layers"):
336
+ layers = getattr(transformer, attr, None)
337
+ if isinstance(layers, torch.nn.ModuleList) and len(layers) > 0:
338
+ return list(layers)
339
+
340
+ model_module = getattr(model, "model", None)
341
+ if model_module is not None:
342
+ for attr in ("h", "layers"):
343
+ layers = getattr(model_module, attr, None)
344
+ if isinstance(layers, torch.nn.ModuleList) and len(layers) > 0:
345
+ return list(layers)
346
+
347
  queue = deque([model])
348
  while queue:
349
  m = queue.popleft()
350
+ for attr in ("h", "layers"):
351
+ layers = getattr(m, attr, None)
352
+ if isinstance(layers, torch.nn.ModuleList) and len(layers) > 0:
353
+ return list(layers)
354
  for _, child in m.named_children():
355
  queue.append(child)
356
+ raise RuntimeError(f"Cannot find decoder layers on {type(model).__name__}")
357
 
358
 
359
  def _get_projection_map(layer: torch.nn.Module) -> Dict[str, torch.nn.Module]:
360
  """Get projection modules for a layer."""
361
  result = {}
362
+ # MLP projections (Llama and GPT-NeoX/EXAONE aliases)
363
  mlp = getattr(layer, "mlp", None)
364
  if mlp is not None:
365
+ aliases = {
366
+ "gate_proj": ["gate_proj", "c_fc_0", "c_fc"],
367
+ "up_proj": ["up_proj", "c_fc_1"],
368
+ "down_proj": ["down_proj", "c_proj", "wo"],
369
+ }
370
+ for canon, names in aliases.items():
371
+ for name in names:
372
+ mod = getattr(mlp, name, None)
373
+ if mod is not None and hasattr(mod, "weight"):
374
+ result[canon] = mod
375
+ break
376
  # Attention projections
377
  attn = getattr(layer, "self_attn", None) or getattr(layer, "attention", None) or getattr(layer, "attn", None)
378
+ if attn is not None and hasattr(attn, "attention"):
379
+ attn = attn.attention
380
  if attn is not None:
381
+ for name in ["q_proj", "k_proj", "v_proj", "o_proj", "out_proj"]:
382
  mod = getattr(attn, name, None)
383
  if mod is not None and hasattr(mod, "weight"):
384
+ # Normalize out_proj to o_proj for downstream naming.
385
+ key = "o_proj" if name == "out_proj" else name
386
+ result[key] = mod
387
  return result
388
 
389