File size: 12,987 Bytes
a2ffd07
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
# Implementation Plan: Knowledge Editing Baselines

## Baseline Lineup

| Method | Category | Role |
|--------|----------|------|
| **LoRA v5** | Your method | Optimization-based, handles distributional visual subjects + conditional suppression |
| **OVERTONE (LoRA v3)** | Text KME baseline (adapted) | Token-level adaptive targets, shows text-only KME on VLM |
| **MEMIT** | Classic locate-then-edit | Shows point-subject methods struggle with distributional setting |
| **DualEdit** | VLM-specific editor (COLM 2025) | Best existing VLM editor, gating mechanism provides visual conditioning |

---

## Part 1: MEMIT Baseline

**Effort:** Small (1-2 days)
**Status:** EasyEdit has MEMIT at `EasyEdit/easyeditor/models/memit/`. Just needs wiring up.

### Files to Create

#### 1. `experiment/knowledge_editing/hparams/memit.yaml`

```yaml
alg_name: "MEMIT"
model_name: "llava-hf/llava-1.5-7b-hf"
device: 0
stats_dir: "./data/stats"

# Target mid-range layers for LLaMA backbone
layers: [4, 5, 6, 7, 8]
layer_selection: "all"
fact_token: "subject_last"

v_num_grad_steps: 25
v_lr: 5e-1
v_loss_layer: 31
v_weight_decay: 1e-3
clamp_norm_factor: 4
kl_factor: 0.0625
mom2_adjustment: true
mom2_update_weight: 15000

# Module templates for LLaVA-1.5's LLaMA backbone
# MEMIT operates on model.language_model (a LlamaForCausalLM)
# These paths are relative to the language_model, not the full LlavaForConditionalGeneration
rewrite_module_tmp: "model.layers.{}.mlp.down_proj"
layer_module_tmp: "model.layers.{}"
mlp_module_tmp: "model.layers.{}.mlp"
attn_module_tmp: "model.layers.{}.self_attn"
ln_f_module: "model.norm"
lm_head_module: "lm_head"

mom2_dataset: "wikipedia"
mom2_n_samples: 100000
mom2_dtype: "float32"
model_parallel: false
```

#### 2. `experiment/knowledge_editing/memit_wrapper.py`

Adapts text-only MEMIT for the multimodal pipeline:

- **Extract `model.language_model`** from `LlavaForConditionalGeneration` — MEMIT operates on CausalLM directly
- **Convert edit requests** from image-based format to MEMIT's text-only format:
  ```python
  # Our format (from build_requests):
  {"prompt": "Describe this image.", "target": "A bathroom with a sink and mirror.", "image": <PIL>}

  # MEMIT format:
  {"prompt": "In the bathroom, the {} is", "subject": "toilet", "target_new": {"str": "not visible"}}
  ```
- **Call `apply_memit_to_model()`** from EasyEdit on the language model
- **Return the full LlavaForConditionalGeneration** with edited language model

Function signature must match `run_baselines.py` pattern:
```python
def apply_memit_to_multimodal_model(model, processor, requests, hparams,
                                     copy=False, return_orig_weights=True,
                                     keep_original_weight=False):
```

**Key limitation:** MEMIT is text-only, cannot condition on images. It does an unconditional edit
suppressing the bathroom→toilet association globally. Expected to hurt locality (suppress toilet
even when present). This is the point — demonstrates why vision-conditioned methods are needed.

**Pitfalls:**
- Module path mismatch: paths must be relative to `model.language_model`, not full model
- Covariance computation (`mom2`): runs model on Wikipedia text, needs CausalLM not full VLM
- Tokenizer: use `processor.tokenizer` or `processor._processor.tokenizer`
- `target_new` vs `target`: wrapper must translate field names

### Files to Modify

#### 3. `experiment/knowledge_editing/run_baselines.py`

Add `memit` to three places:

**`load_hparams()` (~line 181):**
```python
elif method == "memit":
    from easyeditor.models.memit import MEMITHyperParams
    return MEMITHyperParams.from_hparams(yaml_path)
```

**`get_apply_algo()` (~line 197):**
```python
elif method == "memit":
    from experiment.knowledge_editing.memit_wrapper import apply_memit_to_multimodal_model
    return apply_memit_to_multimodal_model
```

**CLI args (~line 459):** Add `"memit"` to choices list.

#### 4. `experiment/evaluation/validate.py`

MEMIT edits weights directly (like LoRA merged), so treat `--model_type memit` same as `merged`.
Minimal change — just document it or add alias.

---

## Part 2: DualEdit Baseline

**Effort:** Medium (3-5 days)
**Paper:** "DualEdit: Dual Editing for Knowledge Updating in Vision-Language Models" (COLM 2025)
**Code:** https://github.com/zhiyiscs/DualEdit

### How DualEdit Works

1. Inserts **two learnable cross-attention adapters** at modality-specific key layers:
   - Layer 16: text adapter (modifies textual representations)
   - Layer 19: vision adapter (modifies visual representations)
2. **Gating mechanism**: cosine similarity of last-token representations decides whether to apply edit
   - `Sim = cos(h^e, h^i)` — edit sample vs input sample
   - If `Sim > τ`: route through adapter (apply edit)
   - Else: use original model (preserve behavior)
3. **Loss** = `L_rel + L_gen + L_loc` (reliability + generality + locality)

### Why It Fits Our Problem

- Gating = natural implementation of our `g(image)` visual grounding function
- Dual-modality editing matches our insight (prior in LLM, triggered by visual input)
- Near-perfect locality (99.89% M-Loc in paper) via gating

### Key Adaptation: Per-Sample → Distributional

DualEdit is designed for per-sample edits. We adapt to **batched training**:
- Train ONE pair of adapters across ALL bathroom-no-toilet images
- Store mean last-token representation as gate prototype
- At inference, gate fires for inputs similar to prototype

### Files to Create

```
experiment/knowledge_editing/dualedit/
    __init__.py
    adapter.py
    gating.py
    dualedit_main.py
    dualedit_hparams.py
```

#### 1. `dualedit/adapter.py` — Dual Adapter Modules

Cross-attention adapter (from paper Eq. 5, Section 3.2):

```python
class DualEditAdapter(nn.Module):
    """Learnable adapter using cross-attention.

    Inserted at a specific layer. Uses the edit signal (h_e from the edit sample)
    as Key/Value, and the current hidden state as Query.

    Separate weight matrices W_1, W_2, W_3 for text vs vision modalities.
    """
    def __init__(self, hidden_size, d_a=64):
        # W_1^{t/v}: Query projection  (hidden_size -> d_a)
        # W_2^{t/v}: Key projection    (hidden_size -> d_a)
        # W_3^{t/v}: Value projection   (hidden_size -> hidden_size)
        # Text and vision get separate weight matrices
        ...

    def forward(self, h_k, h_e_k):
        # h_k: current layer's hidden state for text or vision tokens
        # h_e_k: edit signal from edit sample at this layer
        # Returns: edited hidden state
        # h_hat = Softmax(h_k @ W_1 . (h_e_k @ W_2)^T) . h_e_k @ W_3
        ...
```

Two instances needed: one at layer 16 (text), one at layer 19 (vision).

#### 2. `dualedit/gating.py` — Gating Mechanism

```python
class DualEditGate:
    """Cosine similarity gate on last-token representations.

    At training time: stores edit sample representations.
    At inference time: compares input repr to stored prototypes.
    If similarity > threshold: activate adapters.
    Otherwise: bypass (use original model).
    """
    def __init__(self, threshold=0.6):
        self.threshold = threshold
        self.edit_prototypes = []  # mean last-token reprs from edit samples

    def register_edit_repr(self, h_last_token):
        """Store representation during training."""
        ...

    def compute_prototype(self):
        """Average all stored reprs into a single gate key."""
        ...

    def should_edit(self, h_input_last_token) -> bool:
        """Check if input should be routed through adapters."""
        sim = F.cosine_similarity(h_input_last_token, self.prototype, dim=-1)
        return sim > self.threshold
```

Threshold: τ=0.6 for LLaVA-1.5 (from paper Appendix D).

#### 3. `dualedit/dualedit_main.py` — Main Apply Function + Training

```python
def apply_dualedit_to_multimodal_model(model, processor, requests, hparams, **kwargs):
    """
    1. Insert adapter modules at layers 16 and 19
    2. Freeze all params except adapters
    3. Train adapters on edit requests:
       - L_rel: -log P(target | edit_image, prompt) on bathroom_no_toilet
       - L_gen: same on rephrased prompts + different bathroom_no_toilet images
       - L_loc: KL preservation on bathroom_with_toilet + unrelated
    4. Compute and store gate prototype (mean last-token repr)
    5. Return edited model with adapters + gating state
    """
```

Training details (from paper Appendix D):
- Learning rate: 1e-4
- Batch size: 4
- Max iterations: 50,000 (but we can use fewer for our distributional task)
- Checkpoint every 1000 iterations, select best by loss

#### 4. `dualedit/dualedit_hparams.py` — Hyperparameters

