2026-01-30 07:56:10 +08:00
# BAGEL-7B-MoT
Source <https://github.com/vllm-project/vllm-omni/tree/main/examples/online_serving/bagel>.
2026-04-24 21:21:30 +08:00
## Installation
2026-01-30 07:56:10 +08:00
2026-02-03 18:11:50 +08:00
Please refer to [README.md ](https://github.com/vllm-project/vllm-omni/tree/main/README.md )
2026-01-30 07:56:10 +08:00
2026-04-24 21:21:30 +08:00
## Architecture
2026-01-30 07:56:10 +08:00
2026-04-24 21:21:30 +08:00
BAGEL-7B-MoT is a Mixture-of-Transformers (MoT) model supporting both image generation and understanding. It offers two deployment topologies:
2026-01-30 07:56:10 +08:00
2026-04-24 21:21:30 +08:00
| Topology | Stages | Description |
| :------- | :----- | :---------- |
| **Two-stage** (default) | Stage 0 (Thinker, AR) + Stage 1 (DiT, Diffusion) | Thinker handles text/understanding via vLLM AR engine; DiT handles image generation. KV cache is transferred between stages. |
| **Single-stage** | Stage 0 (DiT, Diffusion) only | The DiT stage contains a full LLM, ViT, VAE, and tokenizer internally. All modalities are handled within a single diffusion process. |
Both topologies support all four modalities: `text2img` , `img2img` , `img2text` , `text2text` .
> **Note**: These examples work with the default configuration on an **NVIDIA A100 (80GB)**. We also tested on dual **NVIDIA RTX 5000 Ada (32GB each)**. For dual-GPU setups, modify the deploy YAML to distribute stages across devices.
## Launch the Server
### Two-Stage (Default)
The default pipeline is auto-detected from the model. No extra flags needed:
2026-01-30 07:56:10 +08:00
```bash
vllm serve ByteDance-Seed/BAGEL-7B-MoT --omni --port 8091
```
Or use the convenience script:
```bash
2026-04-24 21:21:30 +08:00
cd examples/online_serving/bagel
2026-01-30 07:56:10 +08:00
bash run_server.sh
2026-04-24 11:25:22 +08:00
# Launch a single stage per terminal
bash run_server_stage_cli.sh --stage 0
bash run_server_stage_cli.sh --stage 1
2026-01-30 07:56:10 +08:00
```
2026-08-03 23:41:52 +08:00
To use a custom deploy YAML:
2026-02-27 17:28:35 +08:00
```bash
vllm serve ByteDance-Seed/BAGEL-7B-MoT --omni --port 8091 \
2026-04-24 21:21:30 +08:00
--deploy-config /path/to/deploy_config.yaml
2026-02-27 17:28:35 +08:00
```
2026-04-24 21:21:30 +08:00
See [`bagel.yaml` ](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/deploy/bagel.yaml ) for the default two-stage deploy configuration.
2026-02-27 17:28:35 +08:00
2026-04-24 21:21:30 +08:00
### Single-Stage
2026-02-27 17:28:35 +08:00
2026-04-24 21:21:30 +08:00
The DiT stage contains a full LLM, ViT, VAE, and tokenizer, so it can handle all modalities (text2img, img2img, img2text, text2text, think) without a separate Thinker stage:
2026-02-27 17:28:35 +08:00
```bash
2026-04-24 21:21:30 +08:00
vllm serve ByteDance-Seed/BAGEL-7B-MoT --omni --port 8091 \
--deploy-config vllm_omni/deploy/bagel_single_stage.yaml
2026-02-27 17:28:35 +08:00
```
2026-04-24 21:21:30 +08:00
See [`bagel_single_stage.yaml` ](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/deploy/bagel_single_stage.yaml ) for configuration. The `pipeline: bagel_single_stage` field selects the single-stage topology from the pipeline registry.
2026-09-04 09:36:11 +08:00
### Step Execution and Continuous Batching
Image generation supports step execution with all three BAGEL deploy configs.
The global flag is applied only to diffusion stages:
- With `bagel.yaml` or `bagel_think.yaml` , Stage 1 uses step execution and the
Stage 0 Thinker remains autoregressive.
- With `bagel_single_stage.yaml` , image requests use step execution in Stage 0.
Explicit `text2text` and `img2text` requests use the same complete-request
text path as they do without `--step-execution` .
Start with the deploy file's default diffusion capacity of one:
```bash
vllm serve ByteDance-Seed/BAGEL-7B-MoT --omni --port 8091 \
--deploy-config vllm_omni/deploy/bagel.yaml \
--step-execution
```
To enable step-wise continuous batching, override `max_num_seqs` on the
diffusion stage. Use Stage 1 for either two-stage config:
```bash
vllm serve ByteDance-Seed/BAGEL-7B-MoT --omni --port 8091 \
--deploy-config vllm_omni/deploy/bagel.yaml \
--step-execution \
--stage-overrides '{"1":{"max_num_seqs":4}}'
```
Use Stage 0 for the single-stage config:
```bash
vllm serve ByteDance-Seed/BAGEL-7B-MoT --omni --port 8091 \
--deploy-config vllm_omni/deploy/bagel_single_stage.yaml \
--step-execution \
--stage-overrides '{"0":{"max_num_seqs":4}}'
```
2026-09-05 01:05:05 +08:00
BAGEL image requests require `num_inference_steps >= 2` : the original BAGEL
schedule uses `num_inference_steps - 1` denoising updates. The scheduler batches
only requests with compatible effective image sizes and BAGEL CFG/renormalization
settings. Sequence parallelism and diffusion cache backends such as TeaCache or
2026-09-04 09:36:11 +08:00
Cache-DiT are not currently supported together with BAGEL step execution.
2026-04-24 21:21:30 +08:00
### Tensor Parallelism (TP)
For larger models or multi-GPU environments, enable TP via CLI:
```bash
vllm serve ByteDance-Seed/BAGEL-7B-MoT --omni --port 8091 --tensor-parallel-size 2
```
Or set `tensor_parallel_size` per stage in a custom deploy YAML.
### Multi-Node Deployment
Deploy each stage on a **separate node** for better resource utilization. Replace `<ORCHESTRATOR_IP>` with the actual IP address of your orchestrator node.
**1. Launch Stage 0 (Thinker / Orchestrator)** on the orchestrator node:
2026-02-27 17:28:35 +08:00
```bash
2026-04-24 11:25:22 +08:00
# API server port for client requests: 8000
2026-02-27 17:28:35 +08:00
vllm serve ByteDance-Seed/BAGEL-7B-MoT --omni \
2026-04-24 11:25:22 +08:00
--port 8000 \
2026-02-27 17:28:35 +08:00
--stage-id 0 \
2026-04-24 11:25:22 +08:00
--omni-master-address <ORCHESTRATOR_IP> \
--omni-master-port 8091
2026-02-27 17:28:35 +08:00
```
2026-04-24 21:21:30 +08:00
**2. Launch Stage 1 (DiT)** on the remote node in headless mode:
2026-02-27 17:28:35 +08:00
```bash
vllm serve ByteDance-Seed/BAGEL-7B-MoT --omni \
--stage-id 1 \
--headless \
2026-04-24 11:25:22 +08:00
--omni-master-address <ORCHESTRATOR_IP> \
--omni-master-port 8091
2026-02-27 17:28:35 +08:00
```
2026-04-24 21:21:30 +08:00
Or use the convenience script:
2026-02-27 17:28:35 +08:00
2026-04-24 21:21:30 +08:00
```bash
# Terminal 1: Stage 0
bash run_server_stage_cli.sh --stage 0
# Terminal 2: Stage 1
bash run_server_stage_cli.sh --stage 1
# With extra args
bash run_server_stage_cli.sh --stage 0 -- --tensor-parallel-size 2
bash run_server_stage_cli.sh --stage 1 -- --gpu-memory-utilization 0.9
```
2026-02-27 17:28:35 +08:00
**vllm serve arguments:**
| Argument | Description |
| :------- | :---------- |
| `--stage-id` | Which stage this process runs (0 = Thinker, 1 = DiT) |
| `--headless` | Run without the API server (worker-only mode) |
2026-04-24 21:21:30 +08:00
| `-oma` / `--omni-master-address` | Orchestrator master address |
| `-omp` / `--omni-master-port` | Orchestrator master port |
2026-02-27 17:28:35 +08:00
> [!IMPORTANT]
> **Startup Order**: Stage 0 (orchestrator) must be launched **before** Stage 1 (headless).
> Stage 0 will appear to hang on startup until Stage 1 (worker) connects — this is expected behavior.
2026-04-24 21:21:30 +08:00
### Inter-Stage Connectors
2026-02-27 17:28:35 +08:00
2026-04-24 21:21:30 +08:00
When deploying stages across nodes, configure the connector type in the deploy YAML:
2026-02-27 17:28:35 +08:00
2026-04-24 21:21:30 +08:00
- **SharedMemoryConnector** (default): Used for single-node deployments. No explicit configuration needed.
- **MooncakeTransferEngineConnector**: For multi-node setups with RDMA hardware. Defined in [`bagel.yaml` ](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/deploy/bagel.yaml ) under `connectors.rdma_connector` .
2026-02-27 17:28:35 +08:00
2026-04-24 21:21:30 +08:00
To use Mooncake, create a custom deploy YAML that binds `output_connectors` / `input_connectors` on each stage to the `rdma_connector` defined in the `connectors` section.
2026-02-27 17:28:35 +08:00
2026-04-24 21:21:30 +08:00
## Send Requests
2026-01-30 07:56:10 +08:00
```bash
cd examples/online_serving/bagel
```
### Text to Image (text2img)
2026-04-24 21:21:30 +08:00
**Python client:**
2026-01-30 07:56:10 +08:00
```bash
python openai_chat_client.py \
--prompt "A beautiful sunset over mountains" \
--modality text2img \
--output sunset.png \
--steps 50
```
2026-04-24 21:21:30 +08:00
**curl:**
2026-01-30 07:56:10 +08:00
```bash
curl http://localhost:8091/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"messages": [{"role": "user", "content": [{"type": "text", "text": "<|im_start|>A beautiful sunset over mountains<|im_end|>"}]}],
"modalities": ["image"],
"height": 512,
"width": 512,
"num_inference_steps": 50,
"seed": 42
}'
```
### Image to Image (img2img)
2026-04-24 21:21:30 +08:00
**Python client:**
2026-01-30 07:56:10 +08:00
```bash
python openai_chat_client.py \
--prompt "Make the cat stand up" \
--modality img2img \
--image-url /path/to/input.jpg \
--output transformed.png
```
2026-04-24 21:21:30 +08:00
**curl:**
2026-01-30 07:56:10 +08:00
```bash
IMAGE_BASE64 = $( base64 -w 0 cat.jpg)
cat <<EOF > payload.json
{
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "<|im_start|>Make the cat stand up<|im_end|>"},
{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,${IMAGE_BASE64}"}}
]
}],
"modalities": ["image"],
"height": 512,
"width": 512,
"num_inference_steps": 50,
"seed": 42
}
EOF
curl http://localhost:8091/v1/chat/completions \
-H "Content-Type: application/json" \
-d @payload.json
```
2026-09-21 15:29:24 +08:00
When no output size is requested (`size=auto` on `/v1/images/edits` , or no
`height` /`width` in a chat request), BAGEL img2img derives the canvas from the
input image: it preserves the input aspect ratio, aligns dimensions to the
latent stride (16 px), and applies the checkpoint size limit. An explicit
`size` , `height` , or `width` is honored instead, in both the single-stage and
the two-stage deployment; the input image is still resized to a stride-aligned
size for the VAE/ViT prefill. The latent grid needs multiples of 16, so a
requested side that is not one is floored to the next multiple (1000x700
generates 992x688) and the server logs a warning; the response reports the
generated size. A side above the checkpoint limit is rejected with HTTP 400.
In step mode, the effective size is resolved before scheduler admission so
requests with different resulting shapes are not combined.
2026-09-04 09:36:11 +08:00
2026-01-30 07:56:10 +08:00
### Image to Text (img2text)
2026-04-24 21:21:30 +08:00
**Python client:**
2026-01-30 07:56:10 +08:00
```bash
python openai_chat_client.py \
--prompt "Describe this image in detail" \
--modality img2text \
--image-url /path/to/image.jpg
```
2026-04-24 21:21:30 +08:00
**curl:**
2026-01-30 07:56:10 +08:00
```bash
IMAGE_BASE64 = $( base64 -w 0 cat.jpg)
cat <<EOF > payload.json
{
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "<|im_start|>user\n<|image_pad|>\nDescribe this image in detail<|im_end|>\n<|im_start|>assistant\n"},
{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,${IMAGE_BASE64}"}}
]
}],
"modalities": ["text"]
}
EOF
curl http://localhost:8091/v1/chat/completions \
-H "Content-Type: application/json" \
-d @payload.json
```
### Text to Text (text2text)
2026-04-24 21:21:30 +08:00
**Python client:**
2026-01-30 07:56:10 +08:00
```bash
python openai_chat_client.py \
--prompt "What is the capital of France?" \
--modality text2text
```
2026-04-24 21:21:30 +08:00
**curl:**
2026-01-30 07:56:10 +08:00
```bash
curl http://localhost:8091/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
2026-04-24 21:21:30 +08:00
"messages": [{"role": "user", "content": [{"type": "text", "text": "<|im_start|>user\nWhat is the capital of France?<|im_end|>\n<|im_start|>assistant\n"}]}],
2026-01-30 07:56:10 +08:00
"modalities": ["text"]
}'
```
2026-04-24 21:21:30 +08:00
### Python Client Arguments
| Argument | Default | Description |
| :------- | :------ | :---------- |
| `--prompt` / `-p` | `A cute cat` | Text prompt |
| `--output` / `-o` | `bagel_output.png` | Output file path |
| `--server` / `-s` | `http://localhost:8091` | Server URL |
| `--image-url` / `-i` | `None` | Input image URL or local path (img2img/img2text) |
| `--modality` / `-m` | `text2img` | `text2img` , `img2img` , `img2text` , `text2text` |
2026-09-21 15:29:24 +08:00
| `--height` | `512` | Output height, a multiple of 16; omit both `--height` and `--width` to let img2img derive the size from the input image |
| `--width` | `512` | Output width, a multiple of 16; omit both `--height` and `--width` to let img2img derive the size from the input image |
2026-04-24 21:21:30 +08:00
| `--steps` | `25` | Number of inference steps |
| `--seed` | `42` | Random seed |
| `--negative` | `None` | Negative prompt for CFG |
Example with custom parameters:
```bash
python openai_chat_client.py \
--prompt "A futuristic city" \
--modality text2img \
--height 768 \
--width 768 \
--steps 50 \
--seed 42 \
--negative "blurry, low quality"
```
## Configuration Reference
### Deploy YAML Files
| File | Description |
| :--- | :---------- |
| [`bagel.yaml` ](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/deploy/bagel.yaml ) | Two-stage default (Thinker + DiT on GPU 0) |
2026-09-04 09:36:11 +08:00
| [`bagel_think.yaml` ](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/deploy/bagel_think.yaml ) | Two-stage think mode (Thinker + DiT) |
2026-04-24 21:21:30 +08:00
| [`bagel_single_stage.yaml` ](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/deploy/bagel_single_stage.yaml ) | Single-stage (DiT only) |
### Key Deploy YAML Fields
| Field | Scope | Description |
| :---- | :---- | :---------- |
| `pipeline` | top-level | Override auto-detected pipeline (e.g. `bagel_single_stage` ) |
| `stages[].stage_id` | per-stage | Stage identifier (0, 1, ...) |
| `stages[].devices` | per-stage | GPU device IDs (e.g. `"0"` , `"0,1"` ) |
| `stages[].max_num_seqs` | per-stage | Maximum concurrent sequences |
| `stages[].gpu_memory_utilization` | per-stage | Fraction of GPU memory to use |
| `stages[].enforce_eager` | per-stage | Disable CUDA graphs |
| `stages[].tensor_parallel_size` | per-stage | TP degree for this stage |
| `connectors` | top-level | Define available connector instances (SHM, Mooncake) |
| `platforms` | top-level | Platform-specific overrides (e.g. `xpu` ) |
2026-01-30 07:56:10 +08:00
## FAQ
2026-04-24 21:21:30 +08:00
- If you encounter OOM errors, try decreasing `max_model_len` or `gpu_memory_utilization` in the deploy YAML.
2026-01-30 07:56:10 +08:00
2026-04-24 21:21:30 +08:00
**Two-stage VRAM usage:**
| Stage | VRAM |
| :---- | :--- |
| Stage 0 (Thinker) | **15.04 GiB + KV Cache** |
| Stage 1 (DiT) | **26.50 GiB** |
| Total | ** ~42 GiB + KV Cache** |
**Single-stage VRAM usage:** The DiT loads the full model (~42 GiB) in one process.
2026-02-03 18:11:50 +08:00
## Example materials
??? abstract "openai_chat_client.py"
``````py
--8<-- "examples/online_serving/bagel/openai_chat_client.py"
` `````
??? abstract "run_server.sh"
` `````sh
--8<-- "examples/online_serving/bagel/run_server.sh"
` `````
2026-02-27 17:28:35 +08:00
??? abstract "run_server_stage_cli.sh"
` `````sh
--8<-- "examples/online_serving/bagel/run_server_stage_cli.sh"
` `````