From e7d2e28d3d68fdce3b24d82c1dfede327d3cb15d Mon Sep 17 00:00:00 2001 From: CalamitousFelicitousness Date: Mon, 25 May 2026 05:47:56 +0100 Subject: [PATCH] feat(pipelines): wire native_spec for arches missing single_file_model entry ChronoEdit, HunyuanImage, Kandinsky5, LongCat, Ovis, NucleusMoE, Bria, BriaFibo. Each inherits from_single_file via FromOriginalModelMixin but has no SINGLE_FILE_LOADABLE_CLASSES entry; calling it crashed with "FromOriginalModelMixin is currently only compatible with [...]". TransformerSpec(cls=...) for each. Bria specs in pipelines/bria/__init__.py; the rest are module-level in model_.py since they have no package directory. --- pipelines/bria/__init__.py | 29 +++++++++++++++++++++++++++++ pipelines/model_bria.py | 5 ++++- pipelines/model_chrono.py | 6 +++++- pipelines/model_hyimage.py | 6 +++++- pipelines/model_kandinsky.py | 6 +++++- pipelines/model_longcat.py | 6 +++++- pipelines/model_nucleus.py | 5 +++++ pipelines/model_ovis.py | 6 +++++- 8 files changed, 63 insertions(+), 6 deletions(-) diff --git a/pipelines/bria/__init__.py b/pipelines/bria/__init__.py index e69de29bb..4dcb2d97a 100644 --- a/pipelines/bria/__init__.py +++ b/pipelines/bria/__init__.py @@ -0,0 +1,29 @@ +"""Bria pipeline package. + +Exports :data:`BRIA_SPEC` and :data:`BRIA_FIBO_SPEC` for use by +:mod:`pipelines.model_bria` together with :mod:`pipelines.native_transformer`. + +Bria ships two transformer variants: + +- The original Bria family uses a custom :class:`BriaTransformer2DModel` + imported from :mod:`pipelines.bria.transformer_bria`. The custom class + has no entry in diffusers' ``SINGLE_FILE_LOADABLE_CLASSES`` table, so a + community single-file selection previously crashed in + ``ModelMixin.from_pretrained``. +- Bria FIBO (and FIBO Edit) use the upstream + :class:`diffusers.BriaFiboTransformer2DModel`, which also lacks a + ``SINGLE_FILE_LOADABLE_CLASSES`` entry. Same crash. + +Both specs use the default 3-prefix detection +(``model.diffusion_model.``, ``diffusion_model.``, ``net.``), no +converter, and no siblings. +""" + +import diffusers + +from pipelines.bria.transformer_bria import BriaTransformer2DModel +from pipelines.native_transformer import TransformerSpec + + +BRIA_SPEC = TransformerSpec(cls=BriaTransformer2DModel) +BRIA_FIBO_SPEC = TransformerSpec(cls=diffusers.BriaFiboTransformer2DModel) diff --git a/pipelines/model_bria.py b/pipelines/model_bria.py index ae9c9fa7a..961f9c26f 100644 --- a/pipelines/model_bria.py +++ b/pipelines/model_bria.py @@ -20,11 +20,13 @@ def load_bria(checkpoint_info, diffusers_load_config=None): load_args, _quant_args = model_quant.get_dit_args(diffusers_load_config, allow_quant=False) log.debug(f'Load model: type=BriaFibo repo="{repo_id}" config={diffusers_load_config} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype} args={load_args}') + from pipelines.bria import BRIA_FIBO_SPEC transformer = generic.load_transformer( repo_id, cls_name=diffusers.BriaFiboTransformer2DModel, load_config=diffusers_load_config, allow_quant=False, + native_spec=BRIA_FIBO_SPEC, ) text_encoder = generic.load_text_encoder( repo_id, @@ -66,7 +68,8 @@ def load_bria(checkpoint_info, diffusers_load_config=None): load_args, _quant_args = model_quant.get_dit_args(diffusers_load_config, allow_quant=False) log.debug(f'Load model: type=Bria repo="{repo_id}" config={diffusers_load_config} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype} args={load_args}') - transformer = generic.load_transformer(repo_id, cls_name=BriaTransformer2DModel, load_config=diffusers_load_config) + from pipelines.bria import BRIA_SPEC + transformer = generic.load_transformer(repo_id, cls_name=BriaTransformer2DModel, load_config=diffusers_load_config, native_spec=BRIA_SPEC) text_encoder = generic.load_text_encoder(repo_id, cls_name=transformers.T5EncoderModel, load_config=diffusers_load_config) pipe = BriaPipeline.from_pretrained( diff --git a/pipelines/model_chrono.py b/pipelines/model_chrono.py index 502e7d89d..1bab65c04 100644 --- a/pipelines/model_chrono.py +++ b/pipelines/model_chrono.py @@ -3,6 +3,10 @@ import transformers from modules import shared, devices, sd_models, model_quant, sd_hijack_te, sd_hijack_vae from modules.logger import log from pipelines import generic +from pipelines.native_transformer import TransformerSpec + + +CHRONOEDIT_SPEC = TransformerSpec(cls=diffusers.ChronoEditTransformer3DModel) def postprocess(p, result): # pylint: disable=unused-argument @@ -21,7 +25,7 @@ def load_chrono(checkpoint_info, diffusers_load_config=None): load_args, _quant_args = model_quant.get_dit_args(diffusers_load_config, allow_quant=False) log.debug(f'Load model: type=ChronoEdit repo="{repo_id}" config={diffusers_load_config} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype} args={load_args}') - transformer = generic.load_transformer(repo_id, cls_name=diffusers.ChronoEditTransformer3DModel, load_config=diffusers_load_config, subfolder="transformer") + transformer = generic.load_transformer(repo_id, cls_name=diffusers.ChronoEditTransformer3DModel, load_config=diffusers_load_config, subfolder="transformer", native_spec=CHRONOEDIT_SPEC) text_encoder = generic.load_text_encoder(repo_id, cls_name=transformers.UMT5EncoderModel, load_config=diffusers_load_config, subfolder="text_encoder") try: diff --git a/pipelines/model_hyimage.py b/pipelines/model_hyimage.py index 4cf9776ee..2bed9851b 100644 --- a/pipelines/model_hyimage.py +++ b/pipelines/model_hyimage.py @@ -5,6 +5,10 @@ import diffusers from modules import shared, sd_models, devices, model_quant, sd_hijack_te, sd_hijack_vae from modules.logger import log from pipelines import generic +from pipelines.native_transformer import TransformerSpec + + +HUNYUANIMAGE_SPEC = TransformerSpec(cls=diffusers.HunyuanImageTransformer2DModel) def load_hyimage(checkpoint_info, diffusers_load_config=None): # pylint: disable=unused-argument @@ -16,7 +20,7 @@ def load_hyimage(checkpoint_info, diffusers_load_config=None): # pylint: disable load_args, _quant_args = model_quant.get_dit_args(diffusers_load_config) log.debug(f'Load model: type=HunyuanImage21 repo="{repo_id}" config={diffusers_load_config} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype} args={load_args}') - transformer = generic.load_transformer(repo_id, cls_name=diffusers.HunyuanImageTransformer2DModel, load_config=diffusers_load_config, subfolder="transformer") + transformer = generic.load_transformer(repo_id, cls_name=diffusers.HunyuanImageTransformer2DModel, load_config=diffusers_load_config, subfolder="transformer", native_spec=HUNYUANIMAGE_SPEC) text_encoder = generic.load_text_encoder(repo_id, cls_name=transformers.Qwen2_5_VLForConditionalGeneration, load_config=diffusers_load_config, subfolder="text_encoder") text_encoder_2 = generic.load_text_encoder(repo_id, cls_name=transformers.T5EncoderModel, load_config=diffusers_load_config, subfolder="text_encoder_2", allow_shared=False) diff --git a/pipelines/model_kandinsky.py b/pipelines/model_kandinsky.py index d8e950177..4f06e185d 100644 --- a/pipelines/model_kandinsky.py +++ b/pipelines/model_kandinsky.py @@ -3,6 +3,10 @@ import diffusers from modules import shared, sd_models, devices, model_quant, sd_hijack_te, sd_hijack_vae from modules.logger import log from pipelines import generic +from pipelines.native_transformer import TransformerSpec + + +KANDINSKY5_SPEC = TransformerSpec(cls=diffusers.Kandinsky5Transformer3DModel) def load_kandinsky21(checkpoint_info, diffusers_load_config=None): @@ -83,7 +87,7 @@ def load_kandinsky5(checkpoint_info, diffusers_load_config=None): load_args, _quant_args = model_quant.get_dit_args(diffusers_load_config) log.debug(f'Load model: type=Kandinsky50 repo="{repo_id}" config={diffusers_load_config} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype} args={load_args}') - transformer = generic.load_transformer(repo_id, cls_name=diffusers.Kandinsky5Transformer3DModel, load_config=diffusers_load_config) + transformer = generic.load_transformer(repo_id, cls_name=diffusers.Kandinsky5Transformer3DModel, load_config=diffusers_load_config, native_spec=KANDINSKY5_SPEC) text_encoder = generic.load_text_encoder(repo_id, cls_name=transformers.Qwen2_5_VLForConditionalGeneration, load_config=diffusers_load_config) if 'I2I' in repo_id: diff --git a/pipelines/model_longcat.py b/pipelines/model_longcat.py index ac8a27322..8af13fffe 100644 --- a/pipelines/model_longcat.py +++ b/pipelines/model_longcat.py @@ -3,6 +3,10 @@ import diffusers from modules import shared, devices, sd_models, model_quant, sd_hijack_te from modules.logger import log from pipelines import generic +from pipelines.native_transformer import TransformerSpec + + +LONGCAT_SPEC = TransformerSpec(cls=diffusers.LongCatImageTransformer2DModel) def load_longcat(checkpoint_info, diffusers_load_config=None): @@ -14,7 +18,7 @@ def load_longcat(checkpoint_info, diffusers_load_config=None): load_args, _quant_args = model_quant.get_dit_args(diffusers_load_config, allow_quant=False) log.debug(f'Load model: type=LongCat repo="{repo_id}" config={diffusers_load_config} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype} args={diffusers_load_config}') - transformer = generic.load_transformer(repo_id, cls_name=diffusers.LongCatImageTransformer2DModel, load_config=diffusers_load_config) + transformer = generic.load_transformer(repo_id, cls_name=diffusers.LongCatImageTransformer2DModel, load_config=diffusers_load_config, native_spec=LONGCAT_SPEC) text_encoder = generic.load_text_encoder(repo_id, cls_name=transformers.Qwen2_5_VLForConditionalGeneration, load_config=diffusers_load_config) text_processor = transformers.Qwen2VLProcessor.from_pretrained(repo_id, subfolder='tokenizer', cache_dir=shared.opts.hfcache_dir) diff --git a/pipelines/model_nucleus.py b/pipelines/model_nucleus.py index b7087fa59..8625bc7db 100644 --- a/pipelines/model_nucleus.py +++ b/pipelines/model_nucleus.py @@ -3,6 +3,10 @@ import transformers from modules import shared, devices, sd_models, model_quant, sd_hijack_te, sd_hijack_vae from modules.logger import log from pipelines import generic +from pipelines.native_transformer import TransformerSpec + + +NUCLEUS_SPEC = TransformerSpec(cls=diffusers.NucleusMoEImageTransformer2DModel) def load_nucleus(checkpoint_info, diffusers_load_config=None): @@ -18,6 +22,7 @@ def load_nucleus(checkpoint_info, diffusers_load_config=None): repo_id, cls_name=diffusers.NucleusMoEImageTransformer2DModel, load_config=diffusers_load_config, + native_spec=NUCLEUS_SPEC, ) text_encoder = generic.load_text_encoder( repo_id, diff --git a/pipelines/model_ovis.py b/pipelines/model_ovis.py index e4e65270f..1cd26a63c 100644 --- a/pipelines/model_ovis.py +++ b/pipelines/model_ovis.py @@ -3,6 +3,10 @@ import diffusers from modules import shared, devices, sd_models, model_quant, sd_hijack_te from modules.logger import log from pipelines import generic +from pipelines.native_transformer import TransformerSpec + + +OVIS_SPEC = TransformerSpec(cls=diffusers.OvisImageTransformer2DModel) def load_ovis(checkpoint_info, diffusers_load_config=None): @@ -14,7 +18,7 @@ def load_ovis(checkpoint_info, diffusers_load_config=None): load_args, _quant_args = model_quant.get_dit_args(diffusers_load_config, allow_quant=False) log.debug(f'Load model: type=OvisImage repo="{repo_id}" config={diffusers_load_config} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype} args={diffusers_load_config}') - transformer = generic.load_transformer(repo_id, cls_name=diffusers.OvisImageTransformer2DModel, load_config=diffusers_load_config) + transformer = generic.load_transformer(repo_id, cls_name=diffusers.OvisImageTransformer2DModel, load_config=diffusers_load_config, native_spec=OVIS_SPEC) text_encoder = generic.load_text_encoder(repo_id, cls_name=transformers.Qwen3Model, load_config=diffusers_load_config) pipe = diffusers.OvisImagePipeline.from_pretrained(