Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

## 📖 Overview

We provide efficient and streamlined implementations of the TOFU, MUSE and WMDP unlearning benchmarks while supporting 14+ unlearning methods, 5+ datasets, 10+ evaluation metrics, and 7+ LLM architectures. Each of these can be easily extended to incorporate more variants.
We provide efficient and streamlined implementations of the TOFU, MUSE and WMDP unlearning benchmarks while supporting 15+ unlearning methods, 5+ datasets, 10+ evaluation metrics, and 7+ LLM architectures. Each of these can be easily extended to incorporate more variants.

We invite the LLM unlearning community to collaborate by adding new benchmarks, unlearning methods, datasets and evaluation metrics here to expand OpenUnlearning's features, gain feedback from wider usage and drive progress in the field.

Expand Down Expand Up @@ -84,7 +84,7 @@ We provide several variants for each of the components in the unlearning pipelin
| **Component** | **Available Options** |
|------------------------|----------------------|
| **Benchmarks** | [TOFU](https://arxiv.org/abs/2401.06121), [MUSE](https://muse-bench.github.io/), [WMDP](https://www.wmdp.ai/), [DUET](https://arxiv.org/abs/2602.19612) |
| **Unlearning Methods** | GradAscent, GradDiff, NPO, SimNPO, DPO, RMU, UNDIAL, AltPO, SatImp, WGA, CE-U, PDU, AdaPop, T3 |
| **Unlearning Methods** | GradAscent, GradDiff, NPO, SimNPO, DPO, RMU, UNDIAL, AltPO, SatImp, WGA, CE-U, PDU, AdaPop, T3, PALU |
Comment thread
nxZhai marked this conversation as resolved.
Resolved
| **Evaluation Metrics** | Verbatim Probability, Verbatim ROUGE, Knowledge QA-ROUGE, Model Utility, Forget Quality, TruthRatio, Extraction Strength, Exact Memorization, 6 MIA attacks, [Unlearning Depth Score](https://arxiv.org/abs/2605.24614), [lm-evaluation-harness](https://github.com/EleutherAI/lm-evaluation-harness) |
| **Datasets** | MUSE-News (BBC), MUSE-Books (Harry Potter), TOFU (different splits), WMDP-Bio, WMDP-Cyber, [DUET](https://huggingface.co/datasets/SwetieePawsss/DUET) (rare / popular Wikidata facts) |
| **Model Families** | TOFU: Llama-3.2, Llama-3.1, Llama-2; MUSE: Llama-2; DUET: Llama-3.1, Qwen2.5, Gemma; Additional: Phi-3.5, Phi-1.5, Gemma, Zephyr |
Expand Down
2 changes: 2 additions & 0 deletions community/methods/PALU/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
!data/
!data/**
21 changes: 21 additions & 0 deletions community/methods/PALU/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Naixin Zhai

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
43 changes: 43 additions & 0 deletions community/methods/PALU/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# PALU

Implementation of [PALU](https://arxiv.org/abs/2601.03190) (Naixin Zhai, University of Science and Technology of China, 2601.03190, [nxZhai/PALU](https://github.com/nxZhai/PALU), Stars: 16 as of 2026-11-05): *Maximizing Local Entropy Where It Matters: Prefix-Aware Localized LLM Unlearning*.

## Method and configuration

Use [run.sh](run.sh), which selects `experiment=unlearn/tofu/default`, `trainer=PALU`, and the annotated forget data through command-line overrides. At each selected sensitive position, PALU selects the reference model's top-k vocabulary candidates and moves their current logits toward the current model's vocabulary-wide mean.

`first_n` selects a prefix of each contiguous sensitive span, independently for each example; EOS is excluded from sensitive positions.

| Parameter under `trainer.method_args` | Default | Meaning |
| --- | --- | --- |
| `top_k` | `1` | Reference vocabulary candidates to flatten; capped at vocabulary size. |
| `first_n` | `-1` | Prefix length per sensitive span; non-positive values select every sensitive token. |
| `target_mode` | `mean` | Current vocabulary mean, matching the source objective. |
| `non_sensitive_constraint_type` | `kl` | Preserve non-sensitive answer tokens with `kl`, or with `nll` on reference argmax tokens. |
| `kl_direction` | `reverse` | `forward`, `reverse`, or `mixed`, defined below. |
| `gamma`, `alpha` | `1.0`, `1.0` | Sensitive loss weight and shared preservation weight. |
| `retain_loss_type` | `NLL` | Existing Open-Unlearning retain objective; `KL` also remains available. |

## Annotated data

The three directories under [data/](data/) are copied byte-for-byte from the [official code's processed TOFU data](https://github.com/nxZhai/PALU/tree/main/data/palu). Together they occupy 909,489 bytes (about 0.87 MiB).

| Directory | Examples |
| --- | ---: |
| `forget01_with_common_words_gpt` | 40 |
| `forget05_with_common_words_gpt` | 200 |
| `forget10_with_common_words_gpt` | 400 |

Each directory contains the original Arrow file, `dataset_info.json`, and `state.json`, readable with `datasets.load_from_disk`. The columns are `question`, `answer`, `target_words`, and `common_words`. Sensitive spans in `target_words` use half-open character offsets `[start, end)` into the answer. `common_words` is preserved; as in the source implementation, all answer tokens outside sensitive spans receive the non-sensitive label, so this column is not needed to build masks. Examples with no annotated sensitive span remain usable for preservation.

`PALUDataset` requires a fast tokenizer. It uses the model's existing prompt template and maps character spans using native tokenizer offsets. Labels are token IDs for sensitive tokens, `-200` for other answer tokens, and `-100` for prompt/padding positions. The custom forget labels are never passed to the language model's cross-entropy loss. Retain data and evaluation data use the existing TOFU loaders and standard labels.

These are annotations of the [TOFU dataset](https://huggingface.co/datasets/locuslab/TOFU), whose dataset card specifies the MIT license. The original implementation's MIT notice is preserved in [LICENSE](LICENSE).

## Run an example

Run from the repository root:

```bash
bash community/methods/PALU/run.sh
```
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"citation": "",
"description": "",
"features": {
"question": {
"dtype": "string",
"_type": "Value"
},
"answer": {
"dtype": "string",
"_type": "Value"
},
"target_words": {
"dtype": "string",
"_type": "Value"
},
"common_words": {
"feature": {
"dtype": "string",
"_type": "Value"
},
"_type": "Sequence"
}
},
"homepage": "",
"license": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"_data_files": [
{
"filename": "data-00000-of-00001.arrow"
}
],
"_fingerprint": "d2a5066b9ab95478",
"_format_columns": null,
"_format_kwargs": {},
"_format_type": null,
"_output_all_columns": false,
"_split": null
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"citation": "",
"description": "",
"features": {
"question": {
"dtype": "string",
"_type": "Value"
},
"answer": {
"dtype": "string",
"_type": "Value"
},
"target_words": {
"dtype": "string",
"_type": "Value"
},
"common_words": {
"feature": {
"dtype": "string",
"_type": "Value"
},
"_type": "Sequence"
}
},
"homepage": "",
"license": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"_data_files": [
{
"filename": "data-00000-of-00001.arrow"
}
],
"_fingerprint": "e47996a11813ab7b",
"_format_columns": null,
"_format_kwargs": {},
"_format_type": null,
"_output_all_columns": false,
"_split": null
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"citation": "",
"description": "",
"features": {
"question": {
"dtype": "string",
"_type": "Value"
},
"answer": {
"dtype": "string",
"_type": "Value"
},
"target_words": {
"dtype": "string",
"_type": "Value"
},
"common_words": {
"feature": {
"dtype": "string",
"_type": "Value"
},
"_type": "Sequence"
}
},
"homepage": "",
"license": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"_data_files": [
{
"filename": "data-00000-of-00001.arrow"
}
],
"_fingerprint": "1ffb9df4bb1e5d69",
"_format_columns": null,
"_format_kwargs": {},
"_format_type": null,
"_output_all_columns": false,
"_split": null
}
31 changes: 31 additions & 0 deletions community/methods/PALU/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -euo pipefail

# Run one example from the Open-Unlearning repository root; append Hydra overrides.
MODEL="${MODEL:-Llama-2-7b-chat-hf}"
PRETRAINED_PATH="${PRETRAINED_PATH:-open-unlearning/tofu_${MODEL}_full}"
KL_DIRECTION="${KL_DIRECTION:-reverse}"
TASK_NAME="palu_${MODEL}_forget01_${KL_DIRECTION}"

python src/train.py --config-name=unlearn.yaml \
experiment=unlearn/tofu/default \
trainer=PALU \
data/datasets@data.forget=TOFU_QA_forget_palu \
'~data.forget.TOFU_QA_forget' \
model="${MODEL}" \
model.model_args.pretrained_model_name_or_path="${PRETRAINED_PATH}" \
model.tokenizer_args.pretrained_model_name_or_path="${PRETRAINED_PATH}" \
forget_split=forget01 \
retain_split=retain99 \
holdout_split=holdout01 \
task_name="${TASK_NAME}" \
paths.output_dir=".cache/palu/runs/${TASK_NAME}" \
trainer.method_args.first_n=3 \
trainer.method_args.top_k=1000 \
trainer.method_args.kl_direction="${KL_DIRECTION}" \
trainer.args.report_to=none \
trainer.args.eval_strategy=no \
trainer.args.eval_on_start=false \
trainer.args.do_eval=false \
'~eval.tofu' \
"$@"
93 changes: 93 additions & 0 deletions community/methods/PALU/scripts/tofu/train_tofu_palu_llama2.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/usr/bin/env bash
set -euo pipefail

DATE=$(date "+%m%d")
TIME=$(date "+%H%M%S")

export CUDA_VISIBLE_DEVICES="${CUDA_VISIBLE_DEVICES:-0}"
MODEL="Llama-2-7b-chat-hf"

REPORTTO="${REPORTTO:-none}"
WANDB_PROJECT="${WANDB_PROJECT:-palu}"
KL_DIRECTION="${KL_DIRECTION:-reverse}"
OUTPUT_ROOT="${OUTPUT_ROOT:-.cache/palu/runs}"
RETAIN_LOGS_ROOT="${RETAIN_LOGS_ROOT:-saves/eval}"

TRAINER="PALU"
PRETRAINED_PATH="open-unlearning/tofu_Llama-2-7b-chat-hf_full"

splits=(
"forget05 holdout05 retain95"
"forget01 holdout01 retain99"
"forget10 holdout10 retain90"
)
# lr, batchsize, grad_acc, epochs
lr_set=("1e-5" "2e-5" "3e-5" "4e-5" "5e-5")
bz_set=("8 4")
target_mode_set=("mean")
alpha_set=(1 2 5 0.5 0.2)
topk_set=(1 1000 5000 10000)
first_n_set=(1 2 3 4 5 10)
epoch_set=(10)

for split in "${splits[@]}"; do
for lr in "${lr_set[@]}"; do
for bz in "${bz_set[@]}"; do
for target_mode in "${target_mode_set[@]}"; do
for epochs in "${epoch_set[@]}"; do
for alpha in "${alpha_set[@]}"; do
for topk in "${topk_set[@]}"; do
for first_n in "${first_n_set[@]}"; do
# Args ========================================
read -r forget_split holdout_split retain_split <<< "$split"

read -r bsz grad_acc <<< "$bz"

# learning_rate, batchsize, grad_acc, epochs
SUFFIX="kl${KL_DIRECTION}_target_mode${target_mode}_first_n${first_n}_lr${lr}_b${bsz}_ga${grad_acc}_a${alpha}_topk${topk}_e${epochs}_day${DATE}_time${TIME}"
TASK_NAME="unlearn_tofu_${MODEL}_${forget_split}_${TRAINER}_${SUFFIX}"
OUTPUT_DIR="${OUTPUT_ROOT}/tofu/${forget_split}/${MODEL}/${TRAINER}/${SUFFIX}"

# TRAIN COMMAND =================================
export WANDB_PROJECT
python src/train.py --config-name=unlearn.yaml \
experiment=unlearn/tofu/default \
trainer="${TRAINER}" \
data/datasets@data.forget=TOFU_QA_forget_palu \
'~data.forget.TOFU_QA_forget' \
model="${MODEL}" \
model.model_args.pretrained_model_name_or_path="${PRETRAINED_PATH}" \
model.tokenizer_args.pretrained_model_name_or_path="${PRETRAINED_PATH}" \
forget_split="${forget_split}" \
holdout_split="${holdout_split}" \
retain_split="${retain_split}" \
task_name="${TASK_NAME}" \
paths.output_dir="${OUTPUT_DIR}" \
eval.tofu.retain_logs_path="${RETAIN_LOGS_ROOT}/tofu_${MODEL}_${retain_split}/TOFU_EVAL.json" \
trainer.args.ddp_find_unused_parameters=true \
trainer.args.gradient_checkpointing=true \
trainer.args.report_to="${REPORTTO}" \
+trainer.args.run_name="${TASK_NAME}" \
trainer.args.logging_steps=1 \
trainer.args.learning_rate="$lr" \
trainer.args.per_device_train_batch_size="$bsz" \
trainer.args.gradient_accumulation_steps="$grad_acc" \
trainer.args.num_train_epochs="$epochs" \
trainer.args.eval_strategy=epoch \
trainer.args.eval_on_start=True \
trainer.method_args.gamma=1.0 \
trainer.method_args.alpha="$alpha" \
trainer.method_args.retain_loss_type=NLL \
trainer.method_args.top_k="$topk" \
trainer.method_args.target_mode="${target_mode}" \
trainer.method_args.first_n="${first_n}" \
trainer.method_args.kl_direction="${KL_DIRECTION}" \
"$@"
done
done
done
done
done
done
done
done
Loading
Loading