feat(examples): add interactive JAX distributed TPU smoke test notebook (#3531)

Signed-off-by: Richa Banker <[email protected]>
This commit is contained in:
Richa Banker
2026-06-26 16:26:06 +00:00
committed by GitHub
parent a6e862ee0c
commit eb600c46fa
+315
View File
@@ -0,0 +1,315 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "48dd25df",
"metadata": {},
"source": [
"# Distributed JAX TPU Smoke Test with Kubeflow Trainer\n",
"\n",
"This notebook demonstrates how to run a distributed JAX verification job on physical Cloud TPUs using the Kubeflow Trainer Python SDK.\n",
"\n",
"It initializes a distributed JAX environment, verifies hardware discovery across all physical TPU chips, and executes a basic multi-host matrix multiplication."
]
},
{
"cell_type": "markdown",
"id": "b4af3557",
"metadata": {},
"source": [
"## Install the Kubeflow SDK\n",
"\n",
"You need to install the Kubeflow SDK to interact with Kubeflow Trainer."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a0434dd0",
"metadata": {},
"outputs": [],
"source": [
"# !pip install -U kubeflow"
]
},
{
"cell_type": "markdown",
"id": "c7b57327",
"metadata": {},
"source": [
"## Define JAX Distributed Verification Function\n",
"\n",
"This function will run on each TPU worker. It initializes JAX's distributed coordination service, prints diagnostic information about local and global TPU devices, and runs a distributed matrix multiplication."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4a05ab4c",
"metadata": {},
"outputs": [],
"source": [
"def jax_tpu_smoke_test():\n",
" import jax\n",
" import jax.numpy as jnp\n",
"\n",
" # Initialize distributed JAX coordination\n",
" jax.distributed.initialize()\n",
"\n",
" # Log device count\n",
" print(\"==========================\")\n",
" print(f\"Total global TPU device count: {jax.device_count()}\")\n",
" print(f\"Local TPU device count: {jax.local_device_count()}\")\n",
" print(f\"Global TPU devices details: {jax.devices()}\")\n",
" print(\"==========================\")\n",
"\n",
" # Execute distributed matrix multiplication to verify JAX TPU backend\n",
" x = jnp.ones((1000, 1000))\n",
" y = (x @ x).block_until_ready()\n",
" \n",
" print(f\"JAX Matrix Multiplication verification successfully completed! Result shape: {y.shape}\")"
]
},
{
"cell_type": "markdown",
"id": "2481ec3e",
"metadata": {},
"source": [
"## Initialize Kubeflow Trainer Client\n",
"\n",
"We initialize the `TrainerClient` which communicates with the Kubeflow Trainer API on the Kubernetes cluster."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "591048ad",
"metadata": {},
"outputs": [],
"source": [
"from kubeflow.trainer import TrainerClient, CustomTrainer\n",
"\n",
"client = TrainerClient()"
]
},
{
"cell_type": "markdown",
"id": "183e82e4",
"metadata": {},
"source": [
"## Configure GKE TPU Scheduling Patches\n",
"\n",
"Since physical TPU hardware requires GKE-specific node selectors, topologies, and tolerations, we configure a `RuntimePatch` programmatically in the Python SDK. This will inject the GKE scheduling parameters directly into our training Pod specifications."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cd87905d",
"metadata": {},
"outputs": [],
"source": [
"from kubeflow.trainer.options import RuntimePatch\n",
"from kubeflow.trainer.options.kubernetes import (\n",
" TrainingRuntimeSpecPatch,\n",
" JobSetTemplatePatch,\n",
" JobSetSpecPatch,\n",
" ReplicatedJobPatch,\n",
" JobTemplatePatch,\n",
" JobSpecPatch,\n",
" PodTemplatePatch,\n",
" PodSpecPatch,\n",
")\n",
"\n",
"# We define a GKE scheduling patch using typed SDK dataclasses\n",
"tpu_patch = RuntimePatch(\n",
" training_runtime_spec=TrainingRuntimeSpecPatch(\n",
" template=JobSetTemplatePatch(\n",
" spec=JobSetSpecPatch(\n",
" replicated_jobs=[\n",
" ReplicatedJobPatch(\n",
" name=\"node\",\n",
" template=JobTemplatePatch(\n",
" spec=JobSpecPatch(\n",
" template=PodTemplatePatch(\n",
" spec=PodSpecPatch(\n",
" node_selector={\n",
" \"cloud.google.com/gke-tpu-accelerator\": \"tpu-v5-lite-podslice\",\n",
" \"cloud.google.com/gke-tpu-topology\": \"2x2\",\n",
" },\n",
" tolerations=[\n",
" {\n",
" \"key\": \"google.com/tpu\",\n",
" \"operator\": \"Exists\",\n",
" \"effect\": \"NoSchedule\",\n",
" }\n",
" ],\n",
" )\n",
" )\n",
" )\n",
" )\n",
" )\n",
" ]\n",
" )\n",
" )\n",
" )\n",
")"
]
},
{
"cell_type": "markdown",
"id": "56ba99df",
"metadata": {},
"source": [
"## Submit the Distributed JAX TPU TrainJob\n",
"\n",
"We submit our JAX TPU job by referencing the `jax-distributed` ClusterTrainingRuntime and applying our custom TPU scheduling runtime patch.\n",
"\n",
"Note that we configure:\n",
"1. `resources_per_node` requesting `\"google.com/tpu\": 4` to specify the physical TPU chips.\n",
"2. JAX platform coordination environment variables: `JAX_PLATFORMS=\"tpu,cpu\"` and `ENABLE_PJRT_COMPATIBILITY=\"true\"`.\n",
"3. A JAX compatible TPU image: `us-docker.pkg.dev/cloud-tpu-images/jax-ai-image/tpu:latest`."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d5243de1",
"metadata": {},
"outputs": [],
"source": [
"num_tpu_per_node = 4\n",
"num_nodes = 1\n",
"\n",
"job_name = client.train(\n",
" trainer=CustomTrainer(\n",
" func=jax_tpu_smoke_test,\n",
" image=\"us-docker.pkg.dev/cloud-tpu-images/jax-ai-image/tpu:latest\",\n",
" num_nodes=num_nodes,\n",
" resources_per_node={\n",
" \"google.com/tpu\": num_tpu_per_node\n",
" },\n",
" env={\n",
" \"JAX_PLATFORMS\": \"tpu,cpu\",\n",
" \"ENABLE_PJRT_COMPATIBILITY\": \"true\"\n",
" }\n",
" ),\n",
" runtime=\"jax-distributed\",\n",
" options=[tpu_patch]\n",
")\n",
"\n",
"print(f\"Training job '{job_name}' submitted successfully for JAX TPU execution!\")"
]
},
{
"cell_type": "markdown",
"id": "2a037675",
"metadata": {},
"source": [
"## Monitor TrainJob Steps & Devices\n",
"\n",
"Wait for the TrainJob to transition into `Running` status, and check details about scheduled worker Pods, devices, and replica counts."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "70deefeb",
"metadata": {},
"outputs": [],
"source": [
"# Wait for the job to reach 'Running' status\n",
"client.wait_for_job_status(name=job_name, status={\"Running\"})\n",
"\n",
"# Display step properties and active Pod metadata\n",
"for step in client.get_job(name=job_name).steps:\n",
" print(f\"Step Name: {step.name}, Pod Name: {step.pod_name}, Status: {step.status}, Device Requested: {step.device}, Device Count: {step.device_count}\")"
]
},
{
"cell_type": "markdown",
"id": "41677279",
"metadata": {},
"source": [
"## Fetch JAX TPU Coordinator Logs\n",
"\n",
"Retrieve and print logs from all active distributed JAX hosts. You should see JAX successfully initialize PJRT on the physical Cloud TPU backend and display details of the global devices."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b410f857",
"metadata": {},
"outputs": [],
"source": [
"import time\n",
"\n",
"# Give JAX initialization some time to write stdout\n",
"time.sleep(10)\n",
"\n",
"# Fetch and print logs from each worker replica\n",
"logs = client.get_job_logs(name=job_name)\n",
"for worker_name, log_text in logs.items():\n",
" print(f\"\\n=== Distributed JAX Logs for Worker Replica: {worker_name} ===\")\n",
" print(log_text)\n",
" print(\"=======================================================\")"
]
},
{
"cell_type": "markdown",
"id": "4162b7ac",
"metadata": {},
"source": [
"## Verify TrainJob Successful Completion\n",
"\n",
"We block and wait for the job to finish with a success state."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "26cab010",
"metadata": {},
"outputs": [],
"source": [
"# Wait for job to reach 'Succeeded' status\n",
"client.wait_for_job_status(name=job_name, status={\"Succeeded\"}, timeout=120)\n",
"print(f\"Distributed JAX TPU TrainJob '{job_name}' finished and verified successfully!\")"
]
},
{
"cell_type": "markdown",
"id": "5b926dfd",
"metadata": {},
"source": [
"## Clean Up Resources\n",
"\n",
"Once training or verification is finished, clean up the Kubernetes resources by deleting the TrainJob object."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "13759389",
"metadata": {},
"outputs": [],
"source": [
"# client.delete_job(job_name)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python",
"version": "3.11.15"
}
},
"nbformat": 4,
"nbformat_minor": 5
}