Instructions to use darask0/MOSS-Image_4-step_adapter_lora with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use darask0/MOSS-Image_4-step_adapter_lora with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("OpenMOSS-Team/MOSS-Image-SFT", dtype=torch.bfloat16, device_map="cuda") pipe.load_lora_weights("darask0/MOSS-Image_4-step_adapter_lora") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- Draw Things
- DiffusionBee
Download code/tests/test_comfy_adapter.py from darask0/MOSS-Image_4-step_adapter_lora: direct link, hf CLI and curl.
- Browser
- Download file 5.87 kB
-
https://huggingface.co/darask0/MOSS-Image_4-step_adapter_lora/resolve/main/code/tests/test_comfy_adapter.py
- Command line
-
hf download hf://darask0/MOSS-Image_4-step_adapter_lora/code/tests/test_comfy_adapter.py
-
curl -L -o test_comfy_adapter.py https://huggingface.co/darask0/MOSS-Image_4-step_adapter_lora/resolve/main/code/tests/test_comfy_adapter.py
5.87 kB
| """COMFYUI_ROOT=/path/to/ComfyUI python -m pytest code/tests/test_comfy_adapter.py""" | |
| import importlib.util | |
| import os | |
| from pathlib import Path | |
| import sys | |
| import pytest | |
| import torch | |
| from safetensors.torch import save_file | |
| sys.path.insert(0, os.environ['COMFYUI_ROOT']) | |
| from comfy.cli_args import args | |
| args.cpu = True | |
| import comfy.ops | |
| from comfy.ldm.moss_image.model import MOSSImage | |
| from comfy.model_patcher import ModelPatcher | |
| spec = importlib.util.spec_from_file_location('rapid_nodes', Path(__file__).parents[2] / 'comfyui/rapid-moss/nodes.py') | |
| rapid = importlib.util.module_from_spec(spec) | |
| spec.loader.exec_module(rapid) | |
| def adapter(tmp_path, monkeypatch): | |
| torch.manual_seed(123) | |
| dim, ffn, rank = 128, 192, 3 | |
| lora = {} | |
| for name in rapid.PROJ: | |
| inp, out = (ffn, dim) if name == 'ffn_down' else (dim, 2 * ffn if name == 'ffn_up_gate' else dim) | |
| prefix = 'diffusion_model.layers.0.proj.' + name | |
| lora[prefix + '.lora_down.weight'] = torch.randn(rank, inp) * 0.03 | |
| lora[prefix + '.lora_up.weight'] = torch.randn(out, rank) * 0.03 | |
| lora[prefix + '.alpha'] = torch.tensor(float(rank)) | |
| time = { | |
| 'time_embedding.0.weight': torch.randn(dim, 256) * .01, | |
| 'time_embedding.0.bias': torch.randn(dim) * .01, | |
| 'time_embedding.2.weight': torch.randn(dim, dim) * .01, | |
| 'time_embedding.2.bias': torch.randn(dim) * .01, | |
| 'shared_block_modulation.bias': torch.randn(6 * dim) * .01, | |
| 'video_head_modulation.bias': torch.randn(2 * dim) * .01, | |
| } | |
| save_file(lora, tmp_path / 'lora.safetensors') | |
| save_file(time, tmp_path / 'time_embedding.safetensors') | |
| save_file({'latent_mix.Q': torch.eye(128), 'step_codes': torch.tensor([1000, 968, 926, 871])}, | |
| tmp_path / 'dataspace.safetensors') | |
| monkeypatch.setattr(rapid, '_adapter_dirs', lambda: {'test': str(tmp_path)}) | |
| return lora | |
| def make_model(fused): | |
| holder = torch.nn.Module() | |
| holder.diffusion_model = MOSSImage(dim=128, ffn_dim=192, num_heads=1, num_layers=1, | |
| fused_qkv=fused, dtype=torch.float32, operations=comfy.ops.manual_cast) | |
| for p in holder.parameters(): | |
| torch.nn.init.normal_(p, std=.02) | |
| return ModelPatcher(holder, torch.device('cpu'), torch.device('cpu')) | |
| def test_lora_apply_and_restore(adapter, fused): | |
| model = make_model(fused) | |
| layer = model.model.diffusion_model.layers[0] | |
| base_weights = {k: m.weight.detach().clone() for k, m in layer.proj.items()} | |
| patched, _, sigmas = rapid.RapidMOSSAdapter().apply(model, 'test', 4, .7) | |
| assert sigmas.tolist() == pytest.approx([1, .968, .926, .871, 0]) | |
| assert not model.object_patches | |
| patched.patch_model(load_weights=False) | |
| for name, module in layer.proj.items(): | |
| x = torch.randn(1, 5, module.weight.shape[1]) | |
| expected = torch.nn.functional.linear(x, base_weights[name]) | |
| names = ('q', 'k', 'v') if name == 'qkv' else (name,) | |
| deltas = [] | |
| for proj in names: | |
| prefix = 'diffusion_model.layers.0.proj.' + proj | |
| deltas.append(.7 * (x @ adapter[prefix + '.lora_down.weight'].T) @ adapter[prefix + '.lora_up.weight'].T) | |
| expected += torch.cat(deltas, dim=-1) | |
| torch.testing.assert_close(module(x), expected) | |
| torch.testing.assert_close(module.weight, base_weights[name], rtol=0, atol=0) | |
| patched.unpatch_model() | |
| for name, module in layer.proj.items(): | |
| x = torch.randn(1, 2, module.weight.shape[1]) | |
| torch.testing.assert_close(module(x), torch.nn.functional.linear(x, base_weights[name])) | |
| def test_sampler_matches_dataspace_recurrence(): | |
| torch.manual_seed(4) | |
| z = torch.randn(1, 3, 2, 2) | |
| q = torch.randn(3, 3) * .1 | |
| codes = torch.tensor([1000, 968, 926, 871]) | |
| sigmas = torch.cat((codes.float() / 1000, torch.zeros(1))) | |
| calls = [] | |
| def denoise(x, sigma): | |
| calls.append(sigma.clone()) | |
| return x - sigma[:, None, None, None] * (x * .3 + sigma[:, None, None, None]) | |
| expected = torch.zeros_like(z) | |
| for code in codes: | |
| x = z + torch.einsum('oc,bchw->bohw', q, expected) | |
| expected = z - (x * .3 + code / 1000) | |
| actual = rapid.sample_dataspace(denoise, z, sigmas, Q=q, codes=codes) | |
| torch.testing.assert_close(actual, expected) | |
| assert len(calls) == 4 | |
| def test_reject_too_many_steps(adapter): | |
| with pytest.raises(ValueError, match='4 step codes'): | |
| rapid.RapidMOSSAdapter().apply(make_model(True), 'test', 5, 1.) | |
| def test_native_forward_fused_matches_split(adapter, dtype, device): | |
| model = make_model(False) | |
| fused = make_model(True) | |
| sd = model.model.state_dict() | |
| prefix = 'diffusion_model.layers.0.proj.' | |
| sd[prefix + 'qkv.weight'] = torch.cat([sd.pop(prefix + n + '.weight') for n in ('q', 'k', 'v')]) | |
| fused.model.load_state_dict(sd) | |
| x = torch.randn(1, 128, 2, 3, device=device, dtype=dtype) | |
| ctx = torch.randn(1, 4, 4096, device=device, dtype=dtype) | |
| t = torch.tensor([.968], device=device) | |
| outputs = [] | |
| for m in (model, fused): | |
| m.model.to(device=device, dtype=dtype) | |
| patched, _, _ = rapid.RapidMOSSAdapter().apply(m, 'test', 4, 1.) | |
| patched.patch_model(load_weights=False) | |
| with torch.no_grad(): | |
| outputs.append(m.model.diffusion_model(x.clone(), t, ctx)) | |
| patched.unpatch_model() | |
| assert all(torch.isfinite(out).all() for out in outputs) | |
| assert all(out.abs().max() < 10 for out in outputs) | |
| torch.testing.assert_close(*outputs, rtol=.01, atol=.001) | |