TAI BUI
Back to curriculum
LearnPython

Show-o and Discrete-Diffusion Unified Models

Transfusion mixes continuous and discrete representations. Show-o (Xie et al., August 2024) goes the other way: text tokens use causal next-token prediction, and image tokens use masked discrete diffusion in the spirit of MaskGIT. Both sit inside one transformer with a hybrid attention mask. That one backbone covers VQA, text-to-image, inpainting, and mixed-modality generation, with one tokenizer per modality and one loss family (next-token prediction extended to masked prediction). This lesson walks the Show-o design, explains why masked discrete diffusion is a parallel, few-step image generator, and contrasts it with Transfusion and Emu3.

TIME: ~120 minutesPREREQUISITES: Phase 12 · 13 (Transfusion)

Learning Objectives

  • Explain masked discrete diffusion: the schedule that masks tokens uniformly then asks the transformer to recover them.
  • Compare parallel image decoding (Show-o, MaskGIT) to autoregressive image decoding (Chameleon, Emu3) on speed and quality.
  • Name the four tasks Show-o handles in one checkpoint: text generation, VQA, T2I, image inpainting.
  • Pick a masking schedule (cosine, linear, truncated) and reason about its effect on sample quality.

The Problem

Transfusion's two-loss training works, but the dynamics are trickier. The continuous diffusion loss lives on a different numerical scale from the discrete NTP loss, so balancing the loss weights becomes a hyperparameter search. The architecture is effective and also complex.

Show-o keeps both modalities discrete, like Chameleon, but generates images in parallel with masked discrete diffusion instead of one token at a time. The training objective collapses into a single masked-token prediction that generalizes next-token prediction.

Warm-up0/3
1. Transfusion trains one backbone on text and images. What makes its two-loss setup awkward to tune?Warm-up
Diagram of a Transfusion sequence: text tokens and noised continuous image patches enter one shared transformer body, which feeds a cross-entropy next-token loss on text and a mean-squared-error diffusion loss on image patches, summed into one gradient step.
Typed schematic of the Transfusion two-loss setup described in the prerequisite lesson.
2. In Transfusion's attention mask, how are image patches and text tokens treated?Warm-up
An empty 8 by 8 attention grid. Rows and columns are labelled T1, T2, T3, P1, P2, P3, P4, T4 for three text tokens, four image patches in a dashed image block, and a final text token. No entries are filled in.
Blank grid with typed labels; the sequence is illustrative. Rows are the attending token, columns the token it may see.
3. A BERT-style model is trained by hiding some tokens in a sentence. What is its training target?Warm-up
A six-word sentence, a copy of it with two words replaced by dashed MASK boxes, an arrow into a box labelled BERT-style model, and an empty dashed box labelled training target with a question mark.
Typed example sentence; the masked positions are illustrative.
Check: The Problem0/1
1. Which problem with Transfusion does Show-o's single masked-token objective remove?Explain
Two side-by-side cards. Transfusion: text as discrete tokens, images as continuous patches, text trained with next-token prediction, images with diffusion, one backbone. Show-o: text as discrete tokens, images as discrete VQ tokens, a single masked-token prediction objective, one backbone.
Typed summary of the setups as the lesson describes them.

The Concept

Masked discrete diffusion (MaskGIT)

The original Chang et al. (2022) MaskGIT trick is simple. Start from a fully masked image, where every token is the special <MASK> id. At each step, predict all the masked tokens in parallel, keep the top-K most confident predictions, and leave the rest masked. After ~8-16 iterations every token is filled in. How many tokens to unmask per step is a tuned schedule, and cosine schedules work well.

Training is simple too. Sample a masking ratio uniformly from [0, 1], apply it to the image's VQ tokens, and train the transformer to recover the masked ones. That is what BERT did for text, scaled up to image generation.

Show-o: one transformer, hybrid mask

Show-o puts MaskGIT inside a causal-language-model transformer. The attention mask is:

  • Text tokens: causal (standard LLM).
  • Image tokens: full bidirectional within the image block, so the masked tokens can see every other image token during prediction.
  • Text-to-image: text attends to prior images, image attends to prior text.

Training alternates between:

  1. Standard NTP on text sequences.
  2. T2I samples: text → image with masked image tokens, masked-token-prediction loss.
  3. VQA samples: image → text with masked text tokens (really just NTP).

The unified loss is cross-entropy on <MASK> tokens. It covers text NTP (only the last token is "masked") and image masked-diffusion (a random subset is masked) with the same formulation.

Parallel sampling

Show-o generates an image in ~16 steps instead of ~1000 (autoregressive per token) or ~20 (diffusion). Each step is a full transformer pass that predicts all masked tokens at once, commits the top-K confident ones, and repeats.

