New model: Anima - #1487
Conversation
- Bump requirements: transformers 4.57.6 → 5.9, huggingface-hub 0.34.4 → 1.16.1 - Remove HF_HUB_DISABLE_XET workaround from startup scripts; Xet is stable in hub 1.16 - Remove _prepare_sub_modules / snapshot_download prefetching; hub 1.16 fetches lazily on demand - Delete thread_safety.py and apply_thread_safe_forward calls; workaround for transformers#42673 was fixed upstream in v5 - Replace _remove_added_embeddings_from_tokenizer (relied on internal Trie, removed in v5) with orig_tokenizer deep-copies stored at load time; model savers pass use_original_tokenizers=True to create_pipeline() so saved checkpoints use the unmodified tokenizer - Switch ErnieModelLoader to AutoTokenizer; eliminates the tokenization-logger suppress workaround - Suppress httpx INFO logs; hub 1.16 uses httpx internally and logs every HTTP request Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: dxqb <183307934+dxqb@users.noreply.github.com>
|
Unsure if this is in scope for this PR, but I think it would be useful to expose an optional toggle to train Anima's llm_adapter. |
This comment was marked as resolved.
This comment was marked as resolved.
training text components should be a thing of the past. it's always been a crutch for diffusion models that weren't very capable yet. So I'm hesitant to reintroduce this, with all the problems that come with it (such as having multiple learning rates and many more failure modes). |
torch._dynamo.config overrides are thread-local. The existing call in checkpointing_util runs in the main thread and is invisible to the training thread spawned by the UI. This caused compiled optimizers (e.g. AdamW_adv with compiled_optimizer=True) to hit the default recompile_limit of 8 and abort with FailOnRecompileLimitHit when training models with more than 8 distinct parameter shapes. Fix: call init_compile() from GenericTrainer.__init__, which runs in whichever thread/process owns training (UI thread, CLI main thread, or torch.multiprocessing.spawn subprocess for multi-GPU). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fixed by #1495, merged into this PR |
|
Thank you for your great work! I've been training Anima LoRAs in OneTrainer and using the same dataset/settings in Kohya sd-scripts. Training itself works fine, but LoRAs saved from OneTrainer (preview branch) don't load correctly in ComfyUI when paired with the standard single-checkpoint Anima model (anima-base-v1.0.safetensors). I believe this is due to the LoRA key naming on export. Example key:
Other model types in OneTrainer already handle this via Diffusers has the inverse mapping in I prototyped the conversion script as below. It might be missing things as I haven't tested exhaustively yet: # convert_anima_lora.py
from modules.util.convert.lora.convert_lora_util import LoraConversionKeySet
def __map_anima_blocks(parent: LoraConversionKeySet) -> list[LoraConversionKeySet]:
return [LoraConversionKeySet(
omi_prefix=f"blocks.{i}",
diffusers_prefix=f"transformer_blocks.{i}",
legacy_diffusers_prefix=f"blocks_{i}",
parent=parent,
next_omi_prefix=f"blocks.{i + 1}",
next_diffusers_prefix=f"transformer_blocks.{i + 1}",
) for i in range(100)]
def __map_transformer_block(key_prefix: LoraConversionKeySet) -> list[LoraConversionKeySet]:
mappings = [
("self_attn.q_proj", "attn1.to_q", "self_attn_q_proj"),
("self_attn.k_proj", "attn1.to_k", "self_attn_k_proj"),
("self_attn.v_proj", "attn1.to_v", "self_attn_v_proj"),
("self_attn.output_proj", "attn1.to_out.0", "self_attn_output_proj"),
("cross_attn.q_proj", "attn2.to_q", "cross_attn_q_proj"),
("cross_attn.k_proj", "attn2.to_k", "cross_attn_k_proj"),
("cross_attn.v_proj", "attn2.to_v", "cross_attn_v_proj"),
("cross_attn.output_proj", "attn2.to_out.0", "cross_attn_output_proj"),
("mlp.layer1", "ff.net.0.proj", "mlp_layer1"),
("mlp.layer2", "ff.net.2", "mlp_layer2"),
]
return [
LoraConversionKeySet(omi, diffusers, legacy_diffusers_prefix=legacy, parent=key_prefix)
for omi, diffusers, legacy in mappings
]
def convert_anima_lora_key_sets() -> list[LoraConversionKeySet]:
keys = []
transformer = LoraConversionKeySet(
"lora_unet",
"transformer",
legacy_diffusers_prefix="lora_unet",
)
for block_prefix in __map_anima_blocks(transformer):
keys += __map_transformer_block(block_prefix)
return keysAfter converting, the output in ComfyUI seems to be affected by the LoRA as expected. |
|
Doesn't look like Comfyanon wants to merge this one and also keep in mind that other inference tools (at least the ones that aren't built upon Diffusers) would also have to make the same change to their code. So I say OneTrainer should include the above proposed conversion logic into it's code and settle for the de-facto standard already established. I know OT wants to use Diffusers keys whenever possible for consistency, and that's perfectly fine for all the models like Flux or Qwen, their original repos being Diffusers format, but this is a special case. Initial Anima release wasn't in Diffusers format, so it's hard to argue for the Diffusers keys. |
if that is the case, they should close the PR. As for the other points, we already had this discussion on Discord. |
|
By the way, this PR already includes conversion code: https://github.com/dxqb/OneTrainer/blob/03b7156c49bac5c8f5a8f13de259357f94047d75/modules/model/AnimaModel.py#L31 It's just not used for LoRAs currently (only for full finetunes), because this was the consistent and accepted way to do things for all other models. If inference tools want to change that now, they should make that clear (by closing the PR, for example) |
Several model savers (Ernie, Flux2, Z-Image, ...) duplicate the same deepcopy + tokenizer __deepcopy__ workaround to produce a dtype-converted copy of a diffusers pipeline for saving. Extract it into a shared helper so new savers can reuse it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a tokenizer_attrs parameter (default ("tokenizer",)) so savers with
extra/different tokenizer attributes (Flux's tokenizer_2, SD3's
tokenizer_3, HiDream's tokenizer_3/tokenizer_4) can use the same helper.
Replaces the duplicated deepcopy + tokenizer __deepcopy__ workaround in
Chroma, Ernie, Flux, Flux2, HiDream, HunyuanVideo, PixArtAlpha, Qwen,
Sana, StableDiffusion3 and Z-Image with calls to the shared helper.
No behavior change.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resolves the Ctk/PySide6 view-controller split against the LoRA/full-model output-format rework: LoRAModule.py keeps the fusion check while dropping the rank check (upstream Nerogar#1549); ModelTab.py's split becomes BaseModelTabView.py + ModelTabController.py, with the output-format selection logic living in the controller (get_output_formats), matching the TopBarController pattern.
Brings in Nerogar's Ctk/PySide6 view split (branch merge) plus the LoRA/full-model output-format rework, with no anima-specific conflicts since this base branch carries no Anima code yet.
Ports Anima's model-tab/top-bar/training-tab UI hooks onto the new Base/Ctk/PySide6 view-controller split (branch merge): __setup_anima_ui in BaseModelTabView.py and BaseTrainingTabView.py, and the Anima entries in ConvertModelUIController's and TopBarController's model-type lists.
|
Anima now has the new LoRA saver merged. You can select output formats. Both Kohya and Comfy are loaded successfully by Comfy. |
|
I tested the new output format "Comfy" with Forge-neo and I can confirm that LoRA and also LoKr can be loaded (and affects the output), without having to convert anything manually now. |
Wire attention backend selection into Anima setup (mask=False: Anima's predict() passes no attention_mask/encoder_attention_mask into model.transformer, only a pixel-space padding_mask for the conv, which is unrelated) and pass controller through the Anima UI base2 frame.
FusedModuleGroup._leaf_forward_N called the inner peft module's forward once per leaf, and that forward's orig_forward is the synthetic fused base recomputing all N leaves' base output every time -- N real base computes per leaf, N^2 total for a group of N. Add PeftBase.delta_forward, an optional hook returning just the adapter's own contribution (the term added to orig_forward(x)) without touching the base. LoRAModule and LoHaModule implement it (their deltas never read the base weight); FusedModuleGroup uses it, when available, to add each leaf's real, unfused base once instead. DoRA/OFT/LoKr keep the slower generic path (delta_forward defaults to None) since their forwards recompose the base weight itself and aren't expressible this way. Also replace the functools.partial(self._leaf_forward, leaf_index) hook with four fixed _leaf_forward_0..3 methods: torch.compile guards on leaf.forward's function identity, and a partial rebuilt on every hook_to_module() call was a fresh object each time, forcing a recompile on every hook/unhook cycle. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Remove non-explanatory/out-of-place comments, drop the untrue Cascade bracket note on LEGACY_LORA, and revert unnecessary learning_rate notation-only changes in a few presets. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…uess Mirrors the saver's _convert_legacy opt-in default: a model gets LEGACY load support only by explicitly declaring its historical layout, not by inheriting a generic reconstruction that happens to be right for most models but silently wrong for any that isn't. Flux/Flux2/HunyuanVideo/SD3 opt in via the extracted _mixture_legacy_conversion() helper; Sana's now- redundant None override is removed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Trims explanatory-only comments, converts ModelType's LEGACY/ORIGINAL_TRANSFORMER format support from denylists to allow-lists (new models default to unsupported until a saver implements them), drops the qkv-group matching's dependency on a literal "i" placeholder name (matched_leaf_groups works with any/no placeholder), removes dead fuse_qkv/fuse_split duplication in favor of a single variadic fuse(), and removes the _denoising_body_conversion identity wrapper.
…ression - Add required base-model-name field to the convert tool for LoRA/embedding conversion - Fix convert_model.py CLI crashing on any LoRA/embedding conversion - Inline the unused _check_fusion_match indirection in LoRASaverMixin - Fix Flux2 LEGACY LoRA output regression and remove leftover debug print
Squashed review fixes: centralize the LoRA param allowlist and derive SUPPORTED_PARAM_PREFIXES from FACTOR_PREFIXES, filter absent text encoders, drop dead guards, fix the DoRA chunk-swap, and trim duplicate comments. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rmats merge The lora-output-formats merge silently converted this from a denylist (everything except Sana/Wuerstchen) to an allowlist that predates Anima, dropping full-model transformer output support for it.
# Conflicts: # modules/module/FusedModule.py # modules/ui/BaseModelTabView.py # modules/util/enum/ModelType.py
# Conflicts: # modules/ui/BaseModelTabView.py # modules/util/enum/ModelType.py
Remove dead TE-related guards (Anima never supports TE/embedding training, TE is always loaded), drop unused text_encoder_lora, freeze text_conditioner explicitly, remove stray comments, and repin mgds to Nerogar/mgds@bae73e5. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Test in preview branch: https://github.com/Nerogar/OneTrainer/tree/preview
Includes: