Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 47 additions & 4 deletions docs/tutorials/posttraining/multimodal.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ This document provides a guide to use the multimodal functionalities in MaxText

We also provide a [colab](https://github.com/AI-Hypercomputer/maxtext/blob/main/src/maxtext/examples/multimodal_gemma3_demo.ipynb) for multimodal features demonstration. The following table provides a list of models and modalities we currently support:

| Models | Input Modalities | Output Modalities |
| :--------------------------------------------- | :--------------- | :---------------- |
| - Gemma3-4B/12B/27B<br>- Llama4-Scout/Maverick | Text, images | Text |
| Models | Input: Text | Input: Image | Input: Video | Input: Audio | Output |
| :-------------------------- | :---------: | :----------: | :----------: | :----------: | :----: |
| **Gemma3** (4B/12B/27B) | ✓ | ✓ | | | Text |
| **Gemma4** (26B/31B) | ✓ | ✓ | | | Text |
| **Llama4** (Scout/Maverick) | ✓ | ✓ | | | Text |
| **Qwen3-Omni** | ✓ | ✓ | ✓ | ✓ | Text |
| **Qwen3.5** (35B/397B) | ✓ | ✓ | ✓ | | Text |

## Introduction

Expand Down Expand Up @@ -73,6 +77,8 @@ MaxText supports multimodal decoding, allowing you to input text with multiple i

Since each model uses a unique native chatting template from its pretraining, we've implemented these specific templates within `multimodal_utils.py` and apply them directly to your prompt.

### Decode with text+image

To run a forward pass and verify the model's output, use the following command:

```shell
Expand Down Expand Up @@ -124,10 +130,47 @@ python -m maxtext.inference.decode \

For larger models such as Llama4-Scout/Maverick, we suggest to run the decoding on a TPU cluster such as v5p-16.

### Decode with text+video+audio

For models that support video input (e.g., Qwen3-Omni and Qwen3.5), pass a video file via `video_path`. For Qwen3-Omni, which also supports audio, set `use_audio_in_video=true` to additionally process the embedded audio track. Since the required token budget scales with video length and resolution, set `max_prefill_predict_length` accordingly.

```shell
# Qwen3-Omni decode with video + audio
export MAXTEXT_CKPT_PATH=<Checkpoint GCS path> # gs://my-bucket/path for Qwen3-Omni
python -m maxtext.inference.decode \
model_name=qwen3-omni-30b-a3b \
tokenizer_path=Qwen/Qwen3-Omni-30B-A3B-Instruct \
tokenizer_type=huggingface \
load_parameters_path=${MAXTEXT_CKPT_PATH?}/0/items \
per_device_batch_size=1 \
run_name=ht_test \
steps=1 \
async_checkpointing=false \
scan_layers=false \
use_multimodal=true \
use_audio_in_video=true \
prompt='What can you see and hear? Answer in one short sentence.' \
video_path='tests/assets/test_video.mp4' \
max_prefill_predict_length=1250 \
max_target_length=1280 \
add_bos=false \
attention='dot_product' \
```

The expected output will look similar to:

```
Input `<|im_start|>user
<|vision_start|><|video_pad|><|vision_end|>What can you see and hear? Answer in one short sentence.<|im_end|>
<|im_start|>assistant
` -> `A roaring Tyrannosaurus rex animatronic is displayed in a museum exhibit.
```

## Supervised Fine-Tuning

Supervised Fine-Tuning (SFT) of multimodal LLMs in MaxText focuses specifically on post-training; we don't yet support pre-training multimodal models from scratch. The SFT process typically involves training on Visual Question Answering (VQA) datasets where the model learns to generate accurate text responses based on both visual and textual inputs. During this fine-tuning phase, we recommend to freeze the pre-trained encoder layers (such as vision transformers) to preserve their learned visual representations, while the projection layers and LLM decoder components remain trainable. This selective training strategy allows the model to adapt the cross-modal alignment and text generation capabilities without disrupting the robust feature extraction abilities of the encoders, ultimately leading to improved performance on multimodal understanding and reasoning tasks while maintaining computational efficiency. This is achieved by setting `freeze_vision_encoder_params=True` in [sft-vision-chartqa.yml](https://github.com/AI-Hypercomputer/maxtext/blob/main/src/maxtext/configs/post_train/sft-vision-chartqa.yml).
Here, we use [ChartQA](https://huggingface.co/datasets/HuggingFaceM4/ChartQA) as an example to demonstrate SFT functionality:

**Text+image SFT is supported for all models listed above.** The following example uses Gemma3-4B with the [ChartQA](https://huggingface.co/datasets/HuggingFaceM4/ChartQA) dataset:

```shell
export MAXTEXT_CKPT_PATH=<your-checkpoints-path> # either set to an already available MaxText ckpt or to the one we just converted in the previous step
Expand Down
2 changes: 2 additions & 0 deletions tests/end_to_end/tpu/gemma3/Run_Gemma3.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

We provide examples for checkpoint conversion and decoding/training/finetuning Gemma3 in test scripts at [tests/end_to_end/tpu/gemma3](https://github.com/AI-Hypercomputer/maxtext/tree/main/tests/end_to_end/tpu/gemma3).

For multimodal functionality, see the [Multimodal Support guide](../../../../docs/tutorials/posttraining/multimodal.md).


## Pre-training
You can train from scratch to generate a new checkpoint. One example command to run pretraining Gemma3-4B model is as follows:
Expand Down
1 change: 1 addition & 0 deletions tests/end_to_end/tpu/llama4/Run_Llama4.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* LLama4 Maverick (17B-128E)
* Llama4 Maverick (17B-128E-Instruct)

For multimodal functionality, see the [Multimodal Support guide](../../../../docs/tutorials/posttraining/multimodal.md).

## Checkpoint conversion
Currently, we support converting both [PyTorch](https://www.llama.com/) and [HuggingFace](https://huggingface.co/collections/meta-llama/llama-4-67f0c30d9fe03840bc9d0164) checkpoints. Note that we recommend using the `huggingface-cli download` command with environment variable
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/bash

# This file is documentation for how to get started with Qwen3-Omni-30B-A3B.

# This file runs Step 1 on CPU.
# 1. Convert the HuggingFace checkpoint (bf16) to MaxText-compatible checkpoint (bf16):
# Unscanned format is used here as it is better suited for decoding.
# ---
# Example Usage:
#
# export HF_TOKEN=<your_hf_token>
# export BASE_OUTPUT_PATH=gs://your-gcs-bucket/qwen3-omni-30b-a3b_maxtext_ckpt
# bash tests/end_to_end/tpu/qwen/moe/qwen3-omni-30b-a3b/1_test_qwen3_omni_30b_a3b.sh
# ---

set -ex

export MODEL_NAME="${MODEL_NAME:-qwen3-omni-30b-a3b}"
export TOKENIZER_PATH="${TOKENIZER_PATH:-Qwen/Qwen3-Omni-30B-A3B-Instruct}"

# (Optional) Path to your local Hugging Face checkpoint
export HF_MODEL_PATH="${HF_MODEL_PATH:-}"

# Base output path for MaxText checkpoint.
export BASE_OUTPUT_PATH="${BASE_OUTPUT_PATH:-gs://your-gcs-bucket/qwen3-omni-30b-a3b_maxtext_ckpt}"

if [ -z "${HF_TOKEN}" ]; then
echo "Error: HF_TOKEN environment variable is not set. Please export your Hugging Face token."
echo "Example: export HF_TOKEN=hf_..."
exit 1
fi

# Strip trailing slash from base path to avoid malformed URIs
BASE_OUTPUT_PATH=${BASE_OUTPUT_PATH%/}
echo "Using BASE_OUTPUT_PATH = ${BASE_OUTPUT_PATH}"

# Install torch for checkpoint conversion
python3 -m pip install torch --index-url https://download.pytorch.org/whl/cpu

# Setup local HF path argument if one was provided
HF_LOCAL_ARG=""
if [ -n "${HF_MODEL_PATH}" ]; then
HF_LOCAL_ARG="hf_model_path=${HF_MODEL_PATH}"
fi

# ---
# Step 1: Checkpoint Conversion
Comment thread
hengtaoguo marked this conversation as resolved.
# Convert HuggingFace checkpoint to MaxText unscanned format (better for decoding).
# use_multimodal=true is required to include vision/audio encoder weights.
# ---
JAX_PLATFORMS=cpu python3 -m maxtext.checkpoint_conversion.to_maxtext src/maxtext/configs/base.yml \
model_name=${MODEL_NAME} \
base_output_directory=${BASE_OUTPUT_PATH}/unscanned \
hf_access_token=${HF_TOKEN} \
scan_layers=false \
use_multimodal=true \
--lazy_load_tensors=False \
${HF_LOCAL_ARG}


Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/bin/bash

# This file is documentation for how to get started with Qwen3-Omni-30B-A3B.

# This file runs Step 2 on a v5p-8 TPU VM.
# 2. Run multimodal decoding: text+image, and text+video+audio.
# ---
# Example Usage:
#
# export HF_TOKEN=<your_hf_token>
# export BASE_OUTPUT_PATH=gs://your-gcs-bucket/qwen3-omni-30b-a3b_maxtext_ckpt
# bash tests/end_to_end/tpu/qwen/moe/qwen3-omni-30b-a3b/2_test_qwen3_omni_30b_a3b.sh
# ---

set -ex

export MODEL_NAME="${MODEL_NAME:-qwen3-omni-30b-a3b}"
export TOKENIZER_PATH="${TOKENIZER_PATH:-Qwen/Qwen3-Omni-30B-A3B-Instruct}"

if [ -z "${BASE_OUTPUT_PATH}" ]; then
# Non-Googlers please remember to point `BASE_OUTPUT_PATH` to GCS buckets that you own, this script uses internal buckets for testing.
# this bucket will store all the files generated by MaxText during a run
export BASE_OUTPUT_PATH=gs://runner-maxtext-logs/$(date +%Y-%m-%d-%H-%M)
echo "BASE_OUTPUT_PATH is not set"
fi
BASE_OUTPUT_PATH=${BASE_OUTPUT_PATH%/}
echo using BASE_OUTPUT_PATH = ${BASE_OUTPUT_PATH}

if [ -z "${HF_TOKEN}" ]; then
echo "Error: HF_TOKEN environment variable is not set. Please export your Hugging Face token."
echo "Example: export HF_TOKEN=hf_..."
exit 1
fi

UNSCANNED_CKPT_PATH=gs://maxtext-model-checkpoints/qwen3-omni-30b-a3b/unscanned/0/items

# ---
# Step 2a: Multimodal Decode — text + image
Comment thread
hengtaoguo marked this conversation as resolved.
# Uses a test image from the repo assets.
# max_prefill_predict_length accounts for image tokens (~256) + text prompt tokens.
# ---
python3 -m maxtext.inference.decode ${MAXTEXT_CONFIGS_DIR:-${MAXTEXT_REPO_ROOT:-$PWD}/src/maxtext/configs}/base.yml \
model_name=${MODEL_NAME} \
tokenizer_path=${TOKENIZER_PATH} \
tokenizer_type=huggingface \
load_parameters_path=${UNSCANNED_CKPT_PATH} \
hf_access_token=${HF_TOKEN} \
per_device_batch_size=1 \
run_name=qwen3_omni_decode_image \
steps=1 \
async_checkpointing=false \
scan_layers=false \
use_multimodal=true \
prompt='Describe this image in one sentence.' \
image_path='tests/assets/test_image.jpg' \
max_prefill_predict_length=512 \
max_target_length=542 \
add_bos=false \
attention=dot_product

# ---
# Step 2b: Multimodal Decode — text + video + audio
# Passes a video file and enables audio processing from the video track.
# max_prefill_predict_length is set higher to accommodate video frame tokens (~1126)
# plus audio tokens (~77) plus text prompt tokens.
# ---
python3 -m maxtext.inference.decode ${MAXTEXT_CONFIGS_DIR:-${MAXTEXT_REPO_ROOT:-$PWD}/src/maxtext/configs}/base.yml \
model_name=${MODEL_NAME} \
tokenizer_path=${TOKENIZER_PATH} \
tokenizer_type=huggingface \
load_parameters_path=${UNSCANNED_CKPT_PATH} \
hf_access_token=${HF_TOKEN} \
per_device_batch_size=1 \
run_name=qwen3_omni_decode_video \
steps=1 \
async_checkpointing=false \
scan_layers=false \
use_multimodal=true \
use_audio_in_video=true \
prompt='What can you see and hear? Answer in one short sentence.' \
video_path='tests/assets/test_video.mp4' \
max_prefill_predict_length=1240 \
max_target_length=1280 \
add_bos=false \
attention=dot_product
22 changes: 22 additions & 0 deletions tests/end_to_end/tpu/qwen/moe/run_qwen_moe.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,20 @@ Qwen3 is a family of open-source large language models from the Qwen team at Ali

- **Qwen3-480B-A35B**

- **Qwen3-Omni-30B-A3B**
Comment thread
hengtaoguo marked this conversation as resolved.

- **Qwen3.5-397B-A17B**

- **Qwen3.5-35B-A3B**

For more details on Qwen3 architecture, see the [Qwen3 Technical Report](https://arxiv.org/abs/2505.09388).

For more details on Qwen3-Omni architecture, see the [Qwen3-Omni Technical Report](https://arxiv.org/abs/2509.17765).

For more details on Qwen3.5 architecture, see the [Qwen3.5 Blog](https://qwen.ai/blog?id=qwen3.5)

For multimodal functionality (image, video, and audio input), see the [Multimodal Support guide](../../../../../docs/tutorials/posttraining/multimodal.md).

* * * * *

Checkpoint Conversion
Expand Down Expand Up @@ -153,6 +159,22 @@ export MAXTEXT_CHECKPOINT_PATH=gs://your-gcs-bucket/qwen3-480b-a35b_maxtext_ckpt
bash tests/end_to_end/tpu/qwen/moe/qwen3-480b-a35b/1_test_qwen3_480b_a35b.sh
```

### Qwen3-Omni-30B-A3B

```bash
# 1. Export your Hugging Face token
export HF_TOKEN="your_hf_token_here"

# 2. Set the base path for conversion and SFT outputs
export BASE_OUTPUT_PATH=gs://<YOUR-GCS-BUCKET>/qwen3-omni-30b-a3b_maxtext_ckpt

# (Optional) Set the path if you are using a local Hugging Face checkpoint instead of downloading
# export HF_MODEL_PATH=/path/to/local/qwen3-omni-30b-a3b_hf_checkpoint

# 3. Execute the conversion and multimodal decode verification
bash tests/end_to_end/tpu/qwen/moe/qwen3-omni-30b-a3b/1_test_qwen3_omni_30b_a3b.sh
```

### Qwen3.5-35B-A3B

```bash
Expand Down
Loading