Compare:

  • Chameleon / Emu3 (autoregressive over tokens): N_tokens forward passes, typically 1024-4096 per image.
  • Transfusion (continuous diffusion): ~20 steps, each a full transformer pass.
  • Show-o (masked discrete diffusion): ~16 steps, each a full transformer pass.

Show-o is faster than Chameleon at similar-scale models. It roughly matches Transfusion's step count at a lower per-step cost, because it computes discrete vocab logits instead of a continuous MSE loss.

Tasks in one checkpoint

Show-o supports four tasks at inference, selected by prompt format:

  • Text generation: standard autoregressive text output.
  • VQA: image in, text out.
  • T2I: text in, image out via masked discrete diffusion.
  • Inpainting: image with some tokens masked, fill in.

Inpainting comes from the masked-prediction training with no extra work. Mask a region of the VQ-token grid, feed in the rest plus a text prompt, and predict the masked tokens.

Masking schedule

The schedule of how many tokens to unmask per step shapes quality. Show-o recommends cosine:

mask_ratio(t) = cos(pi * t / (2 * T))   # t = 0..T

At step 0, all tokens are masked (ratio 1.0). At step T, none are. Cosine concentrates mass on mid-range ratios, where prediction is most informative. Linear schedules also work but plateau faster.

Show-o2

Show-o2 (2025 follow-up, arXiv 2506.15564) scales Show-o with a larger LLM base, a better tokenizer, and an improved mask schedule. The architectural pattern stays the same.

Where Show-o sits

In the 2026 taxonomy:

  • Discrete tokens + NTP: Chameleon, Emu3. Simple, but inference is slow.
  • Discrete tokens + masked diffusion: Show-o, MaskGIT, LlamaGen, Muse. Parallel sampling, still lossy because of the tokenizer.
  • Continuous + diffusion: Transfusion, MMDiT, DiT. Highest quality, more complex training.
  • Continuous + flow matching in a VLM: JanusFlow, InternVL-U. Newest.

Pick by task. Use Show-o when you want T2I, inpainting, and VQA in one open model at reasonable speed. Use Transfusion when quality matters most and you can afford the two-loss plumbing.

