|
1 | | -This repository implements the [DiffusionGemma](https://deepmind.google/models/gemma/diffusiongemma/) |
2 | | -denoiser in [MLX](https://github.com/ml-explore/mlx): a *uniform-state* discrete |
3 | | -diffusion language model ([UDLM](https://arxiv.org/abs/2412.10193)) on a Gemma-4 |
4 | | -MoE backbone, intended to sit inside the *block-diffusion* |
5 | | -([BD3LM](https://arxiv.org/abs/2503.09573)) generation framework. |
| 1 | +# DiffusionGemma |
| 2 | + |
| 3 | +This example trains [DiffusionGemma](https://deepmind.google/models/gemma/diffusiongemma/) |
| 4 | +on `tiny_shakespeare`. |
6 | 5 |
|
7 | | -You can find a minimal experiment in [experiments/diffusiongemma](experiments/diffusiongemma) where we train DiffusionGemma on `tiny_shakespeare`. |
8 | | -For reference on DiffusionGemma itself, see the |
9 | | -[DeepMind implementation](https://github.com/google-deepmind/gemma/tree/main/gemma/diffusion), |
10 | | -the [vLLM writeup](https://github.com/vllm-project/vllm-project.github.io/blob/main/_posts/2026-06-10-diffusion-gemma.md), |
11 | | -and the [NeMo fine-tuning guide](https://github.com/NVIDIA-NeMo/Automodel/blob/main/docs/guides/dllm/diffusiongemma.md). |
12 | 6 | To run the experiment, first download the latest release and install all dependencies via: |
13 | 7 |
|
14 | 8 | ```bash |
15 | | -wget -qO- https://github.com/dirmeier/block-diffusion-mlx/archive/refs/tags/<TAG>.tar.gz | tar zxvf - |
| 9 | +wget -qO- https://github.com/dirmeier/d3pm-mlx/archive/refs/tags/<TAG>.tar.gz | tar zxvf - |
16 | 10 | uv sync --all-groups |
17 | 11 | ``` |
18 | 12 |
|
19 | 13 | To train a model and generate some text, call: |
20 | 14 |
|
21 | 15 | ```bash |
22 | | -uv run python experiments/diffusiongemma/main.py |
| 16 | +uv run python examples/diffusiongemma/main.py |
23 | 17 | ``` |
24 | 18 |
|
25 | | -Pass `--prompt "..."` to condition generation on a prefix, and `--entropy-bound` |
26 | | -to set the sampler's cumulative acceptance budget. The budget does not scale |
27 | | -with canvas length, so a small or under-trained model on a wide `--block-size` |
28 | | -needs a looser bound (raise it if samples stay noisy). |
29 | | - |
30 | | - |
31 | 19 | ## Method |
32 | 20 |
|
33 | | -DiffusionGemma combines two lines of work from the Kuleshov group: the |
34 | | -block-autoregressive *structure* of BD3LM with the uniform-state *noise* of |
35 | | -UDLM (plus self-conditioning and an entropy-bounded sampler). The axes below |
36 | | -show where each model — and this repository — sits. |
37 | | - |
38 | | -| Axis | MDLM | BD3LM | UDLM | Duo | DiffusionGemma | This repo | |
39 | | -|------|------|-------|------|-----|----------------|-----------| |
40 | | -| Noise state | masked | masked | uniform | uniform | uniform (no mask) | **uniform (no mask)** | |
41 | | -| Noise schedule | loglinear | loglinear | loglinear | loglinear | — | **linear or loglinear (+ importance sampling)** | |
42 | | -| Generation | single block | block-autoregressive | single block | single block | block-autoregressive | **block-autoregressive** | |
43 | | -| Attention | bidirectional | block-causal | bidirectional | bidirectional | causal prefill + bidir. denoise | **block-causal + bidir. denoise** | |
44 | | -| Self-conditioning | no | no | no | yes | yes | **yes (`encode_logits` signal, GeGLU FFN + post-norm)** | |
45 | | -| Guidance | — | — | D-CFG | — | D-CFG | **D-CFG (toy label)** | |
46 | | -| Variable length | no | yes | no | no | yes | **yes (growing KV cache)** | |
47 | | -| Backbone | encoder | encoder | encoder | encoder | Gemma-4 MoE | **Gemma-4 MoE** | |
| 21 | +The axes below show the model details of the original DiffusionGemma implementation (as well as |
| 22 | +several models), and how they compare to `d3pm`'s implementation. |
48 | 23 |
|
49 | | -The block-autoregressive loop is implemented: the sampler commits each denoised |
50 | | -block to a growing KV cache and starts the next block conditioned on that |
51 | | -history (`BlockSampler`), and training scores multiple blocks under a |
52 | | -block-causal mask (`block_diffusion_loss`). Two invariants from DeepMind's |
53 | | -reference hold — attention is **bidirectional within a block** (every query |
54 | | -attends to the whole current block, no triangular structure) and |
55 | | -**block-causal across blocks** (block `i` attends to blocks `j <= i`, never |
56 | | -future blocks). That cross-block causality is realised either by an explicit |
57 | | -block-causal mask (parallel processing / training) or implicitly by the |
58 | | -streaming sampler, where future blocks are simply not in the cache yet; the |
59 | | -variable length comes from appending keys/values to the growing cache. An |
60 | | -optional prompt is committed to the cache first (block-causal prefill), so |
61 | | -generation continues from it (`BlockSampler.generate(prompt=...)`). |
62 | | - |
63 | | -### Gemma-4 parity |
64 | | - |
65 | | -The backbone tracks the reference Gemma-4 MoE block: interleaved |
66 | | -local-sliding / global attention with dual RoPE bases, QK- and value-norm, a |
67 | | -per-block `skip_scale`, a normed-and-scaled MoE router with per-expert scaling |
68 | | -and a shared dense branch, and projection-only per-layer embeddings. The |
69 | | -training recipe uses a UDLM-faithful stratified/antithetic noise sampler with an |
70 | | -optional loglinear schedule and importance-sampling reparametrisation |
71 | | -(transcribed from MDLM `LogLinearNoise`), and the sampler uses an entropy-budget |
72 | | -token-acceptance rule with annealed temperature. Self-conditioning feeds the |
73 | | -previous step's predicted distribution back through the embedding table |
74 | | -(`encode_logits`), matching the reference. |
75 | | - |
76 | | -**Deferred (documented):** EMA weights, Duo consistency distillation |
77 | | -([2506.10892](https://arxiv.org/abs/2506.10892)) for few-step sampling, a real |
78 | | -(SentencePiece) tokenizer, and batched multi-sequence sampling. |
| 24 | +| Axis | MDLM | BD3LM | UDLM | Duo | DiffusionGemma | `d3pm` package | |
| 25 | +|------|------|-------|------|-----|----------------|------| |
| 26 | +| Noise state | masked | masked | uniform | uniform | uniform (no mask) | uniform (no mask) | |
| 27 | +| Noise schedule | loglinear | loglinear | loglinear | loglinear | ? | linear or loglinear | |
| 28 | +| Generation | single block | block-autoregressive | single block | single block | block-autoregressive | block-autoregressive | |
| 29 | +| Attention | bidirectional | block-causal | bidirectional | bidirectional | causal prefill + bidir. denoise | causal prefill + bidir. denoise | |
| 30 | +| Self-conditioning | no | no | no | yes | yes | yes | |
| 31 | +| Guidance | — | — | D-CFG | — | D-CFG | D-CFG | |
| 32 | +| Variable length | no | yes | no | no | yes | yes | |
| 33 | +| Backbone | encoder | encoder | encoder | encoder | Gemma-4 MoE | Gemma-4 MoE | |
79 | 34 |
|
80 | 35 | ## Additional references |
| 36 | + |
| 37 | +- [DeepMind reference implementation](https://github.com/google-deepmind/gemma/tree/main/gemma/diffusion) |
| 38 | +- [DiffusionGemma model card](https://ai.google.dev/gemma/docs/diffusiongemma/model_card) |
| 39 | +- [vLLM integration write-up](https://github.com/vllm-project/vllm-project.github.io/blob/main/_posts/2026-06-10-diffusion-gemma.md) |
| 40 | +- [NeMo fine-tuning guide](https://github.com/NVIDIA-NeMo/Automodel/blob/main/docs/guides/dllm/diffusiongemma.md) |
| 41 | +- [How to Build a Diffusion Language Model](https://kuleshov-group.github.io/blog/blog/2026/how-to-build-a-diffusion-language-model/), 2026. |
0 commit comments