```python
@dataclass
class DualEditHyperParams:
    model_name: str = "llava-hf/llava-1.5-7b-hf"
    text_adapter_layer: int = 16
    vision_adapter_layer: int = 19
    adapter_dim: int = 64
    gating_threshold: float = 0.6
    edit_lr: float = 1e-4
    n_iterations: int = 5000
    batch_size: int = 4
    reliability_weight: float = 1.0
    generality_weight: float = 0.5
    locality_weight: float = 1.0
    checkpoint_every: int = 500
```

#### 5. `experiment/knowledge_editing/hparams/dualedit.yaml`

YAML version of the above hparams.

### Files to Modify

#### 6. `experiment/knowledge_editing/run_baselines.py`

Add `dualedit` to `load_hparams()`, `get_apply_algo()`, and CLI args.

#### 7. `experiment/evaluation/validate.py`

Add `model_type="dualedit"` support:
1. Load base LlavaForConditionalGeneration
2. Insert adapter modules at layers 16 and 19
3. Load adapter weights + gating keys from `.pt` file
4. Register forward hooks for gating

Follow existing GRACE/WISE save/restore pattern in `_extract_adapter_states()`.

### Pitfalls

1. **Layer numbering**: Verify 0-indexed layers 16 and 19 match paper's intent for LLaVA-1.5
2. **Gating prototype noise**: Mean of diverse bathroom images may be noisy — may need multiple prototypes or tuned threshold
3. **Memory**: Training requires backprop through frozen model. ~16-20GB VRAM with batch_size=4 and fp16. May need gradient checkpointing.
4. **Multimodal loss**: Locality loss must handle both text-only (unrelated) and image+text (bathroom-with-toilet) inputs

---

## Implementation Order

```
Week 1:
  Day 1-2: MEMIT
    ├── Create memit.yaml hparams
    ├── Create memit_wrapper.py
    ├── Wire into run_baselines.py
    └── Test: run MEMIT on small edit set, verify weights change, run eval

  Day 3-4: DualEdit (architecture)
    ├── Clone DualEdit repo, study source code
    ├── Create dualedit/ directory structure
    ├── Implement adapter.py (cross-attention modules)
    └── Implement gating.py (cosine similarity gate)

  Day 5: DualEdit (training + integration)
    ├── Implement dualedit_main.py (training loop)
    ├── Create hparams, wire into run_baselines.py
    └── Add save/restore + validate.py support

Week 2:
  Day 1: Testing & debugging
    ├── Run DualEdit training on bathroom dataset
    ├── Debug gating behavior (check threshold sensitivity)
    └── Verify locality on bathroom-with-toilet images

  Day 2: Joint evaluation
    ├── Run all methods through validate.py
    ├── Compare: LoRA v5, OVERTONE, MEMIT, DualEdit
    └── Generate comparison table
```

---

## Reference: Existing Infrastructure

| Component | Location | Notes |
|-----------|----------|-------|
| LoRA v5 (your method) | `experiment/training/finetune_lora_v5.py` | Already implemented |
| OVERTONE (LoRA v3) | `experiment/training/finetune_lora_v3.py` | Already implemented |
| EasyEdit baselines | `experiment/knowledge_editing/run_baselines.py` | WISE, GRACE, LoRA, IKE |
| EasyEdit MEMIT | `EasyEdit/easyeditor/models/memit/memit_main.py` | Needs wrapper |
| Evaluation | `experiment/evaluation/validate.py` | Supports lora, merged, delta_w, grace, wise |
| Edit set builder | `experiment/knowledge_editing/build_edit_set.py` | Generates edit_set.json |
| Dataset | `experiment/data/datasets.py` | CC3M bathroom categories |
| LLaVA compat | `experiment/knowledge_editing/llava15_compat.py` | Processor wrapper |
| Config | `experiment/config/train_config.py` | Comprehensive config system |
| DualEdit paper code | https://github.com/zhiyiscs/DualEdit | To be cloned |

## Reference: Key Papers

- **MEMIT**: Meng et al. (2023). "Mass-Editing Memory in a Transformer." ICLR.
- **DualEdit**: Shi et al. (2025). "DualEdit: Dual Editing for Knowledge Updating in Vision-Language Models." COLM.
- **VisEdit**: Chen et al. (2024). "Attribution Analysis Meets Model Editing." AAAI. (Not implementing, but VisEdit/ code available for reference)
- **OVERTONE**: Liu et al. (2025). "Mitigating Heterogeneous Token Overfitting in LLM Knowledge Editing." ICML.
- **AlphaEdit**: Fang et al. (2025). "AlphaEdit: Null-Space Constrained Knowledge Editing." ICLR. (Optional post-hoc enhancement)