From 6b92f2ba036fc3a28003466759cc972fae15eaa9 Mon Sep 17 00:00:00 2001 From: CalamitousFelicitousness Date: Fri, 4 Sep 2026 22:15:17 +0100 Subject: [PATCH] feat(model): add anima 2.9b as a base reference model Anima-2.9B is a depth-expanded finetune of Anima 1.0 Base carrying 40 transformer blocks against the base repo's 28. The reference entry points at the Diffusers conversion. Single-file releases load through the native loader: TransformerSpec gains an infer_config hook, the Anima spec uses it to size num_layers to the block indices in the file, and model_anima routes a checkpoint-selected safetensors through the loader with the remaining components from the base repo. --- data/reference-base.json | 8 ++ ...sness--Anima-2.9B-Preview-v1-Diffusers.jpg | Bin 0 -> 54594 bytes pipelines/anima/__init__.py | 16 +++ pipelines/model_anima.py | 34 +++-- pipelines/native_transformer.py | 19 ++- test/test-anima-native-adapters.py | 7 + test/test-native-transformer.py | 131 ++++++++++++++++++ 7 files changed, 200 insertions(+), 15 deletions(-) create mode 100644 models/Reference/CalamitousFelicitousness--Anima-2.9B-Preview-v1-Diffusers.jpg diff --git a/data/reference-base.json b/data/reference-base.json index 5ad8fad56..39f430c3b 100644 --- a/data/reference-base.json +++ b/data/reference-base.json @@ -296,6 +296,14 @@ "date": "2026 July", "size": 4.99 }, + "Anima 2.9B Preview v1": { + "path": "CalamitousFelicitousness/Anima-2.9B-Preview-v1-Diffusers", + "preview": "CalamitousFelicitousness--Anima-2.9B-Preview-v1-Diffusers.jpg", + "desc": "Anima 2.9B preview v1 by Gazingstars, a depth-expanded fine-tune of Anima 1.0 Base: the transformer is grown from 28 to 40 layers and trained on 1.7M additional anime and illustration samples with mixed tag and natural-language captions. Same Qwen3-0.6B text encoder, LLM adapter and VAE as Anima 1.0.", + "extras": "sampler: Default, cfg_scale: 4.0, steps: 30", + "date": "2026 August", + "size": 7.32 + }, "Meituan LongCat Image": { "path": "meituan-longcat/LongCat-Image", "preview": "meituan-longcat--LongCat-Image.jpg", diff --git a/models/Reference/CalamitousFelicitousness--Anima-2.9B-Preview-v1-Diffusers.jpg b/models/Reference/CalamitousFelicitousness--Anima-2.9B-Preview-v1-Diffusers.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a403db0794b3fe243c336d1aad40a0ea2e6d5a43 GIT binary patch literal 54594 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 dict: + """Derive ``num_layers`` from the highest transformer block index in the file.""" + indices = [int(m.group(1)) for key in state_dict if (m := BLOCK_INDEX.match(key))] + if not indices: + return {} + return {'num_layers': max(indices) + 1} + + ANIMA_SPEC = TransformerSpec( cls=diffusers.CosmosTransformer3DModel, converter=convert_cosmos_transformer_checkpoint_to_diffusers, @@ -37,4 +52,5 @@ ANIMA_SPEC = TransformerSpec( 'unsupported Cosmos 1.0 structure', ), ), + infer_config=infer_config, ) diff --git a/pipelines/model_anima.py b/pipelines/model_anima.py index cbf10885c..c3e20dc66 100644 --- a/pipelines/model_anima.py +++ b/pipelines/model_anima.py @@ -1,9 +1,11 @@ +import os import importlib.util import transformers import diffusers from modules import shared, devices, sd_models, model_quant, sd_hijack_te, sd_hijack_vae, errors from modules.logger import log from pipelines import generic +from pipelines.generic_map import transformers_map def _import_from_file(module_name, file_path): @@ -13,17 +15,18 @@ def _import_from_file(module_name, file_path): return mod -def init_transformer_component(repo_id, diffusers_load_config, adapter_cls): +def init_transformer_component(repo_id, diffusers_load_config, adapter_cls, local_file=None): """Load (transformer, llm_adapter_or_none). - If the UNET dropdown points at a valid safetensors, route through - :mod:`pipelines.native_transformer` with :data:`pipelines.anima.ANIMA_SPEC`, - which extracts any bundled ``llm_adapter`` weights inline with the - transformer. Otherwise fall back to :func:`generic.load_transformer` and - return ``None`` for the adapter so the caller loads it from the base repo. + A UNET dropdown selection, else ``local_file`` (a single-file checkpoint), + goes through :mod:`pipelines.native_transformer`, which also extracts a + bundled ``llm_adapter``. Without either, the transformer comes from the base + repo and the adapter is ``None`` for the caller to load. """ + from modules import sd_unet from pipelines import native_transformer - local_file = native_transformer.resolve_path() + override = native_transformer.resolve_path() + local_file = override or local_file if local_file is not None: from pipelines.anima import ANIMA_SPEC try: @@ -31,11 +34,13 @@ def init_transformer_component(repo_id, diffusers_load_config, adapter_cls): local_file, repo_id, ANIMA_SPEC, diffusers_load_config, sibling_classes={'llm_adapter': adapter_cls}, ) - return transformer, siblings.get('llm_adapter') except Exception as e: log.error(f'Load model: type=Anima custom transformer="{local_file}": {e}') errors.display(e, 'Load') return None, None + if override is not None: + sd_unet.loaded_unet = shared.opts.sd_unet + return transformer, siblings.get('llm_adapter') transformer = generic.load_transformer( repo_id, cls_name=diffusers.CosmosTransformer3DModel, @@ -51,9 +56,15 @@ def load_anima(checkpoint_info, diffusers_load_config=None): repo_id = sd_models.path_to_repo(checkpoint_info) sd_models.hf_auth_check(checkpoint_info) + # single-file checkpoint: transformer (and bundled llm_adapter) from the file, everything else from the base repo + local_file = None + if repo_id is not None and os.path.isfile(repo_id) and repo_id.lower().endswith('.safetensors'): + local_file = repo_id + repo_id = transformers_map['AnimaTextToImagePipeline'] + load_args, _quant_args = model_quant.get_dit_args(diffusers_load_config, allow_quant=False) load_args.pop('cache_dir', None) - log.debug(f'Load model: type=Anima repo="{repo_id}" config={diffusers_load_config} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype} args={load_args}') + log.debug(f'Load model: type=Anima repo="{repo_id}" file="{local_file}" config={diffusers_load_config} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype} args={load_args}') if repo_id is None or repo_id.lower() == 'none': return None @@ -69,9 +80,8 @@ def load_anima(checkpoint_info, diffusers_load_config=None): diffusers.pipelines.auto_pipeline.AUTO_INPAINT_PIPELINES_MAPPING["anima"] = AnimaInpaintPipeline generic.set_pipeline('Anima', AnimaTextToImagePipeline) - # UNET dropdown (shared.opts.sd_unet) may redirect the transformer to a - # community file that bundles both the transformer and the llm_adapter. - transformer, llm_adapter = init_transformer_component(repo_id, diffusers_load_config, modeling_llm_adapter.AnimaLLMAdapter) + # UNET dropdown or single-file checkpoint may bundle transformer and llm_adapter + transformer, llm_adapter = init_transformer_component(repo_id, diffusers_load_config, modeling_llm_adapter.AnimaLLMAdapter, local_file=local_file) if transformer is None: return None text_encoder = generic.load_text_encoder( diff --git a/pipelines/native_transformer.py b/pipelines/native_transformer.py index fc844bf5e..3c77d01cd 100644 --- a/pipelines/native_transformer.py +++ b/pipelines/native_transformer.py @@ -28,9 +28,10 @@ Algorithm: in a Cosmos 2.0 loader). 5. Partition off sibling component keys (e.g. Anima's bundled ``llm_adapter.*``). 6. Run the spec's converter if present (else pass through unchanged). -7. Fetch ``/config.json`` from the base repo, instantiate via - ``cls.from_config``, ``load_state_dict(strict=False)``, validate, dtype-cast, - quantize, and offload-place. +7. Fetch ``/config.json`` from the base repo, apply the spec's + ``infer_config`` overrides, instantiate via ``cls.from_config``, + ``load_state_dict(strict=False)``, validate, dtype-cast, quantize, and + offload-place. 8. Repeat the build for each populated sibling (no converter, no quant by default; sibling weights are read raw from the bundled file). @@ -134,6 +135,11 @@ class TransformerSpec: ``converter_handles_quant`` runs the converter before comfy_quant detection; such converters must translate marker/scale sidecar keys along with the weights. Float-oriented converters keep the default. + + ``infer_config`` receives the transformer state dict after prefix strip and + sibling partition, before the converter, and returns config overrides + merged over the base repo config (e.g. ``num_layers`` of a depth-expanded + finetune). """ cls: type @@ -146,6 +152,7 @@ class TransformerSpec: acceptable_missing: tuple[str, ...] = DEFAULT_ACCEPTABLE_MISSING zero_init_missing: tuple[str, ...] = () forbidden_markers: tuple[tuple[str, str], ...] = () + infer_config: Callable[[dict], dict] | None = None def make_default_spec(cls: type) -> TransformerSpec: @@ -296,6 +303,12 @@ def load( effective_dtype = dtype if dtype is not None else devices.dtype transformer_cfg = fetch_component_config(repo_id, spec.subfolder) + if spec.infer_config is not None: + inferred = spec.infer_config(transformer_sd) + overrides = {k: v for k, v in inferred.items() if transformer_cfg.get(k) != v} + if overrides: + log.info(f'Load model: type={spec.cls.__name__} native_transformer config={overrides}') + transformer_cfg = {**transformer_cfg, **overrides} transformer = build_component( component_name="transformer", state_dict=transformer_sd, diff --git a/test/test-anima-native-adapters.py b/test/test-anima-native-adapters.py index e2923ad32..08eae0963 100644 --- a/test/test-anima-native-adapters.py +++ b/test/test-anima-native-adapters.py @@ -821,6 +821,10 @@ def test_cosmos_rename_full_coverage(): ('blocks_0_adaln_modulation_cross_attn_2', 'transformer_blocks_0_norm2_linear_2'), ('blocks_0_adaln_modulation_mlp_1', 'transformer_blocks_0_norm3_linear_1'), ('blocks_0_adaln_modulation_mlp_2', 'transformer_blocks_0_norm3_linear_2'), + # Depth-expanded checkpoints (Anima-2.9B carries 40 blocks) + ('blocks_39_self_attn_q_proj', 'transformer_blocks_39_attn1_to_q'), + ('blocks_39_cross_attn_output_proj', 'transformer_blocks_39_attn2_to_out_0'), + ('blocks_39_mlp_layer2', 'transformer_blocks_39_ff_net_2'), ] for src, expected in cases: got = A.cosmos_rename_flat(src) @@ -837,6 +841,9 @@ def test_resolve_targets_per_prefix(): assert A.resolve_targets('diffusion_model.', 'blocks.0.self_attn.q_proj') == [ ('transformer_blocks_0_attn1_to_q', None), ] + assert A.resolve_targets('diffusion_model.', 'blocks.39.cross_attn.k_proj') == [ + ('transformer_blocks_39_attn2_to_k', None), + ] assert A.resolve_targets('diffusion_model.llm_adapter.', 'input_proj') == [ ('input_proj', None), ] diff --git a/test/test-native-transformer.py b/test/test-native-transformer.py index 84775b51e..d45cac649 100644 --- a/test/test-native-transformer.py +++ b/test/test-native-transformer.py @@ -843,6 +843,7 @@ def test_transformer_spec_defaults(): assert spec.acceptable_missing == ('rope.', 'pos_embedder.', 'learnable_pos_embed.') assert spec.ignored_prefixes == ('cond_stage_model.', 'conditioner.', 'first_stage_model.', 'text_encoders.', 'vae.') assert spec.forbidden_markers == () + assert spec.infer_config is None def test_sibling_spec_defaults(): @@ -903,6 +904,23 @@ class MockKwargsTransformer(MockMiniTransformer): return cls(dim=config['dim']) +class MockLayeredTransformer(torch.nn.Module): + """Depth comes from config, mirroring ``num_layers`` on real DiTs.""" + + @classmethod + def from_config(cls, config: dict) -> 'MockLayeredTransformer': + return cls(dim=config['dim'], num_layers=config['num_layers']) + + def __init__(self, dim: int, num_layers: int): + super().__init__() + self.blocks = torch.nn.ModuleList([torch.nn.Linear(dim, dim) for _ in range(num_layers)]) + + +def infer_num_layers(state_dict: dict) -> dict: + indices = [int(k.split('.')[1]) for k in state_dict if k.startswith('blocks.')] + return {'num_layers': max(indices) + 1} if indices else {} + + def write_fixture(state_dict_keys: dict, fd: int, path: str, metadata: dict | None = None) -> str: os.close(fd) safetensors.torch.save_file(state_dict_keys, path, metadata=metadata) @@ -1012,6 +1030,51 @@ def test_load_forwards_kwargs_to_from_config(): os.unlink(path) +def test_load_infer_config_sizes_module_to_file(): + """A file deeper than the base config loads only with the hook; without it + the extra block is an arch mismatch.""" + fd, path = tempfile.mkstemp(suffix='.safetensors') + try: + dim = 8 + file_layers = 3 + raw = {} + for i in range(file_layers): + raw[f'model.diffusion_model.blocks.{i}.weight'] = torch.randn(dim, dim) + raw[f'model.diffusion_model.blocks.{i}.bias'] = torch.zeros(dim) + write_fixture(raw, fd, path) + + orig_fetch = nt.fetch_component_config + nt.fetch_component_config = lambda repo, sub: {'dim': dim, 'num_layers': 2} + from modules import model_quant + orig_get_dit = model_quant.get_dit_args + orig_get_qtype = model_quant.get_quant_type + orig_do_post = model_quant.do_post_load_quant + model_quant.get_dit_args = lambda *a, **k: ({}, {}) + model_quant.get_quant_type = lambda *a, **k: None + model_quant.do_post_load_quant = lambda *a, **k: None + + try: + try: + nt.load(local_file=path, repo_id='fake/repo', spec=nt.TransformerSpec(cls=MockLayeredTransformer), diffusers_cfg={}) + raise AssertionError('expected OverrideArchMismatch without infer_config') + except nt.OverrideArchMismatch: + pass + spec = nt.TransformerSpec(cls=MockLayeredTransformer, infer_config=infer_num_layers) + transformer, _ = nt.load(local_file=path, repo_id='fake/repo', spec=spec, diffusers_cfg={}) + finally: + nt.fetch_component_config = orig_fetch + model_quant.get_dit_args = orig_get_dit + model_quant.get_quant_type = orig_get_qtype + model_quant.do_post_load_quant = orig_do_post + + assert len(transformer.blocks) == file_layers + loaded_w = transformer.blocks[2].weight.detach().cpu() + assert torch.allclose(loaded_w, raw['model.diffusion_model.blocks.2.weight'].to(loaded_w.dtype)) + finally: + if os.path.exists(path): + os.unlink(path) + + def test_load_end_to_end_with_sibling_partition(): """Bundled-sibling case: file carries both transformer and sibling weights, sibling_classes supplies the runtime sibling class, partition routes each @@ -2204,6 +2267,61 @@ def test_build_component_comfy_preempts_sdnq_fresh_quant(): assert component.in_proj.weight.dtype == torch.int8 +# ============================================================ +# anima config inference (depth-expanded checkpoints) +# ============================================================ + +def anima_block_keys(count: int, prefix: str = 'blocks') -> dict: + sd = {} + for i in range(count): + sd[f'{prefix}.{i}.self_attn.q_proj.weight'] = torch.zeros(2, 2) + sd[f'{prefix}.{i}.mlp.layer2.weight'] = torch.zeros(2, 2) + return sd + + +def test_anima_infer_config_counts_cosmos_blocks(): + """40-block file reports num_layers=40; adapter ``blocks.N`` keys and + top-level tensors do not count.""" + from pipelines import anima + sd = anima_block_keys(40) + sd['llm_adapter.blocks.5.self_attn.q_proj.weight'] = torch.zeros(2, 2) + sd['x_embedder.proj.1.weight'] = torch.zeros(2, 2) + sd['final_layer.linear.weight'] = torch.zeros(2, 2) + assert anima.infer_config(sd) == {'num_layers': 40} + + +def test_anima_infer_config_matches_base_depth(): + from pipelines import anima + assert anima.infer_config(anima_block_keys(28)) == {'num_layers': 28} + + +def test_anima_infer_config_diffusers_layout(): + """Files already in diffusers key layout count ``transformer_blocks.N``.""" + from pipelines import anima + assert anima.infer_config(anima_block_keys(40, prefix='transformer_blocks')) == {'num_layers': 40} + + +def test_anima_infer_config_comfy_sidecars_do_not_inflate(): + """Per-block quant sidecars share the block index and do not change the count.""" + from pipelines import anima + sd = anima_block_keys(40) + for i in range(40): + sd[f'blocks.{i}.self_attn.q_proj.weight_scale'] = torch.zeros(2, 1) + sd[f'blocks.{i}.self_attn.q_proj.comfy_quant'] = torch.zeros(8, dtype=torch.uint8) + assert anima.infer_config(sd) == {'num_layers': 40} + + +def test_anima_infer_config_no_blocks_returns_empty(): + from pipelines import anima + assert anima.infer_config({'x_embedder.proj.1.weight': torch.zeros(2, 2)}) == {} + assert anima.infer_config({}) == {} + + +def test_anima_spec_registers_infer_config(): + from pipelines import anima + assert anima.ANIMA_SPEC.infer_config is anima.infer_config + + # ============================================================ # Run # ============================================================ @@ -2353,6 +2471,7 @@ def run_all(): for fn in [ test_load_end_to_end_with_bfl_prefix_no_converter, test_load_forwards_kwargs_to_from_config, + test_load_infer_config_sizes_module_to_file, test_load_end_to_end_with_sibling_partition, test_load_raises_on_missing_sibling_class, test_load_rejects_non_safetensors, @@ -2401,6 +2520,18 @@ def run_all(): ]: run_test(cat, fn) + log.warning('=== anima config inference ===') + cat = category('anima') + for fn in [ + test_anima_infer_config_counts_cosmos_blocks, + test_anima_infer_config_matches_base_depth, + test_anima_infer_config_diffusers_layout, + test_anima_infer_config_comfy_sidecars_do_not_inflate, + test_anima_infer_config_no_blocks_returns_empty, + test_anima_spec_registers_infer_config, + ]: + run_test(cat, fn) + log.warning('=== Results ===') total_passed = 0 total_failed = 0