Check: The Concept0/20
1. What is the masked discrete diffusion (MaskGIT-style) procedure that Show-o uses to generate an image?Define
Pipeline: a text prompt 'a red car' enters a box labelled Show-o transformer, masked discrete diffusion sampling, which produces a four by four grid of sixteen VQ codes shown as question marks; a VQ decoder then turns the codes into pixels. A dashed box asks how the grid is filled.
Typed schematic; the prompt is an example. The 4 by 4 grid matches the toy size in main.py.
2. What is a cosine schedule in masked discrete diffusion?Define
A plot of cos(x) for x from 0 to pi/2: a smooth curve falling from 1 at x equals 0 to 0 at x equals pi/2, with tick labels 0, 0.5, 1 and 0, pi/4, pi/2.
Plain cos(x), computed here.
3. What does parallel decoding mean for Show-o's image generation?Define
A box column reading one Show-o model, one text prompt, one image to produce, beside a four by four grid of position cells numbered 1 to 16, with a dashed box asking how many passes are used.
Typed schematic. Positions are numbered in raster order for reference only.
4. What is hybrid attention in Show-o?Define
A caption of three text tokens, 'a', 'red', 'car', next to a dashed image block holding a four by four grid of VQ token ids with three cells marked M for masked, and a dashed box asking for the attention rule in each block.
Typed example; the caption and token ids are illustrative.
5. What is inpainting in the Show-o design?Define
A schematic landscape photo with sky, sun, hill and grass, and a dashed rectangle in the lower right marked with a question mark as a region to fill, plus the caption 'a red barn' for the gap.
Schematic drawn here, not a real photo; the caption is typed.
6. What does the commitment rate control in masked discrete diffusion?Define
A seven-line excerpt of the sampling loop in main.py: a for loop over T steps that computes keep_ratio from the ratios list and calls step_unmask with it, with the keep_ratio and step_unmask lines highlighted.
Lines copied from main.py. Setting: T = 8 steps over 16 tokens.
7. What does The Concept's 'Show-o2' section say changes relative to the original Show-o?Define
A card listing the original Show-o's components: causal-LM transformer base, VQ tokenizer, masked discrete diffusion, cosine mask schedule, hybrid mask. An arrow marked 2025 leads to a dashed box asking what changed in Show-o2, arXiv 2506.15564.
Typed summary of the original design from the lesson.
8. How do image tokens attend to each other in Show-o's hybrid mask, and why?Explain
A four by four grid of VQ token ids where three cells are masked and one masked cell is highlighted, next to the question of which other image tokens the highlighted token attends to, with a dashed box for the answer.
Typed example grid; token ids and masked positions are illustrative.
9. How does Show-o pick the masking ratio for an image's VQ tokens during training?Explain
A four by four grid of VQ token ids, an arrow labelled apply ratio r into a dashed box r equals question mark, and an arrow to a dashed box labelled masked input. The masked result and the way r is chosen are not shown.
Token ids are the final trace row from running main.py.
10. Why can one cross-entropy-on-<MASK> loss cover both text generation and image generation in Show-o?Explain
A text sequence of four tokens and an image sequence of eight VQ token ids both feed one transformer, whose output goes to a single box labelled cross-entropy on MASK positions.
Typed schematic; tokens are illustrative.
11. Which pairing of image-generation cost is correct, per The Concept's 'Parallel sampling' section?Explain
Three-method comparison of forward passes per image.
12. Show-o and Transfusion both run full transformer passes per step. Why is a Show-o step cheaper?Explain
Two columns. Show-o step and Transfusion step each show a box labelled full transformer pass, with labels saying Show-o is cheaper per step and Transfusion more costly. A wide dashed box below asks why the Show-o step costs less.
Typed schematic of the stem's comparison.
13. Show-o recommends mask_ratio(t) = cos(pi*t/(2T)). What does The Concept say this does compared with a linear schedule?Explain
Two schedule formulas, linear 1 minus t over T and cosine cos of pi t over 2T, above a table for t from 0 to 4 with linear values 1.00, 0.75, 0.50, 0.25, 0.00 and a column of question marks for the cosine values.
Linear formula assumed (typed) and values computed here for T = 4.
14. A user wants to remove a lamp from a photo and fill the gap using a caption. Using Show-o, what is the right approach?Apply
A schematic room scene with a window, a wooden table and a lamp on it. A dashed outline surrounds the lamp. A request panel reads: remove the lamp and fill the gap using the caption 'an empty wooden table'.
Schematic drawn here, not a real photo; the caption is typed.
15. A 512x512 Show-o image is 1024 tokens at vocab 16384, which is 14 bits per token. Against 512*512*24 raw pixel bits, roughly what compression ratio is that?Apply
A square of 512 by 512 pixels at 24 bits per pixel, an arrow labelled tokenize to a square of 1024 tokens at vocab 16384 meaning 14 bits each, and a dashed box asking for the ratio.
Typed schematic; figures are those in the stem.
16. A service built on a Chameleon-style model spends most of its time on image latency. Logs show about 4096 sequential forward passes per image. What is the root cause?Analyze
An illustrative service log for one text-to-image request showing forward pass 1 of 4096, 2, 3, then an ellipsis, then forward pass 4096 of 4096, followed by image returned, with a dashed box asking for the root cause.
Typed log lines; the request id is made up for illustration. 4096 is the figure from the stem.
17. A Show-o image has good global layout but loses fine texture, even when sampling steps are increased. Which part of the design best explains the ceiling?Analyze
Three schematic landscape panels. The reference photo has fine grass strokes; the Show-o sample and the sample with more sampling steps have the same layout of sky, sun, hill and grass but smooth grass without strokes.
Schematic drawn here to show the stem's symptom; not real model output.
18. A team needs T2I, VQA, and inpainting in one open model at reasonable speed, and top image quality is not the priority. Which family from The Concept's 'Where Show-o sits' fits best?Design
A requirements list: must haves are text-to-image, visual question answering, inpainting, and all three in one open model; reasonable generation speed is wanted; top image quality is marked not a priority.
Typed list restating the stem.
19. A photo product needs the highest image fidelity, and the team can afford a two-loss training setup. Which family should it pick?Design
A photo product's requirements: top need is highest image fidelity, and the budget allows a two-loss training setup. A dashed box asks which family to pick.
Typed list restating the stem.
20. A team's linear unmasking schedule plateaus at lower sample quality than expected. Which change does the lesson back?Design
A plot of mask ratio against step with a straight diagonal line falling from 1 to 0, labelled linear schedule (current), beside a card saying sample quality plateaus below what was expected.
Straight line is the assumed form of a linear schedule, 1 - t/T, plotted here.

Use It

code/main.py simulates Show-o sampling:

  • A toy grid of 16 VQ tokens.
  • A mock "transformer" that predicts logits based on a prompt and the currently unmasked tokens.
  • Parallel masked sampling over 8 steps with a cosine schedule.
  • Printed intermediate states (the mask pattern evolving) and the final tokens.

Run it and watch the mask dissolve step by step.

