このコンテンツは選択した言語では利用できません。
Chapter 6. Running Kubeflow Trainer v2-based distributed training workloads
You can run distributed training workloads on Red Hat OpenShift AI by using Kubeflow Trainer v2. Kubeflow Trainer v2 replaces the framework-specific custom resource definitions (CRDs) from Training Operator v1, such as PyTorchJob, with a unified TrainJob API and pre-built ClusterTrainingRuntime infrastructure templates.
6.1. Understanding and using training runtimes リンクのコピーリンクがクリップボードにコピーされました!
Kubeflow Trainer v2 uses training runtimes to define the distributed training infrastructure for your training jobs. Runtimes encapsulate best practices for distributed training, including PyTorch distributed configuration, torchrun setup, environment variables, and container image defaults.
This section describes how to view the pre-built ClusterTrainingRuntime resources provided by Red Hat OpenShift AI, and how to create custom namespace-scoped TrainingRuntime resources when you need project-specific configuration.
6.1.1. Understanding ClusterTrainingRuntimes リンクのコピーリンクがクリップボードにコピーされました!
ClusterTrainingRuntimes are cluster-scoped infrastructure templates that define the distributed training environment for your training jobs. They are created by the platform administrator and are available to all projects in the cluster. They replace the per-job infrastructure configuration that was required in Training Operator v1 (PyTorchJob), where you had to specify the full pod specification, environment variables, and distributed training setup for every job.
With Kubeflow Trainer v2, your TrainJob resource references a ClusterTrainingRuntime through the runtimeRef field. The runtime handles the complexity of configuring torchrun, environment variables(MASTER_ADDR, MASTER_PORT), node coordination, and container image defaults, so you can focus on your training code and resource requirements.
Red Hat OpenShift AI provides the following pre-built ClusterTrainingRuntimes:
| Runtime | Description |
|---|---|
|
| General-purpose PyTorch distributed training with CUDA support |
|
| PyTorch distributed training for AMD ROCm GPUs |
|
| PyTorch 2.9 with CUDA 12.8, Python 3.12 |
|
| Training Hub runtime with built-in fine-tuning algorithms (OSFT, SFT) |
|
| Training Hub runtime with CUDA 12.8, PyTorch 2.9, Python 3.12 |
6.1.1.1. Viewing available runtimes リンクのコピーリンクがクリップボードにコピーされました!
Prerequisites
-
You have installed the OpenShift CLI (
oc). - You have access to an OpenShift cluster with Red Hat OpenShift AI installed.
Procedure
To list the available ClusterTrainingRuntimes in your cluster, run the following command:
oc get clustertrainingruntime
Example output:
NAME AGE
torch-distributed 5m
torch-distributed-rocm 5m
torch-distributed-th03-cuda128-torch28-py312 5m
training-hub 5m
training-hub03-cuda128-torch28-py312 5m
To view the details of a specific runtime, run the following command:
oc get clustertrainingruntime torch-distributed -o yaml
6.1.2. ClusterTrainingRuntime structure リンクのコピーリンクがクリップボードにコピーされました!
The following example shows the structure of the torch-distributed ClusterTrainingRuntime. This runtime is pre-installed in Red Hat OpenShift AI and handles PyTorch distributed training configuration, including torchrun setup, environment variables, and node coordination:
apiVersion: trainer.kubeflow.org/v1alpha1
kind: ClusterTrainingRuntime
metadata:
name: torch-distributed
spec:
mlPolicy:
torch:
numProcPerNode: auto
template:
spec:
replicatedJobs:
- name: Node
template:
spec:
template:
spec:
containers:
- name: trainer
env:
- name: MASTER_ADDR
value: "$(JOB_NAME)-node-0-0.$(JOB_NAME)"
- name: MASTER_PORT
value: "29500"
command:
- torchrun
You do not need to create the torch-distributed ClusterTrainingRuntime. It is provided out of the box when the platform administrator enables the Kubeflow Trainer component in the DataScienceCluster. Only the platform administrator creates or modifies ClusterTrainingRuntimes.
6.1.3. How runtimeRef connects a TrainJob to a runtime リンクのコピーリンクがクリップボードにコピーされました!
In your TrainJob resource, you reference a runtime using the runtimeRef field. This field specifies the name and kind of the runtime to use:
spec:
runtimeRef:
name: torch-distributed
kind: ClusterTrainingRuntime
where:
kind-
ClusterTrainingRuntimeA cluster-scoped runtime available to all projects. These are the pre-built runtimes provided by Red Hat OpenShift AI. -
TrainingRuntimeA namespace-scoped runtime that you create in your own project. See Creating a custom TrainingRuntime resource below for details.
-
6.1.4. Creating a custom TrainingRuntime resource リンクのコピーリンクがクリップボードにコピーされました!
A project administrator can create a namespace-scoped TrainingRuntime resource when they need a custom training environment that differs from the pre-built ClusterTrainingRuntime resources provided by the platform.
A TrainingRuntime is useful when you need to:
- Use a custom container image with additional libraries or dependencies pre-installed.
- Set custom environment variables for all training pods.
- Define default resource requests and limits specific to your project.
- Configure custom volume mounts or init containers.
For most use cases, the pre-built ClusterTrainingRuntime resources are sufficient. Create a custom TrainingRuntime only when you need project-specific configuration that cannot be overridden in the TrainJob resource.
Prerequisites
- Your platform administrator has installed Red Hat OpenShift AI with the required distributed training components as described in Installing the distributed workloads components (for disconnected environments, see Installing the distributed workloads components). *You can access the OpenShift Console for the cluster where OpenShift AI is installed.
You have project administrator access for the project where you want to create the TrainingRuntime.
- If you created the project, you automatically have administrator access.
- If you did not create the project, the platform administrator must give you project administrator access.
Procedure
- Log in to the OpenShift Console.
Create a
TrainingRuntimeresource, as follows:- In the Administrator perspective, click Home > Search.
- From the Project list, select your project.
-
Click the Resources list, and in the search field, type
TrainingRuntime. - Select TrainingRuntime, and click Create TrainingRuntime. The Create TrainingRuntime page opens, with default YAML code automatically added.
Replace the default YAML code with your custom runtime definition. The following example shows a custom
TrainingRuntimewith a custom container image and default resource configuration:apiVersion: trainer.kubeflow.org/v1alpha1 kind: TrainingRuntime metadata: name: custom-torch-runtime namespace: my-project spec: mlPolicy: torch: numProcPerNode: auto template: spec: replicatedJobs: - name: Node template: spec: template: spec: containers: - name: trainer image: registry.redhat.io/rhoai/odh-training-cuda128-torch28-py312-rhel9:v3.0 env: - name: MASTER_ADDR value: "$(JOB_NAME)-node-0-0.$(JOB_NAME)" - name: MASTER_PORT value: "29500" - name: MY_CUSTOM_ENV_VAR value: "my-custom-value" command: - torchrun resources: requests: cpu: "4" memory: "16Gi" limits: cpu: "4" memory: "16Gi"- Click Create.
Verification
Using the user interface:
- In the OpenShift Console, in the Administrator perspective, click Home > Search.
- From the Project list, select your project.
- Click the Resources list and search for TrainingRuntime.
- Verify that your custom runtime appears in the list.
- Using the CLI:
oc get trainingruntime -n <your-namespace>
6.2. Using Kubeflow Trainer v2 to run distributed training workloads リンクのコピーリンクがクリップボードにコピーされました!
You can use Kubeflow Trainer v2 to run distributed PyTorch training workloads on Red Hat OpenShift AI. This section describes how to create a TrainJob resource by using the OpenShift Console or the OpenShift CLI (oc).
A TrainJob resource references a ClusterTrainingRuntime (or custom TrainingRuntime) that provides the distributed training infrastructure, so you only need to specify your training code, the number of nodes, and resource requirements.
6.2.1. Creating a Kubeflow Trainer TrainJob resource リンクのコピーリンクがクリップボードにコピーされました!
You can create a TrainJob resource to run a distributed PyTorch training job by using the OpenShift Console.
Prerequisites
- You can access an OpenShift cluster that has multiple worker nodes with supported NVIDIA GPUs or AMD GPUs.
Your cluster administrator has configured the cluster as follows:
- Installed Red Hat OpenShift AI with the required distributed training components.
- Configured the distributed training resources.
- Installed the JobSet Operator from OLM.
-
A ClusterTrainingRuntime is available in your cluster (for example, torch-distributed). To verify, run
oc get clustertrainingruntime.
You have administrator access for the project.
- If you created the project, you automatically have administrator access.
- If you did not create the project, your cluster administrator must give you administrator access.
Procedure
- Log in to the OpenShift Console.
Create a TrainJob resource, as follows:
-
In the Administrator perspective, click Home
Search. - From the Project list, select your project.
- Click the Resources list, and in the search field, type Job.
-
In the Administrator perspective, click Home
- Select TrainJob, and click Create TrainJob. The Create TrainJob page opens, with default YAML code automatically added.
Update the metadata to replace the name and namespace values with the values for your environment, as shown in the following example:
metadata: name: pytorch-multi-node-job namespace: test-namespaceConfigure the runtime reference to specify which ClusterTrainingRuntime to use, as shown in the following example:
spec: runtimeRef: name: torch-distributed kind: ClusterTrainingRuntimeConfigure the trainer section with your ClusterTrainingRuntime name, command, and the number of distributed training nodes, as shown in the following example:
spec: runtimeRef: name: torch-distributed kind: ClusterTrainingRuntime trainer: command: ["python", "/workspace/scripts/train.py"] numNodes: 3where:
numNodes-
Specifies the total number of distributed training nodes. This replaces the separate Master and Worker replica specifications used in Training Operator v1. For example, a v1 job with 1 Master and 2 Workers is equivalent to
numNodes: 3in v2.
To use a ConfigMap resource to provide the training script for the TrainJob pods, add the ConfigMap volume mount information, as shown in the following example:
spec: runtimeRef: name: torch-distributed kind: ClusterTrainingRuntime trainer: command: ["python", "/workspace/scripts/train.py"] numNodes: 3 podTemplateOverrides: - targetJobs: - name: node spec: volumes: - name: training-script-volume configMap: name: training-script-configmap containers: - name: node volumeMounts: - name: training-script-volume mountPath: /workspace/scriptsAdd the appropriate resource constraints for your environment, as shown in the following example:
spec: runtimeRef: name: torch-distributed kind: ClusterTrainingRuntime trainer: command: ["python", "/workspace/scripts/train.py"] numNodes: 3 resourcesPerNode: requests: cpu: "4" memory: "8Gi" nvidia.com/gpu: 2 limits: cpu: "4" memory: "8Gi" nvidia.com/gpu: 2 podTemplateOverrides: - targetJobs: - name: node spec: volumes: - name: training-script-volume configMap: name: training-script-configmap containers: - name: node volumeMounts: - name: training-script-volume mountPath: /workspace/scriptswhere:
resourcesPerNode- applies the same resource requests and limits to every training node. This replaces the per-replica resource configuration used in Training Operator v1, where you had to specify resources separately for the Master and each Worker.
- Click Create.
Verification
- In the OpenShift Console, open the Administrator perspective.
From the Project list, select your project.
- Click Home > Search > TrainJob and verify that the job was created.
- Click Workloads > Pods and verify that the requested training node pods are running.
- (Optional) If you enabled progress tracking, navigate to the OpenShift AI dashboard, click Model training, and verify that real-time progress metrics are displayed.
6.2.2. Creating a Kubeflow Trainer TrainJob resource by using the CLI リンクのコピーリンクがクリップボードにコピーされました!
You can use the OpenShift CLI (oc) to create a TrainJob resource to run a distributed PyTorch training job.
Prerequisites
- You can access an OpenShift cluster that has multiple worker nodes with supported NVIDIA GPUs or AMD GPUs.
Your cluster administrator has configured the cluster as follows:
- Installed Red Hat OpenShift AI with the required distributed training components, as described in Installing the distributed workloads components.
- Configured the distributed training resources, as described in Managing distributed workloads.
- Installed the JobSet Operator from OLM, as described in Installing the JobSet Operator.
A ClusterTrainingRuntime is available in your cluster (for example,
torch-distributed). To verify, run:oc get clustertrainingruntimeYou have administrator access for the project.
- If you created the project, you automatically have administrator access.
- If you did not create the project, your cluster administrator must give you administrator access.
You have installed the OpenShift CLI (
oc) as described in the appropriate documentation for your cluster:- Installing the OpenShift CLI for OpenShift Container Platform
- Installing the OpenShift CLI for Red Hat OpenShift Service on AWS
Procedure
Log in to the OpenShift CLI (
oc):oc login --token=<token> --server=<server>Create a file named
train.pyand populate it with your training script, as follows:cat <<EOF > train.py <paste your content here> EOFCreate a ConfigMap resource to store the training script, as follows:
oc create configmap training-script-configmap --from-file=train.py -n <your-namespace>Replace <your-namespace> with the name of your project.
Create a file named trainjob.yaml to define the distributed training job setup, as follows:
cat <<'EOF' > trainjob.yaml apiVersion: trainer.kubeflow.org/v1alpha1 kind: TrainJob metadata: name: pytorch-multi-node-job namespace: <your-namespace> spec: runtimeRef: name: torch-distributed kind: ClusterTrainingRuntime trainer: command: ["python", "/workspace/scripts/train.py"] numNodes: 3 resourcesPerNode: requests: cpu: "4" memory: "8Gi" nvidia.com/gpu: 2 limits: cpu: "4" memory: "8Gi" nvidia.com/gpu: 2 podTemplateOverrides: - targetJobs: - name: node spec: volumes: - name: training-script-volume configMap: name: training-script-configmap containers: - name: node volumeMounts: - name: training-script-volume mountPath: /workspace/scripts EOFReplace
<your-namespace>with the name of your project. Update the numNodes, resource constraints, and image as needed for your environment.Create the distributed training job, as follows:
oc apply -f trainjob.yamlMonitor the running distributed training job, as follows:
oc get trainjob -n <your-namespace>Replace
<your-namespace>with the name of your project.Check the pod status, as follows:
oc logs <pod-name> -n <your-namespace>-
Replace
<pod-name>with the name of the pod and<your-namespace>with the name of your project.
6.2.3. Suspending a training job リンクのコピーリンクがクリップボードにコピーされました!
You can suspend a running TrainJob to pause training and free up cluster resources. If JIT checkpointing is configured, the training state is automatically saved before the pods are terminated.
Prerequisites
-
You have an active
TrainJobcurrently running on the OpenShift cluster. - You have configured JIT (Just-In-Time) checkpointing in your training script.
- You have confirmed that your training script is configured to handle the SIGTERM signal.
-
You have the OpenShift CLI (
oc) installed and are logged in with a user that has patch permissions for theTrainJobresource in the target namespace.
Procedure
Run the following command:
oc patch trainjob pytorch-multi-node-job -n <your-namespace> --type=merge -p {"spec":{"suspend":true}}
6.2.4. Resuming a training job リンクのコピーリンクがクリップボードにコピーされました!
Prerequisites
-
You have a TrainJob that is currently in a suspended state (
spec.suspend: true). - You have a Persistent Volume Claim (PVC) or S3-compatible storage containing the latest saved checkpoint files from the previous session.
- Your training script is configured to automatically detect and load the most recent checkpoint from the designated storage path upon startup.
- The cluster has sufficient available resources to fulfill the original resource requests of the job.
Procedure
Run the following command:
oc patch trainjob pytorch-multi-node-job -n <your-namespace> --type=merge -p {"spec":{"suspend":false}}
When resumed, the job automatically loads the latest checkpoint and continues training from where it stopped.
For more information about JIT checkpointing and suspend/resume, see Using RHAI trainers for progress tracking and checkpointing.
6.2.5. Deleting a training job リンクのコピーリンクがクリップボードにコピーされました!
Prerequisites
-
You have identified the name of the
TrainJoband the namespace where it is deployed. -
You have the OpenShift CLI (
oc) installed and are logged in with a user that has delete permissions for the TrainJob resource.
Procedure
Run the following command:
oc delete trainjob/pytorch-multi-node-job -n <your-namespace>
where
<your-namespace>- is the name of your project.
6.3. Using the Kubeflow SDK to run distributed training workloads リンクのコピーリンクがクリップボードにコピーされました!
You can use the Kubeflow Python SDK to create and manage TrainJob resources programmatically from an OpenShift AI workbench. The SDK provides a higher-level interface that handles the creation of the TrainJob resource, configures the distributed training environment, and sets up communication between nodes.
When you use the SDK with Red Hat OpenShift AI trainers (TransformersTrainer or TrainingHubTrainer), progress tracking and JIT checkpointing are enabled by default.
6.3.1. Creating a Kubeflow Trainer TrainJob resource by using the SDK リンクのコピーリンクがクリップボードにコピーされました!
You can create a TrainJob resource programmatically by using the Kubeflow SDK from an OpenShift AI workbench.
Prerequisites
- You can access an OpenShift cluster that has multiple worker nodes with supported NVIDIA GPUs or AMD GPUs.
Your cluster administrator has configured the cluster as follows:
- Installed Red Hat OpenShift AI with the required distributed training components, as described in Installing the distributed workloads components (for disconnected environments, see Installing the distributed workloads components).
- Configured the distributed training resources, as described in Managing distributed workloads.
- Installed the JobSet Operator from OLM, as described in Installing the JobSet Operator.
- Configured RBAC permissions for SDK access to ClusterTrainingRuntime resources, as described in Configuring User Permissions for SDK Access in the Installation Guide.
-
A ClusterTrainingRuntime is available in your cluster (for example,
torch-distributed). To verify, runoc get clustertrainingruntime. - You can access an OpenShift AI workbench with Python 3.9 or later.
You have installed the Kubeflow SDK:
pip install kubeflow --index-url https://console.redhat.com/api/pypi/public-rhai/rhoai/3.2/cuda12.9-ubi9/simple/Verify the installation:
pip show kubeflowExample output:
Name: kubeflow Version: 0.2.1+rhai0
Procedure
Obtain the API server URL and authentication token from your OpenShift cluster, as follows:
# Get the API server URL oc whoami --show-server # Get your authentication token oc whoami --show-tokenNoteIf your cluster uses a self-signed certificate, you must set configuration.verify_ssl = False in your code to avoid SSL verification errors.
In your workbench, create a Python script or notebook cell and define your training function, configure authentication, and submit the training job, as follows:
from kubernetes import client from kubeflow.trainer import TrainerClient from kubeflow.trainer.rhai import TransformersTrainer from kubeflow.common.types import KubernetesBackendConfig # Define your training function def train_func(): from transformers import ( AutoModelForSequenceClassification, AutoTokenizer, Trainer, TrainingArguments, ) from datasets import load_dataset # Load model and tokenizer model = AutoModelForSequenceClassification.from_pretrained( "bert-base-uncased", num_labels=2 ) tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased") # Load and tokenize dataset dataset = load_dataset("imdb", split="train[:1000]") def tokenize_function(examples): return tokenizer( examples["text"], padding="max_length", truncation=True, max_length=512 ) tokenized_dataset = dataset.map(tokenize_function, batched=True) # Configure training training_args = TrainingArguments( output_dir="/tmp/output", num_train_epochs=3, per_device_train_batch_size=8, ) # Train trainer = Trainer( model=model, args=training_args, train_dataset=tokenized_dataset ) trainer.train() # Configure authentication for the workbench api_server = "<your-api-server-url>" # e.g., "https://api.cluster.example.com:6443" token = "<your-bearer-token>" configuration = client.Configuration() configuration.host = api_server configuration.api_key = {"authorization": f"Bearer {token}"} # Uncomment the following line if your cluster uses a self-signed certificate # configuration.verify_ssl = False # Create the client with authentication trainer_client = TrainerClient( backend_config=KubernetesBackendConfig(client_configuration=configuration) ) # Create the trainer configuration trainer = TransformersTrainer( func=train_func, num_nodes=2, resources_per_node={"nvidia.com/gpu": 1}, ) # Get the runtime and submit the training job runtime = trainer_client.backend.get_runtime("torch-distributed") job_name = trainer_client.train(trainer=trainer, runtime=runtime) print(f"Job {job_name} submitted!")Replace
<your-api-server-url>with the API server URL from step 1 and<your-bearer-token>with the authentication token from step 1.The TransformersTrainer parameters are:
Expand Parameter Type Description funcCallableThe Python function contains your training code.
num_nodesintNumber of distributed training nodes (default: 1).
resources_per_nodedictResource requests per node, for example
"nvidia.com/gpu": 1, "memory": "16Gi".
Verification
Verify that the job was submitted by checking the job status:
job = trainer_client.get_job(job_name) print(f" Status: {job.status}")Verify that the training pods are running:
oc get pods -n <your-namespace> -l job-name=<job-name>Replace
<your-namespace>with the name of your project and<job-name>with the name of your training job.- (Optional) Verify that real-time progress metrics are displayed for your training job. Navigate to the OpenShift AI dashboard and click TrainingJobs to view these metrics.
6.3.2. Configuring JIT checkpointing with a PVC リンクのコピーリンクがクリップボードにコピーされました!
To enable JIT checkpointing with persistent storage, use the pvc:// URI scheme in the output_dir parameter of the TransformersTrainer. The SDK automatically mounts the PVC on all training pods.
Your project must have a PersistentVolumeClaim (PVC) with ReadWriteMany (RWX) access mode.
trainer = TransformersTrainer(
func=train_func,
num_nodes=2,
resources_per_node={"nvidia.com/gpu": 1},
output_dir="pvc://training-checkpoints/checkpoints",
)
When JIT checkpointing is configured:
If pods receive a termination signal (SIGTERM), the trainer automatically saves a checkpoint. When the job restarts, training automatically resumes from the latest checkpoint. For more information about progress tracking and JIT checkpointing, see Using RHAI trainers for progress tracking and checkpointing.
6.3.3. Disabling progress tracking リンクのコピーリンクがクリップボードにコピーされました!
Progress tracking is enabled by default when using RHAI trainers. To disable progress tracking, set enable_progression_tracking=False:
trainer = TransformersTrainer(
func=train_func,
num_nodes=2,
resources_per_node={"nvidia.com/gpu": 1},
enable_progression_tracking=False,
)
6.4. Fine-tuning a model by using Kubeflow Trainer v2 リンクのコピーリンクがクリップボードにコピーされました!
Fine-tuning is the process of customizing a Large Language Model (LLM) for a specific task by using labelled data. You can use Kubeflow Trainer v2 with Training Hub runtimes and the Kubeflow Python SDK to fine-tune LLMs in Red Hat OpenShift AI.
Red Hat OpenShift AI supports the following fine-tuning algorithms through Training Hub:
- Orthogonal Subspace Fine-Tuning (OSFT)
- Enables continual learning of pre-trained or instruction-tuned models without catastrophic forgetting. OSFT does not require a supplementary dataset to maintain the distribution of the original model.
- Supervised Fine-Tuning (SFT)
- Standard fine-tuning for task adaptation using PyTorch Fully Sharded Data Parallel (FSDP) to distribute training across multiple GPUs and nodes.
6.4.1. Configuring the fine-tuning job リンクのコピーリンクがクリップボードにコピーされました!
Before you can use a training job to fine-tune a model, you must configure the training job. You must set the training parameters, select the fine-tuning algorithm, and configure the Kubeflow SDK.
The code in this procedure specifies how to configure an example fine-tuning job. If you have the specified resources, you can run the example code without editing it. Alternatively, you can modify the example code to specify the appropriate configuration for your fine-tuning job.
Prerequisites
You can access an OpenShift cluster that has sufficient worker nodes with supported accelerators to run your training or tuning job.
- For the OSFT example: 2 nodes with 2 NVIDIA L40/L40S GPUs each (4 GPUs total), 4 CPUs and 32 GiB memory per node.
- For the SFT example: 2 nodes with 2 NVIDIA GPUs each (Ampere-based or newer recommended), 4 CPUs and 64 GiB memory per node.
Your cluster administrator has configured the cluster as follows:
- Installed Red Hat OpenShift AI with the required distributed training components, as described in Installing the distributed workloads components (for disconnected environments, see Installing the distributed workloads components).
- Configured the distributed training resources.
- Installed the JobSet Operator from OLM, as described in Installing the JobSet Operator.
- Configured RBAC permissions for SDK access to ClusterTrainingRuntime resources.
-
A training-hub ClusterTrainingRuntime is available in your cluster. To verify, run
oc get clustertrainingruntime training-hub. - You can access a workbench that is suitable for distributed training, as described in Creating a workbench for distributed training.
- You can access a dynamic storage provisioner that supports ReadWriteMany (RWX) Persistent Volume Claim (PVC) provisioning, such as Red Hat OpenShift Data Foundation.
You have administrator access for the project.
- If you created the project, you automatically have administrator access.
- If you did not create the project, your cluster administrator must give you administrator access.
Procedure
- Open the workbench:
- Log in to the Red Hat OpenShift AI web console.
- Click Projects and click your project.
- Click the Workbenches tab.
- Ensure that the workbench uses a storage class with RWX capability.
- If your workbench is not already running, start the workbench.
- Click the Open link to open the IDE in a new window.
- Click File > New > Notebook.
Install the required packages. In a notebook cell, add the code to install the dependencies, as follows:
!pip install kubeflow --index-url https://console.redhat.com/api/pypi/public-rhai/rhoai/3.2/cuda12.9-ubi9/simple/ !pip install training-hub==0.3.0- Select the cell, and click Run > Run selected cell.
Configure the Kubeflow SDK client authentication by creating a cell with the following content:
from kubernetes import client as k8s from kubeflow.common.types import KubernetesBackendConfig from kubeflow.trainer import TrainerClient api_server = "<API_SERVER>" token = "<TOKEN>" configuration = k8s.Configuration() configuration.host = api_server configuration.api_key = {"authorization": f"Bearer {token}"} # Uncomment if your cluster API server uses a self-signed certificate # configuration.verify_ssl = False backend_cfg = KubernetesBackendConfig(client_configuration=configuration) client = TrainerClient(backend_cfg)-
Edit the
api_serverandtokenparameters to enter the values to authenticate to your OpenShift cluster. Run the cell to configure the SDK client authentication. Verify that a Training Hub runtime is available, as follows:
for runtime in client.list_runtimes(): print("Found runtime: " + str(runtime)) if runtime.name == "training-hub": th_runtime = runtime print("Selected runtime: " + str(th_runtime))Set the training parameters. The training parameters depend on the fine-tuning algorithm you choose. See the following sections for algorithm-specific configuration:
- OSFT training parameters for OSFT fine-tuning
- SFT training parameters for SFT fine-tuning
- Click File > Save Notebook As, enter an appropriate file name, and click Save.
6.4.1.1. OSFT training parameters for OSFT fine-tuning リンクのコピーリンクがクリップボードにコピーされました!
Create a cell with the following content to set the OSFT training parameters:
params = {
# Model + Data Paths
"model_path": "Qwen/Qwen2.5-1.5B-Instruct",
"data_path": "/mnt/shared/table-gpt-data/train/train_All_5000.jsonl",
"ckpt_output_dir": "/mnt/shared/checkpoints-logs-dir",
"data_output_path": "/mnt/shared/osft-json/_data",
# Training Hyperparameters
"unfreeze_rank_ratio": 0.25, # OSFT-specific: controls the subspace dimension
"effective_batch_size": 128,
"learning_rate": 5.0e-6,
"num_epochs": 1,
"lr_scheduler": "cosine",
"warmup_steps": 0,
"seed": 42,
# Performance Hyperparameters
"use_liger": True, # OSFT-specific: enables Liger kernel optimization
"max_tokens_per_gpu": 64000,
"max_seq_len": 8192,
# Checkpointing Settings
"save_final_checkpoint": True,
"checkpoint_at_epoch": False,
# Distributed training (delegated to Kubeflow Trainer)
"nproc_per_node": 2,
"nnodes": 2,
}
Optional: Edit the parameters to suit your model, dataset, and resources.
6.4.1.2. SFT training parameters for SFT fine-tuning リンクのコピーリンクがクリップボードにコピーされました!
Create a cell with the following content to set the SFT training parameters:
training_parameters = {
# Model + Data Paths
"model_path": "/mnt/shared/Qwen/Qwen2.5-1.5B-Instruct",
"data_path": "/mnt/shared/table-gpt-data/train/train_All_5000.jsonl",
"ckpt_output_dir": "/mnt/shared/checkpoints",
"data_output_dir": "/mnt/shared/traininghub-sft-data",
# Training Hyperparameters
"effective_batch_size": 128,
"learning_rate": 5e-6,
"num_epochs": 1,
"lr_scheduler": "cosine",
"warmup_steps": 0,
"seed": 42,
# Performance Hyperparameters
"max_tokens_per_gpu": 10000,
"max_seq_len": 8192,
# Checkpointing Settings
"checkpoint_at_epoch": True,
"accelerate_full_state_at_epoch": False,
# FSDP Configuration
"fsdp_options": {
"sharding_strategy": "FULL_SHARD",
},
"nproc_per_node": 1,
"nnodes": 2,
}
Optional: Edit the parameters to suit your model, dataset, and resources.
6.4.1.3. Example fine-tuning notebooks リンクのコピーリンクがクリップボードにコピーされました!
For complete, runnable example notebooks, see the following resources:
OSFT Continual Learning example — Fine-tune Qwen/Qwen2.5-1.5B-Instruct with OSFT for continual learning without catastrophic forgetting. Includes model evaluation before and after fine-tuning.
-
Notebook:
osft-example.ipynb - Hardware: 2 nodes x 2 GPUs (L40/L40S or equivalent), 4 GPUs total
-
Notebook:
SFT with Training Hub example — Fine-tune Qwen/Qwen2.5-1.5B-Instruct with SFT and PyTorch FSDP for distributed training.
-
Notebook:
sft.ipynb - Hardware: validated with Qwen2.5 1.5B, 7B, and 14B models on 4x NVIDIA A100/80GB
-
Notebook:
6.4.1.4. Training data format リンクのコピーリンクがクリップボードにコピーされました!
Training Hub fine-tuning algorithms support training data in JSON Lines (.jsonl) format with a messages structure:
{"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Hello!"}, {"role": "assistant", "content": "Hi there! How can I help you?"}]}
{"messages": [{"role": "user", "content": "What is OSFT?"}, {"role": "assistant", "content": "OSFT stands for Orthogonal Subspace Fine-Tuning..."}]}
6.4.2. Running the fine-tuning job リンクのコピーリンクがクリップボードにコピーされました!
When you run a training job to fine-tune a model, you must specify the resources needed, provide any authorization credentials required, and configure shared storage for datasets, models, and checkpoints.
The code in this procedure specifies how to run the example fine-tuning job. If you have the specified resources, you can run the example code without editing it. Alternatively, you can modify the example code to specify the appropriate details for your fine-tuning job.
Prerequisites
- You have acces to an OpenShift cluster that has sufficient worker nodes with supported accelerators to run your training or tuning job.
- You have access to a workbench that is suitable for distributed training, as described in Creating a workbench for distributed training.
You have administrator access for the project.
- If you created the project, you automatically have administrator access.
- If you did not create the project, your cluster administrator must give you administrator access.
- You have access to a model.
- You have access to data that you can use to fine-tune the model.
- You have configured the fine-tuning job as described in Configuring the fine-tuning job.
- You can access a dynamic storage provisioner that supports ReadWriteMany (RWX) Persistent Volume Claim (PVC) provisioning, such as Red Hat OpenShift Data Foundation.
- A PersistentVolumeClaim resource named shared with RWX access mode is attached to your workbench.
- If using a gated model from the Hugging Face Hub, you have a Hugging Face account and access token. For more information, search for "user access tokens" in the Hugging Face documentation.
Procedure
Open the workbench, as follows:
- Log in to the Red Hat OpenShift AI web console.
- Click Projects and click your project.
- Click the Workbenches tab. If your workbench is not already running, start the workbench.
- Click the Open link to open the IDE in a new window.
- Click File > Open, and open the Jupyter notebook that you used to configure the fine-tuning job.
- Create a cell to run the job.
Depending on your fine-tuning method, add the code for either OSFT or SFT:
To enable OSFT fine-tuning, add:
from kubeflow.trainer.rhai import TrainingHubAlgorithms, TrainingHubTrainer from kubeflow.trainer.options.kubernetes import ( ContainerOverride, PodSpecOverride, PodTemplateOverride, PodTemplateOverrides, ) PVC_NAME = "shared" job_name = client.train( trainer=TrainingHubTrainer( algorithm=TrainingHubAlgorithms.OSFT, func_args=params, env={ "HF_HOME": "/mnt/shared/huggingface", "TRITON_CACHE_DIR": "/mnt/shared/.triton", "XDG_CACHE_HOME": "/opt/app-root/src/.cache", "NCCL_DEBUG": "INFO", }, resources_per_node={ "nvidia.com/gpu": 2, "memory": "32Gi", "cpu": 4, }, ), options=[ PodTemplateOverrides( PodTemplateOverride( target_jobs=["node"], spec=PodSpecOverride( volumes=[ { "name": "work", "persistentVolumeClaim": {"claimName": PVC_NAME}, }, ], containers=[ ContainerOverride( name="node", volume_mounts=[ { "name": "work", "mountPath": "/mnt/shared", }, ], ), ], ), ) ) ], runtime=th_runtime, )To enable SFT fine-tuning, add:
from kubeflow.trainer.rhai import TrainingHubAlgorithms, TrainingHubTrainer from kubeflow.trainer.options.kubernetes import ( ContainerOverride, PodSpecOverride, PodTemplateOverride, PodTemplateOverrides, ) PVC_NAME = "shared" job_name = client.train( trainer=TrainingHubTrainer( algorithm=TrainingHubAlgorithms.SFT, func_args=training_parameters, env={ "HF_HOME": "/mnt/shared/huggingface", "TRITON_CACHE_DIR": "/mnt/shared/.triton", "XDG_CACHE_HOME": "/opt/app-root/src/.cache", "NCCL_DEBUG": "INFO", }, resources_per_node={ "nvidia.com/gpu": 2, "memory": "64Gi", "cpu": 4, }, ), options=[ PodTemplateOverrides( PodTemplateOverride( target_jobs=["node"], spec=PodSpecOverride( volumes=[ { "name": "work", "persistentVolumeClaim": {"claimName": PVC_NAME}, }, ], containers=[ ContainerOverride( name="node", volume_mounts=[ { "name": "work", "mountPath": "/mnt/shared", }, ], ), ], ), ) ) ], runtime=th_runtime, )
where:
resources_per_node-
values should be updated according to the job requirements and the resources available. If you use AMD accelerators, in the
resources_per_nodeentry, changenvidia.com/gputoamd.com/gpu. If the RWX PersistentVolumeClaim resource attached to your workbench has a different name instead of shared, update thePVC_NAMEvalue and themountPathas needed. If using a gated Hugging Face model, add"HF_TOKEN": "<your-token>"to the env dictionary.
Verification
View the progress of the job as follows:
Create a cell with the following content:
for logline in client.get_job_logs(job_name, follow=True): print(logline, end="")- Run the cell to view the job progress.
(Optional) Check the final job status:
job = client.get_job(job_name) print(f"Name: {job.name}") print(f"Status: {job.status}") print(f"Nodes: {job.num_nodes}") print(f"Runtime: {job.runtime.name}")
6.4.3. Deleting the fine-tuning job リンクのコピーリンクがクリップボードにコピーされました!
When you no longer need the fine-tuning job, delete the job to release the resources.
Procedure
- Log in to the Red Hat OpenShift AI web console.
- Click Projects and click your project.
- Click the Workbenches tab. If your workbench is not already running, start the workbench.
- Click the Open link to open the IDE in a new window.
- Click File > Open, and open the Jupyter notebook that you used to configure and run the fine-tuning job.
Create a cell with the following content:
client.delete_job(name=job_name)- Run the cell to delete the job.
Verification
- In the OpenShift Console, in the Administrator perspective, click Workloads > Jobs.
- From the Project list, select your project.
- Verify that the specified job is not listed.
6.5. Example Kubeflow Trainer TrainJob resources リンクのコピーリンクがクリップボードにコピーされました!
This section provides example TrainJob resources and training scripts for common distributed training scenarios with Kubeflow Trainer v2.
6.5.1. Example TrainJob resource for multi-node training リンクのコピーリンクがクリップボードにコピーされました!
The following example shows a complete TrainJob resource for multi-node distributed PyTorch training using a ConfigMap to provide the training script:
apiVersion: trainer.kubeflow.org/v1alpha1
kind: TrainJob
metadata:
name: pytorch-multi-node-job
namespace: test-namespace
annotations:
trainer.opendatahub.io/progression-tracking: "true"
spec:
runtimeRef:
name: torch-distributed
kind: ClusterTrainingRuntime
trainer:
command: ["torchrun", "/workspace/train.py"]
numNodes: 3
resourcesPerNode:
requests:
cpu: "4"
memory: "8Gi"
nvidia.com/gpu: 2
limits:
cpu: "4"
memory: "8Gi"
nvidia.com/gpu: 2
podTemplateOverrides:
- targetJobs:
- name: node
spec:
volumes:
- name: training-script-volume
configMap:
name: training-script-configmap
containers:
- name: node
volumeMounts:
- name: training-script-volume
mountPath: /workspace
6.5.2. Example TrainJob with a minimal training script リンクのコピーリンクがクリップボードにコピーされました!
The following example uses a small training script in a ConfigMap and runs it with torchrun. The runtime sets up distributed training for you, so you do not need to set any environment variables. The script is mounted into the pod using podTemplateOverrides, which works with the default torch-distributed runtime with container name node.
Apply the ConfigMap first, then the TrainJob.
Create a ConfigMap with the training script:
apiVersion: v1 kind: ConfigMap metadata: name: minimal-train-script namespace: test-namespace data: train.py: | import torch import torch.distributed as dist dist.init_process_group(backend="nccl") rank = dist.get_rank() world_size = dist.get_world_size() print(f"Rank {rank}/{world_size}") print(f"PyTorch: {torch.version}, CUDA: {torch.cuda.is_available()}") if torch.cuda.is_available(): print(f"GPU: {torch.cuda.get_device_name(0)}") tensor = torch.ones(1).cuda() * rank dist.all_reduce(tensor) print(f"Rank {rank}: all_reduce result = {tensor.item()}") dist.destroy_process_group() print("Done.")Create the TrainJob:
Use
podTemplateOverridesto add the ConfigMap volume and mount it into the trainer container. The target job namenodematches the defaulttorch-distributedruntime.apiVersion: trainer.kubeflow.org/v1alpha1 kind: TrainJob metadata: name: pytorch-minimal-example namespace: test-namespace spec: runtimeRef: name: torch-distributed kind: ClusterTrainingRuntime trainer: command: ["torchrun", "/workspace/train.py"] numNodes: 2 resourcesPerNode: requests: nvidia.com/gpu: 1 limits: nvidia.com/gpu: 1 podTemplateOverrides: - targetJobs: - name: node spec: volumes: - name: script-volume configMap: name: minimal-train-script containers: - name: node volumeMounts: - name: script-volume mountPath: /workspace
6.5.3. Example TrainJob resource with custom TrainingRuntime (no environment variables needed) リンクのコピーリンクがクリップボードにコピーされました!
The following example shows a TrainJob resource that references a custom namespace-scoped TrainingRuntime. Use podTemplateOverrides to mount the script. Set targetJobs and the container name to match your custom runtime template. Here, node is used as the trainer job and container name:
apiVersion: trainer.kubeflow.org/v1alpha1
kind: TrainJob
metadata:
name: pytorch-custom-runtime-example
namespace: my-project
spec:
runtimeRef:
name: custom-torch-runtime
kind: TrainingRuntime
trainer:
command: ["torchrun", "/workspace/train.py"]
numNodes: 2
resourcesPerNode:
requests:
cpu: "8"
memory: "32Gi"
nvidia.com/gpu: 4
limits:
cpu: "8"
memory: "32Gi"
nvidia.com/gpu: 4
podTemplateOverrides:
- targetJobs:
- name: node
spec:
volumes:
- name: training-script-volume
configMap:
name: training-script-configmap
containers:
- name: node
volumeMounts:
- name: training-script-volume
mountPath: /workspace
where:
kind: TrainingRuntime-
indicates that the runtime is namespace-scoped. Ensure that you have created the custom
TrainingRuntimeresource in the same namespace. See Understanding and using training runtimes for details. If your runtime uses a different replicated job or container name, changetargetJobsandcontainers[].nameaccordingly.
6.5.4. Example TrainJob resource with suspend enabled リンクのコピーリンクがクリップボードにコピーされました!
The following example shows a TrainJob resource that is created in a suspended state. This is useful when you want to define a job before starting it:
apiVersion: trainer.kubeflow.org/v1alpha1
kind: TrainJob
metadata:
name: pytorch-suspended-example
namespace: test-namespace
annotations:
trainer.opendatahub.io/progression-tracking: "true"
spec:
suspend: true
runtimeRef:
name: torch-distributed
kind: ClusterTrainingRuntime
trainer:
command: ["python", "/workspace/scripts/train.py"]
numNodes: 2
resourcesPerNode:
requests:
cpu: "4"
memory: "8Gi"
nvidia.com/gpu: 2
limits:
cpu: "4"
memory: "8Gi"
nvidia.com/gpu: 2
volumeMounts:
- name: training-script-volume
mountPath: /workspace
volumes:
- name: training-script-volume
configMap:
name: training-script-configmap
To start the job:
oc patch trainjob pytorch-suspended-example -n test-namespace --type=merge -p {"spec":{"suspend":false}}
6.5.5. Example PyTorch training script リンクのコピーリンクがクリップボードにコピーされました!
The following example shows a simple distributed PyTorch training script that you can store in a ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: training-script-configmap
namespace: test-namespace
data:
train.py: |
import os
import torch
import torch.nn as nn
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.utils.data import DataLoader, TensorDataset, DistributedSampler
def main():
# Initialize distributed training
dist.init_process_group(backend="nccl")
rank = dist.get_rank()
world_size = dist.get_world_size()
local_rank = int(os.environ.get("LOCAL_RANK", 0))
torch.cuda.set_device(local_rank)
print(f"Rank {rank}/{world_size}, Local Rank: {local_rank}")
# Create a simple model
model = nn.Sequential(
nn.Linear(10, 128),
nn.ReLU(),
nn.Linear(128, 1),
).cuda(local_rank)
model = DDP(model, device_ids=[local_rank])
# Create synthetic dataset
X = torch.randn(1000, 10)
y = torch.randn(1000, 1)
dataset = TensorDataset(X, y)
sampler = DistributedSampler(dataset, num_replicas=world_size, rank=rank)
dataloader = DataLoader(dataset, batch_size=32, sampler=sampler)
# Training loop
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
criterion = nn.MSELoss()
for epoch in range(10):
sampler.set_epoch(epoch)
total_loss = 0
for batch_X, batch_y in dataloader:
batch_X = batch_X.cuda(local_rank)
batch_y = batch_y.cuda(local_rank)
optimizer.zero_grad()
output = model(batch_X)
loss = criterion(output, batch_y)
loss.backward()
optimizer.step()
total_loss += loss.item()
if rank == 0:
print(f"Epoch {epoch+1}/10, Loss: {total_loss/len(dataloader):.4f}")
dist.destroy_process_group()
if rank == 0:
print("Training complete!")
if name == "main":
main()
6.5.6. Example HuggingFace Transformers training script リンクのコピーリンクがクリップボードにコピーされました!
The following example shows a HuggingFace Transformers training script for fine-tuning BERT on the IMDB dataset:
apiVersion: v1
kind: ConfigMap
metadata:
name: transformers-training-script
namespace: test-namespace
data:
train.py: |
from transformers import (
AutoModelForSequenceClassification,
AutoTokenizer,
Trainer,
TrainingArguments,
)
from datasets import load_dataset
def main():
# Load model and tokenizer
model_name = "bert-base-uncased"
model = AutoModelForSequenceClassification.from_pretrained(
model_name, num_labels=2
)
tokenizer = AutoTokenizer.from_pretrained(model_name)
# Load and tokenize dataset
dataset = load_dataset("imdb", split="train[:2000]")
def tokenize_function(examples):
return tokenizer(
examples["text"],
padding="max_length",
truncation=True,
max_length=512,
)
tokenized_dataset = dataset.map(tokenize_function, batched=True)
# Configure training
training_args = TrainingArguments(
output_dir="/tmp/output",
num_train_epochs=3,
per_device_train_batch_size=8,
logging_steps=10,
save_strategy="epoch",
)
# Create trainer and train
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset,
)
trainer.train()
print("Training complete!")
if name == "main":
main()
6.5.7. Example TrainJob resource for AMD ROCm GPUs リンクのコピーリンクがクリップボードにコピーされました!
The following example shows a TrainJob resource configured for AMD ROCm GPUs. The script is mounted using podTemplateOverrides because the target job name node matches the default ROCm runtime:
apiVersion: trainer.kubeflow.org/v1alpha1
kind: TrainJob
metadata:
name: pytorch-rocm-example
namespace: test-namespace
spec:
runtimeRef:
name: torch-distributed-rocm
kind: ClusterTrainingRuntime
trainer:
command: ["torchrun", "/workspace/train.py"]
numNodes: 2
resourcesPerNode:
requests:
cpu: "4"
memory: "8Gi"
amd.com/gpu: 1
limits:
cpu: "4"
memory: "8Gi"
amd.com/gpu: 1
podTemplateOverrides:
- targetJobs:
- name: node
spec:
volumes:
- name: training-script-volume
configMap:
name: training-script-configmap
containers:
- name: node
volumeMounts:
- name: training-script-volume
mountPath: /workspace
where:
torch-distributed-rocm-
ClusterTrainingRuntime is specifically configured for AMD ROCm GPUs. The GPU resource request uses
amd.com/gpuinstead ofnvidia.com/gpu.