RockTalk commited on
Commit
5ba7b08
Β·
verified Β·
1 Parent(s): 3397cf7

Update README: remove broken github link, point to bundled code

Browse files
Files changed (1) hide show
  1. README.md +90 -47
README.md CHANGED
@@ -22,10 +22,87 @@ tags:
22
 
23
  # Lance-3B-Video-MLX
24
 
25
- Video variant of [Lance-3B-MLX](https://huggingface.co/RockTalk/Lance-3B-MLX). First native [MLX](https://github.com/ml-explore/mlx) port of [ByteDance Research's Lance](https://huggingface.co/bytedance-research/Lance) β€” a 3B-parameter unified multimodal model for image/video generation, editing, and understanding. Runs natively on Apple Silicon, no CUDA required.
26
 
27
  The architecture is **Qwen2.5-VL-3B + parallel MoE-gen experts + Wan 2.2 VAE**. Lance uses a "Mixture-of-Tokens" routing: every attention block and MLP has a parallel `*_moe_gen` branch. Text tokens go through normal weights; VAE-latent (generation) tokens go through the `_moe_gen` weights, in the same forward pass.
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  ## What works
30
 
31
  | Capability | Status |
@@ -70,64 +147,25 @@ First-call kernel-compile penalty: ~few seconds per new resolution.
70
  ## Differences vs Lance-3B-MLX
71
 
72
  This is the same architecture as the image variant, with two differences:
 
73
  - `model.safetensors`: 26.5 GB (vs 23 GB) β€” extra weights for multi-frame attention
74
  - `latent_pos_embed.pos_embed`: 31 Γ— 64 Γ— 64 = 126,976 positions (vs 1 Γ— 64 Γ— 64 = 4,096) β€” supports up to 31 latent frames (β‰ˆ 121 video frames @ 4Γ— temporal downsample)
75
 
76
  T2I via this checkpoint works the same as Lance-3B-MLX. **T2V is now live** β€” uses the [Wan 2.2 VAE v0.1.0 streaming cache](https://huggingface.co/RockTalk/Wan2.2-VAE-MLX) under the hood. Pass `latent_shape=(T_lat, H_lat, W_lat)` with `T_lat > 1` to `sample_t2i` to generate a video.
77
 
78
- T_lat β†’ output frames: T = (T_lat - 1) Γ— 4 + 1.
79
- - T_lat=1 β†’ 1 frame (image)
80
- - T_lat=3 β†’ 9 frames
81
- - T_lat=8 β†’ 29 frames
82
- - T_lat=31 β†’ 121 frames (max for this checkpoint)
83
-
84
  ## Files
85
 
86
  | File | Size | Description |
87
  |---|---|---|
88
  | `model.safetensors` | 26.5 GB | LLM (Qwen2.5-VL with MoE-gen) + Lance adapters + bundled ViT (`vit_model.*` prefix), 1411 tensors total |
89
  | `vit.safetensors` | 1.25 GB | Qwen2.5-VL ViT, also extractable from `model.safetensors` |
90
- | `vae.safetensors` | 2.62 GB | Wan 2.2 VAE (older keying β€” for compatibility; the standalone [RockTalk/Wan2.2-VAE-MLX](https://huggingface.co/RockTalk/Wan2.2-VAE-MLX) is recommended) |
91
  | `config.json` | β€” | Distilled architecture config |
92
  | `tokenizer.json`, `vocab.json`, `merges.txt` | β€” | Qwen2.5-VL tokenizer, verbatim |
93
  | `samples/ocean_wave_*.png` | β€” | Verified 9-frame T2V outputs |
94
-
95
- ## Usage
96
-
97
- Requires `mlx >= 0.29`, `mlx-vlm >= 0.3`, `numpy`, `einops`, `transformers`, `pillow`, and the [`lance-mlx`](https://github.com/RockTalk/Lance-MLX) companion repo for the `Lance` Python class.
98
-
99
- ```bash
100
- pip install mlx mlx-vlm numpy einops transformers pillow
101
- ```
102
-
103
- ```python
104
- import mlx.core as mx
105
- from lance_mlx.lance import Lance, LanceConfig
106
- from lance_mlx.vae_wan22 import Wan2_2_VAE
107
-
108
- # Build + strict-load (see tools/lance_t2i.py in the companion repo for the
109
- # full builder; LanceConfig takes a Qwen2.5-VL ModelConfig built from
110
- # config.json).
111
- model = Lance(lance_cfg)
112
- model.load_weights(list(mx.load("model.safetensors").items()), strict=True)
113
-
114
- vae = Wan2_2_VAE(z_dim=48, c_dim=160, dim_mult=(1, 2, 4, 4),
115
- temperal_downsample=(False, True, True))
116
- vae.model.load_weights(list(mx.load("vae.safetensors").items()), strict=True)
117
-
118
- # Sample
119
- latent = model.sample_t2i(
120
- prompt_token_ids=text_ids, # (P,) int32 from tokenizer (no specials)
121
- latent_shape=(1, 32, 32), # (T_lat, H_lat, W_lat) for 512Γ—512 image
122
- special_token_ids={"bos": 151644, "eos": 151645,
123
- "start_of_image": 151652, "end_of_image": 151653,
124
- "image_token_id": 151655},
125
- num_steps=30, timestep_shift=3.5, cfg_scale=4.0, seed=0,
126
- )
127
- img = vae.decode(latent) # (1, 1, 512, 512, 3) in [-1, 1]
128
- ```
129
-
130
- End-to-end script: `tools/lance_t2i.py` in the [companion repo](https://github.com/RockTalk/Lance-MLX).
131
 
132
  ## How the MoE-gen routing is implemented in MLX
133
 
@@ -149,17 +187,21 @@ For T2I/T2V the sequence layout is:
149
  ↑ everything else: normal weights
150
  ```
151
 
152
- The MLX port (`qwen2_navit_mlx.py`) routes by slicing the sequence into the latent slab vs the surrounding text, applying the appropriate expert to each slab, and concatenating. mrope position ids continue to flow normally across both slabs (with axis-T/H/W coordinates only varying inside the latent slab).
153
 
154
  ## Conversion source
155
 
156
- Converted from `bytedance-research/Lance/Lance_3B/*` using the open-source pipeline at https://github.com/RockTalk/Lance-MLX (`tools/convert_weights.py`). Layout transforms:
157
 
158
  - Conv weights: PT `(O, I, [T,] H, W)` β†’ MLX `(O, [T,] H, W, I)`
159
  - Embedding weights: shape preserved
160
  - `lm_head.weight` tied to `embed_tokens.weight` (Qwen default)
161
  - All `*_moe_gen.*` keys copied verbatim under the same names
162
 
 
 
 
 
163
  ## License
164
 
165
  Apache 2.0, inherited from upstream `bytedance-research/Lance`. The Wan 2.2 VAE component is also Apache 2.0 from Alibaba's Wan team.
@@ -170,6 +212,7 @@ Apache 2.0, inherited from upstream `bytedance-research/Lance`. The Wan 2.2 VAE
170
  - **Qwen team** β€” Qwen2.5-VL-3B-Instruct backbone
171
  - **Alibaba Wan team** β€” Wan 2.2 VAE training
172
  - **Apple `mlx` and `mlx-vlm` teams** β€” the underlying frameworks
 
173
  - **This MLX port** β€” RockTalk
174
 
175
  ## Citation
 
22
 
23
  # Lance-3B-Video-MLX
24
 
25
+ Video variant of [Lance-3B-MLX](https://huggingface.co/RockTalk/Lance-3B-MLX). First native [MLX](https://github.com/ml-explore/mlx) port of [ByteDance Research's Lance](https://huggingface.co/bytedance-research/Lance) β€” a 3 B-parameter unified multimodal model for image/video generation, editing, and understanding. Runs natively on Apple Silicon, no CUDA required.
26
 
27
  The architecture is **Qwen2.5-VL-3B + parallel MoE-gen experts + Wan 2.2 VAE**. Lance uses a "Mixture-of-Tokens" routing: every attention block and MLP has a parallel `*_moe_gen` branch. Text tokens go through normal weights; VAE-latent (generation) tokens go through the `_moe_gen` weights, in the same forward pass.
28
 
29
+ ## Quick start (self-contained β€” no external repo needed)
30
+
31
+ ```bash
32
+ # 1. Download the model (one-time, ~30 GB total)
33
+ hf download RockTalk/Lance-3B-Video-MLX --local-dir Lance-3B-Video-MLX
34
+
35
+ # 2. Install runtime deps
36
+ cd Lance-3B-Video-MLX
37
+ pip install -r requirements.txt
38
+
39
+ # 3. Generate a 9-frame video (T_lat=3 β†’ 9 output frames)
40
+ python inference.py --prompt "a calm ocean wave rolling onto a sandy beach"
41
+
42
+ # Longer video (29 frames):
43
+ python inference.py --prompt "..." --t-lat 8
44
+
45
+ # Pure image (T_lat=1):
46
+ python inference.py --prompt "..." --t-lat 1 --size 512 --steps 30
47
+ ```
48
+
49
+ First run auto-fetches the companion VAE ([`RockTalk/Wan2.2-VAE-MLX`](https://huggingface.co/RockTalk/Wan2.2-VAE-MLX), ~2.6 GB, cached as `wan22_vae.safetensors`) so all subsequent runs are fully offline.
50
+
51
+ ### CLI options
52
+
53
+ ```
54
+ python inference.py \
55
+ --prompt "..." \
56
+ --out output.png # frame strip + per-frame PNGs saved next to it
57
+ --size 256 # 256 recommended for T2V
58
+ --t-lat 3 # latent frames; output = (t_lat-1)*4 + 1 frames
59
+ --steps 24 # 24 typical for T2V
60
+ --cfg 4.0
61
+ --seed 0
62
+ --mp4 # also emit output.mp4 (needs `pip install 'imageio[ffmpeg]'`)
63
+ --fps 8
64
+ ```
65
+
66
+ Frame-count table: `T_lat=1 β†’ 1`, `T_lat=3 β†’ 9`, `T_lat=8 β†’ 29`, `T_lat=31 β†’ 121` (max).
67
+
68
+ ### Programmatic use
69
+
70
+ ```python
71
+ from inference import build_lance_config, ensure_vae_weights
72
+ from lance_mlx.lance import Lance, LanceConfig
73
+ from lance_mlx.vae_wan22 import Wan2_2_VAE
74
+ from transformers import AutoTokenizer
75
+ import json, mlx.core as mx
76
+ from pathlib import Path
77
+
78
+ repo = Path(".")
79
+ cfg_json = json.loads((repo / "config.json").read_text())
80
+ lance_cfg = build_lance_config(cfg_json)
81
+
82
+ model = Lance(lance_cfg)
83
+ weights = mx.load("model.safetensors")
84
+ non_vit = {k: v for k, v in weights.items() if not k.startswith("vit_model.")}
85
+ model.load_weights(list(non_vit.items()), strict=True)
86
+
87
+ vae = Wan2_2_VAE(z_dim=48, c_dim=160, dim_mult=(1, 2, 4, 4),
88
+ temperal_downsample=(False, True, True))
89
+ vae.model.load_weights(list(mx.load(str(ensure_vae_weights(repo))).items()), strict=True)
90
+
91
+ tok = AutoTokenizer.from_pretrained(".")
92
+ text_ids = mx.array(tok("a calm ocean wave", add_special_tokens=False,
93
+ return_tensors="np").input_ids[0], dtype=mx.int32)
94
+
95
+ latent = model.sample_t2i(
96
+ prompt_token_ids=text_ids,
97
+ latent_shape=(3, 16, 16), # T_lat=3 β†’ 9 output frames @ 256Γ—256
98
+ special_token_ids={"bos": 151644, "eos": 151645,
99
+ "start_of_image": 151652, "end_of_image": 151653,
100
+ "image_token_id": 151655},
101
+ num_steps=24, timestep_shift=3.5, cfg_scale=4.0, seed=0,
102
+ )
103
+ video = vae.decode(latent) # (1, 9, 256, 256, 3) in [-1, 1]
104
+ ```
105
+
106
  ## What works
107
 
108
  | Capability | Status |
 
147
  ## Differences vs Lance-3B-MLX
148
 
149
  This is the same architecture as the image variant, with two differences:
150
+
151
  - `model.safetensors`: 26.5 GB (vs 23 GB) β€” extra weights for multi-frame attention
152
  - `latent_pos_embed.pos_embed`: 31 Γ— 64 Γ— 64 = 126,976 positions (vs 1 Γ— 64 Γ— 64 = 4,096) β€” supports up to 31 latent frames (β‰ˆ 121 video frames @ 4Γ— temporal downsample)
153
 
154
  T2I via this checkpoint works the same as Lance-3B-MLX. **T2V is now live** β€” uses the [Wan 2.2 VAE v0.1.0 streaming cache](https://huggingface.co/RockTalk/Wan2.2-VAE-MLX) under the hood. Pass `latent_shape=(T_lat, H_lat, W_lat)` with `T_lat > 1` to `sample_t2i` to generate a video.
155
 
 
 
 
 
 
 
156
  ## Files
157
 
158
  | File | Size | Description |
159
  |---|---|---|
160
  | `model.safetensors` | 26.5 GB | LLM (Qwen2.5-VL with MoE-gen) + Lance adapters + bundled ViT (`vit_model.*` prefix), 1411 tensors total |
161
  | `vit.safetensors` | 1.25 GB | Qwen2.5-VL ViT, also extractable from `model.safetensors` |
162
+ | `vae.safetensors` | 2.62 GB | Wan 2.2 VAE (older "nested-conv" keying, kept for archival β€” `inference.py` auto-fetches the cleanly-keyed [RockTalk/Wan2.2-VAE-MLX](https://huggingface.co/RockTalk/Wan2.2-VAE-MLX) instead) |
163
  | `config.json` | β€” | Distilled architecture config |
164
  | `tokenizer.json`, `vocab.json`, `merges.txt` | β€” | Qwen2.5-VL tokenizer, verbatim |
165
  | `samples/ocean_wave_*.png` | β€” | Verified 9-frame T2V outputs |
166
+ | `lance_mlx/` | β€” | **Bundled MLX implementation** (model + VAE + utils) |
167
+ | `inference.py` | β€” | **Self-contained T2V/T2I runner** |
168
+ | `requirements.txt` | β€” | Pip dependencies |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
  ## How the MoE-gen routing is implemented in MLX
171
 
 
187
  ↑ everything else: normal weights
188
  ```
189
 
190
+ The MLX port (`lance_mlx/qwen2_navit_mlx.py`) routes by slicing the sequence into the latent slab vs the surrounding text, applying the appropriate expert to each slab, and concatenating. mrope position ids continue to flow normally across both slabs (with axis-T/H/W coordinates only varying inside the latent slab).
191
 
192
  ## Conversion source
193
 
194
+ Converted from `bytedance-research/Lance/Lance_3B/*` using a local conversion pipeline. Layout transforms:
195
 
196
  - Conv weights: PT `(O, I, [T,] H, W)` β†’ MLX `(O, [T,] H, W, I)`
197
  - Embedding weights: shape preserved
198
  - `lm_head.weight` tied to `embed_tokens.weight` (Qwen default)
199
  - All `*_moe_gen.*` keys copied verbatim under the same names
200
 
201
+ ## Related ports
202
+
203
+ A parallel MLX port exists at [mlx-community/Lance-3B-Video-bf16](https://huggingface.co/mlx-community/Lance-3B-Video-bf16) (Apache-2.0). The two checkpoints have been verified numerically equivalent: remapping this repo's F32 weights into their layout and casting to bf16 produces byte-identical pixel output through their pipeline. Use whichever fits your workflow.
204
+
205
  ## License
206
 
207
  Apache 2.0, inherited from upstream `bytedance-research/Lance`. The Wan 2.2 VAE component is also Apache 2.0 from Alibaba's Wan team.
 
212
  - **Qwen team** β€” Qwen2.5-VL-3B-Instruct backbone
213
  - **Alibaba Wan team** β€” Wan 2.2 VAE training
214
  - **Apple `mlx` and `mlx-vlm` teams** β€” the underlying frameworks
215
+ - **mlx-community Lance porters** β€” parallel bf16 port, numerically cross-checked against this one
216
  - **This MLX port** β€” RockTalk
217
 
218
  ## Citation