Appendix
2026.08.10Appendix A: Hands-On Manual
The brilliance of theory ultimately demands the confirmation of practice. This appendix provides you with an end-to-end, hands-on experimental guide, translating the core concepts explored in the main text -- from low-level driver installation to high-level scheduling, inference, and monitoring -- into executable commands and runnable code for your local environment.
We understand that in the complex domain of AI infrastructure, environmental variability is the greatest challenge. This manual is therefore designed with an emphasis on simplifying dependencies, clarifying prerequisites, and providing detailed annotations for every critical step. We encourage you not simply to "copy-paste" your way through the experiments, but to reflect on the principles behind each step and connect them with the knowledge points in the main text.
Ready your terminal, and let us begin this ultimate exercise of "linking theory with practice."
Environment Preparation Script: Rapid Experiment Environment Setup with Terraform/Ansible
In real production environments, we use Terraform to automate the creation of cloud resources (VPCs, virtual machines, load balancers) and then Ansible to perform fine-grained configuration on those VMs (installing drivers, configuring software). This is a complex but powerful Infrastructure as Code (IaC) workflow.
Because complete IaC scripts are tightly coupled to specific cloud providers (AWS, Azure, GCP, Alibaba Cloud, etc.) and your account configuration, providing a universal script that runs on any cloud is impractical. This section therefore provides a conceptual, templated Ansible Playbook designed to illustrate the core logic of automated configuration. Use it as a starting point and adapt it to your own environment.
For local experiments, we recommend using a physical or virtual machine running Linux (e.g., Ubuntu 22.04) with an NVIDIA GPU or access to an Ascend card.
Ansible Playbook Template (for configuring GPU nodes)
This Playbook demonstrates the automated installation of Docker, NVIDIA drivers, the NVIDIA Container Toolkit, and lightweight K8s (k3s) on one or more fresh Ubuntu nodes.
Prerequisites:
- You have a control machine with Ansible installed (
pip install ansible). - You have one or more target GPU nodes that the control machine can access via SSH without a password.
- You have configured Ansible's
inventoryfile (e.g.,/etc/ansible/hosts) on the control machine, defining your GPU node group.
[gpu_nodes]
192.168.1.101
192.168.1.102
Playbook file (setup_gpu_node.yml):
---
- hosts: gpu_nodes
become: yes
vars:
nvidia_driver_version: "535"
tasks:
- name: 1. Update APT cache and install prerequisite
apt:
update_cache: yes
name: ['apt-transport-https', 'ca-certificates', 'curl', 'gnupg-agent', 'software-properties-common']
state: present
- name: 2. Add Docker's official GPG key
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: 3. Add Docker repository
apt_repository:
repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable
state: present
- name: 4. Install Docker Engine
apt:
name: ['docker-ce', 'docker-ce-cli', 'containerd.io']
state: present
- name: 5. Add NVIDIA driver repository
apt_repository:
repo: ppa:graphics-drivers/ppa
state: present
- name: 6. Install NVIDIA Driver
apt:
name: "nvidia-driver-{{ nvidia_driver_version }}"
state: present
register: driver_install
notify: Reboot node
- name: 7. Add NVIDIA Container Toolkit repository
shell: |
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
- name: 8. Install NVIDIA Container Toolkit
apt:
update_cache: yes
name: nvidia-container-toolkit
state: present
- name: 9. Configure Docker to use NVIDIA runtime and restart
shell: |
nvidia-ctk runtime configure --runtime=docker
systemctl restart docker
- name: 10. Install k3s (Lightweight Kubernetes)
shell: |
curl -sfL https://get.k3s.io | sh -
mkdir -p $HOME/.kube
cp /etc/rancher/k3s/k3s.yaml $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
args:
creates: /usr/local/bin/k3s
handlers:
- name: Reboot node
reboot:
msg: "Rebooting node after NVIDIA driver installation"
connect_timeout: 5
reboot_timeout: 300
pre_reboot_delay: 0
post_reboot_delay: 30
test_command: whoami
How to Run:
Execute on your control machine: ansible-playbook -i /etc/ansible/hosts setup_gpu_node.yml
This Playbook automatically completes the standardized configuration of all nodes, laying a solid foundation for subsequent K8s experiments.
Lab 1 - Basic Environment: Step-by-Step Installation of Ascend Drivers and the CANN Software Stack
This lab guides you through the most basic and critical software stack installation on a server equipped with a Huawei Ascend AI processor.
Prerequisites:
- The server is running a supported operating system (e.g., EulerOS or the specified Ubuntu version).
- You have root or sudo access to the server.
- You have downloaded the
AIA-Ascend-Driver-*.runandAIA-Ascend-Toolkit-*.runfiles matching your hardware model and OS version from the Huawei official website or a mirror source.
Steps:
Step 1: Check hardware and environment
Before installation, confirm that the system recognizes the Ascend device.
lspci | grep -i ascend
You should see output similar to Processing accelerators: Huawei Technologies Co., Ltd. Ascend 910 AI Processor.
Step 2: Install the driver
The driver serves as the bridge between the operating system kernel and the NPU hardware.
# Grant execute permission
chmod +x AIA-Ascend-Driver-*.run
# Execute installation with root privileges
sudo ./AIA-Ascend-Driver-*.run --install
During installation, read the prompts carefully. After installation, a server reboot is typically required to load the new kernel modules.
sudo reboot
Step 3: Install the CANN toolkit
CANN (Compute Architecture for Neural Networks) is Ascend's application enablement software stack, comprising compilers, acceleration libraries, toolchains, and more.
# Grant execute permission
chmod +x AIA-Ascend-Toolkit-*.run
# Execute installation with root privileges
# --install-path specifies the installation path, --install-for-all installs for all users
sudo ./AIA-Ascend-Toolkit-*.run --install --install-path=/usr/local/ascend --install-for-all
Step 4: Configure environment variables
To allow the system to locate CANN commands and libraries, add the relevant paths to your environment variables. The CANN installation package conveniently provides a script for this purpose.
Add the following lines to your ~/.bashrc or the system's /etc/profile:
# Edit .bashrc file
vim ~/.bashrc
# Add the following line at the end of the file (modify the path according to your actual installation path)
source /usr/local/ascend/ascend-toolkit/set_env.sh
# Make the configuration effective immediately
source ~/.bashrc
Step 5: Verify the installation
This is the most critical step -- confirming that our installation was successful.
# Execute the npu-smi command
npu-smi info
If the installation is successful, you will see output similar to the following, listing detailed information about all NPU cards on the server, including model, ID, temperature, power consumption, and HBM usage.
+-------------------------------------------------------------------------------------------+
| npu-smi 21.0.2 Version: 21.0.2 |
+-------------------------------+-----------------+-----------------------------------------+
| NPU Name | Health | Power(W) Temp(C) |
| Chip Device-Chip-Id | Bus-Id | AICore(%) HBM(MB) |
+===============================+=================+=========================================+
| 0 Ascend 910B | OK | 110.0 45 |
| 0 0-0 | 0000:C1:00.0 | 0 0 / 32768 |
+-------------------------------+-----------------+-----------------------------------------+
| 1 Ascend 910B | OK | 108.0 44 |
| 0 1-0 | 0000:C2:00.0 | 0 0 / 32768 |
+-------------------------------+-----------------+-----------------------------------------+
... (other NPU cards)
Seeing this interface, congratulations -- you have built the basic software runtime environment for the Ascend AI processor!
Lab 2 - Scheduling in Practice: Configuring Volcano in K8s and Submitting a Distributed PyTorch Job
This lab walks you through the core content of Chapter 5: using the Volcano scheduler to resolve the distributed training deadlock problem that native K8s cannot handle.
Prerequisites:
- You have a functional K8s cluster with GPU/NPU support already configured on the nodes (i.e., Device Plugin is installed).
- You have the Helm client installed.
Step 1: Install Volcano
Use Helm for one-click installation of Volcano.
helm repo add volcano-sh https://volcano-sh.github.io/charts
helm repo update
helm install volcano volcano-sh/volcano -n volcano-system --create-namespace
Verify installation:
kubectl get pods -n volcano-system
You should see Pods such as volcano-scheduler and volcano-controller in Running state.
Step 2: Prepare the PyTorch distributed training application
We will use a classic PyTorch MNIST distributed training script.
File (mnist_distributed.py):
import torch
import torch.distributed as dist
import torch.nn as nn
import torch.optim as optim
from torch.nn.parallel import DistributedDataParallel as DDP
from torchvision import datasets, transforms
import os
def setup(rank, world_size):
os.environ['MASTER_ADDR'] = os.environ.get('MASTER_ADDR', 'localhost')
os.environ['MASTER_PORT'] = os.environ.get('MASTER_PORT', '12355')
dist.init_process_group("nccl", rank=rank, world_size=world_size)
def cleanup():
dist.destroy_process_group()
class Net(nn.Module):
# ... (a simple CNN model definition)
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 32, 3, 1)
self.conv2 = nn.Conv2d(32, 64, 3, 1)
self.fc1 = nn.Linear(9216, 128)
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = self.conv1(x)
x = torch.relu(x)
x = self.conv2(x)
x = torch.relu(x)
x = torch.max_pool2d(x, 2)
x = torch.flatten(x, 1)
x = self.fc1(x)
x = torch.relu(x)
x = self.fc2(x)
return torch.log_softmax(x, dim=1)
def train(rank, world_size):
setup(rank, world_size)
device = torch.device(f"cuda:{rank % torch.cuda.device_count()}")
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
dataset = datasets.MNIST('../data', train=True, download=True, transform=transform)
train_sampler = torch.utils.data.distributed.DistributedSampler(dataset, num_replicas=world_size, rank=rank)
train_loader = torch.utils.data.DataLoader(dataset, batch_size=64, sampler=train_sampler)
model = Net().to(device)
ddp_model = DDP(model, device_ids=[device])
optimizer = optim.SGD(ddp_model.parameters(), lr=0.01)
for epoch in range(3):
train_sampler.set_epoch(epoch)
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
output = ddp_model(data)
loss = nn.functional.nll_loss(output, target)
loss.backward()
optimizer.step()
if batch_idx % 10 == 0:
print(f"Rank {rank}, Epoch {epoch}, Batch {batch_idx}, Loss: {loss.item()}")
cleanup()
if __name__ == '__main__':
# Volcano injects VC_TASK_INDEX and VC_WORKER_NUM environment variables
rank = int(os.environ.get("VC_TASK_INDEX", "0"))
world_size = int(os.environ.get("VC_WORKER_NUM", "1"))
print(f"Starting training on Rank {rank} of {world_size}...")
train(rank, world_size)
Step 3: Build the Docker image
File (Dockerfile):
FROM pytorch/pytorch:2.1.0-cuda12.1-cudnn8-runtime
WORKDIR /app
COPY mnist_distributed.py .
# Download dataset to avoid downloading at runtime
RUN python -c "from torchvision import datasets; datasets.MNIST('../data', download=True)"
CMD ["python", "mnist_distributed.py"]
Build and push to your image registry:
docker build -t your-registry/pytorch-dist-mnist:v1 .
docker push your-registry/pytorch-dist-mnist:v1
Step 4: Write and submit a VolcanoJob
This is the core step. We define a distributed job requiring 2 Pods (each with 1 GPU).
File (volcano_pytorch_job.yml):
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
name: pytorch-mnist-dist-job
spec:
schedulerName: volcano
minAvailable: 2 # Core: Gang Scheduling, must assemble 2 Pods before starting
queue: default
tasks:
- name: worker
replicas: 2
template:
spec:
containers:
- name: pytorch-worker
image: your-registry/pytorch-dist-mnist:v1
resources:
limits:
nvidia.com/gpu: 1 # Each Pod requests 1 GPU
restartPolicy: OnFailure
Submit the job:
kubectl apply -f volcano_pytorch_job.yml
Step 5: Observe and verify
# View PodGroup status -- the core object of Volcano scheduling
kubectl get podgroup
# View Pod status -- you will see both Pods created and entering Running state almost simultaneously
kubectl get pods -l volcanosh.dev/job-name=pytorch-mnist-dist-job
# View logs of one Pod
kubectl logs pytorch-mnist-dist-job-worker-0
In the logs, you will see training output from different ranks (Rank 0 and Rank 1) interleaved, confirming that distributed training has been successfully established and is running!
Lab 3 - Stress Testing in Practice: Deploying a vLLM Service, Simulating 100 Concurrent Requests, and Generating a Performance Report
This lab guides you through the inference service deployment and stress testing covered in Chapter 8.
Prerequisites:
- One or more machines with NVIDIA GPUs, with drivers and Docker already installed.
- Python environment installed.
Step 1: Deploy the vLLM service
We will use the simplest method -- vLLM's official Docker image -- to deploy a Llama 3 8B Instruct model service.
# Pull the vLLM image
docker pull vllm/vllm-openai:latest
# Start the service
# Note: This requires a good network connection to download the model, which will be cached at ~/.cache/huggingface
docker run --gpus all -d \
-p 8000:8000 \
-v ~/.cache/huggingface:/root/.cache/huggingface \
--name vllm_server \
vllm/vllm-openai:latest \
--model meta-llama/Meta-Llama-3-8B-Instruct
Note: The Llama 3 model requires access authorization from Hugging Face. Ensure you are logged into HF and have accepted its terms of use.
Step 2: Verify the service
Use curl to test whether the service is working correctly.
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "meta-llama/Meta-Llama-3-8B-Instruct",
"messages": [
{"role": "user", "content": "Hello! What is your name?"}
]
}'
If the model responds, the service deployment is successful.
Step 3: Prepare the Locust stress test script
Install Locust: pip install locust
File (locustfile.py): (Referencing the script from Section 8.3, we provide a simplified non-streaming version for quick onboarding)
from locust import task, HttpUser
import random
class LLMUser(HttpUser):
@task
def generate(self):
prompts = ["What is the capital of France?", "Write a short poem about the sea.", "Explain black holes to a 5-year-old."]
payload = {
"model": "meta-llama/Meta-Llama-3-8B-Instruct",
"messages": [{"role": "user", "content": random.choice(prompts)}],
"max_tokens": 100
}
self.client.post("/v1/chat/completions", json=payload, name="/v1/chat/completions")
Step 4: Start the stress test
locust -f locustfile.py --host http://localhost:8000
Step 5: Analyze the performance report
- Open a browser and navigate to
http://localhost:8089. - Enter Total users as
100, Spawn rate as10. - Click "Start swarming."
- Observe the "Charts" tab:
- Total Requests per Second (RPS): The number of requests your service completes per second.
- Response Time (ms): The distribution of response times, focusing on the 95th and 99th percentile values. These represent the experience of the vast majority of users.
- Generate report: In the "Download Data" tab, you can download a detailed CSV report for offline analysis and archiving.
By adjusting the number of concurrent users, you can identify the service's "performance inflection point" -- the concurrency level at which response times begin to degrade sharply. This provides critical data for capacity planning.
Lab 4 - Monitoring and Alerting: Configuring Prometheus Rules to Trigger Alerts When GPU Temperature Exceeds 80 C or Memory Usage Exceeds 95%
This lab guides you through the observability content from Chapter 9, configuring core hardware alerts for your GPU cluster.
Prerequisites:
- A K8s cluster with Prometheus Operator deployed (typically installed via the kube-prometheus-stack Helm chart).
- DCGM-Exporter is deployed on the GPU nodes in the cluster.
Step 1: Understand the PrometheusRule CRD
In the Prometheus Operator ecosystem, alert rules are defined through a Kubernetes custom resource called PrometheusRule. We will create a YAML file to define our rules.
Step 2: Write the alert rule YAML file
File (gpu-alerts.yml):
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: gpu-alerts
labels:
# This label must match the ruleSelector of your Prometheus instance
prometheus: kube-prometheus
role: alert-rules
spec:
groups:
- name: gpu.rules
rules:
- alert: GPUTemperatureHigh
expr: DCGM_FI_DEV_GPU_TEMP > 80
for: 5m
labels:
severity: warning
annotations:
summary: "GPU high temperature on {{ $labels.nodename }}"
description: "GPU {{ $labels.gpu }} on node {{ $labels.nodename }} has been over 80 C for 5 minutes. Current value is {{ $value }} C."
- alert: GPUMemoryHigh
expr: (DCGM_FI_DEV_FB_USED / DCGM_FI_DEV_FB_TOTAL) * 100 > 95
for: 10m
labels:
severity: critical
annotations:
summary: "GPU high memory usage on {{ $labels.nodename }}"
description: "GPU {{ $labels.gpu }} on node {{ $labels.nodename }} memory usage has been over 95% for 10 minutes. Current usage is {{ $value | printf `%.2f` }}%."
- alert: GPUXidErrorDetected
expr: rate(DCGM_FI_DEV_XID_ERRORS[5m]) > 0
for: 1m
labels:
severity: critical
annotations:
summary: "GPU XID Error Detected on {{ $labels.nodename }}"
description: "GPU {{ $labels.gpu }} on node {{ $labels.nodename }} is reporting XID errors. This may indicate a software or hardware issue. Please investigate dmesg logs."
Annotations:
expr: The PromQL query expression, defining the trigger condition for the alert.for: The duration the condition must hold true, preventing false positives from transient fluctuations.labels.severity: Defines the alert severity level, enabling differentiated routing in Alertmanager.annotations: Defines the detailed alert information.{{ $labels... }}and{{ $value }}are template variables that will be replaced with actual values in the alert notification.
Step 3: Apply the rules and verify
# Apply the rules to your K8s cluster (typically in the monitoring namespace)
kubectl apply -f gpu-alerts.yml -n monitoring
After a few minutes, Prometheus will load these new rules.
- Open the Prometheus UI (via
kubectl port-forward). - Navigate to the "Alerts" page. You should see the three newly added rules --
GPUTemperatureHigh,GPUMemoryHigh,GPUXidErrorDetected-- inInactivestate.
Step 4: Simulate triggering alerts (optional but recommended)
To verify that the alert path is functional, we need to artificially trigger the conditions.
- Trigger temperature alert: On a GPU node, run a high-intensity GPU stress testing tool such as
gpu-burn.
# Run on a GPU node
docker run --rm --gpus all -it wshuyi/gpu-burn -t 600 # Run for 10 minutes
Simultaneously, observe nvidia-smi in another terminal. When the temperature exceeds 80 C and persists for 5 minutes, the alert state in Prometheus will change to Pending, then Firing.
- Trigger memory alert: Write a simple PyTorch script that allocates a large tensor.
Step 5: View the alert
When the alert enters Firing state, if you have configured Alertmanager, you will receive a formatted alert message in your configured notification channel (e.g., Slack, DingTalk), containing the details you defined in annotations.
At this point, you have successfully installed the most basic "automatic alarm system" for your AI infrastructure!
Appendix B: Efficiency Toolbox
In the grand engineering endeavor of AI infrastructure, we need not only systematic knowledge and deep insight, but also a set of "sharp tools" that can rapidly translate this wisdom into action. Just as excellent programmers do not reinvent the wheel, experienced AI Infra engineers should be adept at automating and tooling repetitive work.
This appendix provides you with an "Efficiency Toolbox" containing two carefully crafted tools. The first is the "Intelligent Computing Center Compute Resource Planning Calculator," which encapsulates the complex mathematical formulas from Chapter 7 into an easy-to-use Excel spreadsheet, allowing you to complete a cluster planning estimation worth hundreds of millions of yuan in seconds. The second is a Python operations script library, offering a series of plug-and-play scripts to help you perform daily tasks such as one-click cluster health inspections and quick compute demand calculations.
These tools are your accelerators for transforming from a "theorist" into a "practitioner." Keep them in your arsenal, continuously refine and expand them in your daily work, and make them the sharpest and most capable part of your personal knowledge system.
The "Intelligent Computing Center Compute Resource Planning Calculator.xlsx"
This Excel calculator transforms the memory usage and training time estimation models from Chapter 7 into an interactive, visual planning tool. Simply fill in the model's key parameters and your business objectives in the "Input" area, and it will automatically calculate the required resource scale and related performance metrics in the "Output" area.
Calculator Structure Design
We designed this Excel file to contain two main worksheets: Training_Estimator (Training Resource Estimator) and Inference_Memory_Estimator (Inference Memory Estimator).
Sheet 1: Training_Estimator
This worksheet is the core of the calculator, used for resource planning of pre-training or full fine-tuning.
[Input Area] - Yellow background cells
A. Model Parameters
| Parameter Name | Symbol | Example Value | Unit | Notes |
|---|---|---|---|---|
| Model Parameters | P | 70 | B (Billions) | e.g., for Llama 2 70B, enter 70 |
| Number of Layers | L | 80 | ||
| Hidden Dimension | h | 8192 | ||
| Number of Attention Heads | a | 64 | ||
| Sequence Length | s | 4096 | Tokens |
B. Data & Goals
| Parameter Name | Symbol | Example Value | Unit | Notes |
|---|---|---|---|---|
| Training Data Size | D | 2 | T (Trillions) | Tokens |
| Target Training Days | Days | 90 | Days |
C. Hardware & Parallelism
| Parameter Name | Symbol | Example Value | Unit | Notes |
|---|---|---|---|---|
| GPU Model | - | A100-80G | (Dropdown menu selection) | |
| Single Card Peak Compute | Peak | 312 | TFLOPS (FP16) | (Auto-filled based on GPU model) |
| Single Card Memory Capacity | Mem_GPU | 80 | GB | (Auto-filled based on GPU model) |
| Data Parallel Size | DP | 64 | ||
| Tensor Parallel Size | TP | 8 | ||
| Pipeline Parallel Size | PP | 8 | ||
| Global Batch Size | GBS | 1024 | ||
| MFU (Model FLOPs Utilization) | MFU | 40% | % | The most critical empirical value |
[Output Area] - Green background cells
A. Training Time & Compute Requirements
| Metric Name | Formula (Excel Expression) | Result | Unit |
|---|---|---|---|
| Total Compute (FLOPs) | =6 * P * 10^9 * D * 10^12 | 8.40E+23 | FLOPs |
| Required Total Effective Compute | =A2 / (Days * 24 * 3600) | 1.08E+17 | FLOPS |
=B2 / 10^12 | 107,527 | TFLOPS (Effective) | |
| Required Total GPUs | =B3 / (Peak * MFU) | 862 | Cards |
| Recommended Cluster Size | =ROUNDUP(B4, -2) | 900 | Cards |
| Actual Estimated Training Days | =(A2 / (B5 * Peak * MFU * 10^12)) / (24*3600) | 86.4 | Days |
B. Memory Analysis - Based on ZeRO-1 + TP + PP
| Metric Name | Formula (Excel Expression) | Result | Unit |
|---|---|---|---|
| Model Parameters (per GPU) | =2 * P / TP | 17.5 | GB |
| Optimizer States (per GPU) | =12 * P / (DP * TP) | 1.64 | GB |
| Gradient Footprint (per GPU) | =4 * P / (DP * TP) | 0.55 | GB |
| Activation Footprint per GPU (simplified estimate; actual usage depends strongly on activation recomputation and related strategies) | =(34 * s * (GBS/DP) * h * L) / (TP * 10^9) | 19.3 | GB |
| Estimated Peak Memory (per GPU) | =SUM(B8:B11) | 39.0 | GB |
| Memory Sufficient? | =IF(B12 <= Mem_GPU, "Yes", "No! Exceeded!") | Yes |
C. Network Bandwidth Requirement
| Metric Name | Formula (Excel Expression) | Result | Unit |
|---|---|---|---|
| All-Reduce Communication Volume (DP; simplified per-iteration estimate) | = (2 * P * 10^9 * 2) / (TP * (DP-1)/DP) | 8.75 | GB |
| All-Gather/Reduce-Scatter (TP) | = (2 * P * 10^9 * 2 * (TP-1)/TP) / (TP * PP) | 0.05 | GB |
| P2P Bandwidth (PP) | =(s * (GBS/DP) * h * 2 * 2) / (TP * PP) | 0.01 | GB |
| Aggregated Average Bandwidth per GPU (total communication volume per iteration divided by estimated iteration time) | = (B14+B15+B16) * 8 / 10^9 * (1/ (A2/(B5*Peak*MFU*10^12)) ) | ~21 | Gbps |
These network results are for first-pass capacity planning, not link acceptance. Actual requirements vary materially with communication-compute overlap, topology, congestion, protocol overhead, and the collective-communication implementation.
Instructions:
- First, fill in your model, data, and target parameters in the [Input Area].
- Adjust the
DP,TP,PPparameters in [Hardware & Parallelism]. - Observe the "Required Total GPUs" and "Memory Sufficient?" in the [Output Area].
- Your goal is: under the condition that "Memory is Sufficient," find a combination of
DP, TP, PPwhere the "Recommended Cluster Size" is within your budget and the "Actual Estimated Training Days" meets your timeline. - Continuously adjust
DP, TP, PPandMFU(if you are confident in your cluster optimization, you can increase MFU), performing "What-If" analysis to find the optimal resource configuration.
Python Operations Script Library
This script library provides a series of ready-to-use operations tools to help you automate daily inspection and calculation tasks.
check_cluster_health.py: One-Click Cluster Health Inspection
This script uses the Kubernetes Python client to discover all nodes, then SSH into each node to execute nvidia-smi or npu-smi, parse the output, and generate a concise health report.
Prerequisites:
- Install Python libraries:
pip install kubernetes paramiko pandas - Your machine has
~/.kube/configconfigured to access the target K8s cluster. - Your machine can SSH passwordlessly into all nodes in the cluster.
Script (check_cluster_health.py):
import argparse
import paramiko
import pandas as pd
from kubernetes import client, config
from datetime import datetime
def ssh_run_command(hostname, command):
"""Execute command on a remote node via SSH and return output."""
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname, username='root', timeout=5) # Modify username as needed
stdin, stdout, stderr = ssh.exec_command(command)
output = stdout.read().decode('utf-8')
error = stderr.read().decode('utf-8')
ssh.close()
if error and "command not found" not in error:
return f"ERROR: {error}"
return output
except Exception as e:
return f"SSH_ERROR: {str(e)}"
def parse_nvidia_smi(output):
"""Parse nvidia-smi output and extract key health metrics."""
if "NVIDIA-SMI has failed" in output or "ERROR" in output:
return [{"gpu_id": "ALL", "health": "FAIL", "message": output}]
devices = []
lines = output.split('\n')
# Very simplified parsing; in production, use nvidia-smi --query-gpu=... --format=csv
for i, line in enumerate(lines):
if "MiB" in line and "%" in line:
parts = line.split()
gpu_id = parts[1]
temp = parts[3]
power = parts[5]
mem_used = parts[9]
mem_total = parts[11]
gpu_util = parts[13]
health = "OK"
message = []
if int(temp.replace('C','')) > 85:
health = "WARN"
message.append(f"Temp>85C({temp})")
if int(power.replace('W','')) > 350: # Assuming power threshold of 350W
health = "WARN"
message.append(f"Power>350W({power})")
devices.append({
"gpu_id": gpu_id,
"health": health if message else "OK",
"message": ", ".join(message) if message else "N/A"
})
return devices
def get_k8s_nodes(label_selector=""):
"""Get the list of nodes from the K8s cluster matching the label selector."""
config.load_kube_config()
v1 = client.CoreV1Api()
nodes = v1.list_node(label_selector=label_selector)
return [node.status.addresses[0].address for node in nodes.items]
def main():
parser = argparse.ArgumentParser(description="Cluster Health Checker")
parser.add_argument("--vendor", type=str, default="nvidia", choices=["nvidia", "ascend"], help="GPU/NPU vendor")
parser.add_argument("--nodes", type=str, help="Comma-separated list of node IPs. Overrides k8s discovery.")
parser.add_argument("--label", type=str, default="nvidia.com/gpu=true", help="K8s node label selector for discovery.")
args = parser.parse_args()
if args.nodes:
nodes_to_check = args.nodes.split(',')
else:
print(f"Discovering nodes with label '{args.label}' from Kubernetes...")
nodes_to_check = get_k8s_nodes(args.label)
print(f"Found {len(nodes_to_check)} nodes: {nodes_to_check}")
if args.vendor == "nvidia":
command = "nvidia-smi"
parser_func = parse_nvidia_smi
elif args.vendor == "ascend":
command = "npu-smi info"
# You would need to write a similar parsing function for npu-smi
# parser_func = parse_npu_smi
print("Ascend NPU parser not implemented in this example.")
return
results = []
for node in nodes_to_check:
print(f"Checking node: {node} ...")
output = ssh_run_command(node, command)
health_info = parser_func(output)
for device in health_info:
results.append({
"node": node,
"device_type": args.vendor.upper(),
"device_id": device["gpu_id"],
"health": device["health"],
"message": device["message"],
})
report_df = pd.DataFrame(results)
print("\n" + "="*50)
print(f" Cluster Health Report - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("="*50)
print(report_df.to_string())
# Print problem summary
failed_nodes = report_df[report_df['health'] != 'OK']
if not failed_nodes.empty:
print("\n" + "!"*20 + " PROBLEM SUMMARY " + "!"*20)
print(failed_nodes.to_string())
print("!"*59)
else:
print("\n" + "="*10 + " All checks passed! Cluster is healthy. " + "="*10)
if __name__ == "__main__":
main()
How to Use:
- Inspect all K8s nodes with the
nvidia.com/gpu=truelabel:python check_cluster_health.py - Specify nodes for inspection:
python check_cluster_health.py --nodes 192.168.1.101,192.168.1.102
This script outputs a clear table indicating whether each card on each node is healthy, and if not, the likely reason (e.g., high temperature). This is very useful for daily inspections and preliminary fault diagnosis.
calc_model_flops.py: Quickly Calculate Theoretical Model FLOPs
This script encapsulates the 6PD formula from Chapter 7 into a simple command-line tool, helping you quickly estimate the total compute required to train a model and the time required on a specific cluster.
Script (calc_model_flops.py):
import argparse
def sizeof_fmt(num, suffix=""):
for unit in ["", "K", "M", "G", "T", "P", "E", "Z"]:
if abs(num) < 1000.0:
return f"{num:3.1f}{unit}{suffix}"
num /= 1000.0
return f"{num:.1f}Y{suffix}"
def main():
parser = argparse.ArgumentParser(description="Estimate LLM Training FLOPs and Time")
# Model and Data parameters
parser.add_argument("-p", "--params", type=float, required=True, help="Model parameters in billions (e.g., 70 for 70B)")
parser.add_argument("-d", "--data_tokens", type=float, required=True, help="Training data size in trillions of tokens (e.g., 2 for 2T)")
# Hardware and Performance parameters
parser.add_argument("-n", "--num_gpus", type=int, required=True, help="Number of GPUs in the cluster")
parser.add_argument("--peak_tflops", type=float, required=True, help="Peak TFLOPS of a single GPU at target precision (e.g., 312 for A100 FP16)")
parser.add_argument("--mfu", type=float, default=0.4, help="Model FLOPs Utilization (MFU), a value between 0 and 1 (default: 0.4)")
args = parser.parse_args()
# --- Calculations ---
# 1. Total FLOPs
total_flops = 6 * (args.params * 1e9) * (args.data_tokens * 1e12)
# 2. Cluster effective throughput
single_gpu_effective_tflops = args.peak_tflops * args.mfu
cluster_effective_tflops = single_gpu_effective_tflops * args.num_gpus
# 3. Estimated training time
if cluster_effective_tflops == 0:
estimated_seconds = float('inf')
else:
estimated_seconds = total_flops / (cluster_effective_tflops * 1e12)
estimated_days = estimated_seconds / (24 * 3600)
# --- Print Report ---
print("\n" + "="*50)
print(" LLM Training Estimation Report")
print("="*50)
print("\n[Input Parameters]")
print(f" - Model Size: {args.params}B parameters")
print(f" - Dataset Size: {args.data_tokens}T tokens")
print(f" - Cluster Size: {args.num_gpus} GPUs")
print(f" - Single GPU Peak Performance: {args.peak_tflops} TFLOPS")
print(f" - Assumed MFU: {args.mfu:.2%}")
print("\n[Estimated Requirements]")
print(f" - Total Training FLOPs: {sizeof_fmt(total_flops, 'FLOPs')}")
print(f" - Cluster Effective Throughput: {cluster_effective_tflops:,.2f} TFLOPS")
print("\n[Final Estimation]")
print(f" - Estimated Training Time: {estimated_days:.2f} days")
print("="*50)
print("\nNote: This is a theoretical estimation. Actual time may vary based on network, storage, and software stack efficiency.")
if __name__ == "__main__":
main()
How to Use:
Suppose you want to estimate the time required to train a 70B model with 2T tokens on a cluster of 1024 A100s (FP16 peak 312 TFLOPS), assuming an MFU of 40%:
python calc_model_flops.py \
--params 70 \
--data_tokens 2 \
--num_gpus 1024 \
--peak_tflops 312 \
--mfu 0.4
Output:
==================================================
LLM Training Estimation Report
==================================================
[Input Parameters]
- Model Size: 70.0B parameters
- Dataset Size: 2.0T tokens
- Cluster Size: 1024 GPUs
- Single GPU Peak Performance: 312.0 TFLOPS
- Assumed MFU: 40.00%
[Estimated Requirements]
- Total Training FLOPs: 840.0EFLOPs
- Cluster Effective Throughput: 127,795.20 TFLOPS
[Final Estimation]
- Estimated Training Time: 76.08 days
==================================================
Note: This is a theoretical estimation. Actual time may vary based on network, storage, and software stack efficiency.
This script provides a fast, convenient way to verify the plans you developed in the Excel calculator, or to quickly produce order-of-magnitude estimates for compute needs in daily discussions.
Closing Words
This Efficiency Toolbox is your catalyst for transforming theoretical knowledge into productive power. These tools are not perfect, but they provide a solid starting point. The real value lies in how you continuously refine, extend, and customize them based on your team's specific needs. Let them grow with you, becoming the indispensable "right-hand tools" of a top-tier AI Infra engineer.