
Referenzimplementierung eines Multi-Bit-LLM-Wasserzeichenschemas mit codierter Payload-Spreizung, unverzerrter Neugewichtung und Soft-Decision-ECC-Dekodierung zum Einbetten und Erkennen von Nachrichten in generiertem Text.
Referenzimplementierung von Robust and Scalable Multi-bit LLM Watermarking via Coded Payload Spreading.
WeaveMark bettet eine k-Bit-Nachricht in LLM-generierten Text ein, während die Token-Verteilung unverzerrt bleibt. Es kombiniert codierte Payload-Spreading (κ Codewort-Bits pro Token über ℓ Schichten, mit einer kontextgemischten Schicht→Bit-Zuordnung), Soft-Decision-ECC-Dekodierung aus Bit-Abstimmungsmargen pro Bit und unverzerrtes Mehrschicht-Reweighting (jede Richtung mit einem Kontext-Münzwurf XOR-verknüpft). Dedizierte Null-Bit-Schichten, die vom Kontext statt von der Nachricht partitioniert werden, ermöglichen nachrichtenunabhängige Präsenzerkennung.
weavemark/ Bibliothek
watermark.py WeaveMark-Logits-Prozessor (Einbettung)
extraction.py extract_bits, detect_zerobit
prf.py Schlüsselbasierte PRF (gemeinsam für Einbettung/Extraktion)
data.py Datensatz-Laden, Prompt-Vorbereitung, JSONL-Datensätze
device.py CUDA-Prüfung
ecc/ Golay, Reed-Muller, Soft-Decision-Dekodierer
generate.py Wasserzeichen-/Klartext generieren
detect.py Extraktion + Null-Bit-z-Score + PPL
evaluate_downstream.py Zusammenfassungs-/Übersetzungsqualität
perplexity.py PPL-Bewerter
attacks/ Substitution, DIPPER
run_*.py Pipelines (Generieren+Erkennen, Angriffe, Downstream)
data/OpenGen.jsonl OpenGen-Prompts (--dataset opengen); siehe Hinweis unten
data/OpenGen.jsonl (der standardmäßige öffentliche OpenGen-Benchmark) ist aus
diesem Archiv aus Platzgründen ausgelassen; lege es unter data/ ab, um --dataset opengen zu verwenden. Die
Datensätze c4 und openwebtext streamen vom Hub und benötigen keine lokale Datei.
Führe alle Skripte vom Repository-Stammverzeichnis aus, damit import weavemark aufgelöst wird.
Erfordert Python 3.10–3.12 und eine CUDA-GPU (Modelle laden 4-Bit über bitsandbytes; es gibt keinen CPU-Pfad). 4-Bit-LLaMA-3-8B passt in ~16 GB.
cd WeaveMark
python -m venv .venv && source .venv/bin/activate # oder: conda create -n weavemark python=3.11
Installiere einen CUDA-Build von PyTorch vor requirements.txt — ein einfaches
pip install torch ergibt auf Windows ein CPU-only-Rad, und das Rad muss
Kernel für deine GPU haben (RTX-50-Serie / sm_120 benötigt torch ≥ 2.7 auf CUDA ≥ 12.8;
ältere cu121-Räder enden bei sm_90 und schlagen zur Laufzeit fehl). Wähle den passenden Befehl
von https://pytorch.org.
pip install torch --index-url https://download.pytorch.org/whl/cu128 # Beispiel: Blackwell
pip install -r requirements.txt
Prüfe, ob die GPU tatsächlich Kernel ausführt (is_available() allein reicht nicht — es ist
auch dann True, wenn dem Rad die Kernel für die Architektur fehlen):
python -c "import torch; t=torch.zeros(8).cuda().normal_(); print(torch.__version__, torch.cuda.get_device_capability(), (t*t).sum().item())"
LLaMA-3 und C4 sind gated: huggingface-cli login und deren Bedingungen akzeptieren.
OpenGen wird mit dem Repo geliefert. Wähle eine GPU mit CUDA_VISIBLE_DEVICES=<i>.
python generate.py --method weavemark --ecc_method rm --random_message \
--dataset c4 --num_test 100 --max_new_tokens 200 \
--bpt 10 --num_layers 10 --window_size 2 --prob_delta 1.0 \
--num_zerobit_layers 0 --do_sample
python detect.py --data_dir output_dump/<run_folder> --detect --stride 25
detect.py schreibt detailed_eval_*.csv und summary_eval_*.csv; wichtige Spalten
sind success_rate und, mit --zerobit_threshold, z_success_rate.
run_main.py verkettet Generieren + Erkennen (bearbeite die Konstanten oben in der Datei).
Datensätze: c4 / openwebtext streamen vom Hub und kürzen auf
--prompt_len Wörter; opengen liest data/OpenGen.jsonl und kürzt jedes
Präfix auf --prompt_len Tokens.
ECC-Nachricht→Codewort: golay 12→24, rm 16→32, dual_golay 24→48, dual_rm
32→64. none bettet --message uncodiert ein.
Papier-Einstellungen: Mehrbit-Tracing verwendet --bpt 10 --num_layers 10 --window_size 2 --prob_delta 1.0 --num_zerobit_layers 0, ECC nach Nachrichtenlänge; füge
--num_zerobit_layers 2 --enable_zerobit für die kombinierte Einstellung hinzu; reines Null-Bit
ist --bpt 0 --num_layers 0 --num_zerobit_layers 10 --enable_zerobit.
python attacks/substitution.py --data_dir output_dump/<run> --ratios 0.1 0.2 0.3
python attacks/dipper_attack.py --data_dir output_dump/<run> --lex_diversity 20 --order_diversity 20
python detect.py --data_dir output_dump/<run> --text_file attacked_text_10.jsonl --detect --stride 999
run_substitution.py / run_dipper.py verkettet Angriff + Ganztext-Erkennung
(--stride 999 bewertet jeden Ausschnitt ganz). run_downstream.py führt
Zusammenfassung (CNN/DailyMail) und Übersetzung (WMT16 en→ro) mit BERTScore +
ROUGE/BLEU aus.
window_size = 2: das unverzerrte Design verbietet die Wiederverwendung eines Kontexts, daher reduziert ein größeres
Fenster den Skip-Verlust (siehe Anhang).no_watermark-Läufe verwenden dieselben Schlüssel/Parameter, um die Falsch-Positiv-Rate
zu messen.@inproceedings{weavemark,
title = {Robust and Scalable Multi-bit LLM Watermarking via Coded Payload Spreading},
author = {Anonymous},
year = {2026},
note = {Under review}
}
attacks/dipper.py ist angepasst von
martiansideofthemoon/ai-detection-paraphrases
(deren Lizenz gilt für diese Datei). Veröffentlicht unter MIT (siehe LICENSE); setze den
Urheberrechtsinhaber vor der Veröffentlichung.
| Flag | Symbol | Bedeutung | Typisch |
|---|
--bpt | κ | Bits pro Token | 10 |
--num_layers | ℓ | Mehrbit-Schichten | 10 |
--window_size | h | Kontextfenster | 2 |
--prob_delta | δ | Reweighting-Stärke | 1.0 |
--ecc_method | — | none/golay/dual_golay/rm/dual_rm | rm |
--num_zerobit_layers | ℓ_z | Null-Bit-Schichten | 0 oder 2 |
--top_k | K | Sampling top-k | 50 |