unload_textual_inversion(token) leaves the extra tokens of a multi-vector embedding behind, so it can't be loaded again

Offen Anfängerfreundlich
#15,211 3 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
2/5
Geschätzter Aufwand
1-3 Stunden
Anfängerfreundlichkeit
72/100
Issue-Typ
Bug
Klarheit
Klar beschrieben
Aktivitätsstatus
Aktiv
Tech-Stack
python, pytorch

Rechercherichtung

Lies zuerst die Methoden zum Laden und Entladen von textual inversion sowie den Lookup maybe_convert_prompt, den sie verwenden; das Issue nennt keine Dateipfade oder Tests. Reproduziere das Problem mit der winzigen Stable-Diffusion-Pipeline und einem Two-Vector-Embedding. Erledigt ist die Aufgabe, wenn das Entladen des Basistokens auch seine Tokens mit Suffixen und Embedding-Zeilen entfernt, sodass dasselbe Embedding erneut geladen werden kann.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

Describe the bug

load_textual_inversion registers a multi-vector embedding as <token>, <token>_1, ..., <token>_{n-1}, and maybe_convert_prompt expands <token> into all of them. unload_textual_inversion("<token>") only removes <token> itself. The _1 ... _{n-1} tokens and their embedding rows stay in the tokenizer and text encoder, and loading the same embedding again fails with Multi-vector Token [...] already in tokenizer vocabulary.

Users only pass <token> to load_textual_inversion, so they have no reason to know about the suffixed tokens. #7856 hit this with an SDXL negative embedding and was closed with a workaround (list every suffixed token), but the behaviour is still there on main.

I'd like to send a PR for this: when tokens is given, also remove its <token>_1, <token>_2, ... tokens, using the same lookup maybe_convert_prompt uses. Happy to adjust if you prefer a different approach.

Reproduction

Shown with the tiny test pipeline so it runs in seconds; the loader code is the same for SD1.5 and SDXL embeddings.

import torch
from diffusers import StableDiffusionPipeline

pipe = StableDiffusionPipeline.from_pretrained("hf-internal-testing/tiny-stable-diffusion-torch", safety_checker=None)

embedding = torch.randn(2, 32)  # a 2-vector embedding (this tiny text encoder has hidden size 32)
pipe.load_textual_inversion(embedding, token="<neg>")
pipe.unload_textual_inversion("<neg>")
print([t for t in pipe.tokenizer.get_added_vocab() if t.startswith("<neg>")])  # ['<neg>_1']

pipe.load_textual_inversion(embedding, token="<neg>")  # ValueError
Context

I ran into this while testing loading and unloading of multi-vector textual inversion embeddings.

Logs
ValueError: Multi-vector Token ['<neg>', '<neg>_1'] already in tokenizer vocabulary. Please choose a different token name or remove the ['<neg>', '<neg>_1'] and embedding from the tokenizer and text encoder.
System Info
- 🤗 Diffusers version: 0.42.0.dev0 (main @ 84532a058)
- Platform: macOS-26.6.2-arm64-arm-64bit
- Running on Google Colab?: No
- Python version: 3.12.11
- PyTorch version (GPU?): 2.15.0 (False)
- Huggingface_hub version: 2.4.0
- Transformers version: 5.22.2
- Accelerate version: 1.15.0
- PEFT version: 0.21.2
- Safetensors version: 0.8.0
- xFormers version: not installed
- Accelerator: Apple M5 Pro
- Using GPU in script?: No
- Using distributed or parallel set-up in script?: No
Who can help?

@sayakpaul

Vorherrschende Sprache
Python
Sterne
34.9k
Forks
7.5k
Ø Merge
2 T. 16 Std.
Gemergte PRs (30 T.)
57

Entwicklungsumgebung

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus huggingface/diffusers

Alle Issues in huggingface/diffusers

Ähnliche Issues

Weitere Issues zu Python

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.