-
Notifications
You must be signed in to change notification settings - Fork 36
feat: Add Gemma-4 Multi-token-prediction Guide for TPUs #520
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
syeda-anjum
wants to merge
13
commits into
main
Choose a base branch
from
sanjum-dspark-mtp
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
fb8e30a
feat(tpu): add mtp speculative decoding overlay for gemma-4
syeda-anjum 40848ea
fix(tpu): update vllm-tpu image to v0.25.0
syeda-anjum dd683e5
docs: add guide for gemma-4 mtp speculative decoding on tpu
syeda-anjum 6863543
docs: add tfvars configuration steps for gemma-4 mtp
syeda-anjum 11b4a6f
docs: fix model download steps for mtp drafter in readme
syeda-anjum 8ee67e1
fix(tpu): distinguish mtp deployment name from base gemma-4 deployment
syeda-anjum 8868cb0
chore: run prettier on docs and manifests
syeda-anjum dd6646d
fix: revert accidental file modifications and add missing license hea…
syeda-anjum 6e59a6f
docs: expand MTP explanation and add benchmarking configs
syeda-anjum 414292d
docs: add n-gram and dataset explanation, fix OOM config
syeda-anjum f7be9eb
Merge branch 'main' into sanjum-dspark-mtp
syeda-anjum 2e79718
feat: Update TPU Multipod (MTP) configurations for Gemma-4
syeda-anjum f4c53dd
Merge remote-tracking branch 'origin/main' into sanjum-dspark-mtp
syeda-anjum File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
292 changes: 292 additions & 0 deletions
292
.../gke/base/use-cases/inference-ref-arch/online-inference-tpu/vllm-gemma-4-mtp.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,292 @@ | ||
| # Online inference using vLLM with MTP Speculative Decoding and TPUs on Google Kubernetes Engine (GKE) | ||
|
|
||
| This document implements online inference using Trillium TPUs on Google | ||
| Kubernetes Engine (GKE) using vLLM with Multi-Token Prediction (MTP) Speculative | ||
| Decoding enabled for the Gemma-4 model. | ||
|
|
||
| Speculative decoding is a powerful optimization technique that enhances LLM | ||
| inference speed without compromising output quality. By drafting multiple future | ||
| tokens and verifying them in parallel, it significantly improves latency | ||
| compared to standard auto-regressive generation. | ||
|
|
||
| ### How MTP Differs from Other Speculative Decoding Methods | ||
|
|
||
| There are several variations of speculative decoding. MTP (Multi-Token | ||
| Prediction) takes a unique approach compared to traditional methods: | ||
|
|
||
| | Method | Architecture | Training Approach | Alignment & Acceptance Rate | Key Characteristics | | ||
| | :-------------------------------- | :--------------------------------------------------------------- | :---------------------------------------------------------------------- | :-------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------- | | ||
| | **Standard Speculative Decoding** | Separate, smaller "draft" model and large "target" model. | Models are trained completely independently. | **Lower:** Internal logic is separated, leading to frequent rejections. | Traditional approach. Simplest to implement but less efficient. | | ||
| | **Draft-Head (e.g., EAGLE)** | Additional "draft heads" attached directly to the target model. | Draft heads are trained separately _after_ base model pre-training. | **Higher:** Shares the target model's hidden states. | Avoids a separate model, but adds significant post-training complexity. | | ||
| | **MTP (Multi-Token Prediction)** | Draft modules that share the main model's internal states. | Draft modules are trained **jointly** with the base model from scratch. | **Highest:** Perfect alignment due to joint pre-training. | Gemma-4's architecture. Achieves superior efficiency without post-training add-ons. (Loaded as an "assistant" in vLLM). | | ||
| | **dSpark** | Draft-head based parallel verification architecture. | Typically requires separate training or distillation. | **High:** Uses parallel speculative verification. | _Note: Currently, dSpark is supported via the SGLang inference engine._ | | ||
| | **N-gram (Prompt Lookup)** | No extra model or head. Uses string matching against the prompt. | No training required. | **Variable:** High for repetitive/extractive tasks, very low for open-ended generation. | Completely training-free, but highly dependent on the prompt's content. | | ||
|
|
||
| ### Ideal Benchmarking Datasets for Speculative Decoding | ||
|
|
||
| Because speculative decoding works by predicting future tokens, the achievable | ||
| speedup is directly proportional to how predictable the generated text is. For | ||
| this reason, speculative decoding architectures like MTP perform exceptionally | ||
| well on: | ||
|
|
||
| - **Extractive Summarization:** Where the model frequently quotes or restates | ||
| long phrases from the source text (e.g., **CNN Daily Mail**). | ||
| - **Retrieval-Augmented Generation (RAG):** Where the context injected into the | ||
| prompt contains the literal answers the model will output. | ||
| - **Code Generation & Formatting:** Where syntax, indentation, and variable | ||
| names are highly structured and repetitive (e.g., **HumanEval** or | ||
| **ShareGPT**). | ||
|
|
||
| When benchmarking MTP, using datasets like `cnn_dailymail` rather than | ||
| open-ended conversation datasets provides a much more accurate representation of | ||
| the latency improvements you can expect in enterprise use cases. | ||
|
|
||
| This example is built on top of the | ||
| [GKE Inference reference architecture](/docs/platforms/gke/base/use-cases/inference-ref-arch/README.md). | ||
|
|
||
| ## Before you begin | ||
|
|
||
| - Get access to the models. | ||
|
|
||
| - For Gemma-4: | ||
| - Consent to the license on [Kaggle](https://www.kaggle.com/) using a | ||
| Hugging Face account. | ||
| - **google/gemma-4-31b-it** | ||
| - **google/gemma-4-31b-it-assistant** | ||
|
|
||
| - Ensure your | ||
| [Hugging Face Hub **Read** access token](/platforms/gke/base/core/huggingface/initialize/README.md) | ||
| has been added to Secret Manager. | ||
|
|
||
| ## Create and configure the Google Cloud resources | ||
|
|
||
| - Create a standard GKE cluster | ||
|
|
||
| - Inject these values into the appropriate tfvars files | ||
| (`${ACP_REPO_DIR}/platforms/gke/base/_shared_config/platform.auto.tfvars` and | ||
| `cluster.auto.tfvars`) using sed. | ||
|
|
||
| ```shell | ||
| # Update platform variables | ||
| sed -i 's/^platform_name.*/platform_name = "<platform_name>"/g' "${ACP_REPO_DIR}/platforms/gke/base/_shared_config/platform.auto.tfvars" | ||
| grep -q "^platform_default_project_id" "${ACP_REPO_DIR}/platforms/gke/base/_shared_config/platform.auto.tfvars" || echo "platform_default_project_id = \"\"" >> "${ACP_REPO_DIR}/platforms/gke/base/_shared_config/platform.auto.tfvars" | ||
| sed -i 's/^platform_default_project_id.*/platform_default_project_id = "<project_id>"/g' "${ACP_REPO_DIR}/platforms/gke/base/_shared_config/platform.auto.tfvars" | ||
|
|
||
| # Update cluster variables | ||
| sed -i 's/^cluster_region.*/cluster_region = "<cluster_region>"/g' "${ACP_REPO_DIR}/platforms/gke/base/_shared_config/cluster.auto.tfvars" | ||
| ``` | ||
|
|
||
| For Standard Cluster: | ||
|
|
||
| ```shell | ||
| ${ACP_REPO_DIR}/platforms/gke/base/core/deploy-standard.sh | ||
| ``` | ||
|
|
||
| - Deploy the online TPU resources. | ||
|
|
||
| ```shell | ||
| cd ${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/terraform/online_tpu && \ | ||
| rm -rf .terraform/ terraform.tfstate* && \ | ||
| terraform init && \ | ||
| terraform plan -input=false -out=tfplan && \ | ||
| terraform apply -input=false tfplan && \ | ||
| rm tfplan | ||
| ``` | ||
|
|
||
| ## Download the models to Cloud Storage | ||
|
|
||
| - Choose the main model. | ||
|
|
||
| - **Gemma 4 31B Instruction-Tuned (MTP)**: | ||
|
|
||
| ```shell | ||
| export HF_MODEL_ID="google/gemma-4-31b-it" | ||
| ``` | ||
|
|
||
| - Source the environment configuration. | ||
|
|
||
| ```shell | ||
| source "${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/terraform/_shared_config/scripts/set_environment_variables.sh" | ||
| ``` | ||
|
|
||
| - Configure and deploy the main model download job. | ||
|
|
||
| ```shell | ||
| "${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/kubernetes-manifests/model-download/configure_huggingface.sh" | ||
| kubectl apply --kustomize "${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/kubernetes-manifests/model-download/huggingface" | ||
| ``` | ||
|
|
||
| - Watch the main model download job until it is complete. | ||
|
|
||
| ```shell | ||
| watch --color --interval 5 --no-title \ | ||
| "kubectl --namespace=${huggingface_hub_downloader_kubernetes_namespace_name} get job/${HF_MODEL_ID_HASH}-hf-model-to-gcs | GREP_COLORS='mt=01;92' egrep --color=always -e '^' -e 'Complete' | ||
| echo '\nLogs(last 10 lines):' | ||
| kubectl --namespace=${huggingface_hub_downloader_kubernetes_namespace_name} logs job/${HF_MODEL_ID_HASH}-hf-model-to-gcs --all-containers --tail 10" | ||
| ``` | ||
|
|
||
| When the job is complete, you will see the following: | ||
|
|
||
| ```text | ||
| NAME STATUS COMPLETIONS DURATION AGE | ||
| XXXXXXXX-hf-model-to-gcs Complete 1/1 ### ### | ||
| ``` | ||
|
|
||
| You can press `CTRL`+`c` to terminate the watch. | ||
|
|
||
| - Delete the main model download job. | ||
|
|
||
| ```shell | ||
| kubectl delete --ignore-not-found --kustomize "${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/kubernetes-manifests/model-download/huggingface" | ||
| ``` | ||
|
|
||
| - Choose the drafter model and run the download job again. | ||
|
|
||
| ```shell | ||
| export HF_MODEL_ID="google/gemma-4-31b-it-assistant" | ||
| source "${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/terraform/_shared_config/scripts/set_environment_variables.sh" | ||
|
|
||
| "${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/kubernetes-manifests/model-download/configure_huggingface.sh" | ||
| kubectl apply --kustomize "${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/kubernetes-manifests/model-download/huggingface" | ||
| ``` | ||
|
|
||
| - Watch the drafter model download job until it is complete. | ||
|
|
||
| ```shell | ||
| watch --color --interval 5 --no-title \ | ||
| "kubectl --namespace=${huggingface_hub_downloader_kubernetes_namespace_name} get job/${HF_MODEL_ID_HASH}-hf-model-to-gcs | GREP_COLORS='mt=01;92' egrep --color=always -e '^' -e 'Complete' | ||
| echo '\nLogs(last 10 lines):' | ||
| kubectl --namespace=${huggingface_hub_downloader_kubernetes_namespace_name} logs job/${HF_MODEL_ID_HASH}-hf-model-to-gcs --all-containers --tail 10" | ||
| ``` | ||
|
|
||
| - Delete the drafter model download job. | ||
|
|
||
| ```shell | ||
| kubectl delete --ignore-not-found --kustomize "${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/kubernetes-manifests/model-download/huggingface" | ||
| ``` | ||
|
|
||
| ## Deploy the inference workload | ||
|
|
||
| - Set the environment variables for both models. | ||
|
|
||
| ```shell | ||
| export HF_MODEL_ID="google/gemma-4-31b-it" | ||
| export DRAFTER_MODEL_ID="google/gemma-4-31b-it-assistant" | ||
| ``` | ||
|
|
||
| - Source the environment configuration. | ||
|
|
||
| ```shell | ||
| source "${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/terraform/_shared_config/scripts/set_environment_variables.sh" | ||
| ``` | ||
|
|
||
| - Configure the deployment. | ||
|
|
||
| ```shell | ||
| "${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/kubernetes-manifests/online-inference-tpu/vllm/configure_vllm.sh" | ||
| ``` | ||
|
|
||
| - Deploy the inference workload. | ||
|
|
||
| ```shell | ||
| kubectl apply --kustomize "${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/kubernetes-manifests/online-inference-tpu/vllm/v6e-gemma-4-31b-it-mtp" | ||
| ``` | ||
|
|
||
| - Watch the deployment until it is ready. | ||
|
|
||
| ```shell | ||
| watch --color --interval 5 --no-title "kubectl --namespace=${ira_online_tpu_kubernetes_namespace_name} get deployment/vllm-v6e-gemma-4-31b-it-mtp | GREP_COLORS='mt=01;92' egrep --color=always -e '^' -e '1/1 1 1' | ||
| echo '\nLogs(last 10 lines):' | ||
| kubectl --namespace=${ira_online_tpu_kubernetes_namespace_name} logs deployment/vllm-v6e-gemma-4-31b-it-mtp --all-containers --tail 10" | ||
| ``` | ||
|
|
||
| - When the deployment is ready, you will see output similar to the following: | ||
|
|
||
| ```text | ||
| NAME READY UP-TO-DATE AVAILABLE AGE | ||
| vllm-v6e-gemma-4-31b-it-mtp 1/1 1 1 ### | ||
| ``` | ||
|
|
||
| You can press `CTRL`+`c` to terminate the watch. | ||
|
|
||
| - Send a test request to the model. | ||
|
|
||
| Start a port forward to the model service. | ||
|
|
||
| ```shell | ||
| kubectl --namespace=${ira_online_tpu_kubernetes_namespace_name} port-forward service/vllm-v6e-gemma-4-31b-it-mtp 8000:8000 >/dev/null & \ | ||
| PF_PID=$! | ||
| ``` | ||
|
|
||
| Send a test request. | ||
|
|
||
| ```shell | ||
| curl http://127.0.0.1:8000/v1/chat/completions \ | ||
| --data '{ | ||
| "model": "/gcs/'${HF_MODEL_ID}'", | ||
| "messages": [ { "role": "user", "content": "Why is the sky blue?" } ] | ||
| }' \ | ||
| --header "Content-Type: application/json" \ | ||
| --request POST \ | ||
| --show-error \ | ||
| --silent | jq | ||
| ``` | ||
|
|
||
| Stop the port forward. | ||
|
|
||
| ```shell | ||
| kill -9 ${PF_PID} | ||
| ``` | ||
|
|
||
| - Delete the workload. | ||
|
|
||
| ```shell | ||
| kubectl delete --ignore-not-found --kustomize "${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/kubernetes-manifests/online-inference-tpu/vllm/v6e-gemma-4-31b-it-mtp" | ||
| ``` | ||
|
|
||
| ## Benchmark the inference workload | ||
|
|
||
| - Set the variables for the benchmark. | ||
|
|
||
| ```shell | ||
| export ACCELERATOR="TPU" | ||
| export APP_LABEL="vllm-v6e-gemma-4-31b-it-mtp" | ||
| export HF_MODEL_ID="google/gemma-4-31b-it" | ||
| ``` | ||
|
|
||
| - Configure the benchmark manifests. | ||
|
|
||
| ```shell | ||
| "${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/kubernetes-manifests/inference-perf-bench/vllm-spec-decoding/sd-mtp/configure_benchmark.sh" | ||
| ``` | ||
|
|
||
| - Deploy the benchmark job. | ||
|
|
||
| ```shell | ||
| kubectl apply --kustomize "${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/kubernetes-manifests/inference-perf-bench/vllm-spec-decoding/sd-mtp" | ||
| ``` | ||
|
|
||
| - Watch the benchmark job until it completes. | ||
|
|
||
| ```shell | ||
| watch --color --interval 5 --no-title "kubectl --namespace=${ira_online_tpu_kubernetes_namespace_name} get job -l app=inference-perf | GREP_COLORS='mt=01;92' egrep --color=always -e '^' -e '1/1' | ||
| echo '\nLogs(last 10 lines):' | ||
| kubectl --namespace=${ira_online_tpu_kubernetes_namespace_name} logs -l app=inference-perf --tail 10" | ||
| ``` | ||
|
|
||
| - Delete the benchmark workload. | ||
|
|
||
| ```shell | ||
| kubectl delete --ignore-not-found --kustomize "${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/kubernetes-manifests/inference-perf-bench/vllm-spec-decoding/sd-mtp" | ||
| ``` | ||
|
|
||
| ## Clean up | ||
|
|
||
| - Destroy the online TPU resources. | ||
|
|
||
| ```shell | ||
| cd ${ACP_REPO_DIR}/platforms/gke/base/use-cases/inference-ref-arch/terraform/online_tpu && \ | ||
| rm -rf .terraform/ terraform.tfstate* && \ | ||
| terraform init && | ||
| terraform destroy -auto-approve | ||
| ``` | ||
2 changes: 2 additions & 0 deletions
2
platforms/gke/base/core/container_cluster/.terraform.lock.hcl
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
8 changes: 8 additions & 0 deletions
8
...arch/kubernetes-manifests/inference-perf-bench/vllm-spec-decoding/sd-mtp/benchmarking.env
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| BENCHMARKING_KUBERNETES_SERVICE_ACCOUNT=acp-tpu-mtp-inference-perf-bench | ||
| BENCHMARKING_KUBERNETES_NAMESPACE=acp-tpu-mtp-online-tpu | ||
| HUGGINGFACE_TOKEN_READ_SECRET_PROVIDER_CLASS_NAME=huggingface-token-read | ||
| RESULTS_BUCKET_NAME=acp-tpu-mtp-bench-results | ||
| DATASET_BUCKET_NAME=acp-tpu-mtp-bench-dataset | ||
| MODEL_ID=google/gemma-4-31b-it | ||
| APP_LABEL=vllm-v6e-gemma-4-31b-it-mtp | ||
|
|
62 changes: 62 additions & 0 deletions
62
...ernetes-manifests/inference-perf-bench/vllm-spec-decoding/sd-mtp/configmap-benchmark.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| # Copyright 2025 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
| --- | ||
| apiVersion: v1 | ||
| kind: ConfigMap | ||
| metadata: | ||
| name: inference-perf-config | ||
| namespace: acp-tpu-mtp-online-tpu | ||
| data: | ||
| config.yaml: | | ||
| load: | ||
| type: constant | ||
| interval: 1.0 | ||
| sweep: | ||
| type: linear | ||
| timeout: 250 | ||
| num_stages: 7 | ||
| stage_duration: 30 | ||
| num_workers: 20 | ||
| worker_max_concurrency: 15 | ||
| worker_max_tcp_connections: 2500 | ||
| api: | ||
| type: completion | ||
| streaming: true | ||
| server: | ||
| type: vllm | ||
| model_name: /gcs/google/gemma-4-31b-it | ||
| base_url: http://vllm-v6e-gemma-4-31b-it-mtp.acp-tpu-mtp-online-tpu.svc.cluster.local:8000 | ||
| ignore_eos: true | ||
| tokenizer: | ||
| pretrained_model_name_or_path: google/gemma-7b-it | ||
| data: | ||
| type: cnn_dailymail | ||
| metrics: | ||
| type: prometheus | ||
| prometheus: | ||
| scrape_interval: 15 | ||
| google_managed: true # Whether using Google Managed Prometheus | ||
| filters: [] | ||
| report: | ||
| request_lifecycle: | ||
| summary: true | ||
| per_stage: true | ||
| per_request: true | ||
| prometheus: | ||
| summary: true | ||
| per_stage: true | ||
| storage: | ||
| google_cloud_storage: | ||
| bucket_name: acp-tpu-mtp-bench-results # Required GCS bucket | ||
| report_file_prefix: null # Optional filename prefix |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How the result compares with standard inference (without MTP)?
Can you make an analysis here and share this with customers? Is it 30% better for this use case, 50% better? how customer analyse the results?