hallucination / experiment /knowledge_editing /IMPLEMENTATION_PLAN.md
ToiTenBao's picture
Upload hallucination folder
a2ffd07 verified
|
Raw
History Blame Contribute Delete
13 kB
# 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)