Check: Use It0/5
1. In main.py, step_unmask runs with keep_ratio 0.15 while only 3 tokens are still masked. How many does it commit?Apply
A row layout of 16 token positions with three marked M for masked, a card reading keep_ratio 0.15 with 3 tokens masked, and a code excerpt from step_unmask whose n_to_keep line is withheld.
Positions are illustrative. The code lines are copied from main.py.
2. In the T=8 trace, 8 tokens are masked going into the step where the cosine ratio is about 0.556 and keep_ratio is max(0.15, 1 - 0.556). How many remain masked afterward?Apply
A four by four grid taken from the main.py trace with eight masked cells and eight filled cells, cards giving the cosine ratio 0.556 for loop step 4 and the keep_ratio formula max(0.15, 1 minus 0.556), and a dashed box asking how many stay masked.
Grid is row 4 of the real main.py trace.
3. In main.py with T=8, what do cosine_schedule and keep_ratio give at the last step (step 7)?Apply
The cosine_schedule return line and the keep_ratio line from main.py above a strip of eight boxes labelled step 0 to step 7 with step 7 outlined, and two dashed boxes asking for the cosine value and the keep_ratio at step 7.
Code lines copied from main.py. T = 8 as in the stem.
4. In the T=8 trace over 16 tokens, why does step 0 commit only 2 tokens?Apply
Two four by four grids from the real main.py run. Before loop step 0 all sixteen cells are masked; after loop step 0 fourteen are masked and two are filled with token ids. A dashed box asks why only two were committed.
Both grids are rows 0 and 1 of the printed main.py trace.
5. Running main.py, a reader sees that the fallback while loop after the scheduled steps never executes. Which fact explains this?Analyze
An excerpt of sample() in main.py: it starts from all-MASK tokens, loops for step in range(T) computing keep_ratio, calling step_unmask and appending to traces, then has a while-any-MASK fallback loop calling step_unmask with 1.0, which is highlighted.
Lines copied from main.py; a few lines of the original are left out.

Ship It

This lesson produces outputs/skill-unified-gen-model-picker.md. Give it a product that needs both understanding (VQA, captioning) and generation (T2I, inpainting) under an open-weights constraint, and it picks between the Show-o family, the Transfusion/MMDiT family, and the Emu3 / Chameleon family, with concrete trade-offs.

Author's Note

I'd run main.py and read the trace before touching the math. It prints the cosine schedule for T=8, then one sampling run over 16 tokens with a vocab of 8, showing the masked count at each step. The masked count goes 16, 14, 12, 10, 8, 5, 2, 1, 0: two tokens per step at first, three in the middle, then single stragglers at the end.

Keep in mind what the toy is. The transformer is a mock: mock_logits adds noise, a bias toward a token set by the prompt seed and position, and a bonus for tokens already committed. So the trace shows the sampling loop and nothing about image quality. Once a token is committed here it stays, and the tokens that aren't picked simply remain masked for the next pass.

One detail I'd check by hand is how the schedule becomes a commit count. keep_ratio is max(0.15, 1 - ratio), applied to the tokens still masked rather than to all 16. That is why the first step commits only 2 tokens (int(16 * 0.15)). It is also why a few stragglers are left for the late steps: int() floors the count, and at step 7 the ratio reaches 0, so keep_ratio becomes 1.0 and the last masked position is committed. The while loop after the schedule is only a fallback and does not run in this trace. The four tasks printed at the bottom are just print statements. The loop is real, but VQA and inpainting are not run, so treat them as a claim from The Concept about the training objective.

Exercises

  1. Masked discrete diffusion samples in ~16 steps. Why not 1? What breaks if you unmask everything at step 0?

  2. Inpainting is free with masked diffusion. Propose a product use case (real or hypothetical) where Show-o's inpainting beats a specialist model.

  3. Cosine schedule vs linear schedule: trace the number of unmasked tokens per step for T=8. Which is more balanced?

  4. A 512x512 Show-o image is 1024 tokens. At vocab K=16384, the model emits 1024 * log2(16384) = 14,336 bits (~1.75 KiB) of data. Stable Diffusion outputs 51251224 bits = 6,291,456 bits (~768 KiB) of raw pixels. What is the compression ratio and what quality does it buy?

  5. Read LlamaGen (arXiv:2406.06525). How is LlamaGen's class-conditional autoregressive image model different from Show-o's masked approach?

Key Terms

TermWhat people sayWhat it actually means
Masked discrete diffusion"MaskGIT-style"Training to predict masked tokens; at inference, iteratively unmask the most-confident predictions
Cosine schedule"Unmask schedule"Decay of mask ratio over inference steps; concentrates confidence growth at mid-range
Parallel decoding"All tokens at once"Every step predicts the full sequence of masked tokens in one forward pass, then commits top-K
Hybrid attention"Causal + bidirectional"Mask that is causal over text tokens and bidirectional within image blocks
Inpainting"Fill-in generation"Condition on an image with some tokens masked, predict the missing ones; free from the training objective
Commitment rate"Top-K per step"How many tokens are declared "done" per iteration; controls inference vs quality trade-off

Further Reading

Code

Ships With