9
stars
5
commits
1
repos using this model
3
linked in READMEs
Jun 5, 2026
updated
π Part of the Lance MLX collection on mlx-community.
MLX port of ByteDance Intelligent Creation Lab's Lance unified multimodal model β the image-specialist Lance_3B checkpoint, converted to bf16 for Apple Silicon. ~6.19 B LLM parameters in MoT (Mixture-of-Transformer-Experts) layout, plus the Qwen2.5-VL ViT (~669 M) and Lance's bundled Wan2.2 VAE (~705 M) for full image-task coverage.
Lance is ByteDance's 3B-active unified multimodal model (paper, code, HF original). This is not Lance/LanceDB, the columnar data format.
π’ Production-ready for image tasks on Apple Silicon as of 2026-05-21.
| Capability | Status |
|---|---|
| t2i (text β image) | β Photorealistic, prompt-aligned. 768Β² output at ~6.7 s/step. |
| image_edit (instruction-based editing) | β Identity + style + signature preservation verified. ~6.7 s/step. |
| x2t_image (image understanding / VQA) | β Content-correct across all 6 oracle cases. |
| KV cache for autoregressive decode | β 1.7Γβ2.8Γ speedup over no-cache baseline. |
For video tasks (t2v, video_edit, x2t_video), see mlx-community/Lance-3B-Video-bf16. All six Lance task families are now validated end-to-end on Apple Silicon as of 2026-05-21.
The 48-channel Wan2.2 VAE is bundled here for convenience but also published standalone at mlx-community/Wan2.2-VAE-Lance-bf16 β both image_edit and the video pipelines need it.
memory_mode, 2026-06-02)The lance-mlx source repo's memory_mode knob (auto / parallel / relay) brings bf16 image generation within reach of 8β16 GB Apple Silicon Macs:
| RAM | Mode | t2i / image_edit | Notes |
|---|---|---|---|
| 8β16 GB | relay (auto-resolved) | β 768Β² bf16, no swap | Single-shot per pipeline load β re-prefill reloads the UND tower. ~5 min/image at 768Β² on a base-RAM M-series Mac. |
| 24 GB+ | parallel (auto-resolved) | β 768Β² bf16, reusable | Pipeline stays resident across calls. |
relay produces byte-identical output to parallel (MD5-verified on real Lance-3B-bf16) β it sheds the UND tower after prefill and frees the GEN tower before VAE decode, so peak memory β heaviest single phase rather than the sum of all three. Default auto resolves by mx.device_info()'s recommended working-set size with the split at ~18 GiB. The same envelope and modes apply to mlx-community/Lance-3B-Video-bf16 for video tasks.
lossless_decode, 2026-06-05)generate(..., lossless_decode=True) (default since 2026-06-05) uses a bit-identical streaming VAE decode that's lighter than the naive whole dec(z) in every measured config β via temporal causal-cache streaming (flat in frame count) and spatial halo-tile + crop (no blend β exact). 50-case bit-identity test in lance-mlx with a negative control verifies the guarantee. lossless_decode=False keeps the lossy trapezoidal-blend tiling from the prior path (~1.5β4.8 / 255 off the reference) for the one config where lossless exceeds 16 GB (768Β² video; lossless on 1024Β² image fits 16 GB cleanly at ~12.2 GB).
Full envelope and ri_phys-measured numbers (true OS-committed footprint, supersedes the older mx.get_peak_memory() quotes which under-report ~2Γ) in the source repo's LIMITS.md.
For VQA-only use cases on small Macs, the compressed mlx-community/Lance-3B-AWQ-INT4 variant is also available (3.3 GB LLM, 6-9Γ faster long-form decode; VQA only, not for image generation).
Install from the source repo (will be on PyPI in a follow-up release):
git clone https://github.com/xocialize/lance-mlx
cd lance-mlx && uv sync
Download this checkpoint:
from huggingface_hub import snapshot_download
weights = snapshot_download("mlx-community/Lance-3B-bf16")
from lance_mlx.pipeline.t2i import TextToImagePipeline
pipe = TextToImagePipeline.from_pretrained(
lance_weights_dir=weights,
vae_safetensors=f"{weights}/vae.safetensors",
)
image = pipe.generate(
"A photorealistic tabby cat holding up a colorful STOP sign on a sunlit street.",
height=768, width=768, num_steps=30, cfg_scale=4.0, seed=42,
)
image.save("cat_with_stop.png")
from lance_mlx.pipeline.image_edit import ImageEditPipeline
pipe = ImageEditPipeline.from_pretrained(
lance_weights_dir=weights,
vae_safetensors=f"{weights}/vae.safetensors",
)
edited = pipe.generate(
input_image="portrait.jpg",
instruction="Remove the hat from the painting.",
height=768, width=768, num_steps=30, cfg_scale=4.0, seed=42,
)
edited.save("portrait_no_hat.png")
from lance_mlx.pipeline.understanding import UnderstandingPipeline
from PIL import Image
pipe = UnderstandingPipeline.from_pretrained(
lance_weights_dir=weights,
vit_safetensors=f"{weights}/vit.safetensors",
)
answer = pipe.generate(
Image.open("license_plate.png"),
"What is the license plate number visible in this image?",
max_new_tokens=64, prompt_style="lance",
)
print(answer)
| Task | Configuration | Wall-clock |
|---|---|---|
| t2i | 768Β² Γ 30 steps Γ CFG=4.0 | ~201 s |
| image_edit | 768Β² Γ 30 steps Γ CFG=4.0 | ~201 s |
| x2t_image | 6 oracle cases (5β100 token answers), KV-cached | ~34 s combined |
KV cache scales with answer length: 1.7Γ speedup on a 5-token answer, 2.8Γ on a ~100-token answer.
LLM_UND, LLM_GEN), each initialized from Qwen2.5-VL-3B-Instruct, with per-expert FFN, output projection, and QK-norm.LLM_UND (autoregressive next-token); Wan2.2 VAE latent tokens β LLM_GEN (flow-matching velocity prediction). No learned gate.wan2.2_vae.safetensors).causal_mask OR full_and_noise_mask per upstream data/data_utils.py::create_sparse_mask. Without this, the noisy-VAE position 0 of a 2304-token image grid can only see itself + text, producing blurry outputs across all prompts.| File | Size | Purpose |
|---|---|---|
model.safetensors | 12.37 GB | LLM weights (1021 tensors, both UND + GEN towers) |
vit.safetensors | 1.34 GB | Qwen2.5-VL ViT (semantic encoder for x2t_image + image_edit) |
vae.safetensors | 1.41 GB | Lance's bundled Wan2.2 VAE (encoder + decoder, 48-ch) |
config.json | β | Qwen2_5_VLForConditionalGeneration config with tie_word_embeddings=false |
conversion_report.json | β | Provenance of safetensors conversion (PyTorch β MLX bf16) |
tokenizer.json / vocab.json | β | Qwen2.5-VL vocabulary (151,936 tokens) |
Source: bytedance-research/Lance/Lance_3B/model.safetensors (1021 tensors, 6.185 B params).
Conversion script: scripts/02_convert.py in the lance-mlx repo. The script:
language_model. prefix; the MLX LanceModel is the root, not nested.vit_model.* keys) into a sibling vit.safetensors for parity with the Lance_3B distribution shape.llm2vae.weight/bias and time_embedder.mlp.{0,2}.{weight,bias} to match scaffolded MLX modules.Wan2.2 VAE source: bytedance-research/Lance/Wan2.2_VAE.pth β scripts/06_convert_wan_vae.py. Roundtrip MAD on a real photo at 768Β² is ~7/255 in u8 domain.
This MLX port: Apache 2.0.
Underlying weights:
See NOTICE for full attribution.
@article{fu2026lance,
title={Lance: Unified Multimodal Modeling by Multi-Task Synergy},
author={Fu, Fengyi and Huang, Mengqi and Wu, Shaojin and others},
journal={arXiv preprint arXiv:2605.18678},
year={2026}
}
github.com/xocialize/lance-mlxbytedance-research/Lancemlx-community/Wan2.2-VAE-Lance-bf16mlx-community/Lance-3B-Video-bf165 commits
9
stars
5
commits
1
repos using this model
3
linked in READMEs
Jun 5, 2026
updated
π Part of the Lance MLX collection on mlx-community.
MLX port of ByteDance Intelligent Creation Lab's Lance unified multimodal model β the image-specialist Lance_3B checkpoint, converted to bf16 for Apple Silicon. ~6.19 B LLM parameters in MoT (Mixture-of-Transformer-Experts) layout, plus the Qwen2.5-VL ViT (~669 M) and Lance's bundled Wan2.2 VAE (~705 M) for full image-task coverage.
Lance is ByteDance's 3B-active unified multimodal model (paper, code, HF original). This is not Lance/LanceDB, the columnar data format.
π’ Production-ready for image tasks on Apple Silicon as of 2026-05-21.
| Capability | Status |
|---|---|
| t2i (text β image) | β Photorealistic, prompt-aligned. 768Β² output at ~6.7 s/step. |
| image_edit (instruction-based editing) | β Identity + style + signature preservation verified. ~6.7 s/step. |
| x2t_image (image understanding / VQA) | β Content-correct across all 6 oracle cases. |
| KV cache for autoregressive decode | β 1.7Γβ2.8Γ speedup over no-cache baseline. |
For video tasks (t2v, video_edit, x2t_video), see mlx-community/Lance-3B-Video-bf16. All six Lance task families are now validated end-to-end on Apple Silicon as of 2026-05-21.
The 48-channel Wan2.2 VAE is bundled here for convenience but also published standalone at mlx-community/Wan2.2-VAE-Lance-bf16 β both image_edit and the video pipelines need it.
memory_mode, 2026-06-02)The lance-mlx source repo's memory_mode knob (auto / parallel / relay) brings bf16 image generation within reach of 8β16 GB Apple Silicon Macs:
| RAM | Mode | t2i / image_edit | Notes |
|---|---|---|---|
| 8β16 GB | relay (auto-resolved) | β 768Β² bf16, no swap | Single-shot per pipeline load β re-prefill reloads the UND tower. ~5 min/image at 768Β² on a base-RAM M-series Mac. |
| 24 GB+ | parallel (auto-resolved) | β 768Β² bf16, reusable | Pipeline stays resident across calls. |
relay produces byte-identical output to parallel (MD5-verified on real Lance-3B-bf16) β it sheds the UND tower after prefill and frees the GEN tower before VAE decode, so peak memory β heaviest single phase rather than the sum of all three. Default auto resolves by mx.device_info()'s recommended working-set size with the split at ~18 GiB. The same envelope and modes apply to mlx-community/Lance-3B-Video-bf16 for video tasks.
lossless_decode, 2026-06-05)generate(..., lossless_decode=True) (default since 2026-06-05) uses a bit-identical streaming VAE decode that's lighter than the naive whole dec(z) in every measured config β via temporal causal-cache streaming (flat in frame count) and spatial halo-tile + crop (no blend β exact). 50-case bit-identity test in lance-mlx with a negative control verifies the guarantee. lossless_decode=False keeps the lossy trapezoidal-blend tiling from the prior path (~1.5β4.8 / 255 off the reference) for the one config where lossless exceeds 16 GB (768Β² video; lossless on 1024Β² image fits 16 GB cleanly at ~12.2 GB).
Full envelope and ri_phys-measured numbers (true OS-committed footprint, supersedes the older mx.get_peak_memory() quotes which under-report ~2Γ) in the source repo's LIMITS.md.
For VQA-only use cases on small Macs, the compressed mlx-community/Lance-3B-AWQ-INT4 variant is also available (3.3 GB LLM, 6-9Γ faster long-form decode; VQA only, not for image generation).
Install from the source repo (will be on PyPI in a follow-up release):
git clone https://github.com/xocialize/lance-mlx
cd lance-mlx && uv sync
Download this checkpoint:
from huggingface_hub import snapshot_download
weights = snapshot_download("mlx-community/Lance-3B-bf16")
from lance_mlx.pipeline.t2i import TextToImagePipeline
pipe = TextToImagePipeline.from_pretrained(
lance_weights_dir=weights,
vae_safetensors=f"{weights}/vae.safetensors",
)
image = pipe.generate(
"A photorealistic tabby cat holding up a colorful STOP sign on a sunlit street.",
height=768, width=768, num_steps=30, cfg_scale=4.0, seed=42,
)
image.save("cat_with_stop.png")
from lance_mlx.pipeline.image_edit import ImageEditPipeline
pipe = ImageEditPipeline.from_pretrained(
lance_weights_dir=weights,
vae_safetensors=f"{weights}/vae.safetensors",
)
edited = pipe.generate(
input_image="portrait.jpg",
instruction="Remove the hat from the painting.",
height=768, width=768, num_steps=30, cfg_scale=4.0, seed=42,
)
edited.save("portrait_no_hat.png")
from lance_mlx.pipeline.understanding import UnderstandingPipeline
from PIL import Image
pipe = UnderstandingPipeline.from_pretrained(
lance_weights_dir=weights,
vit_safetensors=f"{weights}/vit.safetensors",
)
answer = pipe.generate(
Image.open("license_plate.png"),
"What is the license plate number visible in this image?",
max_new_tokens=64, prompt_style="lance",
)
print(answer)
| Task | Configuration | Wall-clock |
|---|---|---|
| t2i | 768Β² Γ 30 steps Γ CFG=4.0 | ~201 s |
| image_edit | 768Β² Γ 30 steps Γ CFG=4.0 | ~201 s |
| x2t_image | 6 oracle cases (5β100 token answers), KV-cached | ~34 s combined |
KV cache scales with answer length: 1.7Γ speedup on a 5-token answer, 2.8Γ on a ~100-token answer.
LLM_UND, LLM_GEN), each initialized from Qwen2.5-VL-3B-Instruct, with per-expert FFN, output projection, and QK-norm.LLM_UND (autoregressive next-token); Wan2.2 VAE latent tokens β LLM_GEN (flow-matching velocity prediction). No learned gate.wan2.2_vae.safetensors).causal_mask OR full_and_noise_mask per upstream data/data_utils.py::create_sparse_mask. Without this, the noisy-VAE position 0 of a 2304-token image grid can only see itself + text, producing blurry outputs across all prompts.| File | Size | Purpose |
|---|---|---|
model.safetensors | 12.37 GB | LLM weights (1021 tensors, both UND + GEN towers) |
vit.safetensors | 1.34 GB | Qwen2.5-VL ViT (semantic encoder for x2t_image + image_edit) |
vae.safetensors | 1.41 GB | Lance's bundled Wan2.2 VAE (encoder + decoder, 48-ch) |
config.json | β | Qwen2_5_VLForConditionalGeneration config with tie_word_embeddings=false |
conversion_report.json | β | Provenance of safetensors conversion (PyTorch β MLX bf16) |
tokenizer.json / vocab.json | β | Qwen2.5-VL vocabulary (151,936 tokens) |
Source: bytedance-research/Lance/Lance_3B/model.safetensors (1021 tensors, 6.185 B params).
Conversion script: scripts/02_convert.py in the lance-mlx repo. The script:
language_model. prefix; the MLX LanceModel is the root, not nested.vit_model.* keys) into a sibling vit.safetensors for parity with the Lance_3B distribution shape.llm2vae.weight/bias and time_embedder.mlp.{0,2}.{weight,bias} to match scaffolded MLX modules.Wan2.2 VAE source: bytedance-research/Lance/Wan2.2_VAE.pth β scripts/06_convert_wan_vae.py. Roundtrip MAD on a real photo at 768Β² is ~7/255 in u8 domain.
This MLX port: Apache 2.0.
Underlying weights:
See NOTICE for full attribution.
@article{fu2026lance,
title={Lance: Unified Multimodal Modeling by Multi-Task Synergy},
author={Fu, Fengyi and Huang, Mengqi and Wu, Shaojin and others},
journal={arXiv preprint arXiv:2605.18678},
year={2026}
}
github.com/xocialize/lance-mlxbytedance-research/Lancemlx-community/Wan2.2-VAE-Lance-bf16mlx-community/Lance-3B-Video-bf165 commits